/* ==========================================================================
   Page effects (driven by effects.js). Anything hidden up front has a CSS
   fail-safe that reveals it on its own, so a script failure never blanks the page.
   ========================================================================== */

/* Loading screen -------------------------------------------------------------
   Sequence: glow + orbit fade in, the logo draws itself (tile, J, D, then the cursor
   pops and blinks), the name decodes, then on ready the orbit closes, the emblem
   pulses, and the screen splits open (top half up, bottom half down). */
.loader {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center; overflow: hidden;
  transition: visibility 0s linear 1.1s;
  animation: loader-failsafe 0s linear 4.8s forwards;
}
.skip-loader .loader { display: none; }
.loader.is-done { visibility: hidden; pointer-events: none; }
@keyframes loader-failsafe { to { opacity: 0; visibility: hidden; } }

.loader-panel {
  position: absolute; left: 0; right: 0; height: 50.5%; background: var(--bg);
  transition: transform 0.95s cubic-bezier(0.76, 0, 0.24, 1) 0.15s;
}
.loader-panel-top { top: 0; border-bottom: 1px solid transparent; }
.loader-panel-bottom { bottom: 0; }
.loader-panel::before {
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 56px 56px; background-attachment: fixed;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, #000, transparent 75%);
  mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, #000, transparent 75%);
}
.loader.is-done .loader-panel-top { transform: translateY(-100%); border-bottom-color: var(--accent); }
.loader.is-done .loader-panel-bottom { transform: translateY(100%); }

.loader-stage {
  position: relative; z-index: 1;
  display: grid; justify-items: center; gap: 14px; width: min(340px, 84vw);
  transition: opacity 0.35s var(--ease), transform 0.5s var(--ease);
}
.loader.is-done .loader-stage { opacity: 0; transform: scale(0.94); }

/* Emblem: glow, rotating orbit, self-drawing logo */
.loader-emblem { position: relative; display: grid; place-items: center; width: 168px; height: 168px; margin-bottom: 10px; }
.loader-glow {
  position: absolute; inset: 14%; border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 28%, transparent), transparent);
  filter: blur(14px); opacity: 0;
  animation: glow-in 0.8s var(--ease) 0.1s forwards, glow-breathe 2.6s ease-in-out 0.9s infinite;
}
@keyframes glow-in { to { opacity: 0.7; } }
@keyframes glow-breathe { 50% { opacity: 1; transform: scale(1.12); } }

.loader-orbit {
  position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible;
  opacity: 0; transform: scale(0.7);
  animation: orbit-in 0.7s var(--ease) 0.15s forwards, orbit-spin 2.4s linear 0.15s infinite;
}
.orbit-track { fill: none; stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 6; }
.orbit-arc {
  fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round;
  stroke-dasharray: 22 78; transition: stroke-dasharray 0.6s var(--ease);
}
.orbit-dot { fill: var(--accent); filter: drop-shadow(0 0 6px var(--accent)); }
@keyframes orbit-in { to { opacity: 1; transform: scale(1); } }
@keyframes orbit-spin { from { rotate: 0deg; } to { rotate: 360deg; } }
.loader.is-ready .orbit-arc { stroke-dasharray: 100 0; }

.loader-logo { position: relative; width: 92px; height: 92px; }
.loader-logo .logo-tile,
.loader-logo .logo-stroke { stroke-dasharray: 1; stroke-dashoffset: 1; }
.loader-logo .logo-tile { fill: transparent; animation: draw 0.7s var(--ease) 0.2s forwards, tile-fill 0.5s var(--ease) 0.7s forwards; }
.loader-logo .logo-j { animation: draw 0.45s var(--ease) 0.55s forwards; }
.loader-logo .logo-d { animation: draw 0.65s var(--ease) 0.85s forwards; }
.loader-logo .logo-cursor {
  transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(0);
  animation: cursor-pop 0.3s var(--ease) 1.4s forwards, logo-blink 1s steps(1) 1.8s infinite;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes tile-fill { to { fill: var(--surface); } }
@keyframes cursor-pop { to { transform: scaleY(1); } }
.loader.is-ready .loader-logo { animation: emblem-pulse 0.5s var(--ease); }
@keyframes emblem-pulse { 40% { transform: scale(1.08); } }

/* Text: name decodes (effects.js), role and meter fade up */
.loader-name, .loader-role, .loader-meter, .loader-bar { opacity: 0; transform: translateY(6px); animation: rise-in 0.5s var(--ease) forwards; }
.loader-name { margin: 0; font-size: clamp(1.25rem, 4vw, 1.5rem); font-weight: 650; letter-spacing: -0.02em; animation-delay: 0.7s; }
.loader-role { margin: -8px 0 6px; color: var(--text-3); font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.04em; animation-delay: 0.9s; }
.loader-meter { display: flex; justify-content: space-between; width: 100%; color: var(--text-3); font-family: var(--mono); font-size: 0.75rem; animation-delay: 1s; }
.loader-status::before { content: "> "; color: var(--accent-text); }
.loader.is-ready .loader-status { color: var(--text); }
.loader-bar { position: relative; width: 100%; height: 2px; margin-top: -6px; overflow: hidden; border-radius: 2px; background: var(--border); animation-delay: 1s; }
.loader-bar span { display: block; width: calc(var(--p, 0) * 1%); height: 100%; background: var(--accent); box-shadow: 0 0 10px var(--accent); }
@keyframes rise-in { to { opacity: 1; transform: none; } }

/* Scroll progress ------------------------------------------------------------ */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; z-index: 70; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%; pointer-events: none;
}
html:not(.has-scroll-progress) .scroll-progress { display: none; }

/* Word reveals (hero name, section headings) --------------------------------- */
.word { display: inline-block; overflow: hidden; padding-bottom: 0.1em; margin-bottom: -0.1em; vertical-align: top; }
.word-inner { display: inline-block; will-change: transform; }

/* Hero intro: hidden until the loader lifts (fail-safe shows it after 4.6s regardless). */
.hero.is-pre .hero-status,
.hero.is-pre .hero-headline,
.hero.is-pre .hero-intro,
.hero.is-pre .hero-actions,
.hero.is-pre .hero-meta,
.hero.is-pre .editor { opacity: 0; animation: intro-failsafe 0s linear 4.6s forwards; }
.hero.is-pre .hero-title .word-inner { transform: translateY(105%); animation: intro-failsafe 0s linear 4.6s forwards; }
@keyframes intro-failsafe { to { opacity: 1; transform: none; } }

/* Code panel typing ----------------------------------------------------------- */
.editor-code.is-typing .line {
  overflow: hidden; padding-right: 0;
  max-width: calc(3.2em + (var(--chars, 0) + 1) * 1ch);
  animation: type-line var(--dur, 0.3s) steps(var(--chars, 1), end) var(--delay, 0s) both;
}
@keyframes type-line { from { max-width: 3.2em; } }
.editor-code.is-typing .line:last-child::after {
  content: ""; display: inline-block; width: 0.55em; height: 1.15em; margin-left: 2px;
  vertical-align: -0.2em; background: var(--accent); opacity: 0;
  animation: caret 1.05s linear var(--done, 0s) infinite;
}
@keyframes caret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* Tech marquee --------------------------------------------------------------- */
.marquee {
  overflow: hidden; padding: 18px 0;
  border-block: 1px solid var(--border); background: var(--bg-2);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track { display: flex; width: max-content; animation: marquee 60s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-list { display: flex; align-items: center; gap: 44px; padding-right: 44px; margin: 0; }
.marquee-list li {
  display: inline-flex; align-items: center; gap: 10px; white-space: nowrap;
  color: var(--text-3); font-family: var(--mono); font-size: 0.8125rem;
  transition: color 0.2s var(--ease);
}
.marquee-list li:hover { color: var(--text); }
.marquee-list .brand-icon { width: 18px; height: 18px; }
.marquee-mono { display: inline-grid; place-items: center; min-width: 22px; height: 18px; padding: 0 4px; border: 1px solid var(--border-2); border-radius: 4px; font-size: 0.625rem; font-weight: 700; }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } }

/* Cursor spotlight + magnetic buttons (mouse only) ---------------------------- */
@property --spot { syntax: "<color>"; inherits: false; initial-value: transparent; }
@media (hover: hover) and (pointer: fine) {
  .slide-card, .tech-tile, .editor, .contact-form {
    background-image: radial-gradient(380px circle at var(--mx, 50%) var(--my, 50%), var(--spot), transparent 60%);
  }
  .slide-card:hover, .tech-tile:hover, .editor:hover, .contact-form:hover { --spot: color-mix(in srgb, var(--accent) 13%, transparent); }
  .slide-card { transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease), --spot 0.4s var(--ease); }
  .tech-tile { transition: border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.2s var(--ease), --spot 0.4s var(--ease); }
  .editor, .contact-form { transition: --spot 0.4s var(--ease); }

  .magnetic {
    translate: var(--tx, 0px) var(--ty, 0px);
    transition: translate 0.3s var(--ease), background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.2s var(--ease);
  }
}

/* Tech globe (tech-sphere.js) ---------------------------------------------- */
.tech-sphere {
  position: relative; width: min(100%, 440px); aspect-ratio: 1; justify-self: center;
  cursor: grab; touch-action: pan-y; user-select: none; -webkit-user-select: none;
}
.tech-sphere.is-dragging { cursor: grabbing; }
.tech-sphere::before {
  content: ""; position: absolute; inset: 9%; border-radius: 50%;
  border: 1px dashed var(--border);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 12%, transparent), transparent 72%);
}
.sphere-stage { position: absolute; inset: 0; }
.sphere-chip {
  position: absolute; left: 50%; top: 50%;
  display: grid; place-items: center; width: 46px; height: 46px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface); color: var(--text-2);
  box-shadow: var(--shadow); will-change: transform, opacity;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.sphere-chip .brand-icon { width: 22px; height: 22px; }
.sphere-chip b { font-family: var(--mono); font-size: 0.625rem; font-weight: 700; }
.sphere-chip.is-front { color: var(--text); border-color: var(--border-2); }
.sphere-chip:hover { color: var(--accent-text); border-color: var(--accent-text); }
.sphere-chip::after {
  content: attr(data-name); position: absolute; top: calc(100% + 6px); left: 50%; translate: -50% 0;
  padding: 2px 7px; border-radius: 5px; background: var(--text); color: var(--bg);
  font-family: var(--mono); font-size: 0.6875rem; white-space: nowrap; opacity: 0; pointer-events: none;
  transition: opacity 0.15s var(--ease);
}
.sphere-chip:hover::after { opacity: 1; }
@media (max-width: 899px) { .tech-sphere { width: min(100%, 340px); } .sphere-chip { width: 40px; height: 40px; } }

/* Tech tiles: flip up per category (effects.js adds .flip-ready, then .is-in per group) */
.tech-grid { perspective: 900px; }
.flip-ready .tech-tile {
  opacity: 0; rotate: x -75deg; translate: 0 18px; transform-origin: 50% 100%;
  transition:
    opacity 0.45s var(--ease) calc(var(--i, 0) * 45ms),
    rotate 0.75s var(--ease) calc(var(--i, 0) * 45ms),
    translate 0.75s var(--ease) calc(var(--i, 0) * 45ms),
    border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.25s var(--ease), --spot 0.4s var(--ease);
}
.flip-ready .is-in .tech-tile { opacity: 1; rotate: none; translate: none; }

/* ...then tilt toward the cursor, with the icon lifting off the surface (mouse only) */
@media (hover: hover) and (pointer: fine) {
  .tech-tile { transform-style: preserve-3d; transform: perspective(500px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); }
  .tech-tile:hover, .tech-tile:focus-visible { transform: perspective(500px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateZ(8px); }
  .tech-icon { transition: color 0.2s var(--ease), transform 0.25s var(--ease); }
  .tech-tile:hover .tech-icon { transform: translateZ(26px) scale(1.1); }
}
