/* ---------- tokens ----------
   Black and white at full contrast, like a plot on paper; dusty pink is
   the one highlight, always a solid block with black text on it (where
   you are, what you're pointing at, a selection). */
:root {
  --bg:      #ffffff;
  --surface: #efefef;
  --fg:      #000000;
  --muted:   #4d4d4d;
  --line:    #000000;
  --pink:    #f0d3d6;
  --on-pink: #000000;

  /* one spacing rhythm for the whole page: each step about 1.6 times the
     last (8, 13, 21, 34, 55, 89, 144), so gaps relate to each other */
  --s1: 8px;
  --s2: 13px;
  --s3: 21px;
  --s4: 34px;
  --s5: 55px;
  --s6: 89px;
  --s7: 144px;
  /* the margin at each side grows with the screen; the content stops at
     --content and centres */
  --gutter: clamp(21px, 4vw, 55px);
  --content: 1376px;
  --measure: min(var(--content), 100% - 2 * var(--gutter));
  color-scheme: light;
  /* machine type: a monospace for labels and titles */
  --mono: "Martian Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --sans: var(--mono);
  /* what you read at length: a serif made for reading on screens */
  --text: "Source Serif 4", "Iowan Old Style", Georgia, serif;
}


/* the pink highlight: a solid block, black text, edges that follow wrapped lines */
.hl,
.nav a[aria-current="page"] {
  background: var(--pink);
  color: var(--on-pink);
}

/* ---------- base ---------- */
* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 15px;
  font-stretch: 87.5%;
  line-height: 1.65;
  font-feature-settings: "kern" 1;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

button { font: inherit; color: inherit; }

a { color: inherit; }

::selection { background: var(--pink); color: var(--on-pink); }

:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--bg);
  color: var(--fg);
  padding: 10px 16px;
  border: 1px solid var(--line);
}
.skip:focus { left: 16px; top: 16px; }

/* ---------- header ---------- */
.nameplate {
  width: 100%;
  padding: var(--s3) 0 0;
}

/* name on the left, pages on the right, a hairline under both: the
   letterhead every page shares */
/* name on the left, pages on the right, a light rule under both */
.nameplate-top {
  width: var(--measure);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px 28px;
  flex-wrap: wrap;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--surface);
}

/* the name, typed, until the header image is set; then the image */
.nameplate h1 {
  margin: 0;
  font-size: 1.375rem;
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.2;
}
.nameplate h1.has-logo { line-height: 0; }
.nameplate h1 img {
  display: block;
  height: clamp(64px, 3.5rem + 2.4vw, 104px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* nav and the icons sit on one line, with a hairline between them */
.top-right {
  display: flex;
  align-items: center;
  gap: 28px;
}

.nav {
  display: flex;
  gap: 12px;
}
.nav a {
  position: relative;
  padding: 3px 7px;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  text-decoration: none;
  transition: background-color 0.12s ease;
}
.nav a:hover { background: color-mix(in srgb, var(--pink) 45%, transparent); }
/* a fingertip-sized target around each small link, without moving it */
.nav a::after {
  content: "";
  position: absolute;
  inset: -12px -10px;
}
.nav a[aria-current="page"] {
  /* the pink block (see .hl) */
}

/* the lace header (main.js + filet.js): one band of black filet lace with
   the name, the page tabs and the socials in it. The canvas sits over each
   link's pink backing, so the pink shows through the openings and holes.
   The typed nav and icons are only there until the lace is drawn. */
.nameplate.is-lace .nameplate-top { display: block; border-bottom: 0; padding-bottom: 0; }
.nameplate.is-lace .top-right { display: none; }
.lace-box { position: relative; isolation: isolate; line-height: 0; }
.lace-box canvas { position: relative; display: block; }
.lace-box .hit { position: absolute; display: block; }
.lace-box .hit::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  transition: background-color 0.12s ease;
}
.lace-box .hit:hover::before { background: color-mix(in srgb, var(--pink) 70%, transparent); }
.lace-box .hit[aria-current="page"]::before { background: var(--pink); }
/* a fingertip-sized target round each small tab and icon, without moving it */
.lace-box .hit::after { content: ""; position: absolute; inset: -9px -3px; }
/* on a phone: the slim lace menu that drops in once the header scrolls away */
.lace-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  justify-content: center;
  padding-top: env(safe-area-inset-top, 0px);
  transform: translateY(-120%);
  transition: transform 0.2s ease;
  pointer-events: none;
}
.lace-bar::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: env(safe-area-inset-top, 0px);
  background: var(--bg);
}
.lace-bar.show { transform: none; pointer-events: auto; }
.lace-backing { position: absolute; z-index: -2; background: var(--bg); }
@media (prefers-reduced-motion: reduce) { .lace-bar { transition: none; } }
/* the lace trim along the very bottom of the page */
.lace-trim { flex-shrink: 0; display: flex; justify-content: center; line-height: 0; }
.lace-trim canvas { display: block; }
body.has-trim footer { padding-bottom: var(--s3); }


/* a section's name, with a quiet fact on the right */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 20px;
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}
.section-head h2 {
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: 0.01em;
  line-height: 1.3;
  margin: 0;
}


/* ---------- the wall ---------- */
main {
  position: relative;
  flex: 1 0 auto;
  width: 100%;
}

/* the work, and the plotting series in a sidebar beside it */
.rooms {
  width: var(--measure);
  margin: 0 auto;
  padding: var(--s5) 0 0;
}
#wall { min-width: 0; }

/* hung like a gallery wall: every piece keeps its artwork's proportions
   (--r, width / height), and the pieces in a row share one height. Each
   grows in proportion to its ratio, so a row fills the width without
   anything being cropped. */
.wall {
  --row: 250px;
  --frame: 0px;      /* nothing around the art; the layout still reads it */
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s5) var(--s4);
}
/* soaks up the spare room on the last row, so a short row isn't blown up */
.wall::after { content: ""; flex: 999 1 0; }

/* once the script has hung a wall, every piece has a measured place */
.wall.hung {
  display: block;
  position: relative;
}
.wall.hung::after { display: none; }
.hung > .frame { position: absolute; flex: none; }

.frame {
  --r: 1;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}
.wall .frame {
  flex: var(--r) 1 calc(var(--r) * var(--row));
  width: auto;
  min-width: 0;
}

/* the art itself, at its own proportions */
.frame-inner {
  position: relative;
  aspect-ratio: var(--r);
  background: var(--surface);
  overflow: hidden;
  transition: opacity 0.2s ease;
}
.frame-inner img,
.frame-inner video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.frame:hover .frame-inner { opacity: 0.85; }
.frame-title {
  transition: background-color 0.12s ease;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.frame:hover .frame-title {
  background: var(--pink);
  color: var(--on-pink);
}

/* placeholder drawings sit on a plain board */
.frame-inner.doodle {
  display: grid;
  place-items: center;
  padding: 22px;
}
.frame-inner svg {
  width: 58%;
  height: 58%;
  color: var(--muted);
}

/* the name, underneath */
.frame-caption { padding-top: var(--s2); }
.frame-title {
  display: inline;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.5;
}
.frame-sub {
  display: block;
  margin-top: 1px;
  color: var(--muted);
  font-size: 0.8125rem;
  line-height: 1.4;
}

/* ---------- the plotting series ----------
   The current series, above the work: the ten most recent days in one
   row (two on phones), newest first. */
.plots { scroll-margin-top: 24px; }
/* the work comes after the series */
#wall { margin-top: var(--s6); }
#series[hidden] + #wall { margin-top: 0; }
/* the section names are marked in the pink highlight, black on pink */
.series-label,
.section-label { color: var(--on-pink); background: var(--pink); padding: 2px 6px; margin-left: -6px; }
.plots-head { display: block; margin-bottom: var(--s3); }
/* the series name moves to its own line as a whole rather than breaking */
#series-title { display: inline-block; }
.plots-head h2 {
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: 0.01em;
  line-height: 1.3;
  margin: 0;
}
.series-intro {
  margin: var(--s1) 0 0;
  max-width: 52ch;
  color: var(--muted);
  font-family: var(--text);
  font-stretch: normal;
  font-size: 0.9375rem;
}
/* the count sits on the intro line, in the same quiet voice */
.series-count {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.series-count:empty { display: none; }

.days {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: var(--s3);
}
.day {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 4px;
  padding: 8px;
  overflow: hidden;
  border: 0;
  font: inherit;
  font-size: 0.6875rem;
  line-height: 1.3;
  text-align: left;
  font-variant-numeric: tabular-nums;
}
button.day {
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  transition: outline-color 0.12s ease;
  outline: 2px solid transparent;
  outline-offset: 2px;
}
.day.has-image img,
.day.has-image video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.day-num { position: relative; letter-spacing: 0.04em; }
/* a day with a picture shows its number under the square instead */
.day.has-image .day-num { display: none; }
/* the number lights up in the pink highlight while you point at its day */
.days li:hover .day-caption,
.day:focus-visible + .day-caption { background: var(--pink); color: var(--on-pink); }
.day-caption {
  display: table;
  padding: 0 3px;
  margin-left: -3px;
  transition: background-color 0.12s ease;
  margin-top: var(--s1);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
.day-concept { color: var(--muted); }

.wall-empty { color: var(--muted); }

/* ---------- about ---------- */
/* the text on the left, your photo (when there is one) on the right */
.about {
  width: var(--measure);
  margin: 0 auto;
  padding: var(--s5) 0 var(--s4);
  display: grid;
  /* the photo sits right beside the text, not out at the far edge */
  grid-template-columns: minmax(0, 60ch) minmax(240px, 560px);
  justify-content: start;
  gap: var(--s4) var(--s5);
  align-items: start;
}
.about-body { grid-column: 1; grid-row: 1; }
.about-portrait { grid-column: 2; grid-row: 1; }
/* no photo yet: the text starts at the left edge, in line with the wall */
.about:has(.about-portrait[hidden]) .about-body { grid-column: 1 / -1; }
/* the photo, whole, at its own proportions, with its caption under it */
.about-portrait { margin: 0; }
.about-portrait[hidden] { display: none; }
.about-portrait img,
.about-portrait video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--surface);
  /* the same pink as the highlights, as a fine rule under the photo */
  border-bottom: 2px solid var(--pink);
}
.about-portrait figcaption {
  margin-top: 10px;
  color: var(--muted);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
}
.about-label {
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: 0.01em;
  line-height: 1.3;
  margin: 0 0 var(--s3);
}

.about-text {
  max-width: 60ch;
  font-family: var(--text);
  font-stretch: normal;
  font-size: 1.125rem;
  line-height: 1.65;
  font-optical-sizing: auto;
}
/* links in the text: a fine underline, filling in pink on hover */
.about-text a {
  color: inherit;
  text-decoration: underline 1px var(--fg);
  text-underline-offset: 4px;
  transition: background-color 0.12s ease;
}
.about-text a:hover { background: var(--pink); color: var(--on-pink); }
.about-text a .ext-tail { white-space: nowrap; }
/* the new-tab arrow: small, raised, outside the underline */
.about-text a .ext {
  display: inline-block;
  margin-left: 0.12em;
  font-family: var(--mono);
  font-size: 0.62em;
  vertical-align: 0.5em;
  line-height: 0;
  text-decoration: none;
}
.about-text p { margin: 0 0 1.1em; }
.about-text p:last-child { margin-bottom: 0; }

/* ---------- toast ---------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 10px);
  z-index: 60;
  padding: 10px 18px;
  border-radius: 6px;
  background: var(--fg);
  color: var(--bg);
  font-size: 0.875rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.selectable { pointer-events: auto; user-select: all; }

/* ---------- footer ---------- */
footer {
  position: relative;
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 28px;
  flex-wrap: wrap;
  /* the rule lines up with the content, like the header's */
  width: var(--measure);
  margin: var(--s6) auto 0;
  padding: 0 0 var(--s4);
}



.socials {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0;
  margin: -7px -10px -7px 0;
  padding: 0;
}
.social {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 44px;
  color: var(--fg);
  text-decoration: none;
  transition: color 0.15s ease;
}
.social:hover { background: var(--pink); color: var(--on-pink); }
.social-icon { display: block; width: 19px; height: 19px; }
.social-icon svg { display: block; width: 100%; height: 100%; }

/* visible to screen readers, not to eyes */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.colophon {
  margin: 0;
  color: var(--fg);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ---------- the viewer ---------- */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 28px;
}
.viewer[hidden] { display: none; }

.viewer-backdrop {
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 0.97;
}

.viewer-panel {
  position: relative;
  width: min(1040px, 100%);
  max-height: calc(100dvh - 56px);
  overflow: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 44px;
  align-items: start;
}

.viewer-close {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  z-index: 2;
  transition: color 0.15s ease;
}
.viewer-close svg { width: 15px; height: 15px; }
.viewer-close:hover { background: var(--pink); color: var(--on-pink); }

.viewer-media {
  display: grid;
  gap: 12px;
  min-width: 0;
}

/* the art, with arrows either side when a piece has several images */
.viewer-stage { position: relative; display: grid; min-width: 0; }
.viewer-step {
  position: absolute;
  top: 50%;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--fg);
  border-radius: 50%;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  color: var(--fg);
  cursor: pointer;
  z-index: 1;
  transition: background-color 0.12s ease;
}
.viewer-step.prev { left: 8px; }
.viewer-step.next { right: 8px; }
.viewer-step:hover { background: var(--pink); color: var(--on-pink); }
.viewer-step svg { width: 18px; height: 18px; }
@keyframes viewer-nudge {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: no-preference) {
  .viewer-step.next.nudge { animation: viewer-nudge 0.6s ease-in-out 0.4s 2; }
}

/* the art at its own proportions, as large as the screen allows */
.viewer-art {
  display: grid;
  place-items: center;
  min-width: 0;
}
.viewer-art .frame-inner { aspect-ratio: auto; max-width: 100%; background: none; }
.viewer-art .frame-inner img,
.viewer-art .frame-inner video {
  max-width: 100%;
  max-height: calc(100dvh - 150px);
  width: auto;
  height: auto;
}
.viewer-art .frame-inner.doodle {
  width: min(460px, 70vw);
  aspect-ratio: 1 / 1;
  padding: 34px;
}
.viewer-art svg { width: 48%; height: 48%; color: var(--muted); }

/* pause / play, under a video; worded like the back and next buttons */
.viewer-play {
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 0 12px;
  background: none;
  border: 0;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  cursor: pointer;
  transition: color 0.15s ease;
}
.viewer-play[hidden] { display: none; }
.viewer-play:hover { background: var(--pink); color: var(--on-pink); }
.viewer-play svg { width: 13px; height: 13px; }
.viewer-play .icon-play,
.viewer-play[data-state="paused"] .icon-pause { display: none; }
.viewer-play[data-state="paused"] .icon-play { display: block; }

.viewer-thumbs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.viewer-thumb {
  position: relative;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 0;
  background: var(--surface);
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s ease;
}
.viewer-thumb:hover { opacity: 1; }
.viewer-thumb[aria-current="true"] {
  opacity: 1;
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}
.viewer-thumb img,
.viewer-thumb video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.viewer-text { padding-right: 46px; }
.viewer-text h2 {
  font-family: var(--mono);
  font-size: 1.125rem;
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: 0.01em;
  margin: 0;
  line-height: 1.3;
}
.viewer-year {
  color: var(--muted);
  font-size: 0.875rem;
  margin: 4px 0 20px;
}
.viewer-note {
  margin: 0 0 28px;
  font-family: var(--text);
  font-stretch: normal;
  font-size: 1rem;
  line-height: 1.6;
}

.viewer-nav {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  padding-top: 18px;
}
.nav-btn {
  background: none;
  border: 0;
  padding: 12px 8px;
  margin: -12px -8px;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  cursor: pointer;
  transition: color 0.15s ease;
}
.nav-btn:hover { background: var(--pink); color: var(--on-pink); }
.viewer-count {
  color: var(--muted);
  font-size: 0.8125rem;
  margin-left: auto;
}

/* tablets: two columns would squeeze the text beside the photo, so the
   photo goes under the text */
@media (max-width: 960px) {
  .about { grid-template-columns: minmax(0, 60ch); }
  .about-body { grid-column: 1; grid-row: 1; }
  .about-portrait { grid-column: 1; grid-row: 2; max-width: 480px; }
}

/* ---------- small screens ---------- */
@media (max-width: 760px) {
  .nameplate { padding: var(--s2) 0 0; }
  .nameplate-top {
    margin: 0 auto;
    padding-bottom: 14px;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  /* the highlight block's padding would push the text off the left edge */
  .nav { gap: 12px; margin-left: -7px; }
  .socials { margin-left: -10px; margin-right: 0; }
  .rooms { padding: var(--s4) 0 0; }
  .wall { --row: 230px; gap: var(--s4) var(--s3); }
  #wall { margin-top: var(--s5); }
  .days { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s2); }
  .day { padding: 6px; }
  .day-concept { display: none; }
  .about {
    grid-template-columns: 1fr;
    gap: var(--s4);
    padding: var(--s4) 0 var(--s3);
  }
  /* one column: the text first, the photo after it */
  .about-body { grid-column: 1; grid-row: 1; }
  .about-portrait { grid-column: 1; grid-row: 2; max-width: 480px; }
  .about-text { font-size: 1.0625rem; }
  footer {
    margin-top: var(--s5);
    padding: var(--s3) 0 var(--s4);
    flex-direction: column;
    gap: 14px;
  }
  .viewer { padding: 20px; }
  .viewer-panel {
    grid-template-columns: 1fr;
    gap: 26px;
  }
  .viewer-text { padding-right: 0; }
  /* the art spans the full width here, so the close button gets its own
     strip above it instead of sitting on the piece */
  .viewer-panel { padding-top: 40px; }
  .viewer-close { top: -4px; right: -10px; }
  .viewer-art .frame-inner img,
  .viewer-art .frame-inner video { max-height: 58dvh; }
  .viewer-art .frame-inner.doodle { padding: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
