/* shared/texture.css — Export D texture pass.
   Faded backdrop banners + the micro-animation layer. Everything here is
   transform/opacity only, self-hosted (no external assets), attention-caused
   wherever the framework demands it, and fully disabled under
   prefers-reduced-motion (see the block at the end). */

/* ---- 1. Backdrop banner: faded image, gradient to ground going down ---- */
.page-backdrop {
  position: absolute; top: 0; left: 0; right: 0;
  height: min(74vh, 720px);
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.page-backdrop .bg {
  position: absolute; inset: -4%;
  background-size: cover;
  background-position: center 32%;
  opacity: 0.20;
  will-change: transform;
  transition: opacity 1.6s ease;
}
.page-backdrop.bg-grey .bg { filter: grayscale(1) contrast(0.9) brightness(0.8); }
.page-backdrop::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--ground) 42%, transparent) 0%,
    color-mix(in srgb, var(--ground) 62%, transparent) 38%,
    var(--ground) 96%);
}
.page-backdrop.is-loading .bg { opacity: 0; }

/* ---- 4. Cursor light: the one light, made literal ---- */
.cursor-light {
  position: fixed; left: 0; top: 0; z-index: 980;
  width: 240px; height: 240px;
  margin: -120px 0 0 -120px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--room-temp, var(--ink-dim)) 10%, transparent) 0%,
    transparent 62%);
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity .6s ease;
  will-change: transform;
}
body.has-pointer .cursor-light { opacity: 1; }
.cursor-light.is-interactive { transform: scale(1.35); }

/* ---- 6. Frame tilt (JS drives --tx/--ty) + hover lift ---- */
.frame {
  transform: perspective(900px) rotateX(var(--ty, 0deg)) rotateY(var(--tx, 0deg));
  transition: box-shadow .5s ease;
  will-change: transform;
}
.frame.is-lit { box-shadow: 0 14px 44px rgba(0, 0, 0, 0.45); }

/* ---- 9. Sheen radius follows pointer velocity (JS sets --sheen-r) ---- */
.frame .sheen {
  background: radial-gradient(circle var(--sheen-r, 260px) at var(--lx, 50%) var(--ly, 50%),
              color-mix(in srgb, var(--room-temp) 22%, transparent), transparent 70%);
}

/* ---- 10. Captions answer their frame's attention ---- */
.caption {
  transition: color .7s ease, transform .7s ease;
  transform: translateY(2px);
}
.cell-attended .caption, .frame.is-attended ~ .caption {
  color: var(--ink);
  transform: translateY(0);
}

/* ---- 11. Scroll reveal: sections arrive as you reach them ---- */
.tx-reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .9s ease, transform .9s cubic-bezier(.22, .61, .36, 1);
  transition-delay: var(--tx-delay, 0ms);
}
.tx-reveal.is-inview { opacity: 1; transform: none; }

/* ---- 12. Hero heading: letter-spacing eases open under the cursor ---- */
.type-hero { transition: letter-spacing 1.2s cubic-bezier(.22,.61,.36,1), text-shadow 1.2s ease; }
.type-hero.is-lit {
  letter-spacing: 0.035em;
  text-shadow: 0 0 32px color-mix(in srgb, var(--room-temp, var(--ink-dim)) 28%, transparent);
}

/* ---- 13. Overview icon squares: stagger pulse on hover ---- */
.chrome-overview rect { transition: fill .3s, transform .35s ease; transform-origin: center; }
.chrome-overview:hover rect { transform: scale(0.82); }
.chrome-overview:hover rect:nth-child(1) { transition-delay: 0ms; }
.chrome-overview:hover rect:nth-child(2) { transition-delay: 50ms; }
.chrome-overview:hover rect:nth-child(3) { transition-delay: 100ms; }
.chrome-overview:hover rect:nth-child(4) { transition-delay: 150ms; }

/* ---- 14. Overview panel cards: staggered arrival ---- */
.ovl-card { opacity: 0; transform: translateY(14px); transition: opacity .5s ease, transform .5s ease; }
.ovl.is-open .ovl-card { opacity: 1; transform: none; }

/* ---- 15. Scroll progress hairline, room-tinted ---- */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 2px; width: 0;
  background: color-mix(in srgb, var(--room-temp, var(--ink-dim)) 70%, transparent);
  z-index: 995; pointer-events: none;
  transition: opacity .4s ease;
}

/* ---- 5/6. Magnetic chrome dots + ripple ---- */
.chrome-dot { transition: background .3s, border-color .3s, transform .25s ease; will-change: transform; }
.tx-ripple {
  position: absolute; border-radius: 50%; pointer-events: none;
  border: 1px solid var(--room-temp, var(--ink-dim));
  opacity: .7;
  animation: tx-ripple .6s ease-out forwards;
}
@keyframes tx-ripple {
  from { transform: scale(0.4); opacity: .7; }
  to   { transform: scale(2.6); opacity: 0; }
}

/* ---- 7. Text links: underline draws in ---- */
.home-foot a, .room-aside a, .print-cta, .cv-link {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 0% 1px;
  background-position: 0 100%;
  transition: background-size .45s cubic-bezier(.22,.61,.36,1), color .3s;
  border-bottom-color: transparent;
}
.home-foot a:hover, .room-aside a:hover { background-size: 100% 1px; }

/* ---- 16. Sound toggle: gentle pulse while unmuted ---- */
.frame .sound.is-on { animation: tx-sound 2.4s ease-in-out infinite; }
@keyframes tx-sound {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--room-temp) 34%, transparent); }
  50%      { box-shadow: 0 0 0 7px transparent; }
}

/* ---- 17. Press feedback everywhere clickable ---- */
a:active, button:active, .chrome-dot:active, .overview-toggle:active { transform: scale(0.97); }

/* ---- 18. Images fade in as they load ---- */
img.tx-loading { opacity: 0; }
img { transition: opacity .7s ease; }

/* ---- 19. Film grain: generated at runtime, zero external assets ---- */
.tx-grain {
  position: fixed; inset: -60px; z-index: 990;
  pointer-events: none;
  opacity: 0.028;
  animation: tx-grain 0.9s steps(3) infinite;
  will-change: transform;
}
@keyframes tx-grain {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-28px, 16px); }
  66%  { transform: translate(18px, -24px); }
  100% { transform: translate(0, 0); }
}

/* ---- 20. Numbers strip: staggered slide-in on first view ---- */
.numbers span { opacity: 0; transform: translateX(18px); transition: opacity .8s ease, transform .8s ease; }
.numbers.is-inview span { opacity: 1; transform: none; }
.numbers.is-inview span:nth-child(1) { transition-delay: 0ms; }
.numbers.is-inview span:nth-child(2) { transition-delay: 90ms; }
.numbers.is-inview span:nth-child(3) { transition-delay: 180ms; }
.numbers.is-inview span:nth-child(4) { transition-delay: 270ms; }
.numbers.is-inview span:nth-child(5) { transition-delay: 360ms; }
.numbers.is-inview span:nth-child(6) { transition-delay: 450ms; }
.numbers.is-inview span:nth-child(7) { transition-delay: 540ms; }

/* ---- 21. Room-entry thumbnails: two depths under the pointer ---- */
.room-entry .pics img { will-change: transform; }
.room-entry .pics img:nth-child(1) { transform: translate(calc(var(--par-x, 0) * 6px), calc(var(--par-y, 0) * 4px)); }
.room-entry .pics img:nth-child(2) { transform: translate(calc(var(--par-x, 0) * 12px), calc(var(--par-y, 0) * 8px)); }
.room-entry:hover .pics img:nth-child(1) { transform: translate(calc(var(--par-x, 0) * 6px), calc(var(--par-y, 0) * 4px)) scale(1.02); }
.room-entry:hover .pics img:nth-child(2) { transform: translate(calc(var(--par-x, 0) * 12px), calc(var(--par-y, 0) * 8px)) scale(1.02); }

/* ---- 22. Smooth anchor travel ---- */
html { scroll-behavior: smooth; }

/* ---- 23. Focus ring lands with a single pulse ---- */
:focus-visible { animation: tx-focus .5s ease-out; }
@keyframes tx-focus {
  from { outline-offset: 8px; }
  to   { outline-offset: 3px; }
}

/* ---- 24. CV / venue rows: temp rule grows on hover ---- */
.cv-row, .venue { position: relative; transition: padding-left .4s cubic-bezier(.22,.61,.36,1); }
.cv-row::before, .venue::before {
  content: ""; position: absolute; left: 0; top: 14px; bottom: 14px; width: 2px;
  background: var(--room-temp, var(--ink-dim));
  transform: scaleY(0);
  transform-origin: top;
  transition: transform .4s cubic-bezier(.22,.61,.36,1);
}
.cv-row:hover, .venue:hover { padding-left: 16px; }
.cv-row:hover::before, .venue:hover::before { transform: scaleY(1); }

/* ---- 25. Page header: staggered fade-up on arrival ---- */
.tx-arrive { opacity: 0; transform: translateY(14px); animation: tx-arrive .8s cubic-bezier(.22,.61,.36,1) forwards; animation-delay: var(--tx-delay, 0ms); }
@keyframes tx-arrive { to { opacity: 1; transform: none; } }

/* ---- 26. Work-title year/medium brightens when its work is attended ---- */
.work .type-meta { transition: color .6s ease; }
.work.is-settled .type-meta, .work:hover .work-title-row .type-meta { color: var(--ink); }

/* ---- Small screens: shorter banner, no cursor-light, calmer tilt ---- */
@media (max-width: 640px) {
  .page-backdrop { height: min(52vh, 420px); }
  .cursor-light { display: none; }
}
@media (pointer: coarse) {
  .cursor-light { display: none; }
  .frame { transform: none; }
}

/* ---- Reduced motion: the texture layer stands down ---- */
@media (prefers-reduced-motion: reduce) {
  .page-backdrop .bg { transition: none; }
  .cursor-light, .tx-grain, .scroll-progress { display: none !important; }
  .frame { transform: none !important; }
  .tx-reveal, .numbers span, .ovl-card, .tx-arrive { opacity: 1 !important; transform: none !important; animation: none !important; }
  html { scroll-behavior: auto; }
  .frame .sound.is-on { animation: none; }
}
