/* ==========================================================================
   Kitty van de Rijt, 2026
   A quiet, achromatic frame. The colour belongs to the paintings.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@400;500&family=Newsreader:ital,opsz,wght@0,6..72,200..400;1,6..72,200..400&display=swap');

:root{
  /* achromatic ground, slightly cool, so the warm canvases lift off it */
  --paper:        #EFEEEC;
  --paper-lift:   #F7F6F5;
  --paper-deep:   #E4E3E0;
  --ink:          #100F0E;
  --ink-70:       #4B4A47;
  --ink-45:       #6B6963;   /* 4.7:1 on paper, labels stay legible */
  --ink-25:       #B6B4AF;
  --rule:         #D8D6D1;

  /* Newsreader: open, wide, low-contrast. Optical sizing lets the big
     settings stay generous instead of tightening the way a display cut does. */
  --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --sans:  'Archivo', -apple-system, 'Helvetica Neue', Arial, sans-serif;

  --gut: clamp(1.25rem, 4vw, 3.5rem);   /* page margin */
  --stack: clamp(5rem, 14vw, 13rem);    /* vertical rhythm between movements */

  --ease: cubic-bezier(.22,.61,.36,1);
}

/* ---------- reset ---------- */
*,*::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:var(--sans);
  font-size:clamp(15px,.55vw + 13.4px,17px);
  line-height:1.75;
  font-weight:400;
  letter-spacing:-.005em;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img{ display:block; max-width:100%; height:auto; }
a{ color:inherit; }
h1,h2,h3,p,figure,blockquote{ margin:0; }
ul{ margin:0; padding:0; list-style:none; }
::selection{ background:var(--ink); color:var(--paper); }

/* ---------- type scale ---------- */
.display{
  font-family:var(--serif);
  font-optical-sizing:auto;
  font-weight:300;
  font-size:clamp(2.5rem,7vw,7rem);
  line-height:1.02;
  letter-spacing:-.014em;
}
.display em{ font-style:italic; }

.statement{
  font-family:var(--serif);
  font-optical-sizing:auto;
  font-weight:300;
  font-size:clamp(1.5rem,3.1vw,2.9rem);
  line-height:1.22;
  letter-spacing:-.008em;
}

.lede{
  font-size:clamp(1.02rem,.9vw + .78rem,1.28rem);
  line-height:1.62;
  color:var(--ink-70);
}

.label{
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:.185em;
  text-transform:uppercase;
  line-height:1.4;
  color:var(--ink-45);
  font-feature-settings:"tnum";
}
.label--ink{ color:var(--ink); }

.prose p + p{ margin-top:1.35em; }
.prose{ color:var(--ink-70); max-width:62ch; }
.prose strong{ color:var(--ink); font-weight:500; }

/* ---------- layout ---------- */
/* A ceiling on the measure. Without it an image on a 27-inch screen is asked
   for more pixels than the photograph contains, and softens. */
.wrap{ padding-inline:var(--gut); max-width:1680px; margin-inline:auto; }
.grid{
  display:grid;
  grid-template-columns:repeat(12,minmax(0,1fr));
  column-gap:clamp(.9rem,2.2vw,2rem);
}
.section{ padding-block:var(--stack); }
.rule{ height:1px; background:var(--rule); border:0; margin:0; }

/* ---------- skip link ---------- */
.skip{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--ink); color:var(--paper); padding:.8rem 1.2rem;
}
.skip:focus{ left:var(--gut); top:.6rem; }

/* ---------- masthead ---------- */
.masthead{
  position:sticky; top:0; z-index:50;
  padding:clamp(1rem,2vw,1.6rem) var(--gut);
  display:flex; align-items:baseline; justify-content:space-between; gap:2rem;
  background:color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter:saturate(140%) blur(14px);
  -webkit-backdrop-filter:saturate(140%) blur(14px);
  border-bottom:1px solid transparent;
  transition:border-color .5s var(--ease);
}
.masthead.is-scrolled{ border-bottom-color:var(--rule); }
.masthead__name{
  font-size:.75rem; font-weight:500; letter-spacing:.24em; text-transform:uppercase;
  text-decoration:none; white-space:nowrap;
}
.nav{ display:flex; gap:clamp(1.1rem,2.6vw,2.6rem); }
.nav a{
  font-size:.6875rem; font-weight:500; letter-spacing:.185em; text-transform:uppercase;
  text-decoration:none; color:var(--ink-45);
  padding-block:.2rem;
  transition:color .35s var(--ease);
}
.nav a:hover,.nav a:focus-visible{ color:var(--ink); }
.nav a[aria-current="page"]{ color:var(--ink); }
.nav a[aria-current="page"]::after{
  content:""; display:block; height:1px; background:var(--ink); margin-top:.34rem;
}

/* ---------- hero ----------
   The opening image is a fragment, so it is deliberately NOT full-bleed:
   a crop only has so many pixels, and stretching one across the viewport
   is what makes it look soft. It sits in seven columns and stays crisp. */
.hero{ padding-top:clamp(2rem,7vh,5rem); }
.hero__figure{ grid-column:1 / span 12; }
.hero__title{ grid-column:1 / span 12; margin-top:clamp(2rem,5vw,3.5rem); }
@media (min-width:900px){
  /* Eight columns, flush right, the same slot every right-hand canvas uses. */
  .hero__figure{ grid-column:5 / span 8; }
  .hero__title{ grid-column:1 / span 4; grid-row:1; align-self:end; margin-top:0; }
  /* The name yields to the image here: at full display size it out-shouted
     a fragment that is only 1166 px tall. */
  .hero__title{ font-size:clamp(2.4rem,4.6vw,4.6rem); }
}
.hero__frame{
  position:relative; overflow:hidden;
  background:var(--paper-deep);
}
.hero__frame img{
  width:100%; height:auto; display:block;   /* native ratio, never re-cropped */
  transform:scale(1.03);
  transition:transform 14s var(--ease);
}
.hero.is-in .hero__frame img{ transform:scale(1); }
.hero__meta{
  display:flex; justify-content:space-between; gap:1.5rem;
  padding-top:.8rem;
}

/* ---------- the swap: full work <-> fragment ---------- */
.plate{ position:relative; display:block; }
.plate__stage{
  position:relative; overflow:hidden; background:var(--paper-deep);
  cursor:crosshair;
}
.plate__stage img{
  width:100%; display:block;
  transition:opacity 1.05s var(--ease), transform 1.6s var(--ease);
}
/* The swap image is generated at the SAME aspect ratio as the work it
   covers, so object-fit has nothing to trim. Proportions never shift. */
.plate__alt{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover;
  opacity:0;
  transform:scale(1.025);
}
.plate.is-open .plate__base{ opacity:0; }
.plate.is-open .plate__alt{ opacity:1; transform:scale(1); }

.plate__caption{
  display:flex; justify-content:space-between; align-items:baseline; gap:1.5rem;
  padding-top:.8rem;
  border-top:1px solid var(--rule);
  margin-top:.9rem;
}
.plate__state{ position:relative; display:inline-block; min-width:5.5em; text-align:right; }
.plate__state span{
  position:absolute; right:0; top:0; white-space:nowrap;
  transition:opacity .5s var(--ease);
}
.plate__state .s-full{ opacity:1; }
.plate__state .s-frag{ opacity:0; }
.plate.is-open .plate__state .s-full{ opacity:0; }
.plate.is-open .plate__state .s-frag{ opacity:1; }

@media (hover:none){ .plate__stage{ cursor:pointer; } }

/* ---------- work entries ---------- */
.entry{ padding-block:clamp(4rem,10vw,9rem); }
.entry + .entry{ border-top:1px solid var(--rule); }

.entry__index{ grid-column:1 / span 12; margin-bottom:1.6rem; }
.entry__plate{ grid-column:1 / span 12; }
.entry__text{ grid-column:1 / span 12; margin-top:2.4rem; }
.entry__frag{ display:none; }

@media (min-width:900px){
  /* Rows are stated, never inferred. With auto-placement a child whose
     column start lies behind the cursor is pushed onto a fresh row, which
     is what dropped the fragment a whole row below the text. */
  .entry__index{ grid-row:1; grid-column:1 / span 2; margin-bottom:0; }
  .entry__plate{ grid-row:1; grid-column:3 / span 8; }
  .entry__text { grid-row:2; grid-column:3 / span 4; margin-top:3rem; }
  .entry__frag {
    grid-row:2; grid-column:8 / span 3;
    display:block; margin-top:3rem;
    align-self:start;          /* top edge level with the text */
  }

  /* Mirrored on every second work. The outer edges stay flush with the
     canvas above: text ends where the canvas ends, fragment begins where
     it begins. */
  .entry:nth-child(even) .entry__index{ grid-column:11 / span 2; text-align:right; }
  .entry:nth-child(even) .entry__plate{ grid-column:3 / span 8; }
  .entry:nth-child(even) .entry__text { grid-column:7 / span 4; }
  .entry:nth-child(even) .entry__frag { grid-column:3 / span 3; }
}
.entry__frag figcaption{ margin-top:.7rem; }

/* ---------- home sequence ---------- */
.seq{ padding-block:var(--stack); }
.seq__lead{ grid-column:1 / span 12; }
@media (min-width:900px){
  .seq__lead{ grid-column:3 / span 7; }
}

/* Two fragments side by side, flush with the page edge. Capped in width so
   neither is ever asked to render wider than the pixels it actually has. */
.duo{
  display:grid; gap:clamp(1.1rem,3vw,2.5rem);
  grid-template-columns:1fr; align-items:end;
  max-width:54rem;
  grid-column:1 / span 12;
}
@media (min-width:900px){ .duo{ grid-column:1 / span 8; } }
@media (min-width:760px){
  .duo{ grid-template-columns:1fr .74fr; }
  .duo--flip{ grid-template-columns:.74fr 1fr; }
}

.offset{ grid-column:1 / span 12; }
/* Text always begins at column 3. A canvas is flush right (5-12), on the
   centre axis (2-11), or flush with the page edge (the duo of fragments).
   Column 1 is reserved for the page edge: the name, the fragments, the
   index. The near-miss left edges that came before read as drift. */
@media (min-width:900px){
  .offset--l{ grid-column:1 / span 7; }
  .offset--r{ grid-column:5 / span 8; }   /* canvas, right edge of the page */
  .offset--c{ grid-column:3 / span 8; }   /* text */
  .offset--narrow{ grid-column:4 / span 6; }  /* text, on the centre axis */
  .offset--axis{ grid-column:2 / span 10; }   /* canvas, on the centre axis */
  /* smaller slots, for fragments that do not have the pixels for seven columns */
  .offset--l5{ grid-column:2 / span 5; }
  .offset--r6{ grid-column:6 / span 6; }
}

/* ---------- index list ---------- */
.index__row{
  display:grid; grid-template-columns:2.5rem 1fr auto; gap:1rem;
  align-items:baseline;
  padding-block:1.15rem;
  border-top:1px solid var(--rule);
  text-decoration:none;
  transition:padding-left .5s var(--ease), color .4s var(--ease);
}
.index__row:last-child{ border-bottom:1px solid var(--rule); }
.index__row:hover,.index__row:focus-visible{ padding-left:.7rem; }
.index__title{
  font-family:var(--serif);
  font-size:clamp(1.4rem,3vw,2.35rem);
  line-height:1.1; letter-spacing:-.015em;
}
.index__meta{ color:var(--ink-45); }
@media (max-width:600px){
  .index__row{ grid-template-columns:2rem 1fr; }
  .index__meta{ grid-column:2; }
}

/* ---------- quiet links ---------- */
.qlink{
  display:inline-block;
  text-decoration:none;
  font-size:.6875rem; font-weight:500; letter-spacing:.185em; text-transform:uppercase;
  padding-bottom:.35rem;
  background-image:linear-gradient(currentColor,currentColor);
  background-size:100% 1px; background-repeat:no-repeat; background-position:0 100%;
  transition:background-size .55s var(--ease), opacity .35s var(--ease);
}
.qlink:hover,.qlink:focus-visible{ background-size:0% 1px; background-position:100% 100%; }
.mail{
  font-family:var(--serif);
  font-size:clamp(1.5rem,4.6vw,3.4rem);
  line-height:1.1; letter-spacing:-.02em;
  text-decoration:none;
  background-image:linear-gradient(currentColor,currentColor);
  background-size:100% 1px; background-repeat:no-repeat; background-position:0 100%;
  transition:background-size .6s var(--ease);
  word-break:break-word;
}
.mail:hover,.mail:focus-visible{ background-size:0% 1px; background-position:100% 100%; }

/* ---------- chronology ---------- */
.chron{ border-top:1px solid var(--rule); }
.chron li{
  display:grid; grid-template-columns:4.5rem 1fr; gap:1rem;
  padding-block:.85rem;
  border-bottom:1px solid var(--rule);
  color:var(--ink-70);
  font-size:.94rem;
}
.chron li span:first-child{
  font-size:.6875rem; font-weight:500; letter-spacing:.14em;
  color:var(--ink-45); padding-top:.32em; font-feature-settings:"tnum";
}
.chron__note{ padding-block:1rem; color:var(--ink-45); font-size:.88rem; }

/* ---------- portrait ---------- */
.portrait img{ filter:grayscale(1) contrast(1.03); }

/* ---------- footer ---------- */
.foot{
  border-top:1px solid var(--rule);
  padding:clamp(2.5rem,6vw,4.5rem) var(--gut) clamp(1.6rem,3vw,2.4rem);
}
.foot__grid{ display:flex; flex-wrap:wrap; gap:2rem 3.5rem; justify-content:space-between; align-items:flex-start; }
.foot__nav{ display:flex; flex-direction:column; gap:.55rem; }
.foot__nav a{ text-decoration:none; color:var(--ink-70); font-size:.94rem; transition:color .35s var(--ease); }
.foot__nav a:hover{ color:var(--ink); }
.foot__base{
  display:flex; flex-wrap:wrap; gap:1rem 2rem; justify-content:space-between;
  margin-top:clamp(2.5rem,6vw,4.5rem);
}

/* ---------- reveal ---------- */
.rv{ opacity:0; transform:translateY(14px); }
.rv.is-in{ opacity:1; transform:none; transition:opacity 1.1s var(--ease), transform 1.1s var(--ease); }
.rv-d1.is-in{ transition-delay:.09s; }
.rv-d2.is-in{ transition-delay:.18s; }

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
  .rv{ opacity:1; transform:none; }
  .hero__frame img{ transform:none; }
}

/* ---------- focus ---------- */
:focus-visible{ outline:1px solid var(--ink); outline-offset:3px; }
