/* =================================================================
   WEIRD WITH CODE — light system ("quiet gallery" register)
   Near-white ground, micro type, media-forward. Replaces the dark
   system; same filename so all pages pick it up without edits.
   ================================================================= */

:root {
  --paper:  #fafafa;
  --ink:    #141414;
  --dim:    #8a8a86;
  --faint:  #d9d9d5;
  --line:   rgba(20, 20, 20, 0.12);
  --pad:    clamp(18px, 3.5vw, 48px);
  --ease:   cubic-bezier(0.25, 1, 0.3, 1);
  --mono:   'Barlow', system-ui, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { background: var(--paper); }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: 'Barlow', system-ui, sans-serif;
  font-weight: 400;
  font-size: 13px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: var(--ink); color: var(--paper); }
::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--faint); }

/* =================================================================
   MICRO TYPE UTILITIES
   ================================================================= */

.uv-micro {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--dim);
}
.uv-num { font-variant-numeric: tabular-nums; }

/* =================================================================
   PRELOADER — counter that runs 00→100, then the veil lifts
   ================================================================= */

#uv-veil {
  position: fixed; inset: 0; z-index: 5000;
  background: var(--paper);
  display: flex; align-items: flex-end; justify-content: flex-end;
  padding: var(--pad);
  transition: transform 0.9s var(--ease);
}
#uv-veil.up { transform: translateY(-101%); }
#uv-count {
  font-size: 11px; letter-spacing: .12em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
html.uv-loading { overflow: hidden; }

/* =================================================================
   HEADER — four corners, fixed, tiny
   ================================================================= */

.uv-head {
  position: fixed; top: 0; left: 0; z-index: 2100;  /* above the contact overlay */
  display: flex; gap: 3px;
  padding: 6px;
}
.uv-head a, .uv-head button {
  font-family: inherit; font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim); text-decoration: none;
  background: rgba(250, 250, 250, 0.88);
  border: 1px solid var(--faint);
  cursor: pointer;
  display: flex; align-items: flex-end;
  min-height: 64px; min-width: 128px;
  padding: 10px 40px 10px 12px;
  transition: color .3s, border-color .3s;
}
.uv-head a:hover, .uv-head button:hover { color: var(--ink); border-color: var(--dim); }
.uv-mark { color: var(--ink) !important; font-weight: 500; min-width: 210px !important; }
.uv-mark sup { font-size: 7px; vertical-align: super; }
.uv-nav { display: contents; }
.uv-nav .now { color: var(--ink); pointer-events: none; }

/* =================================================================
   REVEALS — soft fade, barely any travel
   ================================================================= */

[data-rise] {
  opacity: 0; transform: translate3d(0, 14px, 0);
  transition: opacity 1.1s var(--ease), transform 1.1s var(--ease);
  transition-delay: var(--d, 0ms);
}
[data-rise].wc-in { opacity: 1; transform: none; }

/* =================================================================
   MOUSE-TRAIL IMAGES (homepage intro)
   ================================================================= */

.uv-trail-img {
  position: fixed; z-index: 30;
  width: clamp(150px, 17vw, 260px); aspect-ratio: 4 / 3;
  object-fit: cover; pointer-events: none;
  transform: translate(-50%, -50%) scale(0.7);
  opacity: 0;
  transition: transform .7s var(--ease), opacity .7s var(--ease);
}
.uv-trail-img.live { transform: translate(-50%, -50%) scale(1); opacity: 1; }
.uv-trail-img.gone { transform: translate(-50%, -50%) scale(0.94); opacity: 0; }

/* =================================================================
   PROJECT FEED — one large centred media per project
   ================================================================= */

.uv-feed {
  display: flex; flex-direction: column;
  gap: clamp(60px, 12vh, 140px);
  padding: clamp(40px, 8vh, 90px) 0 clamp(80px, 14vh, 160px);
}
.uv-item {
  display: block; width: min(72vw, 880px);
  margin: 0 auto; text-decoration: none; color: inherit;
}
.uv-item-media {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 10; background: #eeeeec;
}
.uv-item-media img {
  position: absolute; inset: -6% 0;
  width: 100%; height: 112%; object-fit: cover; display: block;
  filter: grayscale(0.15);
  transition: filter .8s var(--ease), transform 1.2s var(--ease);
  will-change: transform;
}
.uv-item:hover .uv-item-media img { filter: none; transform: scale(1.025); }
.uv-item-cap {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-top: 10px;
}
.uv-item-cap .t { font-size: 12px; letter-spacing: .02em; }
.uv-item-cap .m {
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim); font-variant-numeric: tabular-nums;
}

/* =================================================================
   INDEX LIST (works page) — hairline rows, hover dims siblings
   ================================================================= */

.uv-list { border-top: 1px solid var(--line); }
.uv-list:hover .uv-row:not(:hover) { opacity: .35; }
.uv-row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) minmax(0, .7fr) 190px;
  gap: clamp(10px, 2vw, 28px);
  align-items: baseline;
  padding: 13px var(--pad);
  border-bottom: 1px solid var(--line);
  text-decoration: none; color: var(--ink);
  transition: opacity .45s var(--ease);
}
.uv-row .n {
  font-size: 10px; letter-spacing: .1em; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.uv-row .t { font-size: clamp(14px, 1.6vw, 19px); letter-spacing: .01em; }
.uv-row .g {
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim);
}
.uv-row .y {
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim); text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Hover media that trails the pointer over the list */
#wc-peek {
  position: fixed; top: 0; left: 0; z-index: 40;
  width: clamp(190px, 20vw, 300px); aspect-ratio: 4 / 3;
  overflow: hidden; pointer-events: none;
  opacity: 0; will-change: transform;
  transition: opacity .35s linear;
}
#wc-peek.on { opacity: 1; }
#wc-peek img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* =================================================================
   CONTACT OVERLAY
   ================================================================= */

#uv-overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: var(--paper);
  display: flex; flex-direction: column;
  padding: var(--pad);
  transform: translateY(101%);
  transition: transform .8s var(--ease);
  visibility: hidden;
}
#uv-overlay.open { transform: none; visibility: visible; }
body.uv-contact .uv-head button[data-overlay-open] { color: var(--ink); }
.uv-ov-top {
  display: flex; gap: 18px; align-items: baseline;
  /* clear the fixed header, which stays visible above the overlay */
  padding-top: 86px;
}
.uv-ov-close {
  font-family: inherit; font-size: 11px; letter-spacing: .06em;
  background: none; border: 0; cursor: pointer; color: var(--ink);
  transition: opacity .3s;
}
.uv-ov-close:hover { opacity: .4; }
.uv-ov-mid {
  flex: 1; display: flex; flex-direction: column;
  justify-content: center; gap: 8px;
}
.uv-ov-mid a {
  font-size: clamp(24px, 5vw, 56px); letter-spacing: -.015em;
  color: var(--ink); text-decoration: none; line-height: 1.15;
  transition: opacity .3s;
}
.uv-ov-mid a:hover { opacity: .4; }
.uv-ov-foot {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim);
}

/* =================================================================
   FOOTER
   ================================================================= */

.uv-foot {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 14px;
  padding: 26px var(--pad);
  border-top: 1px solid var(--line);
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim);
}
.uv-foot a { color: inherit; text-decoration: none; transition: color .3s; }
.uv-foot a:hover { color: var(--ink); }

/* =================================================================
   LEGACY CLASS BRIDGE
   Old dark-system class names still present in rebuilt pages get a
   quiet neutral rendering rather than a broken one.
   ================================================================= */

.wc-lines .wc-line { display: block; overflow: hidden; padding-bottom: .14em; margin-bottom: -.14em; }
.wc-lines .wc-line > i {
  display: block; font-style: inherit;
  transform: translate3d(0, 112%, 0);
  transition: transform 1.1s var(--ease);
  transition-delay: var(--d, 0ms);
}
.wc-lines.wc-in .wc-line > i { transform: none; }

/* =================================================================
   RESPONSIVE + ACCESSIBILITY
   ================================================================= */

@media (max-width: 860px) {
  .uv-row { grid-template-columns: 32px minmax(0, 1fr) 66px; }
  .uv-row .g { display: none; }
  .uv-item { width: min(88vw, 880px); }
  .uv-nav { gap: 14px; }
}

a:focus-visible, button:focus-visible {
  outline: 1px solid var(--ink); outline-offset: 3px;
}

@media (hover: none) {
  #wc-peek, .uv-trail-img { display: none !important; }
  .uv-list:hover .uv-row:not(:hover) { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  [data-rise], .wc-lines .wc-line > i {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
  #uv-veil { display: none !important; }
  html.uv-loading { overflow: auto !important; }
  .uv-trail-img, #wc-peek { display: none !important; }
  #uv-overlay { transition: none; }
  .uv-item-media img { transition: none; transform: none !important; }
}


/* =================================================================
   3D PROJECT DECK (homepage overview)
   Cascading tilted panes receding into depth; scrub with wheel or
   drag, parallax with the mouse, hover flattens a pane forward.
   ================================================================= */

.uv-stage {
  position: fixed; inset: 0; overflow: hidden;
  /* A long perspective keeps every pane's vertical edges vertical.
     At 2100px the stack keystoned badly: panes far from the vanishing
     point sheared into leaning parallelograms. */
  perspective: 9500px; perspective-origin: 50% 46%;
}
.uv-deck {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  will-change: transform;
}
:root { --cardw: clamp(450px, 50vw, 500px); }
/* Phones: a 450px minimum is wider than the whole screen. */
@media (max-width: 700px) {
  :root { --cardw: clamp(160px, 62vw, 300px); }
}
.uv-card {
  /* Browser hit-testing on deep preserve-3d stacks proved unreliable
     (only the front panes ever received events). The deck does its own
     geometric hit-testing, so panes never intercept the pointer. */
  pointer-events: none;
  position: absolute; top: 50%; left: 50%;
  /* Each pane picks one of three frame ratios; JS sets --cw / --ch. */
  width: var(--cw, var(--cardw));
  height: var(--ch, var(--cardw));
  margin: calc(var(--ch, var(--cardw)) / -2) 0 0 calc(var(--cw, var(--cardw)) / -2);
  /* will-change: opacity would force this element to flatten, which
     collapses the slab's 3D side faces into the sheet's plane. */
  will-change: transform;
  cursor: pointer;
  /* The pane IS a sheet of glass: the image runs edge to edge and the
     glass reads as a thin bright rim, a bevel and a specular sweep.
     No white frame, no fill. */
  --frame: 0px;
  --thick: 11px;   /* glass slab thickness */
  background: rgba(255, 255, 255, 0.04);
  border: none;
  border-radius: 2px;
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.95),    /* top edge, lit */
    inset 1.5px 0 0 rgba(255, 255, 255, 0.70),    /* leading edge, lit */
    inset -1px 0 0 rgba(255, 255, 255, 0.40),
    inset 0 -1px 0 rgba(255, 255, 255, 0.32),
    0 18px 40px rgba(20, 20, 20, 0.10);           /* contact shadow */
  transform-style: preserve-3d;
}
/* Physical edge of the slab: a second face pushed back in Z so the
   pane has real depth when the deck rotates. */
.uv-card::before {
  content: ''; position: absolute; inset: 0;
  border-radius: 2px;
  background: linear-gradient(120deg,
    rgba(226, 236, 240, .30), rgba(255,255,255,.14) 45%, rgba(226, 236, 240, .24));
  box-shadow: 0 0 0 1px rgba(255,255,255,.22);
  transform: translateZ(calc(var(--thick) * -1));
  pointer-events: none;
}
.uv-card img {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
}
/* Glass is translucent: panes behind show through the ones in front,
   exactly as overlapping sheets do. */
.uv-card img.uv-sharp { opacity: .88; }
.uv-card img.uv-blur { display: none; }

.uv-card { visibility: hidden; }
.uv-card.ready { visibility: visible; }
.uv-card img {
  object-fit: cover; display: block;
  border-radius: 2px;
  backface-visibility: hidden;
}
/* Native image/link dragging starts a browser drag that CANCELS the
   pointer gesture, killing click detection. Disable it entirely. */
.uv-card, .uv-card img {
  -webkit-user-drag: none;
  user-select: none;
}
.uv-card::after { /* specular sweep + rim light across the sheet */
  content: ''; position: absolute; inset: 0;
  border-radius: 2px;
  background:
    linear-gradient(118deg,
      rgba(255,255,255,0) 26%, rgba(255,255,255,.30) 42%,
      rgba(255,255,255,.06) 49%, rgba(255,255,255,0) 60%),
    linear-gradient(245deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 9%),
    rgba(250, 250, 250, var(--haze, 0));
  pointer-events: none;
}

/* The slab's side face: a real quad standing perpendicular to the
   sheet, extending backwards from its right edge. With the deck's
   left-facing tilt this edge is turned toward the viewer, so the pane
   reads as a solid piece of glass with measurable thickness. */
.uv-edge {
  position: absolute; top: 0; right: 0;
  width: var(--thick); height: 100%;
  transform-origin: 100% 50%;
  transform: rotateY(-90deg);
  background: linear-gradient(180deg,
    rgba(255,255,255,.92), rgba(214,228,234,.55) 35%,
    rgba(198,214,222,.45) 70%, rgba(255,255,255,.72));
  box-shadow: inset 0 0 6px rgba(255,255,255,.55);
  pointer-events: none;
}
/* Bottom face, catching the same light — visible on the lower panes */
.uv-edge-b {
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: var(--thick);
  transform-origin: 50% 100%;
  transform: rotateX(90deg);
  background: linear-gradient(90deg,
    rgba(255,255,255,.70), rgba(206,220,228,.42) 50%, rgba(255,255,255,.60));
  pointer-events: none;
}

/* Hover popup: small card that trails the cursor */
.uv-caption {
  position: fixed; top: 0; left: 0; z-index: 960;
  background: rgba(250,250,250,.92);
  border: 1px solid var(--faint);
  padding: 7px 11px;
  font-size: 10px; letter-spacing: .06em; color: var(--ink);
  white-space: nowrap;
  opacity: 0; transition: opacity .25s;
  pointer-events: none; will-change: transform;
}
.uv-caption .yr { color: var(--dim); margin-left: 9px; letter-spacing: .12em; }
.uv-caption.on { opacity: 1; }

/* Overview / Index switch, bottom-right */
.uv-switch {
  position: fixed; right: var(--pad); bottom: 16px; z-index: 950;
  display: flex; gap: 18px;
  background: rgba(250,250,250,.88);
  padding: 8px 12px;
}
.uv-switch button {
  font-family: inherit; font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; background: none; border: 0;
  color: var(--dim); cursor: pointer; padding: 0;
  transition: color .3s;
}
.uv-switch button.on { color: var(--ink); }
.uv-switch button:hover { color: var(--ink); }

/* Index view on the homepage */
.uv-home-index { display: none; padding-top: 96px; }
body.mode-index .uv-home-index { display: block; }
body.mode-index .uv-stage, body.mode-index .uv-caption { display: none; }
body.mode-overview { overflow: hidden; }

@media (max-width: 860px) {
  .uv-head {
    flex-wrap: wrap; right: 0;      /* bound the width, or it overflows */
    box-sizing: border-box; width: 100%;
    gap: 2px;
  }
  .uv-head a, .uv-head button {
    min-height: 40px; min-width: 0;
    flex: 1 1 0;                    /* equal shares of one row */
    padding: 8px 6px;
    font-size: 9px; letter-spacing: .08em;
    align-items: center; justify-content: center;
    text-align: center;
  }
  .uv-mark {
    min-width: 100% !important; flex: 1 1 100%;
    justify-content: flex-start; text-align: left;
    padding-left: 10px;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Only reduced-motion falls back to the list. Touch keeps the deck:
     drag and tap are the core interactions; hover (the slide-out) is
     an enhancement that simply does not apply on a finger. */
  .uv-stage, .uv-switch, .uv-caption { display: none !important; }
  .uv-home-index { display: block !important; }
  body.mode-overview { overflow: auto !important; }
}

/* Touch: the browser must not pan/zoom while a drag scrubs the deck. */
.uv-stage { touch-action: none; }

@media (hover: none) {
  /* No hover, so the popup cannot follow a cursor: pin the front
     pane's name and year to the bottom-left instead. */
  .uv-caption {
    left: var(--pad) !important; right: auto;
    top: auto !important; bottom: 58px;
    transform: none !important;
  }
}
