/* ==========================================================================
   AlwaysHere
   Type, spacing and colour are taken from Reference/O2.
   Desktop frames are 1920x1080, mobile frames 1081x1921 — every size below
   is expressed as a proportion of those, then clamped so it stays sensible
   on very small and very large screens.
   ========================================================================== */

/* --- Font --- (the site is set entirely in Untitled Sans Bold) ------------ */

@font-face {
  font-family: "Untitled Sans";
  src: url("../fonts/UntitledSans-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* --- Tokens --------------------------------------------------------------- */

:root {
  --bg: #ffffff;
  --blue: #0d1ef2;
  --grey: #d2d7d7;

  /* Untitled Sans vertical metrics, used to trim line-box leading so that
     cap-heights and baselines land exactly on the margins, as drawn. */
  --f-a: 1.002;   /* ascent  */
  --f-d: 0.247;   /* descent */
  --f-sum: 1.249; /* ascent + descent */
  --f-c: 0.714;   /* cap height */

  --edge: clamp(20px, 1.77vw, 38px);

  /* Content column: 12.5% in from the left, for the ABOUT copy. */
  --col-x: 12.5%;

  /* The four corner labels and the work list all share one size in O3. */
  --fs-corner: clamp(28px, 2.969vw, 60px); /* 57px @1920 */
  --fs-about: clamp(30px, 3.125vw, 64px); /* 60px @1920 */
  --fs-body: clamp(16px, 1.8229vw, 40px); /*  35px @1920 */

  --lh-display: 1.04;
  --lh-about: 1.06;
  --lh-body: 1.2;
  --lh-work: 0.9; /* tight leading within a wrapped project name */

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* --- Reset ---------------------------------------------------------------- */

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

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--grey);
  font-family: "Untitled Sans", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-weight: 700;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

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

button {
  font: inherit;
  color: inherit;
  /* Form controls do not inherit these from the UA stylesheet. */
  text-transform: inherit;
  letter-spacing: inherit;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: inherit;
  -webkit-tap-highlight-color: transparent;
}

a {
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 4px;
}

/* Cap-height / baseline trimming. Set --lh on the element, then this pulls
   the invisible leading off the top and bottom of the line box. */
.trim-top {
  margin-top: calc(((var(--lh) - var(--f-sum)) / 2 + (var(--f-a) - var(--f-c))) * -1em);
}
.trim-bottom {
  margin-bottom: calc(((var(--lh) - var(--f-sum)) / 2 + var(--f-d)) * -1em);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   HOME — background video and the veil that covers it
   ========================================================================== */

.home {
  height: 100%;
  overflow: hidden;
}

.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

/* One reel per project, stacked. Only the active reel is shown; the rest sit
   at opacity 0 with their playheads paused, so returning to one resumes where
   it left off rather than restarting. */
.stage__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.stage__video.is-active {
  opacity: 1;
}

/* The Open Cube motion layer sits over the reels but under the veil and the
   chrome. It is transparent, so the active reel shows through and only the
   wordmark floats in the space. It belongs to the resting home reel: when a
   project reel takes over it fades out (cube.js pauses it too), crossfading on
   the same 0.6s as the reels. It never intercepts pointer events. */
.cube {
  position: fixed;
  inset: 0;
  z-index: 5;
  overflow: hidden;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.6s var(--ease);
}
.cube.is-hidden {
  opacity: 0;
}
.cube canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* The #ffffff wash that covers the reel behind the ABOUT copy. WORK does NOT
   veil the video — the whole point is that the reel shows through and swaps
   as projects are hovered. */
.veil {
  position: fixed;
  inset: 0;
  z-index: 15;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s var(--ease);
}
body.is-about .veil {
  opacity: 1;
  transition-duration: 0.7s;
}

/* ==========================================================================
   Persistent chrome — WORK top-left, CONTACT top-right, mark bottom-left,
   ABOUT bottom-right (Reference/O3).
   ========================================================================== */

.chrome {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
}
.chrome > * {
  pointer-events: auto;
}

.corner {
  --lh: var(--lh-display);
  font-size: var(--fs-corner);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--grey);
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}
@media (hover: hover) {
  .corner:hover {
    color: var(--blue);
  }
}

.corner--work {
  position: absolute;
  top: var(--edge);
  left: var(--edge);
}
.corner--about {
  position: absolute;
  right: var(--edge);
  bottom: var(--edge);
}
body.is-work .corner--work {
  color: var(--blue);
}
body.is-about .corner--about {
  color: var(--blue);
}

/* The mark */
.mark {
  position: absolute;
  left: var(--edge);
  bottom: var(--edge);
  color: var(--blue);
  display: block;
}
.mark svg {
  height: calc(var(--fs-corner) * 1.15);
  width: auto;
}

/* CONTACT and its links share a top-right column; the links drop straight
   down out of CONTACT, right-aligned (Reference/O3 ContactSubHover). */
.nav-contact {
  position: absolute;
  top: var(--edge);
  right: var(--edge);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
}
body.is-contact .corner--contact {
  color: var(--blue);
}

.nav__links {
  --lh: var(--lh-display);
  font-size: var(--fs-corner);
  line-height: var(--lh-display);
  text-transform: uppercase;
  overflow: hidden;
  max-height: 0;
  transition: max-height 0.6s var(--ease);
  pointer-events: none;
}
body.is-contact .nav__links {
  max-height: calc(3.2 * var(--fs-corner) * var(--lh-display));
  pointer-events: auto;
}

.nav__link {
  display: block;
  color: var(--grey);
  opacity: 0;
  transform: translateY(-0.4em);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease), color 0.25s var(--ease);
}
body.is-contact .nav__link {
  opacity: 1;
  transform: none;
}
body.is-contact .nav__link:nth-child(1) { transition-delay: 0.05s, 0.05s, 0s; }
body.is-contact .nav__link:nth-child(2) { transition-delay: 0.11s, 0.11s, 0s; }
body.is-contact .nav__link:nth-child(3) { transition-delay: 0.17s, 0.17s, 0s; }
@media (hover: hover) {
  .nav__link:hover {
    color: var(--blue);
  }
}

/* ==========================================================================
   Panels — ABOUT copy and the WORK list
   ========================================================================== */

.panel {
  position: fixed;
  inset: 0;
  z-index: 20;
  pointer-events: none;
  visibility: hidden;
}
.panel.is-open {
  visibility: visible;
}

/* ABOUT ------------------------------------------------------------------- */

.about {
  padding: var(--edge) var(--edge) var(--edge) var(--col-x);
}

.about__copy {
  --lh: var(--lh-about);
  /* Wraps to roughly the reference measure at any size. */
  max-width: 18.6em;
  color: var(--blue);
  font-size: var(--fs-about);
  line-height: var(--lh-about);
  /* First line's cap-height lands on the same line as WORK. */
  margin-top: calc(((var(--lh) - var(--f-sum)) / 2 + (var(--f-a) - var(--f-c))) * -1em);
}

.about__copy p {
  margin: 0;
  /* \n in the copy becomes a real line break (the last paragraph puts each
     sentence on its own line); ordinary text still wraps normally. */
  white-space: pre-line;
  opacity: 0;
  transform: translateY(0.28em);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
}
.about__copy p + p {
  margin-top: 0.9em;
}
body.is-about .about__copy p {
  opacity: 1;
  transform: none;
}
body.is-about .about__copy p:nth-child(1) { transition-delay: 0.08s; }
body.is-about .about__copy p:nth-child(2) { transition-delay: 0.16s; }
body.is-about .about__copy p:nth-child(3) { transition-delay: 0.24s; }
body.is-about .about__copy p:nth-child(4) { transition-delay: 0.32s; }
/* Leaving is quicker, and all together — 0.5s budget. */
.about__copy p {
  transition-duration: 0.38s;
}
body:not(.is-about) .about__copy p {
  transition-delay: 0s;
}

/* WORK -------------------------------------------------------------------- */

/* The list sits under WORK at the left edge, starting one line below it. */
.work {
  height: 100%;
  padding: calc(var(--edge) + var(--fs-corner) * var(--lh-display)) 0 var(--edge) var(--edge);
}

.work__list {
  --lh: var(--lh-work);
  /* Trim the leading so the first item's cap lands exactly one line under
     WORK's cap. */
  margin: calc(((var(--lh) - var(--f-sum)) / 2 + (var(--f-a) - var(--f-c))) * -1em) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-corner);
  /* Tight leading within a project; the gap between projects is restored by
     the margin on .work__item below, so the project-to-project rhythm is
     unchanged while a wrapped name's own lines hug together. */
  line-height: var(--lh-work);
  text-transform: uppercase;
  max-height: 100%;
  overflow-y: auto;
  scrollbar-width: none;
  pointer-events: none;
  /* Locking a project slides the whole list up by an amount set inline. */
  transition: transform 0.55s var(--ease);
}
.work__list::-webkit-scrollbar {
  display: none;
}
body.is-work .work__list {
  pointer-events: auto;
}

.work__item {
  display: block;
  opacity: 0;
  transform: translateY(0.3em);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
/* Restore the gap between projects to the original one-line rhythm, so only
   the leading *within* a project has tightened. */
.work__item + .work__item {
  margin-top: calc((var(--lh-display) - var(--lh-work)) * 1em);
}
body.is-work .work__item {
  opacity: 1;
  transform: none;
}
/* Clicking a project locks it: the list slides up as one block (in JS) so the
   chosen project lands just below WORK, and the others fade out as they travel
   up with it. Hovering/clicking WORK, or clicking the chosen project again,
   reverses it. */
body.is-locked .work__item:not(.is-locked) {
  opacity: 0;
  pointer-events: none;
}

.work__btn {
  display: inline-block;
  color: var(--grey);
  /* \n in a title becomes a real line break; long lines still wrap. */
  white-space: pre-line;
  transition: color 0.25s var(--ease);
}
@media (hover: hover) {
  .work__btn:hover {
    color: var(--blue);
  }
}
/* The hovered project (video showing) and the locked project are blue. */
.work__item.is-hover .work__btn,
.work__item.is-locked .work__btn {
  color: var(--blue);
}

.work__empty {
  --lh: var(--lh-body);
  color: var(--blue);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  max-width: 40ch;
}

/* ==========================================================================
   MOBILE  — proportions from Reference/O2/Mobile (1081 x 1921 frames)
   ========================================================================== */

@media (max-width: 860px) {
  :root {
    --edge: clamp(18px, 3.7vw, 40px);

    /* Corner labels and the work list, from Reference/O3/Mobile (1081 wide). */
    --fs-corner: clamp(18px, 5vw, 54px); /* 54px @1081 */
    --fs-about: clamp(16px, 3.9vw, 42px); /* 42px @1081 */
    --fs-body: clamp(14px, 3.238vw, 26px); /* the empty-state message */
  }

  .mark svg {
    height: calc(var(--fs-corner) * 1.1);
  }

  /* On phones every reel — the project reels and the brand ident — is a true
     portrait 1080x1920, so they all fill the screen edge to edge. */
  .stage__video {
    object-fit: cover;
  }

  /* On phones the about copy sits at the bottom, above the mark and ABOUT
     (Reference/O3 AboutClicked-Mobile). */
  .about {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: var(--edge);
    padding-bottom: calc(var(--edge) + var(--fs-corner) * 1.6);
  }
  .about__copy {
    max-width: none;
    margin-top: 0;
  }

  /* The list still sits under WORK; give it room to wrap on the right. */
  .work {
    padding-right: 12%;
  }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .stage__video {
    opacity: 1;
  }
}
