:root {
  /* Tell the browser this page is intentionally dark, so it doesn't try
     to auto-invert/re-theme anything on its own. */
  color-scheme: dark;
}

/* Film-grain texture over the whole page — a tiny tiled SVG noise pattern
   (feTurbulence), not an image file. Fixed so it doesn't scroll with the
   page, ignores clicks, and sits above everything (including the video
   modal) so the grain reads consistently everywhere. */
#grain-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: .035;
  /* soft-light instead of overlay: overlay pushes random noise pixels
     strongly toward white over a near-black background specifically,
     which read as a visible gray "wash" over empty/plain sections while
     staying near-invisible over busy video content — inconsistent from
     section to section. soft-light is far gentler across the board. */
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) {
  /* Not animated either way, but keep it out of the way for anyone who
     finds visual texture noise distracting. */
  #grain-overlay { opacity: .02; }
}

/* ==========================================================
   CUSTOM COLORS — written as plain CSS, not left to Tailwind's CDN.
   Confirmed by direct inspection: Tailwind's runtime loads and generates
   its STANDARD utilities fine (flex, spacing, etc.), but for this build
   it never generates rules for the CUSTOM colors defined in
   tailwind.config (ink/paper/accent) — 0 of 157 generated rules
   referenced them, even though the HTML classes (bg-ink, text-accent...)
   are all correct. That's what made the hero overlay, and potentially
   any other bg-ink/text-paper/etc element on the page, render with no
   color at all despite the class being right there in the markup.
   Every one of those custom-color classes is re-declared here as plain
   CSS instead, using the exact same selector Tailwind would generate
   (escaped ':' and '/'), so they work regardless of whether Tailwind's
   CDN cooperates. Tailwind is still used for layout/spacing utilities,
   which have proven reliable — just not for these specific colors.
========================================================== */

html, body {
  background: #050505;
  color: #f5f4f0;
}

/* Frosted-glass panel — translucent + heavy backdrop-blur, used for the
   Contact section's card so the soft amber glow behind it reads through
   as a genuine "glass" surface instead of a flat solid block. */
.glass-panel {
  background: rgba(255,255,255,.04);
  backdrop-filter: blur(40px) saturate(140%);
  -webkit-backdrop-filter: blur(40px) saturate(140%);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 28px;
  box-shadow: 0 20px 60px -20px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.06);
}

.bg-ink { background-color: #050505; }
.bg-ink-raised { background-color: #0d0d0d; }
.bg-ink\/70 { background-color: rgba(5,5,5,.7); }
.bg-ink\/80 { background-color: rgba(5,5,5,.8); }
.bg-ink\/100 { background-color: #050505; }
.bg-paper { background-color: #f5f4f0; }
.bg-accent { background-color: #f59e0b; }

.text-ink { color: #050505; }
.text-paper { color: #f5f4f0; }
.text-paper-dim { color: #9a988f; }
.text-paper-faint { color: #5c5b55; }
.text-accent { color: #f59e0b; }

.border-accent { border-color: #f59e0b; }
.border-paper\/10 { border-color: rgba(245,244,240,.10); }
.border-paper\/20 { border-color: rgba(245,244,240,.20); }
.border-paper\/25 { border-color: rgba(245,244,240,.25); }
.divide-paper\/10 > :not([hidden]) ~ :not([hidden]) { border-color: rgba(245,244,240,.10); }

.hover\:bg-accent:hover { background-color: #f59e0b; }
.hover\:border-accent:hover { border-color: #f59e0b; }
.hover\:text-accent:hover { color: #f59e0b; }
.focus\:ring-accent:focus { outline: none; box-shadow: 0 0 0 2px #f59e0b; }

/* ==========================================================
   NAVBAR
========================================================== */

.nav-link:hover {
  color: #f59e0b;
  text-shadow: 0 0 8px rgba(245,158,11,.65), 0 0 18px rgba(245,158,11,.4);
}

/* The Contact link is also an outlined button — its border glows too. */
#navbar a.nav-link:hover {
  border-color: #f59e0b;
}

/* Glassmorphism: translucent, blurred, frosted-glass panel — subtle even
   at rest, a bit more opaque/defined once scrolled so text stays legible
   over whatever's behind it. */
#navbar {
  background: rgba(10,10,10,.28);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid rgba(245,244,240,.08);
  box-shadow: 0 1px 24px rgba(0,0,0,.15);
}

#navbar.nav-scrolled {
  background: rgba(8,8,8,.55);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  border-bottom: 1px solid rgba(245,244,240,.12);
  box-shadow: 0 4px 30px rgba(0,0,0,.3);
}

/* ==========================================================
   HERO / HIGHLIGHT OVERLAP
   Both layers sit stacked in the same pinned viewport. main.js drives
   --hero-fade (0→1: headline holds, then fades/lifts away) and
   --highlight-fade (0→1: highlight reel scales+fades in from the
   center) from one continuous scroll value, so the handoff overlaps
   in the same screen space instead of being two separate sections.
========================================================== */

#hero-bg {
  --hero-fade: 0;
  z-index: 0;
  opacity: calc(1 - var(--hero-fade));
  will-change: opacity;
}

.hero-layer {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 24px;
}

#hero-content {
  --hero-fade: 0;
  z-index: 1;
  /* Settles at ~15% opacity instead of 0 — like the reference, the big
     name stays as a dim backdrop instead of disappearing completely
     once the highlight reel has settled fully in front of it — but
     during the transition itself (--hero-fade between 0 and 1) it's
     genuinely still on screen, overlapping with the incoming reel. */
  opacity: calc(1 - var(--hero-fade));
  transform: scale(calc(1 - var(--hero-fade) * .08));
  will-change: opacity, transform;
}

#highlight-content {
  --highlight-fade: 0;
  z-index: 2;
  opacity: var(--highlight-fade);
  transform: scale(calc(0.75 + var(--highlight-fade) * .25));
  pointer-events: none;
  will-change: opacity, transform;
}

/* ==========================================================
   REVEAL ANIMATION
========================================================== */

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 1.5s cubic-bezier(.19,1,.22,1), transform 1.5s cubic-bezier(.19,1,.22,1);
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

.reveal-delay-1 { transition-delay: .2s; }
.reveal-delay-2 { transition-delay: .4s; }
.reveal-delay-3 { transition-delay: .6s; }
.reveal-delay-4 { transition-delay: .8s; }
/* Used so a second element (the About photo) starts fading in only once
   the text beside it — now a staggered sequence of 5 lines ending around
   .8s + 1.5s ≈ 2.3s — is roughly halfway through its own reveal. */
.reveal-delay-half { transition-delay: 1.15s; }

.scroll-indicator {
  animation: bounce-down 2s ease-in-out infinite;
}

@keyframes bounce-down {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(8px); }
}

/* ==========================================================
   HIGHLIGHT GRID
========================================================== */

.highlight-card {
  position: relative;
  /* Fluid instead of fixed breakpoint widths — sized so all 6 cards plus
     gaps and side padding always fit within the viewport, on common
     laptop widths (1366–1536px) too, instead of overflowing past the
     screen edge and getting clipped there. */
  width: clamp(60px, 14vw, 220px);
  aspect-ratio: 9 / 16;
  overflow: hidden;
  border-radius: 24px;
  /* Belt-and-suspenders for the rounded corners: some browsers can let a
     <video> escape a plain overflow:hidden+border-radius clip once the
     element is under a continuous transform (the floating bob below runs
     permanently), so clip-path pins the rounding more reliably. */
  clip-path: inset(0 round 24px);
  background: #0d0d0d;
  border: 1px solid rgba(245,244,240,.08);
  flex-shrink: 0;
  /* decorative only — not clickable, so no pointer cursor */
}

/* Extra safety net for very narrow phones: even the fluid width above has
   a floor, so let the row wrap onto two lines there rather than ever
   risk clipping past the screen edge. */
@media (max-width: 420px) {
  #highlight-grid { flex-wrap: wrap; row-gap: 12px; }
}

/* Clean, consistent zigzag — not random — matching a fixed up/down/up
   row rhythm: odd cards sit higher, even cards sit lower.
   (scaled up +50% then +20% along with the card size above) */
.highlight-card:nth-child(odd) {
  margin-top: -61px;
}

.highlight-card:nth-child(even) {
  margin-top: 61px;
}

@media (min-width: 640px) {
  .highlight-card:nth-child(odd) { margin-top: -83px; }
  .highlight-card:nth-child(even) { margin-top: 83px; }
}

/* Each card gets a randomized --scatter-x/y/rot inline (set in main.js).
   It's driven by the inherited --highlight-fade from #highlight-content
   (see above) rather than its own observer: at fade=0 it sits scattered
   off its grid slot, at fade=1 it has settled fully into place.

   This uses the standalone `translate`/`rotate` CSS properties (NOT the
   `transform` shorthand) on purpose: the continuous floating bob below
   animates `transform` via @keyframes, and a CSS animation always wins
   over a plain `transform` declaration on the same property — using the
   separate properties lets the scroll-driven scatter and the floating
   bob compose together on the SAME element (whole card, frame included)
   instead of one silently overriding the other. */
.highlight-card {
  opacity: var(--highlight-fade, 0);
  translate: calc(var(--scatter-x, 0px) * (1 - var(--highlight-fade, 0))) calc(var(--scatter-y, 40px) * (1 - var(--highlight-fade, 0)));
  rotate: calc(var(--scatter-rot, 0deg) * (1 - var(--highlight-fade, 0)));
  animation: highlight-bob 4s ease-in-out infinite;
}

@keyframes highlight-bob {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-10px) rotate(0.6deg); }
}

.highlight-card video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s ease;
}

.highlight-card:hover video {
  transform: scale(1.04);
}

.highlight-card .label {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 14px 16px;
  background: linear-gradient(to top, rgba(0,0,0,.75), transparent);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #f5f4f0;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .3s ease, transform .3s ease;
}

.highlight-card:hover .label {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================
   TOOL ROW
========================================================== */

.tool-row {
  transition: padding-left .3s ease;
}

.tool-row:hover {
  padding-left: 12px;
}

.tool-row h3,
.tool-row span {
  transition: color .3s ease;
}

.tool-row:hover h3,
.tool-row:hover span {
  color: #f59e0b;
}

/* ==========================================================
   PROJECTS CAROUSEL (showreel marquee)
========================================================== */

.carousel-wrapper {
  position: relative;
  overflow: hidden;
  width: 100%;
  padding: 32px 24px;
  margin: 0;
}

.carousel-wrapper::before,
.carousel-wrapper::after {
  content: "";
  position: absolute;
  top: 0;
  width: 120px;
  height: 100%;
  z-index: 5;
  pointer-events: none;
}

.carousel-wrapper::before {
  left: 0;
  background: linear-gradient(to right, #050505, transparent);
}

.carousel-wrapper::after {
  right: 0;
  background: linear-gradient(to left, #050505, transparent);
}

.carousel-track {
  display: flex;
  gap: 24px;
  width: max-content;
  animation: marqueeLeft 35s linear infinite;
  will-change: transform;
}

.reverse .carousel-track {
  animation: marqueeRight 35s linear infinite;
}

.carousel-track:hover {
  animation-play-state: paused;
}

@keyframes marqueeLeft {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@keyframes marqueeRight {
  from { transform: translateX(-50%); }
  to { transform: translateX(0); }
}

/* Fluid width instead of fixed breakpoint jumps — scales continuously
   with viewport width so it reads consistently across devices instead of
   snapping to a different fixed size at 1024px/768px. */
.video-card {
  width: clamp(130px, 20vw, 210px);
  aspect-ratio: 9 / 16;
  flex-shrink: 0;
  position: relative;
  overflow: hidden;
  border-radius: 18px;
  clip-path: inset(0 round 18px);
  cursor: pointer;
  transition: transform .35s ease, box-shadow .35s ease;
  background: linear-gradient(155deg, #1a1a24 0%, #12121a 55%, #1f1730 100%);
}

.video-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(245,158,11,.35) 0%, transparent 70%);
  opacity: .5;
  transition: opacity .35s ease;
}

.video-card:hover {
  transform: translateY(-8px) scale(1.03);
  box-shadow:
    0 24px 48px -16px rgba(0,0,0,.6),
    0 0 32px 4px rgba(245,158,11,.28),
    0 0 60px 14px rgba(99,102,241,.18);
}

.video-card:focus-visible {
  outline: 2px solid #f59e0b;
  outline-offset: 2px;
}

.video-card video {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-card.video-missing video {
  display: none;
}

.video-card.video-missing .play-overlay {
  background: transparent;
  backdrop-filter: none;
}

.play-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgba(0,0,0,.15);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity .3s;
}

/* Hidden at rest so the preview plays clean; appears on hover as the
   click invitation. No video loaded yet → keep it up regardless,
   since there's nothing to reveal underneath it. */
.video-card:hover .play-overlay,
.video-card.video-missing .play-overlay {
  opacity: 1;
}

.play-btn {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(245,244,240,.15);
  border: 1px solid rgba(245,244,240,.4);
  backdrop-filter: blur(8px);
  color: #f59e0b;
  transition: transform .3s ease, background .3s ease, border-color .3s ease;
}

.play-btn svg {
  width: 22px;
  height: 22px;
  margin-left: 3px;
}

.video-card:hover .play-btn {
  transform: scale(1.08);
  background: rgba(245,158,11,.18);
  border-color: rgba(245,158,11,.5);
}

@media (max-width: 768px) {
  .carousel-track { gap: 16px; animation-duration: 25s; }
}

/* ==========================================================
   VIDEO MODAL — loading spinner
   Shown between clicking a card and the full-res video actually being
   ready to play (main.js toggles #modal-loading's hidden class).
========================================================== */

.modal-spinner {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 3px solid rgba(245,244,240,.2);
  border-top-color: #f59e0b;
  animation: modal-spin .8s linear infinite;
}

@keyframes modal-spin {
  to { transform: rotate(360deg); }
}

/* ==========================================================
   FIXED BOTTOM BAR — progressive glass blur, always visible while
   scrolling. Not a fully opaque bar: a stack of layers, each blurred
   a little more than the last and masked to a taller band above it,
   so content scrolling underneath fades from sharp to soft rather
   than hitting a hard blur edge (same technique as Portfolite's
   fixed bottom element — layered backdrop-filter + gradient masks).
========================================================== */

#bottom-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  height: 72px;
  pointer-events: none;
}

.bottom-bar-blur {
  position: absolute;
  inset: 0;
}

.bottom-bar-blur span {
  position: absolute;
  inset: 0;
  display: block;
}

/* Every layer (including the backing tint below) carries its own
   mask fading out toward the top — no layer has a hard box edge,
   so there's no visible seam where the blur "starts". */
.bottom-bar-blur span:nth-child(1) {
  backdrop-filter: blur(0.35px);
  -webkit-backdrop-filter: blur(0.35px);
  mask-image: linear-gradient(to top, black 0%, black 15%, transparent 40%);
  -webkit-mask-image: linear-gradient(to top, black 0%, black 15%, transparent 40%);
}

.bottom-bar-blur span:nth-child(2) {
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
  mask-image: linear-gradient(to top, black 0%, black 32%, transparent 60%);
  -webkit-mask-image: linear-gradient(to top, black 0%, black 32%, transparent 60%);
}

.bottom-bar-blur span:nth-child(3) {
  backdrop-filter: blur(2.5px);
  -webkit-backdrop-filter: blur(2.5px);
  mask-image: linear-gradient(to top, black 0%, black 50%, transparent 80%);
  -webkit-mask-image: linear-gradient(to top, black 0%, black 50%, transparent 80%);
}

.bottom-bar-blur span:nth-child(4) {
  backdrop-filter: blur(5px) saturate(120%);
  -webkit-backdrop-filter: blur(5px) saturate(120%);
  background: linear-gradient(to top, rgba(5,5,5,.4), rgba(5,5,5,0) 90%);
  mask-image: linear-gradient(to top, black 0%, black 65%, transparent 100%);
  -webkit-mask-image: linear-gradient(to top, black 0%, black 65%, transparent 100%);
}

/* ==========================================================
   REDUCE MOTION
========================================================== */

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .carousel-track { animation: none; }
  .scroll-indicator { animation: none; }
  .highlight-card:hover video { transform: none; }
  .highlight-float { animation: none; }
  .modal-spinner { animation: none; border-top-color: rgba(245,244,240,.2); }
}
