/* ===========================================================================
   ATOMYS_OS — MICRO-INTERACTION PRIMITIVES
   Snap-on classes that add tasteful, single-shot motion. Subtle by default,
   tied to existing tokens (--violet, --lime, --t-fast, --ease).

   Color system
   - Every primitive that paints color exposes a single `--accent` custom
     property and routes ALL its visual color (halos, particles, scan flash,
     pixel shadow, toast) through it. The default is `var(--violet)` — the
     brand primary — so primitives feel on-brand out of the box.
   - Modifiers `.lime` and `.danger` swap the accent. You can also override
     `--accent` inline (style="--accent: var(--lime)") to match a host card.

   Conventions
   - Each primitive is opt-in via a class (and sometimes a data-* attribute).
   - Scroll-triggered primitives flip to `.is-on` once via IntersectionObserver
     in js/interactions.js (one-shot — they don't repeat on re-enter).
   - All animations gate on `prefers-reduced-motion` at the bottom of the file.
   =========================================================================== */

@layer interactions {
  /* ── 1. .boot-in — CRT warm-up reveal (one-shot, scroll-into-view) ─────
     Use on cards / sections. Fades + lifts + briefly halos with the accent
     color. No pseudo-elements, so it composes safely with .win / .featured /
     .hole which already use ::before/::after. */
  .boot-in {
    --accent: var(--violet);
    opacity: 0.55;
    transform: translateY(4px);
    filter: brightness(0.85) saturate(0.92);
    transition:
      opacity 320ms var(--ease),
      transform 320ms var(--ease),
      filter 380ms var(--ease);
  }
  .boot-in.lime {
    --accent: var(--lime);
  }
  .boot-in.danger {
    --accent: var(--danger);
  }
  .boot-in.is-on {
    opacity: 1;
    transform: translateY(0);
    filter: brightness(1) saturate(1);
    animation: boot-halo 700ms var(--ease) 1;
  }
  @keyframes boot-halo {
    0%,
    100% {
      box-shadow: 0 0 0 color-mix(in oklab, var(--accent) 0%, transparent);
    }
    35% {
      box-shadow:
        0 0 0 1px color-mix(in oklab, var(--accent) 38%, transparent),
        0 0 32px color-mix(in oklab, var(--accent) 22%, transparent);
    }
  }

  /* ── 2. .pixel-hover — steppy shadow + edge tint on hover ──────────────
     Steps(2) makes the shadow snap rather than tween — reads as "pixel"
     rather than "smooth". Use on list rows, links, tag chips. */
  .pixel-hover {
    --accent: var(--violet);
    transition:
      box-shadow var(--t-fast) steps(2),
      transform var(--t-fast) steps(2),
      color var(--t-fast),
      border-color var(--t-fast);
  }
  .pixel-hover.lime {
    --accent: var(--lime);
  }
  .pixel-hover.danger {
    --accent: var(--danger);
  }
  .pixel-hover:hover {
    transform: translate(-1px, -1px);
    box-shadow:
      2px 2px 0 0 color-mix(in oklab, var(--accent) 55%, transparent),
      4px 4px 0 0 color-mix(in oklab, var(--accent) 22%, transparent);
  }

  /* ── 3. [data-count] — tabular numerals so the width doesn't jump ──────
     The actual count animation runs in JS (rAF, ease-out cubic). This rule
     just keeps the layout stable while digits change. */
  [data-count] {
    font-variant-numeric: tabular-nums;
  }

  /* ── 4. .copy-flash — CRT scan flash + COPIED toast on click ───────────
     Default accent is violet (primary). Add .lime for success-coded
     "confirm" feedback. The element needs `position: relative` so the toast
     can be absolutely positioned within. */
  .copy-flash {
    --accent: var(--violet);
    position: relative;
  }
  .copy-flash.lime {
    --accent: var(--lime);
  }
  .copy-flash.danger {
    --accent: var(--danger);
  }
  .copy-flash.is-flashing {
    animation: copy-scan 280ms linear 1;
  }
  @keyframes copy-scan {
    0% {
      box-shadow: inset 0 0 0 9999px transparent;
    }
    25% {
      box-shadow: inset 0 0 0 9999px
        color-mix(in oklab, var(--accent) 18%, transparent);
    }
    100% {
      box-shadow: inset 0 0 0 9999px transparent;
    }
  }
  .copy-toast {
    position: absolute;
    inset-block-start: 0.5rem;
    inset-inline-end: 0.5rem;
    font-family: var(--font-mono);
    font-size: var(--fs-meta);
    letter-spacing: 0.18em;
    color: color-mix(in oklab, var(--accent) 35%, var(--ink-0));
    background: color-mix(in oklab, var(--accent) 14%, var(--bg-1));
    border: 1px solid color-mix(in oklab, var(--accent) 50%, transparent);
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius-s);
    pointer-events: none;
    opacity: 0;
    transform: translateY(-4px);
    transition:
      opacity var(--t-fast),
      transform var(--t-fast);
    z-index: 4;
  }
  .copy-toast.is-on {
    opacity: 1;
    transform: translateY(0);
  }

  /* ── 5. .bar-fill — progress bar that animates from 0 → data-value ─────
     Drop on inner <span> of any progress bar (.hole .bar > span and friends).
     Reads `data-value` (e.g. "72") and animates the inline-size on intersect.
     Color comes from the host (existing .hole .bar > span rules apply). */
  .bar-fill {
    inline-size: 0%;
    transition: inline-size 800ms cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .bar-fill.is-on {
    inline-size: var(--bar-target, 0%);
  }

  /* ── 6. .reveal-stagger — children fade + lift in sequence ─────────────
     JS sets --i on each child. Total stagger ≈ children * 60ms. Color-free. */
  .reveal-stagger > * {
    opacity: 0;
    transform: translateY(6px);
    transition:
      opacity 320ms var(--ease),
      transform 320ms var(--ease);
    transition-delay: calc(60ms * var(--i, 0));
  }
  .reveal-stagger.is-on > * {
    opacity: 1;
    transform: translateY(0);
  }

  /* ── 7. .like-burst — pixel particles + scale pop on click ─────────────
     Default accent is violet. Use .lime for affirmative "spark" feedback.
     Particles are injected by JS as <span class="like-particle"> with
     --dx / --dy and inherit `--accent` from the host button. */
  .like-burst {
    --accent: var(--violet);
    position: relative;
  }
  .like-burst.lime {
    --accent: var(--lime);
  }
  .like-burst.danger {
    --accent: var(--danger);
  }
  .like-burst.is-bursting {
    animation: like-pop 280ms var(--ease) 1;
  }
  @keyframes like-pop {
    0% {
      transform: scale(1);
    }
    40% {
      transform: scale(1.12);
    }
    100% {
      transform: scale(1);
    }
  }
  /* Particles are appended to <body> (not the button) so clip-path on
     hex-notched buttons doesn't erase them before they paint outward. The
     button forwards its --accent via inline style on each particle. */
  .like-particle {
    position: fixed;
    inline-size: 4px;
    block-size: 4px;
    background: var(--accent, var(--violet));
    pointer-events: none;
    image-rendering: pixelated;
    animation: like-fly 480ms cubic-bezier(0.2, 0.7, 0.2, 1) 1 forwards;
    z-index: 9999;
  }
  @keyframes like-fly {
    0% {
      opacity: 1;
      transform: translate(0, 0) scale(1);
    }
    100% {
      opacity: 0;
      transform: translate(var(--dx, 0px), var(--dy, -20px)) scale(0.5);
    }
  }

  /* ── a11y: prefers-reduced-motion ──────────────────────────────────────
     For triggered primitives we want the END state, not nothing — the user
     should still see the revealed content / final count / filled bar. */
  @media (prefers-reduced-motion: reduce) {
    .boot-in {
      opacity: 1;
      transform: none;
      filter: none;
      transition: none;
    }
    .boot-in.is-on {
      animation: none;
    }
    .reveal-stagger > * {
      opacity: 1;
      transform: none;
      transition: none;
    }
    .bar-fill {
      transition: none;
    }
    .copy-flash.is-flashing,
    .like-burst.is-bursting {
      animation: none;
    }
    .like-particle {
      display: none;
    }
    .pixel-hover {
      transition: none;
    }
    .pixel-hover:hover {
      transform: none;
    }
  }
}
