/**
 * Brand wash — structure.
 *
 * A band of colour derived from a brand, with a texture over it. Atmosphere
 * for whatever sits on top: an integration row, a section header, a card.
 *
 * COPY THIS FILE BYTE-IDENTICAL. Colour lives in brand-wash.tokens.css.
 *
 * TWO LAYERS, AND KEEPING THEM SEPARATE IS THE WHOLE DESIGN
 *   1. the gradient — three stops, all brand-derived, all ~90% surface
 *   2. the texture  — GREYSCALE, carrying texture and nothing else
 *
 * Because the texture layer holds no colour, one set of textures serves every
 * brand. There is no tinted asset per client, and swapping a texture never
 * touches a colour or vice versa.
 */

.sp-brand-wash {
  position: relative;
  overflow: hidden;
  padding: var(--sp-brand-wash-pad, 34px);
  border-radius: var(--radius-card, 16px);
  background-color: var(--sp-brand-wash-base, #ffffff);
  /* Three stops, not two. A multicolour mark washes from its own palette —
     Slack's rose, cream and green — and a two-stop gradient throws away the
     middle one, which is the stop doing most of the work. --via falls back to
     --to, so a single-colour brand still renders correctly. */
  background-image:
    radial-gradient(68% 120% at 6% 18%, var(--sp-brand-wash-from, #f1f1ef) 0%, transparent 58%),
    radial-gradient(62% 110% at 50% 100%, var(--sp-brand-wash-via, var(--sp-brand-wash-to, #f6f6f4)) 0%, transparent 60%),
    radial-gradient(80% 130% at 96% 72%, var(--sp-brand-wash-to, #f6f6f4) 0%, transparent 62%),
    linear-gradient(101deg, var(--sp-brand-wash-from, #f1f1ef) 0%, var(--sp-brand-wash-via, transparent) 48%, var(--sp-brand-wash-to, #f6f6f4) 100%);
  isolation: isolate;
}

/* Content is CLOSED on all sides — the band frames what it holds, with equal
   wash visible left and right. It is a contained object, not a slice of
   something wider. */
.sp-brand-wash > * { position: relative; }

/* ── The texture layer ──────────────────────────────────────────────────── */

.sp-brand-wash::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--sp-brand-grain, 0.055);
  mix-blend-mode: var(--sp-brand-grain-blend, multiply);
  background-image: var(--sp-brand-texture, var(--sp-texture-grain));
  background-size: var(--sp-brand-texture-size, auto);
  background-position: var(--sp-brand-texture-position, center);
  background-repeat: var(--sp-brand-texture-repeat, repeat);
}

/* ── The procedural set ─────────────────────────────────────────────────────
   Inline feTurbulence and gradients rather than files: no asset to lose,
   nothing to 404, and resolution-independent in a way a tiled bitmap is not.
   Defined on the element so a host that copies only the two CSS files still
   gets all seven. */
.sp-brand-wash {
  /* Fine photographic grain — the default. */
  --sp-texture-grain: 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.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");

  /* Uncoated paper: the tooth is anisotropic, so the frequency is too. */
  --sp-texture-paper: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9 0.06' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");

  /* Pulp: large slow density variation, the cloudiness in handmade stock. */
  --sp-texture-pulp: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='400' height='400' filter='url(%23n)'/%3E%3C/svg%3E");

  /* Linen weave: two anisotropic turbulences crossed at 90 degrees. */
  --sp-texture-linen: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.02 0.7' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Cfilter id='b'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.7 0.02' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23a)'/%3E%3Crect width='260' height='260' filter='url(%23b)' opacity='0.6'/%3E%3C/svg%3E");

  /* Soft blotches — the cloud layer under a watercolour, blurred hard. */
  --sp-texture-mist: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='500' height='500'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008' numOctaves='3' stitchTiles='stitch'/%3E%3CfeGaussianBlur stdDeviation='6'/%3E%3C/filter%3E%3Crect width='500' height='500' filter='url(%23n)'/%3E%3C/svg%3E");

  /* Print screen. A real halftone is a dot grid on a 45-degree axis, which two
     offset radial gradients give exactly — and no filter can. */
  --sp-texture-halftone:
    radial-gradient(circle at 1px 1px, rgba(0, 0, 0, 0.9) 0.7px, transparent 0.9px),
    radial-gradient(circle at 4px 4px, rgba(0, 0, 0, 0.9) 0.7px, transparent 0.9px);
}

/* Dark: multiply on a dark surface just makes mud, so the procedural set
   screens instead. Scoped per modifier rather than to .sp-brand-wash, so it
   cannot flatten the per-texture values below. */
:root.dark .sp-brand-wash--grain, [data-theme="dark"] .sp-brand-wash--grain,
:root.dark .sp-brand-wash--paper, [data-theme="dark"] .sp-brand-wash--paper,
:root.dark .sp-brand-wash--pulp, [data-theme="dark"] .sp-brand-wash--pulp,
:root.dark .sp-brand-wash--linen, [data-theme="dark"] .sp-brand-wash--linen,
:root.dark .sp-brand-wash--mist, [data-theme="dark"] .sp-brand-wash--mist,
:root.dark .sp-brand-wash--halftone, [data-theme="dark"] .sp-brand-wash--halftone {
  --sp-brand-grain-blend: screen;
}

.sp-brand-wash--grain { --sp-brand-texture: var(--sp-texture-grain); --sp-brand-grain: 0.06; }
.sp-brand-wash--paper { --sp-brand-texture: var(--sp-texture-paper); --sp-brand-grain: 0.08; }
.sp-brand-wash--linen { --sp-brand-texture: var(--sp-texture-linen); --sp-brand-grain: 0.07; }

/* The two large-scale textures are scaled DOWN rather than left at their native
   tile. A band is ~60px tall; a 400px cloud crossing it shows one smooth slice
   and reads as a flat tint, which is the opposite of the point. */
.sp-brand-wash--pulp {
  --sp-brand-texture: var(--sp-texture-pulp);
  --sp-brand-texture-size: 190px;
  --sp-brand-grain: 0.2;
}
.sp-brand-wash--mist {
  --sp-brand-texture: var(--sp-texture-mist);
  --sp-brand-texture-size: 230px;
  --sp-brand-grain: 0.28;
}
.sp-brand-wash--halftone {
  --sp-brand-texture: var(--sp-texture-halftone);
  --sp-brand-texture-size: 6px 6px;
  --sp-brand-grain: 0.09;
}

/* ── The raster set ─────────────────────────────────────────────────────────
   The organic surfaces feTurbulence cannot fake — a real background rather
   than a field of noise: pigment pooling into a tide-line, cloud, the mineral
   drift in a stone slab. Generated with Nano Banana Pro, then baked and gated
   by scripts/texture-bake.mjs. Greyscale JPEGs, 12-47KB each,
   scaled to fill rather than tiled — a visible repeat is the one thing that
   gives a photographed surface away.

   OPT-IN: nothing loads unless you add one of these classes, so a project that
   only uses the procedural set pays nothing.

   Paths are relative to this stylesheet, so the textures/ folder must be
   copied next to it — `cp -R`, not a flattening `cp`, or every one 404s and
   the band silently loses its texture. */
.sp-brand-wash--photo,
.sp-brand-wash--crackle,
.sp-brand-wash--stucco,
.sp-brand-wash--granite,
.sp-brand-wash--felt,
.sp-brand-wash--washi,
.sp-brand-wash--watercolour,
.sp-brand-wash--riso {
  /* TILED, not `cover`. A band is ~800x114; `cover` scales a 600px square to
     800x800 and shows a 14% slice of it, which magnifies every feature about
     seven times and turns a dense texture into a smooth blur. Tiling at ~300px
     renders the texture near its intended scale, and at that fineness the seam
     is not findable — which is exactly the trade a coarse texture cannot make. */
  --sp-brand-texture-size: 300px;
  --sp-brand-texture-repeat: repeat;
  --sp-brand-grain: 0.62;
  --sp-brand-grain-blend: multiply;
}

.sp-brand-wash--crackle { --sp-brand-texture: url("textures/crackle.jpg"); --sp-brand-grain: 0.8; }
.sp-brand-wash--stucco { --sp-brand-texture: url("textures/stucco.jpg"); --sp-brand-grain: 0.75; }
.sp-brand-wash--granite { --sp-brand-texture: url("textures/granite.jpg"); --sp-brand-grain: 0.7; }
.sp-brand-wash--felt { --sp-brand-texture: url("textures/felt.jpg"); --sp-brand-grain: 0.7; }
.sp-brand-wash--washi { --sp-brand-texture: url("textures/washi.jpg"); --sp-brand-grain: 0.75; }
.sp-brand-wash--watercolour { --sp-brand-texture: url("textures/watercolour.jpg"); --sp-brand-grain: 0.62; }
.sp-brand-wash--riso { --sp-brand-texture: url("textures/riso.jpg"); --sp-brand-grain: 0.6; }

/* Dark inverts the blend, it does not just lower the opacity.
   Every texture here is high key — around 90% white — and multiplying a nearly
   white layer over a dark band is very close to a no-op: on dark the textures
   simply vanished. Screen is the correct operator, because on dark it is the
   texture's LIGHT areas that have to do the work. The opacity comes right down
   to compensate, since screening a near-white layer blows out fast. */
:root.dark .sp-brand-wash--photo, [data-theme="dark"] .sp-brand-wash--photo,
:root.dark .sp-brand-wash--crackle, [data-theme="dark"] .sp-brand-wash--crackle,
:root.dark .sp-brand-wash--stucco, [data-theme="dark"] .sp-brand-wash--stucco,
:root.dark .sp-brand-wash--granite, [data-theme="dark"] .sp-brand-wash--granite,
:root.dark .sp-brand-wash--felt, [data-theme="dark"] .sp-brand-wash--felt,
:root.dark .sp-brand-wash--washi, [data-theme="dark"] .sp-brand-wash--washi,
:root.dark .sp-brand-wash--watercolour, [data-theme="dark"] .sp-brand-wash--watercolour,
:root.dark .sp-brand-wash--riso, [data-theme="dark"] .sp-brand-wash--riso {
  --sp-brand-grain-blend: screen;
  /* Read off a ladder rendered in the browser, not guessed: below ~0.18 the
     texture does not register, and above ~0.34 the screened layer lifts the
     band far enough that it stops reading as dark at all. */
  --sp-brand-grain: 0.24;
}

/* Shapes. A band is the default; these are the other two things it gets used
   as often enough to name. */
.sp-brand-wash--panel { border-radius: var(--radius-panel, 24px); --sp-brand-wash-pad: 44px; }
.sp-brand-wash--flush { border-radius: 0; }
.sp-brand-wash--tight { --sp-brand-wash-pad: 14px; }

@media (prefers-reduced-transparency: reduce) {
  .sp-brand-wash::before { opacity: 0; }
}
