/* =========================================================================
   Elias Ripari — landing
   Current state: full-bleed HD portrait + small logo top-left.
   Plain CSS, no build. Text/links will come back later (see js/config.js).
   ========================================================================= */

/* ---- Fonts --------------------------------------------------------------
   Display / titles / important text  →  CS Caleb Mono (self-hosted).
   Everything else (body)             →  Inter.
--------------------------------------------------------------------------- */
@font-face {
  font-family: "Caleb Mono";
  src: url("../assets/fonts/CSCalebMono-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Caleb Mono";
  src: url("../assets/fonts/CSCalebMono-Italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
/* optional reverse-italic (backslant) as its own family: font-family: "Caleb Mono Reverse" */
@font-face {
  font-family: "Caleb Mono Reverse";
  src: url("../assets/fonts/CSCalebMono-ReverseItalic.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}

/* Inter — self-hosted files land in assets/fonts/ (see below). Falls back to
   system sans until the woff2s exist. */
@font-face {
  font-family: "Inter";
  src: url("../assets/fonts/Inter-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../assets/fonts/Inter-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../assets/fonts/Inter-SemiBold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}

/* ---- Tokens ------------------------------------------------------------- */
:root {
  --font-display: "Caleb Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --font:         "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --bg:     #050A03;
  --fg:     #f4f2ee;                 /* warm off-white */
  --muted:  #b9b6ae;                 /* connective text */
  --accent: #d8a56b;                 /* amber rim-light from the photo */
  --logo-size: 40px;   /* height of the top-left logo */
  --logo-inset: clamp(20px, 4vw, 36px);
  --photo-shift-x: 25%;  /* horizontal push of the photo (img + WebGL layer) */
  --photo-fade-x: 14vw;  /* soft fade on the photo's left edge → hides the seam */

  /* Motion — strong custom curves (built-in CSS easings are too weak). */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);      /* enter/exit — snappy start */
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);     /* on-screen movement */
}

/* ---- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: var(--font);
  background: var(--bg);
  overflow: hidden;              /* single screen, no scroll */
  -webkit-font-smoothing: antialiased;
}
img { display: block; }

/* ---- Initial loader -----------------------------------------------------
   Counts 0→100%, then exits in three staged beats (driven by js/loader.js):
     1. .exit-bar  → the progress bar retracts + fades
     2. .exit-num  → the number rises, blurs and fades
     3. .is-done   → the veil lifts, revealing the page (which staggers in)
--------------------------------------------------------------------------- */
.loader {
  position: fixed;
  inset: 0;
  z-index: 50;                     /* above everything until done */
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--fg);
  transition: opacity 450ms var(--ease-out);     /* stage 3: veil lift */
}
.loader.is-done {
  opacity: 0;
  pointer-events: none;
}
.loader__box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.4rem;
}
.loader__count {
  display: flex;
  align-items: baseline;
  font-family: var(--font-display);            /* Caleb Mono */
  font-weight: 400;
  font-size: clamp(3.5rem, 12vw, 9rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  transition: opacity 300ms var(--ease-out),
              transform 300ms var(--ease-out),
              filter 300ms var(--ease-out);
}
.loader.exit-num .loader__count {              /* stage 2: number out */
  opacity: 0;
  transform: translateY(-10px);
  filter: blur(4px);
}
.loader__pct {
  font-size: 0.34em;
  color: var(--muted);
  margin-left: 0.15em;
}
.loader__bar {
  width: min(220px, 46vw);
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  overflow: hidden;
  transform-origin: center;
  transition: opacity 260ms var(--ease-out),
              transform 260ms var(--ease-out);
}
.loader.exit-bar .loader__bar {                /* stage 1: bar retracts */
  opacity: 0;
  transform: scaleX(0);
}
.loader__fill {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.12s linear;              /* progress → linear */
}

/* ---- Full-bleed HD photo ------------------------------------------------ */
.photo {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100dvh;
  object-fit: cover;             /* fills viewport, keeps aspect */
  object-position: center;
  z-index: 0;
  transform: translateX(var(--photo-shift-x));  /* push subject right */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--photo-fade-x));
          mask-image: linear-gradient(to right, transparent 0, #000 var(--photo-fade-x));
  /* full quality: no opacity, filter, or downscale */
}

/* ---- WebGL pixelate-on-hover layer -------------------------------------- */
/* Sits directly over .photo (same box, later in DOM → paints on top). The
   <canvas> is injected inside and fills it. The canvas is opaque and renders
   the same photo, so it simply covers the <img> — which stays underneath as
   the instant LCP paint and the no-WebGL fallback. pointer-events:none keeps
   the logo/bio above clickable; hover is tracked on window. */
.photo-fx {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100dvh;
  z-index: 0;
  pointer-events: none;
  transform: translateX(var(--photo-shift-x));  /* keep canvas aligned with .photo */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--photo-fade-x));
          mask-image: linear-gradient(to right, transparent 0, #000 var(--photo-fade-x));
}
.photo-fx canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ---- Logo, top-left ----------------------------------------------------- */
.logo {
  position: fixed;
  top: var(--logo-inset);
  left: var(--logo-inset);
  z-index: 1;
  display: inline-flex;
  line-height: 0;
}
.logo__img {
  height: var(--logo-size);
  width: auto;
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.6s var(--ease-out);
  /* subtle lift so it reads on any part of the photo */
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
}
.logo__img[src] { opacity: 1; }

/* ---- Left statement ----------------------------------------------------- */
.bio {
  position: fixed;
  left: var(--logo-inset);
  top: 50%;
  transform: translateY(-50%);
  z-index: 1;
  max-width: min(35vw, 620px);       /* half the width */
  color: var(--muted);
  font-family: var(--font);          /* Inter body */
  font-weight: 500;
  font-size: clamp(1.05rem, 1.9vw, 2rem);
  line-height: 1.2;
  letter-spacing: -0.03em;
  text-wrap: pretty;
  overflow-wrap: break-word;
  text-shadow: 0 1px 18px rgba(0, 0, 0, 0.55);   /* legible over the photo */
}
.bio__line { margin: 0; }
.bio__line + .bio__line { margin-top: 0.55em; }

/* highlighted names — Caleb Mono, white. As links: no underline at rest,
   amber + underline on hover/focus. */
.bio .hl {
  font-family: var(--font-display);
  font-style: normal;
  color: white;
  letter-spacing: 0;
}
a.hl {
  text-decoration: none;
  transition: color 180ms ease;   /* hover/color → ease */
}
a.hl:hover,
a.hl:focus-visible {
  color: var(--accent);   /* amber on hover, no underline */
}
a.hl:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, #fff);
  outline-offset: 3px;
  border-radius: 2px;
}

/* fade-in once populated */
.bio { opacity: 0; transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1); }
.bio.is-ready { opacity: 1; }

/* ---- Contact, bottom-right ---------------------------------------------- */
.contact {
  position: fixed;
  right: var(--logo-inset);
  bottom: var(--logo-inset);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3em;
  width: max-content;              /* size to the longest line, don't collapse */
  max-width: calc(100vw - 2 * var(--logo-inset));
  text-align: right;
  font-family: var(--font-display);              /* Caleb Mono, like the names */
  font-size: clamp(0.8rem, 1vw, 0.95rem);
  letter-spacing: 0;
  text-shadow: 0 1px 18px rgba(0, 0, 0, 0.55);   /* legible over the photo */
}
.contact__item {
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color 180ms ease;
}
.contact__item:hover,
.contact__item:focus-visible { color: var(--accent); }
.contact__item:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 60%, #fff);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---- Credentials, bottom-left ------------------------------------------- */
.credo {
  position: fixed;
  left: var(--logo-inset);
  bottom: var(--logo-inset);
  z-index: 1;
  margin: 0;
  max-width: min(40ch, 32vw);
  color: var(--muted);
  font-family: var(--font);                        /* Inter body */
  font-weight: 400;
  font-size: clamp(0.72rem, 0.82vw, 0.82rem);
  line-height: 1.45;
  letter-spacing: -0.005em;
  text-wrap: pretty;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.55);     /* legible over the photo */
  opacity: 0.82;
}

/* ---- Entrance choreography (after the loader lifts) ---------------------
   The page sits behind the opaque loader while it counts. When the loader
   reaches 100% it plays its staged exit (bar → number → veil) and adds
   `is-loaded` to <body>; the content then settles in, staggered. Everything
   here is transform + opacity only (GPU), with the strong --ease-out curve. */

/* Photo backdrop fades + unblurs in as the veil lifts. */
.photo,
.photo-fx {
  transition: opacity 800ms var(--ease-out), filter 800ms var(--ease-out);
}
body:not(.is-loaded) .photo,
body:not(.is-loaded) .photo-fx {
  opacity: 0;
  filter: blur(6px);
}

/* Foreground elements rise + fade in, staggered. */
@keyframes fx-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fx-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.is-loaded .logo__img,
.is-loaded .bio__line,
.is-loaded .credo,
.is-loaded .contact__item {
  animation: fx-rise 560ms var(--ease-out) both;
}
.is-loaded .logo__img              { animation-delay: 40ms; }
.is-loaded .bio__line:nth-child(1) { animation-delay: 120ms; }
.is-loaded .bio__line:nth-child(2) { animation-delay: 170ms; }
.is-loaded .credo                  { animation-delay: 230ms; }
.is-loaded .contact__item:nth-child(1) { animation-delay: 280ms; }
.is-loaded .contact__item:nth-child(2) { animation-delay: 320ms; }

/* Reduced motion: keep the reveal, drop the movement + blur. */
@media (prefers-reduced-motion: reduce) {
  .loader__fill { transition: none; }
  .loader__bar,
  .loader__count { transition: opacity 220ms ease; }
  .loader.exit-bar .loader__bar { transform: none; }
  .loader.exit-num .loader__count { transform: none; filter: none; }

  .photo,
  .photo-fx { transition: opacity 500ms ease; }
  body:not(.is-loaded) .photo,
  body:not(.is-loaded) .photo-fx { filter: none; }

  .is-loaded .logo__img,
  .is-loaded .bio__line,
  .is-loaded .credo,
  .is-loaded .contact__item {
    animation: fx-fade 420ms ease both;
  }
}

/* Mobile: portrait face is centered — move text to the lower third,
   full width, so it never sits on the face. */
@media (max-width: 720px) {
  :root { --photo-shift-x: 0%; --photo-fade-x: 0px; }   /* portrait centered, no edge fade on mobile */
  .bio {
    top: auto;
    bottom: clamp(28px, 8vh, 64px);
    transform: none;
    left: var(--logo-inset);
    right: auto;
    width: calc(100vw - 2 * var(--logo-inset));
    max-width: none;
    font-size: clamp(1.05rem, 4.6vw, 1.35rem);
  }
  /* bio takes the bottom → move contact up to the logo row (top-right) */
  .contact {
    top: var(--logo-inset);
    bottom: auto;
  }
  /* no room for the credentials line on mobile — hide it */
  .credo { display: none; }
}
