@import "./tokens.css?v=26";

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Subtle atmospheric wash — two off-center glows on the near-black base */
  background-image:
    radial-gradient(60% 50% at 78% -5%, oklch(30% 0.04 68 / 0.5), transparent 70%),
    radial-gradient(55% 45% at 10% 8%, oklch(28% 0.03 265 / 0.5), transparent 70%);
  background-attachment: fixed;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: 0;
}

a {
  color: inherit;
}

img {
  max-width: 100%;
  display: block;
}

.wrap {
  width: min(100% - 2 * var(--space-gutter), 1180px);
  margin-inline: auto;
}

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-accent);
  font-weight: 600;
}

.is-hidden {
  display: none !important;
}

/* ---------- Focus visibility ---------- */
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ============================================================
   GATE (password screen)
   ============================================================ */
.gate {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--space-gutter);
}

.gate__card {
  width: min(100%, 420px);
  background: linear-gradient(
    180deg,
    var(--color-surface-raised),
    var(--color-surface)
  );
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  box-shadow: var(--shadow-lift);
}

.gate__mark {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  margin-bottom: 1.75rem;
}

.gate__mark span[aria-hidden] {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 8px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-size: 1rem;
}

.gate__title {
  font-size: var(--text-xl);
  margin-bottom: 0.5rem;
}

.gate__sub {
  color: var(--color-text-muted);
  margin: 0 0 1.75rem;
  font-size: 0.95rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.field label {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  letter-spacing: 0.02em;
}

.field input {
  width: 100%;
  padding: 0.85rem 1rem;
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  transition: border-color var(--duration-fast) var(--ease-out-expo),
    box-shadow var(--duration-fast) var(--ease-out-expo);
}

.field input::placeholder {
  color: var(--color-text-faint);
}

.field input:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px oklch(78% 0.14 68 / 0.18);
}

.btn {
  --btn-bg: var(--color-accent);
  margin-top: 1.25rem;
  width: 100%;
  padding: 0.9rem 1.25rem;
  font: inherit;
  font-weight: 600;
  color: var(--color-accent-contrast);
  background: var(--btn-bg);
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out-expo),
    filter var(--duration-fast) var(--ease-out-expo);
}

.btn:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

.btn:active {
  transform: translateY(0);
}

.gate__error {
  margin: 1rem 0 0;
  min-height: 1.2em;
  font-size: var(--text-sm);
  color: oklch(72% 0.17 25);
}

.gate__hint {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-faint);
}

/* ============================================================
   APP (gallery)
   ============================================================ */
.site-header {
  padding: var(--space-gutter) 0;
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 10;
  background: oklch(16% 0.012 265 / 0.72);
  backdrop-filter: blur(14px);
  /* Auto-hide: header.js toggles .is-tucked on scroll direction */
  transition: transform var(--duration-normal) var(--ease-out-expo),
    opacity var(--duration-normal) var(--ease-out-expo);
}

.site-header.is-tucked {
  transform: translateY(-100%);
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .site-header {
    transition: none;
  }
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

.brand span[aria-hidden] {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 7px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-size: 0.9rem;
}

.logout {
  background: transparent;
  border: 1px solid var(--color-border-strong);
  color: var(--color-text-muted);
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out-expo),
    border-color var(--duration-fast) var(--ease-out-expo);
}

.logout:hover {
  color: var(--color-text);
  border-color: var(--color-accent);
}

/* ---------- Hero (compact, centered — the carousel is the star) ---------- */
.hero {
  padding: clamp(1rem, 0.6rem + 1.8vw, 2rem) 0 clamp(0.6rem, 0.4rem + 0.8vw, 1rem);
  text-align: center;
}

.hero__eyebrow {
  margin-bottom: 0.7rem;
}

.hero__title {
  font-size: clamp(2.1rem, 1.2rem + 3.4vw, 3.75rem);
  margin-inline: auto;
}

.hero__title em {
  font-style: normal;
  font-weight: 800;
  color: var(--color-accent);
}

.hero__lede {
  margin: 0.75rem auto 0;
  max-width: 48ch;
  font-size: var(--text-base);
  color: var(--color-text-muted);
}

/* ============================================================
   COVERFLOW CAROUSEL
   ============================================================ */
.carousel {
  padding-top: clamp(1rem, 0.5rem + 1.5vw, 2.25rem);
  padding-bottom: calc(var(--space-section) * 0.7);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.carousel__viewport {
  position: relative;

  /* ONE source of truth for card width. Whichever limit is smallest wins:
     screen width, an absolute max, or the space the window's height allows. */
  --card-gutter: 130px; /* guaranteed breathing room above + below the card */
  --card-w: max(
    260px,
    min(50vw, 760px, calc((66vh - var(--card-gutter)) * 16 / 9))
  );

  /* Height is DERIVED from the card, so the card can never be taller than the
     box that clips it — the top (and its label) can't get cut off. */
  height: calc(var(--card-w) * 9 / 16 + var(--card-gutter));

  /* Depth comes from each card's own transformPerspective (see carousel.js),
     not from a shared 3D context here — that's what keeps this clip working. */
  overflow: hidden;
}

/* Edge scrims: fade the left/right edges into the page so faded far cards
   never "ghost" over the navigation. Sit above the cards, below the arrows. */
.carousel__viewport::before,
.carousel__viewport::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(70px, 14%, 260px);
  z-index: 2;
  pointer-events: none;
}

.carousel__viewport::before {
  left: 0;
  background: linear-gradient(90deg, var(--color-bg), transparent);
}

.carousel__viewport::after {
  right: 0;
  background: linear-gradient(270deg, var(--color-bg), transparent);
}

.carousel__stage {
  position: absolute;
  inset: 0;
  /* Own stacking level so card z-indexes stay scoped below the scrims/arrows. */
  z-index: 1;
  /* NO transform-style: preserve-3d here — on purpose.
     A preserve-3d context breaks `overflow: hidden` clipping on the viewport
     (3D children escape the box) AND sorts children by 3D position instead of
     z-index, which makes the edge scrims and nav arrows impossible to layer.
     Each card gets its own perspective via GSAP's transformPerspective instead,
     so cards stay 2D-composited: clipping and z-index behave normally. */
  transform-style: flat;
}

/* ---------- Cards ---------- */
.video-card {
  position: absolute;
  top: 50%;
  left: 50%;
  /* Set on .carousel__viewport — the same value its height is derived from,
     so the card always fits inside the box with clearance above and below. */
  width: var(--card-w);
  aspect-ratio: 16 / 9;
  /* GSAP owns transform; give it a compositor layer */
  will-change: transform, opacity;
  transform: translate(-50%, -50%);
}

.video-card__media {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: linear-gradient(
    160deg,
    var(--color-surface-raised),
    oklch(30% 0.05 250)
  );
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--duration-normal) var(--ease-out-expo),
    border-color var(--duration-normal) var(--ease-out-expo);
}

.video-card__thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-card__thumb.is-empty {
  display: none;
}

/* Active card: brighter, ringed, lifted — reads as the "on stage" piece */
.video-card.is-active .video-card__media {
  border-color: oklch(78% 0.14 68 / 0.55);
  box-shadow: var(--shadow-lift), 0 0 0 1px oklch(78% 0.14 68 / 0.3),
    0 0 60px oklch(78% 0.14 68 / 0.18);
}

/* ---------- Label ---------- */
.video-card__label {
  position: absolute;
  inset: 0 0 auto 0;
  padding: 1.1rem 1.15rem 2.5rem;
  z-index: 3;
  background: linear-gradient(
    180deg,
    oklch(12% 0.02 265 / 0.72),
    transparent
  );
  pointer-events: none;
}

.video-card__tag {
  display: block;
  font-size: var(--text-sm);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-accent);
  font-weight: 600;
}

.video-card__title {
  font-size: clamp(1.3rem, 1rem + 0.9vw, 2rem);
  margin: 0.3rem 0 0;
  color: var(--color-text);
  text-shadow: 0 1px 12px oklch(0% 0 0 / 0.5);
  text-wrap: balance;
}

/* ---------- Play button ---------- */
.video-card__play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
  display: grid;
  place-items: center;
  width: clamp(56px, 7vw, 74px);
  aspect-ratio: 1;
  border: none;
  border-radius: 50%;
  background: oklch(98% 0.005 265 / 0.92);
  color: var(--color-accent-contrast);
  cursor: pointer;
  box-shadow: 0 8px 26px oklch(0% 0 0 / 0.4);
  transition: transform var(--duration-fast) var(--ease-out-expo),
    background var(--duration-fast) var(--ease-out-expo);
}

.video-card__play svg {
  width: 42%;
  height: 42%;
  fill: currentColor;
  margin-left: 8%;
}

.video-card.is-active .video-card__play:hover {
  transform: translate(-50%, -50%) scale(1.08);
  background: var(--color-accent);
}

/* ---------- Depth dimmer (darkens receding cards) ---------- */
.video-card__dim {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--color-bg);
  opacity: 0;
  pointer-events: none;
}

/* ---------- Hover / nav zones ---------- */
.carousel__zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 22%;
  /* Above the cards (stage z-index:1) and the scrims (z-index:2) so the arrows
     always render crisply on top and nothing ghosts over them. */
  z-index: 3;
  border: none;
  cursor: pointer;
  background: transparent;
  display: flex;
  align-items: center;
  color: var(--color-text);
  /* Prevent the grey/coloured flash some browsers paint on tap */
  -webkit-tap-highlight-color: transparent;
}

.carousel__zone--left {
  left: 0;
  justify-content: flex-start;
  padding-left: clamp(0.5rem, 2vw, 2rem);
}

.carousel__zone--right {
  right: 0;
  justify-content: flex-end;
  padding-right: clamp(0.5rem, 2vw, 2rem);
}

/* No hover background on the zones — an amber tint over the near-black page
   reads as a muddy brown block. The arrow fading in is the affordance. */

.carousel__arrow {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  font-size: 2rem;
  line-height: 1;
  border-radius: 50%;
  background: oklch(21% 0.014 265 / 0.7);
  border: 1px solid var(--color-border-strong);
  backdrop-filter: blur(8px);
  opacity: 0;
  transform: translateX(0);
  transition: opacity var(--duration-normal) var(--ease-out-expo),
    transform var(--duration-fast) var(--ease-out-expo);
}

.carousel__zone:hover .carousel__arrow,
.carousel__zone:focus-visible .carousel__arrow {
  opacity: 1;
}

.carousel__zone--left:hover .carousel__arrow {
  transform: translateX(-3px);
}
.carousel__zone--right:hover .carousel__arrow {
  transform: translateX(3px);
}

/* ---------- Detail panel (write-up for the centered video) ---------- */
.carousel__detail {
  margin-top: clamp(1.75rem, 1rem + 2vw, 3rem);
  max-width: 68ch;
  text-align: center;
}

.carousel__detail-tag {
  margin: 0 0 0.5rem;
  font-size: var(--text-sm);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--color-accent);
}

.carousel__detail-title {
  font-size: clamp(1.4rem, 1.1rem + 1.1vw, 2.1rem);
  margin: 0 0 0.9rem;
  text-wrap: balance;
}

.carousel__detail-body {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-base);
  line-height: 1.7;
  text-align: left;
}

/* ---------- Dots ---------- */
.carousel__dots {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

.carousel__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--color-border-strong);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out-expo),
    background var(--duration-fast) var(--ease-out-expo);
}

.carousel__dot:hover {
  background: var(--color-text-muted);
}

.carousel__dot.is-active {
  background: var(--color-accent);
  transform: scale(1.35);
}

/* ---------- Empty state ---------- */
.empty {
  text-align: center;
  padding: var(--space-section) 1rem;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
}

.empty code {
  color: var(--color-accent);
  font-size: 0.95em;
}

/* ============================================================
   SKILLS
   ============================================================ */
.icon-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.skills {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem);
  text-align: center;
}

.skills__eyebrow {
  margin-bottom: 0.7rem;
}

.skills__title {
  font-size: clamp(1.8rem, 1.2rem + 2.2vw, 3rem);
  margin-bottom: clamp(1.75rem, 1rem + 2vw, 2.75rem);
}

.skills__title em {
  font-style: normal;
  font-weight: 800;
  color: var(--color-accent);
}

.skills__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(0.6rem, 0.4rem + 0.6vw, 1rem);
}

.skill {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 1.15rem;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  background: linear-gradient(
    180deg,
    var(--color-surface-raised),
    var(--color-surface)
  );
  color: var(--color-text-muted);
  font-size: 0.95rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: default;
  box-shadow: 0 1px 2px oklch(0% 0 0 / 0.35);
  transition: transform var(--duration-normal) var(--ease-out-expo),
    border-color var(--duration-normal) var(--ease-out-expo),
    color var(--duration-normal) var(--ease-out-expo),
    box-shadow var(--duration-normal) var(--ease-out-expo);
}

.skill__icon {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
  color: var(--color-accent);
  transition: transform var(--duration-normal) var(--ease-out-expo);
}

.skill:hover {
  transform: translateY(-3px);
  color: var(--color-text);
  border-color: oklch(78% 0.14 68 / 0.55);
  box-shadow: 0 8px 22px oklch(0% 0 0 / 0.45),
    0 0 24px oklch(78% 0.14 68 / 0.16);
}

.skill:hover .skill__icon {
  transform: scale(1.15) rotate(-6deg);
}

/* Pre-reveal state — the stagger tween in skills.js animates these in.
   Only applied when JS will actually run the animation, so the badges are
   never left invisible if scripting fails. */
.skills__grid.is-armed .skill {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .skills__grid.is-armed .skill {
    opacity: 1;
  }
}

/* ============================================================
   VIDEO LIGHTBOX
   ============================================================ */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  /* Tight padding = more pixels for the player = higher streamed quality */
  padding: clamp(0.75rem, 1.5vw, 1.75rem);
}

.lightbox[hidden] {
  display: none;
}

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  /* Near-opaque: at lower alpha the sticky header showed through as a dark
     band across the top of the player. */
  background: oklch(9% 0.008 265 / 0.96);
  backdrop-filter: blur(12px);
  cursor: pointer;
}

.lightbox__dialog {
  position: relative;
  z-index: 1;
  /* Deliberately large: YouTube's adaptive streaming selects quality partly
     from the player's pixel size, so a bigger player is the most reliable way
     to get 1080p instead of 720p. */
  width: min(100%, 1600px);
  /* will-change so the scale-in tween stays on the compositor */
  will-change: transform, opacity;
}

.lightbox__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  /* Never taller than the window, even on short/wide screens */
  max-height: 84vh;
  margin-inline: auto;
  width: 100%;
  background: #000;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--color-border-strong);
  box-shadow: var(--shadow-lift), 0 0 80px oklch(78% 0.14 68 / 0.12);
}

.lightbox__frame iframe,
.lightbox__frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
}

.lightbox__caption {
  margin-top: 1.1rem;
  text-align: center;
}

.lightbox__tag {
  margin: 0 0 0.3rem;
  font-size: var(--text-sm);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--color-accent);
}

.lightbox__title {
  margin: 0;
  font-size: clamp(1.15rem, 0.9rem + 0.8vw, 1.6rem);
  text-wrap: balance;
}

.lightbox__close {
  /* Anchored to the overlay's top-right corner, so it stays on screen no
     matter how large the player gets. */
  position: absolute;
  top: clamp(0.6rem, 1.4vw, 1.25rem);
  right: clamp(0.6rem, 1.4vw, 1.25rem);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--color-border-strong);
  background: oklch(21% 0.014 265 / 0.85);
  color: var(--color-text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--duration-fast) var(--ease-out-expo),
    border-color var(--duration-fast) var(--ease-out-expo),
    transform var(--duration-fast) var(--ease-out-expo);
}

.lightbox__close svg {
  width: 55%;
  height: 55%;
  fill: none;
}

.lightbox__close:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
  transform: scale(1.06);
}

/* (No breakpoint needed — the close button is anchored to the overlay corner
   and is therefore always on screen.) */

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--color-border);
  padding: 2.5rem 0;
  color: var(--color-text-faint);
  font-size: var(--text-sm);
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2rem;
  justify-content: space-between;
  align-items: flex-end;
}

.site-footer__left {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

/* Contact — the one thing a recruiter needs to act on, so it outranks the
   copyright line in both size and colour. */
.site-footer__contact {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
}

.site-footer__contact a {
  color: var(--color-text-muted);
  font-size: var(--text-base);
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--duration-fast) var(--ease-out-expo),
    border-color var(--duration-fast) var(--ease-out-expo);
}

.site-footer__contact a:hover,
.site-footer__contact a:focus-visible {
  color: var(--color-accent);
  border-bottom-color: var(--color-accent);
}

/* ---------- Reveal-on-load motion ---------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(16px);
    animation: reveal var(--duration-normal) var(--ease-out-expo) forwards;
  }
  @keyframes reveal {
    to {
      opacity: 1;
      transform: none;
    }
  }
}
