/* ===================================================================
   WILD PIXEL — TEXTURES (LOCKED)
   Locked Apr 21, 2026 from design-exploration/new-concepts/07-atlas.html
   ---
   THE RULE: Paper is the stage. Gradients live ONLY inside rounded
   containers. Each of the six swatches has exactly one job on a page.
   Grain is bounded — it never bleeds past its parent's corner radius.
   =================================================================== */

/* -- Color tokens this file expects to inherit (defined in :root elsewhere) --
   --salmon         #EA5541
   --salmon-soft    #F08573
   --salmon-deep    #C13E2D
   --salmon-glow    #FF6B4F
   --peach          #F5C7B6
   --charcoal       #1E1E1C
   --midnight       #3A3932
   --midnight-deep  #2A2924
   --slate-soft     #C4C4BC
   --stone          #DCDCD0
   --paper          #EEEEE3
   --paper-warm     #EFE8D6
   --white          #FFFFFF
   ----------------------------------------------------------------------- */


/* ===================================================================
   GRAIN — v3 HARD-EDGED
   Binary on/off pixels via discrete feFuncA threshold. Zero blur.
   Bounded to its parent via `border-radius: inherit` — grain never
   escapes the card it lives in.

   Apply to: any element with `position: relative; overflow: hidden;
   border-radius: <radius>;` that already carries a swatch background.
   =================================================================== */

.grain-heavy::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.55' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.85 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
  opacity: 0.85;
  border-radius: inherit;
}

.grain-med::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.45' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.68 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
  opacity: 0.72;
  border-radius: inherit;
}

.grain-light::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.35' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.48 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
  opacity: 0.55;
  border-radius: inherit;
}


/* ===================================================================
   THE SIX SWATCHES — v2 EXTENDED FALLOFFS
   Each swatch = three layered gradients (two radials + one linear).
   Stops sit at 78–95% so color reaches softer before fade.
   Each swatch has ONE job per page — see INDEX.md for the job map.
   =================================================================== */

/* 01 — swatch-warm · "Workshop Warm" · HERO STAT CARD */
.swatch-warm {
  background:
    radial-gradient(ellipse 80% 70% at 25% 30%, var(--salmon-glow) 0%, transparent 82%),
    radial-gradient(ellipse 90% 80% at 78% 78%, var(--peach) 0%, transparent 85%),
    linear-gradient(135deg, var(--paper) 0%, var(--paper-warm) 100%);
  color: var(--charcoal);
}

/* 02 — swatch-fire · "Pure Heat" · ONE-MOMENT salmon accent tile */
.swatch-fire {
  background:
    radial-gradient(ellipse 85% 75% at 25% 30%, var(--salmon-glow) 0%, transparent 85%),
    radial-gradient(ellipse 100% 95% at 80% 80%, var(--salmon-deep) 0%, transparent 90%),
    linear-gradient(135deg, var(--salmon) 0%, var(--salmon-deep) 100%);
  color: var(--paper);
}

/* 03 — swatch-stone · "Soft Foundation" · QUIET AUTHORITY tile */
.swatch-stone {
  background:
    radial-gradient(ellipse 75% 65% at 30% 20%, var(--white) 0%, transparent 82%),
    radial-gradient(ellipse 105% 95% at 80% 90%, var(--paper-warm) 0%, transparent 88%),
    linear-gradient(135deg, var(--stone) 0%, var(--slate-soft) 100%);
  color: var(--charcoal);
}

/* 04 — swatch-cool · "Charcoal Field" · DEPTH / STRATEGY tile */
.swatch-cool {
  background:
    radial-gradient(ellipse 75% 65% at 75% 25%, var(--midnight) 0%, transparent 82%),
    radial-gradient(ellipse 95% 85% at 20% 85%, var(--midnight-deep) 0%, transparent 88%),
    linear-gradient(135deg, var(--charcoal) 0%, var(--midnight) 100%);
  color: var(--paper);
}

/* 05 — swatch-heat · "Foundry" · FEATURED WORK / CINEMATIC tile */
.swatch-heat {
  background:
    radial-gradient(ellipse 70% 60% at 75% 80%, var(--salmon) 0%, transparent 80%),
    radial-gradient(ellipse 85% 75% at 25% 25%, var(--midnight) 0%, transparent 85%),
    linear-gradient(135deg, var(--charcoal) 0%, var(--midnight-deep) 100%);
  color: var(--paper);
}

/* 06 — swatch-bipolar · "Dawn to Dark" · TRANSITION / FINAL CTA */
.swatch-bipolar {
  background:
    radial-gradient(ellipse 70% 75% at 18% 30%, var(--salmon-glow) 0%, transparent 78%),
    radial-gradient(ellipse 85% 85% at 82% 75%, var(--midnight) 0%, transparent 82%),
    linear-gradient(135deg, var(--peach) 0%, var(--charcoal) 100%);
  color: var(--paper);
}


/* ===================================================================
   USAGE PATTERN
   ===================================================================
   <div class="some-card swatch-warm grain-light">
     ...content (must be position: relative + z-index: 2 to sit above grain)...
   </div>

   The card itself MUST have:
     position: relative;
     overflow: hidden;
     border-radius: <e.g. 24px or 14px>;

   Anything inside the card that needs to read above the grain layer:
     position: relative;
     z-index: 2;
   =================================================================== */


/* ===================================================================
   FX BLOOM — "Lagged Drift" (LOCKED Apr 22, 2026)
   ---
   Opt-in cursor interaction. Add `.fx-bloom` to any swatched +
   grained card. A salmon halo follows the cursor with thermal-mass
   lag (lerp 0.10/frame) — the surface feels heated, not chased.

   Mechanism:
     ::before pseudo carries a radial-gradient at (--bloom-lx, --bloom-ly).
     JS writes the lerped position each frame; CSS does the painting.
     mix-blend-mode: screen keeps the halo additive over the swatch
     and underneath the grain. border-radius: inherit keeps it bounded.

   Pseudo stack (paint order):
     ::before  →  bloom (z-index 1)
     ::after   →  grain (already defined; painted after ::before)
     content   →  z-index 2 (must be position: relative)

   Companion JS:
     <script src="textures.js" defer></script>
     Auto-wires every .fx-bloom on the page. Honors prefers-reduced-motion.

   Usage:
     <div class="card swatch-warm grain-light fx-bloom">
       <div class="card-content"> ... </div>
     </div>
   =================================================================== */

.fx-bloom {
  --bloom-lx: 50%;
  --bloom-ly: 50%;
  --bloom-opacity: 0;
}

.fx-bloom::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(
    circle 240px at var(--bloom-lx) var(--bloom-ly),
    rgba(255, 107, 79, 0.55) 0%,
    rgba(255, 107, 79, 0.18) 35%,
    transparent 70%
  );
  mix-blend-mode: screen;
  opacity: var(--bloom-opacity);
  transition: opacity 320ms ease;
  z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
  .fx-bloom::before {
    transition: none;
    opacity: 0 !important;
  }
}


/* ===================================================================
   FX GRAIN WARP — "Smear S2" (LOCKED Apr 23, 2026)
   ---
   Opt-in cursor interaction that warps the grain locally around the
   cursor with a soft trail. Add `.fx-grain-warp` to any swatched +
   grained card; the companion JS injects two SVG layers and wires
   pointer events. The base layer always renders the static binary
   noise. The warp layer renders the same noise through a feTurbulence
   + feDisplacementMap, masked to a 200px circle that lags the cursor.

   Mechanism:
     JS injects `.gw-base` + `.gw-warp` <svg> children into the card.
     Both use the same noise seed so the boundary is invisible at idle.
     JS writes --gw-cx, --gw-cy each frame (lerped position).
     Velocity drives feDisplacementMap scale; decay smooths settle.
     The data-URI ::after grain is suppressed where this class is
     present — the inline SVG layers replace it.

   Pseudo / layer stack (paint order):
     .gw-base   →  static noise (z-index 1)
     .gw-warp   →  warped noise, masked (z-index 2)
     content    →  z-index 3 (must be position: relative)

   Locked tuning (S2 — Medium + Trailing, picked from
   interactions-grain-warp-smear.html):
     baseFreq        0.018       (warpfield turbulence frequency)
     MAX             32          (peak displacement scale)
     VEL gain        0.45        (px/ms velocity → scale gain)
     DECAY           0.92        (per-frame scale multiplier)
     LAG             0.12        (lerp rate; lower = more lag)
     RADIUS          200px       (mask circle radius)

   Companion JS:
     <script src="textures.js" defer></script>
     Auto-wires every .fx-grain-warp on the page. Honors
     prefers-reduced-motion.

   Usage:
     <div class="card swatch-warm grain-heavy fx-grain-warp">
       <div class="card-content"> ... </div>
     </div>
   =================================================================== */

.fx-grain-warp {
  --gw-cx: 50%;
  --gw-cy: 50%;
  --gw-r: 200px;
}

/* When .fx-grain-warp is on, hide the static data-URI grain — the
   inline SVG layers below carry the grain rendering instead. */
.fx-grain-warp.grain-heavy::after,
.fx-grain-warp.grain-med::after,
.fx-grain-warp.grain-light::after {
  display: none;
}

.fx-grain-warp .gw-base,
.fx-grain-warp .gw-warp {
  position: absolute;
  inset: -10px;
  width: calc(100% + 20px);
  height: calc(100% + 20px);
  pointer-events: none;
  border-radius: inherit;
  mix-blend-mode: overlay;
  opacity: 0.85;
}

.fx-grain-warp .gw-base { z-index: 1; }

.fx-grain-warp .gw-warp {
  z-index: 2;
  -webkit-mask-image: radial-gradient(
    circle var(--gw-r) at var(--gw-cx) var(--gw-cy),
    #000 0%,
    #000 35%,
    transparent 100%
  );
          mask-image: radial-gradient(
    circle var(--gw-r) at var(--gw-cx) var(--gw-cy),
    #000 0%,
    #000 35%,
    transparent 100%
  );
}

@media (prefers-reduced-motion: reduce) {
  .fx-grain-warp .gw-warp { display: none; }
}


/* ===================================================================
   WP-STOP — locked spacing rule
   Locked May 2, 2026.

   The Wild Pixel hover-state device (the salmon pixel grid) always sits
   with a small amount of breathing space from the text it accompanies.
   Applies site-wide — every wp-stop on every page.

   Default margin: 16px. Override case-by-case for tighter pairings
   (e.g., the Calibration 2 reference cards) if needed.
   =================================================================== */
.wp-stop {
  margin-left: 16px;
}
@media (max-width: 720px) {
  .wp-stop {
    margin-left: 12px;
  }
}
