/* ky-motion — scroll-scrubbed motion layer (companion for ky/ky-motion.js).
   Where ky-flow owns ARRIVAL (veil, once-only reveals) this layer owns motion
   LINKED to position and reversible: the reading-ink scrub on the About copy,
   the media-drift law extended to the hero/About portraits, the magnetic CTA
   spring, and the theme flood. House laws hold throughout: scroll-mapped
   values are linear (the parallax precedent), time-based motion uses the
   site's cubic-bezier(.51,.92,.24,1.15), every color is a token with the
   ky-work-style fallback, and only color / opacity / translate / scale ever
   animate. The independent translate/scale properties are used so the site's
   own inline transforms are never contested. z-index <= 12000.

   Known asymmetry, on purpose: ky-flow's Works parallax runs on touch, but
   this module's portrait drift is fine-pointer only (the suite constraint
   wins; drift is near-invisible at phone sizes anyway). */

/* ---- reading-ink scrub -------------------------------------------------------
   ky-motion.js writes inline color as color-mix() over the two tokens, so the
   words re-resolve live under all themes. The short transition softens the
   quantized buckets into an ink-soak instead of visible steps. No color is
   declared here: below the reading line the JS removes the property and the
   site's own resting mix returns untouched. */
.ky-ink-w { transition: color 0.25s ease; }

/* ---- media drift (hero + about portraits) --------------------------------------
   Same law as ky-flow's work cards: <=2.4% translate under an overscan so the
   clip never shows an edge. The overscan lives here as the standalone `scale`
   property; JS only ever writes `translate`. Applied exclusively to an <img>
   inside a verified overflow-clip ancestor — no clip, no class, no effect. */
img.ky-mo-plximg { scale: 1.06; will-change: translate; }

/* ---- magnetic CTAs ------------------------------------------------------------
   The pull/return runs as a JS spring writing the translate property (the
   ky-cursor constants), so NO transition is declared here — a transition
   rule on these buttons would replace the site's own transition stack.
   Press feedback rides the standalone scale property; if the button carries
   the site's transition-all it eases, otherwise it snaps — both acceptable. */
html.ky-mo-fine .ky-mag:active { scale: 0.97; }

/* ---- theme flood ----------------------------------------------------------------
   Poured-ink theme switch: the exact #ky-work-goo overlay pattern (fixed,
   goo-filtered stage, scaling blobs, the house bezier). The blob color is the
   TARGET theme's paper, read from the switcher row's own chip, so this needs
   no palette knowledge of its own. Overlay is pointer-events:none and torn
   down on a hard backstop; reduced-motion never builds it. */
#ky-mo-flood {
  position: fixed; inset: 0;
  z-index: 12000;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}
#ky-mo-flood .ky-mof-stage {
  position: absolute; inset: 0;
  filter: url(#goo);
  will-change: filter;
}
#ky-mo-flood .ky-mof-blob {
  position: absolute; top: 0; left: 0;
  width: 220px; height: 220px;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  will-change: transform;
  transition: transform 0.7s cubic-bezier(0.51, 0.92, 0.24, 1.15);
}

/* ---- reduced motion --------------------------------------------------------------
   JS bails out of every entry point on its own; this block is the ky-flow /
   ky-work belt-and-braces double guard. The un-scrubbed paragraph is a valid
   site-native state (the site itself rests revealed words at the muted mix),
   so nothing here forces ink — the words simply stay the site's own color. */
@media (prefers-reduced-motion: reduce) {
  .ky-ink-w { transition: none; }
  img.ky-mo-plximg { scale: none; will-change: auto; translate: none !important; }
  .ky-mag { translate: none !important; }
  html.ky-mo-fine .ky-mag:active { scale: none; }
  #ky-mo-flood { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE HERO PLACEHOLDER PHOTO — OFF
   ---------------------------------------------------------------------------
   Owner's call: "remove the image on the main landing page, effectively. I
   don't want it. Maybe later we will add it."

   Done in CSS, deliberately, NOT by deleting the markup. index.html is a
   static Next export that React hydrates: removing a node from the shipped
   HTML makes the server markup disagree with what the component renders, and
   React answers a mismatch by recreating the node — so the image would come
   back on hydration and the only lasting result would be one more hydration
   error on a page that already has one. A stylesheet cannot be overruled by
   hydration, and "maybe later we will add it" is one commented-out line away.

   The GRID CELL is hidden, not the <img>, so the column collapses and the
   copy beside it re-centres instead of sitting next to a hole. col-span-4 is
   what distinguishes the hero copy of this photo from the second copy far
   below it in the about band (col-span-3), which is left alone.

   NOTE: /1.webp is still <link rel=preload as=image> in the document head for
   that second copy. It is below the fold and should not be preloaded at all,
   but that is a head edit on the hydrated document and belongs with whatever
   pass finally decides the fate of the about-band photo. */
div.col-span-4:has(> div > div > img[alt="Just an Image."]) { display: none; }

/* …and put the calendar back in the columns the photo used to sit beside.
   ---------------------------------------------------------------------------
   The hero is one grid-cols-12 row holding three auto-placed cells:

     (1) tagline + CONTACT   col-span-12  md:col-span-4   → columns 1–4
     (2) the photo           col-span-4                   → columns 5–8
     (3) calendar + AUG'26   col-span-8   md:col-span-4   → columns 9–12

   None of them declares a start line, so they are placed in DOM order. Taking
   cell (2) out of flow with display:none therefore does not leave a hole where
   the photo was — it slides the calendar 4 columns LEFT into 5–8, stranding it
   mid-page with ~625px of dead amber to its right, which is the layout break
   this rule exists to undo.

   grid-column-end:-1 pins the cell's END to the final column line and lets the
   span resolve backwards from it, so the fix holds at BOTH breakpoints without
   hard-coding a start: span 4 → columns 9–12 on desktop, span 8 → columns 5–12
   below md, each identical to where the cell sat before the photo was hidden.

   Anchored to the same :has() the rule above uses, so if the photo is ever
   restored this override stops matching in the same edit. */
div.grid.grid-cols-12:has(> div.col-span-4 > div > div > img[alt="Just an Image."])
  > div.col-span-8 { grid-column-end: -1; }

/* THEME SWITCHER — drop it out of the header's row.
   ---------------------------------------------------------------------------
   #ky-sw is fixed at top:14px right:14px (inline <style> in the document head).
   The header nav is absolute top-0 and ends at the 40px gutter, so at desktop
   widths the pill's box (right edge 14px from the viewport) reaches back UNDER
   the last nav item and clips "Contact" — visibly, since the pill paints a dark
   plate at z-index 99999 against the nav's z-40.

   Moving it below the 58px header band clears the collision without touching
   the nav, and the panel still opens downward into empty hero space. Only from
   md up: ky/ky-mobile.css already re-places this control on small screens and
   owns that case. */
@media (min-width: 768px) {
  #ky-sw { top: 74px; right: 40px; }
}
