/* ==========================================================================
   Motion layer (on top of the page's own styles in index.html)
   - Liquid gradient: WebGL flowing mesh gradient behind the hero and contact.
     The CSS aurora blobs stay as the fallback when WebGL or motion is off.
   - Spotlight cards: light + iridescent edge that follows the pointer.
   - Tilt + sheen on project frames, smooth scroll (Lenis) on desktop.
   Patterns after 21st.dev's Aurora shader / Spotlight Card, ported to vanilla.
   ========================================================================== */

/* ── Liquid gradient canvas ──────────────────────────────────────────── */
.lg-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 1.6s cubic-bezier(.22, 1, .36, 1); }
.lg-on > .lg-canvas { opacity: 1; }
.aurora.lg-on > i, .contact .glow.lg-on > i { display: none; }
.contact .glow .lg-canvas { mix-blend-mode: screen; }

/* ── Spotlight cards ─────────────────────────────────────────────────── */
.spot { --mx: 50%; --my: 50%; }
.spot::before, .spot::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .5s cubic-bezier(.22, 1, .36, 1); }
/* soft light under the pointer */
.spot::after { z-index: 0; background: radial-gradient(340px circle at var(--mx) var(--my), rgba(0, 0, 0, .05), rgba(0, 0, 0, .02) 40%, transparent 70%); }
/* iridescent edge ring (only where the card has a rounded box) */
.spot.ring::before { z-index: 1; padding: 1px;
  background: radial-gradient(240px circle at var(--mx) var(--my), var(--c3), var(--c2) 35%, var(--c1) 55%, transparent 75%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0); }
.spot.lit::before, .spot.lit::after { opacity: 1; }
.spot > * { position: relative; z-index: 1; }
.step.spot > .bar-line { position: absolute; }

/* ── Tilt + sheen on project frames ──────────────────────────────────── */
.tilt { transition: transform .8s cubic-bezier(.22, 1, .36, 1), box-shadow .8s cubic-bezier(.22, 1, .36, 1); }
.tilt.tilting { transform: translateY(-4px); }
.tilt .sheen { position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: 0; transition: opacity .5s;
  background: radial-gradient(520px circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, .12), transparent 50%); }
.tilt.tilting .sheen { opacity: 1; }

/* ── Smooth scroll (Lenis) ───────────────────────────────────────────── */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: clip; }
.lenis.lenis-smooth iframe { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .lg-canvas { display: none; }
  .aurora.lg-on > i, .contact .glow.lg-on > i { display: block; }
  .spot::before, .spot::after, .tilt .sheen { display: none; }
  .tilt { transform: none !important; }
}

/* ── Whole-page background (opt-in: <div class="bg-liquid" aria-hidden="true"></div> first in <body>) ──
   Static dark gradient first; motion.js cross-fades the WebGL flow in on the first interaction. */
.bg-liquid { position: fixed; left: 0; top: 0; width: 100%; height: 100vh; height: 100lvh; z-index: -1; pointer-events: none; overflow: hidden;
  background:
    radial-gradient(60vmax 50vmax at 12% 8%, color-mix(in srgb, var(--c3) 22%, transparent), transparent 70%),
    radial-gradient(55vmax 45vmax at 88% 30%, color-mix(in srgb, var(--c4) 18%, transparent), transparent 70%),
    radial-gradient(50vmax 40vmax at 30% 95%, color-mix(in srgb, var(--c2) 14%, transparent), transparent 70%),
    var(--night, #0f0f0e); }
.bg-liquid .lg-canvas { mix-blend-mode: normal; }

/* ── Buttons: calm premium hover (replaces the magnetic follow + circle fill) ──
   No movement toward the cursor. The label rolls up letter by letter, the arrow
   glides along its own direction, and the surface brightens with a soft glow. */
.btn.magnetic { transform: none !important; }
.btn::before { display: none !important; }
.btn, .btn.magnetic { transition: background-color .5s cubic-bezier(.22, 1, .36, 1), border-color .5s cubic-bezier(.22, 1, .36, 1), box-shadow .6s cubic-bezier(.22, 1, .36, 1), scale .3s cubic-bezier(.22, 1, .36, 1) !important; }
.btn:active { scale: .97; }
.btn:focus-visible { outline: 2px solid var(--focus, var(--accent, var(--ink, #fafafa))); outline-offset: 3px; }
.roll { position: relative; display: inline-block; vertical-align: top; overflow: hidden; line-height: 1.25; padding: 0 .02em; }
.roll > span { display: inline-block; white-space: pre; }
.roll > span + span { position: absolute; left: .02em; top: 100%; }
.roll i { font-style: normal; display: inline-block; transition: transform .55s cubic-bezier(.65, 0, .15, 1); transition-delay: calc(var(--i, 0) * 14ms); }
/* soft light sweep across filled buttons */
.btn-dark::after, .btn-light::after { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; border-radius: inherit;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, .55) 48%, transparent 66%); background-size: 250% 100%; background-position: 130% 0; opacity: 0; }
html:not([data-theme="light"]) .btn-dark::after, html:not([data-theme="light"]) .btn-light::after { background-image: linear-gradient(110deg, transparent 30%, rgba(0, 0, 0, .09) 48%, transparent 66%); }
.btn svg.arr-down { transition: transform .5s cubic-bezier(.22, 1, .36, 1); }

@media (hover: hover) and (pointer: fine) {
  .btn:hover .roll i { transform: translateY(-100%); }
  .btn-dark:hover::after, .btn-light:hover::after { opacity: 1; background-position: -30% 0; transition: background-position 1s cubic-bezier(.22, 1, .36, 1), opacity .2s; }
  .btn-dark:hover, .btn-light:hover { box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink, #fafafa) 9%, transparent), 0 14px 34px -14px color-mix(in srgb, var(--ink, #fafafa) 45%, transparent); }
  .btn-line:hover { color: var(--ink) !important; border-color: color-mix(in srgb, var(--ink, #fafafa) 55%, transparent); background-color: color-mix(in srgb, var(--ink, #fafafa) 6%, transparent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink, #fafafa) 5%, transparent); }
  .btn-dark:hover { color: var(--bg) !important; }
  .btn:hover svg.arr-down { transform: translateY(3px); }
}
@media (prefers-reduced-motion: reduce) {
  .roll i { transition: none; }
  .btn:hover .roll i { transform: none; }
  .btn::after { display: none; }
}

/* No tilting anywhere: service icons and the logo stay level and readable on hover */
.svc .ico, .svc:hover .ico { rotate: none; }
.svc:hover .ico svg { color: var(--ink, #fafafa); }
.logo .mark, .logo:hover .mark { transform: none !important; rotate: none; }

/* ── Opening intro: the K tile appears, "kaydaweb" types itself with the brand cursor,
   then a curtain lifts. Gone by ~0.9 s.
   Hook: the head script adds html.intro once per browser session (never with reduced motion),
   and <div class="intro-ov"> sits first in <body>. Pure CSS: it finishes even if JS fails,
   and the page renders underneath the whole time (nothing is hidden from Google). */
.intro-ov { display: none; }
html.intro .intro-ov { display: grid; place-items: center; position: fixed; inset: 0; z-index: 10000; pointer-events: none;
  background: var(--lg-bg, var(--bg, #03090f)); clip-path: inset(0 0 0 0);
  animation: io-lift .38s cubic-bezier(.76, 0, .24, 1) .52s forwards; }
.intro-ov .in { display: flex; align-items: center; gap: 14px; animation: io-in-out .26s cubic-bezier(.65, 0, .35, 1) .5s forwards; }
.intro-ov .im { width: 48px; height: 48px; display: block; animation: io-mark .34s cubic-bezier(.22, 1, .36, 1) both; }
.intro-ov .im svg { width: 100%; height: 100%; display: block; }
.intro-ov .im .t { fill: var(--ink, #fafafa); }
.intro-ov .im .k { fill: var(--bg, #03090f); }
.intro-ov .im .cur, .intro-ov .ic { fill: var(--blue, #5fa3c0); background: var(--blue, #5fa3c0); }
.intro-ov .im .k { transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(0); animation: io-rise .26s cubic-bezier(.22, 1, .36, 1) .06s forwards; }
.intro-ov .im .cur { transform-box: fill-box; opacity: 0; transform: translateX(45%); animation: io-slide .24s cubic-bezier(.22, 1, .36, 1) .24s forwards; }
@keyframes io-rise { to { transform: scaleY(1); } }
@keyframes io-slide { to { opacity: 1; transform: none; } }
.intro-ov .iw { display: inline-flex; align-items: baseline; color: var(--ink, #fafafa); font-size: 1.9rem; font-weight: 600; letter-spacing: -.045em; line-height: 1; }
.intro-ov .iw i { font-style: normal; display: inline-block; overflow: hidden; max-width: 0; animation: io-type .01s linear calc(.1s + var(--i) * .045s) forwards; }
.intro-ov .ic { display: inline-block; width: .44em; height: .74em; margin-left: .08em; align-self: center; animation: io-blink .3s steps(1) .45s infinite; }
@keyframes io-mark { from { opacity: 0; transform: scale(.82); } }
@keyframes io-type { to { max-width: 1em; } }
@keyframes io-blink { 50% { opacity: 0; } }
@keyframes io-in-out { to { opacity: 0; transform: translateY(-12px); } }
@keyframes io-lift { to { clip-path: inset(0 0 100% 0); visibility: hidden; } }
/* v7 "Firma" wordmark intro: markup is <div class="in"><svg class="wm-intro" …> (the header's
   wordmark SVG: 1st path "kayda", 2nd path "web"). "kayda" wipes in left to right, then the italic
   "web" rises 6px and fades in; the curtain lifts at ~1s, everything is gone by ~1.35s. */
.intro-ov .wm-intro { display: block; height: 64px; width: auto; color: var(--ink, #fafafa); overflow: visible; }
.intro-ov .wm-intro path:first-of-type { clip-path: inset(-10% 100% -10% 0); animation: io-wipe .5s cubic-bezier(.65, 0, .35, 1) .08s forwards; }
.intro-ov .wm-intro path:last-of-type { opacity: 0; transform: translateY(6px); animation: io-up .4s cubic-bezier(.22, 1, .36, 1) .48s forwards; }
html.intro .intro-ov:has(.wm-intro) { animation-delay: .98s; }
.intro-ov:has(.wm-intro) .in { animation-delay: .92s; }
@media (max-width: 640px) { .intro-ov .wm-intro { height: 48px; } }
@keyframes io-wipe { to { clip-path: inset(-10% -2% -10% 0); } }
@keyframes io-up { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { html.intro .intro-ov { display: none; } }

/* ── Phone-only motion (touch screens have no hover) ──────────────────────
   1. "Scroll hover": the card crossing the middle of the screen gets the same
      highlight a mouse would give it (motion.js adds .is-center).
   2. Tap feedback: everything tappable presses in slightly.
   3. The main call to action catches a soft light sweep every few seconds. */
@media (hover: none), (pointer: coarse) {
  .work .shot, .work .frame, .work .view img, .svc .ico, .step, .next { transition-duration: .7s; }
  .work.is-center .shot { transform: translateY(-6px); }
  .work.is-center .frame { box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink, #fafafa) 18%, transparent), 0 40px 70px -40px rgba(0, 0, 0, .8); }
  .work.is-center .view img.alt { opacity: 1; }
  .js .work.in.is-center .view img { transform: scale(1.025); }
  .works-cards .work.is-center { box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink, #fafafa) 22%, transparent); }
  .works-cards .work.is-center .info .go svg { transform: translate(2px, -2px); }
  .svc.is-center .ico { transform: translateY(-3px); color: var(--ink); box-shadow: 0 0 0 1px color-mix(in srgb, var(--blue, #5fa3c0) 70%, transparent), 0 14px 34px -12px color-mix(in srgb, var(--blue, #5fa3c0) 60%, transparent); }
  .step.is-center { transform: translateY(-6px); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink, #fafafa) 22%, transparent), 0 30px 60px -36px rgba(0, 0, 0, .8); }
  .next.is-center .next-go svg { transform: translateX(6px); }

  .btn, .work, .svc, .step, .next, .gauge, .rows a { -webkit-tap-highlight-color: transparent; }
  .btn:active, .work:active, .svc:active, .step:active, .next:active, .gauge:active, .rows a:active { scale: .975; transition: scale .12s ease-out; }

  .hero .btn-dark::after { animation: cta-sweep 4.8s cubic-bezier(.22, 1, .36, 1) 2.2s infinite; }
  @keyframes cta-sweep { 0% { opacity: 1; background-position: 130% 0; } 22%, 100% { opacity: 1; background-position: -30% 0; } }
}
@media (prefers-reduced-motion: reduce) {
  .work.is-center .shot, .step.is-center, .svc.is-center .ico { transform: none; }
  .hero .btn-dark::after { animation: none; }
}

/* No tilts anywhere (Vitalii): keep the hero's featured-project card level */
.js.ready .hero-peek.fade { transform: none !important; }
.hero-peek:hover .pk-frame { transform: translateY(-6px) !important; }

/* Whole-page background: "Oceanic Shimmer" (Vitalii's 21st.dev gradient, pure CSS), made truly dark.
   Same four soft horizontal ocean-blue bands and grain, but dimmed to a near-black navy so the dark
   theme reads as dark and white text has strong contrast. Light theme = the original light version.
   Visible motion: the gradient field itself flows. One more full-screen set of the same wide bands
   (::before, 8s) drifts and cross-fades over the base; the light waves come from the canvas in motion.js
   (a second ::after layer was dropped for frame rate). No spots, orbs or sweeping highlights (Vitalii). Transform/opacity only. Nothing follows
   the cursor. */
html:not([data-theme="light"]) body .bg-liquid { background-color: #020710;
  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='.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.07'/%3E%3C/svg%3E"), radial-gradient(150% 48.4% at 41.58% 6%, rgba(34,54,78,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 42.42% 33%, rgba(18,42,64,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 51.19% 67%, rgba(10,30,56,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 53.67% 94%, rgba(4,14,30,.92) 0%, rgba(0,0,0,0) 53%);
  background-size: 140px 140px, auto, auto, auto, auto; }
:root[data-theme="light"] body .bg-liquid { background-color: #e4eef5;
  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='.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.07'/%3E%3C/svg%3E"), radial-gradient(150% 48.4% at 41.58% 6%, rgba(255,255,255,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 42.42% 33%, rgba(214,235,245,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 51.19% 67%, rgba(180,211,234,.92) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 53.67% 94%, rgba(196,217,234,.92) 0%, rgba(0,0,0,0) 53%);
  background-size: 140px 140px, auto, auto, auto, auto; }
.bg-liquid::before { content: ""; position: absolute; pointer-events: none; will-change: transform, opacity; }
.bg-liquid::after { content: none; }
.bg-liquid::before {
  inset: -16% -12%;
  background-image: radial-gradient(150% 48.4% at 58% 12%, rgba(46,76,106,.9) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 36% 41%, rgba(22,58,88,.9) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 60% 72%, rgba(14,42,76,.9) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 44% 98%, rgba(5,16,34,.8) 0%, rgba(0,0,0,0) 53%);
  animation: oc-drift 8s ease-in-out infinite alternate;
}
:root[data-theme="light"] .bg-liquid::before { background-image: radial-gradient(150% 48.4% at 58% 12%, rgba(255,255,255,.85) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 36% 41%, rgba(178,212,236,.9) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 60% 72%, rgba(160,198,230,.9) 0%, rgba(0,0,0,0) 53%),
    radial-gradient(150% 48.4% at 44% 98%, rgba(206,224,238,.85) 0%, rgba(0,0,0,0) 53%); }
@keyframes oc-drift {
  0%   { opacity: .15; transform: translate3d(-5%, -9%, 0) rotate(-2deg) scale(1); }
  50%  { opacity: 1;   transform: translate3d(4%, 0, 0) rotate(1deg) scale(1.08); }
  100% { opacity: .35; transform: translate3d(-3%, 9%, 0) rotate(2deg) scale(1.02); }
}
/* Reduced motion: index.html stops every animation there; the background keeps a calmer drift
   (Vitalii's Mac may have "Reduce motion" on, and he wants to see it move) */
@media (prefers-reduced-motion: reduce) {
  html body .bg-liquid::before { animation: oc-drift 14s ease-in-out infinite alternate !important; }
}

/* Vitalii does not want anything following the cursor: no glow, no custom cursor ball, no light on cards */
.bg-cur, .cursor { display: none !important; }
html, body { cursor: auto; }
.spot::after, .spot.spot::after, .frame .sheen { display: none !important; }

/* The CSS page background replaces the old hero aurora and contact glow (they used to hide under the shader) */
.bg-liquid ~ main .aurora, .bg-liquid ~ * .aurora, html:not([data-theme="light"]) .bg-liquid ~ .contact .glow, html:not([data-theme="light"]) .bg-liquid ~ * .contact .glow { opacity: 0; }
/* ...and their blobs stop animating while hidden, so they cost nothing */
.bg-liquid ~ main .aurora i, .bg-liquid ~ * .aurora i, html:not([data-theme="light"]) .bg-liquid ~ .contact .glow i, html:not([data-theme="light"]) .bg-liquid ~ * .contact .glow i { animation: none; }

/* Noise Shimmer canvas (motion.js) over the page gradient: fades in once it runs */
.bg-liquid > .nz-canvas { position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none; opacity: 0; transition: opacity 1.2s cubic-bezier(.22, 1, .36, 1); }
.bg-liquid.nz-on > .nz-canvas { opacity: 1; }
