/* Jessica de Ruiter
   ------------------------------------------------------------------
   One long scroll of small, gutterless images. The name is centred at
   the top of the page and again at the foot, white on near-black. Bio
   opens as a dark overlay. The name is an inline SVG logo (see the
   <symbol> in index.html); everything else is set in Helvetica.

   Grid: portraits only, every tile 3:4, no gutters, 6 / 3 / 2 columns.
   An incomplete final row hides itself (the "orphan row" rules below),
   so images can be added or removed freely without leaving a ragged
   bottom edge at any breakpoint.
   ------------------------------------------------------------------ */

:root {
  --paper: rgb(235, 229, 225);
  --ink: rgb(59, 51, 49);
  --ink-soft: rgb(124, 114, 109);
  --accent: rgb(28, 24, 23);   /* hover */
  --fade: 420ms;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }

/* ---------- Wordmark, top and foot -------------------------------- */

/* The band at the top is just the page ground; the name then sticks, riding
   up level with the corner chrome and floating over the pictures as they
   scroll under it. The negative offset lets the mark — not the top of the
   band — come to rest at --mark-top. */
.masthead {
  --mark-pad: clamp(38px, 8vh, 86px);
  --mark-top: clamp(10px, 1.6vw, 20px);
  position: sticky;
  top: calc(var(--mark-top) - var(--mark-pad));
  z-index: 20;
  display: flex;
  justify-content: center;
  padding: var(--mark-pad) 20px clamp(30px, 6vh, 62px);
  pointer-events: none;
}

/* Same 52px box as .bio-open / .social so the name rests on their line. */
.masthead .wordmark {
  align-items: center;
  height: 52px;
}

.masthead .wordmark a { pointer-events: auto; }

.masthead .wordmark__svg {
  color: var(--ink);
  transition: color .2s var(--ease);
}

/* Once it leaves the band it sits over the pictures, where black holds up
   better than the warm dark of the type. The corner chrome follows suit. */
.masthead.is-over-work .wordmark__svg,
body.is-over-work .bio-open,
body.is-over-work .social { color: #000; }

/* The masthead is page content under the overlay, so it would ghost through
   the veil. Hide it while the bio is open. */
body.bio-is-open .masthead { visibility: hidden; }

.wordmark {
  display: flex;
  justify-content: center;
  margin: 0;
  line-height: 1;
}

.wordmark a { display: block; }

/* The logo is inline SVG (see the <symbol> at the top of index.html) so it
   takes its colour from the surrounding type and needs no network request. */
.wordmark__svg {
  display: block;
  height: clamp(21px, 3.1vw, 44px);
  width: auto;
  aspect-ratio: 126.66 / 9.05;
  fill: currentColor;
  overflow: visible;
}

/* The foot is a warm off-white band closing the scroll, so type inverts. */
.colophon {
  display: grid;
  justify-items: center;
  gap: 18px;
  padding: clamp(42px, 9vh, 96px) 20px clamp(38px, 8vh, 84px);
  background: rgb(235, 229, 225);
  color: rgb(59, 51, 49);
}

.wordmark--foot .wordmark__svg { height: clamp(14px, 1.8vw, 25px); }

.colophon__role {
  margin: -6px 0 0;
  font-size: 9px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #6f675f;
}

.colophon__links {
  /* pairs stay together so a separator never ends a line */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  margin: 0;
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #6f675f;
  text-align: center;
}

.colophon__links a { color: rgb(59, 51, 49); white-space: nowrap; }
.colophon__links a:hover { color: rgb(59, 51, 49); }
.colophon__sep { padding: 0 .8em; }

@media (max-width: 600px) {
  .colophon__links {
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
  .colophon__sep { display: none; }
}

/* Below 600px the Bio button and Instagram icon sit close enough to the
   centred wordmark that it needs to yield room rather than just shrink
   uniformly — pin its width to the space actually left between them. */
@media (max-width: 600px) {
  .masthead .wordmark__svg {
    height: auto;
    width: calc(100vw - 160px);
    min-width: 110px;
    max-width: 260px;
  }
}

/* ---------- Grid -------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0;
}

.tile {
  margin: 0;
  overflow: hidden;
  /* the block blacks in first (js/grid.js adds .is-lit), then its image
     fades in on top of it */
  background: transparent;
  aspect-ratio: 3 / 4;
  transition: background-color 260ms var(--ease);
}

.tile.is-lit { background-color: rgb(214, 205, 199); }


.tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* each image fades up as it decodes — js/grid.js adds .is-in */
  opacity: 0;
  transition: opacity var(--fade) var(--ease);
}

.tile img.is-in { opacity: 1; }

/* ---------- Fixed corner chrome ---------------------------------- */

/* Difference blending keeps these legible over photos and over white. */
.bio-open,
.social {
  position: fixed;
  z-index: 20;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}

.bio-open {
  /* same top and box height as .social, inset by the same amount the
     Instagram glyph sits inside its 52px box, so the two align optically */
  top: clamp(10px, 1.6vw, 20px);
  left: calc(clamp(14px, 2vw, 26px) + 14px);
  display: flex;
  align-items: center;
  height: 52px;
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  transition: opacity .3s var(--ease);
}

.social {
  top: clamp(10px, 1.6vw, 20px);
  right: clamp(14px, 2vw, 26px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  transition: opacity .3s var(--ease);
}

/* One hover colour for everything: type is off-white and goes bright white.
   The corner chrome drops its difference blending on hover. */
.bio-open:hover,
.social:hover { color: var(--accent); }

.social--close { display: none; }
body.bio-is-open .social { display: none; }
body.bio-is-open .social--close { display: flex; }

/* Over the bio panel, blending is unreliable — set the colour plainly. */
body.bio-is-open .bio-open { display: none; }

body.bio-is-open .social--close {
  color: var(--ink);
  transition: color .25s var(--ease);
}

body.bio-is-open .social--close:hover { color: var(--accent); }

/* ---------- Bio overlay ------------------------------------------ */

/* A spread: the portrait takes the left of the window full bleed, the name
   and copy sit in a narrow measure on the right. */
.bio {
  position: fixed;
  inset: 0;
  z-index: 15;
  overflow-y: auto;
  background: rgb(235, 229, 225);
  color: rgb(59, 51, 49);
  opacity: 0;
  visibility: hidden;
  transition: opacity 300ms cubic-bezier(.05, .8, .15, 1), visibility 0s linear 300ms;
}

body.bio-is-open .bio {
  opacity: 1;
  visibility: visible;
  transition: opacity 300ms cubic-bezier(.05, .8, .15, 1), visibility 0s;
}

.bio__inner {
  display: grid;
  grid-template-columns: 42% 1fr;
  min-height: 100%;
}

.bio__plate {
  overflow: hidden;
  background: rgb(214, 205, 199);
}

.bio__plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
}

.bio__col {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(60px, 9vh, 110px) clamp(34px, 5vw, 72px);
}

/* Three paragraphs is taller than most windows, so the copy column scrolls
   on its own and the portrait stays put beside it. */
@media (min-width: 821px) {
  .bio__inner { height: 100vh; }
  .bio__plate { position: sticky; top: 0; height: 100vh; }
  .bio__col { justify-content: flex-start; overflow-y: auto; }
}

/* The panel cross-fades in one piece — no staggered drift. */
.bio__label,
.bio__mark,
.bio__text {
  opacity: 0;
  transition: opacity 260ms cubic-bezier(.05, .8, .15, 1);
}

body.bio-is-open .bio__label,
body.bio-is-open .bio__mark,
body.bio-is-open .bio__text { opacity: 1; }

.bio__label {
  margin: 0 0 clamp(18px, 3vh, 26px);
  font-size: 9px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #6f675f;
}

.bio__mark {
  display: flex;
  justify-content: flex-start;
  margin: 0 0 clamp(30px, 5vh, 54px);
  line-height: 1;
}

.bio__mark .wordmark__svg { height: clamp(20px, 2.4vw, 32px); }

.bio__text p + p { margin-top: 1.1em; }

.bio__text p {
  max-width: 68ch;
  margin: 0;
  text-indent: 0;
  font-size: 13.5px;
  line-height: 1.85;
  text-align: left;
  text-wrap: pretty;
}

.bio__text p.bio__contact {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  max-width: none;
  margin-top: clamp(38px, 6vh, 62px);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #6f675f;
}

.bio__contact a {
  color: rgb(59, 51, 49);
  white-space: nowrap;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color .25s var(--ease);
}

.bio__contact a:hover { color: rgb(59, 51, 49); }

.bio__sep { padding: 0 .8em; }

@media (max-width: 600px) {
  .bio__text p.bio__contact {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .bio__sep { display: none; }
}

/* Under 820px the plate goes above the copy rather than beside it. */
@media (max-width: 820px) {
  .bio__inner { grid-template-columns: 1fr; }
  .bio__plate { height: 58vh; }
  .bio__col { justify-content: flex-start; }
}

/* ---------- Responsive ------------------------------------------- */

/* Orphan row, 6 columns: find the first tile of the last row when that row
   is short (fewer than 6 tiles follow it), and hide it and everything after.
   Independent of the total image count. */
.grid > :nth-child(6n + 1):nth-last-child(-n + 5),
.grid > :nth-child(6n + 1):nth-last-child(-n + 5) ~ * { display: none; }

@media (max-width: 860px) {
  /* four across on tablets and large phones */
  .grid { grid-template-columns: repeat(4, 1fr); }

  .grid > :nth-child(6n + 1):nth-last-child(-n + 5),
  .grid > :nth-child(6n + 1):nth-last-child(-n + 5) ~ * { display: block; }

  /* orphan row, 4 columns */
  .grid > :nth-child(4n + 1):nth-last-child(-n + 3),
  .grid > :nth-child(4n + 1):nth-last-child(-n + 3) ~ * { display: none; }
  .social { width: 44px; height: 44px; }
  .bio-open,
  .masthead .wordmark { height: 44px; }
}

/* Four across is the floor — phones keep four columns, never three. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .tile img { opacity: 1; transition: none; }
  .bio__inner > * { opacity: 1; transform: none; transition: none; }
}
