/* ==========================================================================
   DROPOUT — custom.css
   Loaded after built.css (Tailwind). Plain CSS only, no build step needed.
   Theme colors come from settings.json via master.njk as "r, g, b" triplets:
   --cl-accent, --cl-background, --cl-card, --cl-t-primary, --cl-t-accent
   ========================================================================== */

:root {
  color-scheme: dark;
  --dx-ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Palette taken from the logo (blue-violet, hue ≈ 250°). Every tone is mixed from the
     accent, so changing the accent color in the builder still recolors the whole site.
     accent #6c47ff → logo core · deep → logo outline · glow → logo highlights · blue → washes
     Small accent-colored text should use --dx-glow (≈5:1 on the background). */
  --dx-violet: rgb(var(--cl-accent));
  --dx-deep: color-mix(in srgb, rgb(var(--cl-accent)) 45%, #1a0a8c);
  --dx-glow: color-mix(in srgb, rgb(var(--cl-accent)) 50%, #b3a4ff);
  --dx-blue: color-mix(in srgb, rgb(var(--cl-accent)) 55%, #3346ff);

  /* Buttons: dark indigo → light violet, like the shading inside the logo letters */
  --dx-btn-from: color-mix(in srgb, rgb(var(--cl-accent)) 75%, #2a0fb0);
  --dx-btn-to: color-mix(in srgb, rgb(var(--cl-accent)) 75%, #8a74ff);
}

::selection {
  background: rgba(var(--cl-accent), 0.35);
  color: #fff;
}


/* ==========================================================================
   BACKGROUND  (snippets/background.njk)
   Dark base + soft accent aurora, an indigo/violet color wash at the bottom, a faded grid,
   fine grain and a vignette. Only transform/opacity are animated.
   ========================================================================== */

.dx-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background: rgb(var(--cl-background));
  contain: strict;
}

.dx-bg > div {
  position: absolute;
  pointer-events: none;
}

/* Top spotlight */
.dx-bg__aurora {
  top: -38vh;
  left: 50%;
  width: min(1400px, 140vw);
  height: 85vh;
  margin-left: calc(min(1400px, 140vw) / -2);
  background:
    radial-gradient(closest-side, rgba(var(--cl-accent), 0.30), rgba(var(--cl-accent), 0.10) 45%, transparent 100%);
  opacity: 0.9;
  transform-origin: 50% 0%;
  animation: dx-aurora 16s ease-in-out infinite alternate;
  will-change: transform, opacity;
}

/* Bottom color wash: a continuous blue-indigo ⇄ violet gradient across the full width,
   fading upwards into the dark base. The band is 200% wide and slides slowly,
   so the hues shift instead of spots moving around. */
.dx-bg__floor {
  left: 0;
  right: 0;
  bottom: 0;
  height: 70vh;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.75) 25%, rgba(0, 0, 0, 0.25) 60%, transparent 100%);
          mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.75) 25%, rgba(0, 0, 0, 0.25) 60%, transparent 100%);
}

.dx-bg__floor::before,
.dx-bg__floor::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  pointer-events: none;
}

/* One period = one viewport width: blue-indigo → violet → blue-indigo (repeats seamlessly) */
.dx-bg__floor::before {
  left: 0;
  width: 200%;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--dx-blue) 30%, transparent) 0%,
    color-mix(in srgb, var(--dx-violet) 34%, transparent) 25%,
    color-mix(in srgb, var(--dx-blue) 30%, transparent) 50%,
    color-mix(in srgb, var(--dx-violet) 34%, transparent) 75%,
    color-mix(in srgb, var(--dx-blue) 30%, transparent) 100%);
  animation: dx-floor-shift 36s ease-in-out infinite alternate;
  will-change: transform;
}

/* Depth: slightly brighter accent haze right at the bottom edge */
.dx-bg__floor::after {
  left: 0;
  right: 0;
  background: linear-gradient(to top, rgba(var(--cl-accent), 0.10) 0%, transparent 45%);
}

/* Faded grid, strongest under the navbar, gone by mid-page */
.dx-bg__grid {
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 72px 72px;
  background-position: calc(50% - 36px) -1px;
  -webkit-mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 80%);
          mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 80%);
}

/* Film grain against gradient banding */
.dx-bg__noise {
  inset: 0;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.6 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

/* Edge darkening keeps focus in the middle */
.dx-bg__vignette {
  inset: 0;
  background: radial-gradient(ellipse 130% 100% at 50% 40%, transparent 60%, rgba(0, 0, 0, 0.45) 100%);
}

@keyframes dx-aurora {
  0%   { transform: scale(1, 1);       opacity: 0.75; }
  100% { transform: scale(1.08, 1.15); opacity: 1; }
}

@keyframes dx-floor-shift {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(-25%, 0, 0); }
}

@media (max-width: 768px) {
  .dx-bg__aurora { top: -30vh; height: 70vh; }
  .dx-bg__floor  { height: 60vh; }
  .dx-bg__grid   { background-size: 48px 48px; background-position: calc(50% - 24px) -1px; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-bg__aurora,
  .dx-bg__floor::before { animation: none; }
}


/* ==========================================================================
   HEADER  (components/navbar.njk, icons: snippets/dx-icon.njk)
   Row 1 .dx-top  — brand + actions, always visible.
   Row 2 .dx-tabs — page tabs; slides up behind row 1 on scroll down.
   The header's layout height never changes (only transform/opacity), so
   the page never jumps and scroll anchoring can't cause flicker.
   ========================================================================== */

html.dx-lock { overflow: hidden; }

.dx-header {
  --dx-h1: 76px;
  --dx-h2: 54px;
  --dx-ease: cubic-bezier(0.22, 1, 0.36, 1);
  position: sticky;
  top: 0;
  z-index: 40;
  pointer-events: none; /* empty area under a hidden tab row must not block clicks */
  animation: dx-header-in 0.7s var(--dx-ease) both;
}

.dx-top,
.dx-tabs,
.dx-drawer,
.dx-header .builder-toolbar { pointer-events: auto; }

.dx-wrap {
  max-width: 85rem;
  margin: 0 auto;
  padding: 0 1rem;
}

@media (min-width: 768px)  { .dx-wrap { padding: 0 1.5rem; } }
@media (min-width: 1024px) { .dx-wrap { padding: 0 2rem; } }

/* ---------- Row 1 ---------- */
.dx-top {
  position: relative;
  z-index: 3;
  background:
    linear-gradient(180deg, rgba(var(--cl-accent), 0.07), transparent 70%),
    rgba(var(--cl-background), 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
  transition: background-color 0.35s ease, box-shadow 0.35s ease;
}

.dx-header.is-scrolled .dx-top,
.dx-header.is-open .dx-top {
  background:
    linear-gradient(180deg, rgba(var(--cl-accent), 0.07), transparent 70%),
    rgba(var(--cl-background), 0.86);
}

.dx-header.is-scrolled.tabs-hidden .dx-top { box-shadow: 0 12px 40px -14px rgba(0, 0, 0, 0.75); }

/* Glowing gradient divider between the rows + a light sweeping along it */
.dx-top::after,
.dx-top::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  pointer-events: none;
}

.dx-top::after {
  background: linear-gradient(90deg, transparent 0%, var(--dx-violet) 20%, var(--dx-glow) 50%, var(--dx-violet) 80%, transparent 100%);
  box-shadow: 0 0 14px 0 rgba(var(--cl-accent), 0.55);
  opacity: 0.7;
}

.dx-top::before {
  z-index: 1;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95), transparent) no-repeat;
  background-size: 18% 100%;
  background-position: -30% 0;
  opacity: 0.6;
  animation: dx-line-sweep 7s linear infinite;
}

.dx-top__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--dx-h1);
}

.dx-top__brand { display: flex; flex: 1 1 auto; min-width: 0; }

.dx-top__actions {
  display: flex;
  flex: none;
  align-items: center;
  gap: 0.6rem;
}

/* Visibility helpers (!important so Alpine's x-show can't override them) */
@media (max-width: 1023.98px) { .dx-desktop-only { display: none !important; } }
@media (min-width: 1024px)    { .dx-mobile-only  { display: none !important; } }
@media (max-width: 479.98px)  { .dx-sm-up        { display: none !important; } }

/* ---------- Brand (logo: assets/logo-header.png, 498×138 = 3× the desktop size) ---------- */
.dx-brand {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  border-radius: 10px;
  text-decoration: none;
}

.dx-brand:focus-visible { outline: 2px solid rgba(var(--cl-accent), 0.7); outline-offset: 4px; }

.dx-brand__logo {
  display: block;
  width: auto;
  height: 46px;
  max-width: 100%;
  object-fit: contain;
  object-position: left center;
  transform-origin: left center;
  transition: transform 0.5s var(--dx-ease), filter 0.5s ease;
}

.dx-brand:hover .dx-brand__logo,
.dx-brand:focus-visible .dx-brand__logo {
  transform: translateY(-1px) scale(1.04);
  filter: drop-shadow(0 0 16px rgba(var(--cl-accent), 0.55));
}

/* ---------- Online counter ---------- */
.dx-online {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.5rem;
  height: 42px;
  padding: 0 0.95rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  white-space: nowrap;
}

.dx-online__dot {
  position: relative;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 8px rgba(34, 197, 94, 0.8);
}

.dx-online__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #22c55e;
  animation: dx-ping 2s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.dx-online__count {
  font-size: 0.95rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #4ade80;
}

.dx-online__label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.5);
}

/* ---------- Icon buttons ---------- */
.dx-icon-btn {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  padding: 0;
  border-radius: 12px;
  color: rgba(var(--cl-t-primary), 0.8);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  cursor: pointer;
  transition: color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease, box-shadow 0.3s ease, transform 0.25s var(--dx-ease);
}

.dx-icon-btn svg { width: 20px; height: 20px; }

.dx-icon-btn:hover,
.dx-icon-btn:focus-visible,
.dx-icon-btn.is-current,
.dx-burger.is-open {
  color: #fff;
  background: rgba(var(--cl-accent), 0.12);
  border-color: rgba(var(--cl-accent), 0.45);
  box-shadow: 0 0 0 4px rgba(var(--cl-accent), 0.08), 0 8px 24px -10px rgba(var(--cl-accent), 0.75);
  outline: none;
}

.dx-icon-btn--discord:hover,
.dx-icon-btn--discord:focus-visible {
  background: rgba(88, 101, 242, 0.18);
  border-color: rgba(88, 101, 242, 0.6);
  box-shadow: 0 0 0 4px rgba(88, 101, 242, 0.1), 0 8px 24px -10px rgba(88, 101, 242, 0.9);
}

.dx-icon-btn:hover { transform: translateY(-1px); }
.dx-icon-btn:active { transform: translateY(0) scale(0.95); }

.dx-cart:hover .dx-cart__icon { animation: dx-cart-wiggle 0.6s ease; }
.dx-icon-btn--discord:hover svg { animation: dx-cart-wiggle 0.6s ease; }

.dx-badge {
  position: absolute;
  top: -7px;
  right: -7px;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 19px;
  text-align: center;
  color: #fff;
  background: linear-gradient(135deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow: 0 0 0 2px rgb(var(--cl-background)), 0 4px 12px -2px var(--dx-violet);
  animation: dx-badge-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.dx-badge.is-bump { animation: dx-badge-bump 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }

/* ---------- Primary button (Dashboard) ---------- */
.dx-cta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  height: 42px;
  padding: 0 1.25rem;
  border: 0;
  border-radius: 12px;
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  background: linear-gradient(135deg, var(--dx-btn-from) 0%, var(--dx-btn-to) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 8px 26px -10px var(--dx-violet);
  transition: transform 0.25s var(--dx-ease), box-shadow 0.3s ease;
}

.dx-cta svg { width: 18px; height: 18px; transition: transform 0.35s var(--dx-ease); }

.dx-cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(135deg, var(--dx-btn-to) 0%, var(--dx-btn-from) 100%);
  opacity: 0;
  transition: opacity 0.4s ease;
}

.dx-cta::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -60%;
  width: 40%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-20deg);
  pointer-events: none;
  transition: left 0.75s var(--dx-ease);
}

.dx-cta:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 14px 32px -12px var(--dx-violet);
}

.dx-cta:hover::before { opacity: 1; }
.dx-cta:hover::after { left: 130%; }
.dx-cta:hover svg { transform: translateX(2px); }
.dx-cta:active { transform: scale(0.97); }
.dx-cta:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.75); outline-offset: 2px; }

.dx-cta--block { width: 100%; height: 48px; font-size: 0.95rem; }

/* ---------- Row 2: tabs ---------- */
.dx-tabs {
  position: relative;
  z-index: 1;
  background: rgba(var(--cl-background), 0.5);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  transition: transform 0.45s var(--dx-ease), opacity 0.3s ease, visibility 0s linear 0s, background-color 0.35s ease;
}

.dx-header.is-scrolled .dx-tabs { background: rgba(var(--cl-background), 0.8); box-shadow: 0 12px 40px -16px rgba(0, 0, 0, 0.75); }

.dx-header.tabs-hidden .dx-tabs {
  transform: translateY(-100%);
  opacity: 0;
  visibility: hidden;
  transition: transform 0.45s var(--dx-ease), opacity 0.3s ease, visibility 0s linear 0.45s, background-color 0.35s ease;
}

.dx-tabs__list {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  height: var(--dx-h2);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.dx-tabs__list::-webkit-scrollbar { display: none; }

.dx-tabs__indicator {
  position: absolute;
  top: 50%;
  left: 0;
  width: 0;
  height: 40px;
  margin-top: -20px;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(var(--cl-accent), 0.2), rgba(var(--cl-accent), 0.07));
  box-shadow:
    inset 0 0 0 1px rgba(var(--cl-accent), 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 0 18px -6px rgba(var(--cl-accent), 0.8);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.45s var(--dx-ease), width 0.45s var(--dx-ease), opacity 0.25s ease;
}

/* small glowing bar under the highlighted tab */
.dx-tabs__indicator::after {
  content: "";
  position: absolute;
  left: 30%;
  right: 30%;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--dx-violet), var(--dx-glow));
  box-shadow: 0 0 10px var(--dx-glow);
}

.dx-tabs__indicator.is-visible { opacity: 1; }

.dx-tab {
  position: relative;
  z-index: 1;
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.55rem;
  height: 40px;
  padding: 0 0.95rem;
  border-radius: 10px;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: rgba(var(--cl-t-primary), 0.62);
  text-decoration: none;
  transition: color 0.25s ease;
  animation: dx-fade-down 0.55s var(--dx-ease) both;
  animation-delay: calc(0.12s + var(--i, 0) * 0.045s);
}

.dx-tab__icon {
  flex: none;
  width: 17px;
  height: 17px;
  color: color-mix(in srgb, var(--dx-glow) 80%, #fff);
  opacity: 0.75;
  transition: transform 0.35s var(--dx-ease), color 0.25s ease, opacity 0.25s ease;
}

.dx-tab:hover,
.dx-tab:focus-visible,
.dx-tab.is-active {
  color: rgb(var(--cl-t-primary));
  outline: none;
}

.dx-tab:hover .dx-tab__icon,
.dx-tab:focus-visible .dx-tab__icon,
.dx-tab.is-active .dx-tab__icon {
  color: color-mix(in srgb, var(--dx-glow) 55%, #fff);
  opacity: 1;
}

.dx-tab:hover .dx-tab__icon { transform: translateY(-1px) scale(1.1); }

.dx-tab--button {
  color: #fff;
  background: linear-gradient(135deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow: 0 6px 20px -8px var(--dx-violet);
  transition: filter 0.25s ease;
}

.dx-tab--button .dx-tab__icon { color: #fff; opacity: 1; }
.dx-tab--button:hover { filter: brightness(1.12); }

/* ---------- Burger ---------- */
.dx-burger { flex-direction: column; gap: 4px; }

.dx-burger span {
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.35s var(--dx-ease), opacity 0.25s ease;
}

.dx-burger.is-open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.dx-burger.is-open span:nth-child(2) { opacity: 0; transform: scaleX(0.3); }
.dx-burger.is-open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ---------- Mobile drawer ---------- */
.dx-drawer {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  max-height: calc(100vh - var(--dx-h1) - var(--dx-h2) - 3rem);
  max-height: calc(100dvh - var(--dx-h1) - var(--dx-h2) - 3rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 0 1.25rem;
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(var(--cl-accent), 0.08), transparent 70%),
    rgb(var(--cl-background));
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.85);
}

@media (min-width: 1024px) { .dx-drawer { display: none !important; } }

.dx-drawer__inner {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.dx-drawer__item {
  animation: dx-slide-in 0.45s var(--dx-ease) both;
  animation-delay: calc(0.05s + var(--i, 0) * 0.05s);
}

.dx-drawer__inner > .dx-online { align-self: flex-start; }

.dx-drawer__link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  border-radius: 12px;
  font-size: 0.95rem;
  font-weight: 600;
  color: rgba(var(--cl-t-primary), 0.85);
  text-decoration: none;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  transition: color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
}

.dx-drawer__link-icon { width: 20px; height: 20px; color: #8e97ff; }

.dx-drawer__link:hover,
.dx-drawer__link:focus-visible {
  color: #fff;
  background: rgba(88, 101, 242, 0.14);
  border-color: rgba(88, 101, 242, 0.5);
  outline: none;
}

/* Alpine x-transition classes for the drawer */
.dx-t-enter { transition: opacity 0.3s ease, transform 0.35s var(--dx-ease); }
.dx-t-leave { transition: opacity 0.2s ease, transform 0.2s ease; }
.dx-t-from  { opacity: 0; transform: translateY(-10px); }
.dx-t-to    { opacity: 1; transform: translateY(0); }

/* ---------- Small screens ---------- */
@media (max-width: 1023.98px) {
  .dx-header { --dx-h1: 64px; --dx-h2: 50px; }
  .dx-brand__logo { height: 36px; }
  .dx-tab { height: 36px; padding: 0 0.8rem; font-size: 0.85rem; }
  .dx-tabs__indicator { height: 36px; margin-top: -18px; }

  /* fade the scrollable tab row at its edges */
  .dx-tabs__list {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 28px), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 28px), transparent 100%);
    padding-right: 1.5rem;
  }
}

/* ---------- Keyframes ---------- */
@keyframes dx-header-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

@keyframes dx-fade-down {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

@keyframes dx-slide-in {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes dx-line-sweep {
  from { background-position: -30% 0; }
  to   { background-position: 130% 0; }
}

@keyframes dx-ping {
  0%       { transform: scale(1);   opacity: 0.7; }
  75%, 100% { transform: scale(2.6); opacity: 0; }
}

@keyframes dx-cart-wiggle {
  0%, 100% { transform: rotate(0); }
  25%      { transform: rotate(-12deg); }
  50%      { transform: rotate(9deg); }
  75%      { transform: rotate(-5deg); }
}

@keyframes dx-badge-in {
  from { transform: scale(0); }
  to   { transform: scale(1); }
}

@keyframes dx-badge-bump {
  0%, 100% { transform: scale(1); }
  40%      { transform: scale(1.35); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-header,
  .dx-top::before,
  .dx-online__dot::after,
  .dx-tab,
  .dx-drawer__item,
  .dx-badge,
  .dx-cart:hover .dx-cart__icon,
  .dx-icon-btn--discord:hover svg { animation: none; }

  .dx-tabs,
  .dx-header.tabs-hidden .dx-tabs,
  .dx-tabs__indicator { transition: none; }
}


/* ==========================================================================
   PAGE SHELL  (layouts/master.njk)
   header · content · footer in one column; content fills the remaining
   height so the footer sits at the bottom even on short pages.
   ========================================================================== */

.dx-app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  overflow-x: clip; /* full-bleed sections (100vw) never cause a horizontal scrollbar; unlike hidden, clip keeps the sticky header working */
}

.dx-main {
  flex: 1 0 auto;
  width: 100%;
}


/* ==========================================================================
   FOOTER  (components/footer.njk)
   Mirror of the header: glowing gradient line on top (light sweeps the other
   way), row 1 logo + socials, row 2 links + copyright.
   ========================================================================== */

.dx-foot {
  position: relative;
  margin-top: 3rem;
}

/* ---------- Row 1 ---------- */
.dx-foot__top {
  position: relative;
  background:
    linear-gradient(0deg, rgba(var(--cl-accent), 0.07), transparent 70%),
    rgba(var(--cl-background), 0.6);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
}

.dx-foot__top::after,
.dx-foot__top::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 1px;
  pointer-events: none;
}

.dx-foot__top::after {
  background: linear-gradient(90deg, transparent 0%, var(--dx-violet) 20%, var(--dx-glow) 50%, var(--dx-violet) 80%, transparent 100%);
  box-shadow: 0 0 14px 0 rgba(var(--cl-accent), 0.55);
  opacity: 0.7;
}

.dx-foot__top::before {
  z-index: 1;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95), transparent) no-repeat;
  background-size: 18% 100%;
  background-position: 130% 0;
  opacity: 0.6;
  animation: dx-line-sweep-rev 7s linear infinite;
}

.dx-foot__top-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 88px;
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.dx-foot__brand .dx-brand__logo { height: 44px; }

.dx-foot__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.dx-foot__sep {
  width: 1px;
  height: 24px;
  margin: 0 0.15rem;
  background: rgba(255, 255, 255, 0.1);
}

/* Social buttons glow in their own brand color (set per button via --dx-brand) */
.dx-social:hover,
.dx-social:focus-visible {
  color: #fff;
  background: color-mix(in srgb, var(--dx-brand, rgb(var(--cl-accent))) 18%, transparent);
  border-color: color-mix(in srgb, var(--dx-brand, rgb(var(--cl-accent))) 60%, transparent);
  box-shadow:
    0 0 0 4px color-mix(in srgb, var(--dx-brand, rgb(var(--cl-accent))) 12%, transparent),
    0 8px 24px -10px var(--dx-brand, rgb(var(--cl-accent)));
}

.dx-social:hover svg { animation: dx-cart-wiggle 0.6s ease; }
.dx-totop:hover svg { animation: dx-rise 0.7s var(--dx-ease); }

/* ---------- Row 2 ---------- */
.dx-foot__bottom {
  position: relative;
  background: rgba(var(--cl-background), 0.82);
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.dx-foot__bottom-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  min-height: 60px;
  padding-top: 0.75rem;
  padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
}

.dx-foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem;
  margin-left: -0.75rem; /* text lines up with the logo */
}

.dx-foot__link {
  position: relative;
  padding: 0.5rem 0.75rem;
  border-radius: 10px;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.2;
  color: rgba(var(--cl-t-primary), 0.6);
  text-decoration: none;
  transition: color 0.25s ease, background-color 0.25s ease;
}

.dx-foot__link::after {
  content: "";
  position: absolute;
  left: 0.75rem;
  right: 0.75rem;
  bottom: 0.3rem;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--dx-violet), var(--dx-glow));
  box-shadow: 0 0 8px var(--dx-glow);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s var(--dx-ease);
}

.dx-foot__link:hover,
.dx-foot__link:focus-visible {
  color: #fff;
  background: rgba(255, 255, 255, 0.035);
  outline: none;
}

.dx-foot__link:hover::after,
.dx-foot__link:focus-visible::after { transform: scaleX(1); }

.dx-foot__copy {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  white-space: pre-line;
  color: rgba(var(--cl-t-primary), 0.5);
}

/* ---------- Reveal when scrolled into view (only if it starts off-screen) ---------- */
.dx-foot__item {
  transition: opacity 0.7s var(--dx-ease), transform 0.7s var(--dx-ease);
  transition-delay: calc(var(--i, 0) * 0.08s);
}

.dx-foot.is-waiting .dx-foot__item {
  opacity: 0;
  transform: translateY(16px);
}

/* ---------- Small screens ---------- */
@media (max-width: 639.98px) {
  .dx-foot { margin-top: 2rem; }
  .dx-foot__top-inner { min-height: 0; }
  .dx-foot__brand .dx-brand__logo { height: 34px; }
  .dx-foot__actions { gap: 0.45rem; }
  .dx-foot .dx-icon-btn { width: 38px; height: 38px; border-radius: 11px; }
  .dx-foot .dx-icon-btn svg { width: 18px; height: 18px; }
  .dx-foot__sep { margin: 0; }
  .dx-foot__bottom-inner { flex-direction: column; align-items: flex-start; }
}

@keyframes dx-line-sweep-rev {
  from { background-position: 130% 0; }
  to   { background-position: -30% 0; }
}

@keyframes dx-rise {
  0%   { transform: translateY(0); }
  40%  { transform: translateY(-4px); }
  100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-foot__top::before,
  .dx-social:hover svg,
  .dx-totop:hover svg { animation: none; }

  .dx-foot__item { transition: none; }
  .dx-foot.is-waiting .dx-foot__item { opacity: 1; transform: none; }
}


/* ==========================================================================
   SHARED BUTTONS
   .dx-cta (primary, defined in HEADER) · .dx-ghost (secondary glass button)
   ========================================================================== */

.dx-cta--lg { height: 52px; padding: 0 1.6rem; border-radius: 14px; font-size: 0.975rem; }

.dx-ghost {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  height: 42px;
  padding: 0 1.15rem;
  border-radius: 12px;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: #fff;
  text-decoration: none;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  transition: background-color 0.25s ease, border-color 0.25s ease, box-shadow 0.3s ease, transform 0.25s var(--dx-ease);
}

.dx-ghost svg { width: 20px; height: 20px; color: color-mix(in srgb, var(--dx-glow) 70%, #fff); transition: color 0.25s ease, transform 0.35s var(--dx-ease); }

.dx-ghost:hover,
.dx-ghost:focus-visible {
  background: rgba(var(--cl-accent), 0.14);
  border-color: rgba(var(--cl-accent), 0.55);
  box-shadow: 0 0 0 4px rgba(var(--cl-accent), 0.08), 0 12px 30px -14px rgba(var(--cl-accent), 0.9);
  transform: translateY(-1px);
  outline: none;
}

.dx-ghost:hover svg { color: #fff; transform: rotate(-8deg) scale(1.08); }
.dx-ghost:active { transform: scale(0.97); }

.dx-ghost--lg { height: 52px; padding: 0 1.4rem; border-radius: 14px; font-size: 0.975rem; }


/* ==========================================================================
   HERO  (components/hero.njk)
   The artwork layer breaks out to the full viewport width and reaches up
   behind the glass header. A single radial mask fades it out towards the
   left and bottom (fully transparent before any box edge → no cut lines),
   and it is color-graded with the accent so any image matches the theme.
   ========================================================================== */

:root { --dx-header-h: 131px; }                       /* row 1 + row 2 + border */
@media (max-width: 1023.98px) { :root { --dx-header-h: 115px; } }

.dx-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  /* Obere Grenze grosszuegig, damit der Hero auf hohen Bildschirmen bis zum
     unteren Rand reicht: Logoband und Features haengen per margin-top:auto
     am Heroende, ein zu niedriger Deckel laesst sie in der Bildmitte stehen. */
  min-height: clamp(600px, calc(100vh - var(--dx-header-h)), 1100px);
  min-height: clamp(600px, calc(100svh - var(--dx-header-h)), 1100px);
  margin-top: -1rem;                                   /* cancel .dx-main top padding */
}

@media (min-width: 768px)  { .dx-hero { margin-top: -1.5rem; } }
@media (min-width: 1024px) { .dx-hero { margin-top: -2rem; } }

/* ---------- Artwork ---------- */
.dx-hero__media,
.dx-hero__lines,
.dx-hero__glow {
  position: absolute;
  top: calc(-1 * var(--dx-header-h) - 2rem);
  bottom: 0;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  pointer-events: none;
}

.dx-hero__media {
  z-index: -2;
  animation: dx-fade-in 1.4s ease both;
}

.dx-hero__art {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 78%;
  overflow: hidden;
  /* Mask geometry: the gradient reaches full transparency at 77% of the ellipse radius.
     Left edge: 80% / 100% = 0.80 · image top (9%): 39% / 50% = 0.78 · box bottom: 52% / 50% > 1
     → every edge that is not the viewport edge is fully transparent, so no cut line anywhere. */
  -webkit-mask-image: radial-gradient(100% 50% at 80% 48%, #000 30%, rgba(0, 0, 0, 0.62) 54%, rgba(0, 0, 0, 0.2) 67%, transparent 77%);
          mask-image: radial-gradient(100% 50% at 80% 48%, #000 30%, rgba(0, 0, 0, 0.62) 54%, rgba(0, 0, 0, 0.2) 67%, transparent 77%);
}

.dx-hero__img {
  position: absolute;
  top: 9%;          /* pushes the subject below the header; that edge is faded by the mask */
  left: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 62% 32%;
  /* graded by .dx-hero__grade, see note there */
}

/* Color grade: a translucent accent tint + a darkening layer in the background color.
   Plain translucent layers instead of `filter` / `mix-blend-mode` on the image: they look
   the same in every engine, cost nothing to composite and keep the masked layer simple. */
.dx-hero__grade,
.dx-hero__grade::before,
.dx-hero__grade::after {
  position: absolute;
  inset: 0;
}

.dx-hero__grade::before {
  content: "";
  background: linear-gradient(120deg, rgba(var(--cl-accent), 0.34) 0%, rgba(var(--cl-accent), 0.16) 45%, color-mix(in srgb, var(--dx-blue) 22%, transparent) 100%);
}

.dx-hero__grade::after {
  content: "";
  background:
    radial-gradient(50% 55% at 68% 36%, rgba(var(--cl-accent), 0.14), transparent 70%),
    linear-gradient(180deg, rgba(var(--cl-background), 0.66) 0%, rgba(var(--cl-background), 0.4) 30%, rgba(var(--cl-background), 0.44) 68%, rgba(var(--cl-background), 0.7) 100%);
}

/* Soft falling snow (two layers, transform-only animation) */
.dx-hero__snow::before,
.dx-hero__snow::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  pointer-events: none;
  will-change: transform;
}

.dx-hero__snow::before {
  top: -260px;
  bottom: 0;
  opacity: 0.55;
  background-image:
    radial-gradient(circle at 24px 40px, rgba(255, 255, 255, 0.9) 0 1.3px, transparent 1.8px),
    radial-gradient(circle at 130px 12px, rgba(255, 255, 255, 0.7) 0 1px, transparent 1.5px),
    radial-gradient(circle at 200px 150px, rgba(255, 255, 255, 0.8) 0 1.5px, transparent 2px),
    radial-gradient(circle at 80px 210px, rgba(255, 255, 255, 0.6) 0 1px, transparent 1.5px);
  background-size: 260px 260px;
  animation: dx-snow-a 16s linear infinite;
}

.dx-hero__snow::after {
  top: -180px;
  bottom: 0;
  opacity: 0.35;
  background-image:
    radial-gradient(circle at 60px 30px, rgba(255, 255, 255, 0.8) 0 0.9px, transparent 1.3px),
    radial-gradient(circle at 150px 120px, rgba(255, 255, 255, 0.7) 0 0.8px, transparent 1.2px);
  background-size: 180px 180px;
  animation: dx-snow-b 24s linear infinite;
}

/* Diagonal light lines on the left, faded out */
.dx-hero__lines {
  z-index: -3;
  background: repeating-linear-gradient(118deg, transparent 0 96px, rgba(255, 255, 255, 0.035) 96px 97px);
  -webkit-mask-image: radial-gradient(45% 55% at 30% 45%, #000 0%, rgba(0, 0, 0, 0.4) 55%, transparent 100%);
          mask-image: radial-gradient(45% 55% at 30% 45%, #000 0%, rgba(0, 0, 0, 0.4) 55%, transparent 100%);
}

/* Accent glow behind the headline */
.dx-hero__glow {
  z-index: -1;
  background: radial-gradient(34% 40% at 24% 50%, rgba(var(--cl-accent), 0.16), transparent 70%);
}

/* ---------- Copy ---------- */
.dx-hero__body {
  display: flex;
  flex: 1 0 auto;
  align-items: center;
  padding: 4rem 0 3rem;
}

.dx-hero__content { max-width: 38rem; }

.dx-hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  padding: 0.4rem 0.9rem 0.4rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--dx-glow) 55%, #fff);
  background: rgba(var(--cl-accent), 0.12);
  border: 1px solid rgba(var(--cl-accent), 0.35);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}

.dx-hero__eyebrow-dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--dx-glow);
  box-shadow: 0 0 10px var(--dx-glow);
}

.dx-hero__eyebrow-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--dx-glow);
  animation: dx-ping 2.2s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.dx-hero__title {
  margin: 1.4rem 0 0;
  font-size: clamp(2.75rem, 1.5rem + 4.4vw, 5.25rem);
  font-weight: 800;
  line-height: 0.98;
  letter-spacing: -0.025em;
  text-transform: uppercase;
}

.dx-hero__title-top,
.dx-hero__title-accent { display: block; }

.dx-hero__title-top {
  color: #fff;
  text-shadow: 0 2px 40px rgba(0, 0, 0, 0.35);
}

.dx-hero__gradient {
  display: inline-block;
  padding-bottom: 0.08em; /* keeps descenders inside the clipped background */
  color: transparent;
  background: linear-gradient(95deg,
    color-mix(in srgb, var(--dx-glow) 45%, #fff) 0%,
    var(--dx-glow) 28%,
    var(--dx-violet) 62%,
    var(--dx-blue) 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  animation: dx-gradient-pan 8s ease-in-out infinite alternate;
}

.dx-hero__subtitle {
  max-width: 33rem;
  margin: 1.4rem 0 0;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  line-height: 1.7;
  color: rgba(var(--cl-t-primary), 0.7);
}

.dx-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2.25rem;
}

/* ---------- Logo marquee ---------- */
/* Sitzt zwischen Buttons und Features und fuellt den Leerraum darunter.
   margin-top: auto schiebt Band + Features gemeinsam an den unteren Rand. */
.dx-hero__marquee {
  position: relative;
  margin-top: auto;
  /* Bewusst klein halten: zusaetzliche Hoehe verteilt margin-top:auto bereits
     in den Abstand ueber dem Band. Groessere Innenabstaende wuerden dagegen
     auch auf flachen Bildschirmen wirken und Band + Features unter die
     Falz druecken. */
  padding-top: clamp(1.5rem, 4vh, 3rem);
}

/* ---------- Features ---------- */
.dx-hero__features-wrap { padding-bottom: 1.5rem; }

.dx-hero__features {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.5rem 2rem;
  margin: 0;
  padding: 1.75rem 0 0;
  list-style: none;
}

.dx-hero__features::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1) 15%, rgba(var(--cl-accent), 0.45) 50%, rgba(255, 255, 255, 0.1) 85%, transparent);
}

.dx-feature {
  display: flex;
  align-items: flex-start;
  gap: 0.95rem;
  min-width: 0;
}

.dx-feature__icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  color: color-mix(in srgb, var(--dx-glow) 60%, #fff);
  background: linear-gradient(180deg, rgba(var(--cl-accent), 0.22), rgba(var(--cl-accent), 0.06));
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transition: transform 0.35s var(--dx-ease), box-shadow 0.35s ease, color 0.25s ease;
}

.dx-feature__icon svg { width: 21px; height: 21px; }

.dx-feature:hover .dx-feature__icon {
  color: #fff;
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.65), 0 12px 28px -12px rgba(var(--cl-accent), 0.95);
}

.dx-feature__text {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
  padding-top: 0.15rem;
}

.dx-feature__title {
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.3;
  color: #fff;
}

.dx-feature__stat {
  font-weight: 800;
  color: color-mix(in srgb, var(--dx-glow) 40%, #fff);
}

.dx-feature__desc {
  font-size: 0.85rem;
  line-height: 1.5;
  color: rgba(var(--cl-t-primary), 0.55);
}

/* ---------- Entrance ---------- */
.dx-hero__in {
  animation: dx-rise-in 0.85s var(--dx-ease) both;
  animation-delay: calc(0.1s + var(--i, 0) * 0.08s);
}

/* ---------- Responsive ---------- */
@media (max-width: 1023.98px) {
  .dx-hero__art { width: 100%; }
  .dx-hero__img { object-position: 56% 32%; } /* subject a bit further right, face stays in frame */
  .dx-hero__features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767.98px) {
  .dx-hero { min-height: 0; }

  /* Image becomes a backdrop at the top; text sits below it in the dark part.
     Mask edges: top 45/58 = 0.78 · bottom 55/58 = 0.95 · left 60/78 = 0.77 → all transparent. */
  .dx-hero__art {
    bottom: auto;
    height: 640px;
    -webkit-mask-image: radial-gradient(78% 58% at 60% 45%, #000 28%, rgba(0, 0, 0, 0.55) 54%, rgba(0, 0, 0, 0.18) 67%, transparent 77%);
            mask-image: radial-gradient(78% 58% at 60% 45%, #000 28%, rgba(0, 0, 0, 0.55) 54%, rgba(0, 0, 0, 0.18) 67%, transparent 77%);
  }

  .dx-hero__img { top: 0; object-position: 64% 22%; }

  .dx-hero__grade::after {
    background:
      radial-gradient(60% 45% at 60% 40%, rgba(var(--cl-accent), 0.12), transparent 70%),
      linear-gradient(180deg, rgba(var(--cl-background), 0.55) 0%, rgba(var(--cl-background), 0.35) 35%, rgba(var(--cl-background), 0.6) 70%, rgba(var(--cl-background), 0.85) 100%);
  }

  .dx-hero__body { padding: 15rem 0 2.5rem; }
  .dx-hero__glow { background: radial-gradient(70% 35% at 30% 62%, rgba(var(--cl-accent), 0.14), transparent 70%); }
}

@media (max-width: 479.98px) {
  .dx-hero__features { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .dx-hero__actions > a { flex: 1 1 auto; }
}

/* ---------- Keyframes ---------- */
@keyframes dx-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes dx-snow-a {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, 260px, 0); }
}

@keyframes dx-snow-b {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, 180px, 0); }
}

@keyframes dx-gradient-pan {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

@keyframes dx-rise-in {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-hero__media,
  .dx-hero__snow::before,
  .dx-hero__snow::after,
  .dx-hero__gradient,
  .dx-hero__eyebrow-dot::after,
  .dx-hero__in { animation: none; }
}


/* ==========================================================================
   LOGO MARQUEE  (components/logo-marquee.njk)
   Endlosband aus Spielelogos. Die Spur enthaelt die Liste zweimal und laeuft
   um genau -50% ihrer Breite — am Ende steht Kopie 2 dort, wo Kopie 1 begann,
   der Ruecksprung ist deshalb unsichtbar. Der Abstand zwischen den beiden
   Kopien kommt aus demselben gap wie innerhalb einer Kopie, sonst entstuende
   an der Nahtstelle eine zu grosse Luecke.
   Die Raender werden per mask ausgeblendet, damit nichts hart abgeschnitten
   wirkt. Logos laufen entsaettigt und hellen beim Hover auf.
   ========================================================================== */

.dx-marquee {
  --dx-marquee-gap: clamp(2rem, 4.5vw, 4rem);
  --dx-marquee-height: clamp(30px, 3.4vw, 44px);
  position: relative;
  padding: clamp(1.25rem, 3.5vw, 2.5rem) 0;
}

.dx-marquee__title {
  margin: 0 0 clamp(1rem, 2.4vw, 1.75rem);
  text-align: center;
  font-size: clamp(0.688rem, 0.35vw + 0.6rem, 0.813rem);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.45);
}

.dx-marquee__viewport {
  overflow: hidden;
  /* Volle Viewportbreite, damit das Band nicht im Container endet. */
  width: 100vw;
  margin-left: 50%;
  transform: translateX(-50%);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}

.dx-marquee__track {
  display: flex;
  gap: var(--dx-marquee-gap);
  width: max-content;
  animation: dx-marquee-scroll var(--dx-marquee-duration, 40s) linear infinite;
}

.dx-marquee__track.is-paused:hover { animation-play-state: paused; }

.dx-marquee__group {
  display: flex;
  align-items: center;
  gap: var(--dx-marquee-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Feste Box pro Logo. Normierte man stattdessen nur die Hoehe, wuerde ein hohes
   Logo schmal und ein breites Logo riesig — die Leiste wirkte unruhig. Die Box
   haelt ausserdem den Platz frei, solange ein Bild laedt, und faengt ein defektes
   Bild ab: ohne feste Breite fiele der Eintrag auf 0 zusammen, die Spur wuerde
   kuerzer als zwei Kopien und die Endlosschleife bekaeme einen Sprung. */
.dx-marquee__item {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: clamp(104px, 11vw, 156px);
  height: var(--dx-marquee-height);
}

/* contain skaliert jedes Logo in die Box, ohne es zu verzerren: breite Logos
   stossen an die Breite, hohe an die Hoehe. */
.dx-marquee__logo {
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.55;
  filter: grayscale(1) brightness(1.7);
  transition: opacity 0.35s ease, filter 0.35s ease, transform 0.35s var(--dx-ease);
}

.dx-marquee__item:hover .dx-marquee__logo {
  opacity: 1;
  filter: none;
  transform: translateY(-2px) scale(1.04);
}

/* Fallback, solange fuer einen Eintrag noch kein Logo hochgeladen ist. */
.dx-marquee__name {
  white-space: nowrap;
  font-size: clamp(0.938rem, 1.1vw, 1.25rem);
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.42);
  transition: color 0.35s ease;
}

.dx-marquee__item--plain:hover .dx-marquee__name {
  color: color-mix(in srgb, var(--dx-glow) 70%, #fff);
}

@keyframes dx-marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-marquee__track { animation: none; }
  /* Ohne Animation waere die zweite Kopie nur Ballast — Band wird scrollbar. */
  .dx-marquee__viewport { overflow-x: auto; scrollbar-width: none; }
  .dx-marquee__viewport::-webkit-scrollbar { display: none; }
  .dx-marquee__group[aria-hidden="true"] { display: none; }
  .dx-marquee__logo { transition: none; }
}


/* ==========================================================================
   SCROLL REVEAL  ([data-dx-reveal], driven by assets/script.js)
   Hidden state only applies once the script added html.dx-reveal-ready.
   Put it on a wrapper, not on an element that has its own hover transform.
   ========================================================================== */

[data-dx-reveal] {
  transition:
    opacity 0.8s ease,
    transform 0.9s var(--dx-ease),
    filter 0.8s ease;
  transition-delay: var(--dx-delay, 0ms);
}

.dx-reveal-ready [data-dx-reveal]:not(.is-revealed) {
  opacity: 0;
  transform: translate3d(0, 32px, 0) scale(0.97);
  filter: blur(8px);
}


/* ==========================================================================
   SECTION HEADER  (shared by content sections)
   ========================================================================== */

.dx-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  margin-bottom: 2.5rem;
}

.dx-section-head__copy { max-width: 40rem; }

.dx-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  padding: 0.4rem 0.9rem 0.4rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--dx-glow) 55%, #fff);
  background: rgba(var(--cl-accent), 0.12);
  border: 1px solid rgba(var(--cl-accent), 0.35);
}

.dx-eyebrow__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--dx-glow);
  box-shadow: 0 0 10px var(--dx-glow);
}

.dx-section-title {
  margin: 1rem 0 0;
  font-size: clamp(1.9rem, 1.2rem + 2.4vw, 3rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: #fff;
}

.dx-text-gradient {
  color: transparent;
  background: linear-gradient(95deg, color-mix(in srgb, var(--dx-glow) 45%, #fff) 0%, var(--dx-glow) 35%, var(--dx-violet) 75%, var(--dx-blue) 100%);
  -webkit-background-clip: text;
          background-clip: text;
}

.dx-section-sub {
  max-width: 34rem;
  margin: 0.85rem 0 0;
  font-size: 1rem;
  line-height: 1.65;
  color: rgba(var(--cl-t-primary), 0.62);
}


/* ==========================================================================
   FEATURED PRODUCTS  (components/featured-products.njk)
   Cards have a 1px gradient "frame" (the .dx-pcard padding) with a light
   that follows the cursor (--mx / --my set by Alpine), an inner glow, image
   zoom and a gradient arrow button on hover.
   ========================================================================== */

.dx-fp {
  position: relative;
  /* no isolation / z-index here: the group modal (z-index 60) must stack above the sticky header */
  padding: 5rem 0 1.5rem;
}

/* soft full-width glow behind the grid */
.dx-fp::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 18%;
  bottom: 0;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  pointer-events: none;
  background: radial-gradient(45% 50% at 50% 55%, rgba(var(--cl-accent), 0.1), transparent 70%);
}

.dx-fp__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dx-fp__item { min-width: 0; }

.dx-fp__empty {
  padding: 3rem 1rem;
  text-align: center;
  color: rgba(var(--cl-t-primary), 0.5);
}

/* ---------- Card ---------- */
.dx-pcard {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 1px;
  border: 0;
  border-radius: 18px;
  font: inherit;
  text-align: left;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.11), rgba(255, 255, 255, 0.03) 60%, rgba(var(--cl-accent), 0.12));
  transition: transform 0.45s var(--dx-ease), box-shadow 0.45s ease;
}

/* cursor light on the frame */
.dx-pcard::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 0%), rgba(var(--cl-accent), 0.95), color-mix(in srgb, var(--dx-glow) 40%, transparent) 18%, transparent 45%);
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
}

.dx-pcard:hover,
.dx-pcard:focus-visible {
  transform: translateY(-6px);
  box-shadow: 0 28px 60px -28px rgba(var(--cl-accent), 0.6), 0 18px 36px -24px rgba(0, 0, 0, 0.8);
  outline: none;
}

.dx-pcard:hover::before,
.dx-pcard:focus-visible::before { opacity: 1; }

.dx-pcard:focus-visible { box-shadow: 0 0 0 2px var(--dx-glow), 0 28px 60px -28px rgba(var(--cl-accent), 0.6); }

.dx-pcard__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  border-radius: 17px;
  background: linear-gradient(180deg, rgb(var(--cl-card)) 0%, color-mix(in srgb, rgb(var(--cl-card)) 55%, rgb(var(--cl-background))) 100%);
}

/* cursor light inside the card */
.dx-pcard__inner::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: radial-gradient(280px circle at var(--mx, 50%) var(--my, 0%), rgba(var(--cl-accent), 0.12), transparent 60%);
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
}

.dx-pcard:hover .dx-pcard__inner::after { opacity: 1; }

/* ---------- Media ---------- */
.dx-pcard__media {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: var(--product-card-image-aspect-ratio, 16/9);
  background: linear-gradient(135deg, rgba(var(--cl-accent), 0.14), rgba(var(--cl-background), 0.6));
}

.dx-pcard__media--group { aspect-ratio: var(--group-card-image-aspect-ratio, 16/9); }

.dx-pcard__img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: var(--product-image-fit, cover);
  transition: transform 0.9s var(--dx-ease), opacity 0.3s ease;
}

.dx-pcard:hover .dx-pcard__img { transform: scale(1.07); }

.dx-pcard__placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: color-mix(in srgb, var(--dx-glow) 70%, #fff);
  background: radial-gradient(55% 60% at 50% 45%, rgba(var(--cl-accent), 0.28), transparent 70%);
}

.dx-pcard__placeholder svg { width: 44px; height: 44px; opacity: 0.8; }

.dx-pcard__shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(var(--cl-background), 0.45) 0%, transparent 32%, transparent 55%, rgb(var(--cl-card)) 100%);
}

.dx-pcard__badges {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  right: 7.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.dx-pcard__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.6rem;
  border-radius: 999px;
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  background: color-mix(in srgb, var(--dx-badge) 80%, transparent);
  box-shadow: 0 6px 16px -6px var(--dx-badge);
}

.dx-pcard__status {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: rgba(var(--cl-background), 0.72);
  border: 1px solid color-mix(in srgb, var(--dx-status) 45%, transparent);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
}

.dx-pcard__status-dot {
  position: relative;
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--dx-status);
  box-shadow: 0 0 8px var(--dx-status);
}

.dx-pcard__status-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--dx-status);
  animation: dx-ping 2.2s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.dx-pcard__soldout {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
  background: rgba(var(--cl-background), 0.45);
}

.dx-pcard.is-soldout .dx-pcard__img { opacity: 0.45; }

/* ---------- Body ---------- */
.dx-pcard__body {
  position: relative;
  z-index: 1;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.45rem;
  margin-top: -0.75rem;
  padding: 0 1.15rem 1.15rem;
}

.dx-pcard__meta {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: rgba(var(--cl-t-primary), 0.52);
}

.dx-pcard__meta svg { width: 14px; height: 14px; }

.dx-pcard__stock {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.dx-pcard__stock.is-ok  { background: #22c55e; box-shadow: 0 0 8px rgba(34, 197, 94, 0.8); }
.dx-pcard__stock.is-out { background: #ef4444; box-shadow: 0 0 8px rgba(239, 68, 68, 0.8); }

.dx-pcard__title {
  display: -webkit-box;
  overflow: hidden;
  font-size: 1.12rem;
  font-weight: 700;
  line-height: 1.3;
  color: #fff;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.dx-pcard__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: auto;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.dx-pcard__price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.5rem;
  min-width: 0;
}

.dx-pcard__from {
  width: 100%;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.42);
}

.dx-pcard__amount {
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1.1;
  color: #fff;
}

.dx-pcard__slash {
  font-size: 0.85rem;
  color: rgba(var(--cl-t-primary), 0.4);
}

.dx-pcard__go {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  color: color-mix(in srgb, var(--dx-glow) 60%, #fff);
  background: rgba(var(--cl-accent), 0.12);
  border: 1px solid rgba(var(--cl-accent), 0.32);
  transition: background 0.35s ease, border-color 0.35s ease, color 0.25s ease, box-shadow 0.35s ease;
}

.dx-pcard__go svg { width: 18px; height: 18px; transition: transform 0.35s var(--dx-ease); }

.dx-pcard:hover .dx-pcard__go {
  color: #fff;
  border-color: transparent;
  background: linear-gradient(135deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow: 0 10px 24px -10px var(--dx-violet);
}

.dx-pcard:hover .dx-pcard__go svg { transform: translateX(2px); }

/* ---------- Group modal ---------- */
.dx-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.dx-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(4, 3, 14, 0.72);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}

.dx-modal__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 34rem;
  max-height: min(80vh, 640px);
  overflow: hidden;
  border-radius: 20px;
  background: linear-gradient(180deg, rgb(var(--cl-card)), rgb(var(--cl-background)));
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(var(--cl-accent), 0.12), 0 0 80px -30px rgba(var(--cl-accent), 0.5);
  transition: transform 0.35s var(--dx-ease);
}

.dx-modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 1.25rem 1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.dx-modal__kicker {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--dx-glow) 60%, #fff);
}

.dx-modal__title {
  margin: 0.25rem 0 0;
  font-size: 1.35rem;
  font-weight: 800;
  color: #fff;
}

.dx-modal__list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
  padding: 0.6rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
}

.dx-mrow {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.9rem;
  padding: 0.6rem;
  border-radius: 14px;
  border: 1px solid transparent;
  color: inherit;
  text-decoration: none;
  transition: background-color 0.25s ease, border-color 0.25s ease;
}

.dx-mrow:hover,
.dx-mrow:focus-visible {
  background: rgba(var(--cl-accent), 0.08);
  border-color: rgba(var(--cl-accent), 0.3);
  outline: none;
}

.dx-mrow.is-soldout { opacity: 0.55; }

.dx-mrow__thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 40px;
  overflow: hidden;
  border-radius: 10px;
  color: color-mix(in srgb, var(--dx-glow) 70%, #fff);
  background: rgba(var(--cl-accent), 0.12);
}

.dx-mrow__thumb img { width: 100%; height: 100%; object-fit: cover; }
.dx-mrow__thumb svg { width: 20px; height: 20px; }

.dx-mrow__text {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.dx-mrow__name {
  overflow: hidden;
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: #fff;
}

.dx-mrow__status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: color-mix(in srgb, var(--dx-status) 75%, #fff);
}

.dx-mrow__price {
  font-size: 0.95rem;
  font-weight: 800;
  color: #fff;
}

.dx-mrow__go { display: inline-flex; color: rgba(var(--cl-t-primary), 0.4); transition: color 0.25s ease, transform 0.3s var(--dx-ease); }
.dx-mrow__go svg { width: 18px; height: 18px; }
.dx-mrow:hover .dx-mrow__go { color: #fff; transform: translateX(3px); }

/* Alpine x-transition classes */
.dx-modal-enter { transition: opacity 0.25s ease; }
.dx-modal-leave { transition: opacity 0.2s ease; }
.dx-modal-from  { opacity: 0; }
.dx-modal-to    { opacity: 1; }
.dx-modal-from .dx-modal__panel { transform: translateY(14px) scale(0.97); }

/* ---------- Responsive ---------- */
@media (max-width: 1023.98px) {
  .dx-fp { padding-top: 4rem; }
  .dx-fp__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 639.98px) {
  .dx-fp { padding-top: 3.5rem; }
  .dx-section-head { margin-bottom: 1.75rem; }
  .dx-fp__grid { grid-template-columns: minmax(0, 1fr); }
  .dx-mrow { grid-template-columns: 56px minmax(0, 1fr) auto; }
  .dx-mrow__thumb { width: 56px; height: 36px; }
  .dx-mrow__go { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  [data-dx-reveal],
  .dx-pcard,
  .dx-pcard__img,
  .dx-modal__panel { transition: none; }

  .dx-pcard:hover,
  .dx-pcard:focus-visible { transform: none; }

  .dx-pcard:hover .dx-pcard__img { transform: none; }
  .dx-pcard__status-dot::after { animation: none; }
}



/* ==========================================================================
   POPUP  (components/popup.njk)
   Willkommens-Dialog beim Laden der Seite. Geoeffnet wird er ueber die Klasse
   .is-open, die assets/script.js setzt — ohne JS bleibt [hidden] bestehen.
   Die Illustration besteht aus zwei Ebenen, die beide prozentual skalieren:
   der SVG-Linie (preserveAspectRatio="none" + non-scaling-stroke) und den
   absolut per --x/--y positionierten Stationen darueber.
   ========================================================================== */

.dx-popup {
  /* Laufzeit und Vorlauf der Linien-Animation. Fuellung und Lichtpunkt teilen
     sich beide Werte — laufen sie auseinander, sitzt der Punkt nicht mehr auf
     der Vorderkante der Fuellung. */
  --dx-popup-run: 1.6s;
  --dx-popup-lag: 0.15s;
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  overflow-y: auto;
}

.dx-popup[hidden] { display: none; }

.dx-popup__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(3, 2, 12, 0.78);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.35s ease;
}

.dx-popup.is-open .dx-popup__backdrop { opacity: 1; }

.dx-popup__card {
  position: relative;
  width: 100%;
  max-width: 30rem;
  margin: auto;
  border-radius: 20px;
  overflow: hidden;
  background: rgb(var(--cl-card));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 40px 80px -24px rgba(0, 0, 0, 0.85),
    0 0 90px -40px var(--dx-violet);
  opacity: 0;
  transform: translateY(18px) scale(0.96);
  transition: opacity 0.4s var(--dx-ease), transform 0.5s var(--dx-ease);
}

.dx-popup.is-open .dx-popup__card {
  opacity: 1;
  transform: none;
}

.dx-popup__close {
  position: absolute;
  top: 0.9rem;
  right: 0.9rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 11px;
  cursor: pointer;
  color: rgba(var(--cl-t-primary), 0.7);
  background: rgba(0, 0, 0, 0.45);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
  transition: color 0.25s ease, background 0.25s ease, transform 0.25s var(--dx-ease);
}

.dx-popup__close svg { width: 17px; height: 17px; }
.dx-popup__close:hover { color: #fff; background: rgba(0, 0, 0, 0.7); transform: rotate(90deg); }

/* ---------- Illustration ---------- */
.dx-popup__art {
  position: relative;
  height: 190px;
  overflow: hidden;
  color: var(--dx-glow);
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(var(--cl-accent), 0.3), transparent 70%),
    linear-gradient(180deg, rgba(var(--cl-accent), 0.12), rgba(0, 0, 0, 0.25));
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

/* Atmender Schein hinter der Illustration. */
.dx-popup__art::before {
  content: "";
  position: absolute;
  inset: -30% -10% auto;
  height: 150%;
  background: radial-gradient(50% 50% at 50% 50%, rgba(var(--cl-accent), 0.42), transparent 70%);
  pointer-events: none;
}

.dx-popup.is-open .dx-popup__art::before {
  animation: dx-popup-breathe 4.5s ease-in-out infinite;
}

/* Gemeinsame Ebene fuer Linie und Stationen. Beide liegen mit inset:0 darin,
   verschiebt man sie, bleiben die Stationen auf der Linie. */
.dx-popup__stage {
  position: absolute;
  inset: 0;
}

.dx-popup__line {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 6px rgba(var(--cl-accent), 0.85));
}

/* Graue Grundlinie: liegt von Anfang an da und bleibt stehen. */
.dx-popup__track {
  color: rgba(var(--cl-t-primary), 0.16);
}

/* Violette Fuellung, die sich ueber die graue Linie zeichnet und dann bleibt.
   --dx-line ist die gemessene Pfadlaenge (gesetzt in script.js): bei
   stroke-dashoffset o reicht die Fuellung bis Position (--dx-line - o).
   Die Zahlen im Fallback entsprechen dem aktuellen Pfad. */
.dx-popup__path {
  stroke-dasharray: var(--dx-line, 1270);
  stroke-dashoffset: var(--dx-line, 1270);
}

.dx-popup.is-open .dx-popup__path {
  animation:
    dx-popup-draw var(--dx-popup-run) linear var(--dx-popup-lag) forwards,
    dx-popup-glow 3.2s ease-in-out calc(var(--dx-popup-run) + var(--dx-popup-lag)) infinite;
}

/* Der weisse Punkt fuehrt die Fuellung an. Das Muster ist genau so lang wie
   der Pfad (Strich + Luecke = --dx-line), deshalb ist immer nur EIN Punkt
   unterwegs. Bei demselben Offset o sitzt er bei Position (--dx-line - o) —
   also exakt auf der Vorderkante der violetten Fuellung. Gleiche Dauer,
   gleiche Verzoegerung und beide linear: nur so bleiben sie deckungsgleich.
   Danach laeuft er endlos weiter ueber die fertige Linie. */
.dx-popup__comet {
  stroke-dasharray: var(--dx-lead, 50) calc(var(--dx-line, 1270) - var(--dx-lead, 50));
  stroke-dashoffset: var(--dx-line, 1270);
  filter: drop-shadow(0 0 4px #fff) drop-shadow(0 0 10px #fff) drop-shadow(0 0 18px var(--dx-violet));
}

.dx-popup.is-open .dx-popup__comet {
  animation: dx-popup-draw var(--dx-popup-run) linear var(--dx-popup-lag) infinite;
}

.dx-popup__steps {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Aufspannender Rahmen ohne eigene Position — Icon und Beschriftung darin
   werden unabhaengig voneinander platziert. */
.dx-popup__step {
  position: absolute;
  inset: 0;
}

.dx-popup__node-wrap {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, -50%);
  opacity: 0;
}

.dx-popup.is-open .dx-popup__node-wrap {
  animation: dx-popup-pop 0.45s var(--dx-ease) both;
  animation-delay: calc(0.25s + var(--i, 0) * 0.2s);
}


.dx-popup__node {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 17px;
  color: #fff;
  background: linear-gradient(160deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.22),
    0 10px 26px -8px var(--dx-violet),
    0 0 0 7px rgba(var(--cl-accent), 0.13);
}

/* Ring, der aus der Station nach aussen laeuft — versetzt pro Station, damit
   es pulsiert statt gleichzeitig zu blinken. */
.dx-popup__node::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 0 2px rgba(var(--cl-accent), 0.55);
  opacity: 0;
  pointer-events: none;
}

.dx-popup.is-open .dx-popup__node::after {
  animation: dx-popup-ring 2.4s ease-out infinite;
  animation-delay: calc(0.9s + var(--i, 0) * 0.35s);
}

/* Schwebeeffekt — versetzt pro Station, damit sie nicht im Gleichschritt
   wippen. Erst nach dem Aufpoppen, sonst ueberlagern sich die Bewegungen. */
.dx-popup.is-open .dx-popup__node {
  animation: dx-popup-float 3.2s ease-in-out infinite;
  animation-delay: calc(0.8s + var(--i, 0) * 0.5s);
}

.dx-popup__node svg { width: 24px; height: 24px; }


/* ---------- Inhalt ---------- */
.dx-popup__body {
  padding: 1.75rem 1.75rem 1.5rem;
  text-align: center;
}

.dx-popup__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  font-size: 0.688rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.85);
  background: rgba(var(--cl-accent), 0.16);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.4);
}

.dx-popup__eyebrow-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--dx-glow);
  box-shadow: 0 0 8px 1px var(--dx-violet);
}

.dx-popup__title {
  margin: 0 0 0.75rem;
  font-size: clamp(1.5rem, 4vw, 1.875rem);
  font-weight: 800;
  line-height: 1.2;
  color: #fff;
}

.dx-popup__gradient {
  background: linear-gradient(95deg, var(--dx-glow), var(--dx-btn-to), var(--dx-glow));
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: dx-gradient-pan 4s linear infinite alternate;
}

.dx-popup__text {
  margin: 0 0 1.25rem;
  font-size: 0.925rem;
  line-height: 1.6;
  color: rgba(var(--cl-t-primary), 0.72);
}

.dx-popup__list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
  text-align: left;
}

.dx-popup__item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.9rem;
  color: rgba(var(--cl-t-primary), 0.9);
}

.dx-popup__item-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  color: color-mix(in srgb, var(--dx-glow) 60%, #fff);
  background: rgba(var(--cl-accent), 0.14);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.32);
}

.dx-popup__item-icon svg { width: 16px; height: 16px; }

.dx-popup__cta {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 0.95rem 1.25rem;
  border: 0;
  border-radius: 13px;
  cursor: pointer;
  font-size: 1rem;
  font-weight: 700;
  font-family: inherit;
  color: #fff;
  text-decoration: none;
  background: linear-gradient(95deg, var(--dx-btn-from), var(--dx-btn-to));
  background-size: 200% auto;
  box-shadow: 0 14px 30px -12px var(--dx-violet);
  transition:
    background-position 0.5s ease,
    transform 0.25s var(--dx-ease),
    box-shadow 0.4s ease,
    background-color 0.45s ease;
}

.dx-popup__cta svg { width: 18px; height: 18px; }

.dx-popup__cta:hover {
  background-position: right center;
  transform: translateY(-2px);
  box-shadow: 0 18px 36px -12px var(--dx-violet);
}

/* Beide Zustaende liegen uebereinander, damit die Breite beim Wechsel nicht
   springt. Der inaktive wird nur ausgeblendet, nicht entfernt. */
.dx-popup__cta-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  transition: opacity 0.25s ease, transform 0.35s var(--dx-ease);
}

.dx-popup__cta-done {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(6px);
}

.dx-popup__cta.is-activated {
  cursor: default;
  background-image: linear-gradient(95deg, #15803d, #22c55e);
  box-shadow: 0 14px 34px -12px rgba(34, 197, 94, 0.9);
  transform: none;
}

.dx-popup__cta.is-activated .dx-popup__cta-default {
  opacity: 0;
  transform: translateY(-6px);
}

.dx-popup__cta.is-activated .dx-popup__cta-done {
  opacity: 1;
  transform: none;
}

.dx-popup__cta-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
}

.dx-popup__cta-check svg { width: 13px; height: 13px; stroke-width: 3; }

.dx-popup__cta.is-activated .dx-popup__cta-check {
  animation: dx-popup-check 0.5s var(--dx-ease) 0.1s both;
}

.dx-popup__dismiss {
  display: block;
  width: 100%;
  margin-top: 0.85rem;
  padding: 0.35rem;
  border: 0;
  background: none;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  color: rgba(var(--cl-t-primary), 0.45);
  transition: color 0.25s ease;
}

.dx-popup__dismiss:hover { color: rgba(var(--cl-t-primary), 0.8); }

@keyframes dx-popup-draw {
  to { stroke-dashoffset: 0; }
}

/* Schweben der Stationen. Sitzt auf dem inneren Element, weil das aeussere
   .dx-popup__step seinen transform schon fuer die Zentrierung und das
   Aufpoppen braucht. */
@keyframes dx-popup-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}

@keyframes dx-popup-glow {
  0%, 100% { filter: drop-shadow(0 0 5px rgba(var(--cl-accent), 0.7)); }
  50%      { filter: drop-shadow(0 0 13px rgba(var(--cl-accent), 1)); }
}

@keyframes dx-popup-ring {
  0%   { opacity: 0.85; transform: scale(1); }
  70%  { opacity: 0; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}

@keyframes dx-popup-breathe {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.12); }
}

@keyframes dx-popup-check {
  from { transform: scale(0.3) rotate(-25deg); }
  60%  { transform: scale(1.18) rotate(0deg); }
  to   { transform: scale(1); }
}

@keyframes dx-popup-pop {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
  60%  { opacity: 1; transform: translate(-50%, -50%) scale(1.08); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}


@media (max-width: 479.98px) {
  .dx-popup__art { height: 175px; }
  /* Schmale Karte: Stationen nach unten und von rechts weg, sonst liegt die
     letzte unter dem Schliessen-Button in der Ecke. */
  .dx-popup__stage { inset: 20% 13% 0 0; }
  .dx-popup__node { width: 46px; height: 46px; border-radius: 15px; }
  .dx-popup__node svg { width: 21px; height: 21px; }
  .dx-popup__body { padding: 1.5rem 1.25rem 1.25rem; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-popup__card,
  .dx-popup__backdrop { transition: none; }
  .dx-popup.is-open .dx-popup__path { stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
  .dx-popup.is-open .dx-popup__comet { display: none; }
  .dx-popup.is-open .dx-popup__node::after,
  .dx-popup.is-open .dx-popup__node,
  .dx-popup.is-open .dx-popup__art::before { animation: none; }
  .dx-popup.is-open .dx-popup__node-wrap { animation: none; opacity: 1; }
  .dx-popup__gradient { animation: none; }
  /* Der gruene Zustand bleibt — er ist Rueckmeldung, keine Zierde. */
  .dx-popup__cta.is-activated .dx-popup__cta-check { animation: none; }
}


/* ==========================================================================
   PRODUCT PAGE  (components/product-page.njk, snippets/product-form.njk)
   Die Produktseite nutzt noch das SellAuth-Standardmarkup: beide Spalten sind
   Stapel aus Geschwister-Divs mit eigenen Rahmen, die optisch zu einem Block
   zusammenwachsen — mit harten Ecken. Statt das Markup umzubauen bekommen die
   beiden Stapel hier eine Rundung; overflow:hidden schneidet die eckigen
   Kinder in die runde Form. Die Trennlinien zwischen den Abschnitten bleiben
   gerade, nur der Aussenrand wird weich.
   Aufhaenger: .dx-product (Sektion) und .dx-product__card (die zwei Stapel).
   ========================================================================== */

.dx-product__card {
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 24px 50px -30px rgba(0, 0, 0, 0.9);
}

/* Innenliegende Bedienelemente auf dasselbe Formvokabular bringen wie der
   Rest der Seite. rounded-full ausgenommen: das sind Statuspunkte und
   Karussell-Pfeile, die rund bleiben sollen. */
.dx-product button:not([class*="rounded-full"]),
.dx-product select,
.dx-product input,
.dx-product .badges > a,
.dx-product .badges > div {
  border-radius: 11px;
}

/* Kategorie und Produkt-Badges als Pillen — dasselbe Formvokabular wie der
   Eyebrow im Hero und im Popup. Steht nach der Regel oben und gewinnt damit. */
.dx-product .badges > a,
.dx-product .badges > div {
  border-radius: 999px;
}

/* Varianten, Mengenwaehler und die beiden Kaufknoepfe sind die groessten
   Schaltflaechen der Seite und vertragen etwas mehr Rundung. */
.dx-product [x-data="productForm"] button {
  border-radius: 12px;
}

/* ---------- Kopf ueber dem Seitenhintergrund ---------- */
.dx-product__head {
  position: relative;
  margin-bottom: clamp(1.25rem, 3vw, 2rem);
}

/* Weicher Lila-Schein hinter dem Titel, der langsam atmet. Liegt hinter dem
   Text (z-index -1) und faengt keine Klicks ab. */
.dx-product__head::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: -6%;
  top: -55%;
  width: 62%;
  height: 230%;
  background: radial-gradient(50% 50% at 50% 50%, rgba(var(--cl-accent), 0.3), transparent 70%);
  pointer-events: none;
  animation: dx-product-breathe 7s ease-in-out infinite;
}

.dx-product__crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-size: 0.813rem;
  color: rgba(var(--cl-t-primary), 0.4);
}

.dx-product__crumbs a {
  color: inherit;
  text-decoration: none;
  transition: color 0.25s ease;
}

.dx-product__crumbs a:hover { color: var(--dx-glow); }
.dx-product__crumb-current { color: rgba(var(--cl-t-primary), 0.75); }

.dx-product__head-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.85rem 1rem;
}

.dx-product__title {
  margin: 0;
  font-size: clamp(1.75rem, 4.5vw, 2.75rem);
  font-weight: 800;
  line-height: 1.1;
  color: #fff;
  text-shadow: 0 0 34px rgba(var(--cl-accent), 0.45);
}

/* Status als Pille statt als Zeile in einer Kopfleiste. */
.dx-product__status {
  padding: 0.4rem 0.9rem 0.4rem 0.7rem;
  border-radius: 999px;
  background: rgba(var(--cl-accent), 0.1);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.3);
}

.dx-product__meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.85rem 0 0;
  font-size: 0.875rem;
  color: rgba(var(--cl-t-primary), 0.55);
}

.dx-product__meta svg { width: 16px; height: 16px; color: var(--dx-glow); }
.dx-product__meta strong { color: rgba(var(--cl-t-primary), 0.9); }

@keyframes dx-product-breathe {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.1); }
}

/* ---------- Spalten: Bild bekommt mehr Breite ---------- */
.dx-product__main { width: 100%; }
.dx-product__side { width: 100%; }

@media (min-width: 1024px) {
  .dx-product__main { width: 63%; }
  .dx-product__side { width: 37%; }
}

/* ---------- Kauf-Widget ---------- */
.dx-product__variant-head {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.5);
}

.dx-product__price { font-weight: 800; }

.dx-product__save {
  align-self: center;
  margin-bottom: 0.15rem;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  color: #4ade80;
  background: rgba(34, 197, 94, 0.14);
  box-shadow: inset 0 0 0 1px rgba(34, 197, 94, 0.35);
}

.dx-product__variant-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
}

.dx-product__per-day {
  font-size: 0.688rem;
  color: rgba(var(--cl-t-primary), 0.45);
  white-space: nowrap;
}

/* ---------- Vertrauenszeile ---------- */
.dx-product__trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 0.9rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.dx-product__trust-label {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.813rem;
  font-weight: 600;
  color: rgba(var(--cl-t-primary), 0.6);
}

.dx-product__trust-label svg { width: 15px; height: 15px; color: var(--dx-glow); }

.dx-product__pay {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

/* Jede Karte bringt ihren eigenen Hintergrund mit (Visa blau, Mastercard
   dunkel, Apple Pay weiss). Deshalb kein Entsaettigen und kein Abdunkeln —
   sie sollen wie aufgeklebte Kaertchen wirken. Einheitliche Hoehe, Breite
   nach Seitenverhaeltnis. */
.dx-product__pay-logo {
  height: 24px;
  width: auto;
  max-width: 46px;
  object-fit: contain;
  border-radius: 4px;
  background: #fff;
  transition: transform 0.25s var(--dx-ease);
}

.dx-product__pay-logo:hover { transform: translateY(-1px) scale(1.06); }

.dx-product__pay-note {
  font-size: 0.75rem;
  color: rgba(var(--cl-t-primary), 0.4);
}

@media (prefers-reduced-motion: reduce) {
  .dx-product__head::before { animation: none; }
}

/* ---------- Status-Abzeichen ---------- */
/* Farbe kommt per --dx-status aus product.status_color, das Abzeichen passt
   sich damit an Undetected / Testing / Detected an. */
.dx-product__status {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.85rem;
  border-radius: 10px;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--dx-status, #22c55e);
  background: color-mix(in srgb, var(--dx-status, #22c55e) 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dx-status, #22c55e) 55%, transparent);
}

.dx-product__status svg { width: 14px; height: 14px; }

/* ---------- Badges im Kopf ---------- */
.dx-product__badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.85rem;
}

.dx-product__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--dx-badge, rgb(var(--cl-accent)));
  background: color-mix(in srgb, var(--dx-badge, rgb(var(--cl-accent))) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dx-badge, rgb(var(--cl-accent))) 45%, transparent);
  transition: background 0.25s ease;
}

.dx-product__badge--cat { --dx-badge: rgb(var(--cl-accent)); }
.dx-product__badge:hover { background: color-mix(in srgb, var(--dx-badge, rgb(var(--cl-accent))) 26%, transparent); }

/* ---------- Titel: Verlauf, der langsam wandert ---------- */
.dx-product__title {
  background: linear-gradient(100deg, #fff 10%, var(--dx-glow) 35%, #fff 60%, var(--dx-btn-to) 85%, #fff 100%);
  background-size: 260% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: dx-product-sheen 9s linear infinite;
}

/* text-shadow greift bei transparentem Text nicht — der Schein kommt deshalb
   aus einer Kopie des Textes hinter dem Original. */
.dx-product__title-wrap {
  position: relative;
  display: inline-block;
}

@keyframes dx-product-sheen {
  from { background-position: 0% 50%; }
  to   { background-position: 260% 50%; }
}

/* ---------- Kaufbox ---------- */
.dx-product__buybox { box-shadow: 0 30px 60px -34px rgba(0, 0, 0, 0.95); }

.dx-variants {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.dx-variant {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.35rem 1rem;
  width: 100%;
  padding: 0.85rem 1rem;
  border: 0;
  border-radius: 14px;
  cursor: pointer;
  text-align: left;
  color: rgb(var(--cl-t-primary));
  background: rgba(255, 255, 255, 0.025);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  transition: background 0.25s ease, box-shadow 0.3s ease, transform 0.25s var(--dx-ease);
}

.dx-variant:hover:not(:disabled):not(.is-active) {
  background: rgba(255, 255, 255, 0.05);
  transform: translateY(-1px);
}

.dx-variant.is-active {
  background: rgba(var(--cl-accent), 0.12);
  box-shadow:
    inset 0 0 0 1.5px rgba(var(--cl-accent), 0.9),
    0 0 26px -8px rgba(var(--cl-accent), 0.8);
}

.dx-variant:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.dx-variant__left {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

.dx-variant__name {
  font-size: 1rem;
  font-weight: 700;
}

.dx-variant__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.18rem 0.5rem;
  border-radius: 6px;
  font-size: 0.625rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(var(--cl-t-primary), 0.55);
  background: rgba(255, 255, 255, 0.07);
}

.dx-variant__chip svg { width: 11px; height: 11px; }

.dx-variant__chip--best {
  color: #fdba74;
  background: rgba(249, 115, 22, 0.16);
  box-shadow: inset 0 0 0 1px rgba(249, 115, 22, 0.4);
}

.dx-variant__chip[hidden] { display: none; }

.dx-variant__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.1rem;
}

.dx-variant__price {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 1rem;
  font-weight: 700;
}

.dx-variant__slash {
  font-size: 0.75rem;
  font-weight: 500;
  color: rgba(var(--cl-t-primary), 0.4);
  text-decoration: line-through;
}

.dx-variant__perday {
  font-size: 0.688rem;
  color: rgba(var(--cl-t-primary), 0.42);
  white-space: nowrap;
}

.dx-variant__desc {
  grid-column: 1 / -1;
  font-size: 0.75rem;
  color: rgba(var(--cl-t-primary), 0.5);
}

/* ---------- Endpreis ueber dem Kaufknopf ---------- */
.dx-buy__total { margin-top: 1.25rem; }

.dx-buy__total-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.dx-buy__price {
  font-size: clamp(1.875rem, 5vw, 2.5rem);
  font-weight: 800;
  line-height: 1;
  color: #fff;
}

.dx-buy__save {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  color: #4ade80;
  background: rgba(34, 197, 94, 0.14);
  box-shadow: inset 0 0 0 1px rgba(34, 197, 94, 0.35);
}

.dx-buy__total-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.4rem;
  font-size: 0.813rem;
  color: rgba(var(--cl-t-primary), 0.45);
}

.dx-buy__oos { color: #f87171; }

@media (prefers-reduced-motion: reduce) {
  .dx-product__title { animation: none; }
}

/* ---------- Bild bekommt mehr Platz ---------- */
/* Die linke Karte enthaelt jetzt nur noch das Bild, die Inhalte stehen als
   eigene Abschnitte darunter. Dadurch darf die Spalte breiter werden. */
@media (min-width: 1024px) {
  .dx-product__main { width: 67%; }
  .dx-product__side { width: 33%; }
}

/* ---------- Inhaltsabschnitte unter dem Bild ---------- */
.dx-product__sections {
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin-top: clamp(1.75rem, 4vw, 3rem);
}

.dx-section__title {
  margin: 0 0 1rem;
  font-size: clamp(1.25rem, 2.5vw, 1.625rem);
  font-weight: 800;
  color: #fff;
}

/* Mattglas: die Flaeche ist durchsichtig und zeichnet den Hintergrund
   verwaschen nach, statt ihn mit der Kartenfarbe zuzudecken.

   Drei Dinge machen den Eindruck aus, nicht nur die Unschaerfe:
   - saturate hebt die Farben dahinter an, sonst wirkt Glas grau und tot
   - eine haarfeine helle Linie NUR an der Oberkante (die Lichtkante)
   - ein sehr schwacher heller Schleier von oben nach unten

   position + isolation sind noetig, weil der Schleier als ::before darauf
   liegt und hinter dem Text bleiben muss. */
.dx-section__body {
  position: relative;
  isolation: isolate;
  padding: clamp(1.1rem, 2.5vw, 1.75rem);
  border-radius: 18px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.05);
  -webkit-backdrop-filter: blur(22px) saturate(1.7);
  backdrop-filter: blur(22px) saturate(1.7);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 0 1px rgba(255, 255, 255, 0.09),
    0 24px 50px -34px rgba(0, 0, 0, 0.9);
}

.dx-section__body::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.07),
    rgba(255, 255, 255, 0) 45%
  );
}

/* Ohne backdrop-filter (aeltere Browser) wuerde durchsichtiges Glas zu
   unlesbarem Text fuehren — dort bleibt es bei der gefuellten Karte. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dx-section__body {
    background: rgb(var(--cl-card));
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, 0.06),
      0 24px 50px -34px rgba(0, 0, 0, 0.9);
  }
}

/* Listen im Rich-Text werden zum Raster mit Haken — so sieht der vorhandene
   Inhalt aus SellAuth aus wie eine gebaute Feature-Uebersicht, ohne dass am
   Text etwas geaendert werden muss. */
.dx-section__body ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0.7rem 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dx-section__body ul li {
  position: relative;
  padding-left: 1.6rem;
  font-size: 0.925rem;
  line-height: 1.45;
  color: rgba(var(--cl-t-primary), 0.85);
}

/* Haken als Pseudo-Element: der Rich-Text bleibt unangetastet. */
.dx-section__body ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.35em;
  width: 15px;
  height: 9px;
  border-left: 2px solid var(--dx-glow);
  border-bottom: 2px solid var(--dx-glow);
  transform: rotate(-45deg);
}

.dx-section__body p { margin: 0 0 0.75rem; }
.dx-section__body p:last-child { margin-bottom: 0; }
.dx-section__body strong { color: #fff; }

.dx-section__body h2,
.dx-section__body h3,
.dx-section__body h4 {
  margin: 1.25rem 0 0.6rem;
  font-weight: 700;
  color: #fff;
}

.dx-section__body h2:first-child,
.dx-section__body h3:first-child,
.dx-section__body h4:first-child { margin-top: 0; }

/* ---------- Bildformat der Produktseite ---------- */
/* Der Rahmen uebernimmt das Seitenverhaeltnis des BILDES, nicht umgekehrt.
   --dx-media-ratio setzt zuerst der Server (Einstellung, verhindert das
   Springen des Layouts vor dem Laden) und danach script.js auf das
   tatsaechliche Verhaeltnis der ersten Datei.
   Der innere splide__track muss mitziehen, sonst bleibt er beim alten Wert. */
.dx-product__media,
.dx-product__media .splide__track {
  aspect-ratio: var(--dx-media-ratio, 16/9);
}

/* contain statt des globalen cover: cover fuellt den Rahmen und schneidet
   dabei oben und unten ab — genau das, was hier weg sollte. Mit dem oben
   gemessenen Verhaeltnis liegt das Bild randlos im Rahmen; weicht ein
   weiteres Bild im Slider davon ab, bleibt es wenigstens vollstaendig. */
.dx-product__media img {
  object-fit: contain;
  object-position: center;
}

/* ---------- Kaufknoepfe ---------- */
/* Die rechte Spalte ist schmaler geworden; ohne diese Regel bricht
   "Add to Cart" mitten im Text um. Die Knoepfe duerfen stattdessen
   untereinander rutschen. */
.dx-buy__actions { flex-wrap: wrap; }

.dx-buy__actions > button {
  white-space: nowrap;
  padding-left: 1rem;
  padding-right: 1rem;
}

/* flex-basis nur dort, wo die Reihe waagerecht steht. Darunter ist sie eine
   Spalte — die Basis wuerde dann die HOEHE setzen und die Knoepfe auf 150 px
   aufblasen. */
@media (min-width: 1024px) {
  .dx-buy__actions > button { flex: 1 1 150px; }
}


/* ==========================================================================
   STATUS CARD  (snippets/status-card.njk)
   Transparente Karte mit abgerundeten Ecken, um die ein violetter Lichtstreifen
   laeuft.

   Der Streifen ist ein kegelfoermiger Farbverlauf, der sich dreht. Damit nur
   der RAND leuchtet und die Flaeche transparent bleibt, wird das Pseudo-
   Element maskiert: zwei Masken uebereinander, die per xor/exclude nur den
   Ring zwischen Aussenkante und padding-Box uebrig lassen. Eine gefuellte
   Innenflaeche waere der einfachere Weg, wuerde die Karte aber undurchsichtig
   machen — und genau das soll sie nicht sein.

   Gedreht wird ueber eine registrierte Custom Property: nur ein per @property
   als <angle> angemeldeter Wert laesst sich animieren. Ohne @property (alte
   Browser) bleibt der Verlauf stehen — dann ist es ein ruhiger violetter
   Rand statt eines laufenden, also ein brauchbarer Rueckfall.
   ========================================================================== */

@property --dx-beam {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

.dx-status-card {
  position: relative;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.02);
  text-decoration: none;
  transition: background 0.3s ease, transform 0.3s var(--dx-ease);
}

.dx-status-card:hover {
  background: rgba(255, 255, 255, 0.045);
  transform: translateY(-1px);
}

/* Ruhender Grundrand, damit die Karte auch dort umrissen ist, wo der
   Lichtstreifen gerade nicht steht. */
.dx-status-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  pointer-events: none;
}

.dx-status-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(
    from var(--dx-beam),
    transparent 0turn 0.62turn,
    rgba(var(--cl-accent), 0.55) 0.76turn,
    var(--dx-glow) 0.87turn,
    #fff 0.9turn,
    var(--dx-glow) 0.93turn,
    transparent 1turn
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  animation: dx-status-beam 4.5s linear infinite;
}

/* Versatz pro Karte, damit nicht alle Streifen im Gleichschritt laufen.
   nth-child zaehlt innerhalb jeder Spiel-Gruppe neu, der Versatz allein
   reicht deshalb nicht — leicht unterschiedliche Laufzeiten lassen sie
   zusaetzlich auseinanderdriften. */
.dx-status-card:nth-child(2n)::before { animation-delay: -1.5s; animation-duration: 5.3s; }
.dx-status-card:nth-child(3n)::before { animation-delay: -3s; animation-duration: 6.1s; }
.dx-status-card:nth-child(4n)::before { animation-delay: -0.8s; animation-duration: 3.9s; }

@keyframes dx-status-beam {
  to { --dx-beam: 1turn; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-status-card::before { animation: none; }
}


/* ==========================================================================
   UPSELL CARD  (snippets/upsell-card.njk, "Commonly bought together")
   Raster mit gleich breiten Spalten und ueberall demselben Abstand. Die
   Karten zeigen nur Bild, Name und Preis; beim Ueberfahren zoomt das Bild
   leicht heran und die Karte hebt sich an.
   ========================================================================== */

.dx-upsells { margin-top: clamp(1.75rem, 4vw, 3rem); }
.dx-upsells__title { margin-bottom: 1rem; }

.dx-upsells__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(0.85rem, 2vw, 1.5rem);
  justify-content: center;
}

.dx-upsell {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 16px;
  text-decoration: none;
  color: inherit;
  background: rgb(var(--cl-card));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 18px 40px -28px rgba(0, 0, 0, 0.9);
  transition: transform 0.35s var(--dx-ease), box-shadow 0.35s ease;
}

.dx-upsell:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 0 0 1px rgba(var(--cl-accent), 0.5),
    0 26px 50px -26px rgba(0, 0, 0, 0.95),
    0 0 40px -18px rgba(var(--cl-accent), 0.8);
}

/* ---------- Bild ---------- */
.dx-upsell__media {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: rgba(0, 0, 0, 0.25);
}

.dx-upsell__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--dx-ease), filter 0.4s ease;
}

.dx-upsell:hover .dx-upsell__img {
  transform: scale(1.08);
  filter: brightness(1.1) saturate(1.1);
}

/* Lichtschleier, der beim Ueberfahren einmal ueber das Bild wischt. */
.dx-upsell__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, 0.18) 50%, transparent 65%);
  transform: translateX(-120%);
  transition: transform 0.75s var(--dx-ease);
  pointer-events: none;
}

.dx-upsell:hover .dx-upsell__media::after { transform: translateX(120%); }

.dx-upsell__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: rgba(var(--cl-accent), 0.5);
}

.dx-upsell__placeholder svg { width: 38px; height: 38px; }

/* ---------- Text ---------- */
.dx-upsell__body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.9rem 1rem 1.05rem;
}

.dx-upsell__name {
  font-size: 1rem;
  font-weight: 700;
  color: #fff;
  /* Lange Namen umbrechen lassen statt abschneiden. */
  overflow-wrap: anywhere;
}

.dx-upsell__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.dx-upsell__price {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin-top: auto;
}

.dx-upsell__from {
  font-size: 0.75rem;
  color: rgba(var(--cl-t-primary), 0.45);
}

.dx-upsell__amount {
  font-size: 1.125rem;
  font-weight: 800;
  color: #fff;
}

.dx-upsell__slash {
  font-size: 0.813rem;
  color: rgba(var(--cl-t-primary), 0.35);
  text-decoration: line-through;
}


/* ==========================================================================
   FLAME BADGE  (dx-flame-badge)
   Durchsichtige Blase, in der ein Lagerfeuer brennt. Die Farbe kommt per
   --dx-flame aus der im Dashboard gesetzten Badge-Farbe.

   Der Rand ist bewusst still: keine Animation, kein Leuchten nach aussen.
   Es bewegt sich nur das Feuer INNEN.

   Das Feuer sind einzelne Flammenzungen (Tropfenform: eine eckige Ecke,
   um 45deg gedreht zeigt sie nach oben) plus ein Glutbett unten. Jede
   Zunge steigt auf, wird schmaler und verschwindet — mit eigener Dauer und
   eigenem Versatz, damit nie zwei im Gleichschritt laufen.
   ========================================================================== */

.dx-flame-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  overflow: hidden;
  font-size: 0.688rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: color-mix(in srgb, var(--dx-flame, #f97316) 25%, #fff);
  /* Vollstaendig durchsichtig — kein Fuellton, kein Schein nach aussen.
     Nur eine haarduenne, unbewegte Kante haelt die Blasenform. */
  background: transparent;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dx-flame, #f97316) 28%, transparent);
}

/* Schrift und Symbol ueber das Feuer heben. Das :not() ist wichtig: ohne
   es traefe die Regel auch die Feuerstelle (ebenfalls ein direktes span)
   und wuerde deren position:absolute mit hoeherer Spezifitaet kippen. */
.dx-flame-badge i,
.dx-flame-badge > span:not(.dx-flame-badge__fire) { position: relative; z-index: 1; }

/* Feuerstelle: nur ein Rahmen fuer die Zungen. Die Glut liegt im ::before,
   damit deren Opacity-Animation die Flammen nicht mitdimmt. */
.dx-flame-badge__fire {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* Glutbett: der schwach gluehende Boden, aus dem die Flammen aufsteigen. */
.dx-flame-badge__fire::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    70% 55% at 50% 108%,
    color-mix(in srgb, var(--dx-flame, #f97316) 60%, transparent),
    transparent 72%
  );
  animation: dx-flame-embers 2.7s ease-in-out infinite alternate;
}

/* Die einzelnen Zungen. mix-blend-mode: screen laesst sie sich dort, wo sie
   sich ueberlappen, gegenseitig aufhellen — so entsteht der heisse Kern.
   Der Selektor nennt bewusst beide Klassen: sonst gewinnt die Textregel
   ".dx-flame-badge > span" und wuerfe die Zungen ueber die Schrift. */
.dx-flame-badge__fire .dx-flame-badge__tongue {
  position: absolute;
  bottom: -4px;
  width: 9px;
  height: 9px;
  /* Tropfen: drei runde Ecken, eine eckige. Um 45deg gedreht zeigt die
     eckige nach oben und wird zur Flammenspitze. Das scaleY DAVOR (also
     nach der Drehung angewendet) zieht sie senkrecht lang — sonst bleibt
     ein Kreis mit Zipfel statt einer Flamme. */
  border-radius: 0 50% 50% 50%;
  /* 315deg laeuft nach der Drehung genau von unten nach oben: heisser
     weissgelber Fuss, oben die Spitze in der Badge-Farbe. Durchgehend
     deckend — verlief sie zur Spitze hin ins Nichts, blieb optisch nur
     ein runder Klecks uebrig. */
  background: linear-gradient(
    315deg,
    #fff4cc 0%,
    #ffc24a 28%,
    color-mix(in srgb, var(--dx-flame, #f97316) 80%, #ff7a18) 62%,
    var(--dx-flame, #f97316) 100%
  );
  /* Weichzeichner: laesst benachbarte Zungen zu EINEM Feuer verschmelzen
     statt zu einzelnen Punkten. */
  filter: blur(1.1px);
  mix-blend-mode: screen;
  transform: scaleY(1.5) rotate(45deg);
  transform-origin: 50% 100%;
  opacity: 0;
  animation: dx-flame-tongue 1s ease-out infinite;
}

/* Zur Mitte hin groesser und langsamer, aussen kleiner und hektischer —
   so brennt ein Lagerfeuer: in der Mitte am hoechsten. */
.dx-flame-badge__fire .dx-flame-badge__tongue:nth-child(1) { left: 10%; width: 9px;  height: 9px;  animation-duration: 0.78s; animation-delay: -0.31s; }
.dx-flame-badge__fire .dx-flame-badge__tongue:nth-child(2) { left: 26%; width: 12px; height: 12px; animation-duration: 1.02s; animation-delay: -0.74s; }
.dx-flame-badge__fire .dx-flame-badge__tongue:nth-child(3) { left: 43%; width: 15px; height: 15px; animation-duration: 1.21s; animation-delay: -0.17s; }
.dx-flame-badge__fire .dx-flame-badge__tongue:nth-child(4) { left: 60%; width: 11px; height: 11px; animation-duration: 0.89s; animation-delay: -0.56s; }
.dx-flame-badge__fire .dx-flame-badge__tongue:nth-child(5) { left: 76%; width: 8px;  height: 8px;  animation-duration: 0.71s; animation-delay: -0.93s; }

@keyframes dx-flame-tongue {
  0%   { transform: translate(0, 2px) scaleY(1.2) rotate(45deg) scale(0.45);   opacity: 0; }
  16%  {                                                                        opacity: 0.85; }
  48%  { transform: translate(-1px, -3px) scaleY(1.55) rotate(45deg) scale(1);  opacity: 0.8; }
  74%  { transform: translate(1px, -6px) scaleY(1.7) rotate(45deg) scale(0.7);  opacity: 0.4; }
  100% { transform: translate(0, -9px) scaleY(1.9) rotate(45deg) scale(0.32);   opacity: 0; }
}

@keyframes dx-flame-embers {
  from { opacity: 0.55; }
  to   { opacity: 0.9; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-flame-badge__fire::before,
  .dx-flame-badge__fire .dx-flame-badge__tongue { animation: none; }
  .dx-flame-badge__fire::before { opacity: 0.7; }
  /* Ohne Bewegung bleibt ein stehendes Feuer statt eines leeren Rahmens. */
  .dx-flame-badge__fire .dx-flame-badge__tongue { opacity: 0.8; transform: translate(0, -3px) scaleY(1.55) rotate(45deg) scale(0.95); }
  .dx-upsell,
  .dx-upsell__img,
  .dx-upsell__media::after { transition: none; }
}


/* ==========================================================================
   PRODUKTSEITE HINTERGRUND  (components/product-page.njk → .dx-product__glow)
   --------------------------------------------------------------------------
   Der Seitenhintergrund (.dx-bg) setzt seinen Schein oben und unten. Die
   Produktseite ist lang — dazwischen blieb eine flache, dunkle Zone. Das fiel
   besonders bei den Glaskaesten auf: Mattglas ueber einer gleichmaessigen
   Flaeche sieht grau aus, weil es nichts zu verwaschen gibt.

   Zwei grosse, weich auslaufende Lichtflaechen wandern langsam durch diese
   Zone. Bewusst nur zwei und bewusst traege: der Hintergrund soll Tiefe geben,
   nicht die Aufmerksamkeit vom Produkt wegziehen.

   Zwei Lehren aus dem Aufbau:
   - isolation auf der Sektion ist noetig, sonst faellt der Kasten mit
     z-index: -1 hinter .dx-bg und ist gar nicht zu sehen.
   - overflow: hidden sitzt auf dem Kasten, NICHT auf der Sektion: an der
     Sektion wuerde es ein sticky gesetztes Kaufwidget festnageln.
   ========================================================================== */

.dx-product {
  position: relative;
  isolation: isolate;
}

.dx-product__glow {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.dx-product__glow::before,
.dx-product__glow::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  will-change: transform;
}

/* Oben links, in der Akzentfarbe — nimmt den Schein aus dem Seitenkopf auf
   und traegt ihn hinter Bild und Kaufbox weiter. */
.dx-product__glow::before {
  top: -14%;
  left: -14%;
  width: min(760px, 72%);
  aspect-ratio: 1;
  background: radial-gradient(
    closest-side,
    rgba(var(--cl-accent), 0.30),
    rgba(var(--cl-accent), 0.11) 46%,
    transparent 72%
  );
  animation: dx-prodglow-a 26s ease-in-out infinite alternate;
}

/* Rechts auf mittlerer Hoehe in Violett — liegt hinter den Glaskaesten und
   gibt ihnen Farbe zum Brechen. Bewusst prozentual von oben statt am unteren
   Rand verankert: am Boden festgemacht klaffte auf der langen Seite zwischen
   beiden Scheinen ein flaches Band von rund 780 px, und zwar genau dort, wo
   die Glaskaesten stehen. So waechst der Abstand mit der Seitenlaenge mit.
   Andere Dauer als oben, damit nie beide gleichzeitig am Umkehrpunkt stehen
   und das Ganze nie gleichmaessig „atmend" wirkt. */
.dx-product__glow::after {
  top: 30%;
  right: -16%;
  width: min(680px, 66%);
  aspect-ratio: 1;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--dx-violet) 30%, transparent),
    color-mix(in srgb, var(--dx-blue) 16%, transparent) 48%,
    transparent 74%
  );
  animation: dx-prodglow-b 34s ease-in-out infinite alternate;
}

@keyframes dx-prodglow-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(7%, 5%, 0) scale(1.12); }
}

@keyframes dx-prodglow-b {
  from { transform: translate3d(0, 0, 0) scale(1.06); }
  to   { transform: translate3d(-8%, -6%, 0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-product__glow::before,
  .dx-product__glow::after { animation: none; }
}

/* ==========================================================================
   RASTER-LICHTSTREIFEN  (snippets/background.njk → .dx-bg__beams)
   --------------------------------------------------------------------------
   Ein violetter Streifen mit weisser Spitze laeuft ueber die Rasterlinien —
   dieselbe Idee wie die Linie im Popup, nur auf dem Hintergrund.

   Warum die Streifen im festen Hintergrund liegen und nicht in der Sektion:
   .dx-bg__grid ist am Fenster verankert. Laege der Streifen beim Inhalt,
   wanderte er beim Scrollen von der Linie weg.

   Die Linienlage muss exakt der des Rasters entsprechen. Das Raster nutzt
   background-position: calc(50% - 36px) -1px bei 72px Teilung, also liegt
   die n-te senkrechte Linie bei calc(50% - 36px + n * 72px) und die n-te
   waagerechte bei calc(-1px + n * 72px). Genau das rechnet --n hier nach.

   Dieselbe Maske wie beim Raster: der Streifen soll nur dort zu sehen sein,
   wo auch Linien zu sehen sind — sonst liefe ein Licht durchs Nichts.
   ========================================================================== */

.dx-bg__beams {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* Deckungsgleich mit .dx-bg__grid */
  -webkit-mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 80%);
          mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 80%);
}

.dx-bg__beam {
  position: absolute;
  /* screen laesst den Streifen den Hintergrund aufhellen statt ihn zu
     ueberdecken — dadurch wirkt er wie Licht IN der Linie, nicht wie ein
     Balken darueber. */
  mix-blend-mode: screen;
  animation-duration: var(--dur, 12s);
  animation-delay: var(--delay, 0s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  will-change: transform;
}

/* Senkrecht: 2px breit, laeuft von oben nach unten.
   Der Verlauf ist der Streifen selbst — hinten auslaufend violett, vorn die
   helle Spitze, genau wie der Lichtpunkt auf der Popup-Linie. */
.dx-bg__beam--v {
  top: 0;
  left: calc(50% - 36px + var(--n) * 72px);
  width: 2px;
  height: 38vh;
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(var(--cl-accent), 0.45) 55%,
    rgba(var(--cl-accent), 1) 90%,
    #ffffff 99%,
    transparent 100%
  );
  animation-name: dx-beam-v;
}

/* Waagerecht: 2px hoch, laeuft von links nach rechts. */
.dx-bg__beam--h {
  left: 0;
  top: calc(-1px + var(--n) * 72px);
  height: 2px;
  width: 34vw;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(var(--cl-accent), 0.45) 55%,
    rgba(var(--cl-accent), 1) 90%,
    #ffffff 99%,
    transparent 100%
  );
  animation-name: dx-beam-h;
}

/* Lichthof: derselbe Verlauf noch einmal, breiter und weichgezeichnet.
   Ein box-shadow ginge nicht — der umgibt den ganzen Kasten und liesse auch
   die durchsichtigen Teile des Streifens leuchten, also die gesamte Linie
   statt nur den Kopf. background: inherit uebernimmt genau den Verlauf. */
.dx-bg__beam::before {
  content: "";
  position: absolute;
  inset: -4px -6px;
  background: inherit;
  filter: blur(6px);
  opacity: 0.7;
}

/* Start ausserhalb, Ziel ausserhalb: der Streifen taucht nicht mitten im
   Bild auf und verschwindet nicht mitten im Bild. */
@keyframes dx-beam-v {
  from { transform: translateY(-40vh); }
  to   { transform: translateY(102vh); }
}

@keyframes dx-beam-h {
  from { transform: translateX(-36vw); }
  to   { transform: translateX(104vw); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-bg__beams { display: none; }
}

/* ==========================================================================
   SPRUNGZIELE  (Menuepunkte, die auf einen Abschnitt der Startseite zeigen)
   --------------------------------------------------------------------------
   Die Kopfleiste steht klebend oben (der Wrapper ist sticky, die Leiste misst
   64 px). Ohne scroll-margin landet ein Sprung genau unter ihr und die
   Ueberschrift des Abschnitts ist verdeckt. Der Wert haelt sie frei.
   ========================================================================== */

.component[id] {
  scroll-margin-top: 5.5rem;
}

/* ==========================================================================
   NAVIGATION: ANGEKUENDIGTER EINTRAG  ("soon.")
   --------------------------------------------------------------------------
   Fuer Menuepunkte, deren Seite es noch nicht gibt. Sie werden in navbar.njk
   als <span> statt <a> ausgegeben (link.soon), fuehren also nirgendwohin —
   sonst zeigt SellAuth seine eigene 404-Seite, die mit dem Theme nichts zu
   tun hat.

   Der Eintrag bleibt lesbar, nimmt sich aber sichtbar zurueck: gedaempft,
   kein Zeigefinger, kein Hover-Wechsel. Die Marke daneben sagt, warum.
   ========================================================================== */

.dx-tab--soon {
  cursor: default;
  color: rgba(var(--cl-t-primary), 0.38);
}

/* Die Hover-Regeln oben gelten fuer alle .dx-tab — hier zuruecknehmen,
   damit der Eintrag nicht anklickbar WIRKT. */
.dx-tab--soon:hover,
.dx-tab--soon:focus-visible {
  color: rgba(var(--cl-t-primary), 0.38);
}

.dx-tab--soon .dx-tab__icon {
  opacity: 0.4;
}

.dx-tab--soon:hover .dx-tab__icon {
  transform: none;
  opacity: 0.4;
}

.dx-tab__soon {
  margin-left: 0.1rem;
  padding: 0.16rem 0.42rem;
  border-radius: 999px;
  font-size: 0.625rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  line-height: 1;
  color: color-mix(in srgb, var(--dx-glow) 35%, #fff);
  background: rgba(var(--cl-accent), 0.16);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.35);
}

/* Auf schmalen Bildschirmen zaehlt jeder Millimeter in der Leiste. */
@media (max-width: 480px) {
  .dx-tab__soon {
    padding: 0.14rem 0.34rem;
    font-size: 0.563rem;
  }
}

/* ==========================================================================
   STATUSSEITE: LEERZUSTAND  (components/status-page.njk)
   --------------------------------------------------------------------------
   Erscheint nur, wenn an keinem Produkt ein Status gesetzt ist. Ohne diesen
   Block stand auf der Seite nur die Ueberschrift und sonst nichts — das sieht
   nach Fehler aus, ist aber keiner.

   Bewusst dieselbe Mattglas-Sprache wie die Abschnitte der Produktseite,
   damit es wie ein geplanter Zustand wirkt und nicht wie ein Rest.
   ========================================================================== */

.dx-status-empty {
  max-width: 34rem;
  margin: 0 auto;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border-radius: 18px;
  text-align: center;
  background: rgba(255, 255, 255, 0.04);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
          backdrop-filter: blur(18px) saturate(1.5);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 24px 50px -34px rgba(0, 0, 0, 0.9);
}

/* Ruhig pulsierender Punkt: signalisiert "wird beobachtet", ohne Alarm. */
.dx-status-empty__dot {
  display: block;
  width: 10px;
  height: 10px;
  margin: 0 auto 1rem;
  border-radius: 50%;
  background: rgb(var(--cl-accent));
  box-shadow: 0 0 0 0 rgba(var(--cl-accent), 0.55);
  animation: dx-status-empty-pulse 2.6s ease-out infinite;
}

@keyframes dx-status-empty-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(var(--cl-accent), 0.5); }
  70%  { box-shadow: 0 0 0 14px rgba(var(--cl-accent), 0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--cl-accent), 0); }
}

.dx-status-empty__title {
  margin: 0 0 0.5rem;
  font-size: 1.125rem;
  font-weight: 800;
  color: #fff;
}

.dx-status-empty__text {
  margin: 0;
  font-size: 0.938rem;
  line-height: 1.6;
  color: rgba(var(--cl-t-primary), 0.55);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dx-status-empty { background: rgb(var(--cl-card)); }
}

@media (prefers-reduced-motion: reduce) {
  .dx-status-empty__dot { animation: none; }
}


/* ==========================================================================
   MENU DEMO  (components/menu-demo.njk)
   --------------------------------------------------------------------------
   Links Text, rechts das bedienbare Fenster.

   --dx-esp ist die Farbe aller Overlay-Linien: Kasten, Skelett, Sichtlinie,
   Fangkreis, Entfernung. An einer Stelle gesetzt, ueberall verwendet — ein
   Farbwechsel ist damit eine Zeile. Der Lebensbalken bleibt bewusst gruen:
   er zeigt einen Wert, keine Umrisslinie, und Gruen liest sich als "voll".
   ========================================================================== */

.dx-demo {
  --dx-esp: #b16bff;
}

.dx-demo__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
}

/* ---------- Linke Spalte ---------- */
.dx-demo__copy .dx-section-title { margin-top: 0.9rem; }
.dx-demo__copy .dx-section-sub { max-width: 30rem; }

.dx-demo__points {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin: 1.6rem 0 0;
  padding: 0;
  list-style: none;
}

.dx-demo__point {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: rgba(var(--cl-t-primary), 0.62);
}

.dx-demo__point strong { color: #fff; font-weight: 700; }

.dx-demo__check {
  flex: none;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-top: 0.15rem;
  border-radius: 50%;
  background: rgba(var(--cl-accent), 0.18);
  color: var(--dx-esp);
}

.dx-demo__check svg { width: 12px; height: 12px; }

.dx-demo__cta { margin-top: 1.8rem; }

/* ---------- Fenster ---------- */
.dx-demo__window {
  border-radius: 14px;
  overflow: hidden;
  background: rgba(10, 9, 24, 0.72);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
          backdrop-filter: blur(20px) saturate(1.4);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.10),
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 40px 80px -48px rgba(0, 0, 0, 1);
}

.dx-demo__chrome {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(255, 255, 255, 0.02);
}

.dx-demo__dots { display: inline-flex; gap: 0.32rem; }

.dx-demo__dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
}

.dx-demo__dots i:nth-child(1) { background: #ff5f57; }
.dx-demo__dots i:nth-child(2) { background: #febc2e; }
.dx-demo__dots i:nth-child(3) { background: #28c840; }

.dx-demo__name {
  font-size: 0.8125rem;
  font-weight: 700;
  color: rgba(var(--cl-t-primary), 0.85);
}

.dx-demo__state {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: auto;
  font-size: 0.75rem;
  font-weight: 700;
  color: #22c55e;
}

.dx-demo__state-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #22c55e;
  animation: dx-demo-pulse 2.4s ease-out infinite;
}

@keyframes dx-demo-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.5); }
  70%  { box-shadow: 0 0 0 9px rgba(34, 197, 94, 0); }
  100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
}

/* ---------- Reiter ---------- */
.dx-demo__tabs {
  display: flex;
  gap: 0.2rem;
  padding: 0.5rem 0.6rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  overflow-x: auto;
  scrollbar-width: none;
}

.dx-demo__tabs::-webkit-scrollbar { display: none; }

.dx-demo__tab {
  flex: none;
  padding: 0.45rem 0.8rem;
  border: 0;
  border-radius: 8px 8px 0 0;
  background: transparent;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  color: rgba(var(--cl-t-primary), 0.5);
  cursor: pointer;
  transition: color 0.2s ease, background-color 0.2s ease;
}

.dx-demo__tab:hover { color: rgba(var(--cl-t-primary), 0.8); }

.dx-demo__tab.is-active {
  color: #fff;
  background: rgba(var(--cl-accent), 0.16);
  box-shadow: inset 0 -2px 0 var(--dx-esp);
}

/* ---------- Koerper ---------- */
.dx-demo__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
}

.dx-demo__panel {
  padding: 0.35rem 0.1rem 0.5rem;
  border-right: 1px solid rgba(255, 255, 255, 0.06);
}

.dx-demo__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.5rem 0.8rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.045);
}

.dx-demo__row:last-child { border-bottom: 0; }

.dx-demo__label {
  font-size: 0.8125rem;
  color: rgba(var(--cl-t-primary), 0.82);
}

/* ---------- Schalter ---------- */
.dx-demo__switch {
  flex: none;
  position: relative;
  width: 36px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  cursor: pointer;
  transition: background-color 0.25s var(--dx-ease);
}

.dx-demo__switch.is-on {
  background: var(--dx-esp);
  box-shadow: 0 0 12px -2px var(--dx-esp);
}

.dx-demo__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.25s var(--dx-ease);
}

.dx-demo__switch.is-on .dx-demo__knob { transform: translateX(16px); }

.dx-demo__switch:focus-visible {
  outline: 2px solid var(--dx-esp);
  outline-offset: 3px;
}

/* ---------- Vorschau ---------- */
.dx-demo__preview {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem;
  background:
    radial-gradient(70% 60% at 50% 30%, rgba(var(--cl-accent), 0.12), transparent 70%),
    rgba(0, 0, 0, 0.28);
}

/* Festes Seitenverhaeltnis = dasselbe wie das viewBox der Zeichnung.
   Nur so liegen Bild und Zeichnung in jeder Groesse deckungsgleich. */
.dx-demo__scene {
  position: relative;
  width: 100%;
  max-width: 190px;
  aspect-ratio: 260 / 360;
}

.dx-demo__player {
  position: absolute;
  left: 50%;
  bottom: 6%;
  height: 76%;
  width: auto;
  transform: translateX(-50%);
  transition: filter 0.3s ease;
}

/* Chams: die Figur wird eingefaerbt, wie es die Funktion im Spiel tut. */
.dx-demo__player.is-chams {
  filter: brightness(0.7) sepia(1) hue-rotate(238deg) saturate(3.4);
}

.dx-demo__hud {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  /* Neon: der Schein kommt vom Filter, nicht von einer zweiten Linie.
     drop-shadow folgt der Form, box-shadow wuerde den Kasten umranden. */
  filter: drop-shadow(0 0 3px rgba(177, 107, 255, 0.85));
}

.dx-demo__box {
  fill: none;
  stroke: var(--dx-esp);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}

.dx-demo__skel line {
  stroke: var(--dx-esp);
  stroke-width: 1.8;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.dx-demo__skel circle {
  fill: none;
  stroke: var(--dx-esp);
  stroke-width: 1.8;
  vector-effect: non-scaling-stroke;
}

.dx-demo__fov {
  fill: none;
  stroke: var(--dx-esp);
  stroke-opacity: 0.7;
  stroke-width: 1.4;
  stroke-dasharray: 5 6;
  vector-effect: non-scaling-stroke;
  animation: dx-demo-fov 12s linear infinite;
  transform-origin: 130px 170px;
}

@keyframes dx-demo-fov {
  to { transform: rotate(360deg); }
}

.dx-demo__snap {
  stroke: var(--dx-esp);
  stroke-opacity: 0.85;
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}

.dx-demo__hp-bg { fill: rgba(0, 0, 0, 0.55); }
.dx-demo__hp { fill: #22c55e; }

/* ---------- Beschriftungen ---------- */
.dx-demo__tag {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 0.625rem;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}

.dx-demo__tag--name { top: 8%; }

.dx-demo__tag--dist {
  bottom: 1%;
  color: var(--dx-esp);
  text-shadow: 0 0 6px rgba(177, 107, 255, 0.6), 0 1px 3px rgba(0, 0, 0, 0.9);
}

/* ---------- Fusszeile ---------- */
.dx-demo__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  padding: 0.55rem 0.85rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(255, 255, 255, 0.02);
  font-size: 0.75rem;
}

.dx-demo__foot-key { color: rgba(var(--cl-t-primary), 0.45); }
.dx-demo__foot-val { color: #22c55e; font-weight: 700; }
.dx-demo__foot-sep { margin: 0 0.35rem; color: rgba(var(--cl-t-primary), 0.3); }

.dx-demo__note {
  margin: 1rem 0 0;
  text-align: center;
  font-size: 0.75rem;
  color: rgba(var(--cl-t-primary), 0.35);
}

/* ---------- Schmale Bildschirme ---------- */
@media (max-width: 1023.98px) {
  .dx-demo__grid { grid-template-columns: minmax(0, 1fr); }
  .dx-demo__window { max-width: 32rem; }
}

@media (max-width: 519.98px) {
  .dx-demo__body { grid-template-columns: minmax(0, 1fr); }
  /* Vorschau nach OBEN: die Wirkung eines Schalters soll sichtbar sein,
     ohne dass man erst scrollen muss. */
  .dx-demo__preview { order: -1; border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
  .dx-demo__panel { border-right: 0; }
  .dx-demo__scene { max-width: 165px; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-demo__state-dot,
  .dx-demo__fov { animation: none; }
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dx-demo__window { background: rgb(var(--cl-card)); }
}

/* ==========================================================================
   TRENNLINIE  (.dx-rule)
   --------------------------------------------------------------------------
   Dieselbe Linie wie unter der Kopfleiste (.dx-top) und ueber dem Footer:
   ein violetter Verlauf, der zu beiden Seiten ausblendet, und ein weisses
   Licht, das langsam darueber wandert.

   Bewusst als eigenes, wiederverwendbares Element herausgezogen — vorher
   steckte das Muster zweimal als Pseudo-Element in fremden Bauteilen.
   Die Sweep-Animation wird geteilt (@keyframes dx-line-sweep).
   ========================================================================== */

.dx-rule {
  position: relative;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--dx-violet) 20%,
    var(--dx-glow) 50%,
    var(--dx-violet) 80%,
    transparent 100%);
  box-shadow: 0 0 14px 0 rgba(var(--cl-accent), 0.35);
  opacity: 0.55;
}

.dx-rule::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95), transparent) no-repeat;
  background-size: 18% 100%;
  background-position: -30% 0;
  opacity: 0.6;
  animation: dx-line-sweep 7s linear infinite;
}

/* Die zweite Linie im selben Abschnitt laeuft versetzt — sonst wandern beide
   Lichter im Gleichschritt und es wirkt mechanisch. */
.dx-rule + * ~ .dx-rule::after,
.dx-rule:last-child::after { animation-delay: -3.5s; }

@media (prefers-reduced-motion: reduce) {
  .dx-rule::after { animation: none; opacity: 0; }
}

/* ---------- Abstand um die Menue-Demo ----------
   Der Abschnitt braucht Luft: darueber endet die Feature-Reihe des Heros
   dicht am Text, darunter beginnen sofort die Produktkarten. */
.dx-demo .dx-rule:first-child { margin-bottom: clamp(3rem, 7vw, 5.5rem); }
.dx-demo .dx-rule:last-child  { margin-top: clamp(3rem, 7vw, 5.5rem); }

.dx-demo { padding-block: clamp(2.5rem, 6vw, 4.5rem); }

/* ==========================================================================
   KUNDENBEREICH  (alle Seiten unter /customer/...)
   --------------------------------------------------------------------------
   Die acht Kundenseiten benutzen noch das Standardmarkup von SellAuth:
   eckige Karten aus Tailwind-Klassen, schmucklose Liste als Seitenleiste.
   Statt acht Vorlagen (zusammen ueber 110 KB) umzuschreiben, setzt dieser
   Block am vorhandenen Markup an. Vorteil: ein Theme-Update ueberschreibt
   die Vorlagen, aber nicht diese Datei.

   Aufhaenger:
     .dx-customer  auf dem Inhaltsrahmen (layouts/master.njk, nur wenn
                   templateName mit "customer" beginnt)
     .dx-cside     auf der Seitenleiste (snippets/customer-sidebar.njk)

   Angesprochen wird ueber [class~="..."] statt ueber maskierte Punktnamen:
   das trifft die Tailwind-Klasse als ganzes Wort und bleibt lesbar — bei
   "bg-card/75" muesste man sonst den Schraegstrich maskieren.
   ========================================================================== */

/* Ein ruhiger Schein hinter dem Bereich, damit die Flaeche nicht so leer
   wirkt wie im Standard. Gleiches Mittel wie auf der Produktseite. */
.dx-customer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: min(1100px, 120%);
  height: 520px;
  transform: translateX(-50%);
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(var(--cl-accent), 0.16), transparent 72%);
}

/* Der Standard setzt py-16 / lg:py-32 — auf einer eingeloggten Seite ist das
   viel Leerraum, bevor ueberhaupt etwas kommt. */
.dx-customer [class~="py-16"] {
  padding-top: clamp(1.5rem, 4vw, 3rem);
  padding-bottom: clamp(2rem, 5vw, 4rem);
}

/* ---------- Karten: Liquid Glass ----------
   Die Rezeptur steht unten in .dx-glass, damit sie sich an einer Stelle
   pflegen und anderswo wiederverwenden laesst. */
.dx-customer [class~="bg-card/75"] {
  border: 0;
}

/* Trennlinien innerhalb einer Karte duerfen bleiben, aber leiser. */
.dx-customer [class~="border-b-2"],
.dx-customer [class~="border-b"] {
  border-bottom-color: rgba(255, 255, 255, 0.06);
}

/* ---------- Seitenleiste ---------- */
.dx-cside ul {
  gap: 0.15rem;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  background: transparent;
}

.dx-cside ul li a,
.dx-cside ul li button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  border-radius: 10px;
  font-weight: 600;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.dx-cside ul li a:hover,
.dx-cside ul li button:hover {
  background: rgba(255, 255, 255, 0.05);
}

/* Der aktive Eintrag traegt im Standardmarkup text-accent-500 — daran
   erkennt man ihn, ohne die Vorlage anzufassen. */
.dx-cside ul li a[class~="text-accent-500"] {
  position: relative;
  background: rgba(var(--cl-accent), 0.14);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.3);
}

.dx-cside ul li a[class~="text-accent-500"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 3px;
  height: 18px;
  transform: translateY(-50%);
  border-radius: 0 3px 3px 0;
  background: rgb(var(--cl-accent));
}

/* ---------- Schaltflaechen ---------- */
/* Hauptaktion: derselbe Verlauf wie die Kaufknoepfe im Rest des Themes. */
.dx-customer button[class~="bg-accent-500"],
.dx-customer a[class~="bg-accent-500"] {
  border-color: transparent;
  border-radius: 11px;
  background: linear-gradient(135deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow: 0 10px 24px -12px rgba(var(--cl-accent), 0.85);
}

.dx-customer button[class~="bg-accent-500"]:hover,
.dx-customer a[class~="bg-accent-500"]:hover {
  filter: brightness(1.08);
}

/* Nebenaktionen und Warnungen: nur Form und Kante, Farbe bleibt. */
.dx-customer button[class~="border-accent-500"]:not([class~="bg-accent-500"]),
.dx-customer a[class~="border-accent-500"]:not([class~="bg-accent-500"]),
.dx-customer button[class~="border-red-500"],
.dx-customer a[class~="border-red-500"] {
  border-radius: 11px;
}

.dx-customer button[class~="border-red-500"]:hover {
  background: rgba(239, 68, 68, 0.12);
}

/* ---------- Eingabefelder ---------- */
.dx-customer input,
.dx-customer select,
.dx-customer textarea {
  border-radius: 11px;
}

.dx-customer input:focus,
.dx-customer select:focus,
.dx-customer textarea:focus {
  outline: none;
  box-shadow: 0 0 0 2px rgba(var(--cl-accent), 0.45);
}

/* ---------- Tabellen und Zeilen ---------- */
.dx-customer table { border-collapse: separate; border-spacing: 0; }

.dx-customer tbody tr {
  transition: background-color 0.2s ease;
}

.dx-customer tbody tr:hover {
  background: rgba(255, 255, 255, 0.035);
}

.dx-customer th {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.45);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dx-customer [class~="bg-card/75"] { background: rgb(var(--cl-card)); }
}

/* ---------- Anmeldefenster (snippets/customer-login-modal.njk) ----------
   Wer nicht angemeldet ist, sieht beim Klick auf "Dashboard" zuerst dieses
   Fenster. Es ist also der erste Eindruck vom Kundenbereich und bekommt
   dieselbe Sprache: runde Ecken, Mattglas, Knopf mit Verlauf. */

.dx-login {
  border: 0 !important;
  border-radius: 18px;
  background: rgba(14, 12, 34, 0.86) !important;
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
          backdrop-filter: blur(22px) saturate(1.5);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 50px 90px -50px rgba(0, 0, 0, 1);
}

.dx-login input,
.dx-login select {
  border-radius: 11px;
}

.dx-login input:focus {
  outline: none;
  box-shadow: 0 0 0 2px rgba(var(--cl-accent), 0.45);
}

/* Hauptknopf im Fenster: derselbe Verlauf wie die Kaufknoepfe. */
.dx-login button[class~="bg-accent-500"] {
  border-color: transparent;
  border-radius: 11px;
  background: linear-gradient(135deg, var(--dx-btn-from), var(--dx-btn-to));
  box-shadow: 0 10px 24px -12px rgba(var(--cl-accent), 0.85);
}

.dx-login button[class~="bg-accent-500"]:hover { filter: brightness(1.08); }

/* Discord-Knopf und andere Nebenaktionen: nur die Form angleichen. */
.dx-login button:not([class~="bg-accent-500"]),
.dx-login a[class*="border"] {
  border-radius: 11px;
}

/* ==========================================================================
   LIQUID GLASS  (.dx-glass)
   --------------------------------------------------------------------------
   Glas nach Apple-Art. Der Unterschied zu einfachem Mattglas liegt nicht in
   der Unschaerfe, sondern in vier Dingen:

   1. SAETTIGUNG UND HELLIGKEIT hinter der Scheibe werden angehoben. Ohne das
      wirkt Glas grau und tot, egal wie stark man weichzeichnet.
   2. KANTENLICHT. Eine echte Glasplatte bricht das Licht an der Oberkante
      hell und an der Unterkante schwaecher. Deshalb vier verschieden helle
      Innenkanten statt eines gleichmaessigen 1px-Rahmens.
   3. TIEFE. Ein weicher heller Schein direkt unter der Oberkante laesst die
      Scheibe dick wirken statt wie eine aufgeklebte Folie.
   4. VERLAUF IN DER FLAECHE. Oben heller, zur Mitte hin fast nichts, unten
      wieder etwas heller — das ist die Reflexion der Umgebung.

   Der Schimmer oben links liegt im ::before, damit er die Flaeche nicht
   einfaerbt und beim Ueberfahren wandern kann.
   ========================================================================== */

.dx-glass,
.dx-customer [class~="bg-card/75"],
.dx-login,
.dx-section__body:has(> h2, > h3, > h4) > ul {
  position: relative;
  isolation: isolate;
  border: 0 !important;
  border-radius: 20px;
  background:
    linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.13) 0%,
      rgba(255, 255, 255, 0.035) 26%,
      rgba(255, 255, 255, 0.02) 68%,
      rgba(255, 255, 255, 0.07) 100%
    ),
    rgba(255, 255, 255, 0.035) !important;
  -webkit-backdrop-filter: blur(26px) saturate(1.9) brightness(1.06);
          backdrop-filter: blur(26px) saturate(1.9) brightness(1.06);
  box-shadow:
    /* Kantenlicht: oben hell, seitlich schwach, unten dazwischen */
    inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 1px 0 0 rgba(255, 255, 255, 0.10),
    inset -1px 0 0 rgba(255, 255, 255, 0.10),
    inset 0 -1px 0 rgba(255, 255, 255, 0.16),
    /* Tiefe: weicher Schein unter der Oberkante */
    inset 0 10px 24px -14px rgba(255, 255, 255, 0.35),
    /* Die Scheibe wirft Schatten auf die Seite dahinter */
    0 26px 56px -34px rgba(0, 0, 0, 0.95);
}

/* Schimmer oben links — die Stelle, an der das Licht einfaellt. */
.dx-glass::before,
.dx-customer [class~="bg-card/75"]::before,
.dx-login::before,
.dx-section__body:has(> h2, > h3, > h4) > ul::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background:
    radial-gradient(120% 80% at 8% -12%, rgba(255, 255, 255, 0.16), transparent 58%),
    radial-gradient(90% 60% at 100% 108%, rgba(var(--cl-accent), 0.12), transparent 62%);
}

/* Die Seitenleiste ist hoeher als breit — dort wirkt der Radius sonst zu
   klein im Verhaeltnis zur Flaeche. */
.dx-cside { border-radius: 22px; }

.dx-login { border-radius: 24px; }

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dx-glass,
  .dx-customer [class~="bg-card/75"],
  .dx-login,
  .dx-section__body:has(> h2, > h3, > h4) > ul {
    background: rgb(var(--cl-card)) !important;
  }
}

/* ==========================================================================
   BESCHREIBUNG IN ABSCHNITTE  (components/product-page.njk → Description)
   --------------------------------------------------------------------------
   Lange Beschreibungen kommen aus SellAuth als ein Block Rich-Text, meist
   nach dem Muster: Zwischenueberschrift, Liste, Zwischenueberschrift, Liste.
   In einer einzigen Karte ist das eine Wand aus Haken.

   Hier wird daraus je Gruppe eine eigene Karte — ohne den Text anzufassen
   und ohne JavaScript. :has() prueft, ob ueberhaupt Zwischenueberschriften
   vorhanden sind; nur dann loest sich die aeussere Karte auf. Eine
   Beschreibung aus reinem Fliesstext behaelt ihre eine Karte.

   Ohne :has()-Unterstuetzung (sehr alte Browser) bleibt alles beim Alten:
   eine Karte, lesbar, nur nicht gegliedert.
   ========================================================================== */

/* Der Rich-Text bringt eigene Listenklassen mit: .e-list-ul setzt
   list-style-type: disc und einen linken Einzug. Das ist spezifischer als
   ".dx-section__body ul" und gewinnt trotz spaeterer Ladereihenfolge —
   deshalb hier ausdruecklich zurueckgenommen. Sonst stehen pro Zeile ZWEI
   Marker: der Punkt des Browsers und der gezeichnete Haken. */
.dx-section__body .e-list-ul,
.dx-section__body .e-list-ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Aeussere Karte aufloesen, sobald es Zwischenueberschriften gibt. */
.dx-section__body:has(> h2, > h3, > h4) {
  padding: 0;
  background: none !important;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  box-shadow: none;
}

.dx-section__body:has(> h2, > h3, > h4)::before { content: none; }

/* Zwischenueberschrift als Titel ueber ihrer Karte. */
.dx-section__body > h2,
.dx-section__body > h3,
.dx-section__body > h4 {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 2rem 0 0.8rem;
  font-size: 1.0625rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: #fff;
}

.dx-section__body > h2:first-child,
.dx-section__body > h3:first-child,
.dx-section__body > h4:first-child { margin-top: 0; }

/* Kurzer Akzentbalken davor — dasselbe Zeichen wie beim aktiven Eintrag in
   der Seitenleiste des Kundenbereichs. */
.dx-section__body > h2::before,
.dx-section__body > h3::before,
.dx-section__body > h4::before {
  content: "";
  flex: none;
  width: 3px;
  height: 1.05em;
  border-radius: 2px;
  background: rgb(var(--cl-accent));
}

/* Die Liste selbst ist die Karte (Glasrezeptur oben). Hier nur Innenmass
   und Rasterverhalten.

   Der zweite Selektor ist noetig, nicht doppelt gemoppelt: ":has(> h3)"
   zaehlt nur so viel wie ein Typselektor, die Regel kaeme damit auf (0,1,2)
   und verloere gegen ".dx-section__body .e-list-ul" mit (0,2,0) — die Karte
   haette keine Polsterung. Mit der Klasse am Ende steht es (0,2,2). */
.dx-section__body:has(> h2, > h3, > h4) > ul,
.dx-section__body:has(> h2, > h3, > h4) > ul.e-list-ul {
  padding: clamp(1rem, 2.2vw, 1.5rem);
  gap: 0.75rem 1.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  .dx-section__body:has(> h2, > h3, > h4) > ul {
    transition: transform 0.35s var(--dx-ease), box-shadow 0.35s var(--dx-ease);
  }
}

/* ==========================================================================
   WALL OF LOVE  (components/feedback-wall.njk)
   --------------------------------------------------------------------------
   Zwei gegenlaeufige Reihen aus Bewertungskarten.

   Die Endlosschleife ist dieselbe wie bei der Logo-Leiste: die Spur besteht
   aus zwei gleichen Haelften und wandert um -50%. Dadurch liegt nach einem
   Durchlauf wieder exakt derselbe Inhalt an derselben Stelle — kein Sprung.
   Die Spur traegt zusaetzlich .dx-marquee__track, damit script.js sie mit
   Kopien auffuellt, bis eine Haelfte breiter als das Fenster ist.

   Die zweite Reihe laeuft rueckwaerts und etwas langsamer. Gleichlaufende
   Reihen wirken wie ein einziger grosser Block, gegenlaeufige erzeugen die
   Tiefe, die man von solchen Waenden kennt.
   ========================================================================== */

.dx-wall { padding-block: clamp(1rem, 3vw, 2rem); }

/* ---------- Kopf ---------- */
.dx-wall__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.dx-wall__copy { max-width: 44rem; }

.dx-wall__eyebrow { gap: 0.45rem; }

.dx-wall__heart {
  width: 13px;
  height: 13px;
  color: rgb(var(--cl-accent));
}

.dx-wall__title { margin-top: 1rem; }

.dx-wall__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 1rem;
  margin-top: 1rem;
}

.dx-wall__stars {
  display: inline-flex;
  gap: 0.12rem;
  font-size: 1rem;
  line-height: 1;
}

.dx-wall__stars--sm { font-size: 0.8125rem; }

.dx-wall__star { color: rgba(var(--cl-t-primary), 0.2); }
.dx-wall__star.is-on { color: rgb(var(--cl-accent)); }

.dx-wall__sub {
  font-size: 0.9375rem;
  color: rgba(var(--cl-t-primary), 0.55);
}

.dx-wall__link { flex: none; }

.dx-wall__rowlabel {
  margin: 0 0 0.85rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.4);
}

/* ---------- Laufende Reihe ---------- */
.dx-wall__row {
  position: relative;
  overflow: hidden;
  margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem);
  /* Zu beiden Seiten ausblenden, damit die Karten nicht hart abgeschnitten
     an der Kante kleben. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.dx-wall__row:last-child { margin-bottom: 0; }

.dx-wall__track {
  display: flex;
  width: max-content;
  gap: 1rem;
  animation: dx-wall-run var(--dx-wall-speed, 55s) linear infinite;
  will-change: transform;
}

.dx-wall__row--rev .dx-wall__track { animation-name: dx-wall-run-rev; }

/* Anhalten beim Ueberfahren: wer eine Bewertung lesen will, soll sie nicht
   verfolgen muessen. */
.dx-wall__row:hover .dx-wall__track,
.dx-wall__row:focus-within .dx-wall__track {
  animation-play-state: paused;
}

.dx-wall__group {
  display: flex;
  flex: none;
  gap: 1rem;
}

@keyframes dx-wall-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@keyframes dx-wall-run-rev {
  from { transform: translate3d(-50%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* ---------- Karte ---------- */
.dx-wall__card {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  width: clamp(240px, 26vw, 310px);
  padding: 1.1rem 1.25rem;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.04);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
          backdrop-filter: blur(18px) saturate(1.6);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 20px 40px -28px rgba(0, 0, 0, 0.95);
  transition: transform 0.3s var(--dx-ease), box-shadow 0.3s var(--dx-ease);
}

.dx-wall__row:hover .dx-wall__card:hover {
  transform: translateY(-3px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 0 0 0 1px rgba(var(--cl-accent), 0.28),
    0 26px 50px -26px rgba(var(--cl-accent), 0.4);
}

.dx-wall__cardtop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.dx-wall__date {
  font-size: 0.6875rem;
  color: rgba(var(--cl-t-primary), 0.4);
}

.dx-wall__quote {
  margin: 0;
  flex: 1 1 auto;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: rgba(var(--cl-t-primary), 0.9);
}

/* Anfuehrungszeichen kommen aus dem CSS, nicht aus dem Text — so bleibt die
   Bewertung im Original und laesst sich weiterhin durchsuchen. */
.dx-wall__quote::before { content: "\201C"; }
.dx-wall__quote::after  { content: "\201D"; }

.dx-wall__cardfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 0.6875rem;
}

.dx-wall__author {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: rgba(var(--cl-t-primary), 0.5);
}

.dx-wall__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgb(var(--cl-accent));
}

.dx-wall__tag {
  max-width: 55%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: rgba(var(--cl-t-primary), 0.38);
}

@media (max-width: 639.98px) {
  .dx-wall__card { width: clamp(220px, 78vw, 270px); }
  .dx-wall__link { width: 100%; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-wall__track { animation: none; }
  /* Ohne Lauf waere nur die erste Karte zu sehen — dann lieber umbrechen
     und alles zeigen. */
  .dx-wall__row { -webkit-mask-image: none; mask-image: none; overflow: visible; }
  .dx-wall__track { width: auto; flex-wrap: wrap; }
  .dx-wall__group { flex-wrap: wrap; }
  .dx-wall__group:not(:first-child) { display: none; }
}

/* ==========================================================================
   BESCHREIBUNG ALS KARTENRASTER  (assets/script.js → "BESCHREIBUNG ALS RASTER")
   --------------------------------------------------------------------------
   Aus dem Rich-Text von SellAuth wird ein Raster aus Karten:

   - Eine Liste, deren Eintraege dem Muster "Bezeichnung: Angabe" folgen,
     wird zu Datenkaertchen mit Symbol (Systemvoraussetzungen).
   - Jede andere Zwischenueberschrift mit Liste wird zu einer Karte, in der
     die Ueberschrift oben steht und die Liste zweispaltig darunter.

   Ohne JavaScript bleibt die bisherige Darstellung bestehen: eine Karte je
   Liste, Ueberschrift darueber. Lesbar, nur nicht im Raster.
   ========================================================================== */

/* Die aeussere Karte loest sich auf, sobald das Raster steht — die Karten
   sind jetzt die Kinder. */
.dx-section__body.is-raster {
  padding: 0;
  background: none !important;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  box-shadow: none;
}

.dx-section__body.is-raster::before { content: none; }

.dx-desc {
  display: grid;
  /* Feste Spaltenzahl statt auto-fit: mit auto-fit springt das Raster je
     nach Fensterbreite zwischen drei und vier Spalten. Drei nebeneinander
     ist die Aufteilung aus dem Entwurf. */
  /* Die Spaltenzahl setzt script.js auf die Zahl der Karten, hoechstens
     vier. Drei feste Spalten ergaben bei vier Reitern drei grosse Karten
     und eine einzelne darunter. */
  grid-template-columns: repeat(var(--dx-spalten, 3), minmax(0, 1fr));
  gap: 0.7rem;
  /* Karten einer Reihe sind gleich hoch. Unterschiedlich hohe Karten
     erzeugen eine ausgefranste Unterkante. */
  align-items: stretch;
}

/* Deckende Karte, kein Glas. Der Hintergrund der Produktseite hat einen
   Verlauf und Lichtstreifen — durch eine durchsichtige Karte wanderten die
   mit und machten die Flaeche fleckig.

   Die Grundflaeche ist die Kartenfarbe aus den Einstellungen. Darueber
   liegt ein heller Verlauf, der nach 70px ausgelaufen ist: das setzt den
   Kartenkopf ab, ohne eine zweite Flaeche zu zeichnen. */
.dx-desc__spec,
.dx-desc__card {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 70px),
    rgb(var(--cl-card));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 12px 26px -20px rgba(0, 0, 0, 0.95);
}

@media (max-width: 1099.98px) {
  .dx-desc { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Ueber die ganze Breite: Zwischenueberschriften und Fliesstext. */
.dx-desc__full { grid-column: 1 / -1; }

.dx-desc__subtitle {
  margin: 0.6rem 0 0;
  font-size: 1.0625rem;
  font-weight: 800;
  color: #fff;
}

.dx-desc__subtitle:first-child { margin-top: 0; }

/* ---------- Datenkaertchen: Symbol, Bezeichnung, Angabe ---------- */
.dx-desc__spec {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.8rem 0.9rem;
  border-radius: 11px;
}

.dx-desc__icon {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-bottom: 0.3rem;
  border-radius: 7px;
  background: rgba(var(--cl-background), 0.55);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  color: rgba(var(--cl-t-primary), 0.5);
}

.dx-desc__icon svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.dx-desc__label {
  font-size: 0.75rem;
  line-height: 1.25;
  color: rgba(var(--cl-t-primary), 0.45);
}

.dx-desc__value {
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.3;
  color: #fff;
}

/* ---------- Merkmalskarte: Ueberschrift oben, Liste darunter ---------- */
.dx-desc__card {
  padding: 0.85rem 0.95rem 0.95rem;
  border-radius: 11px;
}

.dx-desc__cardhead {
  margin: 0 0 0.6rem;
  padding-bottom: 0.6rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

/* Immer zwei Spalten — das halbiert die Hoehe der Karte. Lange Eintraege
   brechen dabei um; das ist gewollt, denn eine hohe schmale Karte fiel
   deutlicher auf als eine umgebrochene Zeile.
   Gleiche Gewichtung wie die Grundregel ".dx-section__body ul", steht aber
   spaeter in der Datei und gewinnt. */
.dx-desc__card ul {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.4rem 0.8rem;
  /* Ohne das waeren alle Eintraege einer Reihe so hoch wie der hoechste.
     Das reisst Luecken auf und verfaelscht die Umbruchmessung. */
  align-items: start;
}

/* Kleiner und enger als der Fliesstext daneben. Die Liste ist hier eine
   Aufzaehlung zum Ueberfliegen, kein Lesetext. */
.dx-desc__card ul li {
  padding-left: 1.2rem;
  font-size: 0.78125rem;
  line-height: 1.3;
  color: rgba(var(--cl-t-primary), 0.8);
}

.dx-desc__card p:last-child { margin-bottom: 0; }

@media (max-width: 599.98px) {
  .dx-desc { grid-template-columns: 1fr; }
  /* Auf dem Telefon ist die Karte so schmal, dass zwei Spalten jede Zeile
     umbrechen wuerden. */
  .dx-desc__card ul { grid-template-columns: 1fr; }
}

/* Die Reiter liegen in einem eigenen Behaelter, damit script.js sie
   zusammenfassen kann. Ohne JavaScript bleiben es mehrere Abschnitte —
   der Abstand zwischen ihnen muss derselbe sein wie zwischen den anderen
   Abschnitten der Produktseite. */
.dx-product__tabs {
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

/* ==========================================================================
   MERKMALSABSCHNITT  (assets/script.js → "BESCHREIBUNG ALS RASTER")
   --------------------------------------------------------------------------
   Der aus den Produktreitern gebaute Abschnitt bekommt einen mittigen Kopf:
   Akzentbalken, Ueberschrift, wahlweise eine Zeile darunter und die
   Systemvoraussetzungen als Chips.

   Die Chips ersetzen den eigenen Abschnitt fuer die Voraussetzungen,
   solange es hoechstens sechs Angaben sind. Zwei Datenkaertchen in einer
   eigenen Zeile ueber den Karten waren viel Flaeche fuer zwei Zeilen Text.
   ========================================================================== */

.dx-feat__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-bottom: clamp(1.25rem, 2.5vw, 1.9rem);
}

.dx-feat__bar {
  width: 34px;
  height: 3px;
  margin-bottom: 0.9rem;
  border-radius: 2px;
  background: rgb(var(--cl-accent));
}

.dx-feat__title { margin: 0; }

.dx-feat__sub {
  max-width: 44rem;
  margin: 0.55rem 0 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: rgba(var(--cl-t-primary), 0.55);
}

.dx-feat__pills {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1rem;
}

.dx-feat__pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.38rem 0.8rem;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.85);
  background: rgb(var(--cl-card));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09);
}

.dx-feat__pill svg {
  flex: none;
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: rgb(var(--cl-accent));
}

/* Bleibt in der letzten Reihe eine Karte allein, nimmt sie die ganze
   Breite ein — und darf dann mehr Spalten fuer ihre Liste nutzen. */
.dx-desc__card--voll { grid-column: 1 / -1; }

.dx-desc__card--voll ul {
  grid-template-columns: repeat(var(--dx-spalten, 3), minmax(0, 1fr));
}

/* Pfeil statt Haken: in der Merkmalsliste steht der Haken auf jeder Zeile
   und wird dadurch zur Tapete. Der Pfeil fuehrt das Auge in die Zeile. */
.dx-desc__card ul li::before {
  top: 0.32em;
  width: 5px;
  height: 5px;
  border: 0;
  border-top: 1.6px solid var(--dx-glow);
  border-right: 1.6px solid var(--dx-glow);
  transform: rotate(45deg);
}

@media (max-width: 599.98px) {
  .dx-desc__card--voll ul { grid-template-columns: 1fr; }
}

/* Karte mit umbrechenden Eintraegen: eine Spalte. Die Klasse setzt
   script.js nach dem Messen, nicht nach der Zeichenzahl. */
.dx-desc__card--lang ul,
.dx-desc__card--lang.dx-desc__card--voll ul { grid-template-columns: 1fr; }

/* Gruppenfenster: sichtbar nur mit .is-open. Frueher steuerte Alpine das
   ueber eine Inline-Formatierung; jetzt macht es assets/script.js
   ("GRUPPENFENSTER") ueber diese Klasse. */
.dx-modal {
  opacity: 0;
  transition: opacity 0.22s ease;
}

.dx-modal.is-open { opacity: 1; }

.dx-modal[hidden] { display: none; }

.dx-modal .dx-modal__panel {
  transform: translateY(14px) scale(0.97);
  transition: transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.dx-modal.is-open .dx-modal__panel { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .dx-modal,
  .dx-modal .dx-modal__panel { transition: none; }
}

/* Fenster einer Gruppe ohne Produkte: ein ruhiger Hinweis statt einer
   leeren Flaeche unter der Ueberschrift. */
.dx-modal__empty {
  margin: 0;
  padding: 1.6rem 1.25rem 1.75rem;
  font-size: 0.875rem;
  text-align: center;
  color: rgba(var(--cl-t-primary), 0.55);
}

/* Listenpunkte mit eigenem Zeichen (✅ ❌ 🛑 …) aus unformatiert
   eingefuegtem Text: das Zeichen steht schon im Text, der gezeichnete
   Pfeil bzw. Haken entfaellt. Sonst staenden zwei Zeichen vor der Zeile.
   (assets/script.js → "Unformatierten Text gliedern") */
.dx-section__body ul li.dx-li-zeichen { padding-left: 0; }
.dx-section__body ul li.dx-li-zeichen::before { content: none; }

/* Absaetze in einer Karte so gross wie die Listenpunkte daneben. Ohne das
   greift die Grundgroesse des Fliesstexts, und ein erklaerender Satz
   steht doppelt so laut da wie die Liste in der Nachbarkarte. */
.dx-desc__card p:not(.dx-desc__cardhead) {
  font-size: 0.78125rem;
  line-height: 1.5;
  color: rgba(var(--cl-t-primary), 0.8);
}

/* ==========================================================================
   HANDY: RUHIGER, SCHNELLER, LESBARER  (bis 767px Breite)
   --------------------------------------------------------------------------
   Gemessen auf 375 px: 59 laufende Animationen, 23 davon endlos, und 16
   Elemente mit backdrop-filter — darunter die feste Kopf- und Tab-Leiste.
   Ein Weichzeichner auf einer festen Leiste wird bei JEDEM Scroll-Bild neu
   berechnet; der Lichtstreifen darin animierte zusaetzlich die
   Hintergrundposition, also wurde die Leiste in jedem Bild neu gezeichnet
   UND neu weichgezeichnet. Auf Handy-Grafikchips ist das das Ruckeln.

   Hier wird auf dem Handy zurueckgenommen, was teuer ist und auf dem
   kleinen Bildschirm kaum auffaellt. Der Desktop bleibt unveraendert.
   ========================================================================== */

@media (max-width: 767.98px) {

  /* ---------- 1. Kopfleiste deckend statt Glas ----------
     Ohne Deckkraft schien beim Scrollen der Inhalt durch die Leiste —
     Text aus den Abschnitten stand hinter dem Logo. */
  .dx-top,
  .dx-header.is-scrolled .dx-top,
  .dx-header.is-open .dx-top {
    background:
      linear-gradient(180deg, rgba(var(--cl-accent), 0.07), transparent 70%),
      rgb(var(--cl-background));
  }

  .dx-tabs,
  .dx-header.is-scrolled .dx-tabs {
    background: rgb(var(--cl-background));
  }

  /* Wandernder Lichtpunkt auf der Trennlinie: die ruhende Linie bleibt. */
  .dx-top::before { animation: none; opacity: 0; }

  /* ---------- 2. Navigation: alle Eintraege sichtbar ----------
     Vorher passten nur "Home", "Products" und "Reselling" in die Breite;
     Status, Blog und Reviews lagen unsichtbar rechts daneben, und nichts
     zeigte, dass man wischen kann. Das Menue rechts oben enthaelt diese
     Seiten nicht — die Leiste ist auf dem Handy die einzige Navigation.
     Jetzt: alle Eintraege gleich breit, Symbol ueber kurzer Beschriftung,
     wie die Leiste unten in einer App. */
  .dx-tabs__list {
    gap: 0;
    height: 58px;
  }

  .dx-tab {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    justify-content: center;
    gap: 0.3rem;
    height: 50px;
    padding: 0 0.1rem;
    font-size: 0.6875rem;
  }

  .dx-tab > span:not(.dx-tab__soon) {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .dx-tab__icon { width: 18px; height: 18px; }

  .dx-tabs__indicator {
    height: 50px;
    margin-top: -25px;
  }

  /* "soon." sitzt als kleine Marke an der Ecke, statt die Beschriftung
     zu verbreitern. */
  .dx-tab--soon { position: relative; }

  .dx-tab__soon {
    position: absolute;
    top: 1px;
    left: 50%;
    margin: 0 0 0 4px;
    padding: 0.1rem 0.28rem;
    font-size: 0.5rem;
  }

  /* ---------- 3. Hero: Text oben, Figur vollstaendig ----------
     Die Figur lag zur Haelfte hinter der Kopfleiste (Kopf abgeschnitten),
     der Text war senkrecht mittig gesetzt und begann erst nach rund
     300 px leerem Bild. */
  .dx-hero__body {
    align-items: flex-start;
    padding: 1.75rem 0 2rem;
  }

  .dx-hero__art {
    top: calc(var(--dx-header-h) + 1rem);
    bottom: auto;
    width: 100%;
    height: 500px;
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, rgba(0, 0, 0, 0.4) 72%, transparent 100%);
            mask-image: linear-gradient(to bottom, #000 0%, #000 45%, rgba(0, 0, 0, 0.4) 72%, transparent 100%);
  }

  .dx-hero__img {
    top: 0;
    height: 100%;
    object-position: 62% 0%;
  }

  /* ---------- 4. Effekte, die das Handy ausbremsen ---------- */

  /* Weichzeichner hinter Flaechen: der teuerste Effekt beim Scrollen.
     Die Flaechen behalten ihre halbdurchsichtige Farbe, sie zeichnen den
     Hintergrund nur nicht mehr verwaschen nach. */
  *,
  *::before,
  *::after {
    -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
  }

  /* Endlose Hintergrundbewegung. Farben und Verlaeufe bleiben stehen,
     sie bewegen sich nur nicht mehr. */
  .dx-bg__aurora,
  .dx-bg__floor::before,
  .dx-hero__gradient,
  .dx-rule::after,
  .dx-foot__top::before {
    animation: none;
  }

  .dx-bg__aurora { will-change: auto; }
  .dx-bg__floor::before { will-change: auto; }

  /* Schnee: zwei bildschirmhohe Ebenen in Dauerbewegung — auf dem kleinen
     Bildschirm kaum zu sehen, aber staendig neu zusammengesetzt. */
  .dx-hero__snow { display: none; }

  /* Einblenden beim Scrollen ohne Weichzeichner: filter: blur() auf
     grossen Kacheln ist pro Bild teuer. Bewegung und Ausblenden bleiben. */
  [data-dx-reveal] {
    transition:
      opacity 0.6s ease,
      transform 0.7s var(--dx-ease);
    transition-delay: var(--dx-delay, 0ms);
  }

  .dx-reveal-ready [data-dx-reveal]:not(.is-revealed) {
    filter: none;
    transform: translate3d(0, 20px, 0);
  }
}

/* ---------- 5. Gruppenkacheln zweispaltig ----------
   Einspaltig war jede Kachel rund 395 px hoch; sieben Gruppen ergaben eine
   sehr lange Liste. Zweispaltig halbiert das. Unter 340 px (sehr kleine
   Geraete) bleibt es einspaltig, sonst wird die Schrift zu klein. */
@media (min-width: 340px) and (max-width: 639.98px) {
  .dx-fp__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.7rem;
  }

  .dx-pcard__body {
    gap: 0.3rem;
    margin-top: -0.5rem;
    padding: 0 0.75rem 0.75rem;
  }

  .dx-pcard__meta { font-size: 0.6875rem; }
  .dx-pcard__meta svg { width: 12px; height: 12px; }

  .dx-pcard__title { font-size: 0.9375rem; }

  .dx-pcard__foot {
    gap: 0.4rem;
    padding-top: 0.6rem;
  }

  .dx-pcard__from { font-size: 0.6rem; }
  .dx-pcard__amount { font-size: 1.05rem; }

  .dx-pcard__go {
    width: 32px;
    height: 32px;
    border-radius: 10px;
  }

  .dx-pcard__go svg { width: 15px; height: 15px; }
}

/* ==========================================================================
   GRUPPENFENSTER MIT KARTEN  (components/featured-products.njk)
   --------------------------------------------------------------------------
   Die Produkte einer Gruppe stehen im Fenster als Karten im Raster —
   dieselben Karten wie auf der Startseite (snippets/product-card.njk),
   statt der frueheren schmalen Zeilenliste.

   Die Breite des Fensters richtet sich nach der Zahl der Karten
   (--dx-gm-spalten, hoechstens 4). Eine einzelne Karte in einem breiten
   Fenster waere vor allem leere Flaeche.
   ========================================================================== */

.dx-modal__panel--karten {
  --dx-gm-karte: 304px;
  --dx-gm-luecke: 16px;
  max-width: min(
    calc(var(--dx-gm-spalten, 1) * var(--dx-gm-karte) + (var(--dx-gm-spalten, 1) - 1) * var(--dx-gm-luecke) + 40px),
    calc(100vw - 2rem)
  );
  max-height: min(88vh, 920px);
}

/* Eine Karte allein: das Fenster nicht schmaler als die Kopfzeile braucht. */
.dx-modal__panel--karten[data-spalten="1"] { min-width: min(300px, calc(100vw - 2rem)); }

/* Nur der Inhalt scrollt, die Kopfzeile mit dem Schliessknopf bleibt stehen. */
.dx-modal__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 20px;
}

.dx-modal__grid {
  display: grid;
  grid-template-columns: repeat(var(--dx-gm-spalten, 1), minmax(0, 1fr));
  gap: var(--dx-gm-luecke);
  margin: 0;
  padding: 0;
  list-style: none;
}

.dx-modal__grid .dx-pcard__title { font-size: 1rem; }

@media (max-width: 767.98px) {
  .dx-modal__panel--karten { max-width: calc(100vw - 1.5rem); }
  .dx-modal__body { padding: 14px; }
  .dx-modal__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .dx-modal__panel--karten[data-spalten="1"] .dx-modal__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   VARIANTEN ZUM SCROLLEN  (snippets/product-form.njk, ab 7 Varianten)
   --------------------------------------------------------------------------
   Statt alle Varianten untereinander zu zeigen, steht die Liste in einem
   Kasten fester Hoehe. Sichtbar sind gut fuenf Zeilen; die naechste ist
   halb angeschnitten und laeuft weich aus — so ist ohne Hinweistext klar,
   dass es weitergeht. Der weiche Rand oben/unten verschwindet am Anfang
   bzw. Ende der Liste (Klassen setzt assets/script.js → "VARIANTEN ZUM
   SCROLLEN").
   ========================================================================== */

.dx-variants--scroll {
  --dx-vs-rand: 26px;
  max-height: 336px;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Luft fuer den Leuchtrand der gewaehlten Variante und die Bildlaufleiste:
     overflow schneidet alles ab, was ueber den Kasten hinausgeht. */
  margin: -4px -4px 0;
  padding: 4px 10px 4px 4px;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--cl-accent), 0.55) transparent;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--dx-vs-rand), #000 calc(100% - var(--dx-vs-rand)), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 var(--dx-vs-rand), #000 calc(100% - var(--dx-vs-rand)), transparent 100%);
}

.dx-variants--scroll.ist-oben {
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - var(--dx-vs-rand)), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - var(--dx-vs-rand)), transparent 100%);
}

.dx-variants--scroll.ist-unten {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--dx-vs-rand), #000 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 var(--dx-vs-rand), #000 100%);
}

.dx-variants--scroll.ist-oben.ist-unten {
  -webkit-mask-image: none;
          mask-image: none;
}

.dx-variants--scroll::-webkit-scrollbar { width: 6px; }
.dx-variants--scroll::-webkit-scrollbar-track { background: transparent; }
.dx-variants--scroll::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: rgba(var(--cl-accent), 0.5);
}
.dx-variants--scroll::-webkit-scrollbar-thumb:hover { background: rgba(var(--cl-accent), 0.75); }

/* Variantenzeilen duerfen nicht schrumpfen, sonst quetscht der Kasten
   sie zusammen, statt zu scrollen. */
.dx-variants--scroll > .dx-variant { flex: none; }

@media (max-width: 767.98px) {
  .dx-variants--scroll { max-height: 300px; }
}

/* ==========================================================================
   MERKMALSKARTEN IM DETAIL-STIL  (assets/script.js → "Merkmalskarten im
   Detail-Stil", aktiv mit data-dx-feature-stil="detail")
   --------------------------------------------------------------------------
   Nummerierte Karten: Symbolfeld, Untertitel in Schreibmaschinenschrift,
   Titel, Nummer rechts oben, optional eine Beschreibung, darunter vier
   Punkte und "+N more" zum Aufklappen. Die erste Karte ist doppelt breit
   und zeigt bis zu zwoelf Punkte in zwei Spalten.
   ========================================================================== */

/* ---------- Kopf: linksbuendig, kleine Zeile ueber der Ueberschrift ---------- */
.dx-feat--detail .dx-feat__head {
  align-items: flex-start;
  text-align: left;
  margin-bottom: clamp(1.4rem, 2.6vw, 2rem);
}

.dx-feat--detail .dx-feat__bar { display: none; }

.dx-feat__eyebrow {
  margin: 0 0 0.6rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in srgb, rgb(var(--cl-accent)) 55%, #fff);
}

.dx-feat--detail .dx-feat__title {
  font-size: clamp(1.75rem, 3.4vw, 2.5rem);
  line-height: 1.1;
}

.dx-feat--detail .dx-feat__pills { justify-content: flex-start; }

/* ---------- Raster ---------- */
.dx-fc-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  align-items: start;
}

.dx-fc--erste { grid-column: span 2; }

/* ---------- Karte ---------- */
.dx-fc {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.4rem, 2.4vw, 2rem);
  border-radius: 18px;
  background: rgb(var(--cl-card));
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 18px 40px -28px rgba(0, 0, 0, 0.9);
  transition: box-shadow 0.3s ease, transform 0.3s var(--dx-ease);
}

/* Lichtkante oben, erscheint beim Ueberfahren. */
.dx-fc::before {
  content: "";
  position: absolute;
  top: 0;
  left: 18%;
  right: 18%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(196, 181, 253, 0.65), transparent);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.dx-fc:hover {
  box-shadow:
    inset 0 0 0 1px rgba(var(--cl-accent), 0.22),
    0 22px 48px -28px rgba(0, 0, 0, 0.95);
}

.dx-fc:hover::before { opacity: 1; }

.dx-fc__top {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.dx-fc__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  color: #fff;
  background: linear-gradient(135deg, color-mix(in srgb, rgb(var(--cl-accent)) 55%, #fff 18%), rgb(var(--cl-accent)));
  box-shadow: 0 10px 24px -10px rgba(var(--cl-accent), 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

.dx-fc__icon svg { width: 19px; height: 19px; }

.dx-fc--erste .dx-fc__icon { width: 48px; height: 48px; border-radius: 13px; }
.dx-fc--erste .dx-fc__icon svg { width: 22px; height: 22px; }

.dx-fc__id {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  flex-direction: column;
  gap: 0.2rem;
}

.dx-fc__kicker,
.dx-fc__num {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--cl-t-primary), 0.5);
}

.dx-fc__num {
  align-self: flex-start;
  margin-top: 0.15rem;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
}

.dx-fc__title {
  margin: 0;
  font-size: 1.3125rem;
  font-weight: 700;
  line-height: 1.2;
  color: #fff;
}

.dx-fc--erste .dx-fc__title { font-size: 1.75rem; }

.dx-fc__desc {
  margin: 1.1rem 0 0;
  font-size: 0.9rem;
  line-height: 1.65;
  color: rgba(var(--cl-t-primary), 0.62);
}

/* ---------- Liste ---------- */
.dx-fc__list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.85rem 2rem;
  margin: 1.4rem 0 0;
  padding: 1.4rem 0 0;
  list-style: none;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.dx-fc--erste .dx-fc__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.dx-fc__list li {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  font-size: 0.875rem;
  line-height: 1.4;
  color: rgba(var(--cl-t-primary), 0.86);
}

.dx-fc__list li[hidden] { display: none; }

.dx-fc__check {
  flex: none;
  width: 13px;
  height: 13px;
  margin-top: 0.2em;
  color: rgba(var(--cl-t-primary), 0.42);
}

/* ---------- "+N more" ---------- */
.dx-fc__more {
  align-self: flex-start;
  margin-top: 1.35rem;
  padding: 0.6rem 1rem;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  background: rgba(255, 255, 255, 0.02);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  transition: background 0.2s ease, box-shadow 0.2s ease;
}

.dx-fc__more:hover,
.dx-fc__more:focus-visible {
  outline: none;
  background: rgba(var(--cl-accent), 0.14);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.55);
}

/* ---------- Breiten ---------- */
@media (max-width: 1023.98px) {
  .dx-fc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 639.98px) {
  .dx-fc-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .dx-fc--erste { grid-column: auto; }
  .dx-fc--erste .dx-fc__list { grid-template-columns: minmax(0, 1fr); }
  .dx-fc--erste .dx-fc__title { font-size: 1.4rem; }
}

@media (prefers-reduced-motion: reduce) {
  .dx-fc, .dx-fc::before { transition: none; }
}

/* Eine einzige Merkmalskarte: volle Breite, Punkte in drei Spalten. */
.dx-fc--allein { grid-column: 1 / -1; }
.dx-fc--allein .dx-fc__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 1023.98px) {
  .dx-fc--allein .dx-fc__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 639.98px) {
  .dx-fc--allein .dx-fc__list { grid-template-columns: minmax(0, 1fr); }
}

/* Groessere Karten im Gruppenfenster: Name und Preis passend zur Breite. */
.dx-modal__grid .dx-pcard__title { font-size: 1.1875rem; }
.dx-modal__grid .dx-pcard__amount { font-size: 1.45rem; }
.dx-modal__grid .dx-pcard__body { padding: 0 1.25rem 1.25rem; gap: 0.5rem; }

@media (max-width: 767.98px) {
  .dx-modal__grid .dx-pcard__title { font-size: 1rem; }
  .dx-modal__grid .dx-pcard__amount { font-size: 1.15rem; }
  .dx-modal__grid .dx-pcard__body { padding: 0 0.85rem 0.85rem; }
}

/* ==========================================================================
   FAQ UND ABSCHLUSS-BANNER  (components/hb-faq.njk, components/hb-cta.njk)
   --------------------------------------------------------------------------
   Uebernommen aus der neuen Startseite (Ordner "Dropout Website v2").
   Schrift: Unbounded fuer Ueberschriften, Inter fuer Text - beides nur in
   diesen zwei Abschnitten, der Rest der Seite behaelt seine Schrift.
   Geladen in layouts/master.njk.
   ========================================================================== */

:root {
  --hb-acc: rgb(var(--cl-accent));
  --hb-acc-hell: color-mix(in srgb, rgb(var(--cl-accent)) 55%, #fff);
  --hb-tinte: #0b0718;
  --hb-karte: rgb(var(--cl-card));
  --hb-display: "Unbounded", "Arial Black", sans-serif;
  --hb-text: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
}

.hb-faq,
.hb-cta {
  position: relative;
  margin-top: clamp(56px, 6vw, 104px);
  font-family: var(--hb-text);
}

/* Die Seite gibt die Breite schon vor (.dx-main). */
.hb-faq .hb-wrap,
.hb-cta .hb-wrap { width: 100%; }

.hb-title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.35em;
  margin: 0 0 clamp(1.25rem, 2vw, 1.9rem);
  font-family: var(--hb-display);
  font-size: clamp(1.65rem, 3.2vw, 3rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: #fff;
}

.hb-title span { color: var(--hb-acc-hell); }
.hb-title--zwei { flex-direction: column; align-items: flex-start; }

/* ---------- FAQ ---------- */
.hb-faq__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.62fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: start;
}

/* overflow: hidden haelt die grossen Buchstaben in ihrer Spalte - ohne das
   ragte das "Q" in die geoeffnete Frage und verdeckte deren Textanfang. */
.hb-faq__art {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 420px;
  overflow: hidden;
}

.hb-faq__letters {
  font-family: var(--hb-display);
  font-size: clamp(100px, 10.5vw, 190px);
  font-weight: 900;
  line-height: 0.9;
  letter-spacing: -0.03em;
  color: #fff;
  -webkit-mask-image: linear-gradient(to bottom, #000 25%, transparent 92%);
          mask-image: linear-gradient(to bottom, #000 25%, transparent 92%);
}

.hb-faq__logo {
  position: absolute;
  bottom: 14%;
  width: 78%;
  max-width: 340px;
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.6));
  animation: hb-logo-puls 2.6s ease-in-out infinite;
}

/* Logo unter "FAQ" pulsiert: wird sanft etwas groesser und leuchtet
   dabei in der Akzentfarbe auf. */
@keyframes hb-logo-puls {
  0%, 100% {
    transform: scale(1);
    filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.6)) drop-shadow(0 0 0 rgba(var(--cl-accent), 0));
  }
  50% {
    transform: scale(1.06);
    filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.6)) drop-shadow(0 0 26px rgba(var(--cl-accent), 0.75));
  }
}

@media (prefers-reduced-motion: reduce) {
  .hb-faq__logo { animation: none; }
}

.hb-faq__list { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 14px; }

.hb-q {
  overflow: hidden;
  border-radius: 16px;
  color: var(--hb-tinte);
  background: #fff;
  box-shadow: 0 14px 30px -24px rgba(0, 0, 0, 0.9);
  transition: background 0.3s ease, color 0.3s ease;
}

.hb-q[open] {
  color: #fff;
  background:
    radial-gradient(120% 140% at 15% 0%, rgba(var(--cl-accent), 0.6), rgba(var(--cl-accent), 0.2) 60%),
    var(--hb-karte);
  box-shadow: inset 0 0 0 1px rgba(var(--cl-accent), 0.45);
}

.hb-q__sum {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 1.05rem 3.5rem 1.05rem 1.2rem;
  cursor: pointer;
  list-style: none;
}

.hb-q__sum::-webkit-details-marker { display: none; }

.hb-q__tag {
  padding: 0.22rem 0.55rem;
  border-radius: 6px;
  font-size: 0.6875rem;
  font-weight: 800;
  color: #fff;
  background: color-mix(in srgb, rgb(var(--cl-accent)) 60%, #6b7280);
}

.hb-q[open] .hb-q__tag { color: var(--hb-tinte); background: #fff; }
.hb-q__frage { font-size: 0.9375rem; font-weight: 800; line-height: 1.35; }

.hb-q__plus {
  position: absolute;
  top: 50%;
  right: 1.25rem;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  opacity: 0.45;
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.hb-q__plus::before,
.hb-q__plus::after {
  content: "";
  position: absolute;
  top: 6px;
  left: 0;
  width: 14px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}

.hb-q__plus::after { transform: rotate(90deg); }
.hb-q[open] .hb-q__plus { transform: rotate(45deg); opacity: 0.9; }

.hb-q__antwort {
  padding: 0 1.2rem 1.15rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85);
}

.hb-q__antwort a { color: #fff; text-decoration: underline; }

/* ---------- Banner ---------- */
.hb-cta__box {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(300px, 26vw, 400px);
  overflow: hidden;
  border-radius: 24px;
  background:
    radial-gradient(70% 120% at 0% 100%, rgba(var(--cl-accent), 0.55), transparent 70%),
    var(--hb-karte);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.hb-cta__img {
  position: absolute;
  top: 0;
  right: 0;
  width: 68%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 25%;
  filter: grayscale(0.55) contrast(1.05);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 35%);
          mask-image: linear-gradient(to right, transparent 0%, #000 35%);
}

.hb-cta__shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(var(--cl-card), 0.92) 0%, rgba(var(--cl-card), 0.4) 45%, transparent 70%);
}

.hb-cta .hb-tapes {
  position: absolute;
  bottom: -8%;
  left: 30%;
  right: -10%;
  height: 170px;
  pointer-events: none;
}

.hb-cta .hb-tape {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  height: 56px;
  overflow: hidden;
  background: var(--hb-acc);
  box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.7);
}

.hb-cta .hb-tape--a { top: 34px; transform: rotate(-14deg); }
.hb-cta .hb-tape--b { top: 88px; transform: rotate(10deg); background: color-mix(in srgb, rgb(var(--cl-accent)) 82%, #000); }

.hb-cta .hb-tape__track { display: flex; width: max-content; animation: hb-band 46s linear infinite; }
.hb-cta .hb-tape--b .hb-tape__track { animation-direction: reverse; animation-duration: 52s; }
.hb-cta .hb-tape__run { display: flex; }

.hb-cta .hb-tape b {
  padding: 0 0.55em;
  font-family: var(--hb-display);
  font-size: 30px;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--hb-tinte);
}

.hb-cta .hb-tape--b b { color: transparent; -webkit-text-stroke: 1.5px var(--hb-tinte); }

@keyframes hb-band { to { transform: translateX(-50%); } }

.hb-cta__tags { position: absolute; inset: 0; pointer-events: none; z-index: 2; }

.hb-cta__tag {
  position: absolute;
  padding: 0.5rem 1rem;
  font-family: var(--hb-display);
  font-size: clamp(1rem, 1.6vw, 1.5rem);
  font-weight: 800;
  text-transform: uppercase;
  color: #fff;
  background: color-mix(in srgb, rgb(var(--cl-accent)) 70%, #000);
  box-shadow: 0 14px 30px -12px rgba(0, 0, 0, 0.7);
}

.hb-cta__tag--1 { top: 28%; left: 52%; transform: rotate(-6deg); }
.hb-cta__tag--2 { top: 50%; left: 64%; transform: rotate(-3deg); }

.hb-cta__copy { position: relative; z-index: 3; padding: clamp(1.75rem, 3vw, 3rem); }

.hb-cta__title {
  margin: 0 0 1.5rem;
  font-family: var(--hb-display);
  font-size: clamp(1.9rem, 3.8vw, 3.4rem);
  font-weight: 800;
  line-height: 1.02;
  text-transform: uppercase;
  color: #fff;
}

.hb-cta__title span { display: block; }

.hb-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.35rem 0.35rem 0.35rem 1.4rem;
  border-radius: 999px;
  font-family: var(--hb-display);
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  color: #fff;
  text-decoration: none;
  background: var(--hb-acc);
  box-shadow: 0 14px 30px -12px var(--hb-acc);
  transition: transform 0.25s ease, filter 0.25s ease;
}

.hb-chip:hover { transform: translateY(-1px); filter: brightness(1.08); }

.hb-chip__go {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: #fff;
  background: var(--hb-tinte);
}

.hb-chip__go svg { width: 16px; height: 16px; }

@media (max-width: 1023.98px) {
  .hb-faq__grid { grid-template-columns: minmax(0, 1fr); }
  .hb-faq__art { min-height: 0; padding: 1rem 0; }
  .hb-faq__letters { display: none; }
  .hb-faq__logo { position: static; width: 220px; }
}

@media (max-width: 639.98px) {
  .hb-cta__img { width: 100%; opacity: 0.45; }
  .hb-cta__tags { display: none; }
  .hb-cta .hb-tape { height: 42px; }
  .hb-cta .hb-tape b { font-size: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .hb-cta .hb-tape__track { animation: none; }
}