/* NXXS Flow - the shop shelves, standards board and disintegrating mark.
   Loaded after nxxs-bright.css, which owns the colour, type and spacing
   tokens this sheet reads. Every value introduced here is declared once in
   the :root block below and referenced with var().

   No CSS grid. No pseudo-element carries anything visible. The mark uses real
   masked shards in one positioned backdrop, and the standards board positions
   its rotating faces around one origin. Shelf cards remain in a scrolling flex
   row and gain depth only through transform. */

:root {
  /* Shop shelves */
  --w-card: 264px;
  --gap-card: var(--s-5);
  --pad-shelf-y: var(--s-7);
  --pad-shelf-x: calc(50% - (var(--w-card) / 2));
  --perspective-shelf: 1150px;
  --ry-card-1: 20deg;
  --ry-card-2: 30deg;
  --ry-card-3: 36deg;
  --z-card-1: -84px;
  --z-card-2: -172px;
  --z-card-3: -244px;
  --sc-card-1: 0.95;
  --sc-card-2: 0.88;
  --sc-card-3: 0.83;
  --op-card-1: 0.97;
  --op-card-2: 0.82;
  --op-card-3: 0.58;
  --blur-card: 1.5px;
  --lift-card: -10px;
  --t-card: 300ms;
  --gap-shelves: var(--s-10);

  /* The standards board */
  --h-creed: 128px;
  --r-creed: 88px;
  --perspective-creed: 720px;
  --step-creed: 72deg;
  --t-creed: 760ms;
  --ease-creed: cubic-bezier(0.32, 0.86, 0.18, 1);
  --op-creed-off: 0;
  --w-creed-mark: 8px;
}

/* ---- The standards board --------------------------------------------- */

.creed {
  position: relative;
  height: var(--h-creed);
  overflow: hidden;
  perspective: var(--perspective-creed);
  border-left: var(--bw-3) solid var(--c-cold);
}

.creed-plate {
  position: absolute;
  inset: var(--s-0);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-2);
  padding-left: var(--s-5);
  transform-origin: 50% 50% calc(var(--r-creed) * -1);
  backface-visibility: hidden;
  transition: transform var(--t-creed) var(--ease-creed),
              opacity var(--t-creed) var(--ease-creed);
}

.creed-claim {
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
  color: var(--c-text);
}

.creed-detail {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--c-text-2);
}

.creed-mark {
  flex: 0 0 auto;
  width: var(--w-creed-mark);
  height: var(--w-creed-mark);
  border-radius: var(--radius-pill);
  background-color: var(--c-wait);
}

.creed-mark-stated { background-color: var(--c-ok); }

/* Only the front face is readable. The face above it is carried so its
   departure can be animated; the three on the back of the drum jump without
   a transition, which is invisible because they are turned away. */
.creed-plate[data-slot="0"] {
  transform: rotateX(var(--s-0));
  opacity: 1;
}
.creed-plate[data-slot="1"] {
  transform: rotateX(calc(var(--step-creed) * -1));
  opacity: var(--op-creed-off);
  transition: none;
}
.creed-plate[data-slot="2"] {
  transform: rotateX(calc(var(--step-creed) * -2));
  opacity: var(--op-creed-off);
  transition: none;
}
.creed-plate[data-slot="3"] {
  transform: rotateX(calc(var(--step-creed) * 2));
  opacity: var(--op-creed-off);
  transition: none;
}
.creed-plate[data-slot="4"] {
  transform: rotateX(var(--step-creed));
  opacity: var(--op-creed-off);
}

/* ---- Shop shelves ----------------------------------------------------- */

.shelf-set {
  display: flex;
  flex-direction: column;
  gap: var(--gap-shelves);
  min-width: 0;
}

.shelf {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 0;
}

.shelf-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  border-bottom: var(--bw-1) solid var(--c-line);
  padding-bottom: var(--s-3);
}

.shelf-name {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.shelf-title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
  color: var(--c-text);
}

.shelf-count {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  /* --c-text-3 lands at 4.39:1 on this ground, which is under AA. */
  color: var(--c-text-2);
}

.shelf-tools {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.shelf-track {
  display: flex;
  align-items: stretch;
  gap: var(--gap-card);
  min-width: 0;
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  perspective: var(--perspective-shelf);
  perspective-origin: 50% 50%;
  padding-block: var(--pad-shelf-y);
  padding-inline: var(--pad-shelf-x);
  scrollbar-width: none;
}

.shelf-track::-webkit-scrollbar { display: none; }

.shelf-card {
  flex: 0 0 var(--w-card);
  display: flex;
  scroll-snap-align: center;
  transform-origin: center center;
  transition: transform var(--t-card) var(--ease),
              opacity var(--t-card) var(--ease),
              filter var(--t-card) var(--ease);
}

.shelf-card .tile { flex: 1 1 auto; width: 100%; }

.shelf-card[data-depth="0"] {
  transform: translateY(var(--lift-card));
  opacity: 1;
}

.shelf-card[data-depth="1"][data-side="l"] {
  transform: translateZ(var(--z-card-1)) rotateY(var(--ry-card-1)) scale(var(--sc-card-1));
  opacity: var(--op-card-1);
}
.shelf-card[data-depth="1"][data-side="r"] {
  transform: translateZ(var(--z-card-1)) rotateY(calc(var(--ry-card-1) * -1)) scale(var(--sc-card-1));
  opacity: var(--op-card-1);
}
.shelf-card[data-depth="2"][data-side="l"] {
  transform: translateZ(var(--z-card-2)) rotateY(var(--ry-card-2)) scale(var(--sc-card-2));
  opacity: var(--op-card-2);
}
.shelf-card[data-depth="2"][data-side="r"] {
  transform: translateZ(var(--z-card-2)) rotateY(calc(var(--ry-card-2) * -1)) scale(var(--sc-card-2));
  opacity: var(--op-card-2);
}
.shelf-card[data-depth="3"][data-side="l"] {
  transform: translateZ(var(--z-card-3)) rotateY(var(--ry-card-3)) scale(var(--sc-card-3));
  opacity: var(--op-card-3);
  filter: blur(var(--blur-card));
}
.shelf-card[data-depth="3"][data-side="r"] {
  transform: translateZ(var(--z-card-3)) rotateY(calc(var(--ry-card-3) * -1)) scale(var(--sc-card-3));
  opacity: var(--op-card-3);
  filter: blur(var(--blur-card));
}

/* ---- Screens ---------------------------------------------------------- */

@media (max-width: 767px) {
  :root {
    --w-card: 232px;
    --pad-shelf-y: var(--s-5);
    --z-card-1: -60px;
    --z-card-2: -130px;
    --z-card-3: -180px;
    --h-creed: 116px;
    --r-creed: 80px;
    --gap-shelves: var(--s-8);
  }
  .creed-plate { padding-left: var(--s-4); }
  .creed-claim { font-size: var(--fs-xl); }
}

@media (min-width: 1024px) {
  :root { --w-card: 288px; --h-creed: 136px; --r-creed: 94px; }
}

/* A viewer who has asked for less motion gets the shelves flat and the whole
   standards board at once, as a list, rather than one claim at a time. */
@media (prefers-reduced-motion: reduce) {
  .shelf-track { scroll-behavior: auto; }
  .shelf-track .shelf-card[data-depth][data-side] {
    transform: none;
    opacity: 1;
    filter: none;
    transition: none;
  }
  .creed {
    height: auto;
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
    perspective: none;
  }
  .creed .creed-plate[data-slot] {
    position: static;
    transform: none;
    opacity: 1;
    transition: none;
  }
}

/* ---- Carousel backdrops: the mark, disintegrating behind the vials -----

   Scoped exception: .dust is absolutely positioned, because a backdrop by
   definition sits behind the content rather than beside it. Everything inside
   it is a real element in a flex grid, so each shard occupies real space and
   is only displaced by transform.

   The mark is carried as an alpha mask rather than as a picture, so the shards
   are painted in a token colour. The logo cannot drift off-palette, and a
   change of accent moves it with the rest of the site. */

:root {
  --w-dust: 300px;
  --h-dust: 350px;
  --w-bit: calc(100% / 6);
  --h-bit: calc(100% / 7);
  --cols-dust: 600%;
  --rows-dust: 700%;
  --perspective-dust: 900px;
  --c-dust: var(--c-halo);

  --op-dust-in: 1;
  --op-dust-out: 0.1;
  --t-dust: 16s;
  --ease-dust: cubic-bezier(0.45, 0, 0.2, 1);
  --dust-x: 34px;
  --dust-y: 26px;
  --dust-z: -70px;
  --dust-turn: 16deg;
  --dust-lag: 260ms;

  /* Where each shard reads from the mask. Six columns, seven rows. */
  --bx-0: 0%;
  --bx-1: 20%;
  --bx-2: 40%;
  --bx-3: 60%;
  --bx-4: 80%;
  --bx-5: 100%;
  --by-0: 0%;
  --by-1: 16.6667%;
  --by-2: 33.3333%;
  --by-3: 50%;
  --by-4: 66.6667%;
  --by-5: 83.3333%;
  --by-6: 100%;

  /* The cinematic vial carousel */
  --h-vial: 250px;
  --sc-card-0: 1.05;
  --float-rise: -9px;
  --t-float: 5200ms;
  --t-card-cine: 620ms;
}

.stage-shop { position: relative; }

.shelf-stage {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background-color: var(--c-surface);
}
.stage-shop .shell { position: relative; }

.dust {
  position: absolute;
  inset: var(--s-0);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  perspective: var(--perspective-dust);
}

.dust-field {
  display: flex;
  flex-wrap: wrap;
  width: var(--w-dust);
  height: var(--h-dust);
  transform-style: preserve-3d;
}

.dust-bit {
  flex: 0 0 var(--w-bit);
  height: var(--h-bit);
  background-color: var(--c-dust);
  -webkit-mask-image: url("../img/web/nxxs-mark-mask.png");
  mask-image: url("../img/web/nxxs-mark-mask.png");
  -webkit-mask-size: var(--cols-dust) var(--rows-dust);
  mask-size: var(--cols-dust) var(--rows-dust);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: var(--bx) var(--by);
  mask-position: var(--bx) var(--by);
  animation-delay: var(--lag);
}

[data-shelf-stage="live"] .dust-bit {
  animation: dust-drift var(--t-dust) var(--ease-dust) infinite;
}

.bx-0 { --bx: var(--bx-0); }
.bx-1 { --bx: var(--bx-1); }
.bx-2 { --bx: var(--bx-2); }
.bx-3 { --bx: var(--bx-3); }
.bx-4 { --bx: var(--bx-4); }
.bx-5 { --bx: var(--bx-5); }

.by-0 { --by: var(--by-0); }
.by-1 { --by: var(--by-1); }
.by-2 { --by: var(--by-2); }
.by-3 { --by: var(--by-3); }
.by-4 { --by: var(--by-4); }
.by-5 { --by: var(--by-5); }
.by-6 { --by: var(--by-6); }

/* Six drift vectors, cycled across the grid so neighbouring shards never
   leave together and the mark comes apart unevenly, the way a real thing does. */
.d-0 { --dx: calc(var(--dust-x) * -1);   --dy: calc(var(--dust-y) * -1);   --dr: calc(var(--dust-turn) * -1);   --lag: var(--s-0); }
.d-1 { --dx: var(--dust-x);              --dy: calc(var(--dust-y) * -1.4); --dr: var(--dust-turn);              --lag: var(--dust-lag); }
.d-2 { --dx: calc(var(--dust-x) * 1.6);  --dy: var(--dust-y);              --dr: calc(var(--dust-turn) * 0.5);  --lag: calc(var(--dust-lag) * 2); }
.d-3 { --dx: calc(var(--dust-x) * -1.8); --dy: calc(var(--dust-y) * 0.6);  --dr: calc(var(--dust-turn) * -1.5); --lag: calc(var(--dust-lag) * 3); }
.d-4 { --dx: calc(var(--dust-x) * 0.4);  --dy: calc(var(--dust-y) * 1.8);  --dr: var(--dust-turn);              --lag: calc(var(--dust-lag) * 4); }
.d-5 { --dx: calc(var(--dust-x) * -0.6); --dy: calc(var(--dust-y) * -1.9); --dr: calc(var(--dust-turn) * 0.8);  --lag: calc(var(--dust-lag) * 5); }

@keyframes dust-drift {
  0%, 14%, 100% {
    transform: translate3d(var(--s-0), var(--s-0), var(--s-0)) rotate(var(--s-0));
    opacity: var(--op-dust-in);
  }
  56% {
    transform: translate3d(var(--dx), var(--dy), var(--dust-z)) rotate(var(--dr));
    opacity: var(--op-dust-out);
  }
}

/* ---- The vials --------------------------------------------------------
   On this stage the card chrome goes away and the vial itself is the object:
   it stands on a soft floor, turns as it leaves the centre, and breathes
   while it holds it. */

.stage-shop .tile {
  background-color: transparent;
  border-color: transparent;
  padding: var(--s-0);
}

.stage-shop .tile-plate {
  height: var(--h-vial);
  padding: var(--s-2);
  border: var(--s-0);
  background-color: transparent;
  background-image: radial-gradient(ellipse at 50% 94%, var(--c-floor), var(--c-scrim-0) 66%);
}

.stage-shop .tile-image {
  height: 100%;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

.stage-shop .shelf-card { transition-duration: var(--t-card-cine); }

.stage-shop .shelf-card[data-depth="0"] {
  transform: translateY(var(--lift-card)) scale(var(--sc-card-0));
}

.stage-shop .shelf-card[data-depth="0"] .tile-plate {
  animation: vial-float var(--t-float) var(--ease) infinite;
}

@keyframes vial-float {
  0%, 100% { transform: translateY(var(--s-0)); }
  50%      { transform: translateY(var(--float-rise)); }
}

@supports (color: color-mix(in srgb, red 50%, transparent)) {
  :root { --c-dust: color-mix(in srgb, var(--c-cold) 20%, transparent); }
}

@media (max-width: 767px) {
  :root {
    --w-dust: 232px;
    --h-dust: 270px;
    --h-vial: 196px;
    --dust-x: 22px;
    --dust-y: 18px;
  }
}

@media (min-width: 1024px) {
  :root { --h-vial: 282px; }
}

/* Nothing here is information, so a viewer who has asked for less motion
   gets the mark whole and still, and the vials simply stop breathing. */
@media (prefers-reduced-motion: reduce) {
  .dust-bit { animation: none; }
  .stage-shop .shelf-card[data-depth="0"] .tile-plate { animation: none; }
}