/* ==========================================================================
   CC, Costina Cindea
   One stylesheet for the whole site. Sections:
   1. fonts + tokens    2. base    3. paper system (tears, notes, tape, tags)
   4. layout (collage)  5. masthead + colophon    6. pages    7. motion
   Theme: fixed dark "desk" with paper sheets on top. Radius: none, anywhere.
   ========================================================================== */

/* 1. fonts + tokens ------------------------------------------------------- */

@font-face {
  font-family: "Courier Prime";
  src: url("../fonts/courier-prime-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Courier Prime";
  src: url("../fonts/courier-prime-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Courier Prime";
  src: url("../fonts/courier-prime-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Courier Prime";
  src: url("../fonts/courier-prime-700-italic.woff2") format("woff2");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

:root {
  --ink: #0d0d0d;
  --paper: #ebe9e4;
  --paper-shade: #d8d6d0;
  --graphite: #a09e99; /* secondary text on ink, 7.4:1 */
  --pencil: #484743; /* secondary text on paper, 8.3:1 */
  --blend: #f2f1ee; /* colour used with mix-blend-mode: difference */

  --font: "Courier Prime", "Courier New", Courier, monospace;
  --t-xs: 0.75rem;
  --t-s: 0.875rem;
  --t-m: 1rem;
  --t-l: clamp(1.2rem, 1rem + 0.8vw, 1.65rem);
  --t-xl: clamp(2.1rem, 1.3rem + 3.4vw, 4.75rem);

  --edge: max(clamp(1.1rem, 4vw, 4.5rem), env(safe-area-inset-left), env(safe-area-inset-right));
  --gutter: clamp(0.75rem, 1.6vw, 1.75rem);
  --slow: cubic-bezier(0.2, 0.65, 0.1, 1);
  /* reveals: starts like --slow but settles instead of creeping for a second
     (a tilted sheet moving by sub-pixels while the page scrolls looks laggy) */
  --settle: cubic-bezier(0.33, 1, 0.68, 1);

  /* foreground / background pair, flipped on paper */
  --fg: var(--paper);
  --bg: var(--ink);

  /* z-index scale */
  --z-lift: 2;
  --z-nav: 50;
  --z-grain: 60;
}

/* 2. base ----------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--ink) url("../tex/dark.webp") 0 0 / 1200px repeat;
}
html {
  scrollbar-width: none;
}
html::-webkit-scrollbar {
  display: none;
}
html:has(.page--quiet) {
  background-image: none;
}
/* large and very large screens: scale the whole rem-based system up */
@media (min-width: 1800px) {
  html {
    font-size: 112.5%;
  }
}
@media (min-width: 2400px) {
  html {
    font-size: 131.25%;
  }
}

body {
  margin: 0;
  min-height: 100dvh;
  overflow-x: hidden; /* fallback for Safari < 16 */
  overflow-x: clip;
  font-family: var(--font);
  font-size: var(--t-m);
  line-height: 1.55;
  color: var(--paper);
  position: relative;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* film grain, never catches the pointer. Pinned to the screen on desktop;
   on touch screens it is part of the page, because Safari resizes pinned
   layers while its toolbars slide in and out, which left bare bands at the
   top and bottom of the screen. */
body::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  /* strength is baked into the texture: opacity on a page-sized layer
     costs an extra pass over the whole screen */
  background: url("../tex/grain.webp") 0 0 / 200px;
}
@media (hover: hover) and (pointer: fine) {
  body::after {
    position: fixed;
  }
}

img,
video,
svg {
  display: block;
  max-width: 100%;
}
img,
video {
  height: auto;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
  user-select: none;
}

h1,
h2,
h3,
p,
dl,
dd,
ol,
ul,
figure,
blockquote {
  margin: 0;
}
ol,
ul {
  padding: 0;
  list-style: none;
}

h1,
h2,
h3 {
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.035em;
}

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

::selection {
  background: var(--paper);
  color: var(--ink);
}

:focus-visible {
  outline: 1px dashed currentColor;
  outline-offset: 4px;
}

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

.skip {
  position: absolute;
  left: var(--edge);
  top: -10rem;
  z-index: calc(var(--z-grain) + 1);
  padding: 0.6rem 0.9rem;
  background: var(--paper);
  color: var(--ink);
  font-size: var(--t-s);
}
.skip:focus {
  top: 1rem;
}

/* tilted sheets may poke past the screen edge: clip them here (a plain
   element, so iOS can't pan sideways the way it can with body overflow) */
.page {
  position: relative;
  overflow-x: hidden; /* fallback for Safari < 16 */
  overflow-x: clip;
}
.page:focus {
  outline: none;
}

/* typed link: a plain underline; the hover is the marker below */
.typed-link {
  display: inline-block;
  padding: 0.2em 0.2em 0.15em;
  margin-inline: -0.2em;
  color: var(--fg);
  font-size: var(--t-s);
  letter-spacing: 0.04em;
  text-decoration: none;
  background: linear-gradient(var(--fg) 0 0) left bottom / 100% 1px no-repeat;
}
.typed-link:active {
  translate: 0 1px;
}

/* marker: on hover a thick felt-tip stroke is drawn across the word from
   left to right and the letters knock out of it. Black marker on paper,
   white paint marker on the dark desk. */
:root {
  --marker: var(--paper);
  --marker-text: var(--ink);
}
.on-paper,
.note,
.tag,
.masthead__nav,
.viewer__sheet {
  --marker: var(--ink);
  --marker-text: var(--paper);
}
.typed-link,
.masthead__nav a,
.tag__name a,
.contact__row dd a,
.viewer__close,
.contents__name,
.archive-index a span:last-child,
.piece__enquire {
  position: relative;
  isolation: isolate;
  transition: color 0.3s ease 0.12s;
}
.typed-link::before,
.masthead__nav a::before,
.tag__name a::before,
.contact__row dd a::before,
.viewer__close::before,
.contents__name::before,
.archive-index a span:last-child::before,
.piece__enquire::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -0.1em -1em -0.06em -0.3em;
  background: var(--marker);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.55s cubic-bezier(0.65, 0, 0.25, 1);
  pointer-events: none;
}
/* the stroke texture is only fetched where it can be seen: on hover devices
   up front (so the first hover is ready), on touch screens only for a
   keyboard focus ring. Phones save 46 KB on the first visit. */
@media (hover: hover) {
  .typed-link::before,
  .masthead__nav a::before,
  .tag__name a::before,
  .contact__row dd a::before,
  .viewer__close::before,
  .contents__name::before,
  .archive-index a span:last-child::before,
  .piece__enquire::before {
    -webkit-mask: url("../tex/marker.webp") left center / 100% 100% no-repeat;
    mask: url("../tex/marker.webp") left center / 100% 100% no-repeat;
  }
}
:is(.typed-link, .masthead__nav a, .tag__name a, .contact__row dd a, .viewer__close, .piece__enquire):focus-visible::before,
.contents a:focus-visible .contents__name::before,
.archive-index a:focus-visible span:last-child::before {
  -webkit-mask: url("../tex/marker.webp") left center / 100% 100% no-repeat;
  mask: url("../tex/marker.webp") left center / 100% 100% no-repeat;
}
:is(.typed-link, .masthead__nav a, .tag__name a, .contact__row dd a, .viewer__close, .piece__enquire):focus-visible,
.contents a:focus-visible .contents__name,
.archive-index a:focus-visible span:last-child {
  color: var(--marker-text);
}
:is(.typed-link, .masthead__nav a, .tag__name a, .contact__row dd a, .viewer__close, .piece__enquire):focus-visible::before,
.contents a:focus-visible .contents__name::before,
.archive-index a:focus-visible span:last-child::before {
  clip-path: inset(0 0 0 0);
}
@media (hover: hover) {
  :is(.typed-link, .masthead__nav a, .tag__name a, .contact__row dd a, .viewer__close, .piece__enquire):hover,
  .contents a:hover .contents__name,
  .archive-index a:hover span:last-child,
  .object:hover .tag__name a {
    color: var(--marker-text);
  }
  :is(.typed-link, .masthead__nav a, .tag__name a, .contact__row dd a, .viewer__close, .piece__enquire):hover::before,
  .contents a:hover .contents__name::before,
  .archive-index a:hover span:last-child::before,
  .object:hover .tag__name a::before {
    clip-path: inset(0 0 0 0);
  }
}

.label {
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--graphite);
}

.on-paper {
  --fg: var(--ink);
  --bg: var(--paper);
  color: var(--ink);
}
.on-paper .label {
  color: var(--pencil);
}

/* catalogue data: key / value rows */
.meta {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.3rem 1.2rem;
  font-size: var(--t-s);
  line-height: 1.45;
}
.meta dt {
  padding-top: 0.12em;
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--graphite);
}
.on-paper .meta dt {
  color: var(--pencil);
}

/* 3. paper system ---------------------------------------------------------- */

.paper {
  background: var(--paper) url("../tex/paper.webp") center / 700px;
}

/* torn photograph: the wrapper is the paper backing (outer mask), the image
   is cut a little further in (inner mask), leaving a frayed white rim. */
.tear {
  --outer: url("../tex/tear-portrait-a-outer.webp");
  --inner: url("../tex/tear-portrait-a-inner.webp");
  display: block;
  position: relative;
  overflow: hidden;
  background: var(--paper) url("../tex/paper.webp") center / 700px;
  -webkit-mask: var(--outer) center / 100% 100% no-repeat;
  mask: var(--outer) center / 100% 100% no-repeat;
}
.tear > img,
.tear > video {
  width: 100%;
  -webkit-mask: var(--inner) center / 100% 100% no-repeat;
  mask: var(--inner) center / 100% 100% no-repeat;
}
.tear--pb {
  --outer: url("../tex/tear-portrait-b-outer.webp");
  --inner: url("../tex/tear-portrait-b-inner.webp");
}
.tear--tall {
  --outer: url("../tex/tear-tall-a-outer.webp");
  --inner: url("../tex/tear-tall-a-inner.webp");
}
.tear--land {
  --outer: url("../tex/tear-land-a-outer.webp");
  --inner: url("../tex/tear-land-a-inner.webp");
}
.tear--land-b {
  --outer: url("../tex/tear-land-b-outer.webp");
  --inner: url("../tex/tear-land-b-inner.webp");
}
.tear--square {
  --outer: url("../tex/tear-square-a-outer.webp");
  --inner: url("../tex/tear-square-a-inner.webp");
}

/* scissor cut: straight but never square */
.cut {
  clip-path: polygon(0.6% 1.4%, 99.2% 0, 100% 98.2%, 0 100%);
}
.cut--b {
  clip-path: polygon(0 0, 98.6% 1.8%, 99.4% 100%, 1.2% 98.8%);
}

/* full-width tear on top and/or bottom edge. Same outer/inner idea as .tear */
.rip {
  --h: clamp(3.25rem, 7vw, 7.5rem);
  position: relative;
  background: var(--paper) url("../tex/paper.webp") center / 700px;
}
.rip--top {
  -webkit-mask:
    url("../tex/tear-edge-b-top-outer.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) bottom / 100% calc(100% - var(--h) + 1px) no-repeat;
  mask:
    url("../tex/tear-edge-b-top-outer.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) bottom / 100% calc(100% - var(--h) + 1px) no-repeat;
}
.rip--top > :is(img, video) {
  -webkit-mask:
    url("../tex/tear-edge-b-top-inner.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) bottom / 100% calc(100% - var(--h) + 1px) no-repeat;
  mask:
    url("../tex/tear-edge-b-top-inner.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) bottom / 100% calc(100% - var(--h) + 1px) no-repeat;
}
.rip--bottom {
  -webkit-mask:
    url("../tex/tear-edge-a-bottom-outer.webp") bottom / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) top / 100% calc(100% - var(--h) + 1px) no-repeat;
  mask:
    url("../tex/tear-edge-a-bottom-outer.webp") bottom / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) top / 100% calc(100% - var(--h) + 1px) no-repeat;
}
.rip--bottom > :is(img, video) {
  -webkit-mask:
    url("../tex/tear-edge-a-bottom-inner.webp") bottom / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) top / 100% calc(100% - var(--h) + 1px) no-repeat;
  mask:
    url("../tex/tear-edge-a-bottom-inner.webp") bottom / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) top / 100% calc(100% - var(--h) + 1px) no-repeat;
}
.rip--both {
  -webkit-mask:
    url("../tex/tear-edge-b-top-outer.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--h) + 2px) no-repeat,
    url("../tex/tear-edge-a-bottom-outer.webp") bottom / 100% var(--h) no-repeat;
  mask:
    url("../tex/tear-edge-b-top-outer.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--h) + 2px) no-repeat,
    url("../tex/tear-edge-a-bottom-outer.webp") bottom / 100% var(--h) no-repeat;
}
.rip--both > :is(img, video) {
  -webkit-mask:
    url("../tex/tear-edge-b-top-inner.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--h) + 2px) no-repeat,
    url("../tex/tear-edge-a-bottom-inner.webp") bottom / 100% var(--h) no-repeat;
  mask:
    url("../tex/tear-edge-b-top-inner.webp") top / 100% var(--h) no-repeat,
    linear-gradient(#000 0 0) center / 100% calc(100% - 2 * var(--h) + 2px) no-repeat,
    url("../tex/tear-edge-a-bottom-inner.webp") bottom / 100% var(--h) no-repeat;
}
.rip > :is(img, video) {
  width: 100%;
}

/* typed paper note */
.note {
  --fg: var(--ink);
  --bg: var(--paper);
  position: relative;
  color: var(--ink);
  background: var(--paper) url("../tex/paper.webp") center / 700px;
  padding: clamp(2.2rem, 4vw, 3.6rem) clamp(1.8rem, 3.6vw, 3.2rem);
  -webkit-mask: url("../tex/tear-sheet-b-outer.webp") center / 100% 100% no-repeat;
  mask: url("../tex/tear-sheet-b-outer.webp") center / 100% 100% no-repeat;
}
.note--tall {
  -webkit-mask-image: url("../tex/tear-sheet-a-outer.webp");
  mask-image: url("../tex/tear-sheet-a-outer.webp");
}
.note p {
  max-width: 54ch;
}
.note p + p,
.note p + .meta,
.note .meta + p {
  margin-top: 1em;
}
.note .label {
  color: var(--pencil);
}

/* sheet: carrier for shadow + tape; never masked itself. The shadow is a
   box shadow on a layer behind the photo, not filter: drop-shadow(): a filter
   re-renders and blurs the whole sheet off screen, which made scrolling
   stutter on phones, while a box shadow is cached. It is inset where the
   torn edge runs, and the blur hides the difference. */
.sheet {
  --shadow: 0 1.4rem 1.6rem rgb(0 0 0 / 0.5);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  isolation: isolate;
}
.sheet > :first-child,
.sheet::after {
  grid-area: 1 / 1;
}
.sheet::after {
  content: "";
  z-index: -1;
  margin: 1.5%;
  box-shadow: var(--shadow);
}
.sheet--tape::before {
  content: "";
  position: absolute;
  z-index: 3;
  top: -1rem;
  left: var(--tape-x, 38%);
  width: clamp(4.5rem, 8vw, 7.5rem);
  aspect-ratio: 420 / 120;
  background: url("../tex/tape.webp") center / 100% 100% no-repeat;
  rotate: var(--tape-r, -7deg);
}
.sheet > figcaption {
  margin-top: 0.7rem;
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
  color: var(--graphite);
}

/* luggage tag with a punched hole */
.tag {
  --fg: var(--ink);
  --bg: var(--paper);
  position: relative;
  padding: 2.7rem 1.35rem 1.35rem;
  color: var(--ink);
  font-size: var(--t-s);
  line-height: 1.45;
  background: var(--paper) url("../tex/paper.webp") center / 500px;
  clip-path: polygon(13% 0, 87% 0, 100% 8%, 100% 100%, 0 100%, 0 8%);
  -webkit-mask: radial-gradient(circle at 50% 1.25rem, #0000 0.36rem, #000 0.42rem);
  mask: radial-gradient(circle at 50% 1.25rem, #0000 0.36rem, #000 0.42rem);
}
.tag .meta {
  margin-top: 0.9rem;
  gap: 0.2rem 0.9rem;
}
@media (max-width: 480px) {
  .tag .meta {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .tag .meta dd + dt {
    margin-top: 0.45rem;
  }
}
.tag .meta dt {
  color: var(--pencil);
}

/* rubber stamp */
.stamp {
  display: inline-block;
  padding: 0.25rem 0.55rem 0.2rem;
  border: 2px solid currentColor;
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  rotate: -5deg;
  opacity: 0.82;
}

/* 4. layout: collage grid ------------------------------------------------- */
/* Placement lives on each element as custom properties:
   --m-col / --m-mt (mobile)   --d-col / --d-row / --d-mt / --d-ml / --d-mr (desktop)
   --r rotation, --z stacking, --d-align align-self */

.collage {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 2.5rem;
  padding-inline: var(--edge);
  align-items: start;
}
.collage > * {
  grid-column: var(--m-col, 1 / -1);
  margin-top: var(--m-mt, 0);
  rotate: var(--r, 0deg);
  z-index: var(--z, auto);
  min-width: 0;
}

@media (min-width: 900px) {
  .collage {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    row-gap: 0;
  }
  .collage > * {
    grid-column: var(--d-col, 1 / -1);
    grid-row: var(--d-row, auto);
    align-self: var(--d-align, start);
    margin-top: var(--d-mt, 0);
    margin-left: var(--d-ml, 0);
    margin-right: var(--d-mr, 0);
    margin-bottom: var(--d-mb, 0);
  }
}

/* 5. masthead + colophon -------------------------------------------------- */

/* The header is not one box: logo and nav are positioned on their own so the
   logo's difference blend works against the page itself (a shared fixed
   parent would isolate it). */
.masthead {
  --top: calc(clamp(1rem, 2.2vw, 1.8rem) + env(safe-area-inset-top));
}
/* logo and menu both stay pinned while the page scrolls, on every screen */
.masthead__mark,
.masthead__nav {
  position: fixed;
  top: var(--top);
  z-index: var(--z-nav);
}

/* the monogram inverts whatever is behind it (white on black, black on
   white paper); a heavier line keeps it readable over photographs */
.masthead__mark {
  left: var(--edge);
  display: block;
  width: clamp(3rem, 4.2vw, 4.2rem);
  color: var(--blend);
  mix-blend-mode: difference;
}
.masthead__mark svg {
  width: 100%;
  height: auto;
  overflow: visible;
}
/* thicken the hairline outline a little at small sizes */
.masthead__mark path {
  stroke: currentColor;
  stroke-width: 1.2px;
  vector-effect: non-scaling-stroke;
}
.colophon__mark path {
  stroke: currentColor;
  stroke-width: 1.1px;
  vector-effect: non-scaling-stroke;
}

/* the nav words sit on a small torn label, so text scrolling underneath
   never clashes with them */
.masthead__nav {
  right: var(--edge);
  color: var(--ink);
  background: var(--paper) url("../tex/paper.webp") center / 400px;
  padding: 0.7rem 1.1rem 0.75rem 0.95rem;
  -webkit-mask: url("../tex/tear-sheet-b-outer.webp") center / 100% 100% no-repeat;
  mask: url("../tex/tear-sheet-b-outer.webp") center / 100% 100% no-repeat;
  rotate: 1.5deg;
  display: grid;
  justify-items: start;
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  line-height: 1.95;
  text-transform: uppercase;
}
.masthead__nav a {
  position: relative;
  text-decoration: none;
  padding-inline: 0.1em;
}
.masthead__nav a:nth-child(2) {
  margin-left: 2.4em;
}
.masthead__nav a:nth-child(3) {
  margin-left: 0.9em;
}
.masthead__nav a:nth-child(4) {
  margin-left: 3.6em;
}
/* touch screens: each menu word is a 44px-high target, laid out 2 x 2 */
@media (pointer: coarse) {
  .masthead__nav {
    grid-template-columns: auto auto;
    column-gap: 0.4rem;
    padding: 0.35rem 0.55rem 0.4rem;
    font-size: 0.8125rem;
    line-height: 1.2;
  }
  .masthead__nav a,
  .masthead__nav a:nth-child(n) {
    margin-left: 0;
    padding: 0.8rem 0.5rem;
  }
  .masthead__nav a[aria-current="page"]::after {
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.55rem;
  }
}

/* current page: a thin underline */
.masthead__nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.2em;
  height: 1px;
  background: currentColor;
}

.colophon {
  position: relative;
  margin-top: clamp(3rem, 7vw, 6rem);
}
.colophon__sheet {
  padding: calc(var(--h) + clamp(2rem, 5vw, 4rem)) var(--edge) calc(clamp(2rem, 4vw, 3rem) + env(safe-area-inset-bottom));
}
.colophon__grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
  align-items: end;
}
.colophon__mark {
  width: clamp(4.5rem, 9vw, 8rem);
  color: var(--ink);
}
.colophon__name {
  font-size: var(--t-l);
  line-height: 1.2;
  letter-spacing: -0.02em;
}
.colophon__links,
.colophon__nav {
  display: grid;
  gap: 0.35rem;
  justify-items: start;
}
.colophon__small {
  font-size: var(--t-xs);
  letter-spacing: 0.06em;
  color: var(--pencil);
}
@media (min-width: 900px) {
  .colophon__grid {
    grid-template-columns: 1.1fr 1.4fr 1fr 0.8fr;
  }
}

/* 6. pages ----------------------------------------------------------------- */

/* ---- home */

.hero {
  position: relative;
  min-height: max(100dvh, 24rem);
  overflow: clip;
}
.hero__rip {
  --h: clamp(4rem, 11vw, 10rem);
  position: absolute;
  inset: 0;
}
.hero__rip > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 30% 45%;
}
.hero__caption {
  position: absolute;
  left: var(--edge);
  bottom: clamp(6rem, 17vh, 11rem);
  z-index: var(--z-lift);
  color: var(--blend);
  mix-blend-mode: difference;
}
.hero__title {
  font-size: var(--t-xl);
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.hero__title span {
  display: block;
}
.hero__title span + span {
  padding-left: 1.6em;
}
.hero__sub {
  margin-top: 0.9rem;
  padding-left: 0.2em;
  font-size: var(--t-s);
  letter-spacing: 0.06em;
  text-transform: none;
}
/* tall screens (portrait tablets) crop the sides: keep her in frame */
@media (orientation: portrait) {
  .hero__rip > img {
    object-position: 66% 50%;
  }
}
@media (max-width: 899px) {
    .hero__rip > img {
    object-position: 66% 50%;
  }
}

.home-about {
  position: relative;
  margin-top: clamp(-9rem, -12vw, -3rem);
}
.home-about__title {
  font-size: var(--t-l);
  letter-spacing: -0.02em;
  margin-bottom: 1rem;
}
.home-work {
  margin-top: clamp(5rem, 12vw, 12rem);
}
.home-work__title {
  font-size: var(--t-xl);
  margin-bottom: 1rem;
}
.home-work__index {
  max-width: 30rem;
}
.home-work__text p {
  max-width: 44ch;
  margin-bottom: 1.2rem;
}
.home-work__sketch {
  width: 100%;
}
.home-archive {
  position: relative;
  margin-top: 3rem;
}
@media (min-width: 1280px) {
  .home-archive {
    margin-top: clamp(-9rem, -7vw, 2rem);
  }
}
@media (max-width: 899px) {
  .home-archive {
    margin-top: -4rem;
  }
}
.home-archive__img {
  --h: clamp(3rem, 6vw, 6rem);
}
.home-archive__img > img {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
@media (max-width: 899px) {
  .home-archive__img {
    margin-inline: calc(var(--edge) * -1);
  }
  .home-archive__img > img {
    aspect-ratio: 4 / 3;
    object-position: 40% 50%;
  }
}

.crop-wide > img {
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

/* ---- work */

.work-intro {
  padding-top: clamp(6.5rem, 12vw, 10rem);
}
.work-intro__title {
  font-size: var(--t-xl);
  margin-bottom: 1.4rem;
}
.contents {
  margin-top: 1.8rem;
  display: grid;
  gap: 0.35rem;
  font-size: var(--t-s);
}
.contents a {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
  padding-block: 0.15rem;
}
.contents__lead {
  flex: 1;
  min-width: 1.5rem;
  border-bottom: 2px dotted currentColor;
  opacity: 0.55;
  translate: 0 -0.3em;
}


.chapter {
  position: relative;
  z-index: var(--cz, auto);
  padding-block: clamp(5rem, 11vw, 11rem) 0;
  scroll-margin-top: 2rem;
}
.chapter__title {
  font-size: var(--t-xl);
  margin-bottom: 1.4rem;
}
.chapter__title--huge {
  font-size: clamp(2.8rem, 0.8rem + 7.4vw, 9.5rem);
  letter-spacing: -0.06em;
  color: var(--paper);
  text-shadow: 0 0 1.5rem rgb(0 0 0 / 0.6);
}
.chapter__desc {
  max-width: 50ch;
  margin-block: 1.4rem 1.2rem;
}
.chapter__note {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  margin-top: 0;
  transition:
    grid-template-rows 0.9s var(--slow),
    opacity 0.6s ease,
    margin-top 0.9s var(--slow);
}
.chapter__note.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: 1.4rem;
}
.chapter__note-inner {
  min-height: 0;
  overflow: hidden;
}
.chapter__note p {
  max-width: 58ch;
}
.chapter__note p + p {
  margin-top: 1em;
}
.chapter__note-inner:focus {
  outline: none;
}
.chapter--paper {
  margin-top: clamp(-6rem, -5vw, -2rem);
  padding-block: calc(var(--h) + clamp(2rem, 5vw, 5rem));
}
.chapter--paper .sheet {
  --shadow: 0 1rem 1.2rem rgb(0 0 0 / 0.28);
}
.quote {
  font-size: var(--t-l);
  font-style: italic;
  line-height: 1.35;
  max-width: 30ch;
}
.quote p::before {
  content: "\201C";
}
.quote p::after {
  content: "\201D";
}

/* ---- archive */

.archive-intro {
  padding-top: clamp(6.5rem, 12vw, 10rem);
}
.archive-intro__title {
  font-size: var(--t-xl);
  margin-bottom: 1.2rem;
}
.archive-index {
  margin-top: 1.6rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.2rem 1.5rem;
  font-size: var(--t-s);
}
.archive-index a {
  text-decoration: none;
}

.archive-index span:first-child {
  color: var(--pencil);
  margin-right: 0.6rem;
}

.shelf {
  padding-top: clamp(4rem, 8vw, 8rem);
  padding-bottom: clamp(3rem, 6vw, 6rem);
  row-gap: 6rem;
}
@media (min-width: 900px) {
  .shelf {
    row-gap: 0;
  }
}

.object {
  position: relative;
  scroll-margin-top: 3rem;
}
.object__img {
  display: block;
}

.object__label {
  position: relative;
  width: min(18rem, 86%);
  margin: -3.5rem 0 0 auto;
  rotate: var(--tr, 2deg);
  filter: drop-shadow(0 0.8rem 1rem rgb(0 0 0 / 0.45));
}
/* string from the punched hole up towards the photo */
.object__label::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -2.2rem;
  width: 1px;
  height: 3.5rem;
  background: var(--paper-shade);
  rotate: 18deg;
  transform-origin: bottom;
}

.object--label-left .object__label {
  margin: -3.5rem auto 0 0;
}
.tag__no {
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  color: var(--pencil);
}
.tag__name {
  margin-top: 0.3rem;
  font-size: var(--t-l);
  letter-spacing: -0.03em;
}
.tag__name a {
  text-decoration: none;
}

.tag__desc {
  margin-top: 0.5rem;
}
.tag .stamp {
  margin-top: 0.9rem;
}

/* archive viewer (native dialog, content loaded by htmx) */
.viewer {
  width: min(100vw - 2 * var(--edge), 80rem);
  max-width: none;
  max-height: none;
  height: min(94dvh, 64rem);
  margin: auto auto 0;
  padding: 0;
  border: 0;
  color: var(--ink);
  background: transparent;
  overflow: visible;
}
.viewer::backdrop {
  background: rgb(8 8 8 / 0.86);
}
.viewer__sheet {
  --h: 3.5rem;
  --pad: clamp(1.2rem, 3vw, 3rem);
  --fg: var(--ink);
  --bg: var(--paper);
  height: 100%;
  overflow: auto;
  overscroll-behavior: contain;
  padding: calc(var(--h) + 1.5rem) var(--pad) 3rem;
}
/* the pinned menu would show through the backdrop above the sheet */
html:has(.viewer[open]) .masthead__nav {
  visibility: hidden;
}
/* the enquiry bar always sits at the bottom edge of the sheet, whether the
   piece's content is shorter or longer than the sheet */
.viewer__sheet:has(.piece__bar) {
  display: flex;
  flex-direction: column;
  padding-bottom: 0;
}
#viewer-body {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}
.piece {
  flex: 1 0 auto;
  grid-template-rows: auto auto 1fr;
}
.piece__bar {
  align-self: end;
}
@media (min-width: 1100px) {
  .piece {
    grid-template-rows: auto 1fr;
  }
}
.viewer {
  padding-top: env(safe-area-inset-top);
}
.viewer__close {
  position: absolute;
  top: -2.4rem;
  right: 0;
  color: var(--paper);
  font-size: var(--t-s);
  letter-spacing: 0.08em;
  text-decoration: underline;
  text-underline-offset: 0.25em;
  padding: 0.4rem 0;
}
/* phones and tablets: the sheet runs edge to edge. Safari 26 fills the strip
   under its bottom toolbar with the colour of the sticky enquiry bar across
   the full width, so dark side margins would leave the sheet looking cut
   off above a wider paper band. */
@media (max-width: 899px) {
  .viewer {
    width: 100%;
  }
  .viewer__sheet {
    --pad: max(1.2rem, env(safe-area-inset-left), env(safe-area-inset-right));
  }
  .viewer__close {
    right: var(--edge);
  }
}
.viewer__loading,
.viewer__error {
  display: none;
  font-size: var(--t-s);
}
.viewer.is-loading .viewer__loading,
.viewer.is-error .viewer__error {
  display: block;
}
.viewer__loading::after {
  content: "_";
  animation: blink 1s steps(1) infinite;
}

.piece {
  display: grid;
  gap: 2rem;
}
/* carousel: one photo at a time, centred; swipe, arrows or thumbnails */
.piece__media {
  min-width: 0;
}
.piece__stage {
  position: relative;
}
.piece__gallery {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.piece__gallery::-webkit-scrollbar {
  display: none;
}
.piece__gallery img {
  flex: 0 0 100%;
  width: 100%;
  height: min(60dvh, 40rem, 118vw);
  max-width: none;
  object-fit: contain;
  scroll-snap-align: center;
  scroll-snap-stop: always;
}
.piece__arrow {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  color: var(--paper);
  background: var(--ink);
  font-size: 1.1rem;
  opacity: 0.88;
  transition: opacity 0.3s ease;
}
.piece__arrow:hover,
.piece__arrow:focus-visible {
  opacity: 1;
}
.piece__arrow:active {
  translate: 0 calc(-50% + 1px);
}
.piece__arrow--prev {
  left: 0;
}
.piece__arrow--next {
  right: 0;
}
/* contact-sheet strip: shows how many photos there are and which is open */
.piece__thumbs {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-top: 0.9rem;
}
.piece__thumbs button {
  width: 2.9rem;
  aspect-ratio: 4 / 5;
  padding: 0;
  opacity: 0.45;
  outline: 1px solid transparent;
  outline-offset: 2px;
  transition:
    opacity 0.4s ease,
    outline-color 0.4s ease;
}
.piece__thumbs button[aria-current="true"] {
  opacity: 1;
  outline-color: var(--ink);
}
.piece__thumbs button:hover {
  opacity: 0.85;
}
.piece__thumbs img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.piece__gallery:focus-visible {
  outline-offset: 2px;
}
.piece__title:focus {
  outline: none;
}
.piece__title {
  font-size: var(--t-xl);
  margin-block: 0.3rem 1.2rem;
}
.piece__text p {
  max-width: 56ch;
}
.piece__text p + p {
  margin-top: 1em;
}
.piece__text .meta {
  margin-block: 1.6rem;
}
.piece__bar {
  position: sticky;
  bottom: 0;
  z-index: 2;
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 0.6rem 1.6rem;
  margin: 0 calc(var(--pad) * -1);
  padding: 0.9rem var(--pad) calc(0.9rem + env(safe-area-inset-bottom));
  background: var(--paper) url("../tex/paper.webp") center / 700px;
  box-shadow: 0 -1.2rem 1.4rem -1.2rem rgb(0 0 0 / 0.35);
  border-top: 1px solid rgb(13 13 13 / 0.18);
}
.piece__bar-name {
  font-size: var(--t-s);
  color: var(--pencil);
}
.piece__bar-name strong {
  margin-left: 0.4rem;
  font-weight: 400;
  color: var(--ink);
}
.piece__bar-price {
  font-size: var(--t-s);
}
@media (max-width: 599px) {
  .piece__enquire {
    flex-basis: 100%;
    max-width: 16rem;
  }
}
.piece__enquire {
  --marker: var(--paper);
  --marker-text: var(--ink);
  display: inline-block;
  padding: 0.85rem 1.6rem 0.8rem;
  color: var(--paper);
  background: var(--ink);
  font-size: var(--t-s);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
}
.piece__enquire::before {
  inset: 0.35rem 0.6rem;
}
.piece__enquire:active {
  translate: 0 1px;
}
.piece__credit {
  margin-top: 1.6rem;
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
  color: var(--pencil);
}
@media (min-width: 1100px) {
  .piece {
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    align-items: start;
  }
  .piece__media {
    grid-row: 1;
  }
  .piece__text {
    position: sticky;
    top: 0;
  }
}

/* ---- about */

.about-top {
  padding-top: clamp(6.5rem, 10vw, 9rem);
}
.about-name {
  font-size: clamp(3rem, 0.4rem + 8.6vw, 10rem);
  line-height: 0.82;
  letter-spacing: -0.07em;
  text-transform: uppercase;
  color: var(--paper);
}
.about-name span {
  display: block;
}
@media (max-width: 899px) {
  .about-name {
    font-size: 16vw;
  }
}
.about-name span + span {
  padding-left: 0.9em;
}
.idcard .meta {
  grid-template-columns: max-content 1fr;
}
.idcard__title {
  font-size: var(--t-s);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 1rem;
}
.statement {
  font-size: var(--t-l);
  line-height: 1.45;
  max-width: 38ch;
}
.statement em {
  font-style: italic;
}

@media (max-width: 899px) {
  .about-name,
  .chapter__title--huge {
    margin-top: 0 !important;
  }
  .hero__caption {
    mix-blend-mode: normal;
    color: var(--paper);
    text-shadow: 0 0 1.2rem rgb(0 0 0 / 0.75), 0 0 0.3rem rgb(0 0 0 / 0.6);
  }
}

/* ---- contact: quiet on purpose */

.contact {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  padding: clamp(7rem, 14vw, 10rem) var(--edge) clamp(3rem, 8vw, 6rem);
}
.contact__inner {
  width: 100%;
  max-width: 46rem;
}
@media (min-width: 900px) {
  .contact__inner {
    margin-left: clamp(0rem, 16vw, 18rem);
  }
}
.contact__title {
  font-size: var(--t-l);
  letter-spacing: 0.02em;
  margin-bottom: clamp(3rem, 8vw, 6rem);
}
.contact__list {
  display: grid;
  gap: clamp(1.6rem, 3.4vw, 2.6rem);
}
.contact__row {
  display: grid;
  gap: 0.35rem;
}
.contact__row dd {
  font-size: var(--t-l);
  line-height: 1.35;
  letter-spacing: -0.01em;
}
.contact__row dd a {
  text-decoration: none;
  background: linear-gradient(currentColor 0 0) left bottom / 100% 1px no-repeat;
}
.contact__legal {
  margin-top: clamp(4rem, 10vw, 7rem);
  font-size: var(--t-xs);
  line-height: 1.7;
  letter-spacing: 0.03em;
  color: var(--graphite);
}
.contact__legal h2 {
  font-size: var(--t-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}
@media (min-width: 700px) {
  .contact__row {
    grid-template-columns: 9rem 1fr;
    align-items: baseline;
  }
}

/* ---- 404 */

.lost {
  min-height: 100dvh;
  display: grid;
  place-content: center start;
  gap: 1.5rem;
  padding: 8rem var(--edge);
}
.lost h1 {
  font-size: var(--t-xl);
}

/* 7. motion ---------------------------------------------------------------- */

@keyframes blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }

  /* sheets settle onto the desk as they enter the viewport. Only transform
     and opacity move (the GPU runs those in every browser); the placement
     rotation (--r) stays put, transform adds the extra tilt on top. */
  .js [data-reveal] {
    opacity: 0;
    transform: translateY(3rem);
    transition:
      opacity 1.1s var(--settle) var(--delay, 0s),
      transform 1.1s var(--settle) var(--delay, 0s);
  }
  .js .collage > [data-reveal] {
    transform: translateY(3rem) rotate(2.5deg);
  }
  .js [data-reveal].is-visible {
    opacity: 1;
    transform: none;
  }

  /* hero: the photograph develops, then the name surfaces; both wait until
     the photo is decoded and the font is loaded (main.js adds .is-ready) */
  .js .hero:not(.is-ready) .hero__rip > img,
  .js .hero:not(.is-ready) .hero__caption {
    opacity: 0;
  }
  /* fill "backwards", not "both": the keyframes end at the resting style,
     and a finished animation that keeps filling holds the masked photo in
     its own GPU layer while the visitor scrolls */
  .js .hero.is-ready .hero__rip > img {
    animation: develop 2.8s var(--slow) backwards;
  }
  .js .hero.is-ready .hero__caption {
    animation: surface 2s 1.2s var(--slow) backwards;
  }

  /* layered images drift at slightly different speeds (not on small screens,
     where the stacked layout has no room for it) */
  @supports (animation-timeline: view()) {
    @media (min-width: 900px) {
      [data-drift] {
        animation: drift linear both;
        animation-timeline: view();
        animation-range: cover 0% cover 100%;
      }
    }
    .unveil {
      animation: unveil linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 45%;
    }
  }

  .viewer[open] .viewer__sheet {
    animation: rise 1s var(--slow) backwards;
  }
  .viewer[open]::backdrop {
    animation: fade 0.8s ease backwards;
  }

  /* page change: the old page sinks, the new sheet is drawn up over it */
  ::view-transition-old(root) {
    animation: sink 0.8s var(--slow) both;
  }
  ::view-transition-new(root) {
    animation: pull-up 1.2s 0.1s var(--slow) both;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chapter__note,
  .masthead__mark,
  .masthead__nav,
  .typed-link::before,
  .masthead__nav a::before,
  .tag__name a::before,
  .contact__row dd a::before,
  .viewer__close::before,
  .contents__name::before,
  .archive-index a span:last-child::before,
  .piece__enquire::before {
    transition: none !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

@view-transition {
  navigation: auto;
}

@keyframes develop {
  from {
    opacity: 0;
    scale: 1.06;
  }
}
@keyframes surface {
  from {
    opacity: 0;
    translate: 0 1.2rem;
  }
}
/* drift moves `translate`, so it never overrides the reveal's `transform` */
@keyframes drift {
  from {
    translate: 0 var(--drift, 3rem);
  }
  to {
    translate: 0 calc(var(--drift, 3rem) * -1);
  }
}
@keyframes unveil {
  from {
    clip-path: inset(0 0 100% 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes rise {
  from {
    opacity: 0;
    translate: 0 30%;
  }
}
@keyframes fade {
  from {
    opacity: 0;
  }
}
@keyframes sink {
  to {
    opacity: 0;
    scale: 0.985;
  }
}
@keyframes pull-up {
  from {
    clip-path: inset(100% 0 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

@media (max-width: 599px) {
  .piece__thumbs {
    flex-wrap: nowrap;
    gap: 0.35rem;
  }
  .piece__thumbs button {
    width: min(2.4rem, calc((100% - 2.4rem) / 7));
  }
}
