/* ky-show — the Works showcase engine v2 (supersedes ky-hwork).
   ===========================================================================
   Everything structural here is gated on html.ky-show, which ky-show.js
   stamps only on a fine pointer at >=1024px with motion allowed AND only
   while ky-hwork is not running (the js stands down if it sees the old
   engine, so both can never fight over the aside). html.ky-showfx is the
   weaker gate — "the module is alive at all" — and carries the theme
   takeover + canvas entrance, which also run on touch/narrow/reduced
   via IntersectionObserver instead of the lock.

   DOM (all stamped/inserted by ky-show.js, all idempotent):
     .kyv-row    class on the existing grid row (runway)
     .kyv-stage  wrapper around <aside>, taking its grid slot
     .kyv-track  class on <aside> itself
     .kyv-rail   progress hairline inside the stage
     .kyv-on / .kyv-off   active / recessed state on each [data-ky-work] card
     html[data-show-site="atlas|purrhaus|plakat|elara"]  theme takeover
     html[data-exp-axis="h|v"]  layout axis (published by ky-exp packs)

   The class prefix is kyv- on purpose: .kys-* is ky-site.css property
   (its hero/section classes), even though the SKIN VARS here are --kys-*
   per the module contract. The only --kys-* var ky-site uses is --kys-d
   (an element-scoped stagger delay), which this file never touches.

   PER-FRAME WRITES GO TO ELEMENTS, NEVER TO :root — same law ky-hwork
   measured at ~300x cost per root write on this page. The live transform
   is written on .kyv-track directly, --kys-p on .kyv-rail, --kys-roll on
   the number stack. Layout constants live on the elements that need them
   (--kys-card on the stage, --kys-travel on the row), not on :root at all.

   Theme-takeover writes (html[data-show-site]) ARE documentElement writes,
   but they happen only when a slide boundary is crossed — a discrete event,
   explicitly fine. The smoothness comes from transitions on the painted
   properties below, never from animating the vars themselves. */

/* ── the runway ──────────────────────────────────────────────────────────
   --kys-travel is written on the ROW element by measure(), so this rule
   resolves without any :root traffic. */
html.ky-show #Works .kyv-row {
  min-height: calc(100vh + var(--kys-travel, 0px));
  align-items: start;              /* stop the grid stretching the stage */
}

/* ── the pinned window ─────────────────────────────────────────────────── */
html.ky-show #Works .kyv-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;             /* h-axis: cards ride the optical centre */
  overflow: hidden;                /* the clip that makes it a window */
  grid-column: span 7 / span 7;    /* inherits the aside's md:col-span-7 slot */
  /* No backdrop-filter, no filter, no shadow here: this element clips a
     subtree that moves every frame; per-pixel work would be paid all lock. */
}
html.ky-show[data-exp-axis="v"] #Works .kyv-stage {
  align-items: flex-start;         /* v-axis: panes stack from the top */
}

/* While the lock is NOT engaged the wrapper must vanish from layout: a bare
   div in a grid-cols-12 row would otherwise collapse the aside to one column
   on tablets after a resize-out. display:contents makes it transparent. */
html:not(.ky-show) .kyv-stage { display: contents; }
html:not(.ky-show) .kyv-rail  { display: none; }

/* ── the track, axis "h" (default) ─────────────────────────────────────── */
html.ky-show:not([data-exp-axis="v"]) #Works .kyv-track {
  flex-direction: row !important;  /* beats the shipped `flex-col` utility */
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--kys-gap, 40px) !important;
  width: max-content;
  will-change: transform;
  transform: translate3d(0, 0, 0); /* resting state; js owns the live value */
}
/* --kys-card is written on the stage; the cards inherit it from there. */
html.ky-show:not([data-exp-axis="v"]) #Works .kyv-track > * {
  flex: 0 0 auto;
  width: var(--kys-card, 640px);
}

/* ── the track, axis "v" ─────────────────────────────────────────────────
   Full-width vertical panes at their natural height; the stage window slides
   down the stack. No forced card height — the card's aspect-square plate
   already sizes each pane at roughly one viewport. */
html.ky-show[data-exp-axis="v"] #Works .kyv-track {
  flex-direction: column !important;
  flex-wrap: nowrap;
  gap: var(--kys-gap, 40px) !important;
  width: 100%;
  height: max-content;
  will-change: transform;
  transform: translate3d(0, 0, 0);
}
html.ky-show[data-exp-axis="v"] #Works .kyv-track > * {
  flex: 0 0 auto;
  width: 100%;
}

/* ── the numeral ─────────────────────────────────────────────────────────
   The left pane's stack ("1".."4" behind a static "0") — the same channel
   ky-hwork took: an !important rule outranks the React engine's inline
   transform writes, which keep landing harmlessly underneath. --kys-roll is
   written per frame on THIS element, so the invalidation stays in its
   subtree. transition:none kills the shipped transition-all duration-1000,
   which would otherwise lag the spring by a full second — the snap-settle
   lives in ky-show.js's underdamped numeral spring, not in CSS. */
html.ky-show #Works .sticky div.absolute {
  transform: translate3d(0, calc(var(--kys-roll, 0px) * -1), 0) !important;
  transition: none !important;
}

/* Skin hooks for the numeral pane. Defaults reproduce the shipped look
   (text-[22vw], font-weight 400). NOTE from the fonts law: montrealMono has
   no 500 face — if --kys-num-weight is themed for a mono face use 400/700. */
html.ky-show #Works .sticky.top-12 {
  font-size: var(--kys-num-size, 22vw);
  font-weight: var(--kys-num-weight, 400);
  font-family: var(--kys-num-font, inherit);
  font-style: var(--kys-num-style, normal);
  letter-spacing: var(--kys-num-track, normal);
  line-height: var(--kys-num-lh, 0.8);
  color: var(--kys-num-ink, var(--color-secondary-50));
}

/* ── progress rail ───────────────────────────────────────────────────────
   --kys-p is written on .kyv-rail itself; ::after inherits it from its
   originating element, so the per-frame invalidation stays in this node. */
html.ky-show #Works .kyv-rail {
  position: absolute;
  left: var(--kys-rail-inset, 0px);
  right: var(--kys-rail-inset, 0px);
  bottom: var(--kys-rail-pos, max(28px, 6vh));
  height: var(--kys-rail-h, 2px);
  background: color-mix(in srgb,
    var(--kys-rail-c, var(--color-accent-200, #E3AC33)) 22%, transparent);
  border-radius: 2px;
  overflow: hidden;
}
html.ky-show #Works .kyv-rail::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  border-radius: inherit;
  background: var(--kys-rail-c, var(--color-accent-200, #E3AC33));
  transform: scaleX(var(--kys-p, 0));
  transform-origin: 0 50%;
  /* transform only — a width animation here would relayout every frame */
}
/* v-axis: the rail stands upright on the stage's right edge. */
html.ky-show[data-exp-axis="v"] #Works .kyv-rail {
  left: auto;
  right: var(--kys-rail-pos, max(18px, 2vw));
  top: 18vh;
  bottom: 18vh;
  width: var(--kys-rail-h, 2px);
  height: auto;
}
html.ky-show[data-exp-axis="v"] #Works .kyv-rail::after {
  inset: 0 0 auto 0;
  height: 100%;
  width: auto;
  transform: scaleY(var(--kys-p, 0));
  transform-origin: 50% 0;
}

/* ── THEME TAKEOVER (beat 2) ─────────────────────────────────────────────
   Each site's identity, lifted from its art module's own fixed palette:
     atlas    ph-atlas.js     ink #0F2140  accent #2F6EE7  paper #FFFFFF
     purrhaus ph-purrhaus.js  ink #221A14  accent #E0491F  paper #F3E7D3
     plakat   ph-plakat.js    frame #22221E  Klein #1D3FBF  mat #FFFFFF
     elara    ph-elara.js     ink #141310  clay #8A5E20  paper #F4F2ED

   --kys-accL is the accent PRE-LIFTED for >=3:1 on the band ground (the raw
   accents fail on their own inks; plakat's band IS its Klein blue, so its
   text runs on the mat white instead). Verified live by the module QA. */
html.ky-showfx[data-show-site="atlas"] {
  --kys-ink: #0F2140; --kys-acc: #2F6EE7; --kys-accL: #7FA8F0;
  --kys-paper: #FFFFFF; --kys-band: #0F2140; --kys-plate: #FFFFFF;
}
html.ky-showfx[data-show-site="purrhaus"] {
  --kys-ink: #221A14; --kys-acc: #E0491F; --kys-accL: #F0713F;
  --kys-paper: #F3E7D3; --kys-band: #221A14; --kys-plate: #F3E7D3;
}
html.ky-showfx[data-show-site="plakat"] {
  --kys-ink: #22221E; --kys-acc: #1D3FBF; --kys-accL: #FFFFFF;
  --kys-paper: #FFFFFF; --kys-band: #1D3FBF; --kys-plate: #FFFFFF;
}
html.ky-showfx[data-show-site="elara"] {
  --kys-ink: #141310; --kys-acc: #8A5E20; --kys-accL: #C89A55;
  --kys-paper: #F4F2ED; --kys-band: #141310; --kys-plate: #F4F2ED;
}

/* The band re-skins itself by REDEFINING the theming-contract vars scoped to
   the band element only. Every utility inside (bg-[var(--color-secondary-400)]
   is the band's own ground, the plates read secondary-300, the year tag pairs
   50-on-400, headings read accent-400) re-resolves against these, so the
   whole section — cards, tags, numeral pane — inherits the site's identity
   with zero extra selectors, and any future card markup skins itself. */
html.ky-showfx[data-show-site] #Works > .section-padding {
  --color-secondary-400: var(--kys-band);
  --color-secondary-300: var(--kys-plate);
  --color-secondary-50:  color-mix(in srgb, var(--kys-paper) 94%, var(--kys-band));
  --color-secondary-75:  color-mix(in srgb, var(--kys-paper) 80%, var(--kys-band));
  --color-secondary-100: color-mix(in srgb, var(--kys-paper) 66%, var(--kys-band));
  --color-secondary-200: color-mix(in srgb, var(--kys-paper) 88%, var(--kys-band));
  --color-accent-400: var(--kys-accL);
  --color-accent-500: color-mix(in srgb, var(--kys-accL) 82%, var(--kys-paper));
  --color-accent-600: var(--kys-accL);
  --kys-rail-c: var(--kys-accL);
}

/* Page ground follows only while the LOCK is engaged (band >= ~65% of the
   viewport before the attribute ever lands) — in flow mode neighbouring
   sections stay on the active theme, whose text contrast we cannot vouch
   for against a foreign paper. Specificity note: the inline switcher ships
   `html,body{background-color:var(--color-accent-200)!important}`; these
   selectors carry an attribute so they outrank it, same-origin !important. */
html.ky-show[data-show-site],
html.ky-show[data-show-site] body {
  background-color: color-mix(in srgb,
    var(--kys-paper) 70%, var(--color-accent-200)) !important;
}

/* The smoothness: transitions on concrete painted properties, declared while
   the module is alive so the fade runs both into AND out of a takeover.
   transition-property is a closed list of paint props on purpose — the card
   roots (.ky-rv) keep their own opacity/transform entrance transition from
   ky-flow.css, and the heading's letter spans (span.inline-block) are
   excluded because the React engine animates their inline transforms; text
   they merely inherit still fades because the PARENT's color transitions. */
html.ky-showfx,
html.ky-showfx body {
  transition: background-color var(--kys-theme-ms, 720ms) cubic-bezier(.4, 0, .2, 1);
}
html.ky-showfx #Works > .section-padding,
html.ky-showfx #Works .section-padding .custom-cursor-area,
html.ky-showfx #Works .section-padding h1,
html.ky-showfx #Works .section-padding .tag,
html.ky-showfx #Works .section-padding .sticky.top-12,
html.ky-showfx #Works .section-padding span:not(.inline-block) {
  transition-property: background-color, color, border-color;
  transition-duration: var(--kys-theme-ms, 720ms);
  transition-timing-function: cubic-bezier(.4, 0, .2, 1);
}

/* ── CANVAS ENTRANCE (beat 3) ────────────────────────────────────────────
   The active card's media opens from a recessed rest; non-active cards sit
   slightly sunken. Transition-based so it is interruptible mid-flight,
   delayed 180ms behind the numeral snap and the theme fade so the boundary
   reads as three beats, not one blur. transform/opacity/clip-path only.

   The state lands on the slot's .z-10 aspect wrapper, NOT on .ky-media-slot
   itself: ky-flow.js's parallax owns the slot's INLINE transform
   (translateY + scale 1.05, per frame), and an inline write beats any rule —
   measured live: a scale on the slot never applied while .ky-plx was
   active. The wrapper is one level up, untouched by everyone, and already
   overflow-clip rounded-lg, so the clip-path reveal matches its corners. */
html.ky-showfx #Works [data-ky-work] .z-10 {
  will-change: transform;
  transition:
    transform var(--kys-enter-ms, 560ms) cubic-bezier(.22, .9, .24, 1) var(--kys-enter-delay, 180ms),
    opacity   var(--kys-enter-ms, 560ms) ease var(--kys-enter-delay, 180ms),
    clip-path var(--kys-enter-ms, 560ms) cubic-bezier(.22, .9, .24, 1) var(--kys-enter-delay, 180ms);
}
html.ky-showfx #Works [data-ky-work].kyv-off .z-10 {
  transform: scale(var(--kys-rest-scale, 0.94));
  opacity: var(--kys-rest-opacity, 0.55);
  clip-path: inset(3.5% 3.5% 3.5% 3.5% round 12px);
}
html.ky-showfx #Works [data-ky-work].kyv-on .z-10 {
  transform: none;
  opacity: 1;
  clip-path: inset(0 0 0 0 round 8px);   /* matches the wrapper's rounded-lg */
}

/* ── reduced motion ──────────────────────────────────────────────────────
   Static but styled: the takeover colors still land (they are state, not
   motion) but nothing animates, nothing is recessed, and — belt and braces,
   like ky-hwork — if .ky-show is somehow present the lock geometry unwinds
   rather than pinning the user. */
@media (prefers-reduced-motion: reduce) {
  html.ky-showfx,
  html.ky-showfx body,
  html.ky-showfx #Works > .section-padding,
  html.ky-showfx #Works .section-padding .custom-cursor-area,
  html.ky-showfx #Works .section-padding h1,
  html.ky-showfx #Works .section-padding .tag,
  html.ky-showfx #Works .section-padding .sticky.top-12,
  html.ky-showfx #Works .section-padding span:not(.inline-block),
  html.ky-showfx #Works [data-ky-work] .z-10 {
    transition: none !important;
  }
  html.ky-showfx #Works [data-ky-work].kyv-off .z-10 {
    transform: none;
    opacity: 1;
    clip-path: none;
  }
  html.ky-show #Works .kyv-row { min-height: 0; }
  html.ky-show #Works .kyv-stage {
    position: static;
    height: auto;
    overflow: visible;
  }
  html.ky-show #Works .kyv-track {
    flex-direction: column !important;
    width: auto;
    height: auto;
    transform: none;
    will-change: auto;
  }
  html.ky-show #Works .kyv-track > * { width: auto; }
  html.ky-show #Works .kyv-rail { display: none; }
}
