/* ==========================================================================
   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);

  /* below this the bar folds into a single mark; four words plus the name
     stop fitting on one line somewhere around 500px, this leaves room */
  --bar: 680px;
}

/* ---------- reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  /* an anchor must not land underneath the sticky bar. Just over its
     height, so the hairline above a work stays visible. */
  scroll-padding-top:clamp(4.6rem,6vw,6.5rem);
}
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;
}
/* The blur lives on a layer of its own, not on the bar itself. An element
   with backdrop-filter becomes the containing block for anything fixed
   inside it, which would have shrunk the menu sheet to the size of the bar. */
.masthead::before{
  content:""; position:absolute; inset:0; z-index:-1;
  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::before{ border-bottom-color:var(--rule); }
.masthead__name{
  /* stays on top of the menu sheet, so the way back is never lost */
  position:relative; z-index:60;
  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{
  position:relative;
  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);
}
/* A finger needs 44px, the letter does not. The target grows, nothing moves. */
.nav a::before{
  content:""; position:absolute; left:0; right:0; top:50%;
  height:44px; transform:translateY(-50%);
}
.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;
}

/* ---------- the mark that opens the menu ----------
   Two hairlines, the same weight as every other rule on the site, crossing
   when the sheet is open. Hidden above --bar, where the words themselves fit. */
.burger{
  display:none;
  position:relative; z-index:60;
  align-self:center;
  width:44px; height:44px; margin-block:-14px; margin-right:-11px;
  padding:0; border:0; background:none; color:var(--ink);
  cursor:pointer; -webkit-tap-highlight-color:transparent;
}
.burger__bars{ display:block; position:relative; width:22px; height:1px; margin:0 auto; }
.burger__bars::before,.burger__bars::after{
  content:""; position:absolute; left:0;
  width:22px; height:1px; background:currentColor;
  transition:top .3s var(--ease), transform .4s var(--ease);
}
.burger__bars::before{ top:-4px; }
.burger__bars::after{ top:4px; }
.burger[aria-expanded="true"] .burger__bars::before{ top:0; transform:rotate(45deg); }
.burger[aria-expanded="true"] .burger__bars::after{ top:0; transform:rotate(-45deg); }

@media (max-width:679.98px){
  .burger{ display:block; }
  /* The same four links, laid out as a sheet. One list, not two. */
  .nav{
    position:fixed; inset:0; z-index:40;
    flex-direction:column; justify-content:center; align-items:flex-start;
    gap:clamp(.6rem,2.2vh,1.4rem);
    padding:var(--gut);
    background:var(--paper);
    opacity:0; visibility:hidden;
    /* visibility flips at once on the way in, so the first link can take
       focus straight away, and waits for the fade on the way out */
    transition:opacity .45s var(--ease), visibility 0s linear .45s;
  }
  .nav.is-open{
    opacity:1; visibility:visible;
    transition:opacity .45s var(--ease), visibility 0s linear 0s;
  }
  .nav a{
    font-family:var(--serif); font-optical-sizing:auto; font-weight:300;
    font-size:clamp(2rem,11vw,3.1rem);
    letter-spacing:-.015em; line-height:1.15; text-transform:none;
    color:var(--ink-70); padding-block:.1em;
  }
  .nav a::before{ height:100%; }
  .nav a[aria-current="page"]::after{ display:none; }
  .nav a[aria-current="page"]{ color:var(--ink); }
  body.nav-open{ overflow:hidden; }
}

/* ---------- 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); }
/* Stacked, the name sits above the fragment and needs air under it.
   Without this the descender of the j rests on the paint. */
.hero__figure{ grid-column:1 / span 12; margin-top:clamp(1.6rem,6vw,3rem); }
.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; margin-top:0; }
  .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); }

/* ---------- the loupe: the cut that follows the cursor ----------
   Where there is a mouse and motion is welcome, the fixed fragment above
   gives way to the work itself, enlarged, with the point under the cursor
   held still. main.js adds .plate--loupe; on touch and under
   prefers-reduced-motion the class is never set and nothing here applies.

   1.3 is not a design preference but a ceiling. Five of the seven sources
   are 1350 px and already fill their column at about 1.3x. Enlarge further
   and the paint goes soft. Once the H30cm TIFs are in, this can go to 2.4
   in one place: --loupe below. */
.plate--loupe{ --loupe:1.3; }
.plate--loupe .plate__alt{ display:none; }
.plate--loupe .plate__base{
  transition:transform 1.15s var(--ease);
  will-change:transform;
}
.plate--loupe.is-open .plate__base{
  opacity:1;
  transform:scale(var(--loupe));
  transition:transform .45s var(--ease);
}

.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__head { grid-column:1 / span 12; margin-top:2.4rem; }
.entry__body { grid-column:1 / span 12; margin-top:1.4rem; }

@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. */
  .entry__index{ grid-row:1; grid-column:1 / span 2; margin-bottom:0; }
  .entry__plate{ grid-row:1; grid-column:3 / span 8; }

  /* The title hangs from the left edge of the canvas, the description from
     the right. Between them they carry the full width of the work above,
     and both begin at the same height. The fixed fragment that used to sit
     here is gone: the canvas itself is now the thing you look into. */
  .entry__head { grid-row:2; grid-column:3 / span 4; margin-top:3rem; }
  /* The extra quarter of a line is optical, not structural. Two boxes with
     the same top do not read as level, because the serif title carries more
     leading above its capitals than the running text does. This puts the
     first line of the description level with the top of the title. */
  .entry__body { grid-row:2; grid-column:7 / span 4; margin-top:calc(3rem + .25em); }

  /* Title before description, on every work. Mirroring that pair would put
     the description first, so the alternation is carried by the number in
     the margin alone. */
  .entry:nth-child(even) .entry__index{ grid-column:11 / span 2; text-align:right; }
}

/* ---------- 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, and a canvas of 1350px */
  .offset--narrow{ grid-column:4 / span 6; }  /* text, on the centre axis */
  /* Ten columns ask a canvas for about 1300px of width. Only Icarus and
     Deep Ocean can supply that; the rest sit in eight (offset--c) until the
     H30cm TIFs are in. Kept here for when they are. */
  .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{
  position:relative;
  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::before{
  content:""; position:absolute; left:0; right:0; top:50%;
  height:44px; transform:translateY(-50%);
}
.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:1rem; }
.foot__nav a{ position:relative; text-decoration:none; color:var(--ink-70); font-size:.94rem; transition:color .35s var(--ease); }
.foot__nav a::before{
  content:""; position:absolute; left:0; right:0; top:50%;
  height:40px; transform:translateY(-50%);
}
.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; transition-delay:0s !important; }
  .rv{ opacity:1; transform:none; }
  .hero__frame img{ transform:none; }
}

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