/* ==========================================================================
   SODIUM - Tebex webstore template for FiveM stores
   Los Santos after dark: warm near-black, sodium-vapour ember, HUD chamfers.

   Sections
   01 Tokens          07 Hero
   02 Reset & base    08 Catalogue & package cards
   03 Motion system   09 Package modal & options
   04 Ambience        10 Basket & checkout
   05 Typography      11 Sidebar modules
   06 Shell & nav     12 Footer, toast, responsive
   ========================================================================== */

/* 01 Tokens ============================================================== */

:root {
  /* Surfaces are near-neutral carbon with only a trace of warmth. Orange is
     the accent, not the atmosphere - it earns attention by being rare, and
     a cool indigo in the ambience keeps the page from reading monochrome. */
  --asphalt: #0b0b0d;
  --panel: #131316;
  --panel-hi: #1a1a1f;
  --panel-top: #232329;
  --line: #26262c;
  --line-hi: #35353d;

  --ember: #ff6a1a;
  --ember-hot: #ff8a3d;
  --ember-deep: #c94b0a;
  --sodium: #ffb35c;

  /* Cool counter-tone. Ambience and quiet accents only - never a control. */
  --indigo: #4c6fd6;
  --indigo-deep: #22306b;

  --bone: #eef0f4;
  --smoke: #969ba6;
  --smoke-dim: #656a75;
  --steel: #9fb0c4;
  --live: #6fdc8c;
  --alarm: #ff5c5c;

  --ember-a08: rgba(255, 106, 26, 0.08);
  --ember-a16: rgba(255, 106, 26, 0.16);
  --ember-a32: rgba(255, 106, 26, 0.32);
  --wash: rgba(255, 255, 255, 0.045);
  --wash-hi: rgba(255, 255, 255, 0.085);

  /* Chamfered corner - the shape language of the whole template. */
  --cut: 16px;
  --cut-sm: 9px;

  --rail: 34px;
  --head: 68px;
  --page: 1320px;
  --gutter: clamp(16px, 4vw, 40px);

  --dur-1: 150ms;
  --dur-2: 320ms;
  --dur-3: 620ms;
  --dur-4: 1100ms;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);

  --font-display: "Archivo", "Archivo Expanded", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --shadow-lift: 0 18px 40px -18px rgba(0, 0, 0, 0.9);
  --shadow-ember: 0 0 0 1px var(--ember-a32), 0 14px 44px -16px rgba(255, 106, 26, 0.45);
}

/* Warm variant, for stores that want the surfaces to carry the accent hue
   rather than staying neutral. */
[data-tone="sodium"] {
  --asphalt: #0c0908;
  --panel: #16110e;
  --panel-hi: #1f1813;
  --panel-top: #2a201a;
  --line: #2e241e;
  --line-hi: #43342a;
  --indigo: #a8632c;
  --indigo-deep: #5c2d0c;
  --bone: #f5eee9;
  --smoke: #a2938a;
  --smoke-dim: #6f635c;
}

/* Squared-off variant. */
[data-corners="square"] {
  --cut: 0px;
  --cut-sm: 0px;
}

/* 02 Reset & base ======================================================== */

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

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

body {
  margin: 0;
  min-height: 100vh;
  background: var(--asphalt);
  color: var(--bone);
  font-family: var(--font-display);
  font-variation-settings: "wdth" 100, "wght" 400;
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

table {
  border-collapse: collapse;
  width: 100%;
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 28px 0;
}

::selection {
  background: var(--ember);
  color: #1a0d04;
}

:focus-visible {
  outline: 2px solid var(--ember-hot);
  outline-offset: 3px;
}

/* Firefox keeps a UA outline that clashes with the chamfers. */
::-moz-focus-inner {
  border: 0;
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: var(--asphalt);
}

::-webkit-scrollbar-thumb {
  background: var(--line-hi);
  border: 2px solid var(--asphalt);
  border-radius: 8px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--ember-deep);
}

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

.skip {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 999;
  padding: 10px 16px;
  background: var(--ember);
  color: #1a0d04;
  font-family: var(--font-mono);
  font-size: 12px;
  transform: translateY(-160%);
  transition: transform var(--dur-2) var(--ease-out);
}

.skip:focus {
  transform: translateY(0);
}

/* 03 Motion system ======================================================= */

/* Elements opt in with .reveal; the observer in app.js adds .in. Children
   stagger off --i so a grid resolves as one orchestrated sweep rather than
   a dozen unrelated fades. */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 55ms);
}

.reveal.in {
  opacity: 1;
  transform: none;
}

.reveal--left {
  transform: translateX(-26px);
}

.reveal--scale {
  transform: scale(0.96);
}

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

@keyframes sweep-down {
  from {
    transform: translateY(-102%);
    opacity: 1;
  }
  to {
    transform: translateY(102%);
    opacity: 0;
  }
}

@keyframes iris {
  from {
    clip-path: inset(0 0 100% 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

@keyframes pulse-ring {
  0% {
    box-shadow: 0 0 0 0 rgba(111, 220, 140, 0.55);
  }
  70% {
    box-shadow: 0 0 0 7px rgba(111, 220, 140, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(111, 220, 140, 0);
  }
}

@keyframes drift-a {
  0%,
  100% {
    transform: translate3d(-6%, -4%, 0) scale(1);
  }
  50% {
    transform: translate3d(8%, 6%, 0) scale(1.18);
  }
}

@keyframes drift-b {
  0%,
  100% {
    transform: translate3d(6%, 5%, 0) scale(1.1);
  }
  50% {
    transform: translate3d(-7%, -6%, 0) scale(0.92);
  }
}

@keyframes horizon {
  from {
    background-position: 0 0;
  }
  to {
    background-position: 0 60px;
  }
}

@keyframes ticker {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

@keyframes pop {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.34);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes glint {
  from {
    transform: translateX(-130%) skewX(-18deg);
  }
  to {
    transform: translateX(330%) skewX(-18deg);
  }
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateX(120%);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes bar-idle {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(400%);
  }
}

/* 04 Ambience ============================================================ */

/* Deep space, built from five fixed pointer-transparent layers:
     1. nebula clouds drifting on long periods
     2/3/4. three starfields at different depths and speeds (parallax)
     5. film grain
   Stars are tiled radial-gradients rather than hundreds of DOM nodes or a
   giant box-shadow list, so the whole thing costs three composited layers. */

.amb {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse 120% 80% at 50% -20%, rgba(76, 111, 214, 0.12), transparent 70%),
    radial-gradient(ellipse 100% 60% at 80% 110%, rgba(34, 48, 107, 0.18), transparent 70%);
}

/* 1. Nebulae ------------------------------------------------------------- */

.amb__neb {
  position: absolute;
  border-radius: 50%;
  filter: blur(110px);
  will-change: transform;
}

.amb__neb--1 {
  width: 58vmax;
  height: 58vmax;
  top: -20vmax;
  left: -12vmax;
  background: radial-gradient(circle, rgba(94, 74, 190, 0.22), transparent 68%);
  animation: orbit-a 46s ease-in-out infinite;
}

.amb__neb--2 {
  width: 64vmax;
  height: 64vmax;
  top: 26vmax;
  right: -24vmax;
  background: radial-gradient(circle, rgba(38, 84, 168, 0.2), transparent 68%);
  animation: orbit-b 62s ease-in-out infinite;
}

/* One warm cloud only, so the accent is present in the sky without the page
   turning orange. */
.amb__neb--3 {
  width: 44vmax;
  height: 44vmax;
  bottom: -18vmax;
  left: 30vmax;
  background: radial-gradient(circle, rgba(255, 106, 26, 0.1), transparent 70%);
  animation: orbit-c 74s ease-in-out infinite;
}

@keyframes orbit-a {
  0%,
  100% {
    transform: translate3d(0, 0, 0) scale(1);
  }
  33% {
    transform: translate3d(12vmax, 7vmax, 0) scale(1.15);
  }
  66% {
    transform: translate3d(3vmax, 16vmax, 0) scale(0.92);
  }
}

@keyframes orbit-b {
  0%,
  100% {
    transform: translate3d(0, 0, 0) scale(1.05);
  }
  50% {
    transform: translate3d(-16vmax, -11vmax, 0) scale(0.88);
  }
}

@keyframes orbit-c {
  0%,
  100% {
    transform: translate3d(0, 0, 0) scale(0.95);
  }
  50% {
    transform: translate3d(-12vmax, -9vmax, 0) scale(1.2);
  }
}

/* 2-4. Starfields -------------------------------------------------------- */

.amb__stars {
  position: absolute;
  inset: -100% 0 0;
  height: 300%;
  background-repeat: repeat;
  will-change: transform;
}

/* Far: dense, dim, barely moving. */
.amb__stars--far {
  background-image:
    radial-gradient(1px 1px at 12% 8%, rgba(255, 255, 255, 0.55), transparent),
    radial-gradient(1px 1px at 47% 21%, rgba(255, 255, 255, 0.4), transparent),
    radial-gradient(1px 1px at 78% 12%, rgba(255, 255, 255, 0.5), transparent),
    radial-gradient(1px 1px at 27% 44%, rgba(255, 255, 255, 0.35), transparent),
    radial-gradient(1px 1px at 63% 38%, rgba(255, 255, 255, 0.45), transparent),
    radial-gradient(1px 1px at 89% 52%, rgba(255, 255, 255, 0.3), transparent),
    radial-gradient(1px 1px at 8% 67%, rgba(255, 255, 255, 0.45), transparent),
    radial-gradient(1px 1px at 38% 74%, rgba(255, 255, 255, 0.35), transparent),
    radial-gradient(1px 1px at 71% 83%, rgba(255, 255, 255, 0.5), transparent),
    radial-gradient(1px 1px at 55% 94%, rgba(255, 255, 255, 0.3), transparent);
  background-size: 340px 340px;
  animation: star-drift 190s linear infinite;
}

/* Mid: fewer, brighter, and they twinkle. */
.amb__stars--mid {
  background-image:
    radial-gradient(1.4px 1.4px at 22% 15%, rgba(255, 255, 255, 0.85), transparent),
    radial-gradient(1.4px 1.4px at 68% 29%, rgba(200, 220, 255, 0.75), transparent),
    radial-gradient(1.4px 1.4px at 41% 58%, rgba(255, 255, 255, 0.8), transparent),
    radial-gradient(1.4px 1.4px at 85% 71%, rgba(255, 228, 200, 0.7), transparent),
    radial-gradient(1.4px 1.4px at 15% 88%, rgba(255, 255, 255, 0.75), transparent);
  background-size: 520px 520px;
  animation: star-drift 120s linear infinite, twinkle 5.5s ease-in-out infinite;
}

/* Near: a handful of bright ones, noticeably faster. */
.amb__stars--near {
  background-image:
    radial-gradient(2px 2px at 33% 24%, rgba(255, 255, 255, 0.95), transparent),
    radial-gradient(2px 2px at 76% 61%, rgba(255, 210, 170, 0.85), transparent),
    radial-gradient(2px 2px at 9% 79%, rgba(210, 225, 255, 0.9), transparent);
  background-size: 760px 760px;
  animation: star-drift 70s linear infinite;
}

@keyframes star-drift {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, 33.333%, 0);
  }
}

@keyframes twinkle {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

/* 5. Shooting star ------------------------------------------------------- */

/* Crosses roughly once a minute. Rare enough to feel like an event rather
   than decoration you stop seeing. */
.amb__shoot {
  position: absolute;
  top: 12%;
  left: -10%;
  width: 120px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.85));
  opacity: 0;
  transform: rotate(14deg);
  animation: shoot 19s ease-in infinite;
}

.amb__shoot--2 {
  top: 46%;
  width: 90px;
  animation-duration: 27s;
  animation-delay: -11s;
}

@keyframes shoot {
  0%,
  88% {
    opacity: 0;
    transform: translate3d(0, 0, 0) rotate(14deg);
  }
  90% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate3d(125vw, 32vh, 0) rotate(14deg);
  }
}

/* 6. Grain --------------------------------------------------------------- */

.amb__grain {
  position: absolute;
  inset: -50%;
  opacity: 0.045;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>");
}

[data-grain="off"] .amb__grain {
  display: none;
}

/* Navigation progress bar - mirrors the FiveM loading bar. */
.prog {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 200;
  background: transparent;
  overflow: hidden;
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease);
}

.prog.on {
  opacity: 1;
}

.prog::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 34%;
  background: linear-gradient(90deg, transparent, var(--ember), var(--sodium), transparent);
  animation: bar-idle 900ms var(--ease) infinite;
}

/* 05 Typography ========================================================== */

h1,
h2,
h3,
h4 {
  margin: 0 0 0.4em;
  font-family: var(--font-display);
  line-height: 1.02;
  letter-spacing: -0.03em;
}

/* The width axis does the work: display type is pushed wide and heavy so it
   reads as signage, body copy stays at normal width. */
/* Big on purpose. A long headline wraps rather than shrinking to fit one
   line - at 46 characters, one line means small type, and the size is what
   carries the page. */
h1 {
  font-variation-settings: "wdth" 116, "wght" 800;
  font-size: clamp(2.4rem, 6.1vw, 5.2rem);
  line-height: 0.95;
  text-transform: uppercase;
}

h2 {
  font-variation-settings: "wdth" 112, "wght" 700;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  text-transform: uppercase;
}

h3 {
  font-variation-settings: "wdth" 106, "wght" 650;
  font-size: 1.12rem;
}

p {
  margin: 0 0 1em;
}

.lede {
  color: var(--smoke);
  font-size: clamp(1rem, 1.5vw, 1.14rem);
  max-width: 58ch;
}

/* Mono is reserved for machine-truthful content: IDs, prices, counts,
   status. It never dresses up prose. */
/* Section labels stay neutral; a single small ember mark carries the accent
   so the colour is not repeated on every heading down the page. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--smoke);
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.eyebrow::before {
  content: "";
  width: 5px;
  height: 5px;
  flex: none;
  background: var(--ember);
}

.eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-hi), transparent);
}

.mono {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--smoke-dim);
}

.money {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 1.06rem;
  color: var(--bone);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.money s {
  color: var(--smoke-dim);
  font-weight: 400;
  font-size: 0.82em;
  margin-right: 6px;
}

/* Section head ---------------------------------------------------------- */

.sechead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 26px;
  flex-wrap: wrap;
}

.sechead p {
  margin: 6px 0 0;
  color: var(--smoke);
  max-width: 56ch;
}

/* Rich text from the panel (descriptions, CMS pages) --------------------- */

.prose {
  color: var(--smoke);
  max-width: 72ch;
}

.prose h1,
.prose h2,
.prose h3 {
  color: var(--bone);
  margin-top: 1.4em;
}

.prose h2 {
  font-size: 1.5rem;
}

.prose a {
  color: var(--ember-hot);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color var(--dur-1) var(--ease);
}

.prose a:hover {
  color: var(--sodium);
}

/*
 * Sauf s'il s'agit d'un bouton.
 *
 * La regle ci-dessus est plus specifique que `.btn` (0,1,1 contre 0,1,0) : sans
 * ce correctif, un bouton pose dans une description ecrit en ambre sur un fond
 * ambre. `.prose a.btn` pese 0,2,1 et repasse devant.
 */
.prose a.btn {
  color: var(--btn-fg);
  text-decoration: none;
}

.prose a.btn:hover {
  color: var(--btn-fg);
}

/*
 * CE QUI ARRIVE DANS UNE DESCRIPTION N'A PAS DE STYLE A LUI.
 *
 * Tebex nettoie le HTML enregistre et retire les attributs `style` : une image
 * collee dans une description s'affiche donc a sa taille naturelle, et une
 * capture de 1920 pixels pousse la colonne hors de l'ecran. La contrainte est
 * ici plutot que dans le HTML, ou personne ne peut la retirer.
 */
.prose img {
  margin: 1.4em 0;
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--cut-sm);
}

/* Au cas ou une iframe survivrait un jour au filtre : qu'elle soit au moins
   dimensionnee correctement plutot que haute de 150 pixels par defaut. */
.prose iframe {
  display: block;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  margin: 1.4em 0;
  border: 0;
  border-radius: var(--cut-sm);
}

.prose > :last-child {
  margin-bottom: 0;
}

.prose ul,
.prose ol {
  padding-left: 1.2em;
}

.prose li {
  margin-bottom: 0.4em;
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--panel-hi);
  padding: 2px 6px;
  color: var(--sodium);
}

.prose blockquote {
  margin: 1.4em 0;
  padding-left: 18px;
  border-left: 2px solid var(--ember);
  color: var(--bone);
}

/* CMS page content ------------------------------------------------------ *
   Panel-authored HTML. Plain elements are styled so a text page reads well,
   but nothing is width-constrained: these pages are often fully designed,
   with their own <style> block, and a max-width would fight that. Wrap prose
   in .cms__text when you do want a comfortable reading measure. */

.cms {
  color: var(--smoke);
}

.cms h1,
.cms h2,
.cms h3,
.cms h4 {
  color: var(--bone);
  margin-top: 1.4em;
}

.cms h2 {
  font-size: clamp(1.3rem, 2.4vw, 1.8rem);
}

.cms h3 {
  font-size: 1.15rem;
  text-transform: none;
}

.cms p,
.cms li {
  line-height: 1.7;
}

.cms > p,
.cms > ul,
.cms > ol {
  max-width: 72ch;
}

.cms__text {
  max-width: 72ch;
}

.cms a:not(.btn):not(.sup__card) {
  color: var(--ember-hot);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--dur-1) var(--ease);
}

.cms a:not(.btn):not(.sup__card):hover {
  color: var(--sodium);
}

.cms ul,
.cms ol {
  padding-left: 1.2em;
}

.cms li {
  margin-bottom: 0.4em;
}

.cms img {
  margin: 1.4em 0;
}

.cms code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--panel-hi);
  padding: 2px 6px;
  color: var(--sodium);
}

.cms > :last-child {
  margin-bottom: 0;
}

/* Two-column split for designed pages: content beside a form, stacking on
   narrow screens. Used by the contact page. */
.cms__split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}

@media (min-width: 940px) {
  .cms__split {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: 44px;
  }
}

/* Contact page ---------------------------------------------------------- *
   Rendered from cms/page.html, not from panel content: the CMS editor
   strips form, input, select, textarea, button, style and script tags, so a
   working form can only come from the template. */

.contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 26px;
  align-items: start;
}

@media (min-width: 940px) {
  .contact {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: 44px;
  }
}

.contact__aside {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* The intro comes from the page in the panel, so it can contain anything -
   including the stripped remains of markup someone pasted before.
   :empty alone is not enough: it does not match an element holding a stray
   space or newline, which is exactly what a sanitised paste leaves. So every
   box-drawing class is neutralised here as well, and a leftover renders as
   nothing rather than as a blank card. */
.contact__intro *:empty:not(br):not(img):not(hr):not(input) {
  display: none;
}

.contact__intro .sup__card,
.contact__intro .frame,
.contact__intro .frame__in,
.contact__intro .panel,
.contact__intro .module,
.contact__intro .module__in,
.contact__intro .pkg,
.contact__intro .pkg__frame,
.contact__intro .pkg__body,
.contact__intro .chan,
.contact__intro .chan__frame,
.contact__intro .chan__body,
.contact__intro .stat,
.contact__intro .why__item,
.contact__intro .svc,
.contact__intro .feat__viz {
  display: block;
  min-height: 0;
  aspect-ratio: auto;
  background: none;
  border: 0;
  padding: 0;
  clip-path: none;
  box-shadow: none;
}

.contact__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 16px;
}

@media (min-width: 620px) {
  .contact__row {
    grid-template-columns: 1fr 1fr;
  }
}

/* File pickers are unstyleable across browsers; the button half gets the
   theme treatment and the rest stays native. */
.contact__file {
  width: 100%;
  padding: 11px 13px;
  background: var(--asphalt);
  border: 1px dashed var(--line-hi);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--smoke-dim);
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease);
}

.contact__file:hover {
  border-color: var(--ember);
}

.contact__file::file-selector-button {
  margin-right: 12px;
  padding: 6px 12px;
  background: var(--wash);
  border: 0;
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 5px) 0, 100% 5px, 100% 100%, 5px 100%, 0 calc(100% - 5px));
}

.contact__sent {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 20px;
  margin-bottom: 26px;
  background: rgba(111, 220, 140, 0.1);
  border-left: 2px solid var(--live);
  color: var(--live);
  animation: rise var(--dur-3) var(--ease-out) both;
}

.contact__sent strong {
  font-variation-settings: "wdth" 104, "wght" 650;
}

.contact__sent span {
  color: var(--smoke);
  font-size: 14px;
}

/* Buttons --------------------------------------------------------------- */

.btn {
  --btn-bg: var(--wash);
  --btn-fg: var(--bone);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 22px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  border: 0;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  clip-path: polygon(0 0, calc(100% - var(--cut-sm)) 0, 100% var(--cut-sm), 100% 100%, var(--cut-sm) 100%, 0 calc(100% - var(--cut-sm)));
  transition:
    transform var(--dur-1) var(--ease),
    background var(--dur-2) var(--ease),
    color var(--dur-2) var(--ease);
}

/* Ember wipes in from the left rather than the whole button changing at
   once - reads as a switch being thrown. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(100deg, var(--ember), var(--ember-hot));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-2) var(--ease-out);
}

.btn:hover::before,
.btn:focus-visible::before {
  transform: scaleX(1);
}

.btn:hover,
.btn:focus-visible {
  color: #1a0d04;
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0) scale(0.985);
}

.btn--primary {
  --btn-bg: linear-gradient(100deg, var(--ember), var(--ember-hot));
  --btn-fg: #1a0d04;
}

.btn--primary::before {
  background: linear-gradient(100deg, var(--sodium), var(--ember-hot));
}

.btn--primary:hover {
  color: #1a0d04;
  box-shadow: 0 12px 30px -12px rgba(255, 106, 26, 0.7);
}

.btn--block {
  width: 100%;
}

.btn--sm {
  padding: 9px 15px;
  font-size: 11px;
}

.btn--lg {
  padding: 16px 32px;
  font-size: 13px;
}

.btn[disabled],
.btn--muted {
  pointer-events: none;
  opacity: 0.42;
}

/* Already in the basket. Reads green at rest, and the hover wipe turns red
   so it is obvious the next click takes the item back out. */
.btn.is-in {
  background: rgba(111, 220, 140, 0.14);
  color: var(--live);
}

.btn.is-in::before {
  background: linear-gradient(100deg, #c62828, #ff5f5f);
}

.btn.is-in:hover,
.btn.is-in:focus-visible {
  color: #2a0606;
}

/* Held while a basket call or Tebex.js checkout is in flight. */
.btn.is-busy {
  color: transparent;
  pointer-events: none;
}

.btn.is-busy::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 15px;
  height: 15px;
  margin: -7.5px 0 0 -7.5px;
  border: 2px solid rgba(26, 13, 4, 0.35);
  border-top-color: #1a0d04;
  border-radius: 50%;
  animation: spin 640ms linear infinite;
  background: none;
  transform: none;
}

/* Sheen passes once on hover for primary calls to action. */
.btn--primary::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 34px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
  transform: translateX(-130%) skewX(-18deg);
  pointer-events: none;
}

.btn--primary:hover::after {
  animation: glint 720ms var(--ease-out);
}

/* Text link with a rule that draws in from the left. */
.tlink {
  position: relative;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--smoke);
  transition: color var(--dur-1) var(--ease);
}

.tlink::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -4px;
  height: 1px;
  width: 100%;
  background: var(--ember);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-2) var(--ease-out);
}

.tlink:hover {
  color: var(--bone);
}

.tlink:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Panels ---------------------------------------------------------------- */

/* Chamfered border built from two nested clipped boxes: clip-path removes a
   real border, so the frame *is* the 1px line. */
.frame {
  background: var(--line);
  padding: 1px;
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  transition: background var(--dur-2) var(--ease);
}

.frame > .frame__in {
  background: var(--panel);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  height: 100%;
}

.panel {
  padding: 24px;
}

/* Chips & badges -------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  background: var(--wash);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--smoke);
  clip-path: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 6px 100%, 0 calc(100% - 6px));
}

.chip--ember {
  background: var(--ember-a16);
  color: var(--sodium);
}

.chip--live {
  color: var(--live);
}

.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--live);
  flex: none;
  animation: pulse-ring 2.4s var(--ease-out) infinite;
}

.dot--off {
  background: var(--alarm);
  animation: none;
}

/* 06 Shell & nav ========================================================= */

.shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  flex: 1;
}

/* Status rail - a thin always-on strip that keeps the store feeling live
   even when nothing else is moving. */
.rail {
  position: relative;
  height: var(--rail);
  background: rgba(10, 7, 6, 0.86);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--smoke-dim);
  overflow: hidden;
}

.rail__in {
  display: flex;
  align-items: center;
  gap: 20px;
  height: 100%;
}

.rail__status {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--smoke);
  white-space: nowrap;
  flex: none;
}

.rail__marquee {
  flex: 1;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 76%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 76%, transparent);
}

.rail__track {
  display: inline-flex;
  gap: 44px;
  white-space: nowrap;
  animation: ticker 34s linear infinite;
  will-change: transform;
}

.rail__marquee:hover .rail__track {
  animation-play-state: paused;
}

.rail__track span::before {
  content: "//";
  color: var(--ember-deep);
  margin-right: 10px;
}

.rail__end {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: none;
}

/* No dropdown arrow in the rail: the shared select styling paints one over
   the right-hand padding.

   Chrome under-measures a select's intrinsic width for this mono face - it
   sized "GBP" at 21px total and clipped the P. min-width is the fix; extra
   padding only makes it worse, since padding shrinks the content box the
   text is clipped to. Set in em so it follows the font size. */
.rail select {
  background: transparent;
  background-image: none;
  border: 0;
  color: var(--smoke);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: normal;
  cursor: pointer;
  padding: 2px 2px 2px 0;
  min-width: 4.5em;
  max-width: 150px;
  transition: color var(--dur-1) var(--ease);
}

.rail select:hover {
  color: var(--bone);
}

.rail select option {
  background: var(--panel);
  color: var(--bone);
}

/* Flag / symbol picker -------------------------------------------------- *
   Replaces the native select in the rail. The panel is fixed because the
   rail clips its overflow, with coordinates written by app.js. */

.picker {
  position: relative;
  flex: none;
}

.picker__btn {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 8px;
  background: transparent;
  border: 0;
  color: var(--smoke);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 5px) 0, 100% 5px, 100% 100%, 5px 100%, 0 calc(100% - 5px));
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}

.picker__btn:hover,
.picker.is-open .picker__btn {
  background: var(--wash);
  color: var(--bone);
}

.picker__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  font-size: 13px;
  line-height: 1;
}

/* Flags carry a hairline and a light backing plate. Without it the pale ones
   (Japan) float on the panel and the dark ones (Germany's black band) read as
   a missing image against a near-black background. */
.picker__mark svg {
  display: block;
  background: rgba(255, 255, 255, 0.14);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.28);
}

.picker__code {
  letter-spacing: 0.08em;
}

.picker__caret {
  font-size: 8px;
  opacity: 0.55;
  transition: transform var(--dur-2) var(--ease-out);
}

.picker.is-open .picker__caret {
  transform: rotate(180deg);
}

.picker__list {
  position: fixed;
  top: var(--y, 100%);
  left: var(--x, 0);
  z-index: 190;
  min-width: 186px;
  max-height: 320px;
  overflow-y: auto;
  padding: 6px;
  background: var(--panel-hi);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lift);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-out),
    visibility var(--dur-2);
}

.picker.is-open .picker__list {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.picker__opt {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  color: var(--smoke);
  font-family: var(--font-display);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}

/* Each row slides in behind the one above it. */
.picker.is-open .picker__opt {
  animation: rise var(--dur-2) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 26ms);
}

.picker__opt:hover {
  background: var(--ember-a08);
  color: var(--bone);
}

.picker__opt[aria-selected="true"] {
  color: var(--sodium);
}

.picker__opt[aria-selected="true"]::after {
  content: "";
  width: 5px;
  height: 5px;
  margin-left: auto;
  background: var(--ember);
  flex: none;
}

.picker__opt .picker__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.picker__opt .picker__code {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--smoke-dim);
}

.picker__opt[aria-selected="true"] .picker__code {
  display: none;
}

/* Google Translate ------------------------------------------------------ *
   The widget is only there to apply the cookie the picker sets. Its banner
   pushes the whole document down by its own height and its dropdown is a
   second, unstyled language control - both are suppressed so the rail
   picker stays the only one. */

#google_translate_element,
.goog-te-banner-frame,
.goog-te-gadget,
.skiptranslate {
  display: none !important;
}

body {
  /* Google sets an inline top offset for its banner even when hidden. */
  top: 0 !important;
  position: static !important;
}

/* It also wraps translated runs in a font tag with its own styling. */
font[style] {
  background: none !important;
  box-shadow: none !important;
  color: inherit !important;
}

/* Header ---------------------------------------------------------------- */

.head {
  position: sticky;
  top: 0;
  z-index: 90;
  height: var(--head);
  background: rgba(12, 9, 8, 0.72);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 1px solid var(--line);
  transition:
    height var(--dur-2) var(--ease),
    background var(--dur-2) var(--ease),
    border-color var(--dur-2) var(--ease);
}

.head.is-stuck {
  height: 58px;
  background: rgba(12, 9, 8, 0.94);
  border-bottom-color: var(--line-hi);
}

/* Ember filament under the header that stretches as the page scrolls. */
.head::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 1px;
  width: 100%;
  background: linear-gradient(90deg, transparent, var(--ember), transparent);
  transform: scaleX(var(--scroll, 0));
  transform-origin: left;
}

.head__in {
  display: flex;
  align-items: center;
  gap: 18px;
  height: 100%;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
  font-variation-settings: "wdth" 116, "wght" 800;
  font-size: 1.02rem;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  transition: color var(--dur-1) var(--ease);
}

.brand img {
  max-height: 38px;
  width: auto;
  transition: transform var(--dur-2) var(--ease-out);
}

.brand:hover img {
  transform: scale(1.05) rotate(-1.5deg);
}

.brand:hover {
  color: var(--sodium);
}

/* Stores add their own links, so the nav has to survive more items than
   fit. Scrolling is the safe default - it can never collide with the
   account block, with or without JavaScript. When app.js measures that
   everything fits it adds .nav--fits, which lets dropdowns hang outside
   the box normally. */
.nav {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  mask-image: linear-gradient(90deg, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 94%, transparent);
}

.nav::-webkit-scrollbar {
  display: none;
}

.nav--fits {
  overflow: visible;
  mask-image: none;
  -webkit-mask-image: none;
}

.nav__item {
  position: relative;
  flex: none;
}

.nav__link {
  position: relative;
  display: block;
  padding: 9px 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--smoke);
  white-space: nowrap;
  transition: color var(--dur-1) var(--ease);
}

.nav__link::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 2px;
  height: 1px;
  background: var(--ember);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-2) var(--ease-out);
}

.nav__link:hover,
.nav__link.is-active {
  color: var(--bone);
}

.nav__link:hover::after,
.nav__link.is-active::after {
  transform: scaleX(1);
  transform-origin: left;
}

.nav__link.is-active {
  color: var(--sodium);
}

.nav__caret {
  display: inline-block;
  font-size: 9px;
  vertical-align: middle;
  opacity: 0.6;
  transition: transform var(--dur-2) var(--ease-out);
}

.nav__item.has-sub:hover .nav__caret,
.nav__item.has-sub:focus-within .nav__caret {
  transform: translateY(2px);
}

/* Dropdown. Absolute by default, which needs no JavaScript at all. Only
   when the nav is actually scrolling does it switch to fixed, because an
   absolute child would then be clipped by the overflow. */
.nav__sub {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 95;
  min-width: 190px;
  padding: 6px;
  background: var(--panel-hi);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lift);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-out),
    visibility var(--dur-2);
}

/* Scrolling nav: escape the overflow box, using coordinates app.js writes
   from the parent's bounding rect. */
.nav:not(.nav--fits) .nav__sub {
  position: fixed;
  top: var(--y, 100%);
  left: var(--x, 0);
}

.nav__item:hover .nav__sub,
.nav__item:focus-within .nav__sub {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.nav__sub a {
  display: block;
  padding: 8px 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--smoke);
  transition:
    background var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease),
    padding-left var(--dur-1) var(--ease);
}

.nav__sub a:hover {
  background: var(--ember-a08);
  color: var(--sodium);
  padding-left: 17px;
}

.head__end {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

/* Basket button --------------------------------------------------------- */

.basket {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  background: var(--wash);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--bone);
  clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px));
  transition: background var(--dur-2) var(--ease);
}

.basket:hover {
  background: var(--ember-a16);
}

.basket__count {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  background: var(--ember);
  color: #1a0d04;
  font-size: 11px;
  font-weight: 600;
  border-radius: 10px;
}

.basket__count.is-pop {
  animation: pop 420ms var(--ease-out);
}

.user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--smoke);
  max-width: 220px;
  flex: none;
}

.user strong {
  color: var(--bone);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Burger + drawer ------------------------------------------------------- */

.burger {
  display: none;
  width: 42px;
  height: 42px;
  background: var(--wash);
  border: 0;
  cursor: pointer;
  padding: 0;
  place-items: center;
}

.burger span {
  display: block;
  width: 18px;
  height: 1.5px;
  background: var(--bone);
  transition: transform var(--dur-2) var(--ease-out), opacity var(--dur-1) var(--ease);
}

.burger span + span {
  margin-top: 4px;
}

.burger.is-open span:nth-child(1) {
  transform: translateY(5.5px) rotate(45deg);
}

.burger.is-open span:nth-child(2) {
  opacity: 0;
}

.burger.is-open span:nth-child(3) {
  transform: translateY(-5.5px) rotate(-45deg);
}

.drawer {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(8, 6, 5, 0.97);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 92px var(--gutter) 40px;
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur-2) var(--ease),
    visibility var(--dur-2);
}

.drawer.is-open {
  opacity: 1;
  visibility: visible;
}

.drawer a {
  display: block;
  padding: 15px 0;
  border-bottom: 1px solid var(--line);
  font-variation-settings: "wdth" 112, "wght" 650;
  font-size: 1.35rem;
  text-transform: uppercase;
  opacity: 0;
  transform: translateX(-22px);
}

.drawer.is-open a {
  animation: rise var(--dur-3) var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 45ms + 90ms);
}

.drawer a:hover {
  color: var(--sodium);
}

/* 07 Hero ================================================================ */

.hero {
  position: relative;
  padding: clamp(56px, 11vw, 128px) 0 clamp(44px, 7vw, 84px);
  overflow: hidden;
}

/* Perspective grid receding to a horizon - the road out of the city. It
   fills the lower half of the hero, so the space under the headline reads
   as atmosphere rather than as a gap. */
.hero__grid {
  position: absolute;
  inset: auto 0 0;
  height: 58%;
  background-image:
    linear-gradient(rgba(159, 176, 196, 0.42) 1px, transparent 1px),
    linear-gradient(90deg, rgba(159, 176, 196, 0.42) 1px, transparent 1px);
  background-size: 64px 64px;
  transform: perspective(300px) rotateX(70deg) scale(2.6);
  transform-origin: bottom;
  opacity: 0.42;
  mask-image: linear-gradient(transparent, #000 62%, transparent);
  -webkit-mask-image: linear-gradient(transparent, #000 62%, transparent);
  animation: horizon 4.5s linear infinite;
  pointer-events: none;
}

/* Warm haze sitting on the horizon line. It has to finish fading before the
   hero's bottom edge, or overflow:hidden cuts it into a visible seam. */
.hero::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 6%;
  width: 128%;
  height: 34%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(76, 111, 214, 0.16), rgba(255, 106, 26, 0.09) 40%, transparent 68%);
  filter: blur(34px);
  pointer-events: none;
}

.hero__art {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0.22;
  mask-image: radial-gradient(ellipse at 70% 40%, #000, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse at 70% 40%, #000, transparent 72%);
  pointer-events: none;
}

.hero__in {
  position: relative;
  z-index: 1;
  max-width: 900px;
}

.hero h1 {
  margin-bottom: 20px;
  max-width: 20ch;
  /* Whole-sentence entrance. Used as-is while a translation is active,
     where the per-word split has to be skipped. */
  animation: rise 780ms var(--ease-out) both;
  animation-delay: 120ms;
}

/* Split into words: the spans carry the stagger instead. */
.hero h1.is-split {
  animation: none;
}

/* Each word rises on its own beat, so the headline assembles instead of
   fading in as a block.

   The hidden state comes from the keyframes plus `both`, never from a bare
   opacity:0 - if animations are blocked for any reason the headline must
   still be readable rather than invisible. */
.hero h1 .w {
  display: inline-block;
  animation: rise 780ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 70ms + 120ms);
}

.hero .lede {
  animation: rise 780ms var(--ease-out) both;
  animation-delay: 420ms;
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
  animation: rise 780ms var(--ease-out) both;
  animation-delay: 540ms;
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  margin-top: 36px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  animation: rise 780ms var(--ease-out) both;
  animation-delay: 660ms;
}

.hero__meta div {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--smoke-dim);
}

.hero__meta strong {
  display: block;
  color: var(--bone);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* Copy-IP control */
.copyip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 18px;
  background: var(--wash);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--bone);
  border: 0;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px));
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}

.copyip:hover {
  background: var(--ember-a16);
  color: var(--sodium);
}

.copyip.is-done {
  background: rgba(111, 220, 140, 0.16);
  color: var(--live);
}

/* 08 Catalogue & package cards =========================================== */

.section {
  padding: clamp(40px, 6vw, 76px) 0;
}

.section--tight {
  padding: clamp(26px, 3.5vw, 44px) 0;
}

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 34px;
  align-items: start;
}

@media (min-width: 1080px) {
  .layout--aside {
    grid-template-columns: minmax(0, 1fr) 312px;
  }
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
  gap: 18px;
}

/* Package card ---------------------------------------------------------- */

/* Three nested boxes: .pkg carries transform and drop-shadow (which would be
   clipped if it shared an element with clip-path), .pkg__frame paints the
   chamfered 1px edge, .pkg__body holds the content. */
.pkg {
  position: relative;
  transition:
    transform var(--dur-2) var(--ease-out),
    filter var(--dur-2) var(--ease-out);
  will-change: transform;
}

.pkg:hover {
  transform: translateY(-6px);
  filter: drop-shadow(0 22px 34px rgba(0, 0, 0, 0.62)) drop-shadow(0 0 22px rgba(255, 106, 26, 0.18));
}

.pkg__frame {
  background: var(--line);
  padding: 1px;
  height: 100%;
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  transition: background var(--dur-2) var(--ease);
}

.pkg:hover .pkg__frame {
  background: linear-gradient(160deg, var(--ember), var(--line) 55%);
}

.pkg__body {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: linear-gradient(170deg, var(--panel-hi), var(--panel) 62%);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  overflow: hidden;
}

/* The signature: an ember line wipes the card once as it enters the
   viewport, the way FiveM resources report in as they load. */
.pkg__body::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  background: linear-gradient(
    to bottom,
    transparent 42%,
    rgba(255, 138, 61, 0.42) 50%,
    transparent 58%
  );
  transform: translateY(-102%);
  opacity: 0;
}

.reveal.in .pkg__body::after {
  animation: sweep-down 820ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 55ms);
}

.pkg__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--asphalt);
  overflow: hidden;
  flex: none;
}

.pkg__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-4) var(--ease-out), filter var(--dur-3) var(--ease);
}

.reveal.in .pkg__media img {
  animation: iris 700ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 55ms + 90ms);
}

.pkg:hover .pkg__media img {
  transform: scale(1.07);
  filter: saturate(1.15) brightness(1.05);
}

.pkg__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--panel) 2%, transparent 58%);
  pointer-events: none;
}

.pkg__flags {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

/* Package artwork can be any brightness, so flags sitting on top of it need
   their own opaque backing rather than the translucent default. */
.pkg__flags .chip {
  background: rgba(12, 9, 8, 0.84);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  color: var(--bone);
}

.pkg__flags .chip--ember {
  background: var(--ember);
  color: #1a0d04;
}

.pkg__flags .chip--live {
  color: var(--live);
}

.pkg__main {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 16px 18px 18px;
  gap: 10px;
}

/* Image-less packages get a little more breathing room up top, plus a
   diagonal wash so the card still has somewhere for the eye to land. */
.pkg__main--bare {
  padding-top: 22px;
  background: radial-gradient(120% 80% at 100% 0%, var(--ember-a08), transparent 58%);
}

.pkg__flags--inline {
  position: static;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 6px;
}

.pkg__name {
  font-variation-settings: "wdth" 104, "wght" 650;
  font-size: 1.06rem;
  line-height: 1.22;
  letter-spacing: -0.015em;
  margin: 0;
  transition: color var(--dur-1) var(--ease);
}

.pkg:hover .pkg__name {
  color: var(--sodium);
}

/* Package descriptions arrive as panel-authored HTML, so the clamp has to
   survive whatever markup the store owner pasted in. */
.pkg__desc {
  color: var(--smoke);
  font-size: 13.5px;
  line-height: 1.55;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.pkg__desc * {
  display: inline;
  margin: 0;
  padding: 0;
  font-size: inherit;
  font-weight: inherit;
  color: inherit;
  line-height: inherit;
}

.pkg__desc br,
.pkg__desc img {
  display: none;
}

.pkg__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* Real data, not ornament: the store's own package identifier. */
.pkg__id {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--smoke-dim);
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}

.pkg:hover .pkg__id {
  opacity: 1;
  transform: none;
}

.pkg__actions {
  display: flex;
  gap: 8px;
  padding: 0 18px 18px;
}

.pkg--inbasket .pkg__frame {
  background: linear-gradient(160deg, var(--live), var(--line) 55%);
}

/* List display type */
.list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.list .pkg__body {
  flex-direction: row;
  align-items: center;
  gap: 18px;
  padding: 14px 18px;
}

.list .pkg__media {
  width: 108px;
  aspect-ratio: 1;
  flex: none;
}

.list .pkg__media::after {
  display: none;
}

.list .pkg__main {
  padding: 0;
  flex: 1;
}

.list .pkg__foot {
  border: 0;
  padding: 0;
  margin: 0;
}

.list .pkg__actions {
  padding: 0;
  flex: none;
}

@media (max-width: 640px) {
  .list .pkg__body {
    flex-direction: column;
    align-items: stretch;
  }

  .list .pkg__media {
    width: 100%;
    aspect-ratio: 16 / 9;
  }
}

/* Category tile --------------------------------------------------------- *
   The homepage entry points. Categories have no artwork of their own, so
   these carry their weight through type and a hover wash instead of
   pretending to be package cards with a missing image. */

.chan {
  position: relative;
  display: block;
  transition: transform var(--dur-2) var(--ease-out), filter var(--dur-2) var(--ease-out);
}

.chan:hover {
  transform: translateY(-5px);
  filter: drop-shadow(0 20px 32px rgba(0, 0, 0, 0.6));
}

.chan__frame {
  background: var(--line);
  padding: 1px;
  height: 100%;
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  transition: background var(--dur-2) var(--ease);
}

.chan:hover .chan__frame {
  background: linear-gradient(150deg, var(--ember), var(--line) 60%);
}

.chan__body {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  min-height: 148px;
  padding: 22px;
  background: linear-gradient(155deg, var(--panel-hi), var(--panel) 70%);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  overflow: hidden;
}

/* Ember wash rises from the lower-left corner on hover. */
.chan__body::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 0% 100%, var(--ember-a16), transparent 62%);
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease);
}

.chan:hover .chan__body::before {
  opacity: 1;
}

.chan__name {
  position: relative;
  margin: 0;
  font-variation-settings: "wdth" 112, "wght" 700;
  font-size: clamp(1.2rem, 2vw, 1.5rem);
  line-height: 1.05;
  letter-spacing: -0.025em;
  text-transform: uppercase;
  transition: color var(--dur-2) var(--ease);
}

.chan:hover .chan__name {
  color: var(--sodium);
}

.chan__subs {
  position: relative;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.7;
  letter-spacing: 0.04em;
  color: var(--smoke);
}

.chan__go {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  padding-top: 16px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--smoke-dim);
}

.chan__go i {
  font-style: normal;
  color: var(--ember);
  transition: transform var(--dur-2) var(--ease-out);
}

.chan:hover .chan__go {
  color: var(--bone);
}

.chan:hover .chan__go i {
  transform: translateX(6px);
}

/* Trust strip ----------------------------------------------------------- *
   Sits directly under the hero and answers the first questions a server
   owner has: which frameworks, what happens after purchase, who supports
   it. Every entry comes from the template config. */

.trust {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  border-block: 1px solid var(--line);
}

.trust__item {
  position: relative;
  padding: 22px 26px 22px 0;
}

.trust__item + .trust__item {
  padding-left: 26px;
  border-left: 1px solid var(--line);
}

.trust__item h3 {
  margin: 0 0 5px;
  font-variation-settings: "wdth" 104, "wght" 650;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
  text-transform: none;
}

.trust__item p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--smoke);
}

.trust__item::before {
  content: "";
  position: absolute;
  top: 22px;
  left: 0;
  width: 2px;
  height: 0;
  background: var(--ember);
  transition: height var(--dur-3) var(--ease-out);
}

.trust__item + .trust__item::before {
  left: -1px;
}

.trust__item:hover::before {
  height: 20px;
}

@media (max-width: 700px) {
  .trust__item + .trust__item {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--line);
  }
}

/* Stats ----------------------------------------------------------------- *
   Numbers count up once when scrolled into view. */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px;
}

.stat {
  padding: 26px 24px;
  background: linear-gradient(155deg, var(--panel-hi), var(--panel) 72%);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
}

.stat__n {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(2rem, 4.6vw, 3rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--bone);
  font-variant-numeric: tabular-nums;
}

.stat__n span {
  color: var(--ember);
}

.stat__l {
  display: block;
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--smoke-dim);
}

/* Feature blocks -------------------------------------------------------- *
   Alternating image / text rows for the longer sales points. */

.feat {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 30px;
  align-items: center;
}

@media (min-width: 900px) {
  .feat {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 54px;
  }

  .feat--flip .feat__art {
    order: -1;
  }
}

/* Generated panel, used when no screenshot was uploaded. A core label with
   three chips orbiting it - reads as a diagram rather than a placeholder,
   and needs no asset. */
.feat__viz {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  display: grid;
  place-items: center;
  background:
    radial-gradient(90% 70% at 50% 50%, var(--panel-hi), var(--panel) 72%);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  box-shadow: inset 0 0 0 1px var(--line);
}

.feat__viz::before {
  content: "";
  position: absolute;
  inset: -20%;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: radial-gradient(60% 60% at 50% 50%, #000, transparent 78%);
  -webkit-mask-image: radial-gradient(60% 60% at 50% 50%, #000, transparent 78%);
  animation: grid-slide 16s linear infinite;
}

@keyframes grid-slide {
  to {
    background-position: 34px 34px, -34px 0;
  }
}

/* Soft accent bloom behind the core. */
.feat__viz::after {
  content: "";
  position: absolute;
  width: 46%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--ember-a16), transparent 68%);
  filter: blur(26px);
  animation: viz-pulse 6s ease-in-out infinite;
}

@keyframes viz-pulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.8;
  }
  50% {
    transform: scale(1.18);
    opacity: 1;
  }
}

.feat__viz-core {
  position: relative;
  z-index: 2;
  padding: 14px 24px;
  background: linear-gradient(100deg, var(--ember), var(--ember-hot));
  color: #1a0d04;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px));
}

.feat__viz-chip {
  position: absolute;
  z-index: 2;
  padding: 7px 14px;
  background: var(--panel-top);
  box-shadow: inset 0 0 0 1px var(--line-hi);
  color: var(--smoke);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  clip-path: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 6px 100%, 0 calc(100% - 6px));
  animation: viz-float 7s ease-in-out infinite;
}

.feat__viz-chip--a {
  top: 17%;
  left: 12%;
}

.feat__viz-chip--b {
  top: 44%;
  right: 9%;
  animation-delay: -2.4s;
}

.feat__viz-chip--c {
  bottom: 16%;
  left: 24%;
  animation-delay: -4.8s;
}

@keyframes viz-float {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-9px);
  }
}

/* Second block leans cool so the two panels are not identical. */
.feat__viz--alt .feat__viz-core {
  background: linear-gradient(100deg, var(--indigo), #6f8ee6);
  color: #06101f;
}

.feat__viz--alt::after {
  background: radial-gradient(circle, rgba(76, 111, 214, 0.22), transparent 68%);
}

[data-motion="calm"] .feat__viz::before,
[data-motion="calm"] .feat__viz::after,
[data-motion="calm"] .feat__viz-chip {
  animation: none;
}

.feat + .feat {
  margin-top: clamp(40px, 6vw, 78px);
}

.feat__art {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--panel);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
}

.feat__art img,
.feat__art video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-4) var(--ease-out);
}

.feat:hover .feat__art img {
  transform: scale(1.04);
}

/* Slow sheen so a still screenshot does not sit completely dead. */
.feat__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 40%, rgba(255, 255, 255, 0.07) 50%, transparent 60%);
  transform: translateX(-100%);
  animation: feat-sheen 7s var(--ease) infinite;
}

@keyframes feat-sheen {
  0%,
  62% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

.feat__body h3 {
  font-variation-settings: "wdth" 110, "wght" 700;
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  text-transform: uppercase;
  margin-bottom: 14px;
}

.feat__body p {
  color: var(--smoke);
  max-width: 52ch;
}

/* Latest release -------------------------------------------------------- *
   The newest version, given its own billboard. Version and date are mono
   because they are machine facts; the changelog is a real list. */

.rel {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  background: var(--line);
  padding: 1px;
  clip-path: polygon(0 0, calc(100% - 26px) 0, 100% 26px, 100% 100%, 0 100%);
}

@media (min-width: 900px) {
  .rel {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  }
}

.rel__art {
  position: relative;
  min-height: 260px;
  overflow: hidden;
  background: var(--panel);
}

.rel__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-4) var(--ease-out);
}

.rel:hover .rel__art img {
  transform: scale(1.03);
}

/* Blends the screenshot into the panel beside it instead of butting up
   against a hard vertical edge. */
.rel__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, transparent 20%, rgba(19, 19, 22, 0.7) 78%, var(--panel));
  pointer-events: none;
}

@media (max-width: 899px) {
  .rel__art::after {
    background: linear-gradient(to top, var(--panel), transparent 60%);
  }
}

.rel__body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: clamp(24px, 3.4vw, 40px);
  background: var(--panel);
}

.rel__tags {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.rel__name {
  margin: 0;
  font-variation-settings: "wdth" 110, "wght" 750;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-transform: uppercase;
}

.rel__sum {
  margin: 0;
  color: var(--smoke);
  max-width: 52ch;
}

.rel__log {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.rel__log li {
  position: relative;
  padding-left: 20px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--smoke);
}

.rel__log li::before {
  content: "+";
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-mono);
  color: var(--ember);
}

.rel__cta {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 6px;
}

/* Why us ---------------------------------------------------------------- *
   Heavier than the trust strip and less illustrated than the feature rows:
   a grid of reasons, each with its own hover edge. */

.why {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 14px;
}

.why__item {
  position: relative;
  padding: 26px 24px;
  background: linear-gradient(160deg, var(--panel-hi), var(--panel) 72%);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  overflow: hidden;
  transition: transform var(--dur-2) var(--ease-out);
}

.why__item:hover {
  transform: translateY(-4px);
}

.why__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, var(--ember), transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out);
}

.why__item:hover::before {
  transform: scaleX(1);
}

.why__mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: 16px;
  background: var(--ember-a16);
  color: var(--ember);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  clip-path: polygon(0 0, calc(100% - 7px) 0, 100% 7px, 100% 100%, 7px 100%, 0 calc(100% - 7px));
}

.why__item h3 {
  margin: 0 0 8px;
  font-variation-settings: "wdth" 106, "wght" 650;
  font-size: 1.06rem;
  letter-spacing: -0.015em;
}

.why__item p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--smoke);
}

/* Support --------------------------------------------------------------- */

.sup {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
}

.sup__card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 24px;
  background: var(--panel);
  border: 1px solid var(--line);
  transition:
    border-color var(--dur-2) var(--ease),
    background var(--dur-2) var(--ease),
    transform var(--dur-2) var(--ease-out);
}

.sup__card:hover {
  border-color: var(--line-hi);
  background: var(--panel-hi);
  transform: translateY(-3px);
}

.sup__card h3 {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-variation-settings: "wdth" 106, "wght" 650;
  font-size: 1.02rem;
}

.sup__card h3 i {
  font-style: normal;
  color: var(--ember);
  transition: transform var(--dur-2) var(--ease-out);
}

.sup__card:hover h3 i {
  transform: translateX(5px);
}

.sup__card p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--smoke);
}

/* Services band --------------------------------------------------------- *
   The commission pitch. One place on the page where ember fills a whole
   surface, which is what makes it read as the primary call to action. */

.svc {
  position: relative;
  overflow: hidden;
  padding: clamp(34px, 5vw, 60px);
  background: linear-gradient(120deg, var(--panel-hi), var(--panel) 60%);
  clip-path: polygon(0 0, calc(100% - 26px) 0, 100% 26px, 100% 100%, 0 100%);
}

.svc::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 130% at 100% 0%, var(--ember-a16), transparent 62%);
  pointer-events: none;
}

.svc::after {
  content: "";
  position: absolute;
  top: -50%;
  left: -20%;
  width: 40%;
  height: 200%;
  background: linear-gradient(90deg, transparent, rgba(255, 138, 61, 0.06), transparent);
  transform: rotate(16deg);
  animation: beam 14s linear infinite;
  pointer-events: none;
}

.svc__in {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
}

.svc__body {
  max-width: 60ch;
}

.svc__body h2 {
  margin-bottom: 12px;
}

.svc__body p {
  margin: 0;
  color: var(--smoke);
}

/* FAQ ------------------------------------------------------------------- *
   Native <details>, so it opens without JavaScript and stays keyboard
   accessible. */

.faq {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.faq details {
  background: var(--panel);
  border: 1px solid var(--line);
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}

.faq details[open],
.faq details:hover {
  border-color: var(--line-hi);
  background: var(--panel-hi);
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 17px 20px;
  cursor: pointer;
  list-style: none;
  font-variation-settings: "wdth" 104, "wght" 600;
  font-size: 1rem;
  transition: color var(--dur-1) var(--ease);
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary:hover {
  color: var(--sodium);
}

.faq summary::after {
  content: "+";
  flex: none;
  font-family: var(--font-mono);
  font-size: 18px;
  line-height: 1;
  color: var(--ember);
  transition: transform var(--dur-2) var(--ease-out);
}

.faq details[open] summary::after {
  transform: rotate(45deg);
}

.faq__a {
  padding: 0 20px 19px;
  color: var(--smoke);
  font-size: 14px;
  line-height: 1.65;
  animation: faq-open var(--dur-2) var(--ease-out);
}

.faq__a > :last-child {
  margin-bottom: 0;
}

@keyframes faq-open {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

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

.cats {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 8px;
  scrollbar-width: thin;
}

.cats a {
  flex: none;
  padding: 10px 18px;
  background: var(--wash);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--smoke);
  white-space: nowrap;
  clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px));
  transition:
    background var(--dur-2) var(--ease),
    color var(--dur-2) var(--ease),
    transform var(--dur-1) var(--ease);
}

.cats a:hover {
  background: var(--ember-a16);
  color: var(--sodium);
  transform: translateY(-2px);
}

.cats a.is-active {
  background: linear-gradient(100deg, var(--ember), var(--ember-hot));
  color: #1a0d04;
}

/* Subcategories of the open category, indented by a leading rule. */
.cats__sub {
  background: transparent !important;
  border: 1px solid var(--line);
  color: var(--smoke-dim) !important;
}

.cats__sub::before {
  content: "\2514";
  margin-right: 8px;
  opacity: 0.5;
}

.cats__sub:hover {
  border-color: var(--line-hi);
  color: var(--sodium) !important;
}

/* Empty state ----------------------------------------------------------- */

.empty {
  padding: 64px 24px;
  text-align: center;
  color: var(--smoke);
}

.empty__mark {
  width: 54px;
  height: 54px;
  margin: 0 auto 18px;
  border: 1px solid var(--line-hi);
  display: grid;
  place-items: center;
  color: var(--ember);
  font-family: var(--font-mono);
  font-size: 20px;
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
  animation: pulse-ring 3s var(--ease-out) infinite;
}

/* 09 Package modal & options ============================================= */

.modal {
  position: fixed;
  inset: 0;
  z-index: 160;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(6, 4, 3, 0.82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-2) var(--ease), visibility var(--dur-2);
}

.modal.is-open {
  opacity: 1;
  visibility: visible;
}

.modal__box {
  width: min(760px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  background: var(--line);
  padding: 1px;
  clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 0 100%);
  transform: translateY(26px) scale(0.97);
  opacity: 0;
  transition: transform var(--dur-3) var(--ease-out), opacity var(--dur-2) var(--ease);
}

.modal.is-open .modal__box {
  transform: none;
  opacity: 1;
}

.modal__in {
  background: var(--panel);
  clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 0 100%);
}

.modal__close {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 4;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  background: rgba(12, 9, 8, 0.8);
  border: 0;
  color: var(--bone);
  cursor: pointer;
  font-size: 18px;
  transition: background var(--dur-1) var(--ease), transform var(--dur-2) var(--ease-out);
}

.modal__close:hover {
  background: var(--ember);
  color: #1a0d04;
  transform: rotate(90deg);
}

.modal__spin {
  display: grid;
  place-items: center;
  padding: 70px;
}

.modal__spin i {
  width: 26px;
  height: 26px;
  border: 2px solid var(--line-hi);
  border-top-color: var(--ember);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}

/* Package detail (also used standalone) */
.pdet__media {
  position: relative;
  aspect-ratio: 21 / 9;
  overflow: hidden;
  background: var(--asphalt);
}

.pdet__media img,
.pdet__media iframe {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
}

.pdet__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--panel), transparent 62%);
  pointer-events: none;
}

.pdet__body {
  padding: 26px;
}

.pdet__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 22px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.pdet__price {
  font-family: var(--font-mono);
  font-size: 1.7rem;
  font-weight: 600;
  color: var(--sodium);
  letter-spacing: -0.02em;
  line-height: 1;
}

.pdet__price s {
  display: block;
  font-size: 0.92rem;
  color: var(--smoke-dim);
  font-weight: 400;
  margin-bottom: 4px;
}

.pdet__buy {
  display: flex;
  gap: 10px;
  align-items: stretch;
  flex-wrap: wrap;
  margin-top: 24px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

/* Media carousel dots */
.gal {
  display: flex;
  gap: 6px;
  padding: 12px 26px 0;
}

.gal button {
  width: 26px;
  height: 3px;
  background: var(--line-hi);
  border: 0;
  cursor: pointer;
  padding: 0;
  transition: background var(--dur-2) var(--ease);
}

.gal button.is-active {
  background: var(--ember);
}

/* Forms ----------------------------------------------------------------- */

.field {
  margin-bottom: 18px;
}

.field label,
.label {
  display: block;
  margin-bottom: 7px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--smoke);
}

.input,
input[type="text"],
input[type="number"],
input[type="email"],
select,
textarea {
  width: 100%;
  padding: 12px 14px;
  background: var(--asphalt);
  border: 1px solid var(--line);
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: 13px;
  transition:
    border-color var(--dur-2) var(--ease),
    box-shadow var(--dur-2) var(--ease),
    background var(--dur-2) var(--ease);
}

.input:focus,
input:focus,
select:focus,
textarea:focus {
  outline: 0;
  border-color: var(--ember);
  background: var(--panel);
  box-shadow: 0 0 0 3px var(--ember-a16);
}

.input::placeholder,
input::placeholder,
textarea::placeholder {
  color: var(--smoke-dim);
}

select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--smoke) 50%),
    linear-gradient(135deg, var(--smoke) 50%, transparent 50%);
  background-position: calc(100% - 18px) 52%, calc(100% - 13px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
}

.inline-form {
  display: flex;
  gap: 8px;
}

.inline-form .input {
  flex: 1;
}

.opt-price {
  color: var(--sodium);
  font-family: var(--font-mono);
}

/* 10 Basket & checkout =================================================== */

.cart {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.cart__row {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}

.cart__row:hover {
  border-color: var(--line-hi);
  background: var(--panel-hi);
}

/*
 * MEME RAPPORT QUE LES VISUELS, sinon `cover` recadre.
 *
 * Les images de paquet sont en 16/10. Dans un carre, `object-fit: cover` les
 * agrandit jusqu'a remplir la boite et ampute les cotes -- soit un tiers de
 * l'image, en commencant par le titre, qui est a gauche. La grille des paquets
 * emploie deja `16 / 10` : c'est ici que le rapport etait faux.
 */
.cart__thumb {
  width: 104px;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--asphalt);
  border-radius: var(--cut-sm);
}

.cart__name {
  font-variation-settings: "wdth" 104, "wght" 600;
  font-size: 1rem;
  margin: 0 0 3px;
}

.cart__del {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  background: var(--wash);
  border: 0;
  color: var(--smoke);
  cursor: pointer;
  font-size: 15px;
  transition:
    background var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease),
    transform var(--dur-2) var(--ease-out);
}

.cart__del:hover {
  background: rgba(255, 77, 77, 0.16);
  color: var(--alarm);
  transform: rotate(90deg);
}

.cart__row.is-going {
  opacity: 0;
  transform: translateX(28px);
  transition: opacity var(--dur-2) var(--ease-in), transform var(--dur-2) var(--ease-in);
}

@media (max-width: 620px) {
  .cart__row {
    grid-template-columns: 76px minmax(0, 1fr) auto;
    gap: 12px;
  }

  .cart__thumb {
    width: 76px;
  }

  .cart__row .money {
    grid-column: 2 / 3;
  }
}

.summary {
  position: sticky;
  top: calc(var(--head) + 18px);
}

.summary__line {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--smoke);
}

.summary__total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  margin-top: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.summary__total b {
  font-family: var(--font-mono);
  font-size: 1.7rem;
  font-weight: 600;
  color: var(--sodium);
  letter-spacing: -0.02em;
}

.coupon {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 13px;
  background: var(--ember-a08);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--sodium);
  margin-bottom: 8px;
}

.coupon a {
  color: var(--smoke);
  transition: color var(--dur-1) var(--ease);
}

.coupon a:hover {
  color: var(--alarm);
}

/* Login ----------------------------------------------------------------- */

.auth {
  max-width: 460px;
  margin: clamp(40px, 9vw, 96px) auto;
}

.auth__mark {
  width: 58px;
  height: 58px;
  margin-bottom: 22px;
  display: grid;
  place-items: center;
  background: var(--ember-a16);
  color: var(--ember);
  font-size: 22px;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));
}

/* 11 Sidebar modules ===================================================== */

.aside {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Same modules, laid out across the page instead of down a sidebar. Used on
   the homepage, where a column would tower over the content beside it. */
.modrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: 14px;
  align-items: start;
}

.module {
  background: var(--line);
  padding: 1px;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 0 100%);
  transition: background var(--dur-3) var(--ease);
}

.module:hover {
  background: linear-gradient(160deg, var(--line-hi), var(--line) 60%);
}

.module__in {
  background: var(--panel);
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 0 100%);
}

.module__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--smoke);
}

.module__body {
  padding: 16px;
}

.module__body > :last-child {
  margin-bottom: 0;
}

/* Progress bar for goals */
.bar {
  position: relative;
  height: 8px;
  background: var(--asphalt);
  overflow: hidden;
  margin: 12px 0 10px;
}

.bar__fill {
  position: relative;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--ember-deep), var(--ember), var(--sodium));
  transition: width var(--dur-4) var(--ease-out);
}

.bar__fill::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    -45deg,
    rgba(255, 255, 255, 0.18) 25%,
    transparent 25%,
    transparent 50%,
    rgba(255, 255, 255, 0.18) 50%,
    rgba(255, 255, 255, 0.18) 75%,
    transparent 75%
  );
  background-size: 14px 14px;
  animation: horizon 900ms linear infinite;
}

.feed {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.feed li {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  transition: padding-left var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}

.feed li:last-child {
  border-bottom: 0;
}

.feed li:hover {
  padding-left: 6px;
  color: var(--sodium);
}

.feed img {
  width: 32px;
  height: 32px;
  object-fit: cover;
  flex: none;
  background: var(--asphalt);
}

.feed .mono {
  margin-left: auto;
}

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

/* 12 Footer, toast, responsive =========================================== */

.foot {
  margin-top: 40px;
  padding: 46px 0 30px;
  border-top: 1px solid var(--line);
  background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.35));
}

.foot__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 32px;
  margin-bottom: 34px;
}

.foot h4 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--smoke-dim);
  margin-bottom: 14px;
}

.foot ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.foot ul a {
  color: var(--smoke);
  font-size: 14px;
  transition: color var(--dur-1) var(--ease), padding-left var(--dur-2) var(--ease);
}

.foot ul a:hover {
  color: var(--sodium);
  padding-left: 5px;
}

.foot__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--smoke-dim);
}

.foot__bar a:hover {
  color: var(--sodium);
}

/* Toast ----------------------------------------------------------------- */

.toasts {
  position: fixed;
  top: calc(var(--rail) + 14px);
  right: 16px;
  z-index: 180;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(340px, calc(100vw - 32px));
  pointer-events: none;
}

.toast {
  position: relative;
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  background: var(--panel-hi);
  border-left: 2px solid var(--ember);
  box-shadow: var(--shadow-lift);
  font-size: 13.5px;
  pointer-events: auto;
  animation: toast-in var(--dur-3) var(--ease-out) both;
  overflow: hidden;
}

.toast--success {
  border-left-color: var(--live);
}

.toast--error {
  border-left-color: var(--alarm);
}

.toast.is-going {
  opacity: 0;
  transform: translateX(120%);
  transition: opacity var(--dur-2) var(--ease-in), transform var(--dur-2) var(--ease-in);
}

/* Depletion line makes the auto-dismiss legible instead of abrupt. */
.toast::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: currentColor;
  opacity: 0.28;
  transform-origin: left;
  animation: toast-drain 5s linear forwards;
}

@keyframes toast-drain {
  to {
    transform: scaleX(0);
  }
}

/* Responsive ------------------------------------------------------------ */

@media (max-width: 980px) {
  .nav,
  .user {
    display: none;
  }

  .burger {
    display: grid;
  }

  .rail__marquee {
    display: none;
  }
}

@media (max-width: 560px) {
  :root {
    --cut: 12px;
  }

  .rail__end {
    margin-left: auto;
  }

  .hero__cta .btn,
  .hero__cta .copyip {
    flex: 1;
    justify-content: center;
  }

  .modal {
    padding: 0;
    align-items: flex-end;
  }

  .modal__box {
    max-height: 92vh;
    clip-path: polygon(0 22px, 22px 0, 100% 0, 100% 100%, 0 100%);
  }

  .modal__in {
    clip-path: polygon(0 22px, 22px 0, 100% 0, 100% 100%, 0 100%);
  }
}

/* Motion off ------------------------------------------------------------ */

/* Honoured both from the OS and from the template's own config switch. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  .amb__shoot,
  .hero__grid,
  .amb__grain {
    display: none;
  }
}

[data-motion="off"] .amb__shoot,
[data-motion="off"] .hero__grid,
[data-motion="off"] .rail__marquee {
  display: none;
}

[data-motion="off"] .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

[data-motion="off"] *,
[data-motion="off"] *::before,
[data-motion="off"] *::after {
  animation: none !important;
}

/* Calm keeps hover feedback and reveals but drops the ambient loops. The
   stars and nebulae stay in place rather than disappearing, so the page
   keeps its depth. */
[data-motion="calm"] .amb__neb,
[data-motion="calm"] .amb__stars,
[data-motion="calm"] .hero__grid,
[data-motion="calm"] .rail__track,
[data-motion="calm"] .feat__art::after,
[data-motion="calm"] .svc::after {
  animation: none;
}

[data-motion="calm"] .amb__shoot {
  display: none;
}

[data-motion="calm"] .pkg__body::after {
  display: none;
}

@media print {
  .rail,
  .head,
  .amb,
  .toasts,
  .foot,
  .prog {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }
}
