/* ============================================================
   ASHBOURNE — Texture, chamfer & motion utilities
   The Y2K / brutalist surface layer: animated grain, blueprint
   grids, notched corners, corner ticks, marquees, scanlines.
   ============================================================ */

/* ---------- Animated grain (the house texture) ----------
   Put .ash-grain on any positioned container. It paints a
   fixed-size noise tile that jitters between 8 steps, so the
   surface feels alive without any element moving. */
.ash-grain { position: relative; }
/* inset:0 (never negative) + background-position jitter: the tile shifts
   without the layer ever extending past its box, so grained containers
   cannot leak horizontal overflow and children are never clipped. */
.ash-grain::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  opacity: 0.22;
  background-repeat: repeat;
  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.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: ashGrain var(--dur-grain) steps(1) infinite;
}
.ash-grain > * { position: relative; z-index: 4; }
.ash-grain-soft::after { opacity: 0.12; }
.ash-grain-heavy::after { opacity: 0.34; }

@keyframes ashGrain {
  0%   { background-position: 0 0; }
  12%  { background-position: -37px 23px; }
  25%  { background-position: 51px -14px; }
  37%  { background-position: -22px -48px; }
  50%  { background-position: 33px 41px; }
  62%  { background-position: -58px 9px; }
  75%  { background-position: 18px -33px; }
  87%  { background-position: -11px 27px; }
  100% { background-position: 0 0; }
}

/* ---------- Blueprint grid ---------- */
.ash-blueprint {
  background-image:
    linear-gradient(var(--border-faint) 1px, transparent 1px),
    linear-gradient(90deg, var(--border-faint) 1px, transparent 1px);
  background-size: 22px 22px;
}
.ash-blueprint-lg { background-size: 48px 48px; }
/* drifting variant */
.ash-blueprint-drift { animation: ashDrift 24s linear infinite; }
@keyframes ashDrift { to { background-position: 22px 22px; } }

/* ---------- Scanlines ---------- */
.ash-scanlines::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.22) 0 1px,
    transparent 1px 3px
  );
  animation: ashScan 8s linear infinite;
}
@keyframes ashScan { to { transform: translateY(3px); } }

/* ---------- Chamfered / notched corners ---------- */
.ash-notch {
  clip-path: polygon(0 0, calc(100% - 22px) 0, 100% 22px, 100% 100%, 22px 100%, 0 calc(100% - 22px));
}
.ash-notch-tr { clip-path: polygon(0 0, calc(100% - 26px) 0, 100% 26px, 100% 100%, 0 100%); }
.ash-notch-br { clip-path: polygon(0 0, 100% 0, 100% calc(100% - 26px), calc(100% - 26px) 100%, 0 100%); }
.ash-notch-bl { clip-path: polygon(0 0, 100% 0, 100% 100%, 26px 100%, 0 calc(100% - 26px)); }
.ash-notch-lg {
  clip-path: polygon(0 0, calc(100% - 56px) 0, 100% 56px, 100% 100%, 56px 100%, 0 calc(100% - 56px));
}

/* ---------- Corner tick marks (+ at panel corners) ---------- */
.ash-ticks { position: relative; }
.ash-ticks::before,
.ash-ticks::after {
  content: "+";
  position: absolute;
  font-family: var(--font-data);
  font-size: 13px;
  line-height: 1;
  color: var(--text-faint);
  pointer-events: none;
}
.ash-ticks::before { top: 5px; left: 6px; }
.ash-ticks::after { bottom: 5px; right: 6px; }

/* ---------- Marquee rails ---------- */
.ash-marquee {
  overflow: hidden;
  white-space: nowrap;
}
.ash-marquee-track {
  display: inline-flex;
  gap: 2ch;
  animation: ashMarquee var(--dur-marquee) linear infinite;
  will-change: transform;
}
@keyframes ashMarquee { to { transform: translateX(-50%); } }
.ash-marquee:hover .ash-marquee-track { animation-play-state: paused; }

/* vertical variant for side rails */
.ash-marquee-v { overflow: hidden; writing-mode: vertical-rl; }
.ash-marquee-v .ash-marquee-track {
  animation-name: ashMarqueeV;
  flex-direction: column;
}
@keyframes ashMarqueeV { to { transform: translateY(-50%); } }

/* ---------- Entrance / attention ----------
   ⚠ These are unguarded CSS entrances: they park on their from-state while the
   document's animation timeline is frozen (a hidden tab, offscreen or preview
   iframe), which means invisible content. For anything load-bearing use the
   motion layer's data-ash-anim="boot|split|stagger" instead — those wait until
   the document can paint. Keep these for ornaments and short-lived overlays. */
.ash-rise { animation: ashRise var(--dur-slow) var(--ease-elastic) both; }
@keyframes ashRise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
/* The wipe reveals left-to-right, then RELEASES the clip. Display faces
   (Newake at leading 0.92) paint above and below their line box, so a
   resting clip of inset(0) shears the caps — the end state is slack. */
.ash-wipe { animation: ashWipe 420ms var(--ease-snap) both; }
@keyframes ashWipe {
  from { clip-path: inset(-0.3em 100% -0.3em -0.15em); }
  to { clip-path: inset(-0.3em -0.15em -0.3em -0.15em); }
}

/* ---------- Display leading guard ----------
   Newake's caps overshoot the line box at display leading. Any clipped,
   masked, or overflow-hidden display line needs that overshoot back:
   .ash-display adds it as padding and removes it again as margin, so
   optical alignment is unchanged but nothing shears. */
.ash-display {
  padding-block: 0.08em 0.04em;
  margin-block: -0.08em -0.04em;
}
.ash-spin { animation: ashSpin var(--dur-spin) linear infinite; }
@keyframes ashSpin { to { transform: rotate(360deg); } }
.ash-blink { animation: ashBlink 1.1s steps(1) infinite; }
@keyframes ashBlink { 50% { opacity: 0; } }

/* stagger helper — set --i on children */
.ash-stagger > * { animation: ashRise var(--dur-slow) var(--ease-elastic) both; animation-delay: calc(var(--i, 0) * 70ms); }

@media (prefers-reduced-motion: reduce) {
  .ash-grain::after,
  .ash-scanlines::before,
  .ash-blueprint-drift,
  .ash-marquee-track,
  .ash-spin,
  .ash-blink { animation: none !important; }
}
