/* ═══════════════════════════════════════════════════════════
   KSDR — shared motion & UX layer
   Loaded on every page after the page's own styles.
═══════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════
   LIGHT THEME
   Overrides the base CSS variables each page defines in :root.
   Every page's own :root { --bg: … } wins over this file (they
   load later in cascade order), so the light rules use
   :root[data-theme="light"] to bump specificity and land last.
   The mindmap page marks its body [data-no-bg-net] and opts out —
   the graph reads clearest on a dark stage.
═══════════════════════════════════════════════════════════ */
:root[data-theme="light"] {
  --bg: #f5f7fb;
  --bg2: #ffffff;
  --bg3: #eef2f7;
  --border: rgba(15, 23, 42, 0.10);
  --text: #0f172a;
  --muted: #52607a;
  --subtle: #e2e8f0;
  color-scheme: light;
}

/* mindmap page uses a slightly cooler light palette (the graph canvas
   is themed in JS; here we only set the chrome variables) */
:root[data-theme="light"] body[data-no-bg-net] {
  --bg: #eef2f8;
  --bg2: #ffffff;
  --bg3: #e6ecf4;
  --border: rgba(15, 23, 42, 0.10);
  --text: #0f172a;
  --muted: #52607a;
  --subtle: #e2e8f0;
  color-scheme: light;
}

/* smooth the transition on the swap, but keep the mindmap canvas snappy */
html:not([data-theme-anim="off"]) body {
  transition: background-color 0.35s ease, color 0.35s ease;
}

/* nav bar: semi-transparent white on light (applies to every page incl. mindmap) */
:root[data-theme="light"] nav {
  background: rgba(255, 255, 255, 0.72);
  border-bottom-color: rgba(15, 23, 42, 0.08);
}

/* animated background: grid + orbs need to work on white too */
:root[data-theme="light"] .bg-grid {
  background-image:
    linear-gradient(rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px);
}
:root[data-theme="light"] .bg-orb {
  opacity: 0.5;
  mix-blend-mode: multiply;
}

/* ── Mindmap light mode: floating chrome ──
   These panels float over a light canvas now, so their hardcoded dark
   translucent backgrounds must flip to light translucent. The graph
   itself (canvas node fills, label text, halos) is themed in the
   mindmap's own script; the loop redraws every frame so it self-updates. */
:root[data-theme="light"] body[data-no-bg-net] .lens-switch,
:root[data-theme="light"] body[data-no-bg-net] .chip,
:root[data-theme="light"] body[data-no-bg-net] .tool,
:root[data-theme="light"] body[data-no-bg-net] .search {
  background: rgba(255, 255, 255, 0.82);
  box-shadow: 0 8px 28px rgba(15, 23, 42, 0.10);
}
:root[data-theme="light"] body[data-no-bg-net] .chip { color: #334155; }
:root[data-theme="light"] body[data-no-bg-net] .panel {
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.97), rgba(238, 242, 248, 0.98));
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}
:root[data-theme="light"] body[data-no-bg-net] .lens-btn.is-on { color: #0e7490; }
:root[data-theme="light"] body[data-no-bg-net] .lens-thumb {
  background: linear-gradient(135deg, rgba(6, 182, 212, 0.18), rgba(139, 92, 246, 0.18));
  border-color: rgba(6, 182, 212, 0.45);
}
:root[data-theme="light"] body[data-no-bg-net] .plink {
  background: rgba(15, 23, 42, 0.04);
  color: #334155;
}
/* panel body copy is hardcoded slate — darken on the white panel */
:root[data-theme="light"] body[data-no-bg-net] .panel p {
  color: #334155;
}
:root[data-theme="light"] body[data-no-bg-net] .search input { color: #0f172a; }
:root[data-theme="light"] body[data-no-bg-net] .cv-jump {
  background: rgba(6, 182, 212, 0.12);
  color: #0e7490;
}
:root[data-theme="light"] body[data-no-bg-net] .mobile-sidebar {
  background: rgba(255, 255, 255, 0.98);
}
/* particle net: darken the strokes and blend with the light bg */
:root[data-theme="light"] body:not([data-no-bg-net]) #bg-net {
  opacity: 0.6;
  mix-blend-mode: multiply;
  filter: invert(1) hue-rotate(180deg);
}

/* gradient-text titles: swap the white anchor for a dark navy */
:root[data-theme="light"] body:not([data-no-bg-net]) .hero-name {
  background: linear-gradient(135deg, #0f172a 30%, #0891b2 70%, #7c3aed 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
:root[data-theme="light"] body:not([data-no-bg-net]) .nav-logo {
  background: linear-gradient(135deg, #0891b2, #7c3aed);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
/* darker, higher-contrast tagline/section spans on white */
:root[data-theme="light"] body:not([data-no-bg-net]) .hero-tagline,
:root[data-theme="light"] body:not([data-no-bg-net]) .tc-role,
:root[data-theme="light"] body:not([data-no-bg-net]) .edu-school,
:root[data-theme="light"] body:not([data-no-bg-net]) .card-client,
:root[data-theme="light"] body:not([data-no-bg-net]) .pub-type,
:root[data-theme="light"] body:not([data-no-bg-net]) .section-label {
  color: #0e7490;
}

/* hero node-graph: SVG label fills are hardcoded light — flip on white */
:root[data-theme="light"] body:not([data-no-bg-net]) .hg-hub text {
  fill: #0e7490;
}
:root[data-theme="light"] body:not([data-no-bg-net]) .hg-node text {
  fill: #1e293b;
}
/* skyline decoration: lift opacity a touch so it doesn't vanish on white */
:root[data-theme="light"] body:not([data-no-bg-net]) .hero-skyline {
  opacity: 0.85;
}

/* photo desaturation reads harsh on white — leave in colour */
:root[data-theme="light"] body:not([data-no-bg-net]) .hero-photo,
:root[data-theme="light"] body:not([data-no-bg-net]) .avatar-wrap img {
  filter: none;
}

/* body text bumps that pages set directly (not via var) */
:root[data-theme="light"] body:not([data-no-bg-net]) .about-text,
:root[data-theme="light"] body:not([data-no-bg-net]) .tc-bullets li,
:root[data-theme="light"] body:not([data-no-bg-net]) .card-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .card-bullets li,
:root[data-theme="light"] body:not([data-no-bg-net]) .hero-sub,
:root[data-theme="light"] body:not([data-no-bg-net]) .pub-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .sc-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .drone-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .board-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .pfcard-desc,
:root[data-theme="light"] body:not([data-no-bg-net]) .pfcard-bullets li {
  color: #1e293b;
}

/* dot navigation on the CV rail: darker on white */
:root[data-theme="light"] body:not([data-no-bg-net]) .side-rail a {
  color: #52607a;
}
:root[data-theme="light"] body:not([data-no-bg-net]) .side-rail a .dot {
  background: rgba(15, 23, 42, 0.28);
}
:root[data-theme="light"] body:not([data-no-bg-net]) .side-rail a.active .dot {
  background: #0891b2;
  box-shadow: 0 0 10px rgba(8, 145, 178, 0.4);
}
:root[data-theme="light"] body:not([data-no-bg-net]) .side-rail a.active {
  color: #0891b2;
}

/* to-top button: legible on both */
:root[data-theme="light"] body:not([data-no-bg-net]) #to-top {
  background: rgba(255, 255, 255, 0.88);
  border-color: rgba(8, 145, 178, 0.35);
  color: #0891b2;
  box-shadow: 0 4px 24px rgba(15, 23, 42, 0.10);
}

/* ═══════════════════════════════════════════════════════════
   THEME TOGGLE BUTTON (injected by motion.js)
═══════════════════════════════════════════════════════════ */
#theme-toggle {
  position: fixed;
  top: 12px;
  right: 68px;                 /* clears the "Get in touch" / Back-to-CV button */
  z-index: 101;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
              background 0.25s, border-color 0.25s, color 0.25s;
}
#theme-toggle:hover {
  transform: rotate(-18deg) scale(1.06);
  border-color: rgba(6, 182, 212, 0.5);
  color: #67e8f9;
}
:root[data-theme="light"] #theme-toggle {
  background: rgba(255, 255, 255, 0.7);
  border-color: rgba(15, 23, 42, 0.15);
  color: #0f172a;
}
:root[data-theme="light"] #theme-toggle:hover {
  border-color: rgba(8, 145, 178, 0.55);
  color: #0891b2;
}
#theme-toggle svg { display: block; width: 16px; height: 16px; }
/* nudge to a safer spot on very narrow screens (avoids the hamburger area) */
@media (max-width: 900px) {
  #theme-toggle { right: 60px; }
}
@media (max-width: 480px) {
  #theme-toggle { right: 56px; top: 14px; }
}

/* ── Scroll progress bar ── */
#scroll-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 200;
  background: linear-gradient(90deg, #06b6d4, #8b5cf6, #06b6d4);
  background-size: 200% 100%;
  transform-origin: 0 50%;
  transform: scaleX(0);
  animation: progressHue 6s linear infinite;
  pointer-events: none;
}
@keyframes progressHue {
  to { background-position: 200% 0; }
}

/* ── Particle network canvas (injected by motion.js) ── */
#bg-net {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s ease;
}
#bg-net.on { opacity: 1; }

/* ── Page enter / exit transitions ── */
body { animation: pageEnter 0.55s ease both; }
body.page-exit { animation: pageExit 0.26s ease both; }
@keyframes pageEnter { from { opacity: 0; } to { opacity: 1; } }
@keyframes pageExit  { from { opacity: 1; } to { opacity: 0; } }

/* ── Nav scrolled state ── */
nav.scrolled {
  background: rgba(7, 11, 20, 0.88);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
}

/* ── Card sheen — pointer spotlight (spans injected by motion.js) ── */
.card-sheen {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
  background: radial-gradient(
    420px circle at var(--mx, 50%) var(--my, 50%),
    rgba(6, 182, 212, 0.09),
    rgba(139, 92, 246, 0.05) 45%,
    transparent 65%
  );
}
.sheen-host:hover .card-sheen,
.sheen-host.sheen-tap .card-sheen { opacity: 1; }

/* ── Back-to-top button ── */
#to-top {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 90;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(13, 21, 38, 0.85);
  border: 1px solid rgba(6, 182, 212, 0.35);
  color: #67e8f9;
  cursor: pointer;
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), 0 0 16px rgba(6, 182, 212, 0.12);
  opacity: 0;
  transform: translateY(14px) scale(0.9);
  pointer-events: none;
  transition: opacity 0.35s ease,
              transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
              border-color 0.25s, box-shadow 0.25s;
}
#to-top.show {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
#to-top:hover {
  border-color: rgba(6, 182, 212, 0.7);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), 0 0 24px rgba(6, 182, 212, 0.35);
}
#to-top:active { transform: scale(0.92); }
#to-top svg { display: block; }

/* ── Typewriter rotation ── */
.rotate-wrap { display: inline-flex; align-items: baseline; white-space: nowrap; }
.rotate-caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 3px;
  align-self: center;
  background: currentColor;
  animation: caretBlink 1s steps(1) infinite;
}
@keyframes caretBlink { 50% { opacity: 0; } }

/* ── Screen-reader-only utility ── */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── Reduced motion: calm everything down ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  #bg-net { display: none; }
  .rotate-caret { display: none; }
}
