/* GreenMinter app-level rules for the animations family (templates/ui/macros/charts.html dotwave
   and templates/ui/showcase/animations.html): the dot matrix and its canvas layer, scroll-free
   reveals, 3D flip cards, shake and attention. Lumen has no construct for these, so they are
   `gm-dots-bg`, `gm-dot-wave`, `gm-reveal`, `gm-flip`, `gm-shake`, `gm-attn` and `gm-an-*` classes
   over GreenMint's recipes (STYLE_SPEC 4.7, 6.1, 6.3). Colours are --gm-* tokens read at the
   element, so tone scopes apply. Every animation is a
   keyframe whose end is the element's resting style, and all of them are off under
   prefers-reduced-motion. */

/* ---------- dot matrix (STYLE_SPEC 4.7) and the dot-wave canvas layer (6.1) ---------- */
.gm-dots-bg {
  position: relative;
  isolation: isolate;
}
.gm-dots-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-image: radial-gradient(var(--gm-dots-color, rgba(126, 221, 111, 0.12)) 1.2px, transparent 1.3px);
  background-size: var(--gm-dots-pitch, 18px) var(--gm-dots-pitch, 18px);
}
/* Grid only. The canvas is deliberately NOT masked: a mask over a layer that repaints every frame
   is re-applied every frame, so dotwave.js multiplies the identical falloff into each dot instead.
   Change one and change the other. */
.gm-dots-bg--fade::before {
  -webkit-mask-image: radial-gradient(ellipse 90% 90% at 50% 40%, #000 25%, transparent 75%);
  mask-image: radial-gradient(ellipse 90% 90% at 50% 40%, #000 25%, transparent 75%);
}
.gm-dots-bg--pitch-24 {
  --gm-dots-pitch: 24px;
}
.gm-dot-wave {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* the glow colours dotwave.js reads: dark core / halo, then the light pair */
  --dw-core: var(--gm-dots-glow-core, rgba(198, 245, 100, 0.9));
  --dw-mid: var(--gm-dots-glow-mid, rgba(146, 235, 130, 0.4));
}
html[data-theme="light"] .gm-dot-wave {
  --dw-core: var(--gm-dots-glow-core, rgba(47, 157, 63, 0.85));
  --dw-mid: var(--gm-dots-glow-mid, rgba(47, 157, 63, 0.35));
}

/* ---------- hero-style stage: copy on the left, an ambient glow card on the right ---------- */
.gm-an-hero {
  overflow: hidden;
  border: 1px solid var(--gm-border);
  border-radius: 28px;
  background-color: var(--gm-bg);
}
.gm-an-hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 48px;
  align-items: center;
  padding: 56px 48px;
}
.gm-an-hero__copy {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  min-width: 0;
}
/* a soft scrim under the copy dims the dot field behind the words (GreenMint's site-hero-copy) */
.gm-an-hero__copy::before {
  content: "";
  position: absolute;
  inset: -20px -32px;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 60% 62% at 45% 45%, color-mix(in srgb, var(--gm-bg) 85%, transparent) 0%, transparent 100%);
}
.gm-an-hero__title {
  margin: 0;
  font-family: var(--gm-font-display, inherit);
  font-size: clamp(2.25rem, 5.4vw, 3.5rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.03em;
  color: var(--gm-text);
}
.gm-an-hero__title span {
  color: var(--gm-primary-ink);
}
.gm-an-hero__sub {
  max-width: 52ch;
  margin: 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--gm-text-muted);
}
.gm-an-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.gm-an-hero__proof {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  margin-top: 8px;
}
.gm-an-hero__proof span {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.gm-an-hero__proof b {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--gm-text);
}
.gm-an-hero__proof small {
  font-size: 12px;
  color: var(--gm-text-subtle);
}
.gm-an-hero__note {
  margin: 0;
  font-size: 12px;
  color: var(--gm-text-subtle);
}
.gm-an-hero__visual {
  position: relative;
  min-width: 0;
}
.gm-an-hero__visual-label {
  display: block;
  margin-bottom: 12px;
  font-family: var(--gm-font-mono, ui-monospace, monospace);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gm-primary-ink);
}

/* The ambient glow card: one radial wash (STYLE_SPEC 4.5, green for a long setup) over the
   surface, a flat grey animal silhouette bled off the corner (6.2, molecules' animal_watermark with the
   trade-alert brief recipe), no ring: one glow per card. */
.gm-an-glow {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 24px;
  border: 1px solid var(--gm-border);
  border-radius: 20px;
  background-color: var(--gm-surface);
  background-image: var(--gm-glow-green);
  background-repeat: no-repeat;
}
.gm-an-glow__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.gm-an-glow__tick {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.gm-an-glow__tick b {
  font-size: 24px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: 0.02em;
  color: var(--gm-text);
}
.gm-an-glow__tick small {
  font-size: 12px;
  color: var(--gm-text-muted);
}
.gm-an-glow__price {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 16px;
  font-weight: 700;
  color: var(--gm-text);
}
.gm-an-glow__price span {
  font-size: 14px;
  font-weight: 600;
  color: var(--gm-up-ink, var(--gm-up));
}
.gm-an-glow__metric {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.gm-an-glow__metric b {
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--gm-up-ink, var(--gm-up));
}
.gm-an-glow__metric small {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gm-text-subtle);
}
.gm-an-glow__why {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--gm-text);
}
.gm-an-glow__levels {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.gm-an-glow__level {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border: 1px solid var(--gm-border);
  border-radius: 12px;
  background: var(--gm-surface-2);
}
.gm-an-glow__level small {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gm-text-subtle);
}
.gm-an-glow__level b {
  font-size: 14px;
  font-weight: 700;
  color: var(--gm-text);
}
.gm-an-glow__level--stop b { color: var(--gm-down-ink, var(--gm-down)); }
.gm-an-glow__level--target b { color: var(--gm-up-ink, var(--gm-up)); }
.gm-an-glow .gm-ch-radial__center b {
  font-size: 18px;
}

/* A CTA band: a full-width strip with a centred message over the dot field. */
.gm-an-band {
  overflow: hidden;
  border: 1px solid var(--gm-border);
  border-radius: 20px;
  background-color: var(--gm-bg);
}
.gm-an-band__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 56px 24px;
  text-align: center;
}
.gm-an-band__inner h3 {
  max-width: 20ch;
  margin: 0;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--gm-text);
}
.gm-an-band__inner p {
  max-width: 52ch;
  margin: 0;
  font-size: 14px;
  color: var(--gm-text-muted);
}

/* The small option stages: each a bordered box over a dot field, captioned by a sub-label above it. */
.gm-an-stage {
  min-height: 128px;
  overflow: hidden;
  border: 1px solid var(--gm-border);
  border-radius: 20px;
  background-color: var(--gm-surface);
}
.gm-an-opts { margin-top: 8px; }
.gm-an-opt {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

@media (max-width: 860px) {
  .gm-an-hero__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
    padding: 32px 24px;
  }
}

/* ---------- reveals (STYLE_SPEC 6.3): 0.6s strong ease-out, staggered by --d ---------- */
@keyframes gm-rv-fade-up { from { opacity: 0; transform: translateY(24px); } }
@keyframes gm-rv-fade-in { from { opacity: 0; } }
@keyframes gm-rv-scale-in { from { opacity: 0; transform: scale(0.92); } }
@keyframes gm-rv-slide-left { from { opacity: 0; transform: translateX(32px); } }
@keyframes gm-rv-slide-right { from { opacity: 0; transform: translateX(-32px); } }

/* A slide-in tile starts 32px off to the side; clip it so a narrow page never scrolls sideways while it waits. */
.gm-an-clip { overflow-x: clip; }
.gm-reveal {
  animation-duration: 0.6s;
  animation-timing-function: var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1));
  animation-fill-mode: both;
  animation-delay: var(--d, 0ms);
}
.gm-reveal--fade-up { animation-name: gm-rv-fade-up; }
.gm-reveal--fade-in { animation-name: gm-rv-fade-in; }
.gm-reveal--scale-in { animation-name: gm-rv-scale-in; }
.gm-reveal--slide-left { animation-name: gm-rv-slide-left; }
.gm-reveal--slide-right { animation-name: gm-rv-slide-right; }

/* Hover replay, CSS only: at rest the tile is in its final state; the animation plays while the
   pointer is on it and simply stops when it leaves, so there is no flicker on exit. */
.gm-reveal-on-hover {
  animation-duration: 0.6s;
  animation-timing-function: var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1));
}
.gm-reveal-on-hover.gm-reveal--fade-up:hover { animation-name: gm-rv-fade-up; }
.gm-reveal-on-hover.gm-reveal--fade-in:hover { animation-name: gm-rv-fade-in; }
.gm-reveal-on-hover.gm-reveal--scale-in:hover { animation-name: gm-rv-scale-in; }
.gm-reveal-on-hover.gm-reveal--slide-left:hover { animation-name: gm-rv-slide-left; }
.gm-reveal-on-hover.gm-reveal--slide-right:hover { animation-name: gm-rv-slide-right; }

/* ---------- flip cards (STYLE_SPEC 6.3): perspective 1200px, 0.6s, backface hidden ---------- */
.gm-flip {
  height: var(--gm-flip-h, 168px);
  perspective: 1200px;
  border-radius: 20px;
  cursor: default;
}
.gm-flip--click {
  cursor: pointer;
}
.gm-flip__inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1));
}
/* :focus-within as well as :hover, so a keyboard reaches the back (the cards carry tabindex 0). */
.gm-flip:not(.gm-flip--click):hover .gm-flip__inner,
.gm-flip:not(.gm-flip--click):focus-within .gm-flip__inner,
.gm-flip--click.gm-flip--flipped .gm-flip__inner {
  transform: rotateY(180deg);
}
.gm-flip:focus-visible {
  outline: 2px solid var(--gm-primary-control);
  outline-offset: 2px;
}
.gm-flip__face {
  position: absolute;
  inset: 0;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.gm-flip__face--back {
  transform: rotateY(180deg);
}
.gm-flip__face > .lm-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  height: 100%;
  text-align: center;
  /* a backdrop filter would flatten the 3D context and let the back face show through */
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.gm-flip__ticker {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--gm-text);
}
.gm-flip__back-text {
  margin: 4px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--gm-text-muted);
}
.gm-flip__big {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.gm-flip__zap {
  color: var(--gm-primary-control);
}

/* ---------- shake (STYLE_SPEC 6.3): sm 0.4s, md 0.5s, lg 0.6s; replayed by motion.js ---------- */
.gm-shake--sm { animation: gm-shake-sm 0.4s var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1)); }
.gm-shake--md { animation: gm-shake-md 0.5s var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1)); }
.gm-shake--lg { animation: gm-shake-lg 0.6s var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1)); }
@keyframes gm-shake-sm {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}
@keyframes gm-shake-md {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-8px); }
  40%, 60% { transform: translateX(8px); }
}
@keyframes gm-shake-lg {
  10%, 90% { transform: translateX(-3px); }
  20%, 80% { transform: translateX(6px); }
  30%, 50%, 70% { transform: translateX(-12px); }
  40%, 60% { transform: translateX(12px); }
}

/* ---------- attention: a quiet ring ping on the one thing that needs a look ---------- */
.gm-attn {
  position: relative;
  display: inline-flex;
  border-radius: 9999px;
}
.gm-attn::after {
  content: "";
  position: absolute;
  inset: -3px;
  border: 2px solid var(--gm-danger, var(--gm-down));
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
  animation: gm-attn-ping 2s var(--gm-ease, cubic-bezier(0.22, 1, 0.36, 1)) infinite;
}
@keyframes gm-attn-ping {
  0% { opacity: 0.7; transform: scale(0.94); }
  70%, 100% { opacity: 0; transform: scale(1.3); }
}

/* the showcase's shake and attention demos */
.gm-an-shake {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  max-width: 320px;
}
.gm-an-shake .lm-field {
  width: 100%;
}
.gm-an-shake__msg {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--gm-down-ink, var(--gm-down));
}
.gm-an-shake__msg[hidden] {
  display: none;
}
.gm-an-refused {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
}
.gm-an-refused__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.gm-an-refused__text b {
  font-size: 14px;
  font-weight: 600;
  color: var(--gm-text);
}
.gm-an-refused__text small {
  font-size: 12px;
  color: var(--gm-text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .gm-reveal,
  .gm-reveal-on-hover:hover,
  .gm-shake--sm,
  .gm-shake--md,
  .gm-shake--lg,
  .gm-attn::after {
    animation: none !important;
  }
  .gm-flip__inner {
    transition-duration: 0.01ms;
  }
}
