@font-face { font-family: "Inter"; src: url("fonts/inter-400.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/inter-500.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "Newsreader"; src: url("fonts/newsreader-500.woff2") format("woff2"); font-weight: 500; font-display: swap; }
/* spine and cover faces, used by the 3D shelf */
@font-face { font-family: "Jost"; src: url("fonts/jost-500.woff2") format("woff2"); font-weight: 500; font-display: block; }
@font-face { font-family: "Playfair Display"; src: url("fonts/playfair-display-700.woff2") format("woff2"); font-weight: 700; font-display: block; }
@font-face { font-family: "DM Serif Display"; src: url("fonts/dm-serif-display-400.woff2") format("woff2"); font-weight: 400; font-display: block; }
/* each project's own faces, for the note that slides out of its book */
@font-face { font-family: "Manrope"; src: url("fonts/manrope-700.woff2") format("woff2"); font-weight: 700; font-display: block; }
@font-face { font-family: "Outfit"; src: url("fonts/outfit-600.woff2") format("woff2"); font-weight: 600; font-display: block; }
@font-face { font-family: "Gloock"; src: url("fonts/gloock-400.woff2") format("woff2"); font-weight: 400; font-display: block; }
@font-face { font-family: "Hanken Grotesk"; src: url("fonts/hanken-grotesk-500.woff2") format("woff2"); font-weight: 500; font-display: block; }
@font-face { font-family: "Inter"; src: url("fonts/inter-600.woff2") format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: "Inter Tight"; src: url("fonts/inter-tight-600.woff2") format("woff2"); font-weight: 600; font-display: block; }

:root {
  --ink: #ece7de;
  --fade: 700ms;
}

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

html, body { height: 100%; }

body {
  background: #141312;
  color: var(--ink);
  font-family: "Inter", system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* ---------- name ---------- */

.mark {
  position: fixed;
  top: 32px;
  left: 40px;
  z-index: 2;
  font-weight: 500;
  font-size: 18px;
  letter-spacing: .01em;
}

/* ---------- stage ---------- */

.stage {
  position: fixed;
  inset: 0;
  outline: none;
}

.stage canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

/* the lens: the corners fall off a little, as in a photo of a dim room */
.stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 100% at 50% 42%, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, .34) 100%);
}

/* film grain over the scene, under the name and the card; the tile comes from js/grain.js */
body::after {
  content: "";
  position: fixed;
  inset: -128px;
  z-index: 1;
  pointer-events: none;
  background-image: var(--grain, none);
  background-size: 256px 256px;
  opacity: .25;
  animation: grain 1.6s steps(1) infinite;
}
/* a light level (js/quality.js): the grain stands still, one less layer moving over the scene */
.lite body::after { animation: none; }
@keyframes grain {
  0% { transform: translate(0, 0); }
  12.5% { transform: translate(-61px, 37px); }
  25% { transform: translate(43px, -88px); }
  37.5% { transform: translate(-97px, -21px); }
  50% { transform: translate(78px, 64px); }
  62.5% { transform: translate(-28px, 101px); }
  75% { transform: translate(109px, -47px); }
  87.5% { transform: translate(-74px, -113px); }
}

/* visually hidden once the 3D shelf is up */
.stage.is-ready .list {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* fallback without WebGL: a plain list */
.list {
  list-style: none;
  position: absolute;
  left: 40px;
  bottom: 15vh;
  display: grid;
  gap: 8px;
}
.list a { color: var(--ink); font-family: "Newsreader", Georgia, serif; font-weight: 500; font-size: 40px; text-decoration: none; }
.list a:hover, .list a:focus-visible { text-decoration: underline; text-underline-offset: 6px; }

/* ---------- detail card ----------
   The visible card is the paper slip in the 3D book; this one is kept for
   screen readers and keyboard users only. */

.card {
  position: fixed;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.card[hidden] { display: block; }

.kind {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #a89c8a;
}

.card h1 {
  margin-top: 10px;
  font-family: "Newsreader", Georgia, serif;
  font-weight: 500;
  font-size: 40px;
  line-height: 1.08;
  letter-spacing: -.01em;
}

.line { margin-top: 14px; color: #d9cfbf; }

.visit {
  display: inline-block;
  margin-top: 24px;
  color: #efe7da;
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}
.visit::after { content: " \2197"; }
.visit:hover { opacity: .7; }

.steps {
  display: flex;
  gap: 10px;
  margin-top: 28px;
  padding-top: 22px;
  border-top: 1px solid rgba(255, 240, 220, .12);
}

.pill {
  font: inherit;
  font-size: 15px;
  color: #efe7da;
  background: transparent;
  border: 1px solid rgba(255, 240, 220, .16);
  border-radius: 999px;
  padding: 7px 14px;
  cursor: pointer;
  transition: background-color .2s;
}
.pill:hover { background: rgba(255, 240, 220, .08); }

.close {
  position: absolute;
  top: 14px;
  right: 14px;
}

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

/* ---------- phones: the card becomes a sheet at the bottom ---------- */

@media (max-width: 760px) {
  .mark { top: 20px; left: 20px; }
  .list { left: 20px; }
  .list a { font-size: 32px; }
}

@media (prefers-reduced-motion: reduce) {
  :root { --fade: 0ms; }
  .card { transition: none; }
  body::after { animation: none; }
}

/* ---------- while the shelf is made ----------
   The shelf drawn in ink, exactly where it will stand (js/loader.js projects it with the
   shelf's own camera). The pen draws it in, and each spine is printed with its own picture
   as that book is made. Then the shelf dissolves in from the middle of the books: a soft-edged opening (--reveal)
   grows over the canvas while the drawing gives way under the same edge. The timings are
   kept in step with js/loader.js. */

@property --reveal { syntax: "<percentage>"; inherits: true; initial-value: 0%; }

.loader {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(farthest-corner at var(--cx, 50%) var(--cy, 55%), transparent calc(var(--reveal) - 36%), #000 var(--reveal));
  mask-image: radial-gradient(farthest-corner at var(--cx, 50%) var(--cy, 55%), transparent calc(var(--reveal) - 36%), #000 var(--reveal));
}
/* the lamp, where the shelf will have it: a pool on the wood, a breath of it on the wall.
   Over the drawing, so the faces (the room's own dark) stay one with the room around them */
.loader::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 34% 9% at var(--pool, 52% 80%), rgba(255, 178, 104, .085), transparent),
    radial-gradient(ellipse 46% 42% at var(--glow, 53% 36%), rgba(255, 213, 156, .035), transparent);
}
.loader-lines { position: absolute; inset: 0; overflow: hidden; }
.loader-lines > * { position: absolute; display: block; }

/* the pen: every line scaled out from its start, in turn (--d); by transform, so it keeps
   moving while the shelf is being made (js/loader.js) */
.loader-lines .ln {
  height: var(--w);
  margin-top: calc(var(--w) / -2);
  transform-origin: 0 50%;
  transform: rotate(var(--a)) scaleX(0);
  will-change: transform;
}
.loader-lines.is-drawn .ln {
  transform: rotate(var(--a)) scaleX(1);
  transition: transform 700ms cubic-bezier(.55, 0, .25, 1) var(--d, 0ms);
}
/* outer lines firm, the edges between faces light */
.loader-lines .outline { --w: 1.15px; background: rgba(236, 231, 222, .64); }
.loader-lines .edge { --w: .8px; background: rgba(236, 231, 222, .2); }
/* the faces cover what lies behind them */
.loader-lines .face { background: #141312; }

/* a book is made: the dark slides off its spine's picture from the tail up */
.loader-lines .art { left: 0; top: 0; transform-origin: 0 0; overflow: hidden; }
.loader-lines .art img { display: block; width: 100%; height: 100%; }
.loader-lines .art .cover {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 118%;
  background: linear-gradient(#141312 85%, rgba(20, 19, 18, 0));
  will-change: transform;
}
.loader-lines .art.is-printed .cover { transform: translateY(-100%); transition: transform 700ms cubic-bezier(.6, 0, .2, 1); }
.loader-lines.is-instant .ln, .loader-lines.is-instant .cover { transition: none; }

.loader-step {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 9vh;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .02em;
  color: rgba(236, 231, 222, .5);
  transition: opacity 400ms ease;
}
.stage.is-revealing .loader-step, .stage.is-held .loader-step { opacity: 0; }

/* the shelf, under the opening */
.stage canvas {
  -webkit-mask-image: radial-gradient(farthest-corner at var(--cx, 50%) var(--cy, 55%), #000 calc(var(--reveal) - 36%), transparent var(--reveal));
  mask-image: radial-gradient(farthest-corner at var(--cx, 50%) var(--cy, 55%), #000 calc(var(--reveal) - 36%), transparent var(--reveal));
}
.stage.is-revealing { --reveal: 140%; transition: --reveal 3000ms cubic-bezier(.45, 0, .25, 1); }
.stage.is-revealed canvas { -webkit-mask-image: none; mask-image: none; }

/* the plain list is for screen readers while the loader shows; seen only without WebGL */
.stage:has(.loader) .list {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

@media (prefers-reduced-motion: reduce) {
  .stage.is-revealing, .loader-lines .cover { transition: none; }
}

