/* fx.css — the quiet "vibe" layer: film grain for depth, copy flash, and the
   copy toast. Restraint: one ambient texture, motion only on interaction.
   Depends on tokens.css. */

/* Film grain — gives the flat dark surfaces subtle depth. Fixed, non-blocking,
   very low opacity so it reads as texture, not noise. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
body > * { position: relative; z-index: 1; }

/* On light, the noise must darken the surface (multiply) to read as texture. */
:root[data-theme="light"] body::before {
  opacity: 0.03;
  mix-blend-mode: multiply;
}

@media (prefers-reduced-motion: reduce) {
  body::before { display: none; }
}

/* Copy flash — a quick ring pulse in the brand accent on the copied element. */
@keyframes copyFlash {
  0% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 80%, transparent); }
  100% { box-shadow: 0 0 0 2px transparent; }
}
.is-flash { animation: copyFlash 0.5s var(--ease); }

/* Toast — brief confirmation, tinted in the copied color. */
.toast-host {
  position: fixed;
  left: 50%;
  bottom: var(--s-8);
  z-index: 60;
  display: grid;
  gap: var(--s-2);
  transform: translateX(-50%);
  pointer-events: none;
}
.toast {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--toast-accent, var(--border));
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface-2) 88%, var(--toast-accent, transparent));
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  box-shadow: var(--shadow-3);
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.toast.is-in { opacity: 1; transform: translateY(0) scale(1); }
.toast.is-out { opacity: 0; transform: translateY(-6px) scale(0.98); }
.toast-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15) inset;
}

/* "Wear the brand" morph — a brief window where the whole UI transitions its
   token-driven colors, so re-skinning into the brand reads as a smooth change
   of clothes rather than a hard cut. Reduced-motion (above) zeroes this out. */
body.theming,
body.theming *:not(.grain) {
  transition:
    background-color var(--dur-3) var(--ease),
    color var(--dur-3) var(--ease),
    border-color var(--dur-3) var(--ease),
    box-shadow var(--dur-3) var(--ease),
    fill var(--dur-3) var(--ease) !important;
}

/* Scroll-reveal — result sections fade + rise as they enter view (reveal.js
   toggles .is-in). Swatch rows cascade their cards. Reduced-motion never gets
   the .reveal class, so content simply appears. */
.reveal { opacity: 0; transform: translateY(18px); }
.reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease);
}
.reveal .swatch-row .swatch { opacity: 0; transform: translateY(12px); }
.reveal.is-in .swatch-row .swatch {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.reveal.is-in .swatch-row .swatch:nth-child(2) { transition-delay: 45ms; }
.reveal.is-in .swatch-row .swatch:nth-child(3) { transition-delay: 90ms; }
.reveal.is-in .swatch-row .swatch:nth-child(4) { transition-delay: 135ms; }
.reveal.is-in .swatch-row .swatch:nth-child(n + 5) { transition-delay: 180ms; }

/* Save celebration — floating hearts (celebrate.js) + a pop on the heart. */
.celebrate-bit {
  position: fixed;
  font-size: 17px;
  line-height: 1;
  pointer-events: none;
  z-index: 70;
  will-change: transform, opacity;
}
@keyframes heartPop {
  0% { transform: scale(1); }
  35% { transform: scale(1.35); }
  60% { transform: scale(0.92); }
  100% { transform: scale(1); }
}
.tool-btn.is-saved { animation: heartPop 0.45s var(--ease); }
