/* Jessica de Ruiter — splash page
   ------------------------------------------------------------------
   Type:  Bodoni Moda for the wordmark (high-contrast didone)
   Grid:  full-bleed, every tile identical (3:4 portrait, cover crop),
          separated by a 1px seam. 4 columns desktop / 3 tablet /
          2 on phones, so sets of 12 always fill complete rows.
   Chrome: black wordmark in a white box top-left, Instagram in a
          matching box top-right, both floating over the grid.
   ------------------------------------------------------------------ */

:root {
  --paper: #000;
  --loading: #0b2bff; /* shows while a tile's image is still loading */
  --ink: #16150f;
  --seam: 1px;
  --frame: 1px; /* black border around the whole page */
  --fade: 900ms;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

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

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

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%; }

/* 1px black frame around the whole site, drawn above everything. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 30;
  border: var(--frame) solid #000;
  pointer-events: none;
}

a { color: inherit; text-decoration: none; }

/* ---------- Stage: grids stacked in one cell for the crossfade ---- */

/* The splash fills the viewport: one screen, no scrolling. Each set is a
   five-across, two-deep grid of equal cells; images crop to fit (cover).
   Landscapes never stand alone — two of them stack inside one cell, so a
   pair reads as tall as a single portrait. Phones fall back to a normal
   two-column scroll (see the 639px block). */

.stage {
  display: grid;              /* all sets share one cell for the crossfade */
  grid-template-rows: minmax(0, 1fr);   /* cap the row at the stage height */
  height: 100vh;
  height: 100dvh;
  padding: var(--frame);
  overflow: hidden;
}

.stage > .grid { grid-area: 1 / 1; }

.grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(2, minmax(0, 1fr));
  /* surplus blocks (at narrower breakpoints) must not create a paying row */
  grid-auto-rows: 0;
  gap: var(--seam);
  height: 100%;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* The outgoing set stays painted for the length of the fade (the incoming
     one is layered on top of it), so no page background shows through. */
  transition: opacity var(--fade) var(--ease), visibility 0s linear var(--fade);
}

.grid.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--fade) var(--ease), visibility 0s;
}

.tile {
  margin: 0;
  overflow: hidden;
  min-height: 0;
  background: var(--loading);
}

/* Two landscapes stacked inside one cell. */
.stack {
  display: grid;
  grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--seam);
  min-height: 0;
  overflow: hidden;
}

.tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Chrome over the grid --------------------------------- */

.chrome-left {
  position: fixed;
  top: clamp(14px, 2vw, 26px);
  left: clamp(14px, 2vw, 26px);
  z-index: 20;
}

/* Chrome sits directly on the images — no boxes, no drop shadow. Difference
   blending inverts whatever is behind it, so the name reads on a light photo
   and on a dark one, and turns black by itself over the white bio panel. */
.wordmark,
.bio-open,
.social {
  background: transparent;
  color: #fff;
  mix-blend-mode: difference;
}
.wordmark {
  padding: 0;
  font-family: "Bodoni Moda", "Didot", "Times New Roman", serif;
  font-weight: 400;
  font-size: clamp(25px, 2.8vw, 42px);
  line-height: 1;
  letter-spacing: .02em;
  white-space: nowrap;
}

/* Bio floats in the opposite corner, underlined. */
.bio-open {
  position: fixed;
  bottom: clamp(14px, 2vw, 26px);
  left: clamp(14px, 2vw, 26px);
  z-index: 20;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  cursor: pointer;
  transition: opacity .3s var(--ease);
}

.bio-open:hover { opacity: .55; }

.social {
  position: fixed;
  /* nudged up so the icon reads level with the wordmark */
  top: calc(clamp(14px, 2vw, 26px) - 8px);
  right: clamp(14px, 2vw, 26px);
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: opacity .3s var(--ease);
}

.social:hover { opacity: .55; }

/* Instagram shows by default; the X takes its place while the bio is open. */
.social--close { display: none; }
body.bio-is-open .social { display: none; }
body.bio-is-open .social--close { display: flex; }

/* In bio view blending is unreliable against the overlay's own stacking
   context, so the chrome is forced to plain black over the white panel. */
body.bio-is-open .bio-open { display: none; }

body.bio-is-open .wordmark,
body.bio-is-open .social--close {
  mix-blend-mode: normal;
  color: #000;
}

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

.bio {
  position: fixed;
  inset: 0;
  z-index: 15;
  /* Left half solid white, right half semi-transparent white, with a black
     line down the middle: the page reads as split in two. */
  display: flex;
  align-items: stretch;
  background:
    linear-gradient(to right,
      #fff 0, #fff 46%,
      #000 46%, #000 calc(46% + 1px),
      rgba(255, 255, 255, .88) calc(46% + 1px), rgba(255, 255, 255, .88) 100%);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade) var(--ease), visibility 0s linear var(--fade);
}

body.bio-is-open .bio {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--fade) var(--ease), visibility 0s;
}

/* A white band across the top of the white half: copy scrolls out of sight
   under it instead of sliding past the wordmark. */
.bio::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1;
  width: 46%;
  height: clamp(76px, 13vh, 132px);
  background: #fff;
}

/* The white half holds the copy; equal gutters left and right, its left edge
   on the J of the wordmark. It scrolls on its own. */
.bio__inner {
  width: 46%;
  padding: clamp(96px, 16vh, 168px) clamp(14px, 2vw, 26px)
           clamp(28px, 6vh, 64px);
  overflow-y: auto;
}

.bio__portrait {
  margin: 0 0 clamp(22px, 3vh, 38px);
}

.bio__portrait img { width: 100%; height: auto; filter: grayscale(1); }

.bio__text p {
  margin: 0 0 18px;
  font-size: clamp(14px, 1.05vw, 17px);
  line-height: 1.65;
  text-wrap: pretty;
}

.bio__contact {
  margin-top: 28px;
  font-size: clamp(14px, 1.05vw, 17px);
}

.bio__contact a {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color .25s var(--ease);
}

.bio__contact a:hover { color: #c026a6; }

.bio__sep { padding: 0 .7em; }

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

/* Fewer, larger cells on tablets — still one screen. Blocks beyond the cell
   count are hidden so the two rows always fill exactly. */
@media (max-width: 999px) {
  .grid { grid-template-columns: repeat(4, 1fr); }
  .grid > :nth-child(n + 9) { display: none; }
}

@media (max-width: 767px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
  .grid > :nth-child(n + 7) { display: none; }
}

/* Phones: let it scroll, two columns of 3:4 tiles. */
@media (max-width: 639px) {
  .stage { height: auto; overflow: visible; }
  .grid {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: none;
    grid-auto-rows: auto;
    height: auto;
    align-content: start;
  }
  .grid > :nth-child(n + 7) { display: block; }
  /* Phones: one white sheet, no split. */
  .bio {
    background: #fff;
    position: fixed;
  }
  .bio::before { width: 100%; }

  /* On the phone's full-white bio sheet, blending is unreliable — force the
     chrome to plain black. */
  body.bio-is-open .wordmark,
  body.bio-is-open .social--close {
    mix-blend-mode: normal;
    color: #000;
  }
  .bio__inner {
    width: auto;
    padding-right: clamp(14px, 2vw, 26px);
  }
  .tile--port, .stack { aspect-ratio: 3 / 4; }
  .wordmark { font-size: 23px; }
  .social { width: 44px; height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .tile img, .grid { transition-duration: 1ms; }
}
