/* SunX — base + components. Depends on tokens.css. */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Guards every section against a stray wide child pushing the page sideways. */
  overflow-x: hidden;
}

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

/* Pictures are not draggable. The `draggable="false"` attribute covers the
   drag itself; this covers the ghost image Safari and older WebKit still
   render while the pointer moves, which is the part that makes a blocked drag
   look broken rather than refused.

   Scoped to img, and to the one property. There is deliberately no blanket
   `user-select: none` here: the SKU, the order number, the address and every
   line of body copy have to stay selectable and copyable. */
img { -webkit-user-drag: none; user-drag: none; }

/* iOS shows a save/copy sheet on a long press. Withholding it on the
   photographs only — never on links, never on the gallery's own controls, and
   never on anything inside a form — leaves swipe, pinch, scroll and tap
   behaving exactly as they did. */
[data-protect] { -webkit-touch-callout: none; }
a { color: inherit; text-decoration: none; }
button, input, select { font: inherit; color: inherit; }
ul { list-style: none; padding: 0; }

:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ------------------------------------------------------------- typography */

h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: .98;
  letter-spacing: -.02em;
  text-wrap: balance;
}

.eyebrow {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--yellow);
}

.section-head { max-width: 62ch; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-head h2 { font-size: var(--fs-h2); margin: 1rem 0 .9rem; }
.section-head.is-centered { text-align: center; margin-inline: auto; }
.section-head.is-centered .eyebrow { justify-content: center; }
.lead { font-size: var(--fs-lead); color: var(--text-2); text-wrap: pretty; }

/* Every inline icon shares one size contract. Without it an SVG with no
   intrinsic dimensions stretches to the flex line and wraps its own label. */
.ico { width: 18px; height: 18px; flex: none; }
.eyebrow .ico { width: 15px; height: 15px; }

/* ----------------------------------------------------------------- layout */

.shell { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }
.shell-wide { max-width: var(--shell-wide); }
/* A single column of prose and one action — the order confirmation. */
.shell-narrow { max-width: 62ch; }
.section { padding-block: var(--section); position: relative; }
/* Alternating band so long pages keep a rhythm without extra dividers. */
.section.is-raised { background: var(--surface-1); border-block: 1px solid var(--line); }

/* ---------------------------------------------------------------- buttons */

.btn {
  --btn-bg: var(--surface-3);
  --btn-fg: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  min-height: 52px;
  padding: 0 1.6rem;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 700;
  font-size: var(--fs-sm);
  letter-spacing: .01em;
  cursor: pointer;
  transition: transform .18s var(--ease), background .18s, box-shadow .25s, border-color .18s;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; }

.btn-primary {
  --btn-bg: var(--yellow);
  --btn-fg: #0B0B06;
  font-weight: 800;
}
.btn-primary:hover { --btn-bg: #FFF95C; box-shadow: var(--glow-yellow); }

.btn-ghost { --btn-bg: transparent; border-color: var(--line-strong); }
.btn-ghost:hover { border-color: var(--yellow); color: var(--yellow); }

.btn-lg { min-height: 60px; padding: 0 2.2rem; font-size: 1rem; }
.btn-block { width: 100%; }

/* ----------------------------------------------------------------- header */

/* The free-shipping bar stays put.
   It used to scroll away with the page and then be covered outright by the
   mobile drawer, so the one line telling you shipping is free disappeared at
   exactly the moment you went looking for the shop. Sticky above the header,
   and the drawer starts below it. Its height is measured in app.js into
   --announce-h, because the line wraps to two rows under about 380px and a
   hard-coded offset would clip the header there. */
.announce {
  position: sticky;
  top: 0;
  z-index: 260;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .1rem .45rem;
  background: linear-gradient(90deg, var(--surface-2), var(--surface-1));
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--text-2);
  text-align: center;
  padding: .6rem var(--gutter);
}
.announce strong { color: var(--yellow); font-weight: 700; }
.announce .ico { width: 14px; height: 14px; color: var(--yellow); }

.header {
  position: sticky;
  top: var(--announce-h, 0px);
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background .3s, border-color .3s, backdrop-filter .3s;
}

/* A lit seam under the header. Brightest in the middle and gone before either
   end, so it reads as light spilling from the bar rather than as a rule drawn
   across the page — the same idea as the filament on the consent module, which
   is the one place this site is allowed to glow. */
.header::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(254, 245, 24, .12) 18%,
    rgba(254, 245, 24, .75) 50%,
    rgba(254, 245, 24, .12) 82%,
    transparent 100%);
  box-shadow: 0 0 18px rgba(254, 245, 24, .3);
  opacity: .55;
  transition: opacity .3s;
}
/* Once the page has moved the header has a real edge, and the seam sits on it
   at full strength. */
.header.is-stuck::after { opacity: 1; }
/* Only frosts once the page has moved, so the hero stays uninterrupted. */
.header.is-stuck {
  background: rgba(8, 10, 13, .78);
  backdrop-filter: blur(18px) saturate(140%);
  border-bottom-color: var(--line);
}
.header-inner {
  display: flex;
  align-items: center;
  gap: clamp(.75rem, 2.2vw, 2rem);
  min-height: 88px;
}
.logo img { height: clamp(42px, 4.6vw, 64px); width: auto; }

.nav { display: flex; gap: clamp(.65rem, 1.5vw, 1.5rem); margin-inline-start: auto; }
.nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  padding-block: .5rem;
  white-space: nowrap;
  transition: color .2s;
}
.nav a .ico { width: 16px; height: 16px; color: var(--text-3); transition: color .2s; }
.nav a:hover { color: var(--text); }
.nav a:hover .ico { color: var(--yellow); }
.nav a::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--yellow);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .3s var(--ease);
}
.nav a:hover::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: .5rem; }
.header-actions .btn { white-space: nowrap; }

/* ------------------------------------------------------ language switcher */

.flag { width: 22px; height: 22px; flex: none; border-radius: 50%; }

.lang { position: relative; }
.lang > summary {
  display: flex;
  align-items: center;
  gap: .4rem;
  height: 44px;
  padding: 0 .55rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  list-style: none;
  transition: border-color .2s;
}
.lang > summary::-webkit-details-marker { display: none; }
.lang > summary:hover { border-color: var(--line-strong); }
.lang-code { font-size: var(--fs-xs); font-weight: 800; letter-spacing: .06em; }
.lang-chev { width: 14px; height: 14px; color: var(--text-3); transition: transform .2s; }
.lang[open] .lang-chev { transform: rotate(180deg); }

.lang-menu {
  position: absolute;
  top: calc(100% + .5rem);
  inset-inline-end: 0;
  z-index: 120;
  min-width: 190px;
  padding: .4rem;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}
.lang-menu a {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .55rem .6rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  transition: background .15s, color .15s;
}
.lang-menu a:hover { background: var(--surface-3); color: var(--text); }
.lang-menu a.is-active { color: var(--yellow); background: var(--yellow-wash); }

/* Footer / drawer variant: flags only, laid out in a row. */
.lang-row { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.4rem; }
.lang-row a {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  border-radius: 50%;
  transition: border-color .2s, transform .2s var(--ease);
}
.lang-row a:hover { border-color: var(--yellow); transform: translateY(-2px); }
.lang-row a.is-active { border-color: var(--yellow); box-shadow: 0 0 0 3px var(--yellow-wash); }
.lang-row a span {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.icon-btn {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: transparent;
  cursor: pointer;
  transition: border-color .2s, color .2s;
}
.icon-btn:hover { border-color: var(--line-strong); color: var(--yellow); }
.icon-btn svg { width: 19px; height: 19px; }

.burger { display: none; }

/* ------------------------------------------------------------------- hero */

.hero {
  position: relative;
  min-height: min(78vh, 740px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-top: clamp(2rem, 5vw, 3.5rem);
  padding-bottom: clamp(1.5rem, 4vw, 3rem);
  overflow: hidden;
  isolation: isolate;
}
.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
/* The banner is a wide composition (car · bulbs · road). At desktop widths the
   hero box is close to its native 2.33:1, so centring keeps all three visible;
   narrower boxes crop inward and we bias toward the product. */
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
@media (max-width: 1200px) { .hero-media img { object-position: 62% 50%; } }
/* The clip is the backdrop, not a layer over one. It used to fade in over a
   photograph at `canplay`, which is why it was transparent to begin with;
   there is no photograph now and its poster is its own first frame, so it is
   opaque from the first paint and the footage starting is not a visible event.
   It sits below .hero-media::after, which is the last child and therefore
   still paints its scrims over it. */
.hero-clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The clip is a 16:9 composite with the product parked in its upper right, so
     this anchor is the product's own centre, not the frame's. The hero box is
     wider than 16:9 on a desktop (nothing is cropped and the value is moot) and
     much narrower on a tablet, where `cover` throws away a third of the width —
     anchoring on the subject is what keeps the box whole and clear of the finder
     card there. The still below keeps its own framing; these are separate crops. */
  object-position: 68% 39%;
  pointer-events: none;
  /* Poster and frame are the same picture, but a <video> paints its poster
     with the element's `background` behind it — black by default, and briefly
     visible in the gap before the first frame decodes. The page's own graphite
     is what should be there instead. */
  background: var(--bg);
}
/* Two stacked scrims: vertical for text legibility, horizontal so the product
   stays readable on the right while the copy sits on solid ground.

   The horizontal one has a second job, the one the phone band already does a
   few hundred lines down: the footage is a rendered set pasted onto a black
   1920×1080 canvas and the paste has straight vertical sides, so the lit grey
   of the set meets pure black along a hard line with no falloff at all. Here
   the clip is full-bleed, so both lines land inside the viewport — the left one
   used to sit under a scrim that had already thinned to a third by then, and
   the right one under no scrim at all, which is what read as two seams down the
   picture.

   `cover` moves them with the width of the box: between 1024px and 1680px the
   frame is cropped horizontally and the seams travel from 44%/93% out to
   50%/87%, where they stay. So the ramps are not aimed at a line, they are wide
   enough to be over it across that whole range: page colour at each edge, most
   of it still on top of wherever the seam is, and nothing left by 65%/77%,
   which is the product itself at any desktop width. What it costs is some
   darkening on the outer edges of the set, and that reads the way a light
   falling off reads. Below 1024px the band restates this rule with its own
   numbers — see the stacked hero further down. */
.hero-media::after {
  content: '';
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(8,10,13,.88) 0%, rgba(8,10,13,.2) 30%, rgba(8,10,13,.94) 88%),
    linear-gradient(90deg,
      var(--bg) 0%, rgba(8,10,13,.95) 8%, rgba(8,10,13,.9) 24%,
      rgba(8,10,13,.84) 40%, rgba(8,10,13,.72) 48%, rgba(8,10,13,.5) 54%,
      rgba(8,10,13,.24) 59%, rgba(8,10,13,0) 65%,
      rgba(8,10,13,0) 77%, rgba(8,10,13,.18) 81%, rgba(8,10,13,.45) 84%,
      rgba(8,10,13,.72) 87%, rgba(8,10,13,.9) 90%, rgba(8,10,13,.98) 94%,
      var(--bg) 100%);
}

.hero-copy { max-width: 72ch; }
.hero h1 {
  max-width: 14ch;
  font-size: var(--fs-hero);
  font-weight: 800;
  margin: 1rem 0 1.1rem;
}
.hero h1 em {
  display: block;
  font-style: normal;
  color: var(--yellow);
}
.hero .lead { max-width: 60ch; }

.hero-bullets {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem .45rem;
  margin-top: 1.2rem;
}
.hero-bullets li {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .36rem .72rem .36rem .58rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: rgba(16,19,24,.72);
  backdrop-filter: blur(10px);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--text-2);
}
.hero-bullets .ico { width: 14px; height: 14px; color: var(--yellow); }

/* Everything above is the wide-screen hero: a photograph across the whole
   section with the copy laid over its left third. Below 1024px that stops
   working — the box turns from 2.33:1 into something close to a square, the
   copy spans its full width, and the scrim that keeps the copy readable has to
   cover the picture rather than a corner of it. The result was a headline on a
   black rectangle with six seconds of footage playing invisibly underneath.

   So at this width the hero unstacks: headline, then the media as a 16:9 band
   you are meant to look at, then the pills, then the lead. The headline and the
   pills each overlap an edge of the band by a few pixels, which is the only
   thing holding the four parts together as one composition rather than four
   stacked blocks — and the middle of the picture, the part worth having, is
   left alone.

   1024px is not a new breakpoint: it is where app.js already decides about the
   clip, and the two have to agree. */
@media (max-width: 1023px) {
  .hero {
    min-height: auto;
    justify-content: flex-start;
    padding-top: clamp(1.75rem, 4vw, 2.5rem);
  }
  /* The children are in source order except the lead, which belongs under the
     pills here and over them everywhere else. `order` is what keeps that from
     needing a second copy of the paragraph in the markup. */
  .hero-copy {
    display: flex;
    flex-direction: column;
    max-width: none;
  }
  .hero .lead { order: 1; max-width: none; margin-top: 1.1rem; }

  /* Out of the background and into the flow. 16:9 because that is the shape of
     both the clip and the wide still, so the band shows the frame as composed
     and `cover` has nothing to throw away.

     Full width, no rounding and no hairline. The footage is a lit product on a
     pure black canvas and the page is #080A0D, so the two are the same colour
     to the eye — with nothing drawn around the band, the empty half of the
     frame simply reads as page. Put a rounded border back and that same
     emptiness turns into black bars inside a little window, which is what the
     picture looked like boxed. The negative margin is exactly the shell's
     gutter, so the band reaches both edges of the viewport without 100vw and
     its scrollbar arithmetic. */
  .hero-media {
    position: relative;
    inset: auto;
    z-index: 0;
    margin-inline: calc(-1 * var(--gutter));
    aspect-ratio: 16 / 9;
    overflow: hidden;
  }
  /* The desktop anchors were answers to a crop that no longer happens: the
     still is 2.33:1 and loses a tenth off each side, which is dead road on the
     left and dead sky on the right, and the clip is 16:9 and loses nothing. */
  .hero-media img, .hero-clip { object-position: 50% 50%; }

  /* The clip is not a photograph of a scene; it is a lit box on a black
     canvas, parked in the upper right of the frame because on a desktop the
     copy lies over the empty left. Here there is no copy over it, so the
     subject belongs in the middle and rather larger than the composite ships
     it — at native size the box is barely a fifth of the band's height.

     Read the transform right to left: blow the frame up about the subject's
     own centre, then carry that centre from where the desktop layout wanted it
     to the centre of the band. The scale stops short of filling the height:
     the headline crosses the top of the band and the pills the bottom, and the
     product has to clear both. What stays black at the left and right is the
     canvas the shot was always composed on, and full-bleed it is now
     indistinguishable from the page. */
  .hero-clip {
    transform-origin: 69% 39%;
    transform: translate(-17%, 11%) scale(1.85);
  }

  /* The footage is not black all the way out. It is a rendered set pasted onto
     a black 1920×1080 canvas, and the paste has straight vertical sides: the
     lit grey of the set meets pure black along a hard line, with no falloff at
     all. Full-bleed and blown up 1.85× that line lands at 17% and 83% of the
     band and reads as two seams down the picture — colour, then black, in one
     pixel.
     .                                       .
     |<- ramp ->|   the set   |<- ramp ->|
     0%        38%          62%        100%

     So the band paints its own falloff over them: the page colour at full
     strength at each edge, three quarters of it still on top of the seam, and
     nothing left by the time the product starts. The ramp reaches past the
     seam into the set, which is the point — a gradient that stopped at the
     seam would only have drawn a softer version of the same line. What it
     costs is some darkening on the outer edge of the set, and that reads the
     way a light falling off reads.

     Vertically the same thing, for a different reason: there the picture
     really is black to the edge, but #000 against a #080A0D page is a faint
     rectangle on an OLED screen in the dark. */
  .hero-media::after {
    background:
      linear-gradient(90deg,
        var(--bg) 0%, rgba(8,10,13,.98) 10%, rgba(8,10,13,.9) 15%,
        rgba(8,10,13,.62) 20%, rgba(8,10,13,.3) 26%, rgba(8,10,13,.1) 32%,
        rgba(8,10,13,0) 38%, rgba(8,10,13,0) 62%,
        rgba(8,10,13,.1) 68%, rgba(8,10,13,.3) 74%, rgba(8,10,13,.62) 80%,
        rgba(8,10,13,.9) 85%, rgba(8,10,13,.98) 90%, var(--bg) 100%),
      linear-gradient(180deg,
        var(--bg) 0%, rgba(8,10,13,.55) 4%, rgba(8,10,13,0) 22%,
        rgba(8,10,13,0) 74%, rgba(8,10,13,.45) 96%, var(--bg) 100%);
  }

  /* Both overlap the band, so both need to paint over it — the band is a
     positioned element now and would otherwise win on source order. */
  .hero .eyebrow, .hero h1, .hero-bullets { position: relative; z-index: 1; }
  /* The overlap. In em, not rem, because it has to stay the same fraction of
     the headline across a range where the headline grows by a third: about
     half of it closes the leading and the descender space under the last line,
     and the rest carries the capitals down into the band's dark top. */
  .hero h1 { max-width: none; margin-bottom: -.52em; }
  /* Same on the other edge, so the four parts read as one column rather than
     as a headline, a picture, and two paragraphs with air between them. */
  .hero-bullets { margin-top: -1.15rem; }
}

/* --------------------------------------------------------- vehicle finder */

.finder {
  margin-top: clamp(1.75rem, 3.5vw, 2.75rem);
  background: linear-gradient(160deg, rgba(23,27,33,.96), rgba(16,19,24,.96));
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-lg);
  backdrop-filter: blur(20px);
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
.finder-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .75rem 1.25rem; margin-bottom: 1.4rem; }
.finder-head h2 { font-size: clamp(1.15rem, 2vw, 1.5rem); }
.finder-head p { font-size: var(--fs-sm); color: var(--text-2); }

.finder-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .85rem;
}
.field { position: relative; display: flex; flex-direction: column; gap: .45rem; }
.field > label {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-3);
}
.select-wrap { position: relative; }
.select-wrap select {
  appearance: none;
  width: 100%;
  min-height: 58px;
  padding: 0 3rem 0 1.15rem;
  background: var(--surface-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: border-color .2s, background .2s;
}
.select-wrap select:hover:not(:disabled) { border-color: #3C434F; }
.select-wrap select:focus { border-color: var(--yellow); outline: none; }
.select-wrap select:disabled { opacity: .45; cursor: not-allowed; }
.select-wrap::after {
  content: '';
  position: absolute;
  right: 1.15rem; top: 50%;
  width: 9px; height: 9px;
  border-right: 2px solid var(--text-2);
  border-bottom: 2px solid var(--text-2);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.select-wrap.is-loading::after {
  width: 14px; height: 14px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--yellow);
  border-radius: 50%;
  transform: translateY(-50%) rotate(0);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: translateY(-50%) rotate(360deg); } }

/* The button gets its own row under the three selects and runs edge to edge
   across them — squeezed into a fourth column it read as an afterthought next
   to the fields it belongs to. The small top margin keeps it off the last
   select rather than looking glued to it. */
.finder-submit { display: flex; grid-column: 1 / -1; margin-top: .4rem; }
.finder-submit .btn { width: 100%; }
.finder-note {
  margin-top: 1.1rem;
  font-size: var(--fs-sm);
  color: var(--text-3);
  display: flex;
  align-items: center;
  gap: .5rem;
}
.finder-note svg { width: 16px; height: 16px; color: var(--yellow); flex: none; }

.finder-result { margin-top: 1.25rem; font-size: var(--fs-sm); }
.finder-result:empty { display: none; }
.finder-result .ok   { color: var(--ok); font-weight: 700; }
.finder-result .warn { color: var(--warn); font-weight: 700; }

/* Fired when a "find my bulbs" CTA sends the visitor here, so it is obvious
   what the page wants from them next. */
.finder.is-pulsing { animation: finder-pulse 1.1s var(--ease) 2; }
@keyframes finder-pulse {
  0%, 100% { border-color: var(--line-strong); box-shadow: var(--shadow-lg); }
  45%      { border-color: var(--yellow);      box-shadow: var(--shadow-lg), 0 0 0 6px var(--yellow-wash), var(--glow-yellow); }
}
@media (prefers-reduced-motion: reduce) {
  .finder.is-pulsing { animation: none; border-color: var(--yellow); }
}

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

.trust {
  border-block: 1px solid var(--line);
  background: var(--surface-1);
}
.trust ul {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.trust li {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: 1.75rem clamp(.75rem, 2vw, 1.5rem);
  border-inline-start: 1px solid var(--line);
}
.trust li:first-child { border-inline-start: 0; }
.trust svg { width: 26px; height: 26px; color: var(--yellow); flex: none; }
.trust b { display: block; font-size: var(--fs-sm); font-weight: 800; line-height: 1.25; }
.trust span { font-size: var(--fs-xs); color: var(--text-3); }

/* --------------------------------------------------------------- products */

.grid-products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 268px), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

/* Centred under the grid rather than aligned with the heading: the row of cards
   is symmetrical, and a link hanging off its left edge reads as a caption on the
   first card instead of a way out of the section. */
.products-all {
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  text-align: center;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
  transition: border-color .3s, transform .3s var(--ease), box-shadow .3s;
}
.card:hover {
  transform: translateY(-4px);
  border-color: rgba(254,245,24,.45);
  box-shadow: var(--shadow-md), var(--glow-yellow);
}
/* --------------------------------------------- one frame for every product

   The home page, the range, the related strip and the finder's results all
   draw their photograph through this one block, so a product looks the same
   wherever it is shown. Edge to edge: the photographs are shot on their own
   white sweep, so a dark card with 12% padding around them read as a small
   picture floating in a box rather than as a product. Filling the frame also
   makes a row of cards line up at the same visual weight, which `contain`
   never does with mixed crops. */
.pmedia {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  background: #FFFFFF;
  overflow: hidden;
}
.pmedia img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.card:hover .pmedia img,
.tile:hover .pmedia img,
.related:hover .pmedia img,
.fit-card:hover .pmedia img { transform: scale(1.07); }

@media (prefers-reduced-motion: reduce) {
  .pmedia img { transition: none; }
  .card:hover .pmedia img,
  .tile:hover .pmedia img,
  .related:hover .pmedia img,
  .fit-card:hover .pmedia img { transform: none; }
}

/* The lighting position, in its own colour.

   `z-index` is the whole reason this rule has one: on hover the photograph
   gets a transform, which puts it in the same painting layer as this
   absolutely positioned badge — and being later in the markup it painted over
   it, so the badge appeared to vanish under the mouse. Raising the badge one
   step keeps it where it was.

   The colour comes from --pos, set per position below. Everything else about
   the badge is identical across positions so a row of mixed cards still reads
   as one set. */
.ptag {
  position: absolute;
  top: .7rem; left: .7rem;
  z-index: 2;
  display: inline-flex; align-items: center; gap: .35rem;
  max-width: calc(100% - 1.4rem);
  padding: .3rem .6rem;
  border-radius: var(--r-pill);
  background: rgba(8,10,13,.82);
  border: 1px solid color-mix(in srgb, var(--pos, #9aa3ad) 55%, transparent);
  box-shadow: 0 2px 10px rgba(0,0,0,.45);
  backdrop-filter: blur(8px);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  color: var(--pos, var(--text-2));
}
.ptag .ico { width: 13px; height: 13px; flex: none; color: currentColor; }

/* The same badge on a 44-64px photograph: the basket, the checkout summary,
   a search result. A pill with "Low beam" written in it would be wider than
   the picture, so the word goes and the colour does the work — which is the
   half of the badge that is recognisable at a glance anyway. The name is
   never lost: every one of these rows has the position in its own title. */
.ptag.is-mini {
  top: 3px; left: 3px;
  gap: 0;
  max-width: none;
  padding: 3px;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0,0,0,.5);
}
.ptag.is-mini .ico { width: 12px; height: 12px; }

/* The frames those small photographs sit in. Both are inline wrappers whose
   only job is to be the thing the badge is positioned against — an <img>
   cannot contain one. */
.search-media,
.co-media { position: relative; display: block; flex: none; line-height: 0; }

/* Beam colours, chosen to read on the white sweep behind them and to stay
   distinguishable from each other rather than to be literal: the indicators
   are the amber they really are, the headlight pair splits cold blue (low)
   from the brand yellow (high). */
.ptag[data-pos="low_beam"]        { --pos: #5AA9FF; }
.ptag[data-pos="high_beam"]       { --pos: #FEF518; }
.ptag[data-pos="fog_light"]       { --pos: #34D399; }
.ptag[data-pos="drl"]             { --pos: #C084FC; }
.ptag[data-pos="parking_light"]   { --pos: #2DD4BF; }
.ptag[data-pos="reverse_light"]   { --pos: #E8EDF5; }
.ptag[data-pos="indicator_front"] { --pos: #FB923C; }
.ptag[data-pos="indicator_rear"]  { --pos: #F87171; }
.ptag[data-pos="interior"]        { --pos: #F472B6; }
.ptag[data-pos="license_plate"]   { --pos: #A5B4FC; }

.card-body { display: flex; flex-direction: column; gap: .85rem; padding: 1.25rem; flex: 1; }
/* The card clips what it cannot fit, so a word wider than the card is not an
   untidy overhang but a truncated product name: German "Nebelscheinwerfer" and
   Greek "λεπτομέρειες" are both wider than a half-width card at 320px. `break-word`
   rather than `anywhere` on purpose — it breaks the word only once the line has
   run out, and leaves intrinsic sizing alone, so wider screens are untouched. */
.card-title {
  font-family: var(--font-display); font-size: 1.25rem; font-weight: 700;
  letter-spacing: -.01em; overflow-wrap: break-word;
}
.card-sub { font-size: var(--fs-xs); color: var(--text-3); margin-top: -.5rem; }

.spec-row { display: flex; flex-wrap: wrap; gap: .4rem; }
.spec {
  padding: .3rem .55rem;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-2);
}
.spec.is-key { color: var(--yellow); background: var(--yellow-wash); }

.card-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.card-foot .btn { white-space: nowrap; padding: 0 1rem; min-height: 46px; }
.price { font-family: var(--font-display); font-size: 1.4rem; font-weight: 700; }
.price small { font-size: .8rem; color: var(--text-3); font-weight: 600; }

/* ----------------------------------------------------------- why / values */

.grid-why { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); gap: 1.25rem; }
.why {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  transition: border-color .3s, background .3s;
}
.why:hover { border-color: var(--line-strong); background: var(--surface-2); }
.why-icon {
  display: grid; place-items: center;
  width: 52px; height: 52px;
  margin-bottom: 1.25rem;
  border-radius: var(--r-md);
  background: var(--yellow-wash);
  color: var(--yellow);
}
.why-icon svg { width: 26px; height: 26px; }
.why h3 { font-size: 1.2rem; margin-bottom: .6rem; }
.why p { font-size: var(--fs-sm); color: var(--text-2); }

/* -------------------------------------------------------------- split rows */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
}
.split + .split { margin-top: var(--section); }
.split.is-flipped .split-media { order: -1; }
.split-media {
  border-radius: var(--r-2xl);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}
.split-media img { width: 100%; }
.split-copy h2 { font-size: var(--fs-h2); margin: 1rem 0 1.1rem; }
.split-copy p { color: var(--text-2); font-size: var(--fs-lead); }
.split-list { margin-top: 1.75rem; display: grid; gap: .85rem; }
.split-list li { display: flex; gap: .75rem; align-items: flex-start; font-size: var(--fs-sm); color: var(--text-2); }
.split-list svg { width: 18px; height: 18px; color: var(--yellow); flex: none; margin-top: .22rem; }

/* ---------------------------------------------------------- before/after */

.compare {
  position: relative;
  border-radius: var(--r-2xl);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lg);
  /* The box is the frame: both halves are the same 16:9 night shot, so any
     other ratio here is `cover` throwing away road on the left and right. */
  aspect-ratio: 16 / 9;
  cursor: ew-resize;
  user-select: none;
  touch-action: pan-y;
}
.compare img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The "after" layer is clipped by a CSS variable the drag handler updates. */
.compare .after { clip-path: inset(0 0 0 var(--split, 50%)); }
.compare-handle {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--split, 50%);
  width: 2px;
  background: var(--yellow);
  box-shadow: 0 0 22px rgba(254,245,24,.75);
  pointer-events: none;
}
/* The knob is ::before, not ::after, so the direction arrows — real markup
   inside the handle — paint on top of it without needing a z-index. */
.compare-handle::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 52px; height: 52px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--yellow);
  box-shadow: 0 6px 26px rgba(0,0,0,.6);
}
/* Two triangles inside the knob: without them the yellow dot reads as a
   decoration rather than as something you are meant to grab and pull. */
.compare-arrows {
  position: absolute;
  top: 50%; left: 50%;
  width: 34px; height: 17px;
  /* The handle itself is a 2px line, and the global `svg { max-width: 100% }`
     would squeeze the arrows down to those two pixels. */
  max-width: none;
  transform: translate(-50%, -50%);
  fill: var(--bg);
}
/* A three-beat nudge says "drag me" once and then gets out of the way. It is
   hung off the reveal class so it plays when the slider scrolls into view
   rather than unseen at the top of the page. The global reduced-motion rule
   already stops it for anyone who asked. */
.compare.is-in .compare-arrows path:first-child { animation: compare-nudge-l 1.6s ease-in-out 3; }
.compare.is-in .compare-arrows path:last-child  { animation: compare-nudge-r 1.6s ease-in-out 3; }
@keyframes compare-nudge-l {
  0%, 60%, 100% { transform: none; }
  30%           { transform: translateX(-1.6px); }
}
@keyframes compare-nudge-r {
  0%, 60%, 100% { transform: none; }
  30%           { transform: translateX(1.6px); }
}
.compare-label {
  position: absolute;
  top: 1.1rem;
  padding: .4rem .85rem;
  border-radius: var(--r-pill);
  background: rgba(8,10,13,.78);
  backdrop-filter: blur(10px);
  border: 1px solid var(--line-strong);
  font-size: var(--fs-xs);
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.compare-label.left  { left: 1.1rem; color: var(--text-2); }
.compare-label.right { right: 1.1rem; color: var(--yellow); }

/* ------------------------------------------------------------------ steps */

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 1.25rem; counter-reset: step; }
.step {
  position: relative;
  padding: 2.25rem 1.5rem 1.75rem;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
}
.step::before {
  counter-increment: step;
  content: '0' counter(step);
  position: absolute;
  top: 1.1rem; right: 1.25rem;
  font-family: var(--font-display);
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--line-strong);
}
.step h3 { font-size: 1.05rem; margin-bottom: .5rem; }
.step p { font-size: var(--fs-sm); color: var(--text-2); }

/* ------------------------------------------------------------------- CANBUS */

.tech {
  position: relative;
  border-radius: var(--r-2xl);
  overflow: hidden;
  border: 1px solid var(--line);
  background:
    radial-gradient(ellipse at 78% 50%, var(--blue-wash), transparent 62%),
    var(--surface-1);
}
.tech-inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; gap: clamp(2rem, 4vw, 4rem); padding: clamp(2rem, 5vw, 4.5rem); }
.tech-inner img { border-radius: var(--r-lg); }
.tech-title { font-size: var(--fs-h2); margin: 1rem 0 1.1rem; }

/* --------------------------------------------------------------------- FAQ */

/* The accordion used to be a centred 860px column inside a full-width
   section, which gave the page a fourth left edge. It now shares the section
   with its heading: heading on the left, questions filling the rest, both
   landing exactly on the container. */
.faq { max-width: 860px; margin-inline: auto; }

@media (min-width: 900px) {
  .faq-layout {
    display: grid;
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    gap: clamp(2.5rem, 6vw, 6rem);
    align-items: start;
  }
  .faq-layout .section-head { margin-bottom: 0; position: sticky; top: 7rem; }
  .faq-layout .faq { max-width: none; margin-inline: 0; }
}
.faq details {
  border-bottom: 1px solid var(--line);
}
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.5rem 0;
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.7vw, 1.2rem);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition: color .2s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--yellow); }
.faq summary::after {
  content: '';
  flex: none;
  width: 13px; height: 13px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-3px);
  transition: transform .3s var(--ease);
}
.faq details[open] summary { color: var(--yellow); }
.faq details[open] summary::after { transform: rotate(225deg) translateY(-3px); }
.faq-body { padding-bottom: 1.6rem; color: var(--text-2); font-size: var(--fs-sm); max-width: 68ch; }

/* ------------------------------------------------------------------ CTA band */

.cta-band {
  position: relative;
  border-radius: var(--r-2xl);
  padding: clamp(2.5rem, 6vw, 5rem);
  background:
    radial-gradient(ellipse at 15% 20%, rgba(254,245,24,.13), transparent 58%),
    linear-gradient(140deg, var(--surface-2), var(--surface-1));
  border: 1px solid var(--line-strong);
  overflow: hidden;
}
.cta-title { font-size: var(--fs-h2); margin: 1rem 0 1rem; max-width: 18ch; }
.cta-lead { max-width: 52ch; }
.cta-actions { display: flex; flex-wrap: wrap; gap: .85rem; margin-top: 2rem; }
/* A flex item will not shrink past its longest word unless it is told it may.
   On a 320px screen "Kompatibilität prüfen" and "Έλεγχος συμβατότητας" are each
   wider than the band they sit in, so the button hung 18px out to the right of
   the one stacked below it. Zeroing the floor lets the label take a second line
   instead; the buttons are side by side and nowhere near it above 620px. */
.cta-actions .btn { min-width: 0; }

/* ------------------------------------------------------------- B2B enquiry */

/* One form in two settings: folded under the buy button on a product page, and
   standing on its own as a band on the home page. Everything shared lives here
   once; only the surroundings differ below. */

.b2b-form { display: grid; gap: .55rem; }
.b2b-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.b2b-input {
  flex: 1 1 14rem; min-width: 0; min-height: 46px; padding: 0 .9rem;
  background: var(--surface-1); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); color: var(--text);
}
.b2b-input::placeholder { color: var(--text-3); }
.b2b-input:focus-visible { border-color: var(--yellow); outline: none; }
/* `flex: none` keeps the button at its label's width beside the input instead of
   being squeezed to a stub. On a 320px screen that width can exceed the row —
   "Ζητήστε τιμές χονδρικής" wants 273px of a 226px row — and the button pushed
   the page sideways. The cap lets the label wrap onto a second line at the point
   where it no longer fits; above that width nothing changes. */
.b2b-form .btn { min-height: 46px; flex: none; max-width: 100%; }
.b2b-note { display: flex; gap: .5rem; font-size: var(--fs-xs); color: var(--text-3); }
.b2b-note .ico { width: 14px; height: 14px; margin-top: .15rem; flex: none; }
.b2b-msg { font-size: var(--fs-sm); color: #7BD88F; }
.b2b-msg.is-bad { color: #E8705F; }
/* Sent: there is nothing left to type, and a filled-in field beside a thank-you
   reads as "did that go?" and invites a second press. Hidden, not removed, so
   a later failure can bring the field straight back. */
.b2b-form.is-done .b2b-row,
.b2b-form.is-done .b2b-note { display: none; }

/* --- folded into the product page */

.b2b-inline { margin-top: .4rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.b2b-toggle {
  display: flex; align-items: center; gap: .55rem;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
  cursor: pointer; list-style: none; transition: color .2s;
}
.b2b-toggle::-webkit-details-marker { display: none; }
.b2b-toggle:hover { color: var(--yellow); }
.b2b-toggle .ico { width: 16px; height: 16px; flex: none; }
.b2b-toggle .ico:first-child { color: var(--yellow); }
.b2b-toggle .ico:last-child { margin-left: auto; transition: transform .3s var(--ease); }
.b2b-inline[open] .b2b-toggle { color: var(--yellow); }
.b2b-inline[open] .b2b-toggle .ico:last-child { transform: rotate(180deg); }
.b2b-lead { margin: .8rem 0 .7rem; font-size: var(--fs-xs); color: var(--text-2); }

/* --- the band on the home page */

.b2b-band {
  display: grid; gap: 1.4rem; align-items: center;
  /* minmax(0,1fr), not the implicit auto track: the eyebrow is a whole question
     here rather than the two or three words it is in a section head, and an
     auto track sized to a nowrap string that long pushes the whole column wider
     than the card on a phone. */
  grid-template-columns: minmax(0, 1fr);
  padding: clamp(1.8rem, 4vw, 3rem);
  border: 1px solid var(--line-strong); border-radius: var(--r-2xl);
  background: linear-gradient(140deg, var(--surface-2), var(--surface-1));
}
/* Same reason: let this one wrap. German asks it in five words. */
.b2b-band .eyebrow { white-space: normal; }
@media (min-width: 860px) {
  .b2b-band { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); }
}
.b2b-band h2 { font-size: clamp(1.4rem, 2.8vw, 2rem); margin: .7rem 0 .6rem; max-width: 20ch; }
.b2b-band .b2b-head p { font-size: var(--fs-sm); color: var(--text-2); max-width: 46ch; }

/* --------------------------------------------------------------- X-Series */

/* The one band on this page that sells nothing.
 *
 * It borrows the card treatment the CTA and wholesale bands use — same radius,
 * same border, same gradient family — so it reads as part of the page rather
 * than as an advertisement dropped into it. What it does not borrow is the
 * product grid: no tile, no price line, no hover lift, because none of those
 * would be true yet.
 */

.xseries {
  display: grid;
  gap: clamp(1.8rem, 4vw, 3.5rem);
  align-items: center;
  padding: clamp(1.4rem, 3.5vw, 2.6rem);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2xl);
  background:
    radial-gradient(ellipse at 12% 12%, var(--yellow-wash), transparent 55%),
    linear-gradient(140deg, var(--surface-2), var(--surface-1));
}
/* 980px, not the 860 the wholesale band splits at: this column holds a whole
   paragraph beside the picture rather than a heading and a line, and below
   this width the text sets to about forty characters and falls apart. */
@media (min-width: 980px) {
  .xseries { grid-template-columns: minmax(0, 30rem) minmax(0, 1fr); }
}

/* The packshot is lit on a light grey sweep and is not masked onto the page —
   see scripts/hero-media.mjs. Clipping it to the card's own radius is what
   turns the light rectangle from an oversight into a niche: the picture fills
   the frame corner to corner, so there is no seam where the two backgrounds
   would otherwise meet. */
.xseries-media {
  border-radius: var(--r-lg);
  overflow: hidden;
  /* The sweep's own top-left grey. Visible only in the split second before the
     picture paints, which is exactly when a black hole would be noticed. */
  background: #D9D9DC;
}
.xseries-media img { display: block; width: 100%; height: auto; }

/* Filled, where every other eyebrow on the page is bare text. The distinction
   is the point: this one is not a section label, it is the status of the goods
   in the picture beside it, and it has to survive being skimmed past. */
.xseries-badge {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .4rem .8rem;
  border-radius: 999px;
  background: var(--yellow);
  color: #0B0B06;
  font-size: var(--fs-xs);
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.xseries-badge .ico { width: 14px; height: 14px; }

.xseries-title { font-size: clamp(1.5rem, 3vw, 2.3rem); margin: 1rem 0 .7rem; max-width: 20ch; }
.xseries-lead { max-width: 46ch; }
.xseries-body { margin-top: .9rem; font-size: var(--fs-sm); color: var(--text-2); max-width: 60ch; }

/* Same shape as the wholesale form and deliberately not the same rules: that
   one sits in a narrow column beside a heading, this one runs the full width
   of a text column, and sharing a class would mean every later change to
   either having to be true of both. */
.xseries-form { display: grid; gap: .55rem; margin-top: 1.6rem; max-width: 34rem; }
.xseries-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.xseries-input {
  flex: 1 1 14rem; min-width: 0; min-height: 48px; padding: 0 .9rem;
  background: var(--surface-1); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); color: var(--text);
}
.xseries-input::placeholder { color: var(--text-3); }
.xseries-input:focus-visible { border-color: var(--yellow); outline: none; }
.xseries-form .btn { min-height: 48px; flex: none; }
.xseries-note { display: flex; gap: .5rem; font-size: var(--fs-xs); color: var(--text-3); }
.xseries-note .ico { width: 14px; height: 14px; margin-top: .15rem; flex: none; }
.xseries-msg { font-size: var(--fs-sm); color: #7BD88F; }
.xseries-msg.is-bad { color: #E8705F; }
/* On the list: the field and its small print go, the sentence stays. Hidden
   rather than removed, so a later failure can bring the field back. */
.xseries-form.is-done .xseries-row,
.xseries-form.is-done .xseries-note { display: none; }

/* Quiet on purpose. It is the right link for a minority of the people reading
   this band, and competing with the button would cost more signups than it
   would win enquiries — there is a whole band for those further down. */
.xseries-trade {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin-top: 1.4rem;
  font-size: var(--fs-sm);
  color: var(--text-2);
  transition: color .2s;
}
.xseries-trade:hover { color: var(--yellow); }
.xseries-trade .ico { width: 16px; height: 16px; color: var(--yellow); }
/* inline-block because transform does not apply to an inline box, and the
   arrow now lives inside the label so it cannot be pulled off the last word. */
.xseries-arrow { display: inline-block; transition: transform .2s var(--ease); }
.xseries-trade:hover .xseries-arrow { transform: translateX(3px); }

/* ------------------------------------------------------------------ footer */

.footer { border-top: 1px solid var(--line); background: var(--surface-1); padding-block: clamp(3rem, 6vw, 5rem) 2rem; }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); gap: clamp(2rem, 4vw, 3.5rem); }
.footer-brand img { height: 44px; width: auto; margin-bottom: 1.1rem; }
.footer-brand p { font-size: var(--fs-sm); color: var(--text-3); max-width: 34ch; }
.footer h4 {
  font-size: var(--fs-xs);
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 1.1rem;
}
.footer li + li { margin-top: .65rem; }
.footer ul a {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-size: var(--fs-sm);
  color: var(--text-2);
  transition: color .2s;
}
.footer ul a .ico { width: 16px; height: 16px; color: var(--text-3); transition: color .2s, transform .2s var(--ease); }
.footer ul a:hover { color: var(--yellow); }
.footer ul a:hover .ico { color: var(--yellow); transform: translateX(2px); }
.footer-bottom {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.footer-credit {
  margin-top: .9rem;
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.footer-credit a {
  color: var(--text-2);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color .2s;
}
.footer-credit a:hover { color: var(--yellow); }

/* ------------------------------------------------------------ scroll reveal */

.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------- responsive */

@media (max-width: 1080px) {
  .trust ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .trust li:nth-child(3n+1) { border-inline-start: 0; }
  .trust li:nth-child(n+4) { border-top: 1px solid var(--line); }
  .footer-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

@media (max-width: 1100px) {
  .nav, .header-actions .btn { display: none; }
  .burger { display: grid; }
  .header-actions { margin-inline-start: auto; }
}

@media (max-width: 900px) {
  .finder-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .split, .tech-inner { grid-template-columns: minmax(0, 1fr); }
  .split.is-flipped .split-media { order: 0; }
}

@media (max-width: 620px) {
  .header-inner { min-height: 72px; }
  /* Search has no destination yet on small screens and the row is tight. */
  .header-actions > .icon-btn:not(.burger):first-of-type { display: none; }
  .lang > summary { padding: 0 .4rem; }
  .lang-code { display: none; }
  /* The hero's own layout is settled at 1023px and is the same all the way
     down. The headline's bite scales with the headline and needs nothing here;
     the pills are a fixed height at every width, so theirs does. */
  .hero { padding-bottom: 2.5rem; }
  .hero-bullets { margin-top: -1rem; }
  .finder-row { grid-template-columns: minmax(0, 1fr); }
  .trust ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .trust li { border-inline-start: 0; border-top: 1px solid var(--line); padding: 1.35rem 1rem; }
  .trust li:nth-child(-n+2) { border-top: 0; }
  .grid-products { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .75rem; }
  .card-body { padding: .9rem; gap: .6rem; }
  .card-title { font-size: 1.05rem; }
  .price { font-size: 1.15rem; }
  .card-foot { flex-direction: column; align-items: stretch; }
  /* Two cards per row leaves ~170px; longer locales need the label to breathe.
     The nowrap that keeps "View details" off two lines next to the price has to
     go with the row it was protecting: stacked and stretched, the label has the
     full card to wrap into, and holding it on one line only clipped it — Greek
     "Δες λεπτομέρειες" wants 124px of a 101px button. */
  .card-foot .btn {
    padding: .6rem .7rem; font-size: .8125rem; line-height: 1.2;
    text-align: center; white-space: normal;
  }
  /* A 16:9 box is ~200px tall on a phone, too short to read the beam in. 3:2
     buys back the height for the price of a little road off each side —
     the deer and the centre line, which are what the slider is about, are
     nowhere near the edges. */
  .compare { aspect-ratio: 3 / 2; }
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Two cards across a 320px screen leaves the button 101px, a quarter of which is
   its own padding. Greek "λεπτομέρειες" is a single 88px word with 78px to stand
   in, and the card clips what will not fit. Hand the padding back rather than
   break a word that has no break in it — the smallest phone only. */
@media (max-width: 380px) {
  .card-foot .btn { padding: .6rem .35rem; }
  /* The arrow is aria-hidden decoration that does not shrink, and with its gap
     it costs 26 of the 101px the button has. Greek "λεπτομέρειες" needs those
     back — the card clips the difference otherwise. The label says where the
     link goes; the arrow only repeated it. */
  .card-foot .btn .ico { display: none; }
}

/* Mobile nav sheet.
   It hangs off the bottom edge of the main header and ranks below it, so the
   site's own header — logo, basket, language — stays put and keeps working
   while the menu is open. */
.mobile-nav {
  position: fixed;
  inset: calc(var(--announce-h, 0px) + var(--header-h, 0px)) 0 0 0;
  z-index: 90;
  background: rgba(8,10,13,.98);
  backdrop-filter: blur(20px);
  padding: 1.25rem 0 max(2rem, env(safe-area-inset-bottom));
  display: none;
  flex-direction: column;
  gap: 1.25rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.mobile-nav.is-open { display: flex; }
/* The header is only frosted once the page has scrolled; with the sheet open
   it has the menu directly behind it and has to be solid from the first pixel. */
body.nav-open .header {
  background: rgba(8,10,13,.98);
  backdrop-filter: blur(20px);
  border-bottom-color: var(--line);
}
.burger .burger-close { display: none; }
.burger[aria-expanded="true"] .burger-open { display: none; }
.burger[aria-expanded="true"] .burger-close { display: block; }
.mobile-nav-links a {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
}
.mobile-nav-links a .ico { width: 20px; height: 20px; color: var(--yellow); }
.mobile-nav-foot { margin-top: auto; padding-top: 1.5rem; }
.mobile-nav-foot .btn { width: 100%; }
.mobile-nav-foot .lang-row { justify-content: center; }

/* ------------------------------------------------------------- back to top */

.to-top {
  position: fixed;
  right: var(--edge);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 150;
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: rgba(16,19,24,.9);
  backdrop-filter: blur(12px);
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity .3s, transform .3s var(--ease), visibility .3s, border-color .2s, color .2s;
}
.to-top.is-visible { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { border-color: var(--yellow); color: var(--yellow); }
.to-top .ico { width: 20px; height: 20px; }

/* The finder button must never wrap its label onto a second line. */
.finder-submit .btn { white-space: nowrap; }
/* ------------------------------------------------------------------ consent
 *
 * A module that floats above the page rather than a strip welded to the
 * bottom of the window. It reads as a piece of hardware resting on the dark:
 * machined edge, deep shadow, and a single filament of SunX yellow along the
 * top — the one place this component is allowed to be loud, and the one that
 * is literally the product.
 *
 * It only exists once the head stub has decided there is no stored choice.
 * With JavaScript off it never appears, which is correct: with JavaScript off
 * nothing here can write non-essential storage either.
 *
 * Accept and Reject share one class and one set of rules. No variant, no
 * override, no extra weight on the one we would prefer you clicked. The only
 * difference between those two buttons is the text inside them.
 */

[hidden] { display: none !important; }

/*
 * LAYER ORDER. One ladder for the whole site, declared in one place, because
 * the failure it fixes was invisible in any single rule: the cart drawer and
 * the consent bar both sat at 300, so DOM order decided, and the drawer — last
 * in the body — painted over the "Reject non-essential" button. Consent cannot
 * be a matter of who happens to be written last.
 *
 *    100  header          260  announce bar
 *    150  back to top     290  drawer scrim
 *    200  mobile nav      300  cart drawer, search overlay
 *   1000  consent bar     — above everything, unconditionally
 *
 * The preferences dialog is a modal <dialog>: the top layer puts it above all
 * of this without a number.
 */

.cbar { display: none; }
html[data-consent="pending"] .cbar {
  display: block;
  position: fixed;
  inset: auto 0 0 0;
  z-index: 1000;
  /* Same gutter as every .shell on the page, so the card's edge is the
     container's edge and not a fourth one. */
  padding: 0 var(--edge) calc(var(--gutter) + env(safe-area-inset-bottom));
  /* The frame is only a positioning device; the page behind its margins stays
     clickable. */
  pointer-events: none;
}

.cbar-inner {
  pointer-events: auto;
  position: relative;
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.15rem clamp(1.25rem, 2.4vw, 2.25rem);
  padding: clamp(1.1rem, 2.2vw, 1.6rem) clamp(1.15rem, 2.4vw, 2rem);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2xl);
  background: linear-gradient(180deg, rgba(23, 27, 33, .96), rgba(13, 16, 20, .96));
  backdrop-filter: blur(20px) saturate(140%);
  /* Two shadows and one inset hairline: the drop separates it from the page,
     the glow gives it a little warmth, the inset catches light on the edge. */
  box-shadow:
    0 32px 70px -24px rgba(0, 0, 0, .9),
    0 2px 10px -4px rgba(0, 0, 0, .7),
    inset 0 1px 0 rgba(255, 255, 255, .07);
  animation: cbar-rise .42s var(--ease) both;
}

/* The filament: a lit strip along the top edge, brightest above the mark and
   spent by the halfway point. One accent, and it is the product itself. */
.cbar-inner::before {
  content: '';
  position: absolute;
  inset: -1px auto auto 5%;
  width: 52%;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg,
    rgba(254, 245, 24, 0) 0%,
    rgba(254, 245, 24, .95) 20%,
    rgba(254, 245, 24, .45) 58%,
    rgba(254, 245, 24, 0) 100%);
  box-shadow: 0 0 12px rgba(254, 245, 24, .32);
}

@keyframes cbar-rise {
  from { opacity: 0; transform: translateY(1.5rem); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cbar-inner { animation: none; }
}

/* Basis kept small enough that the copy and the actions still share a row at
   desktop widths; the copy grows into whatever is left over. */
.cbar-copy { flex: 1 1 22rem; min-width: 0; }

.cbar-copy h2 {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin: 0 0 .45rem;
  font-family: var(--font-body);
  font-size: 1.125rem;
  font-weight: 800;
  letter-spacing: -.015em;
  color: var(--text);
}

/* The icon gets its own lit disc — the only filled shape in the bar. */
.cbar-mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, rgba(254, 245, 24, .3), rgba(254, 245, 24, .05) 72%);
  box-shadow: inset 0 0 0 1px rgba(254, 245, 24, .3), 0 0 24px -9px rgba(254, 245, 24, .95);
  color: var(--yellow);
}
.cbar-mark .ico { width: 17px; height: 17px; }

/* --text-2, not --text-3: the paler grey measures under 4.5:1 on this
   surface, and legal copy is the last place to spend contrast. */
.cbar-copy p {
  margin: 0;
  max-width: 62ch;
  font-size: .9rem;
  line-height: 1.65;
  color: var(--text-2);
}
.cbar-copy a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.cbar-copy a:hover { color: var(--yellow); }

.cbar-gpc {
  display: flex;
  align-items: flex-start;
  gap: .55rem;
  margin-top: .75rem !important;
  padding: .6rem .8rem;
  border: 1px solid rgba(0, 144, 255, .3);
  border-radius: var(--r-md);
  background: var(--blue-wash);
  color: var(--text-2);
  font-size: .8125rem;
  line-height: 1.55;
}
.cbar-gpc .ico { color: var(--blue); margin-top: .2rem; flex: none; }

/* Two equal tracks plus one that sizes to its text. Equal `fr` tracks in an
   auto-width grid both resolve to the wider label, so Accept and Reject come
   out exactly the same size in every language without a magic number. */
.cbar-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: .6rem;
  flex: 0 1 auto;
}

/* ---------------------------------------------------------------- buttons */

/* Both decision buttons. Equal weight by construction, not by eye. */
.cbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 52px;
  min-width: 10.5rem;
  padding: 0 1.5rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: linear-gradient(180deg, rgba(46, 52, 62, .9), rgba(30, 35, 43, .9));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
  color: var(--text);
  font: inherit;
  font-size: .9375rem;
  font-weight: 700;
  letter-spacing: -.005em;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .2s, color .2s, transform .2s var(--ease), box-shadow .2s;
}
.cbtn:hover {
  border-color: var(--yellow);
  color: var(--yellow);
  transform: translateY(-2px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 10px 24px -14px rgba(254, 245, 24, .8);
}

/* On the first layer both decisions are brand yellow. They are yellow
   *together*: the moment only one of them is, the styling starts making the
   choice for the visitor, which is the asymmetry regulators fine. Inside the
   dialog they stay neutral, because there the primary action is Save. */
.cbar .cbtn {
  background: var(--yellow);
  border-color: var(--yellow);
  color: #0A0A0A;
  box-shadow: none;
}
.cbar .cbtn:hover {
  background: #FFF95C;
  border-color: #FFF95C;
  color: #0A0A0A;
  box-shadow: var(--glow-yellow);
}
.cbtn:active { transform: translateY(0); }
.cbtn .ico { width: 17px; height: 17px; }
@media (prefers-reduced-motion: reduce) {
  .cbtn, .cbtn:hover { transform: none; transition: border-color .2s, color .2s; }
}

/* Save confirms whatever the switches already say, and competes with nothing
   on the first layer — it only exists inside a dialog you chose to open. */
.cbtn-save {
  background: var(--yellow);
  border-color: var(--yellow);
  color: #000;
  box-shadow: none;
}
.cbtn-save:hover {
  background: #FFF95C;
  border-color: #FFF95C;
  color: #000;
  box-shadow: var(--glow-yellow);
}

.clink {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 52px;
  padding: 0 .85rem;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: .9375rem;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  white-space: nowrap;
  cursor: pointer;
  transition: color .2s;
}
.clink:hover { color: var(--yellow); }
.clink .ico { width: 16px; height: 16px; }

/* ----------------------------------------------------------------- dialog */

.cdlg {
  position: fixed;
  inset: 0;
  /* Centred explicitly: the UA's margin:auto only centres vertically when the
     height is definite, and this dialog is content-sized. */
  margin: auto;
  width: min(660px, calc(100vw - 2rem));
  height: fit-content;
  max-height: min(84vh, 860px);
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2xl);
  background: var(--surface-1);
  color: var(--text);
  box-shadow: 0 40px 100px -30px rgba(0, 0, 0, .95), inset 0 1px 0 rgba(255, 255, 255, .06);
  overflow: hidden;
}
.cdlg[open] { display: flex; flex-direction: column; }
.cdlg::backdrop { background: rgba(8, 10, 13, .8); backdrop-filter: blur(6px); }

.cdlg-grip { display: none; }

.cdlg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem clamp(1.15rem, 3vw, 1.75rem) 1.1rem;
  border-bottom: 1px solid var(--line);
}
.cdlg-head h2 {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.1875rem;
  font-weight: 800;
  letter-spacing: -.02em;
}

.cdlg-intro,
.cdlg .cbar-gpc {
  margin: 1.1rem clamp(1.15rem, 3vw, 1.75rem) 0;
  font-size: .875rem;
  line-height: 1.65;
  color: var(--text-2);
}

.cdlg-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1.1rem clamp(1.15rem, 3vw, 1.75rem) 1.35rem;
}

/* One panel with hairline rules, not four identical cards stacked. The rules
   say "these are four rows of the same list"; four cards would say "these are
   four unrelated things". */
.ccats {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  overflow: hidden;
}
.ccat { padding: 1.05rem clamp(.9rem, 2.4vw, 1.15rem); }
.ccat + .ccat { border-top: 1px solid var(--line); }

.ccat-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.25rem; }
.ccat-text h3 {
  margin: 0 0 .3rem;
  font-family: var(--font-body);
  font-size: .9375rem;
  font-weight: 800;
  letter-spacing: -.01em;
}
.ccat-text p { margin: 0; font-size: .8125rem; line-height: 1.6; color: var(--text-2); }
.ccat-control { flex: none; padding-top: .1rem; }

.ccat-locked {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .32rem .7rem;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text-2);
  font-size: .75rem;
  font-weight: 700;
  white-space: nowrap;
}
.ccat-locked .ico { width: 14px; height: 14px; }

/* A real checkbox, visually restyled — so it keeps its role, its label and
   its keyboard behaviour instead of a div pretending to be a switch. */
.cswitch { display: inline-flex; align-items: center; cursor: pointer; }
.cswitch input,
.cswitch-label {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.cswitch-ui {
  display: block;
  position: relative;
  width: 50px; height: 28px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--bg);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .6);
  transition: background .22s, border-color .22s;
}
.cswitch-ui::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--text-2);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .6);
  transition: transform .22s var(--ease), background .22s;
}
.cswitch input:checked + .cswitch-ui {
  background: var(--yellow);
  border-color: var(--yellow);
  box-shadow: 0 0 20px -6px rgba(254, 245, 24, .7);
}
.cswitch input:checked + .cswitch-ui::after { transform: translateX(22px); background: #0A0A0A; }
.cswitch input:focus-visible + .cswitch-ui { outline: 2px solid var(--yellow); outline-offset: 3px; }
.cswitch:hover .cswitch-ui { border-color: var(--yellow); }
@media (prefers-reduced-motion: reduce) {
  .cswitch-ui, .cswitch-ui::after { transition: none; }
}

.ccat-details { margin-top: .85rem; border-top: 1px solid var(--line); padding-top: .7rem; }
/* The default marker is dropped for a chevron that turns, so the row still
   announces itself as something that opens. Without one this reads as a
   caption and nobody finds the cookie table. */
.ccat-details summary {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  cursor: pointer;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--text-2);
  transition: color .2s;
  list-style: none;
}
.ccat-details summary::-webkit-details-marker { display: none; }
.ccat-details summary::after {
  content: '';
  width: 6px; height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  border-radius: 1px;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .22s var(--ease);
}
.ccat-details[open] summary::after { transform: translateY(1px) rotate(-135deg); }
.ccat-details summary:hover { color: var(--yellow); }
@media (prefers-reduced-motion: reduce) {
  .ccat-details summary::after { transition: none; }
}
.ccat-empty { margin: .65rem 0 0; font-size: .8125rem; color: var(--text-2); }

.ctable-wrap {
  overflow-x: auto;
  margin-top: .7rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.ctable { width: 100%; min-width: 32rem; border-collapse: collapse; font-size: .75rem; }
.ctable th, .ctable td { padding: .55rem .65rem; text-align: left; vertical-align: top; }
.ctable thead th { background: var(--surface-3); color: var(--text); font-weight: 700; white-space: nowrap; }
.ctable tbody tr + tr td { border-top: 1px solid var(--line); }
.ctable td { color: var(--text-2); }
.ctable code { color: var(--text); font-size: .75rem; }
.ctable tr.is-inactive td { opacity: .62; }
.ctag {
  display: inline-block;
  padding: .06rem .4rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  font-size: .625rem;
  letter-spacing: .02em;
}

.cdlg-foot {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  padding: 1.1rem clamp(1.15rem, 3vw, 1.75rem) calc(1.1rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--surface-1);
}
.cdlg-foot .cbtn { flex: 1 1 10rem; min-width: 0; }

/* Placeholder standing in for a third-party embed until its category is
   allowed. Nothing uses it yet; it ships so the first embed has somewhere
   correct to go. */
.cembed {
  display: grid;
  place-items: center;
  gap: .75rem;
  min-height: 12rem;
  padding: 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  color: var(--text-2);
  text-align: center;
  font-size: .875rem;
}
.cembed.is-loaded { display: block; min-height: 0; padding: 0; border: 0; background: none; }
.cembed.is-loaded > .cembed-note { display: none; }

/* The only control in the footer that is a button rather than a link, and at the
   footer's font size its line box came to 21px — under the 24px floor a finger
   needs. The height is on the box, not on the text, so the label does not move. */
.footer-consent {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color .2s;
}
.footer-consent:hover { color: var(--yellow); }
.footer-consent .ico { width: 16px; height: 16px; }

/* The module owns the bottom of the screen while it is up. */
html[data-consent="pending"] .to-top { bottom: clamp(13rem, 32vh, 17rem); }

/* ------------------------------------------------------------- responsive */

/* Copy and actions stop fitting on one line: actions move under the copy and
   keep the two decisions side by side. */
@media (max-width: 1079px) {
  .cbar-copy { flex: 1 1 100%; }
  .cbar-actions { display: flex; flex-wrap: wrap; width: 100%; justify-content: flex-start; }
  .cbtn { flex: 1 1 14rem; min-width: 0; }
  .clink { margin-left: auto; }
}

/* Tablet and large phones: the two decisions share a row, Manage sits under
   them across the full width so it never looks like a third option. */
@media (max-width: 759px) {
  .cbar-actions { gap: .55rem; }
  .cbtn { flex: 1 1 calc(50% - .3rem); min-width: 0; padding: 0 1rem; }
  .clink { flex: 1 1 100%; margin-left: 0; justify-content: center; min-height: 44px; }
}

/* Phones: one column, full-width targets, and the dialog becomes a sheet that
   rises from the bottom edge. */
@media (max-width: 619px) {
  .cbar-inner {
    max-height: 76vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    border-radius: 26px;
    padding: 1.15rem 1.1rem 1.25rem;
    gap: 1rem;
  }
  .cbar-copy h2 { font-size: 1rem; }
  .cbar-copy p { font-size: .8438rem; }
  .cbtn { flex: 1 1 100%; }
  html[data-consent="pending"] .to-top { display: none; }

  .cdlg {
    inset: auto 0 0 0;
    margin: 0;
    width: 100%;
    max-width: 100%;
    height: auto;
    max-height: 92dvh;
    border-width: 1px 0 0;
    border-radius: 26px 26px 0 0;
    padding-bottom: env(safe-area-inset-bottom);
    animation: cdlg-sheet .32s var(--ease) both;
  }
  @keyframes cdlg-sheet { from { transform: translateY(100%); } to { transform: none; } }
  .cdlg-grip {
    display: block;
    width: 38px; height: 4px;
    margin: .6rem auto -.2rem;
    border-radius: var(--r-pill);
    background: var(--line-strong);
  }
  .cdlg-head { padding-top: .9rem; }
  .ccat-head { flex-direction: column; gap: .7rem; }
  .cdlg-foot .cbtn { flex: 1 1 100%; }

  /* A five-column table on a phone is a sideways scroll nobody performs.
     Each row becomes a labelled stack instead. */
  .ctable-wrap { overflow-x: visible; border: 0; border-radius: 0; }
  .ctable { min-width: 0; }
  .ctable thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ctable tr {
    display: block;
    margin-top: .6rem;
    padding: .7rem .8rem;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--surface-1);
  }
  .ctable tbody tr + tr td { border-top: 0; }
  .ctable td { display: flex; gap: .75rem; padding: .22rem 0; }
  .ctable td::before {
    content: attr(data-th);
    flex: none;
    width: 5.5rem;
    color: var(--text);
    font-weight: 700;
  }
}

/* Reject and Accept share the sheet's first row; Save takes the one below, so
   the footer costs two rows instead of three. */
@media (min-width: 400px) and (max-width: 619px) {
  .cdlg-foot .cbtn { flex: 1 1 calc(50% - .3rem); }
  .cdlg-foot .cbtn-save { flex: 1 1 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .cdlg { animation: none; }
}

/* Smallest phones still in use: trim the padding, not the tap targets. */
@media (max-width: 379px) {
  .cbar-inner { padding: 1rem .9rem 1.1rem; border-radius: 22px; }
  .cbar-copy h2 { gap: .55rem; font-size: .9375rem; }
  .cbar-mark { width: 30px; height: 30px; }
  .cbar-copy p { font-size: .8125rem; line-height: 1.6; }
  .cbtn { font-size: .9rem; padding: 0 .85rem; }
}

/* Below 360px the hero headline is wide enough to overflow its own box —
   "CONFIDENCE." at 36.8px does not fit 280px of content width. Scoped to the
   widths that actually break so 360 and up keep the size they were designed at. */
@media (max-width: 359px) {
  .hero h1 { font-size: clamp(1.9rem, 9.6vw, 2.3rem); }
}

/* ---------------------------------------------------------------- contact */

/* Three cards: how to reach us, what to send when you ask about a car, and
   the statutory identification. The last one is the imprint — it has to be
   readable, so it gets --text-2 rather than the --text-3 that the earlier
   audit measured at 3.9:1 against this surface. */

.contact-grid {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 760px)  { .contact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .contact-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.contact-card {
  display: flex;
  flex-direction: column;
  gap: .85rem;
  padding: clamp(1.4rem, 2.6vw, 2rem);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  color: var(--text-2);
  transition: border-color .3s, transform .3s var(--ease);
}
.contact-card:hover { border-color: var(--line-strong); transform: translateY(-3px); }
/* Inline rather than a flex row, because a flex row makes the text an anonymous
   item with an automatic minimum of its longest word, and German
   "Unternehmensangaben" is wider than the card at 320px — that minimum was
   pushing the whole page sideways. Inline, the word simply takes the next line,
   and `hyphens` breaks it at a real syllable on the narrowest phones where even
   a line of its own is not enough.

   `overflow-wrap` underneath it, as a floor rather than as the answer: it
   breaks the word anywhere it likes, and the card reads "Unternehmensang /
   aben". That is the lesser of the two evils it sits between, because
   `hyphens: auto` needs a hyphenation dictionary for the language and a browser
   that has none simply ignores it — WebKit here renders the word whole at
   267px in a 233px card and pushes the entire page 16px sideways at 320px. The
   two do not fight: a hyphenation opportunity is an ordinary break opportunity,
   so `break-word` only ever fires on a line that had none, and measuring the
   heading before and after on both engines showed it changing nothing at all
   where the word was already being hyphenated. */
.contact-card h3 {
  position: relative;
  padding-inline-start: calc(18px + .5rem);
  font-size: 1.15rem;
  color: var(--text);
  hyphens: auto;
  overflow-wrap: break-word;
}
/* Lifted out of the line so the text keeps the same width on every line — the
   flex row it replaces indented the wrapped lines the same way, and leaving the
   icon in the flow cost the first line its 18px and made German hyphenate on a
   tablet where it had fitted. */
.contact-card h3 .ico { position: absolute; inset-inline-start: 0; top: .1em; color: var(--yellow); }
.contact-card .contact-sub { margin-top: .6rem; scroll-margin-top: calc(var(--announce-h, 0px) + 110px); }
.contact-card .btn { align-self: flex-start; }

.contact-mails { display: grid; gap: .55rem; }
.contact-mail {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .75rem .9rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-1);
  transition: border-color .2s, background .2s;
}
.contact-mail:hover { border-color: var(--yellow); background: var(--surface-3); }
.contact-mail .ico { color: var(--yellow); }
.contact-mail span { display: grid; min-width: 0; }
.contact-mail strong {
  font-size: var(--fs-sm);
  color: var(--text);
  overflow-wrap: anywhere;
}
.contact-mail small { font-size: var(--fs-xs); color: var(--text-2); }

.contact-dl { display: grid; gap: .1rem; }
.contact-dl > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .1rem;
  padding: .55rem 0;
  border-bottom: 1px solid var(--line);
}
.contact-dl > div:last-child { border-bottom: 0; }
.contact-dl dt {
  font-size: var(--fs-xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-2);
}
.contact-dl dd { color: var(--text); overflow-wrap: anywhere; }
@media (min-width: 460px) and (max-width: 759px) {
  .contact-dl > div { grid-template-columns: 13rem minmax(0, 1fr); align-items: baseline; gap: 1rem; }
}

.contact-note {
  display: flex;
  gap: .5rem;
  font-size: var(--fs-xs);
  color: var(--text-2);
}
.contact-note .ico { width: 14px; height: 14px; margin-top: .22rem; color: var(--text-2); }

/* The anchors the footer links land on sit inside a card, so they need the
   sticky chrome cleared or the heading lands underneath the header. */
#contact, #delivery, #warranty {
  scroll-margin-top: calc(var(--announce-h, 0px) + 100px);
}

/* ------------------------------------------------- listing and products */

.section-top { padding-top: clamp(1.5rem, 3vw, 2.5rem); }

.crumbs { margin-bottom: clamp(1.25rem, 3vw, 2rem); font-size: var(--fs-xs); color: var(--text-2); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; list-style: none; padding: 0; }
.crumbs li + li::before { content: '/'; margin-inline-end: .4rem; color: var(--text-3); }
.crumbs a:hover { color: var(--yellow); }
/* 18px of text is 18px of target, and WCAG 2.2 §2.5.8 wants 24. The standard
   exempts a link sitting inside a sentence, where the line height and not the
   author decides its size — but a breadcrumb is not a sentence: the "/" between
   these is a ::before on the <li>, so each link stands alone in its own box.
   Padding grows the box a thumb can hit; the matching negative margin takes the
   growth back out of the layout, so nothing on the page moves. */
.crumbs a { padding-block: .3rem; margin-block: -.3rem; }

.listing-head { max-width: 70ch; }

.listing-tools {
  display: grid;
  gap: 1.1rem;
  padding: clamp(1rem, 2vw, 1.5rem);
  margin-bottom: 1.25rem;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
}
.filter-group { display: grid; gap: .6rem; }
.filter-label {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-2);
}
.filter-label .ico { width: 15px; height: 15px; color: var(--yellow); }
.chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: 40px; padding: 0 .95rem;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: transparent; color: var(--text-2);
  font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
}
.chip:hover { border-color: var(--yellow); color: var(--text); }
.chip[aria-pressed="true"] {
  background: var(--yellow); border-color: var(--yellow);
  color: #0B0B06; font-weight: 800;
}
/* The count beside a filter's name. At .7 the inherited --text-2 composited
   down to 4.08:1 — below AA, and this is the number that tells you whether the
   filter is worth pressing. Opacity rather than a colour of its own, because
   the chip turns yellow-on-black when it is pressed and a fixed grey would
   then be unreadable; .82 clears 4.5:1 in both states and keeps the count
   quieter than the label it sits next to. */
.chip-n { font-size: var(--fs-xs); opacity: .82; }
.filter-sort { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.filter-sort label {
  font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-2);
}
.listing-count { margin-bottom: 1.25rem; font-size: var(--fs-sm); color: var(--text-2); }

/* The two product families. The rule sits between them rather than above each
   one: it is there to mark where halogen ends and xenon begins, and a line
   under the filter card would only read as a second edge of that card. */
.listing-group + .listing-group {
  margin-top: clamp(2.25rem, 5vw, 3.5rem);
  padding-top: clamp(1.75rem, 4vw, 2.75rem);
  border-top: 1px solid var(--line);
}
/* Filter down to one D-series format and the halogen group goes away, leaving
   the divider with nothing above it to divide. [hidden] still matches here,
   which is what lets a sibling selector notice. */
.listing-group[hidden] + .listing-group { margin-top: 0; padding-top: 0; border-top: 0; }
.group-title { margin-bottom: 1.25rem; font-size: clamp(1.15rem, 2.4vw, 1.5rem); line-height: 1.25; }

.tiles {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  /* Wider tiles, fewer per row: the photograph is what people shop by, and a
     260px tile reduced a 1600px product shot to a thumbnail. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr));
}
.tile {
  display: flex; flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
  transition: border-color .3s, transform .3s var(--ease), box-shadow .3s;
}
.tile:hover { border-color: var(--line-strong); transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.tile[hidden] { display: none; }
.tile-body { display: flex; flex-direction: column; gap: .5rem; padding: 1.1rem; flex: 1; }
.tile-title { font-size: 1.05rem; line-height: 1.2; }
/* Same 24px floor as the breadcrumbs, same trick: hit area out, layout unchanged. */
.tile-title a { padding-block: .25rem; margin-block: -.25rem; }
.tile-title a:hover { color: var(--yellow); }
.tile-sub { font-size: var(--fs-xs); color: var(--text-2); }
.tile-specs { display: flex; flex-wrap: wrap; gap: .35rem; }
.tile-specs li {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .25rem .55rem; border: 1px solid var(--line); border-radius: 6px;
  font-size: var(--fs-xs); color: var(--text-2);
}
.tile-specs .ico { width: 13px; height: 13px; color: var(--text-3); }
.tile-specs .is-key { border-color: rgba(254,245,24,.35); color: var(--yellow); }
.tile-specs .is-key .ico { color: var(--yellow); }
.tile-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-top: auto; padding-top: .75rem;
}
.tile-foot .btn { min-height: 44px; padding: 0 1rem; font-size: var(--fs-xs); }

.listing-empty { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; padding: 2.5rem 0; color: var(--text-2); }
.linklike {
  border: 0; background: none; padding: 0; cursor: pointer;
  color: var(--yellow); font-weight: 700; text-decoration: underline;
  text-underline-offset: 3px;
  display: inline-flex; align-items: center; gap: .4rem;
}
.listing-finder {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1rem; margin-top: clamp(2rem, 4vw, 3rem);
  padding: clamp(1.2rem, 2.5vw, 1.8rem);
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
}
.listing-finder p { display: flex; align-items: center; gap: .6rem; color: var(--text-2); }
.listing-finder .ico { color: var(--yellow); }

/* -------------------------------------------------------- product page */

.product { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }
/* The photograph gets the larger share of the row. It is the only thing on the
   page that shows what actually arrives in the box. */
@media (min-width: 900px) { .product { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); align-items: start; } }

/* `position: relative` is what puts the beam badge on the photograph rather
   than in the top-left corner of the page. The stage is the only frame that
   does not go through .pmedia, so it has to say so itself. */
.product-stage {
  position: relative;
  background: #FFFFFF; border: 1px solid var(--line);
  border-radius: var(--r-xl); aspect-ratio: 1; overflow: hidden;
}
.product-stage img { width: 100%; height: 100%; object-fit: cover; }
/* One size up from the badge on a card: this frame is several times larger,
   and the same .6875rem pill read as a sticker someone forgot to peel off. */
.product-stage .ptag {
  top: 1rem; left: 1rem;
  padding: .4rem .8rem;
  font-size: .8125rem;
}
.product-stage .ptag .ico { width: 15px; height: 15px; }

.product-info { display: flex; flex-direction: column; gap: .9rem; }
.product-info h1 { font-size: clamp(1.9rem, 4vw, 3rem); }
.product-sub { font-size: var(--fs-sm); color: var(--text-2); }
.product-keys { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: .6rem; }
.product-keys li {
  display: grid; gap: .1rem; padding: .8rem;
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-md);
}
.product-keys .ico { color: var(--yellow); }
.product-keys strong { font-family: var(--font-display); font-size: 1.05rem; }
.product-keys span { font-size: var(--fs-xs); color: var(--text-2); }
.product-keys .is-key { border-color: rgba(254,245,24,.35); }

.product-buy {
  display: grid; gap: .85rem; margin-top: .4rem;
  padding: clamp(1.1rem, 2.4vw, 1.6rem);
  background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: var(--r-xl);
}
.product-price { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .75rem; }
.price-lg { font-family: var(--font-display); font-size: clamp(1.7rem, 3.4vw, 2.3rem); color: var(--yellow); }
.product-avail { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--fs-xs); font-weight: 700; }
.product-avail.is-in { color: #7BD88F; }
.product-avail.is-in .ico { color: #7BD88F; }
.product-avail.is-out { color: var(--text-3); }

.qty { display: inline-flex; align-items: center; gap: .25rem; align-self: start; }
.qty-btn {
  width: 46px; height: 46px; display: grid; place-items: center; cursor: pointer;
  background: var(--surface-3); border: 1px solid var(--line-strong); border-radius: var(--r-md);
  transition: border-color .2s, background .2s;
}
.qty-btn:hover { border-color: var(--yellow); color: var(--yellow); }
/* The field is a display for the two buttons beside it, so it carries no
   spinner of its own. `type=number` draws one anyway in every engine, and the
   reserved gutter for it pushes the digit off the centre of the box — which is
   what you actually notice. The input is `type=text inputmode=numeric` now, so
   phones still raise the number pad; these rules cover the rendered spinner in
   case the type ever changes back. */
.qty-input {
  width: 68px; height: 46px; text-align: center; font-weight: 700;
  background: var(--surface-1); border: 1px solid var(--line-strong); border-radius: var(--r-md);
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-input::-webkit-outer-spin-button,
.qty-input::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
.qty-input:focus-visible { border-color: var(--yellow); outline: none; }
.product-pending {
  display: flex; gap: .5rem; font-size: var(--fs-xs); color: var(--text-2);
}
.product-pending .ico { width: 14px; height: 14px; margin-top: .2rem; flex: none; }
.product-assurance { display: grid; gap: .4rem; font-size: var(--fs-xs); color: var(--text-2); }
.product-assurance li { display: flex; gap: .5rem; }
.product-assurance .ico { width: 15px; height: 15px; margin-top: .15rem; color: var(--yellow); }

.product-detail { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }
@media (min-width: 900px) { .product-detail { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); align-items: start; } }
.product-copy { display: grid; gap: .9rem; color: var(--text-2); }
.product-copy h2 { display: flex; align-items: center; gap: .6rem; font-size: clamp(1.3rem, 2.6vw, 1.8rem); color: var(--text); }
.product-copy h2 .ico { color: var(--yellow); }
.product-fit-title { margin-top: 1rem; }
.product-copy .btn { justify-self: start; }

.product-specs h2 { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; font-size: clamp(1.3rem, 2.6vw, 1.8rem); }
.product-specs h2 .ico { color: var(--yellow); }
.speclist { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-xl); overflow: hidden; }
.speclist > div {
  display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: baseline;
  padding: .85rem clamp(.9rem, 2vw, 1.3rem); border-bottom: 1px solid var(--line);
}
.speclist > div:last-child { border-bottom: 0; }
.speclist dt { display: flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); color: var(--text-2); }
.speclist dt .ico { width: 15px; height: 15px; color: var(--text-3); }
.speclist dd { font-weight: 700; text-align: end; }

.tiles-related { grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); }
.related {
  display: flex; flex-direction: column;
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
  overflow: hidden;
  transition: border-color .25s, transform .25s var(--ease);
}
.related:hover { border-color: var(--yellow); transform: translateY(-3px); }
.related-body { display: grid; gap: .3rem; padding: .9rem 1rem 1rem; }
.related strong { font-family: var(--font-display); font-size: .98rem; line-height: 1.2; }

/* ------------------------------------------------- drawer, cart, search */

/* The cart drawer and the search overlay shipped as markup with no stylesheet
   behind them, so both rendered as a plain block at the foot of every page —
   "Your cart is empty" sitting under the footer. Off-canvas by default now,
   and `hidden` on the scrim is honoured because [hidden] is !important above. */

.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: 290;
  background: rgba(4, 5, 7, .62);
  backdrop-filter: blur(3px);
  animation: scrim-in .25s var(--ease);
}
@keyframes scrim-in { from { opacity: 0; } to { opacity: 1; } }

.cart-drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 300;
  width: min(420px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border-inline-start: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(0, 0, 0, .5);
  transform: translateX(101%);
  transition: transform .32s var(--ease);
  padding-bottom: env(safe-area-inset-bottom);
}
.cart-drawer.is-open { transform: none; }
/* Off-screen is not enough on its own: a translated panel still holds focus
   and is still read out. Hidden from the tree until it is actually open. */
.cart-drawer[aria-hidden="true"] { visibility: hidden; }
.cart-drawer.is-open { visibility: visible; }

.cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem var(--gutter);
  border-bottom: 1px solid var(--line);
}
.cart-head h2 { display: flex; align-items: center; gap: .6rem; font-size: 1.2rem; }
.cart-head .ico { color: var(--yellow); }

.cart-body { flex: 1; overflow-y: auto; padding: 1.25rem var(--gutter); }
.cart-empty { color: var(--text-2); }
.cart-empty a { color: var(--yellow); text-decoration: underline; text-underline-offset: 3px; }

.cart-foot { display: grid; gap: .7rem; padding: 1.1rem var(--gutter) 1.4rem; border-top: 1px solid var(--line); }

/* Being *under* the consent bar is the same failure as being over it: the
   checkout button would sit behind the card and never be clickable. While
   consent is pending every overlay keeps the bar's measured height clear at
   its foot. --cbar-h is set by app.js and observed for changes, because the
   card grows to three rows on a narrow phone and in the longer translations. */
html[data-consent="pending"] .cart-foot { padding-bottom: calc(1.4rem + var(--cbar-h, 0px)); }
html[data-consent="pending"] .search-overlay { padding-bottom: calc(var(--gutter) + var(--cbar-h, 0px)); }
html[data-consent="pending"] .mobile-nav { padding-bottom: calc(var(--gutter) + var(--cbar-h, 0px)); }
html[data-consent="pending"] .to-top { bottom: calc(clamp(1rem, 3vw, 2rem) + var(--cbar-h, 0px)); }
.cart-line { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.cart-line strong { font-family: var(--font-display); font-size: 1.3rem; color: var(--yellow); }
.cart-ship, .cart-vat { font-size: var(--fs-xs); color: var(--text-2); }

.cart-count {
  position: absolute;
  inset: -4px -4px auto auto;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--yellow);
  color: #0B0B06;
  font-size: 11px;
  font-weight: 800;
}
.cart-btn { position: relative; }

/* ------------------------------------------------------------- search */

.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  align-content: start;
  justify-items: center;
  padding: clamp(1rem, 8vh, 6rem) var(--gutter) var(--gutter);
  background: rgba(6, 8, 11, .9);
  backdrop-filter: blur(16px);
  overflow-y: auto;
  animation: scrim-in .2s var(--ease);
}
.search-panel { width: 100%; max-width: 680px; display: grid; gap: 1rem; }
.search-field { position: relative; display: flex; align-items: center; gap: .75rem; }
/* Direct child only. As a descendant selector this also caught the X inside
   the close button and pinned it 1.1rem from that button's own left edge —
   an off-centre icon with a dead-looking third of hit area beside it. */
.search-field > .ico { position: absolute; inset-inline-start: 1.1rem; color: var(--text-3); }
.search-input {
  width: 100%;
  min-height: 64px;
  padding: 0 3.6rem;
  background: var(--surface-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-xl);
  font-size: 1.1rem;
}
.search-input:focus { border-color: var(--yellow); outline: none; }
.search-close {
  position: absolute;
  inset-inline-end: .8rem;
  display: grid;
  place-items: center;
  /* The whole 44px square closes the overlay, not just the glyph. */
  width: 44px;
  height: 44px;
}
.search-hint, .search-none { font-size: var(--fs-sm); color: var(--text-2); }
.search-results { display: grid; gap: .5rem; max-height: 60vh; overflow-y: auto; }
.search-hit {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .75rem .9rem;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color .18s, background .18s;
}
.search-hit:hover, .search-hit:focus-visible { border-color: var(--yellow); background: var(--surface-2); }
.search-hit .ico { color: var(--yellow); }
.search-shot { width: 44px; height: 44px; flex: none; border-radius: var(--r-sm); background: #FFFFFF; object-fit: cover; }
.search-hit span { display: grid; min-width: 0; }
/* After `.search-hit span`, which would otherwise make the badge's frame a
   grid and stretch it across the row. */
.search-hit .search-media { display: block; flex: none; }
.search-hit strong { font-size: var(--fs-sm); }
.search-hit small { font-size: var(--fs-xs); color: var(--text-2); }
.search-hit .price { margin-inline-start: auto; white-space: nowrap; }

/* The longer product copy: tagline, sub-headings, bullet list. */
.product-tagline { font-size: var(--fs-lead); color: var(--text-2); text-wrap: pretty; }
.product-h3 {
  display: flex; align-items: center; gap: .6rem;
  margin-top: 1.6rem; font-family: var(--font-display);
  font-size: clamp(1.05rem, 2vw, 1.25rem); color: var(--text);
}
.product-h3 .ico { color: var(--yellow); }
.product-bullets { display: grid; gap: .5rem; }
.product-bullets li { display: flex; gap: .6rem; align-items: baseline; }
.product-bullets .ico { width: 15px; height: 15px; margin-top: .25rem; flex: none; color: var(--yellow); }

/* ------------------------------------------------- basket lines and checkout */

/* The drawer's contents. A line is a thumbnail, the name with its unit price,
   a stepper, a line total, and a way out — in that reading order, because the
   question a basket answers is "what did I put in and what does it cost". */

.cart-items { display: grid; gap: .9rem; list-style: none; padding: 0; }
.cart-item {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 32px;
  gap: .75rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line);
}
.cart-item:last-child { border-bottom: 0; padding-bottom: 0; }
.cart-thumb {
  position: relative;
  width: 64px; height: 64px; overflow: hidden;
  background: #FFFFFF; border: 1px solid var(--line); border-radius: var(--r-md);
}
.cart-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cart-item-main { display: grid; gap: .35rem; min-width: 0; align-content: start; }
.cart-item-name { font-size: var(--fs-sm); font-weight: 700; line-height: 1.25; }
.cart-item-name:hover { color: var(--yellow); }
.cart-item-unit { font-size: var(--fs-xs); color: var(--text-2); }
.cart-item-row { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.cart-item-total { font-family: var(--font-display); font-size: 1rem; white-space: nowrap; }
.cart-item-x {
  width: 32px; height: 32px; display: grid; place-items: center; cursor: pointer;
  align-self: start; background: none; border: 0; color: var(--text-3);
  transition: color .2s;
}
.cart-item-x:hover { color: var(--yellow); }
.cart-item-x .ico { width: 16px; height: 16px; }

/* Something the server changed about the basket after we asked it to price —
   a quantity clamped to the shelf, a line that sold out. Stated, not silent. */
.cart-note {
  display: block; margin-bottom: .9rem; padding: .6rem .75rem;
  background: rgba(254, 245, 24, .08); border: 1px solid rgba(254, 245, 24, .3);
  border-radius: var(--r-md); font-size: var(--fs-xs); color: var(--text);
}

/* The stepper inside a basket line. Same control as the product page, sized to
   sit in a 420px drawer beside a price. */
.qty-sm .qty-btn { width: 32px; height: 32px; border-radius: 10px; }
.qty-sm .qty-btn .ico { width: 14px; height: 14px; }
.qty-sm .qty-input { width: 44px; height: 32px; font-size: var(--fs-xs); border-radius: 10px; }
.qty-btn:disabled { opacity: .35; cursor: not-allowed; }
.qty-btn:disabled:hover { border-color: var(--line-strong); color: inherit; }

/* Quick-add from a listing tile. Price, then the action, then the way to read
   more — the tile's foot wraps to two rows before it squeezes the buttons. */
.tile-foot { flex-wrap: wrap; }
.tile-add { flex: 1 1 auto; }
.tile-view { flex: 0 0 auto; }
/* The confirmation lives on the button that was pressed. It lasts about a
   second and a half, which is long enough to read and short enough that it
   never becomes the button's resting label. */
.btn.is-added { background: #7BD88F; border-color: #7BD88F; color: #07120A; }

/* ------------------------------------------------------------- checkout */

/* Every one of these is a single-column grid, and a grid column that is not
   declared is `auto`, which has a *min-content* minimum — so each of them
   silently refused to go narrower than its widest descendant and passed that
   width up to the next one. On a 320px screen the chain ran
   .co-promo-row's text input → .co-promo (301px) → .co-aside → .checkout-grid,
   and the document came out 358px wide: 38px of sideways scroll on the page
   where a customer types their card details. `minmax(0, 1fr)` is what lets a
   single-column grid actually be as narrow as the box it is in. */
.checkout-grid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem); align-items: start;
}
.checkout-grid > * { min-width: 0; }
@media (min-width: 900px) {
  .checkout-grid { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
  /* The summary follows the form down the page: on a four-step checkout the
     total is the one figure a person keeps checking back against. */
  .co-aside { position: sticky; top: calc(var(--header-h, 72px) + 1rem); }
}

.co-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(1rem, 2vw, 1.5rem); }
.co-step {
  display: grid; gap: .85rem; margin: 0; padding: clamp(1.1rem, 2.4vw, 1.6rem);
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
  /* A fieldset's UA default is min-inline-size: min-content, so these refused
     to shrink past the widest legend and pushed 38px of horizontal scroll onto
     checkout at 320px. Grid children need the same release to stay inside. */
  min-inline-size: 0;
}
.co-step > * { min-width: 0; }
.co-step legend {
  display: flex; align-items: center; gap: .6rem; padding: 0;
  font-family: var(--font-display); font-size: clamp(1.05rem, 2vw, 1.25rem);
}
.co-step-n {
  display: grid; place-items: center; width: 26px; height: 26px; flex: none;
  border-radius: 999px; background: var(--yellow); color: #0B0B06;
  font-size: var(--fs-xs); font-weight: 800;
}
.co-lead { font-size: var(--fs-sm); color: var(--text-2); }

.co-row { display: grid; gap: .85rem; }
@media (min-width: 620px) { .co-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.co-row[hidden] { display: none; }
.co-field { display: grid; gap: .35rem; min-width: 0; }
.co-label { font-size: var(--fs-xs); font-weight: 700; color: var(--text-2); }
.co-field.is-required .co-label::after { content: ' *'; color: var(--yellow); }
.co-field input {
  min-height: 48px; padding: 0 .9rem;
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); color: var(--text); font-size: 1rem;
}
.co-field input:focus { border-color: var(--yellow); outline: none; }
.co-field input:user-invalid { border-color: #E8705F; }
.co-field small { font-size: var(--fs-xs); color: var(--text-3); }
.co-field .select-wrap select { min-height: 48px; }

.co-choices { display: grid; gap: .6rem; }
.co-choice {
  display: flex; align-items: start; gap: .75rem; cursor: pointer;
  padding: .85rem 1rem;
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); transition: border-color .2s, background .2s;
}
.co-choice:hover { border-color: var(--line-strong); background: var(--surface-3); }
.co-choice input { margin-top: .2rem; accent-color: var(--yellow); width: 18px; height: 18px; flex: none; }
.co-choice span { display: grid; gap: .2rem; }
.co-choice strong { font-size: var(--fs-sm); }
.co-choice small { font-size: var(--fs-xs); color: var(--text-2); }
.co-choice:has(input:checked) { border-color: var(--yellow); background: var(--surface-3); }
.co-choice.is-off { opacity: .5; cursor: not-allowed; }

/* --- the card step
   Almost nothing here styles a card field: those are Stripe's iframes, dressed
   through the appearance object in cart.js. What is left is the furniture
   around them. */

.co-pay { display: grid; gap: .9rem; }
/* Reserved before the wallet buttons arrive, so the step does not jump when
   Apple Pay resolves a beat after the page settles. Hidden outright where the
   browser has no wallet at all — an empty gap is worse than no row. */
.co-express { min-height: 46px; }
.co-express[hidden] { display: none; }

/* A rule with a word sitting in it. The gradient fades the line out at both
   ends so it reads as a divider rather than as the top of a box. */
.co-or {
  display: flex; align-items: center; gap: .9rem;
  font-size: var(--fs-xs); color: var(--text-3); text-transform: lowercase;
}
.co-or::before, .co-or::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}
.co-or[hidden] { display: none; }

/* Stripe's iframe reports its own height and grows as the shopper switches
   between tabs, so this only holds the space until it has loaded. */
.co-element { min-height: 120px; }
.co-loading {
  display: flex; align-items: center; gap: .5rem;
  font-size: var(--fs-sm); color: var(--text-3);
}
.co-loading .ico { width: 15px; height: 15px; flex: none; }
.co-loading.is-bad { color: #E8705F; }

/* Reuses the choice-row shape rather than inventing a second one: to the eye
   it is the same kind of control, one step further down the form. */
.co-save {
  display: flex; gap: .7rem; align-items: flex-start;
  padding: .75rem .9rem; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface-2);
}
.co-save input { margin-top: .15rem; accent-color: var(--yellow); width: 18px; height: 18px; flex: none; }
.co-save span { display: grid; gap: .2rem; }
.co-save strong { font-size: var(--fs-sm); }
.co-save small { font-size: var(--fs-xs); color: var(--text-2); }
/* No email in step 1, nowhere to save the card to. Dimmed rather than removed,
   because it comes back the moment an address is typed. */
.co-save.is-off { opacity: .45; pointer-events: none; }

.co-secure {
  display: flex; gap: .5rem; align-items: flex-start;
  font-size: var(--fs-xs); color: var(--text-3);
}
.co-secure .ico { width: 14px; height: 14px; margin-top: .15rem; flex: none; color: var(--yellow); }

.co-withdrawal, .co-terms { font-size: var(--fs-xs); color: var(--text-2); }
.co-withdrawal { display: flex; gap: .5rem; }
.co-withdrawal .ico { width: 15px; height: 15px; margin-top: .15rem; flex: none; color: var(--yellow); }

.co-error {
  padding: .8rem 1rem; border-radius: var(--r-md);
  background: rgba(232, 112, 95, .12); border: 1px solid rgba(232, 112, 95, .45);
  color: #F3B4AA; font-size: var(--fs-sm);
}

.co-aside {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 1rem; padding: clamp(1.1rem, 2.4vw, 1.6rem);
  background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: var(--r-xl);
}
.co-aside h2 { display: flex; align-items: center; gap: .6rem; font-size: 1.15rem; }
.co-aside h2 .ico { color: var(--yellow); }

.co-lines { display: grid; gap: .55rem; list-style: none; padding: 0; }
/* Picture, quantity, name, money. The picture column collapses to nothing on
   a line that has no photograph, so a mixed basket still lines up. */
.co-lines li { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; gap: .6rem; align-items: center; font-size: var(--fs-sm); }
.co-lines li > .co-qty:first-child { grid-column: 2; }
.co-shot { width: 48px; height: 48px; border-radius: var(--r-sm); background: #FFFFFF; object-fit: cover; }
.co-lines a:hover { color: var(--yellow); }
.co-qty { font-weight: 800; color: var(--text-2); }
.co-lines strong { white-space: nowrap; }

.co-totals { display: grid; gap: .45rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.co-totals > div { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; font-size: var(--fs-sm); }
.co-totals dt { color: var(--text-2); }
.co-totals .is-off dd { color: #7BD88F; }
.co-grand { padding-top: .5rem; border-top: 1px solid var(--line); }
.co-grand dt { font-weight: 700; color: var(--text); }
.co-grand dd { font-family: var(--font-display); font-size: 1.35rem; color: var(--yellow); }
.co-vat { font-size: var(--fs-xs); color: var(--text-3); }

.co-promo {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: .4rem; padding-top: .9rem; border-top: 1px solid var(--line);
}
.co-promo-row { display: flex; gap: .5rem; }
.co-promo-row input {
  flex: 1; min-width: 0; min-height: 44px; padding: 0 .8rem;
  background: var(--surface-1); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); color: var(--text); text-transform: uppercase;
}
.co-promo-row input:focus { border-color: var(--yellow); outline: none; }
.co-promo-row .btn { min-height: 44px; padding: 0 1rem; font-size: var(--fs-xs); }
.co-promo-msg { font-size: var(--fs-xs); color: #7BD88F; }
.co-promo-msg.is-bad { color: #E8705F; }

.co-back { display: inline-flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); color: var(--text-2); }
.co-back:hover { color: var(--yellow); }
.co-back .ico { width: 15px; height: 15px; transform: rotate(180deg); }

/* --------------------------------------------------------- order placed */

.thanks { display: grid; justify-items: start; gap: 1rem; }
.thanks-mark {
  display: grid; place-items: center; width: 56px; height: 56px;
  border-radius: 999px; background: rgba(123, 216, 143, .14);
  border: 1px solid rgba(123, 216, 143, .45);
}
.thanks-mark .ico { width: 26px; height: 26px; color: #7BD88F; }
.thanks h1 { font-size: clamp(1.8rem, 4vw, 2.8rem); }
.thanks h1 [data-order-number] { color: var(--yellow); white-space: nowrap; }
.thanks-lead { font-size: var(--fs-lead); color: var(--text-2); max-width: 60ch; }
.thanks-keep { display: flex; gap: .5rem; font-size: var(--fs-sm); color: var(--text-2); }
.thanks-keep .ico { width: 16px; height: 16px; margin-top: .15rem; flex: none; color: var(--yellow); }
.thanks-summary {
  width: 100%; display: grid; gap: .9rem; padding: clamp(1rem, 2.4vw, 1.5rem);
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
}
.thanks h2 { font-size: 1.2rem; margin-top: .5rem; }
.thanks-steps { display: grid; gap: .5rem; padding-inline-start: 1.2rem; color: var(--text-2); }
.thanks-steps li { padding-inline-start: .3rem; }
/* Arrived without an order — the confirmation is hidden rather than shown with
   blanks where the number should be. */
.thanks.is-bare h1, .thanks.is-bare .thanks-keep, .thanks.is-bare .thanks-mark { display: none; }

/* ---------------------------------------------------- bulbs for your car */

.fit { display: grid; gap: clamp(1.25rem, 3vw, 2rem); }
.fit-head { display: grid; gap: .6rem; max-width: 70ch; }
/* The heading carries a whole car in it — make, model, generation and the
   years — so it is set smaller and given a wider measure than a display
   headline would normally get, to keep it to two lines rather than four. */
.fit-head h1 { font-size: clamp(1.6rem, 3.2vw, 2.35rem); max-width: 26ch; text-wrap: balance; }
.fit-lead { font-size: var(--fs-lead); color: var(--text-2); }
.fit-status { display: flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); color: var(--text-2); }
.fit-status.is-warn { color: var(--yellow); }

.fit-groups { display: grid; gap: clamp(1.25rem, 3vw, 2rem); }
.fit-group { display: grid; gap: .9rem; }
/* The position is the heading, because the question being answered is
   "which bulb goes where" — not "which products match". */
.fit-group h2 {
  display: flex; align-items: center; gap: .6rem;
  padding-bottom: .5rem; border-bottom: 1px solid var(--line);
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
}
/* Most positions have exactly one bulb, so the card is laid out wide rather
   than as a tile: a lone 230px tile in a 1200px row reads as a page that
   failed to load the rest. Two per row at desk width, one below that. */
.fit-cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 430px), 1fr)); }
.fit-card {
  display: grid; gap: .3rem 1.1rem; padding: 1rem;
  grid-template-columns: clamp(120px, 26vw, 190px) minmax(0, 1fr);
  align-content: center;
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
  transition: border-color .25s, transform .25s var(--ease);
}
.fit-card:hover { border-color: var(--line-strong); transform: translateY(-3px); }
/* The frame is the shared one; only its place in the card's grid is local. */
.fit-card .pmedia { grid-row: 1 / 3; align-self: center; border-radius: var(--r-md); }
.fit-card-body { display: grid; gap: .25rem; align-self: end; }
/* A grid item, so unlike the breadcrumbs the padding would really make the card
   taller — the negative margin is what keeps every fitment card the height it
   was drawn at while the link itself clears 24px. */
.fit-card-name {
  font-size: var(--fs-base); font-weight: 700; line-height: 1.25;
  padding-block: .25rem; margin-block: -.25rem;
}
.fit-card-name:hover { color: var(--yellow); }
.fit-card-sku { font-size: var(--fs-xs); color: var(--text-3); }
.fit-card .price { font-family: var(--font-display); font-size: 1.35rem; color: var(--yellow); }
.fit-card .btn { min-height: 44px; margin-top: .55rem; align-self: start; }

.fit-again {
  display: grid; justify-items: start; gap: .7rem;
  padding: clamp(1.2rem, 2.5vw, 1.8rem);
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-xl);
}
.fit-again h2 { display: flex; align-items: center; gap: .6rem; font-size: 1.2rem; }
.fit-again h2 .ico { color: var(--yellow); }
.fit-again p { color: var(--text-2); }
.fit-again .btn { min-height: 46px; }
@media (min-width: 620px) {
  .fit-again { grid-template-columns: auto auto; }
  .fit-again h2, .fit-again p { grid-column: 1 / -1; }
}

/* ------------------------------------------------------ the quiet notice */

/* One line, bottom centre, for about two seconds after a withheld right-click.
   It sits above the page but takes no pointer events, so nothing underneath it
   stops working while it is up — and it is raised clear of the consent bar,
   which is fixed to the same edge.

   z-index is below the consent bar and the drawers on purpose: a passing note
   should never cover a control somebody is trying to use. */
.protect-note {
  position: fixed;
  left: 50%;
  bottom: calc(var(--cbar-h, 0px) + 1.25rem);
  z-index: 60;
  transform: translate(-50%, .5rem);
  max-width: min(90vw, 26rem);
  padding: .55rem 1rem;
  border-radius: var(--r-pill);
  background: rgba(8, 10, 13, .92);
  border: 1px solid var(--line-strong);
  color: var(--text-2);
  font-size: var(--fs-sm);
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.protect-note.is-on { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) {
  .protect-note { transition: opacity .2s linear; transform: translate(-50%, 0); }
}
