/* ---------------------------------------------------------------------------
   Project pages. Same design system, quieter: one column of prose, images at
   full width, colour left alone — inside a project the work does the talking.
   --------------------------------------------------------------------------- */

/* --- the grid -------------------------------------------------------------
   One set of vertical lines that every part of a project page aligns to,
   rather than each section carrying its own padding and hoping they agree.

   Two lanes. `bleed` runs the full width of the viewport and belongs to the
   opening image alone. `content` is everything after it: a contained column
   with real margins, so the hero arrives edge to edge and the project settles
   inside a frame directly beneath it.

   Sections do not set horizontal padding. They pick a lane.
   -------------------------------------------------------------------------- */

.proj{
  --content-max:1280px;

  display:grid;
  grid-template-columns:
    [bleed-start] minmax(var(--page-margin), 1fr)
    [content-start] minmax(0, var(--content-max))
    [content-end] minmax(var(--page-margin), 1fr)
    [bleed-end];
  padding-top:var(--nav-height);
}
.proj > *{ grid-column:content; }
.proj__hero{ grid-column:bleed; }

/* --- head ----------------------------------------------------------------- */

/* The opening of a project is five things in a row: which number it is, what
   it is called, where it happened, what it is, and the facts of it. Spaced
   evenly they read as five equal claims competing for the same attention,
   which is what made the top of every project feel crowded and flat.

   So there is no shared gap here. Each level states its own distance, and the
   distances carry the hierarchy: a long fall from the apparatus row to the
   title, the subtitle held tight underneath it because they are one unit, then
   progressively more air down to the facts. */
.proj__head{
  padding:var(--space-10) 0 var(--space-9);
  display:flex;flex-direction:column;gap:0;
}
.proj__head h1{
  margin:0;
  max-width:16ch;
  font-size:var(--size-display-l);
  font-weight:var(--weight-semibold);
  line-height:var(--lh-display);
  letter-spacing:var(--ls-display);
  text-transform:uppercase;
  text-wrap:balance;
}
/* The apparatus row: which number this project is, and whose studio it came
   out of. Both are context rather than content, so they share one line above
   the title instead of stacking on top of it.

   Stacked, the credit read as a kicker and competed with the project name for
   the same slot. Beside the index, in the same register, it reads as what it
   is: a note in the margin of the header. */
.proj__topline{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--space-4) var(--space-6);
  flex-wrap:wrap;
  margin-bottom:var(--space-7);
}
.proj__studio{
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  text-transform:uppercase;
  color:var(--text-faint);
  /* Match the label's line box exactly. The mono default is taller, which
     grew the row and dropped the title 6px on the studio pages only -- a
     stagger you could see paging between projects. */
  line-height:1.1;
}

/* The project's own run line: dates, place, status. It qualifies the title, so
   it sits tight under it and reads one step stronger than the apparatus row
   above — that row is context about the project, this is part of it. */
.proj__run{
  margin:var(--space-4) 0 0;
  font-family:var(--font-mono);
  font-size:calc(var(--size-meta) + 1px);
  letter-spacing:var(--ls-meta);
  color:var(--text-secondary);
}

.proj__lede{
  margin:var(--space-7) 0 0;
  max-width:var(--measure-prose);
  font-size:clamp(1.125rem,1.9vw,1.5rem);
  line-height:1.45;
  letter-spacing:-0.015em;
  color:var(--text-secondary);
  text-wrap:pretty;
}

/* The facts. These were the widest thing in the header -- a band of four
   columns running the full 1280px while the title and the lede sat inside a
   reading measure -- so the smallest information on the page was also the most
   spread out. Held to the same measure as the prose above it, it reads as a
   footnote to the opening rather than a banner under it. */
.proj__meta{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:var(--space-6) var(--space-7);
  max-width:var(--measure-prose);
  margin-top:var(--space-8);
  padding-top:var(--space-6);
  /* A hairline. This was a near-black 1.5px rule running the full width of the
     page, which is a headline's weight given to a divider under one. */
  border-top:var(--border-width-hairline) solid var(--border-hairline);
}
.proj__meta dt{
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  color:var(--text-muted);
}
.proj__meta dd{
  margin:var(--space-2) 0 0;
  font-size:0.9375rem;
  font-weight:var(--weight-semibold);
  text-transform:uppercase;
  letter-spacing:var(--ls-heading);
  line-height:1.35;
}
.proj__meta dd.is-list{
  font-weight:var(--weight-regular);
  text-transform:none;
  letter-spacing:0;
  color:var(--text-secondary);
}

/* --- media ---------------------------------------------------------------- */

.proj__hero{
  margin:0 0 var(--space-10);
  background:var(--surface-media);
}
.proj__hero img{width:100%;height:auto;display:block}

.proj__body{
  display:flex;flex-direction:column;gap:var(--space-10);
}

/* Prose is prose wherever it sits: a heading inside an aside is the same
   heading as one in a text block, and was silently losing its type. */
.block--text{max-width:var(--measure-prose)}
.block--text h2,
.block__side h2{
  margin:0 0 var(--space-5);
  font-size:var(--size-heading-l);
  font-weight:var(--weight-semibold);
  line-height:var(--lh-heading);
  letter-spacing:var(--ls-heading);
  text-transform:uppercase;
}
.block--text p,
.block__side p{
  margin:0 0 var(--space-4);
  font-size:var(--size-body-l);
  line-height:var(--lh-body);
  color:var(--text-secondary);
  text-wrap:pretty;
}
.block--text p:last-child,
.block__side p:last-child{margin-bottom:0}

/* A quiet aside inside a text block — photo provenance, a caveat about what a
   page is and is not claiming. Deliberately smaller than the prose around it. */
.block--text p.proj__note,
.block__side p.proj__note{
  margin-top:var(--space-5);
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  line-height:1.6;
  color:var(--text-muted);
}

.block figure{margin:0}
.block img{
  width:100%;height:auto;display:block;
  background:var(--surface-media);
}
/* Video sits in the same frame as a still, and never downloads until asked:
   these are development animations, and they are heavy. */
.block video{
  width:100%;height:auto;display:block;
  background:var(--surface-media);
}

/* Text reads at a measure. Images do not have to, and in a portfolio they
   should not: a figure breaks out past the body padding so the work carries
   more of the page than the writing about it does.

   This replaces a blanket max-height that was meant to hold back tall media
   and instead shrank every landscape image on any normal laptop, which is
   what made the images feel small. Only genuinely tall media needs holding
   back now, and it opts in below. */
.block figure > img,
.block figure > video{
  width:100%;
  height:auto;
  max-width:100%;
}

/* Portrait media is the one case that still needs a ceiling: at full width it
   stops being an image you look at and becomes a wall you scroll past. Use
   this only where a portrait has to stand alone; where it has text to sit
   beside, .block--aside is the better answer. */
.block--tall figure > img,
.block--tall figure > video{
  width:auto;
  max-height:82svh;
  margin-inline:auto;
}

/* --- a portrait beside its own text ---------------------------------------
   A tall image centred in a wide column leaves a third of the page empty on
   either side of it, which reads as a mistake rather than as space. Given the
   text it belongs to, the same image fills the row, and the pairing says
   something the two apart do not.

   `is-flipped` puts the image on the left. Alternating down a page is what
   keeps a run of these from turning into a template.
   -------------------------------------------------------------------------- */

.block--aside{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:var(--space-6) var(--space-8);
  align-items:center;
}
.block--aside .block__side{max-width:var(--measure-prose)}
.block--aside figure > img,
.block--aside figure > video{max-height:76svh;width:auto;margin-inline:auto}
/* Flipping swaps the widths as well as the sides: the prose keeps the wider
   column wherever it sits, and the portrait keeps the narrower one. */
.block--aside.is-flipped{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr)}
.block--aside.is-flipped .block__side{order:2}
.block--aside.is-flipped figure{order:1}

@media (max-width:760px){
  /* Both selectors, not only the base one. `.block--aside.is-flipped` states
     its own columns at (0,2,0) outside this query, and a media query adds no
     specificity -- so the flipped rows went on holding two columns on a phone
     while the unflipped ones collapsed beside them. At 360px that left the
     prose in a 112px lane: eighteen lines of two words each, on three pages. */
  .block--aside,
  .block--aside.is-flipped{grid-template-columns:minmax(0,1fr)}
  .block--aside.is-flipped .block__side,
  .block--aside.is-flipped figure{order:initial}
  /* A portrait that has just lost the text from its side has the whole column
     to itself, and 76svh of it made the reader scroll past a single image. */
  .block--aside figure > img,
  .block--aside figure > video{max-height:62svh}
}
.block figcaption{
  margin-top:var(--space-3);
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  color:var(--text-muted);
}
/* The row itself is the grid, whatever the block calls itself. This used to be
   scoped to .block--duo, which meant a trio or a strip inherited no grid at
   all and every image took the full measure and stacked — a wall of enormous
   renders instead of a row you can read across. */
.block__pair{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--space-5);
  align-items:start;
}
/* A pair holds one line whatever the two originals were shot at — otherwise a
   portrait next to a landscape leaves half the row empty. */
.block--duo .block__pair img{
  aspect-ratio:var(--aspect-still);
  object-fit:cover;
}

/* Rows of more than two. A pair invites comparison; these are for when the
   images are a sequence and want to be read along rather than against each
   other. */
.block--trio .block__pair{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}

/* A strip is a sequence of frames, and a sequence has to line up. This used to
   trust the assets to arrive at a common shape, on the grounds that they were
   rendered from one scene — and the croc frames, hand-cropped out of a Blender
   session, came in at five different sizes and produced five different heights
   in the row. A row of frames that does not line up reads as a mistake before
   anyone looks at what is in it.

   So the row enforces it rather than hoping for it. The assets are also cut to
   this box on the way in (tools/build-images-croc.ps1), which means `cover`
   normally has nothing left to crop and is here to keep the guarantee if a
   frame is ever replaced with something a few pixels off. */
.block--strip .block__pair{
  grid-template-columns:repeat(5,minmax(0,1fr));
  gap:var(--space-3);
  align-items:start;
}
.block--strip .block__pair img{
  aspect-ratio:var(--aspect-portrait);
  object-fit:cover;
}

/* Opt a pair out of the 4:3 as well, for the same reason. */
.block--keep .block__pair img{aspect-ratio:auto;object-fit:contain}

/* A row of artwork rather than of photographs. Drawings come off a phone at
   whatever proportion the sheet happened to be, and 4:3 is the wrong box for
   almost all of them — a portrait cropped to landscape loses the drawing.

   So the row takes its own aspect, set per row to whatever that set of work
   actually is, and the images fill it. Rows are built from drawings already
   within a couple of percent of each other, so the crop is a hairline; what it
   buys is the guarantee that the row cannot come out ragged if one of them is
   ever rephotographed slightly differently.

   Combine with --duo or --trio for the column count:
     <section class="block block--trio block--upright" style="--row-aspect:3/4">
   -------------------------------------------------------------------------- */
.block--upright .block__pair img{
  aspect-ratio:var(--row-aspect, 3 / 4);
  object-fit:cover;
}

/* --- technical drawings ----------------------------------------------------
   A drawing is evidence, not a headline. It is here to answer the one question
   the prose beside it raises — how does that actually hold up, what is behind
   the glass — and then get out of the way.

   Which is a different job from a photograph, and it wants a different frame.
   Given a full-width figure, a CAD export becomes the loudest thing on the
   page: a bright rectangle of paper with a thin object stranded in the middle
   of it, drawing the eye precisely because there is so little in it to look at.

   So a drawing gets a narrow column beside the paragraph it belongs to, at
   roughly the height of a few lines of text. The prose keeps the measure it
   reads at, the drawing keeps the scale it reads at, and the two are one
   thought rather than two events.

   The assets are trimmed to their linework and carry alpha (tools/build-dwg.ps1),
   so what sits on the page is ink on the site's own paper, with no white box
   around it.
   -------------------------------------------------------------------------- */

.block--detail{
  display:grid;
  grid-template-columns:minmax(0,var(--dwg-column)) minmax(0,1fr);
  gap:var(--space-6) var(--space-8);
  align-items:start;
  --dwg-column:clamp(150px, 21vw, 260px);
  padding-top:var(--space-6);
  border-top:var(--border-width-hairline) solid var(--border-hairline);
}
/* The drawing leads on the left by default. Alternating down a page is what
   stops a run of these from reading as a template. */
.block--detail.is-flipped{grid-template-columns:minmax(0,1fr) minmax(0,var(--dwg-column))}
.block--detail.is-flipped .block__side{order:1}
.block--detail.is-flipped .detail{order:2}

.block--detail .block__side{max-width:var(--measure-prose)}

/* The figure itself. `height` is the real control here, not width: these are
   sections and axonometrics of tall things, and left to width alone a narrow
   500mm section would print at the same size as a whole exhibition wall. */
.detail{
  margin:0;
  display:flex;
  flex-direction:column;
  /* A column flex container stretches its children across the full width by
     default, which silently overrode `width:auto` below and squashed every
     drawing narrower than its column — a section drawn at 1:2 was arriving on
     the page 20% wide. A drawing that is not to scale with itself is not a
     drawing, so this is the line that matters most in the block. */
  align-items:flex-start;
  gap:var(--space-3);
}
/* Two classes deliberately: `.block figure > img` above is (0,1,2) and sets
   width:100% for photographs, which outranks a plain `.detail img` and was
   stretching every drawing to the width of its column while max-height held
   the height — a section arriving 20% too wide. A drawing that is not to scale
   with itself is not a drawing, so this rule has to win. */
.block .detail img{
  width:auto;
  max-width:100%;
  max-height:var(--dwg-height, 340px);
  height:auto;
  display:block;
  /* belt and braces: whatever a future container does to the box, the pixels
     inside it keep their proportions */
  object-fit:contain;
  /* .block img paints a grey plate behind media, which is right for a
     photograph loading and wrong for line art with alpha */
  background:none;
  /* full black is heavier than the prose it sits beside; graphite is not */
  opacity:0.82;
}

/* A drawing that has to carry a whole system rather than one joint. Still
   nowhere near full width. */
.block--detail.is-tall{--dwg-height:clamp(320px, 46svh, 460px)}

/* The label. The site already speaks in mono for anything that is apparatus
   rather than voice, and a figure number is apparatus. */
.detail__label{
  margin:0;
  display:flex;
  align-items:baseline;
  gap:var(--space-3);
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  text-transform:uppercase;
  color:var(--text-muted);
}
.detail__label .num{color:var(--text-faint)}
/* The labels sit inside .block__side, beside the prose they annotate, so
   `.block__side p` (0,1,1) outranked `.detail__label` (0,1,0) and every figure
   number was set at body size: 18px of monospace carrying label tracking, wider
   and louder than the sentences underneath it. On a phone it wrapped to three
   lines of eleven characters. */
.block__side p.detail__label{font-size:var(--size-meta)}

/* No numbered key here, deliberately. A list that counts 01, 02, 03 against a
   drawing carrying no numbers is asking the reader to match things up with
   nothing to match them to, and at the size these are shown there is no room
   to put callouts on the linework without rebuilding the annotation apparatus
   the crop just removed. What the parts are is said in the prose beside the
   figure instead, in the order you meet them.

   Nor does a label state a scale. A drawing reproduced on a web page has no
   scale: it is whatever size the reader's screen makes it, so "1:5" on the
   page is a number that cannot be true. Real dimensions belong in the
   sentences, where they mean something.

   Line art is black on transparent, so the night theme has to flip it or it
   disappears into the page. */
[data-theme="night"] .detail img{filter:invert(1);opacity:0.78}

/* --- interaction previews --------------------------------------------------
   Some things a site does cannot be photographed. A hero that is a blank sheet
   until you rub a pencil over it photographs as an empty page; a wordmark that
   flies to the toolbar on scroll photographs as a wordmark, twice.

   These play a short recording of the real thing instead. Each one is a single
   JPEG holding every frame stacked vertically, stepped through with a CSS
   animation — no video file, no player library, and one request. It runs once
   when it scrolls into view, holds its last frame, and replays on click, so a
   page of them is not a page of things flashing at you.

   tools/capture-sf-motion.ps1 makes the sheets.
   -------------------------------------------------------------------------- */

.demo{
  margin:0;
  display:flex;
  flex-direction:column;
  gap:var(--space-3);
}

.demo__stage{
  position:relative;
  width:100%;
  /* the frame's own aspect, so the row does not jump when the sheet arrives */
  padding-top:var(--demo-ratio,62%);
  background-color:var(--surface-media);
  background-repeat:no-repeat;
  background-position:0 0;
  background-size:100% calc(var(--demo-frames,1) * 100%);
  border:var(--border-width-hairline) solid var(--border-hairline);
  cursor:pointer;
}
.demo__stage.is-ready{background-color:transparent}
.demo__stage.is-playing{
  animation:demo-play var(--demo-ms,2200ms) steps(var(--demo-steps,1)) 1 both;
}
@keyframes demo-play{
  from{background-position:0 0}
  to{background-position:0 100%}
}

/* The caption line carries its own affordance: these look like stills until
   something tells you they are not. */
.demo__meta{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--space-4);
  flex-wrap:wrap;
}
.demo__meta figcaption{margin-top:0}
.demo__replay{
  flex:none;
  appearance:none;
  background:none;
  border:0;
  padding:0;
  cursor:pointer;
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  text-transform:uppercase;
  color:var(--text-muted);
  border-bottom:var(--border-width-hairline) solid var(--border-hairline);
  transition:color var(--dur-fast) var(--ease-out);
}
.demo__replay:hover{color:var(--text-primary)}

/* A pair of previews reads as a sequence: rub it, then scroll it. */
.block--demos{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--space-6) var(--space-5);
  align-items:start;
}

@media (max-width:860px){
  .block--demos{grid-template-columns:minmax(0,1fr)}
}

/* Motion that starts on its own is the part to drop, not the recording. The
   preview still loads and still holds a frame; it just waits to be asked. */
@media (prefers-reduced-motion:reduce){
  .demo__stage.is-playing{animation:none;background-position:0 100%}
}

@media (max-width:760px){
  .block--detail,
  .block--detail.is-flipped{grid-template-columns:minmax(0,1fr)}
  .block--detail.is-flipped .block__side,
  .block--detail.is-flipped .detail{order:initial}
  .detail img{max-height:min(46svh,300px);margin-inline:auto}
}

@media (max-width:1000px){
  .block--strip .block__pair{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* --- a portrait film, on its own ------------------------------------------
   A 9:16 animation given half a row beside a paragraph ends up as a sliver:
   the column caps the width, the height cap catches it again, and the thing
   the page is about is the smallest item on the screen. It also does not want
   full bleed, which for that shape would be a wall.

   So it gets the middle of the page and as much height as the viewport can
   spare, and stops at its own native width rather than being blown up past
   it — the point of making it bigger is to read it better, and upscaling a
   720px film to 1200 does the opposite.
   -------------------------------------------------------------------------- */

.block--reel figure{margin:0}
.block--reel figure > video,
.block--reel figure > img{
  display:block;
  width:auto;
  max-width:min(100%, 720px);
  max-height:min(88svh, 1280px);
  margin-inline:auto;
  background:var(--surface-media);
}
/* the caption belongs to a centred object, so it is centred too */
.block--reel figcaption{
  text-align:center;
  max-width:var(--measure-prose);
  margin-inline:auto;
}

@media (max-width:760px){
  .block--reel figure > video,
  .block--reel figure > img{max-height:76svh}
}

/* --- next ----------------------------------------------------------------- */

.proj__next{
  margin-top:var(--section-gap);
  padding:var(--space-8) 0;
  border-top:var(--border-width-hairline) solid var(--border-hairline);
  display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--space-5);flex-wrap:wrap;
}
.proj__next .label{color:var(--text-muted)}
.proj__next a{
  font-size:clamp(1.5rem,3.6vw,2.75rem);
  font-weight:var(--weight-semibold);
  line-height:1;
  letter-spacing:var(--ls-display);
  text-transform:uppercase;
  display:inline-flex;align-items:baseline;gap:var(--space-4);
}
.proj__next a .glyph{transition:transform var(--dur-fast) var(--ease-out);display:inline-block}
.proj__next a:hover .glyph{transform:translateX(6px)}

/* --- back ----------------------------------------------------------------- */

/* Bottom right, not bottom left. Prose is capped at the reading measure, so
   the right of the column is empty wherever there is text -- on the left the
   chip sat squarely on top of it. */
.proj__back{
  position:fixed;
  right:var(--page-margin);
  bottom:var(--space-6);
  z-index:30;
  display:inline-flex;align-items:center;gap:var(--space-2);
  padding:10px 14px;
  background:var(--surface-inverse);
  color:var(--text-inverse);
  /* the chip also passes over the ink footer, where it would otherwise vanish */
  border:var(--border-width-hairline) solid var(--border-hairline-inverse);
  font-size:var(--size-label);
  font-weight:var(--weight-semibold);
  text-transform:uppercase;
  letter-spacing:var(--ls-label);
  transition:background var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out);
}
.proj__back:hover{background:var(--surface-accent);color:var(--paper)}

@media (max-width:760px){
  .proj__head{padding:var(--space-8) 0 var(--space-7)}
  /* One column, so the row gap is the only thing between four stacked facts.
     At 32 the block ran longer than the writing above it. */
  .proj__meta{gap:var(--space-5) var(--space-7)}
  .proj__topline{margin-bottom:var(--space-6)}
  .block--duo .block__pair{grid-template-columns:minmax(0,1fr)}
  .block--trio .block__pair,
  .block--strip .block__pair{grid-template-columns:repeat(2,minmax(0,1fr))}
  .proj__back{right:var(--space-4);bottom:var(--space-4)}
}

@media (max-width:600px){
  /* 16ch was written to stop a short title stretching across 1280px. In a
     320px column it is no longer a cap on the title, it is a cap on the page:
     the measure ran out before the words did and cost every long name an
     extra line. The column is the limit here. */
  .proj__head h1{max-width:none}

  /* The lede has to stay a step above the body, and the body has just come
     down to 16px. */
  .proj__lede{font-size:1.125rem}

  /* A baseline row with the label on one side and a 24px project name on the
     other: the name takes what it needs and the label is left with whatever is
     over, which on a phone was 138px and folded "Next project" in half. The two
     are a caption and its subject, so they stack. */
  .proj__next{
    flex-direction:column;
    align-items:flex-start;
    gap:var(--space-3);
  }
}

/* --- a scattered wall ------------------------------------------------------
   For the personal page only. The project pages line their images up because
   a row of frames that does not is a mistake; here the opposite is true. This
   is a wall of pinned photographs and drawings, and it should read as one:
   different sizes, different heights, deliberately uneven.

   Uneven, but not accidental. Every item states its own width in columns and
   how far down the wall it is pinned, so the composition is written down and
   repeats exactly rather than falling wherever the aspect ratios happen to put
   it:

     <figure class="scatter__item" style="--span:5;--drop:1">

   --span is columns out of twelve. --drop is steps down, one step per unit.
   Photographs and drawings share the block on purpose: the two halves of the
   page belong to the same person and should not be filed separately.
   -------------------------------------------------------------------------- */

.block--scatter{
  display:grid;
  grid-template-columns:repeat(12,minmax(0,1fr));
  gap:var(--space-7) var(--space-5);
  align-items:start;
}
.scatter__item{
  margin:0;
  grid-column:span var(--span,4);
  margin-top:calc(var(--drop,0) * var(--space-8));
  display:flex;
  flex-direction:column;
  gap:var(--space-3);
}
.scatter__item img{
  width:100%;
  height:auto;
  display:block;
  background:var(--surface-media);
}
/* A drawing on the wall is on paper, not behind glass: no plate behind it. */
.scatter__item.is-paper img{background:none}

.scatter__item figcaption{
  margin-top:0;
  font-family:var(--font-mono);
  font-size:var(--size-meta);
  letter-spacing:var(--ls-meta);
  color:var(--text-muted);
}

@media (max-width:860px){
  /* the drops collapse: on a narrow screen they are just gaps in a column */
  .block--scatter{grid-template-columns:repeat(6,minmax(0,1fr));gap:var(--space-6) var(--space-4)}
  .scatter__item{grid-column:span var(--span-s,6);margin-top:0}
}

/* The one line that gets to be a statement rather than a paragraph. It closes
   the personal page, so it is set at display size and given the room to land. */
.block--statement p{
  margin:0;
  max-width:20ch;
  font-size:clamp(1.75rem,4.4vw,3.5rem);
  font-weight:var(--weight-semibold);
  line-height:var(--lh-display);
  letter-spacing:var(--ls-display);
  text-wrap:balance;
  color:var(--text-primary);
}

/* A fact strip dropped into the body already has the body's own rhythm above
   it. Its header margin on top of that opened a hole big enough to read as a
   missing image. */
/* The body sets one rhythm with its own gap. A child that also carries a
   margin adds to it and opens a hole that reads as a missing image -- the
   fact strips and the history table were both doing this. */
.proj__body > *{margin-block:0}

/* A fact strip in the body is doing a different job from the one in the header.
   The header block is a footnote to the opening and is held to the reading
   measure; these are display -- a site map, a row of numbers -- and want the
   full column and the heavier rule they were built with. */
.proj__body > .proj__meta{
  max-width:none;
  grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
  border-top-width:var(--border-width-strong);
  border-top-color:var(--border-strong);
}

/* Six institutions with names that run to five or six words need wider columns
   than a strip of numbers does. Same block, fewer columns. */
.proj__body > .proj__meta--wide{
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
}
