/* ─────────────────────────────────────────────────────────────────────────
 * <marquee-wc> — Vanilla Breeze component styles
 *
 * Theming hooks (CSS custom properties):
 *   --marquee-gap            : space between repeats (overridable via attr)
 *   --marquee-fade-size      : size of edge fade mask (default 3rem)
 *   --marquee-duration       : set by JS based on speed × content
 *   --marquee-cycle-distance : set by JS (one item + gap)
 *   --marquee-bg, --marquee-fg : background/foreground for themed variants
 *
 * Vanilla Breeze integration:
 *   Themed variants read VB design tokens (--color-surface, --color-text,
 *   --color-error, --font-mono, --font-serif, --radius-m, …) via layered
 *   var() fallbacks. A --marquee-* override always wins; absent that, a VB
 *   token is used; absent that, a sensible built-in default applies. Pages
 *   running a VB theme get a matching marquee automatically, with zero config.
 *
 * State hooks (data-* set by JS):
 *   data-axis        : x | y
 *   data-direction   : forward | reverse
 *   data-behavior    : loop | slide | alternate
 *   data-state       : running | paused
 *   data-visible     : true | false (IntersectionObserver)
 *   data-tab-visible : true | false (Page Visibility)
 * ──────────────────────────────────────────────────────────────────────── */

marquee-wc {
  display: block;
  position: relative;
  overflow: hidden;
  --marquee-gap: 2rem;
  --marquee-fade-size: 3rem;
  --marquee-duration: 20s;
  --marquee-cycle-distance: 100%;
  --marquee-alternate-distance: 0px;
}

/* Unupgraded fallback: render content statically, no animation */
marquee-wc:not(:defined),
marquee-wc:not([data-ready]) {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Edge fade mask via CSS mask (no extra DOM) */
marquee-wc[fade] {
  --_fade: var(--marquee-fade-size);
  mask-image: linear-gradient(
    to right,
    transparent 0,
    black var(--_fade),
    black calc(100% - var(--_fade)),
    transparent 100%
  );
}
marquee-wc[fade][data-axis='y'] {
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    black var(--_fade),
    black calc(100% - var(--_fade)),
    transparent 100%
  );
}

/* Internal structure */
marquee-wc .marquee-viewport {
  display: flex;
  overflow: hidden;
  width: 100%;
  height: 100%;
}
marquee-wc[data-axis='y'] .marquee-viewport {
  flex-direction: column;
}

marquee-wc .marquee-track {
  display: flex;
  flex-shrink: 0;
  gap: var(--marquee-gap);
  will-change: transform;
}
marquee-wc[data-axis='y'] .marquee-track {
  flex-direction: column;
}

marquee-wc .marquee-item {
  flex-shrink: 0;
  white-space: nowrap;
}
marquee-wc[data-axis='y'] .marquee-item {
  white-space: normal;
}

/* ─── Keyframes ──────────────────────────────────────────────────────── */

@keyframes marquee-wc-loop-x {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(calc(-1 * var(--marquee-cycle-distance)), 0, 0);
  }
}

@keyframes marquee-wc-loop-y {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, calc(-1 * var(--marquee-cycle-distance)), 0);
  }
}

@keyframes marquee-wc-slide-x {
  from {
    transform: translate3d(100%, 0, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

@keyframes marquee-wc-slide-y {
  from {
    transform: translate3d(0, 100%, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

@keyframes marquee-wc-alternate-x {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(var(--marquee-alternate-distance, 0px), 0, 0);
  }
}

@keyframes marquee-wc-alternate-y {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, var(--marquee-alternate-distance, 0px), 0);
  }
}

/* ─── Animation application ──────────────────────────────────────────── */

marquee-wc[data-behavior='loop'][data-axis='x'] .marquee-track {
  animation: marquee-wc-loop-x var(--marquee-duration) linear infinite;
}
marquee-wc[data-behavior='loop'][data-axis='y'] .marquee-track {
  animation: marquee-wc-loop-y var(--marquee-duration) linear infinite;
}
marquee-wc[data-behavior='slide'][data-axis='x'] .marquee-track {
  animation: marquee-wc-slide-x var(--marquee-duration) linear 1 forwards;
}
marquee-wc[data-behavior='slide'][data-axis='y'] .marquee-track {
  animation: marquee-wc-slide-y var(--marquee-duration) linear 1 forwards;
}
marquee-wc[data-behavior='alternate'][data-axis='x'] .marquee-track {
  animation: marquee-wc-alternate-x var(--marquee-duration) ease-in-out infinite alternate;
}
marquee-wc[data-behavior='alternate'][data-axis='y'] .marquee-track {
  animation: marquee-wc-alternate-y var(--marquee-duration) ease-in-out infinite alternate;
}

/* Reverse direction uses CSS animation-direction */
marquee-wc[data-direction='reverse'][data-behavior='loop'] .marquee-track,
marquee-wc[data-direction='reverse'][data-behavior='slide'] .marquee-track {
  animation-direction: reverse;
}
marquee-wc[data-direction='reverse'][data-behavior='alternate'] .marquee-track {
  animation-direction: alternate-reverse;
}

/* ─── Pause states ───────────────────────────────────────────────────── */

/* !important: the per-behavior `animation` shorthand below is more specific
   and would otherwise reset animation-play-state back to running. */
marquee-wc[data-state='paused'] :is(.marquee-track, .marquee-char),
marquee-wc[data-visible='false'] :is(.marquee-track, .marquee-char),
marquee-wc[data-tab-visible='false'] :is(.marquee-track, .marquee-char) {
  animation-play-state: paused !important;
}

marquee-wc[pause-on-hover]:where(:hover, :focus-within) :is(.marquee-track, .marquee-char) {
  animation-play-state: paused !important;
}

/* ─── Accessibility: prefers-reduced-motion ──────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  marquee-wc:not([reduced-motion='ignore']) .marquee-track {
    animation: none !important;
    transform: none !important;
  }
  /* Letters stop animating but keep any static styling (e.g. ransom tilt). */
  marquee-wc:not([reduced-motion='ignore']) .marquee-char {
    animation: none !important;
  }
}

/* ─── Theme: ticker (compact, monospace, fade edges) ─────────────────── */

marquee-wc[mode='ticker'] {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.9rem;
  padding-block: 0.5rem;
  background: var(--marquee-bg, var(--color-surface, oklch(20% 0.02 250)));
  color: var(--marquee-fg, var(--color-text, oklch(95% 0.02 100)));
  --marquee-gap: 3rem;
  --_fade: 2rem;
  mask-image: linear-gradient(
    to right,
    transparent 0,
    black var(--_fade),
    black calc(100% - var(--_fade)),
    transparent 100%
  );
}
marquee-wc[mode='ticker'] .marquee-item::after {
  content: ' •';
  opacity: 0.4;
  margin-inline-start: 1rem;
}

/* ─── Theme: breaking-news (red bar + label) ─────────────────────────── */

marquee-wc[mode='breaking-news'] {
  display: flex;
  align-items: stretch;
  background: var(--marquee-bg, var(--color-error, oklch(50% 0.22 25)));
  color: var(--marquee-fg, white);
  font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
  font-weight: 600;
  --marquee-gap: 4rem;
}
marquee-wc[mode='breaking-news']::before {
  content: var(--marquee-label, 'BREAKING');
  flex-shrink: 0;
  padding: 0.75rem 1rem;
  background: oklch(0% 0 0 / 0.25);
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  align-content: center;
}
marquee-wc[mode='breaking-news'] .marquee-viewport {
  padding-block: 0.75rem;
}

/* ─── Theme: code-block (monospace, syntax-friendly) ─────────────────── */

marquee-wc[mode='code-block'] {
  font-family: var(--font-mono, ui-monospace, monospace);
  background: var(
    --marquee-bg,
    var(--color-surface-sunken, var(--color-surface, oklch(15% 0.01 250)))
  );
  color: var(--marquee-fg, var(--color-text, oklch(90% 0.02 250)));
  border-radius: var(--radius-m, 0.5rem);
  padding: 1rem;
  --marquee-gap: 4ch;
  font-size: 0.9rem;
  line-height: 1.5;
}
marquee-wc[mode='code-block'] .marquee-item {
  tab-size: 2;
}

/* ─── Theme: screen-saver (DVD-bouncing energy, big text, glow) ──────── */

marquee-wc[mode='screen-saver'] {
  background: var(--marquee-bg, var(--color-background, oklch(15% 0.05 280)));
  color: var(--marquee-fg, var(--color-accent, var(--color-primary, oklch(80% 0.25 320))));
  font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
  font-size: clamp(2rem, 8vw, 6rem);
  font-weight: 900;
  letter-spacing: -0.02em;
  padding-block: 2rem;
  text-shadow:
    0 0 1rem currentColor,
    0 0 2rem currentColor;
}

/* ─── Theme: credits (vertical movie-credit roll) ────────────────────── */

marquee-wc[mode='credits'] {
  background: var(--marquee-bg, black);
  color: var(--marquee-fg, white);
  font-family: var(--font-serif, ui-serif, Georgia, serif);
  text-align: center;
  min-height: 24rem;
  --marquee-gap: 2rem;
  --marquee-fade-size: 4rem;
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    black 4rem,
    black calc(100% - 4rem),
    transparent 100%
  );
}
marquee-wc[mode='credits'] .marquee-item {
  white-space: normal;
  padding-inline: 2rem;
  line-height: 1.6;
}

/* ─── Theme: dot-matrix (glowing LED board over a dot grid) ───────────── */

marquee-wc[mode='dot-matrix'] {
  --_led: var(--marquee-fg, var(--color-accent, oklch(82% 0.18 90)));
  background-color: var(--marquee-bg, var(--color-background, oklch(16% 0.02 250)));
  color: var(--_led);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  padding-block: 0.75rem;
  text-shadow:
    0 0 0.35em currentColor,
    0 0 0.7em currentColor;
  /* faint LED dot grid behind the text */
  background-image: radial-gradient(
    color-mix(in oklch, currentColor 22%, transparent) 30%,
    transparent 32%
  );
  background-size: 0.42em 0.42em;
}

/* ─── Hover affordance: subtle cursor hint when pausable ─────────────── */

marquee-wc[pause-on-hover] {
  cursor: default;
}

/* ─────────────────────────────────────────────────────────────────────────
 * Per-letter motion modes
 *
 * For mode="bounce|wave|march|pulse|ransom" the component wraps every
 * character in <span class="marquee-char" style="--i:N">. The --i index
 * staggers each letter's animation so the effect ripples across the text.
 * Transforms don't affect layout, so constant-velocity scrolling is unaffected.
 * ──────────────────────────────────────────────────────────────────────── */

marquee-wc[mode='bounce'] .marquee-char,
marquee-wc[mode='wave'] .marquee-char,
marquee-wc[mode='march'] .marquee-char,
marquee-wc[mode='pulse'] .marquee-char {
  display: inline-block;
  animation-iteration-count: infinite;
  animation-delay: calc(var(--i, 0) * var(--marquee-char-stagger, 0.06s));
  will-change: transform;
}

/* bounce — letters hop up and back down */
marquee-wc[mode='bounce'] .marquee-char {
  animation-name: marquee-wc-bounce;
  animation-duration: 0.9s;
  animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
}
@keyframes marquee-wc-bounce {
  0%,
  100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-0.55em);
  }
}

/* wave — roller-coaster: a tall sinusoidal ride with a little banking */
marquee-wc[mode='wave'] .marquee-char {
  animation-name: marquee-wc-wave;
  animation-duration: 1.6s;
  animation-timing-function: ease-in-out;
  --marquee-char-stagger: 0.08s;
}
@keyframes marquee-wc-wave {
  0%,
  100% {
    transform: translateY(0.5em) rotate(8deg);
  }
  50% {
    transform: translateY(-0.5em) rotate(-8deg);
  }
}

/* march — stepped up/down, like a marching band */
marquee-wc[mode='march'] .marquee-char {
  animation-name: marquee-wc-march;
  animation-duration: 0.6s;
  animation-timing-function: step-end;
  --marquee-char-stagger: 0.09s;
}
@keyframes marquee-wc-march {
  0% {
    transform: translateY(-0.3em);
  }
  50% {
    transform: translateY(0.3em);
  }
  100% {
    transform: translateY(-0.3em);
  }
}

/* pulse — letters grow and shrink in a travelling swell */
marquee-wc[mode='pulse'] .marquee-char {
  animation-name: marquee-wc-pulse;
  animation-duration: 1s;
  animation-timing-function: ease-in-out;
  --marquee-char-stagger: 0.07s;
}
@keyframes marquee-wc-pulse {
  0%,
  100% {
    transform: scale(0.7);
  }
  50% {
    transform: scale(1.45);
  }
}

/* pop — letters balloon and burst at random, like little explosions */
marquee-wc[mode='pop'] .marquee-char {
  display: inline-block;
  transform-origin: center;
  animation: marquee-wc-pop 2.8s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}
@keyframes marquee-wc-pop {
  0%,
  68%,
  100% {
    transform: scale(1);
  }
  76% {
    transform: scale(2.6) rotate(-5deg);
    color: var(--color-accent, var(--color-primary, oklch(70% 0.2 30)));
    text-shadow: 0 0 0.5em currentColor;
  }
  84% {
    transform: scale(0.9) rotate(2deg);
  }
}

/* spin — letters cartwheel around, in a rolling stagger */
marquee-wc[mode='spin'] .marquee-char {
  display: inline-block;
  animation: marquee-wc-spin 1.2s linear infinite;
  animation-delay: calc(var(--i, 0) * 0.08s);
}
@keyframes marquee-wc-spin {
  to {
    transform: rotate(1turn);
  }
}

/* flip — split-flap board: letters tumble forward on the X axis */
marquee-wc[mode='flip'] {
  perspective: 600px;
}
marquee-wc[mode='flip'] .marquee-char {
  display: inline-block;
  animation: marquee-wc-flip 1.5s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * 0.1s);
}
@keyframes marquee-wc-flip {
  0%,
  100% {
    transform: rotateX(0deg);
  }
  50% {
    transform: rotateX(1turn);
  }
}

/* rainbow — a flowing spectrum that ripples across the letters */
marquee-wc[mode='rainbow'] .marquee-char {
  display: inline-block;
  color: hsl(calc(var(--i, 0) * 28deg) 95% 55%);
  animation: marquee-wc-rainbow 1.6s linear infinite;
  animation-delay: calc(var(--i, 0) * -0.05s);
}
@keyframes marquee-wc-rainbow {
  to {
    filter: hue-rotate(360deg);
  }
}

/* glitch — jittery skew with a chromatic-aberration shadow */
marquee-wc[mode='glitch'] .marquee-char {
  display: inline-block;
  text-shadow:
    0.03em 0 oklch(60% 0.24 25 / 0.7),
    -0.03em 0 oklch(70% 0.18 220 / 0.7);
  animation: marquee-wc-glitch 0.5s steps(2, jump-none) infinite;
  animation-delay: calc(var(--i, 0) * -0.07s);
}
@keyframes marquee-wc-glitch {
  0%,
  100% {
    transform: translate(0, 0) skewX(0deg);
  }
  25% {
    transform: translate(0.04em, -0.05em) skewX(-9deg);
  }
  50% {
    transform: translate(-0.05em, 0.03em) skewX(7deg);
  }
  75% {
    transform: translate(0.03em, 0.04em) skewX(-3deg);
  }
}

/* leet — l33t substitution (done in JS) with random mirrored/flipped letters
   (--flip, also in JS) and a flickering green-glow terminal vibe */
marquee-wc[mode='leet'] {
  font-family: var(--font-mono, ui-monospace, monospace);
  color: var(--marquee-fg, var(--color-success, oklch(82% 0.2 145)));
  text-shadow: 0 0 0.3em currentColor;
}
marquee-wc[mode='leet'] .marquee-char {
  display: inline-block;
  transform: var(--flip, none);
  animation: marquee-wc-flicker 1.5s steps(2, jump-none) infinite;
  animation-delay: calc(var(--i, 0) * -0.11s);
}
@keyframes marquee-wc-flicker {
  0%,
  86%,
  100% {
    opacity: 1;
  }
  90% {
    opacity: 0.35;
  }
  94% {
    opacity: 1;
  }
  97% {
    opacity: 0.55;
  }
}

/* blink — each letter blinks on its own clock (rate + delay set in JS),
   glowing while lit */
marquee-wc[mode='blink'] .marquee-char {
  display: inline-block;
  animation: marquee-wc-blink var(--blink-rate, 1s) step-end infinite;
  animation-delay: var(--blink-delay, 0s);
}
@keyframes marquee-wc-blink {
  0% {
    opacity: 1;
    text-shadow: 0 0 0.45em currentColor;
  }
  50% {
    opacity: 0.12;
    text-shadow: none;
  }
}

/* chase — a stadium-wave / theater-marquee light that sweeps letter-to-letter
   and loops around. The per-letter delay is spread across one cycle via --i/--n */
marquee-wc[mode='chase'] .marquee-char {
  display: inline-block;
  animation: marquee-wc-chase 1.6s ease-in-out infinite;
  animation-delay: calc((var(--i, 0) / var(--n, 1)) * 1.6s);
}
@keyframes marquee-wc-chase {
  0%,
  100% {
    opacity: 0.5;
    transform: translateY(0);
  }
  50% {
    opacity: 1;
    transform: translateY(-0.18em);
    color: var(--color-accent, var(--color-primary, oklch(82% 0.2 90)));
    text-shadow: 0 0 0.55em currentColor;
  }
}

/* invert — reverse-video chips (text in the page colour on a coloured block)
   whose hue shifts and ripples across the units (works per letter or per word) */
marquee-wc[mode='invert'] .marquee-char {
  display: inline-block;
  margin-inline: 0.02em;
  padding: 0.05em 0.12em;
  border-radius: 0.1em;
  background: hsl(calc(var(--i, 0) * 26deg) 80% 50%);
  color: var(--marquee-bg, var(--color-background, oklch(98% 0 0)));
  animation: marquee-wc-rainbow 2.4s linear infinite;
  animation-delay: calc(var(--i, 0) * -0.08s);
}
marquee-wc[mode='invert'] .marquee-space {
  background: none;
  padding-inline: 0;
}

/* decode — units flicker through random glyphs (set in JS) then lock onto the
   real text. Monospace keeps the width stable while glyphs change, so scrolling
   stays smooth. Matrix-green glow by default. */
marquee-wc[mode='decode'] {
  font-family: var(--font-mono, ui-monospace, monospace);
  color: var(--marquee-fg, var(--color-success, oklch(82% 0.2 145)));
  text-shadow: 0 0 0.25em currentColor;
}
marquee-wc[mode='decode'] .marquee-char {
  display: inline-block;
}

/* ransom — cut-out magazine letters: random font, tilt, scale, colored chip */
marquee-wc[mode='ransom'] {
  font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
  font-weight: 700;
  padding-block: 0.5rem;
}
marquee-wc[mode='ransom'] .marquee-char {
  display: inline-block;
  margin-inline: 0.05em;
  padding: 0.06em 0.2em;
  border-radius: 0.14em;
  background: var(--chip, var(--color-accent, oklch(55% 0.18 250)));
  color: oklch(98% 0 0);
  transform: rotate(var(--rot, 0deg)) scale(var(--scale, 1));
  box-shadow: 0 1px 2px oklch(0% 0 0 / 0.3);
}
marquee-wc[mode='ransom'] .marquee-space {
  background: none;
  box-shadow: none;
  padding-inline: 0;
}
