/* ==========================================================================
   Sujin Kim — portfolio
   Desktop layout, reference width 1440px, stable from ~1280px to ~1920px.
   ========================================================================== */

@font-face {
  font-family: "Le Murmure";
  src: url("../assets/fonts/le-murmure.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Iosevka Charon";
  src: url("../assets/fonts/iosevka-charon-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Iosevka Charon";
  src: url("../assets/fonts/iosevka-charon-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Iosevka Charon";
  src: url("../assets/fonts/iosevka-charon-medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Iosevka Charon";
  src: url("../assets/fonts/iosevka-charon-medium-italic.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Fonts */
  --font-display: "Le Murmure", "Bodoni Moda", "Didot", serif;
  --font-script: "vivaldi-mn", "Apple Chancery", "URW Chancery L", serif;
  --font-mono: "Iosevka Charon", "Iosevka", ui-monospace, "SF Mono", monospace;
  --font-body: "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

  /* Colors */
  --bg-landing-top: #6983a2;
  --bg-landing-bottom: #7694b1;
  --bg-experience: #f4f0e8;
  --red: #e23b32;

  /* Grain (landing) */
  --grain-opacity: 0.32;
  --grain-size: 180px;

  /* Layout unit: 1px at the 1440×900 reference, scaled to the viewport */
  --u: clamp(0.75px, min(100vw / 1440, 100vh / 900), 1.4px);
  --side: calc(60 * var(--u));

  /* Navigation + instructions (both sections) */
  --nav-left: var(--side);
  --nav-size: calc(24 * var(--u));
  --nav-line: calc(50 * var(--u));
  --hint-right: var(--side);
  --hint-line: calc(31 * var(--u));

  /* Shared bottom baseline: distance from the bottom of the screen to the
     baseline of the last nav item ("Contact"). The instruction and the
     contact page's dog link sit on the same baseline.
     (Iosevka Charon: a line's baseline is line-height/2 - 0.375em above
     the bottom of its line box.) */
  --bottom-baseline: calc(55 * var(--u));
  --nav-bottom: calc(var(--bottom-baseline) - var(--nav-line) / 2 + 0.375 * var(--nav-size));
  --hint-bottom: calc(var(--bottom-baseline) - var(--hint-line) / 2 + 0.375 * var(--nav-size));

  /* Tagline (landing, all sizes) */
  --tagline-top: var(--side);
  --tagline-size: var(--nav-size);

  /* Portrait layout (viewport taller than wide); only used inside
     @media (orientation: portrait). Same arrangement as desktop, re-scaled. */
  --portrait-nav-size: clamp(17px, 1.6vw + 12px, 26px); /* nav, instruction, tagline */
  --portrait-gap: calc(24 * var(--u));      /* general clearance */
  --portrait-title-top: calc(var(--tagline-top) + 2.6 * var(--tagline-size) + var(--portrait-gap)); /* top of "Su - Jin" */
  --portrait-hands-width: 180vw;            /* width of the hand canvas (hand scale) */
  --portrait-hands-optical-y: 62%;          /* where the cupped palms sit */
  --portrait-jewel-gap: calc(3 * var(--portrait-gap)); /* min gap: "[receive - treasure]" -> top of the jewels */

  /* Screen transition (landing <-> experience).
     The visual style is chosen with data-transition on <body>. */
  --screen-duration: 700ms;
  --screen-easing: cubic-bezier(0.45, 0, 0.2, 1);

  /* Hands, placed inside the composition. Units are artwork pixels of the
     3840-wide reference composition (the 16:9 stage the title is set on).
     The hand PNGs share one 3840×2160 canvas; --hand-x/--hand-y put that
     canvas where it sits relative to the title in the reference mockup. */
  --hand-x: 18;
  --hand-y: 528;
  --hand-offset-y: 0;     /* extra vertical nudge, artwork px (+ = down) */
  --hand-content-bottom: 2140; /* lowest pearl on the hand canvas */
  --hand-palm-x: 1902;         /* centre of the cupped palms on the hand canvas */
  --hand-palm-y: 900;
  --hand-jewel-top: 167;       /* highest jewel under the title (the crystal) */
  --hand-jewel-left: 866;      /* outermost flower on the left ... */
  --hand-jewel-right: 2829;    /* ... and on the right */

  /* HAND SIZE (landscape). 1 = the size in the reference mockup.
     Both hand layers grow together around the palm point; the title keeps
     its size. */
  --hand-scale: 1.45;

  /* The hands stop growing before the flowers reach the navigation or the
     instruction: this is the gap that is always kept (cap by viewport width). */
  --hand-clear-x: calc(24 * var(--u));
  --hand-nav-width: calc(3.9 * var(--nav-size));   /* "Portfolio" */
  --hand-hint-width: calc(6.6 * var(--nav-size));  /* "scroll down for" */

  /* Title vs. revealed jewels: gap kept under "[receive - treasure]", and
     how close the title may move up towards the tagline to make room. */
  --title-clear: calc(14 * var(--u));
  --title-min-gap: calc(20 * var(--u));
  --title-bottom-share: 0.167; /* bottom of "[receive - treasure]" / stage width */

  /* Optical centring: where the cupped palms sit, as a share of the viewport
     height. Pearls may run past the bottom. If the jewels would reach the
     title, the title first moves up, then the palms move down. */
  --hands-optical-y: 60%;

  /* Landing composition block: title group + hands at the reference size.
     Its size sets the scale (contain) and so the title size; it does not
     change with --hand-scale. */
  --comp-width: 2072;   /* symmetric around the centre axis, covers jewels + title */
  --comp-top: 137;      /* top of "Su - Jin" */
  --comp-bottom: calc(var(--hand-y) + var(--hand-offset-y) + var(--hand-content-bottom));
  --comp-pad-y: 5vh;    /* breathing room above and below the block */
  --comp-reserve-x: calc(220 * var(--u)); /* keeps clear of nav and instruction */
  --landing-scale: 1;     /* multiplier on the fitted size */
  --landing-offset-y: 0px; /* nudge the whole block up (-) or down (+) */

  /* Artwork px -> screen px (derived, do not edit) */
  --comp-fit: min(
    (100vw - 2 * var(--comp-reserve-x)) / var(--comp-width),
    (100vh - 2 * var(--comp-pad-y)) / (var(--comp-bottom) - var(--comp-top))
  );
  --art-px: calc(var(--comp-fit) * var(--landing-scale));
  --stage-width: calc(3840 * var(--art-px));

  /* Hand canvas width on screen (derived, do not edit): the chosen size,
     capped so the flowers keep --hand-clear-x from the nav and the instruction */
  --hands-width: min(
    var(--hand-scale) * var(--stage-width),
    (50vw - var(--nav-left) - var(--hand-nav-width) - var(--hand-clear-x)) * 3840 / (var(--hand-palm-x) - var(--hand-jewel-left)),
    (50vw - var(--hint-right) - var(--hand-hint-width) - var(--hand-clear-x)) * 3840 / (var(--hand-jewel-right) - var(--hand-palm-x))
  );
  /* stage top -> palms, at the reference size */
  --palm-ref: calc((var(--hand-y) + var(--hand-offset-y) + var(--hand-palm-y)) * var(--art-px));
  /* stage top -> palms, needed for the jewels to clear the title */
  --palm-clear: calc(
    var(--title-bottom-share) * var(--stage-width) + var(--title-clear)
    + (var(--hand-palm-y) - var(--hand-jewel-top)) / 3840 * var(--hands-width)
  );
  /* highest the stage (title) may sit: title top stays under the tagline */
  --stage-top-min: calc(
    var(--tagline-top) + 1.3 * var(--tagline-size) + var(--title-min-gap) - var(--comp-top) * var(--art-px)
  );

  /* Hand reveal */
  --reveal-radius: calc(var(--hands-width) * 0.15); /* outer radius, follows the hand size */
  --reveal-feather: 72%;      /* share of the radius that fades out */
  --reveal-trail-scale: 0.72; /* size of the trailing blob */

  /* Title composition */
  --title-top: 4.2cqw;
  --title-center: 50.35%;
  --title-size: 11.9cqw;
  --script-size: 2.8cqw;
  --script-top: 8.1cqw;
  --script-left-end: 37.1%;  /* right edge of "designer" */
  --script-right-start: 63.35%; /* left edge of "portfolio" */
  --meaning-top: 14.95cqw;
  --meaning-left: 37.9%;
  --meaning-right: 61.7%;
  --meaning-size: 1.75cqw;
  --meaning-tracking: 0.22em;

  /* Experience */
  --exp-title-top: calc(112 * var(--u));
  --exp-title-size: calc(127 * var(--u));
  --timeline-top: calc(326 * var(--u));
  --timeline-dot: calc(8 * var(--u));
  --timeline-dot-active: calc(16 * var(--u));
  --timeline-label-gap: calc(31 * var(--u));
  --timeline-label-size: calc(13 * var(--u));
  --detail-top: calc(438 * var(--u));
  --detail-title-size: calc(40 * var(--u));
  --detail-body-size: calc(19.25 * var(--u));
  --detail-body-line: calc(30 * var(--u));

  /* Contact page (colours inverted from the landing) */
  --contact-bg: var(--red);
  /* Contact text blue: saturated sky blue in the landing blue's hue family
     (2.54:1 against --red) */
  --contact-blue: #99ccff;
  --contact-weight: 500;          /* Medium, for small-text legibility */
  --contact-text: var(--contact-blue);
  --contact-size: var(--nav-size);
  --contact-line: var(--nav-line);
  --contact-services-line: var(--hint-line);
  --contact-strong-weight: 700;
  --contact-top: calc(331 * var(--u));       /* first text row */
  --contact-base-top: calc(517 * var(--u));  /* "Based in Toronto" row */
  --contact-dog-size: calc(24.6 * var(--u));

  /* Dog easter egg */
  --dog-size: 130px;    /* width of the photo that follows the cursor */
  --dog-swap-ms: 200;   /* ms between photos */

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

/* ---------- Base ---------- */

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

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

html,
body {
  height: 100%;
  overflow: hidden;
}

body {
  margin: 0;
  background: var(--bg-experience);
  color: var(--red);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, p, ol, ul {
  margin: 0;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

a:focus-visible,
button:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 4px;
}

/* Desktop: keep the layout from collapsing on narrow landscape windows */
@media (orientation: landscape) {
  body {
    min-width: 1024px;
  }
}

/* ---------- Shared: navigation + instructions ---------- */

.side-nav {
  position: absolute;
  left: var(--nav-left);
  bottom: var(--nav-bottom);
  z-index: 5;
  display: flex;
  flex-direction: column;
  font-family: var(--font-mono);
  font-size: var(--nav-size);
  line-height: var(--nav-line);
}

.side-nav a {
  align-self: flex-start;
  transition: opacity 0.2s var(--ease);
}

.side-nav a:hover {
  opacity: 0.6;
}

/* current page */
.side-nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: currentColor;
}

.hint {
  position: absolute;
  right: var(--hint-right);
  bottom: var(--hint-bottom);
  z-index: 5;
  font-family: var(--font-mono);
  font-size: var(--nav-size);
  line-height: var(--hint-line);
  text-align: right;
}

/* Landing only: nav and instruction are vertically centred */
.landing .side-nav,
.landing .hint {
  top: 50%;
  bottom: auto;
  transform: translateY(-50%);
}

/* ---------- Screens + transitions ---------- */

/* Each section is a full-viewport screen; only one is active. */
.screen {
  position: fixed;
  inset: 0;
  overflow: hidden;
  visibility: hidden;
  z-index: 0;
}

.screen:focus {
  outline: none;
}

.screen.is-active {
  visibility: visible;
  z-index: 1;
}

.screen.is-leaving {
  visibility: visible;
  z-index: 1;
}

.screen.is-entering {
  visibility: visible;
  z-index: 2;
}

/* Transition: crossfade.
   The incoming screen fades in over the outgoing one (which stays opaque),
   so there is no dip through the page background.
   To add another style (e.g. a curtain wipe), add a [data-transition="name"]
   block that animates .is-entering / .is-leaving, and set the attribute on <body>. */
[data-transition="crossfade"] .screen.is-entering {
  animation: screen-fade-in var(--screen-duration) var(--screen-easing) both;
}

@keyframes screen-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ---------- Landing ---------- */

.landing {
  background: linear-gradient(180deg, var(--bg-landing-top) 0%, var(--bg-landing-bottom) 100%);
}

/* Grain: SVG noise generated in CSS, above everything, never interactive */
.landing::after,
.contact::after,
.pf-sidebar::after,
.lightbox__backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1 0 0 0 -.2 1 0 0 0 -.2 1 0 0 0 -.2 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: var(--grain-size) var(--grain-size);
}

/* The 16:9 reference composition the title is set on; horizontally centred.
   Everything in the title is sized in cqw (1cqw = 1% of the stage width).
   Vertically the palms sit at --hands-optical-y. When larger hands would put
   the jewels under the title, the stage (title) moves up, at most to
   --stage-top-min; past that the hands sit lower instead. */
.landing__stage {
  position: absolute;
  left: 50%;
  top: calc(
    min(
      var(--hands-optical-y) - var(--palm-ref),
      max(var(--stage-top-min), var(--hands-optical-y) - var(--palm-clear))
    )
    + var(--landing-offset-y)
  );
  width: var(--stage-width);
  aspect-ratio: 16 / 9;
  transform: translateX(-50%);
  container-type: inline-size;
}

/* Both hand images share one box: same position, size, scale, transform.
   Only the jewel layer's mask moves. The box is --hands-width wide and placed
   by its palm point: on the stage's centre axis, below the title. */
.hands {
  position: absolute;
  left: calc(
    (var(--hand-x) + var(--hand-palm-x)) * var(--art-px)
    - var(--hand-palm-x) / 3840 * var(--hands-width)
  );
  top: calc(
    max(var(--palm-ref), var(--palm-clear))
    - var(--hand-palm-y) / 3840 * var(--hands-width)
  );
  width: var(--hands-width);
  aspect-ratio: 3840 / 2160;
  z-index: 1;
}

.hands__layer {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  user-select: none;
  -webkit-user-drag: none;
}

.hands__layer--jewel {
  /* Set by js/reveal.js */
  --rx: 50%;
  --ry: 50%;
  --ra: 0;
  --tx: 50%;
  --ty: 50%;
  --ta: 0;
  --rr: var(--reveal-radius);

  --reveal-core: calc(100% - var(--reveal-feather));
  --reveal-mask:
    radial-gradient(
      circle var(--rr) at var(--rx) var(--ry),
      rgb(0 0 0 / var(--ra)) 0%,
      rgb(0 0 0 / var(--ra)) var(--reveal-core),
      rgb(0 0 0 / calc(var(--ra) * 0.72)) calc(var(--reveal-core) + var(--reveal-feather) * 0.3),
      rgb(0 0 0 / calc(var(--ra) * 0.36)) calc(var(--reveal-core) + var(--reveal-feather) * 0.58),
      rgb(0 0 0 / calc(var(--ra) * 0.1)) calc(var(--reveal-core) + var(--reveal-feather) * 0.82),
      rgb(0 0 0 / 0) 100%
    ),
    radial-gradient(
      circle calc(var(--rr) * var(--reveal-trail-scale)) at var(--tx) var(--ty),
      rgb(0 0 0 / var(--ta)) 0%,
      rgb(0 0 0 / calc(var(--ta) * 0.55)) 45%,
      rgb(0 0 0 / calc(var(--ta) * 0.15)) 78%,
      rgb(0 0 0 / 0) 100%
    );
  -webkit-mask-image: var(--reveal-mask);
  mask-image: var(--reveal-mask);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* Area of the hands that triggers the reveal */
.hands__hit {
  position: absolute;
  left: 21%;
  top: 2%;
  width: 58%;
  height: 97%;
}

/* Title composition */
.title {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.title__name {
  position: absolute;
  top: var(--title-top);
  left: var(--title-center);
  transform: translateX(-50%);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--title-size);
  line-height: 1;
  white-space: nowrap;
  font-kerning: normal;
}

.title__script {
  position: absolute;
  top: var(--script-top);
  font-family: var(--font-script);
  font-weight: 400;
  font-style: normal;
  font-size: var(--script-size);
  line-height: 1;
  white-space: nowrap;
}

.title__script--left {
  right: calc(100% - var(--script-left-end));
}

.title__script--right {
  left: var(--script-right-start);
}

.title__meaning {
  position: absolute;
  top: var(--meaning-top);
  left: var(--meaning-left);
  width: calc(var(--meaning-right) - var(--meaning-left));
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  font-family: var(--font-script);
  font-weight: 400;
  font-size: var(--meaning-size);
  line-height: 1;
  letter-spacing: var(--meaning-tracking);
  white-space: nowrap;
}

/* Letter-spacing trails after each word's last glyph; pull it back so the
   dash sits centred and "]" lands on the right edge */
.title__meaning span {
  margin-right: calc(var(--meaning-tracking) * -1);
}

.title__meaning span:last-child {
  justify-self: end;
}

/* ---------- Experience ---------- */

.experience {
  background: var(--bg-experience);
}

.experience__title {
  position: absolute;
  top: var(--exp-title-top);
  left: var(--side);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--exp-title-size);
  line-height: 1;
  font-kerning: normal;
}

/* Timeline + open space below it: leaving this area resets the section */
.experience__zone {
  position: absolute;
  left: var(--side);
  right: var(--side);
  /* snapped to whole pixels so the 1px line stays crisp */
  top: round(calc(var(--timeline-top) - 24 * var(--u)), 1px);
  height: calc(360 * var(--u));
}

.timeline {
  position: absolute;
  left: 0;
  right: 0;
  top: round(calc(24 * var(--u)), 1px);
  height: 0;
  list-style: none;
}

/* the line */
.timeline::before {
  content: "";
  position: absolute;
  left: calc(var(--timeline-dot) / 2);
  right: calc(var(--timeline-dot) / 2);
  top: 0;
  height: 1px;
  background: currentColor;
}

.timeline__item {
  position: absolute;
  top: 0;
  left: calc((100% - var(--timeline-dot)) * var(--pos) / 100);
  width: var(--timeline-dot);
}

.timeline__year {
  /* reset */
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  padding: 0;
  cursor: default;

  /* generous invisible hit area around the dot and label */
  position: absolute;
  top: calc(-24 * var(--u));
  left: calc(-24 * var(--u));
  width: calc(var(--timeline-dot) + 48 * var(--u));
  height: calc(72 * var(--u));
  font: inherit;
}

.timeline__dot {
  position: absolute;
  top: calc(24 * var(--u) - var(--timeline-dot) / 2);
  left: calc(24 * var(--u));
  width: var(--timeline-dot);
  height: var(--timeline-dot);
  border-radius: 50%;
  background: currentColor;
  transition: transform 0.35s var(--ease);
}

.timeline__year.is-active .timeline__dot {
  transform: scale(calc(var(--timeline-dot-active) / var(--timeline-dot)));
}

.timeline__label {
  position: absolute;
  top: calc(24 * var(--u) + var(--timeline-label-gap) - 11.4 * var(--u));
  left: calc(24 * var(--u));
  font-family: var(--font-mono);
  font-size: var(--timeline-label-size);
  line-height: 1;
  white-space: nowrap;
}

.timeline__item.is-end .timeline__label {
  left: auto;
  right: calc(24 * var(--u));
}

.experience__detail {
  position: absolute;
  left: 0;
  top: calc(var(--detail-top) - var(--timeline-top) + 24 * var(--u));
  right: 0;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}

.experience__detail.is-visible {
  opacity: 1;
}

.experience__detail h3 {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--detail-title-size);
  line-height: 1.2;
  letter-spacing: -0.005em;
  word-spacing: -0.05em;
}

.experience__detail ul {
  margin-top: calc(12 * var(--u));
  list-style: none;
  font-size: var(--detail-body-size);
  line-height: var(--detail-body-line);
}

.experience__detail li {
  position: relative;
  padding-left: calc(30 * var(--u));
}

.experience__detail li::before {
  content: "";
  position: absolute;
  left: calc(12 * var(--u));
  top: calc(var(--detail-body-line) / 2 - 1 * var(--u));
  width: calc(5.5 * var(--u));
  height: calc(5.5 * var(--u));
  border-radius: 50%;
  background: currentColor;
}

/* Tagline, top centre of the landing */
.tagline {
  position: absolute;
  top: var(--tagline-top);
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  max-width: calc(100% - 2 * var(--side));
  font-family: var(--font-mono);
  font-size: var(--tagline-size);
  line-height: 1.3;
  text-align: center;
  text-wrap: balance;
  width: max-content;
}

/* ---------- Landing: portrait (tablet / mobile proportions) ----------
   Same arrangement as desktop. The title row is scaled so "designer" and
   "portfolio" touch the side margins; the hands are placed by their palm point
   (--portrait-hands-optical-y), kept clear of the title and the nav. */
@media (orientation: portrait) {
  :root {
    --nav-size: var(--portrait-nav-size);
    --nav-line: calc(var(--nav-size) * 2.08);
    --hint-line: calc(var(--nav-size) * 1.3);
    --bottom-baseline: calc(var(--nav-size) * 2.29);
    --reveal-radius: calc(var(--portrait-hands-width) * 0.15);

    /* derived, do not edit -------------------------------------------- */
    /* title block: its ink spans 28.07%–71.59% of its width, cap top at 3.65%,
       bottom of "[receive - treasure]" at 16.33% */
    --p-title-w: calc((100vw - 2 * var(--side)) / 0.4352);
    --p-title-bottom: calc(var(--portrait-title-top) + var(--p-title-w) * 0.1268);
    /* hand canvas: palms at y 900, jewels start at y 53, hands end at y 1474 */
    --p-hands-top-optical: calc(var(--portrait-hands-optical-y) - var(--portrait-hands-width) * 900 / 3840);
    --p-hands-top-nav: calc(100vh - var(--nav-bottom) - 3 * var(--nav-line) - var(--portrait-gap) - var(--portrait-hands-width) * 1474 / 3840);
    --p-hands-top-title: calc(var(--p-title-bottom) + var(--portrait-jewel-gap) - var(--portrait-hands-width) * 53 / 3840);
  }

  .landing__stage {
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    transform: none;
  }

  /* The desktop title block, re-scaled; its children keep their cqw layout */
  .title {
    inset: auto;
    left: calc(var(--side) - var(--p-title-w) * 0.2807);
    top: calc(var(--portrait-title-top) - var(--p-title-w) * 0.0365);
    width: var(--p-title-w);
    height: calc(var(--p-title-w) * 0.17);
    container-type: inline-size;
  }

  /* Both hand layers keep sharing this one box.
     Palms at the optical point, but never so low that the empty hands reach
     the nav, and never so high that the jewels touch the title (title wins). */
  .hands {
    left: calc(50% - var(--portrait-hands-width) * 1902 / 3840);
    top: max(
      min(var(--p-hands-top-optical), var(--p-hands-top-nav)),
      var(--p-hands-top-title)
    );
    width: var(--portrait-hands-width);
  }

  /* Nav and instruction in the bottom corners (revealed pearls may pass behind) */
  .landing .side-nav,
  .landing .hint {
    top: auto;
    transform: none;
  }

  .landing .side-nav {
    bottom: var(--nav-bottom);
  }

  .landing .hint {
    bottom: var(--hint-bottom);
  }
}

/* ---------- Contact page ---------- */

.contact {
  position: relative;
  height: 100vh;
  overflow: hidden;
  background: var(--contact-bg);
  color: var(--contact-text);
  font-family: var(--font-mono);
  font-weight: var(--contact-weight);
  font-size: var(--contact-size);
  line-height: var(--contact-line);
}

.contact__title {
  position: absolute;
  top: var(--exp-title-top);
  left: var(--side);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--exp-title-size);
  line-height: 1;
  font-kerning: normal;
}

.contact__left,
.contact__right {
  position: absolute;
  top: var(--contact-top);
}

.contact__left {
  left: var(--side);
}

.contact__right {
  right: var(--side);
  text-align: right;
}

.contact__services {
  margin-top: calc(9.5 * var(--u));
  line-height: var(--contact-services-line);
}

/* the bold row sits at a fixed height in both columns */
.contact__base {
  position: absolute;
  top: calc(var(--contact-base-top) - var(--contact-top));
  white-space: nowrap;
}

.contact__left .contact__base {
  left: 0;
}

.contact__right .contact__base {
  right: 0;
}

.contact__strong {
  font-weight: var(--contact-strong-weight);
}

/* content links (not the nav, which keeps the shared nav hover) */
.contact__left a,
.contact__dog a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: transparent;
  transition: text-decoration-color 0.2s var(--ease);
}

.contact__left a:hover,
.contact__left a:focus-visible,
.contact__dog a:hover,
.contact__dog a:focus-visible {
  text-decoration-color: currentColor;
}

/* Same line box as the last nav item (bottom, size, line-height), so its
   baseline is exactly the nav's (--bottom-baseline); the larger italic text
   sits on that baseline. */
.contact__dog {
  position: absolute;
  bottom: var(--nav-bottom);
  left: 0;
  right: 0;
  z-index: 5;
  text-align: center;
  font-style: italic;
  font-size: var(--nav-size);
  line-height: var(--nav-line);
}

.contact .dog-link {
  font-size: var(--contact-dog-size);
  line-height: 1;
  text-decoration-color: currentColor;
}

.contact .dog-link.has-dog:hover {
  cursor: none;
}

.dog-cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 10;
  width: var(--dog-size);
  height: auto;
  pointer-events: none;
  visibility: hidden;
}

.dog-cursor.is-visible {
  visibility: visible;
}

/* ---------- Page-to-page transition ----------
   Cross-document View Transitions: same crossfade as the in-page screens
   (new page fades in over the old one, --screen-duration / --screen-easing).
   Browsers without support simply navigate instantly. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: none;
}

::view-transition-new(root) {
  animation: screen-fade-in var(--screen-duration) var(--screen-easing) both;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}

/* ---------- Placeholder pages ---------- */

.placeholder {
  position: relative;
  height: 100vh;
}

.placeholder__title {
  position: absolute;
  top: var(--exp-title-top);
  left: var(--side);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--exp-title-size);
  line-height: 1;
}

.placeholder__note {
  position: absolute;
  top: calc(326 * var(--u));
  left: var(--side);
  font-family: var(--font-mono);
  font-size: var(--nav-size);
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  :root {
    --screen-duration: 0ms;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
