/* Nicolás Lapadula
   ------------------------------------------------------------------
   THE ONE RULE THIS FILE EXISTS TO ENFORCE: the interface is achromatic.
   Paper, ink, and grey. Every colour on screen comes from inside a frame.
   His painting is already at maximum saturation — anything saturated beside
   it either loses or wins, and both are wrong on an artist's site.

   The second rule: nothing here may read as a shop. No badges, no "available
   now", no button above the work. Galleries read this site, and a site that
   looks like it is selling costs him the exhibitions that make him worth
   buying. His words, 2026-09-02.
   ------------------------------------------------------------------ */

:root {
  --paper:      #F4F1EA;
  --paper-warm: #FBFAF7;
  --ink:        #0B0B0B;
  --ink-soft:   #5A574F;
  --soft-on-dark: #D6D1C8;   /* descriptions and labels on ink and colour bands */
  --rule:       #CFC9BC;   /* visible against paper — 1.19:1 was not */

  --measure: 34rem;
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --step: clamp(3.5rem, 9vw, 8rem);

  --serif: "Instrument Serif", ui-serif, Georgia, "Times New Roman", serif;
  --sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  /* THE TYPE SCALE, ONE TOKEN PER ROLE. 2026-09-15.
     Ten roles, and every rule below points at one of them rather than carrying
     its own clamp -- the stylesheet had SEVENTEEN rendered sizes and twenty-seven
     family/size/weight/style/line-height/tracking/case combinations, measured at
     1363px, which is what made one family read as several systems.
     Each clamp is solved so it lands exactly on its desktop target at 1363px and
     exactly on its mobile target at 390px, which is why the phone overrides that
     used to re-state these sizes are gone rather than rewritten. */
  /* ONE HEADING SCALE (24/09, JP's unify brief): page openers and section
     heads are the same size, and it is the openers' size they share (JP: "go
     to 72"). 44px at 600px and below, ~57 on a tablet, 72 from 1024px up,
     reached smoothly, not in steps. */
  --t-h1:    var(--t-h2);
  --t-h2:    clamp(2.75rem, .274rem + 6.604vw, 4.5rem);  /* 44 -> 72, full size at 1024px */
  --t-h3:    clamp(1.75rem, 1.5rem + .7vw, 2rem);       /* 28 -> 32 */
  --t-lede:  clamp(1.125rem, 1rem + .4vw, 1.25rem);     /* 18 -> 20 */
  --t-body:  clamp(1.0625rem, 1rem + .2vw, 1.125rem);   /* 17 -> 18 */
  /* --t-quote (24 -> 26) retired 15/09: the artist statement and the pull
     quote were its only two users and both now take --t-body. A size token with
     no role left is how the scale grew to seventeen in the first place. */
  --t-title: clamp(1.25rem, 1.1rem + .4vw, 1.375rem);   /* 20 -> 22 */
  --t-label: .75rem;                                    /* 12, label only   */
  --t-meta:  .875rem;                                   /* 14, record/meta  */
  --t-nav:   .8125rem;                                  /* 13, nav + action */

  /* One easing for everything that moves. Exponential ease-out: fast départ,
     long settle — the curve a heavy thing follows, which is what a painting is. */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --reveal: 900ms;
}

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

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

body {
  margin: 0;
  color: var(--ink);
  font: 400 1rem/1.65 var(--sans);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

/* The surfaces nobody draws. A browser ships its own blue for selection, its own
   caret, its own scrollbar — all of them from a design system that is not this
   one, and all of them chromatic on a site whose whole argument is that the only
   colour comes from inside a frame. */
::selection { background: var(--ink); color: var(--paper); }
html { caret-color: var(--ink); scrollbar-color: var(--rule) var(--paper); }
@supports selector(::-webkit-scrollbar) {
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: var(--paper); }
  ::-webkit-scrollbar-thumb { background: var(--rule); border: 3px solid var(--paper); }
  ::-webkit-scrollbar-thumb:hover { background: var(--ink-soft); }}



/* THE WORK PAGE'S H1, READ AND NEVER SEEN. Its head band was deleted 16/09 --
   a band whose whole content was the word "Work" -- but a page still owes a
   screen reader and a search engine one heading that names it. Off-canvas by
   the same method as the skip link, which is the only other element here that
   exists without being visible. Never `display: none`: that would take it out
   of the accessibility tree, which is the one place it is still needed. */
.h1-off { position: absolute; left: -9999px; top: 0; }

/* Skip link — a gallery of 100+ images is a long way past the navigation. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper); padding: .75rem 1rem;
}

:where(a, button, input, textarea, select):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.wrap { width: min(78rem, 100%); margin-inline: auto; padding-inline: var(--gutter); }

/* ---------- type ---------- */

.display {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.02em;
  margin: 0;
  font-size: var(--t-h1);
  /* The browser distributes the lines instead of filling each one and leaving
     whatever is left on the last. At 390px this sentence otherwise drops
     "orderly." onto a line of its own. A manual <br> would fix the English and
     break the Spanish, which wraps at a different word. */
  text-wrap: balance;
}
.h2 {
  font-family: var(--serif);
  font-weight: 400;
  
  margin: 0;
}
.eyebrow {
  font: 500 0.6875rem/1.4 var(--sans);
  color: var(--ink-soft);
  /* margin set once by the header-group component further down */
}
.lede {    margin: 0; }
.prose { max-width: var(--measure); }
.prose p { margin: 0 0 1.1em; }
.prose p:last-child { margin-bottom: 0; }

/* The only "action" styling on the site: a ruled link, never a filled button.
   A button is a shop. A ruled link is a way through. */
.go {
  display: inline-block;
  font: 500 0.8125rem/1 var(--sans);
  
  text-decoration: none;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--ink);
}
.go:hover, .go:focus-visible { opacity: 1; }

/* ---------- masthead ---------- */

/* THE LANGUAGE SWITCH IS A SIBLING OF THE NAV, NOT A CHILD OF IT (JP, 17/09),
   so that a phone can show it while the nav panel is closed. That makes the
   masthead a three-item row, and `space-between` would have spread wordmark,
   links and language evenly across 78rem instead of keeping the links at the
   right-hand end. `flex-start` plus an auto margin on the nav pushes the nav
   and the language switch to the right AS A PAIR, which is what the two-item
   version used to do by accident. */
.masthead {
  display: flex; flex-wrap: wrap; gap: 1rem 2rem;
  align-items: baseline; justify-content: flex-start;
  padding-block: clamp(1.25rem, 3vw, 2rem);
}
.masthead > .nav { margin-inline-start: auto; }
.wordmark {
  
  text-decoration: none;
  white-space: nowrap;
}
.nav { display: flex; flex-wrap: wrap; align-items: baseline; gap: clamp(1rem, 2.5vw, 2rem); }
/* The language switch is no longer inside `.nav`, so it no longer inherits this
   rule by descent and has to be named. It is the same type at the same size,
   because it is the same row -- it simply lives one level up now so a phone can
   show it while the panel is shut. */
.nav a,
.nav-cities > summary,
.masthead > .lang {
  font: 400 0.875rem/1 var(--sans);
  text-decoration: none;
  padding-block: .35rem;
}
.nav a:hover, .nav a[aria-current="page"],
.nav-cities > summary:hover, .nav-cities > summary[aria-current],
.masthead > .lang:hover { color: var(--ink); }
.lang { font-variant-numeric: tabular-nums; }
/* It sits at the end of the link row, spaced like one more link in it. */
.masthead > .lang { margin-inline-start: clamp(1rem, 2.5vw, 2rem); }

/* ---------- the phone menu ---------- */
/* Four links and a language switch wrapped to THREE LINES on a phone, and a sticky
   bar three lines deep sits on top of every painting on the site. Below 48rem the
   bar is one line -- name, and a hamburger -- and the links drop out of it.

   No JavaScript: a checkbox and a sibling selector. The checkbox is invisible but
   not `hidden`, sized to cover the bars, so it takes the tap AND takes Tab, and
   Space opens the menu. The label is decoration. Above 48rem both vanish and the
   nav is exactly what it was. */
/* ---------- getting close to the painting ---------- */
/* THE OVERLAY IS BUILT BY THE SCRIPT, so none of this applies until a reader
   actually asks for it and nothing here costs a page that never opens one.
   `[hidden]` is honoured explicitly: `display:flex` below would otherwise beat
   the browser's own rule and the overlay would sit over every work page. */
.zoom[hidden] { display: none; }
.zoom {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(.5rem, 2vw, 2rem);
  /* NEARLY BLACK, NOT BLACK. A true black field makes a dark painting look as
     though it has no edge; a hair of light keeps the canvas a rectangle. */
  background: rgba(8, 8, 8, .94);
  overscroll-behavior: contain;
}
.zoom-img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  cursor: zoom-in;
  transition: transform .25s ease;
  /* The browser's own pinch is better than anything scripted, so it is left
     alone rather than intercepted. */
  touch-action: pinch-zoom;
}
.zoom[data-zoomed="true"] .zoom-img {
  transform: scale(2.5);
  cursor: zoom-out;
}
@media (prefers-reduced-motion: reduce) { .zoom-img { transition: none; }}



/* A 44px TARGET, drawn rather than typed: the overlay has no type on it at all
   and a word in the corner would be the only thing competing with the work. */
.zoom-shut {
  position: absolute; inset-block-start: clamp(.5rem, 2vw, 1.5rem);
  inset-inline-end: clamp(.5rem, 2vw, 1.5rem);
  width: 44px; height: 44px;
  padding: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .10);
  cursor: pointer;
}
.zoom-shut::before, .zoom-shut::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 25%;
  width: 50%; height: 1px; background: #fff;
}
.zoom-shut::before { transform: rotate(45deg); }
.zoom-shut::after  { transform: rotate(-45deg); }
.zoom-shut:hover, .zoom-shut:focus-visible { background: rgba(255, 255, 255, .20); }

/* THE CITY IN THE SPEC IS A LINK NOW, AND A LINE OF 13px TYPE IS A 17px TARGET
   -- under the 24px AA floor, on the one link a buyer on a phone is most likely
   to reach for. The hit area is grown with an absolutely positioned pseudo, the
   same device the inline note links use: the thumb gets 39px and the definition
   list keeps its spacing, because nothing about the box the eye sees changes.
   Padding would have worked and would have pushed every row of the spec apart. */
.spec a { position: relative; }
.spec a::after {
  content: "";
  position: absolute;
  inset-block: -.7rem; inset-inline: 0;
}

/* The photograph on a work page now says what it does. */
.shot { cursor: zoom-in; display: block; }

/* ---------- the cities menu ---------- */
/* SET LIKE A NAV LINK, BECAUSE IT IS ONE ITEM IN THAT ROW. The summary borrows
   the same rule as `.nav a` rather than inventing a size, so the bar still
   reads as one row of type; it is not an anchor, so it has to be named. */
/* IT IS NOT AN ANCHOR, SO IT INHERITS NOTHING. Every rule that sets the nav's
   type names `.nav a`, and a <summary> matches none of them -- so this label
   was set in a private copy of the type and drifted from the row it sits in:
   14px against 12px, weight 400 against 500, no uppercase, no letter-spacing,
   and a soft grey against full ink. Six differences in one word.
   The fix is not a better copy. The selector is added to each of the nav's own
   rules below, so the label cannot drift again; all that is left here is what
   is genuinely particular to a summary. */
.nav-cities > summary {
  padding-block: .35rem;
  cursor: pointer;
  list-style: none;                 /* the default triangle, in Firefox */
}
.nav-cities > summary::-webkit-details-marker { display: none; }
.nav-cities > summary::after {
  content: "";
  display: inline-block;
  width: .42em; height: .42em;
  margin-inline-start: .5em;
  border-inline-end: 1px solid currentColor;
  border-block-end: 1px solid currentColor;
  transform: translateY(-.15em) rotate(45deg);
}
.nav-cities[open] > summary::after { transform: translateY(.1em) rotate(-135deg); }

@media (min-width: 48rem) {
  /* A PANEL THAT HANGS OFF THE WORD, and the only absolutely positioned thing
     in this bar. It is held against the RIGHT edge of the summary: the menu is
     the last item before the language switch, so anchoring it left would run
     it off the side of the screen on a narrow laptop. */
  .nav-cities { position: relative; }
  .nav-cities-menu {
    position: absolute; inset-inline-end: 0; top: calc(100% + .5rem);
    z-index: 20;
    display: flex; flex-direction: column; gap: 0;
    min-width: 11rem;
    padding: .25rem 1rem;
    background: var(--paper);
    border: 1px solid var(--rule);
    box-shadow: 0 14px 28px rgba(11, 11, 11, .10);
  }
  .nav-cities-menu a { white-space: nowrap; padding-block: .6rem; }
  .nav-cities-menu a + a { border-block-start: 1px solid var(--rule); }}



@media (max-width: 47.99rem) {
  /* INSIDE THE PANEL IT IS AN ACCORDION, not a second floating layer over a
     panel that is already floating. The cities indent so the row reads as five
     children of one item rather than as five more pages. */
  .nav-cities > summary { border-block-end: 1px solid var(--rule); }
  .nav-cities-menu { display: flex; flex-direction: column; }
  .nav-cities-menu a { padding-inline-start: 1rem; }}



.nav-toggle, .burger { display: none; }

@media (max-width: 47.99rem) {
  /* gap: 0 on the ROW, and the breathing space moved onto the wordmark instead.
     A row gap sits between the checkbox and the icon too, and 16px of it was
     enough to pull the tap target off the drawing again after the first fix. */
  .masthead { flex-wrap: nowrap; align-items: center; gap: 0; }
  .masthead .wordmark { padding-inline-end: 1rem; }

  /* ONE HEIGHT ON A PHONE, and the shrink-on-scroll does not apply here. The tap
     target is 44px and must stay 44px, so the only thing left to give is the air
     around it: 10px instead of 20px takes the bar from 84px to 64px. A bar that
     changes height is also a bar that can fight the scroll position, which is the
     fault this file already carries a fix for. */
  .masthead, .masthead-bar:not([data-scrolled="false"]) .masthead {
    padding-block: .625rem;
  }

  /* The checkbox and the icon SIT ON TOP OF EACH OTHER BY CONSTRUCTION, both in
     flow, the icon pulled back over the box by exactly its own width. Positioning
     the box absolutely instead put the real tap area 12px off the drawn one -- the
     left of the icon did nothing and there was a live strip at the screen edge.
     Nothing here is a magic number, so nothing here can drift apart again. */
  /* ESPANOL IS ALWAYS TAPPABLE (JP, 17/09). It used to live inside the panel,
     so on a phone the only way to change language was to open the burger first
     -- one hidden tap in front of the thing a Spanish-speaking reader needs
     most, on a site whose two languages are deliberately level. It rides in the
     bar now, between the wordmark and the burger, and it is the SAME element
     the desktop row uses.

     The auto margin moves HERE, off the checkbox. Whichever item carries it
     eats all the free space and lands everything after it at the right-hand
     edge, so the language switch and the burger end up adjacent with the gap in
     front of them rather than between them. */
  /* IT IS A SIBLING OF THE MENU LINKS, NOT A HEADLINE (JP, 17/09). In the bar it
     was inheriting the DESKTOP row's 14px at weight 400 while the links inside
     the panel are 12px at weight 500 -- so the one word visible with the menu
     shut was the largest and lightest thing on the bar, and it sat beside a
     signature at 36px arguing with it. Same face, same case, same tracking as
     the panel links, one step smaller than them at 11px, because the mark is
     what the bar is for and this is a way out of the language you are in.
     THE TARGET DOES NOT SHRINK WITH THE TYPE. Type size and target size are
     independent: the padding grows to .55rem so the tap stays 28.6px, over the
     24px floor, which the 11px text on its own would not clear. */
  .masthead > .lang {
    order: 1;
    margin-inline-start: auto;
    font-size: .6875rem;
    font-weight: 500;
    letter-spacing: .065em;
    padding-block: .55rem;
    padding-inline-end: .75rem;
    white-space: nowrap;
  }
  .nav-toggle {
    display: block; flex: none; order: 2;
    width: 2.75rem; height: 2.75rem;
    margin: 0;
    opacity: 0; cursor: pointer; position: relative; z-index: 2;
  }
  .burger {
    display: flex; flex-direction: column; justify-content: center; align-items: center;
    gap: 5px; width: 2.75rem; height: 2.75rem; flex: none; order: 3;
    margin-inline-start: -2.75rem;
    pointer-events: none;   /* the box underneath takes the tap */
  }
  .burger span {
    display: block; width: 22px; height: 2px; background: var(--ink);
    transition: transform 200ms var(--ease), opacity 120ms var(--ease);
  }
  .nav-toggle:checked ~ .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav-toggle:checked ~ .burger span:nth-child(2) { opacity: 0; }
  .nav-toggle:checked ~ .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  .nav-toggle:focus-visible ~ .burger { outline: 2px solid var(--ink); outline-offset: 3px; }

  /* The panel hangs off the BAR, not the header, so it spans the full width even
     though the header is held inside the 78rem column. `.masthead-bar` is sticky,
     which is enough to make it the containing block. */
  .nav {
    display: none;
    position: absolute; inset-inline: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: .25rem clamp(1rem, 5vw, 2rem) .75rem;
    background: var(--paper);
    border-block-start: 1px solid var(--rule);
    box-shadow: 0 14px 28px rgba(11, 11, 11, .10);
  }
  .nav-toggle:checked ~ .nav { display: flex; }
  .nav a, .nav-cities > summary {
    font-size: 1rem; padding-block: .8rem;
    border-block-end: 1px solid var(--rule);
  }
  .nav a:last-child { border-block-end: 0; }}



@media (prefers-reduced-motion: reduce) {
  .burger span { transition: none; }}


/* No negative margins and no 100vw: the figure is simply not inside the column.
   Both bleed tricks measured 4vw past the viewport on each side at every width
   -- 388.8px of image in a 360px screen -- because a percentage margin resolves
   against the padded column, not the page. Sitting outside .wrap cannot drift. */
.hero-figure {
  margin: 0 0 clamp(2rem, 5vw, 4rem);
  /* The entrance scales the painting from 1.08, and an unclipped transform
     widens the PAGE while it settles: measured 388.8px of image in a 360px
     viewport, a real sideways scroll for the second and a half it lasts.
     Clipping here contains it; the effect is unchanged. */
  overflow: clip;
}
@media (max-width: 40rem) {
  .hero-figure img { height: min(62svh, 34rem); }}



/* Padding on ONE side only. Two stacked sections each adding var(--step) put
   16rem of dead space between them at 1440 — measured, not guessed. */
section { padding-block: 0 var(--step); }
/* The last section closes on the standard band value, not on 1.2x an older,
   larger step token -- that produced 147px against every other band's 72. */
section:last-of-type { padding-bottom: clamp(3rem, 5.3vw, 4.5rem); }
/* `.section-head .h2 { margin-bottom: .75rem }` removed 15/09 — it was owner
   number two of the heading-to-subtitle gap. See the header-group component. */

/* ---------- the grid ----------
   Fixed-ratio frames. Every caption lands on the same line, which the current
   site never manages — its rows are ragged because each cell is its own height. */

/* Twelve identical squares is a catalogue. A room is not hung that way, and a
   painter's proportions are part of the work: a 253 x 150 and a 30 x 30 are
   different objects and the page should say so. Twelve columns, and each work
   claims a span and a vertical offset from its own shape. */
.grid {
  display: grid;
  gap: clamp(2rem, 4.5vw, 4.5rem) clamp(1.25rem, 2.5vw, 2rem);
  list-style: none; margin: 0; padding: 0;
}
/* NO PLATE UNDER A PHOTOGRAPH (JP, 15/09). Every image on the site was one of
   two things: a painting, which sits on the band with nothing behind it, or a
   photograph, which sat on a warm-white card with a padded border. Two
   treatments for one job. The card is gone; `overflow: hidden` stays, because
   it is what clips the rise on hover. */
/* NO CLIPPING. `overflow: hidden` belonged to a padded cell that cropped an
   oversized image; with the cell gone it only ate the top 8px of the rise and
   opened a gap under the photograph, so the lift read as the image shrinking.
   A painting lifts clear of the band and so does a photograph. */
.frame { display: block; }
.frame img { display: block; }

.cap { margin-top: 1.1rem; }
.cap-meta {
    color: var(--ink-soft);
  margin: .35rem 0 0; font-variant-numeric: tabular-nums;
}
.cap-where { display: block; }

/* --- SOLD OR AVAILABLE ----------------------------------------------------
   JP, 22/09: "que se distinga, y muy distinguido" -- in the WORK'S OWN ficha
   tecnica, behind the photograph. It was tried on every plate of the hang first
   and taken back off within the hour: a word repeated down a grid of ninety
   paintings is a shop shelf, and the same word in the row of facts a buyer
   opened the page to read is just a fact. It replaces the Location row there,
   because the city never was a separate fact from availability.

   CAPS HERE, AND ONLY HERE. The note on `.cap-meta` argues against capitals
   and is right about a sixty-character label -- but this is one word, which is
   the four-word eyebrow case that note exempts, and one word in caps is what
   makes it readable across a page at a glance instead of read line by line.

   THE TWO STATES ARE DIFFERENT SHAPES, NOT DIFFERENT COLOURS. Sold is a solid
   block, available is an outline, so the two are told apart in greyscale, at a
   glance, and by a reader who cannot separate the hues. Both are built
   from `currentColor`, which is the rule this stylesheet already runs on: the
   bands alternate ink and paper, and a component that NAMES a colour is correct
   on one ground and wrong on the other. The solid state cannot inherit that way
   -- it needs the band's own background as its text colour -- so it is the one
   thing declared per band, just below. */
.spec .state + .state-where { margin-left: .55rem; }
.state {
  font-family: var(--sans);
  font-size: .75rem; line-height: 1; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
  padding: .42em .7em .38em; border: 1px solid currentColor;
  white-space: nowrap;
}
.state--free { background: transparent; }
.state--sold { background: currentColor; }
/* The solid one, once per ground. `color` here is the PILL'S TEXT, painted in
   whatever the band behind it is, while `background: currentColor` above takes
   the colour the band gives it. */
.band--paper .state--sold, .state--sold { color: var(--paper); background: var(--ink);
                                          border-color: var(--ink); }
.band--ink .state--sold { color: var(--ink); background: var(--paper);
                          border-color: var(--paper); }
/* The city sits BESIDE the word, never inside it: it is information, not a
   state, and putting it in the pill would give a Caracas work a wider badge
   than a Miami one for no reason a reader could name. It stays a link -- the
   reader who likes this painting is the one asking what else is near them. */
.state-where { font-family: var(--sans); font-size: .8125rem; }

/* The group heading on /obra. Set as a heading rather than a label: a serif at
   reading size above a rule tells you what you are looking at without the
   all-caps tracking that makes a gallery page read like a storefront aisle. */
.group-head {
  font-family: var(--serif); font-weight: 400;
   margin: 0 0 clamp(1.5rem, 3vw, 2.5rem);
  padding-bottom: .85rem; border-bottom: 1px solid var(--rule);
}

.section-foot { margin-top: clamp(2rem, 4vw, 3rem); }
/* NO PLATE HERE EITHER (15/09). The detail page mounted its painting on a warm
   card with up to 40px of padding -- the biggest white border on the site, on
   every one of the 131 work pages, while the gallery that sent the reader here
   showed the same painting with nothing behind it. */
.work-figure { margin: 0; }
.work-figure img { margin-inline: auto; }
/* Tabular figures so 150 x 100 and 253 x 150 align down the column: a spec
   list with proportional numerals reads as prose about a painting, not as its
   measurements. */
.spec { margin: 0; font-size: var(--t-meta); font-variant-numeric: tabular-nums; }
.spec div { display: flex; gap: 1rem; justify-content: space-between;
            padding-block: .7rem; border-bottom: 1px solid var(--rule); }
.spec dt { color: var(--ink-soft); }
.spec dd { margin: 0; text-align: right; }
.work-note { font-size: .8125rem; color: var(--ink-soft); margin: 1.25rem 0 0; }

/* The ask sits BELOW the work, always. Never above it, never floating. */
.ask { margin-top: 2rem; }

/* THE YEAR COLUMN IS THE SPINE. Fixed width, tabular figures, unbroken from 2018
   to 2026. Every entry hangs off the same left edge, which is the difference
   between a record and a list of sentences that happen to start with a date. */
/* 48rem, not 52: measured at 1440 the entry line ran 78 characters, past the 75
   where the eye starts losing the return sweep. At 48rem it reads 72. */
.cv { max-width: 48rem; }
.cv-head {
  font-family: var(--serif); font-weight: 400;
   
  margin: clamp(2.5rem, 5vw, 4rem) 0 0;
  padding-bottom: .85rem; border-bottom: 1px solid var(--ink);
}
.cv-head:first-child { margin-top: 0; }
.cv-list { list-style: none; margin: 0; padding: 0; }
.cv-row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: 0 1.25rem;
  padding: .95rem 0;
  border-bottom: 1px solid var(--rule);
  /* 16px floor even on the narrowest phone: these are the lines a curator
     actually reads, and 15px is where a record starts to feel like fine print. */
  font-size: var(--t-meta);
  line-height: 1.5;
}
.cv-year {
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  letter-spacing: .01em;
}
.cv-entry { display: block; }
/* THE SHOW'S NAME AND ITS VENUE, TOLD APART BY INK RATHER THAN BY FACE.
   The name used to be serif italic inside an otherwise sans record -- 14px, but
   a fifth treatment all the same, and the one the review names last. The two
   facts still carry different weights of attention: the name is full-strength
   ink, the venue under it is the quieter ink. No bold anywhere; bold in a serif
   this light is a different typeface wearing the same name. (15/09) */
.cv-name { font-family: var(--sans); font-style: normal; font-size: 1em; display: block; }
.cv-venue { display: block; color: var(--ink-soft); margin-top: .15rem; }
.cv-venue--solo { margin-top: 0; color: var(--ink); }

/* A RECORD ENTRY THAT IS ALSO A LINK. The four films joined the record 16/09,
   and they are the only rows in it a reader can open. Underlined on the same
   offset the rest of the site's links use, so the row still reads as a record
   line and not as a button. */
.cv-link {
  color: inherit;
  /* 24px OF TARGET, NOT 21px. The film rows are the only lines in the record a
     reader can tap, and at the record's 14px type a bare block runs 21px --
     under the 24px AA floor, on both phone widths and in both languages. The
     padding buys the height and the matching negative margin gives it back to
     the layout, so the row rhythm is unchanged and only the target grows.
     Type size is not target size: the type here was never the problem. */
  display: block;
  padding-block: .15rem;
  margin-block: -.15rem;
  text-decoration: underline;
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--rule);
}
.cv-link:hover, .cv-link:focus-visible { text-decoration-color: currentColor; }
/* An undated row still holds the year column, so the entries below Press line
   up with the four lists above instead of starting 60px to their left. */
.cv-year--none::before { content: "B"; }
.cv-note { font-size: .875rem; color: var(--ink-soft); margin: 1.25rem 0 0; max-width: 42ch; }

@media (max-width: 30rem) {
  /* The spine collapses on a narrow phone: a 4.5rem column plus a venue name is
     under 20 characters of entry, which breaks every line into three. */
  .cv-row { grid-template-columns: minmax(0, 1fr); gap: .35rem; }
  .cv-year { order: -1; font-size: .8125rem; }}



/* ---------- steps ---------- */

/* THE STEPS ARE BODY COPY, and they used to be 16px only because nothing said
   otherwise and the body inherits 16px. Beside paragraphs at 18px that reads as
   a deliberate third size for text that is doing exactly the same job as the
   paragraph above it -- the review's last type finding. (15/09) */
.steps { list-style: none; counter-reset: s; margin: 0; padding: 0; max-width: 40rem; }
.steps li {
  counter-increment: s; position: relative;
  font-size: var(--t-body); line-height: 1.6;
  padding: 1.1rem 0 1.1rem 3rem;
  border-bottom: 1px solid var(--rule);
}
.steps li::before {
  content: counter(s);
  position: absolute; left: 0; top: 1.1rem;
  font: 400 1rem/1.65 var(--serif); color: var(--ink-soft);
}

/* Prev / next / back, as one line at the foot of a work. The titles are the
   point: "Anterior" alone asks the reader to gamble, the name of the next
   painting is a reason to keep going. */
.work-nav {
  display: grid; gap: 1.5rem 2rem; align-items: end;
  grid-template-columns: 1fr;
  margin-top: var(--step); padding-top: clamp(1.5rem, 3vw, 2.5rem);
  border-top: 1px solid var(--rule);
}
@media (min-width: 48rem) {
  .work-nav { grid-template-columns: 1fr auto 1fr; }
  .work-nav .go { justify-self: center; }
  .work-nav-next { text-align: right; }}


/* THUMBNAIL BESIDE THE LABEL, mirrored on the next side so both thumbnails sit
   on the outside and the two labels face the middle. `contain`, never `cover`:
   a crop is a framing decision, and the one rule this hang runs on is that
   nobody but the painter makes those. The box is fixed so the row does not
   jump between a tall canvas and a wide one; the work floats inside it. */
.work-nav-side {
  text-decoration: none; max-width: 18rem;
  display: flex; align-items: center; gap: .875rem;
}
.work-nav-thumb { flex: 0 0 72px; width: 72px; height: 72px; display: block; }
.work-nav-thumb img {
  width: 100%; height: 100%; object-fit: contain; object-position: center;
  display: block;
}
.work-nav-text { display: block; min-width: 0; }
.work-nav-next { margin-left: auto; justify-content: flex-end; }
.work-nav-dir {
  display: block; font-size: .75rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-soft);
}
.work-nav-title {
  display: block; font-family: var(--serif); font-size: 1.25rem;
  line-height: 1.2; margin-top: .35rem;
  transition: opacity .3s var(--ease);
}
.work-nav-side:hover .work-nav-title { opacity: .55; }

/* ---------- footer ---------- */

/* ONE COLOUR PER PAGE, AND ONLY HERE. Nico's request, JP confirmed 2026-09-14,
   naming five: verde oscuro, morado, azul eléctrico, amarillo vivo, naranja.

   IT DOES NOT REOPEN THE ACHROMATIC RULE, it draws its boundary. The interface
   is grey and paper because his painting is already at maximum saturation, and
   a coloured chrome competes with the only thing a gallery is looking at. The
   footer is the one band with no work in it -- it is where the reader has
   finished looking -- so colour there is the first thing on the page that is
   not fighting a painting. Nothing above it moves.

   FIVE COLOURS, FIVE PAGES, ONE EACH, assigned so the page carrying the most
   work carries the quietest ground and the page asking for a reply carries the
   loudest. A work page inherits obra's, because it is obra.

   EVERY PAIR IS MEASURED, not chosen by eye -- contrast-check.py asserts 4.5:1
   on the small print, which is the text most likely to fail. Orange and yellow
   take near-black; the three dark grounds take white. There is no opacity on
   any of this text: dropping a 4.8:1 pair to 70% is how a footer that passed
   the check stops passing on the screen. */
/* The palette only. Background and colour are applied further down, in the one
   `.foot` block that survives the cascade -- setting them here as well would
   put two rules in the file claiming to decide the same thing, which is what
   broke this in the first place. */
/* The colour block is the separation. A rule on top of it draws a seam. */
.foot:not([class*="foot--"]) { border-top: 1px solid var(--rule); }
/* HOME WAS ELECTRIC BLUE until 24/09 -- JP: "i hate that blue". Ochre, the
   warm ground of the commissions clip, 7.49:1 against white. */
.foot--index    { --foot-bg: #724E00; --foot-fg: #FFFFFF; } /* ocre */
/* `obras` is the collection key a single work page carries, `obra` the index.
   Both are the same place to a reader, so both take the same ground. */
.foot--obra,
.foot--obras    { --foot-bg: #0E3B2E; --foot-fg: #FFFFFF; } /* verde oscuro   */
.foot--artista  { --foot-bg: #4A1E6E; --foot-fg: #FFFFFF; } /* morado         */
/* Darkened from #E2521B on 2026-09-14. That orange was the one pair in the set
   that only reached 4.5:1 -- it passed, and every other footer cleared 7:1, so
   one page was quietly the weakest thing on the site. This is the LIGHTEST
   orange that clears 7:1 against white, so it gives up the least hue to get
   there: still 17 degrees, still 0.96 saturation, just darker. */
.foot--encargos { --foot-bg: #A23207; --foot-fg: #FFFFFF; } /* naranja        */
.foot--contacto { --foot-bg: #FFD400; --foot-fg: #141414; } /* amarillo vivo  */
/* CITIES IS A PAGE IN THE NAVIGATION NOW, so it is a page with a ground. It used
   to wear `obra`'s green, because a city page tells the rest of the site it IS
   Work seen through one city -- which is right for the nav and for the
   structured data, and wrong for the one band whose job is to say where you
   are. Burgundy is the gap in the set: the five were blue, green, purple,
   orange and yellow, and nothing was warm and dark. */
.foot--ciudad   { --foot-bg: #7A1230; --foot-fg: #FFFFFF; } /* burdeos        */
/* THE FOOTER READS TOP TO BOTTOM: his name, then where to go, then how to reach
   him, then the small print. Four things in the order a reader wants them, and
   no labels over any of them -- an address is recognisable as an address.

   THE PAGES AND THE CONTACTS ARE THE TWO HALVES (JP, 17/09). `space-between`
   with wrap put them at opposite ends of a 78rem band with a metre of nothing
   between, which reads as two unrelated footers. They are columns now: the
   pages stack on the left, the address and the accounts on the right, and both
   collapse to one column on a phone. `auto-fit` rather than a fixed pair, so
   the single-column case needs no second rule. */
/* IT READS IN LINES NOW, NOT IN COLUMNS (JP, 17/09). Six pages stacked and an
   address and three accounts stacked beside them made a footer 443px tall on a
   laptop and 495px on a phone -- a second page under every page, and on a phone
   it was taller than the screen it ended. Ten items that each take one line make
   ten lines; the same ten in rows take three.

   It is flex and not the old grid because the two halves are no longer equal
   columns: the pages want the width they need and the contact details want the
   rest, and on a phone they simply stack. `auto-fit` columns cannot express
   that without a second rule per breakpoint. */
.foot-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem 3rem;
  margin-top: 2.25rem;
}
/* THE PAGES ARE A ROW. They were a column on the argument that a reader down
   here is choosing rather than scanning -- true of the destination, not of the
   shape. Six links wrapping across the width are read exactly as easily and
   cost a sixth of the height. The row gap is 0: the padding on each link is
   already what makes the target, and a second gap on top of it reopens the
   height this is closing. */
.foot-nav {
  display: flex; flex-wrap: wrap;
  align-items: baseline; gap: 0 1.5rem;
}
/* The address and the three accounts sit on one line and wrap to two when they
   have to, rather than being four stacked lines by construction. */
.foot-reach {
  display: flex; flex-wrap: wrap;
  align-items: baseline; gap: 0 1.5rem;
}
@media (max-width: 48rem) { .foot-grid { margin-top: 1.75rem; }}


/* Footer links were 20–23px tall, under the 24px WCAG 2.2 minimum target size.
   Padding rather than font-size: the footer is meant to be quiet, and a thumb
   does not care how big the letters are. */
/* TYPE SIZE AND TARGET SIZE ARE INDEPENDENT. Moving the footer to the shared
   13px navigation role took these links from 35px tall to 30px -- still over
   the 24px AA floor, but smaller for no reason a reader benefits from. The
   padding buys the height back without reopening the type scale. Measured, not
   estimated: 13px x 1.4 line-height + 2 x .5rem = 34px. */
.foot a { text-decoration: none; display: inline-block; padding-block: .5rem; }
.foot .eyebrow { color: inherit; }
.foot-small { font-size: var(--t-nav); line-height: 1.5; color: inherit; margin: 1.5rem 0 0; }
/* THE CREDIT RUNS ON, IN ONE TYPE SIZE (JP, 21/09). It was given a line of its
   own earlier the same day, on the argument that running on after "All rights
   reserved" makes it read as part of Nicolás's copyright. Seen on the page, the
   break is what rings the bell: a short line alone under a footer is a line the
   eye stops on, which is the opposite of what a credit on someone else's site
   should do. It goes back inline -- same 13px, same colour, same sentence
   rhythm as the copyright beside it. Nothing here sets a size, deliberately:
   any rule at all would be a second type for one string. */
.social { display: flex; flex-wrap: wrap; gap: 1rem; font-size: .875rem; }

/* THE FOUR MARKS IN THE FOOTER (JP, 17/09).
   Masks, not images and not inline SVG, for the reason the signature above them
   is a mask: this footer travels through the palette every twelve seconds, so
   each mark has to change colour four times a minute. An <img> cannot inherit a
   colour, and inline SVG would put the same paths into all 272 pages twice. A
   mask painted with `currentColor` follows any ground and stays one cached file.
   `-webkit-mask` ships beside it or Safari draws a coloured rectangle.

   THE TARGET IS THE LINK, NOT THE DRAWING. The mark is 20px, which is under the
   24px floor on its own; the padding carries the link to 40px square, and the
   row keeps its 1rem gap so two marks are never closer than 16px. Type size and
   target size are independent, and an icon is the case where forgetting that
   costs the most -- there is no text to make the box big by accident. */
.reach {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem;
  padding: 0;
}
.icon {
  display: block;
  width: 1.25rem; height: 1.25rem;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}
.icon--mail      { -webkit-mask-image: url("assets/icons/mail.86f31d6a.svg");      mask-image: url("assets/icons/mail.86f31d6a.svg"); }
.icon--instagram { -webkit-mask-image: url("assets/icons/instagram.f1ba337b.svg"); mask-image: url("assets/icons/instagram.f1ba337b.svg"); }
.icon--tiktok    { -webkit-mask-image: url("assets/icons/tiktok.ecd7c8c4.svg");    mask-image: url("assets/icons/tiktok.ecd7c8c4.svg"); }
.icon--youtube   { -webkit-mask-image: url("assets/icons/youtube.8033ce15.svg");   mask-image: url("assets/icons/youtube.8033ce15.svg"); }

/* THE UNDERLINE IS WRONG UNDER A DRAWING. `.foot a` and `.social a` grow a rule
   on hover, which is right for a word and reads as a stray line under a 20px
   mark. These lift instead -- the same 8px rise every photograph on the site
   uses when the pointer arrives, so the footer answers a pointer the way the
   rest of the site does. */
.reach::after { display: none; }
.reach .icon { transition: transform 200ms var(--ease), opacity 200ms var(--ease); }
.reach:hover .icon, .reach:focus-visible .icon { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
  .reach .icon { transition: none; }
  .reach:hover .icon, .reach:focus-visible .icon { transform: none; opacity: .72; }}


/* The row was spaced for words. Four 40px boxes sit closer without crowding, and
   the address is no longer a line of its own above them. */
/* 8px BETWEEN BOXES, NOT 4. The marks are 40px targets, which clears the 24px
   floor on its own -- but this file already holds an 8px minimum between
   adjacent targets, found the hard way on the rooms grid, and four icons in a
   row is exactly the case it was written for. */
.foot-reach { gap: 0 .5rem; }
.social { gap: .5rem; }

/* ---------- NOTHING ARRIVES ----------
   The work used to be uncovered on scroll -- the frame wiping open while the
   painting settled back from a slight overscale -- and everything else rose
   quietly behind it. JP killed all of it on 2026-09-04: it read as childish,
   and the pictures were already there.

   So the page is simply finished. No entrance, no stagger, no clip, nothing on
   the hero. What stays is HOVER: a work answers when you put the mouse on it,
   and a link draws its rule. That is state, not performance, and it is the only
   movement left on the site.

   The script that drove the entrance is gone with it -- there is now no
   JavaScript on this site at all, so there is no `.js` class and nothing to
   guard against its absence. */

@media (prefers-reduced-motion: reduce) {
  /* REDUCED MOTION IS LESS MOVEMENT, NOT LESS FEEDBACK. This used to kill every
     transition on the page with one !important, which took the hover and focus
     states down with it -- a reader who asks for calm got a site where nothing
     acknowledges being touched. Movement goes; the rules that draw themselves
     under a link stay, because they are state, not motion. */
  *, *::before, *::after { animation: none !important; }
  /* Duration, not removal: the rule under a link still appears and the outline
     still lands, they simply arrive rather than travel. */
  *, *::before, *::after { transition-duration: .01ms !important; }
  .work a:hover .plate img, .work a:focus-visible .plate img,
  .split-plate a:hover .plate img, .aside-work a:hover img,
  .shot:hover img, .shot:focus-visible img,
  .work-nav-side:hover, .work-nav-side:focus-visible { transform: none !important; }
  /* A COLOUR BAND WITH ITS ANIMATION KILLED IS AN INK BAND AGAIN. The rule
     above already drops the background back to `var(--ink)`, but the three
     text tokens are NOT animated, so without this a reader who asks for calm
     would get today's black ground wearing the lighter tiers the colours
     needed -- legible, but not the design. Reduced motion should land on what
     the site looks like now, not on a third version of it. */
  .band--cycle {
    color: var(--paper);
    --ink-soft: var(--soft-on-dark);
    --rule: #34322D;
  }
  .band--cycle a, .band--cycle .go { color: var(--paper); border-bottom-color: var(--paper); }}


/* THE LEAN IS GONE, AND THE <em> STAYS (second-pass review, 15/09).
   "my own way" used to lean, on the argument that it was the half of the
   sentence that is his rather than descriptive. The review's verdict is that
   the site had three visual treatments of one serif -- upright display,
   leaning display, leaning quotation -- doing a single job between them, and
   that the character has to come from the work rather than from repeated
   italics. The ELEMENT is deliberately left in the template: it still carries
   the emphasis for anything reading the markup, it just stops rendering as a
   second typeface. Reversing the direction is this one line. */
/* <em> IS ITALIC BY DEFAULT IN EVERY BROWSER, so removing a rule is not how
   the lean comes off -- it has to be overridden. This was first written as
   `.hero-line em`, and `.hero-line` turns out to be a dead class: it is
   declared twice in this stylesheet and used in no template, so the headline
   went on leaning and the check went on reporting it.
   Scoped to HEADINGS only. Emphasis inside a paragraph is ordinary emphasis and
   still leans; what the review removes is the serif display italic that was
   reading as a second typeface. */
.display em, .h2 em,
.group-head em, .cv-head em { font-style: normal; }



/* --- SECTION HEADINGS ---------------------------------------------------- */
.h2 {
  font-size: var(--t-h2);
  line-height: 1.08;
  letter-spacing: -.02em;
  /* THE LINES ARE EVENED OUT, THE SAME WAY `.display` AND `.h1` ALREADY DO IT
     (JP, 16/09). A heading that runs past one line otherwise fills the first
     line and drops whatever is left onto the second -- "Begin with a photograph
     of the wall, and the story you have in" / "mind." -- and a one-word second
     line reads as a mistake. This is the ROLE, not that one heading: every h2
     on the site that wraps now splits evenly, in both languages, which a manual
     <br> could never do because English and Spanish break at different words.
     `.h2--name` opts out further down: his name is allowed to break where it
     likes. */
  text-wrap: balance;
}

/* PHONE CAP. At the spec's 4rem floor a section heading measured 91px tall on a
   390px screen: "Society inside the canvas" took most of the viewport before a
   word of explanation, so the type outweighed the paintings -- the one thing
   the brief forbids. Capped so the heading announces the section and the work
   stays the loudest thing on screen. */
/* The phone cap that used to live here is gone: --t-h1 and --t-h2 reach their
   44px and 36px floors at 390px on their own, so a second set of sizes for the
   same two roles would be the accumulation this pass exists to remove. */

.group-head, .cv-head {
  font-size: var(--t-h3);
  line-height: 1.15;
  letter-spacing: -.015em;
}

/* --- ROLE 2: THE LEDE. One per section, always under the heading. --------- */
/* THE SUPPORTING SENTENCE, AND IT IS NOW A ROLE RATHER THAN A POSITION.
   This selector list used to end with four `p:first-child` clauses, which meant
   that being the first paragraph in any prose block silently promoted it to
   20px: the artist page's biography opened at 20px/30 and continued at 18px/29
   for no reason anyone had chosen, and the review read that as a fourth text
   treatment. A subtitle now has to SAY it is a subtitle -- `.lede`, `.hero-sub`
   or `.group-sub` in the markup -- and every paragraph of a biography shares
   one body size. (Second-pass review, 15/09.) */
.lede, .group-sub {
  font-family: var(--sans);
  font-size: var(--t-lede);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -.01em;
  color: var(--ink-soft);
  max-width: 40rem;
}


.group-sub { margin: 0 auto; }

/* ============================================================================
   THE HEADER GROUP — ONE OWNER FOR EACH GAP (second-pass review, 15/09)

   A label, a heading and the sentence that supports it are one component, and
   the two gaps inside it are set HERE and nowhere else. Before this pass the
   same heading-to-subtitle relationship rendered at 0px on four pages, 12px on
   three, 20px on three and 44px on one, because `.eyebrow` carried a bottom
   margin, `.section-head .h2` carried another, centred prose wrappers carried a
   third and `.said--center` a fourth. Nothing was wrong with any single rule;
   there were simply four of them for one gap.

   THE RULE FOR ANYONE EDITING THIS LATER: a heading never carries a bottom
   margin and a subtitle never carries a top margin of its own. The gap belongs
   to the pair, so it is set on the pair with an adjacent-sibling selector. If a
   gap here looks wrong, change the token -- do not add a margin somewhere else,
   which is exactly how the four owners accumulated.
   ========================================================================= */
:root {
  --gap-label: .75rem;   /* 12px — label to heading, same on both           */
  --gap-sub:   1.25rem;  /* 20px — heading to its supporting sentence       */
  --gap-group: 2rem;     /* 32px — the whole header group to its content    */
}
@media (max-width: 48rem) {
  :root {
    --gap-sub:   1rem;     /* 16px */
    --gap-group: 1.75rem;  /* 28px */
  }}



/* 1 — LABEL TO HEADING. The eyebrow owns it, because a label is always above
       the thing it labels and never below anything. */
.eyebrow { margin: 0 0 var(--gap-label); }

/* THE GROUP LABEL IS THE HEADING'S FIRST LINE, NOT A CAPTION ABOVE IT (JP,
   17/09). "Paintings" was an `.eyebrow` -- 11px sans, soft ink -- sitting over
   "In colour" at the h2's 40px serif, so two halves of one name were set as two
   different things. Same face, size, leading and tracking as `.h2`, and no
   colour of its own so it inherits whatever the head it belongs to is using,
   including on the colour group's travelling band.

   NOT the `.h2` class. `.section-head .h2` increments the section counter and
   prints the number, so sharing the class would number the label too. The type
   is copied deliberately; there is no second scale here to keep in step. */
.h2-line { display: block; }

/* .group-label retired 24/09: the label and the series are now ONE h2. */
.group-label-retired {
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--t-h2);
  line-height: 1.08;
  letter-spacing: -.02em;
  margin: 0;
}

/* 2 — HEADING TO SUPPORTING SENTENCE. Set on the pair. Every heading class the
       site uses is listed against every subtitle role it can take; a subtitle
       has to declare itself as one (`.lede`, `.group-sub`, `.hero-sub`), which
       is the other half of removing the `p:first-child` promotion. */
.display + .lede, .display + .group-sub,
.h2 + .lede,      .h2 + .group-sub,
.group-head + .lede, .group-head + .group-sub,
.cv-head + .lede,    .cv-head + .group-sub {
  margin-top: var(--gap-sub);
}



/* 3 — THE GROUP TO ITS CONTENT. */
.section-head { margin-bottom: var(--gap-group); }

/* --- ROLE 3: BODY -------------------------------------------------------- */
.prose p { font-size: var(--t-body); line-height: 1.6; letter-spacing: -.005em; max-width: 38rem; }

/* --- ROLE 4: SMALL CAPS. Captions, labels, links. ------------------------- */
.cap-meta, figcaption.cap-meta {
  font-family: var(--sans);
  /* A GALLERY LABEL IS NOT SET IN CAPITALS. These run to sixty-odd characters --
     "Acrílico sobre lienzo · 150 x 120 cm · 2026 / Currently in Caracas" -- and
     uppercase removes the ascenders and descenders a reader recognises words by,
     which is affordable on a four-word eyebrow and not on a full label under
     every painting. Sentence case, one size up from 12px, and the technique
     keeps the capitalisation Nico typed. The eyebrows stay uppercase: they are
     labels of two or three words, which is what the case is for. */
  font-size: var(--t-meta);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: .005em;
  text-transform: none;
}


.eyebrow{
  font-size: var(--t-label);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .08em;
  text-transform: uppercase;
}


/* NAVIGATION AND TEXT ACTIONS ARE ONE ROLE, and a slightly larger one than a
   label: they are targets, not captions. A single tracking, so `.go` no longer
   states a third value for the same thing. */
.go, .nav a, .nav-cities > summary, .wordmark, .lang, .foot a, .social a {
  font-size: var(--t-nav);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .06em;
}
.go { text-transform: uppercase; }

.nav a, .nav-cities > summary, .lang {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .065em;
  text-transform: uppercase;
  color: var(--ink);
}
.wordmark {
  font-family: var(--sans);
  font-size: var(--t-nav);
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* --- HIS LOGO (JP, 17/09) -------------------------------------------------
   "NLA | Nicolas Lapadula", the mark and the name both drawn in his own hand.
   It replaces a typeset wordmark in the bar and opens the footer.

   A MASK, NOT AN IMAGE, AND THAT IS THE WHOLE REASON THIS IS CSS. The footer
   moves through the palette every twelve seconds and the masthead sits on
   paper, so one file has to be able to be white in one place and near-black in
   the other. An <img> cannot inherit a colour, and inlining 21KB of path into
   all 272 pages twice each is 11MB of duplicated drawing. A mask painted with
   `currentColor` follows any ground, stays one cached file, and needs no
   second rule for the cycle.

   `-webkit-mask` is not optional -- Safari shipped the prefixed property years
   before the unprefixed one, and without it this is a coloured rectangle where
   a signature should be. Both are declared, unprefixed last. */
.logo {
  display: block;
  background-color: currentColor;
  -webkit-mask: url("assets/nla-logo.b6c5c038.svg") no-repeat center / contain;
  mask: url("assets/nla-logo.b6c5c038.svg") no-repeat center / contain;
  /* The artwork is 2983.0128 x 635.27. Declaring the ratio means a height alone
     sizes it and there are never two numbers to keep in step. */
  aspect-ratio: 2983.0128 / 635.27;
  flex: none;
}

/* THE NAME IS STILL IN THE MARKUP, it is simply not on the screen: the logo
   draws his name as artwork, and artwork is invisible to a crawler and to a
   screen reader. Not `display:none` -- that would hide it from both as well.
   The 1px clipped box is the technique that keeps it announced and findable. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* IN THE BAR: sized by HEIGHT, because the bar's height is the constraint and
   the ratio solves the width. 4.7:1 is a long mark, so it is kept modest --
   the masthead is furniture and the paintings are the page. */
.wordmark { display: inline-flex; align-items: center; align-self: center; }
/* IT IS BIGGER THAN THE ROW IT SITS IN, AND THE ROW DOES NOT MOVE (JP, 17/09).
   24px was still reading as a smudge -- this mark is 4.7:1, so height is the only
   thing that makes his handwriting legible, and the bar's height is set by the
   nav links at 28px. The negative margins are what separate the two: the drawing
   renders at 36px and CONTRIBUTES 28px to the line, so it overhangs its own line
   box by 4px top and bottom and the bar stays exactly where it was. Measured
   either side of the change: 92.0px before, 92.0px after.
   -4px is not a magic number, it is (36 - 28) / 2. Change the height and this
   changes with it. */
.logo--nav { height: 2.25rem; margin-block: -0.25rem; }
/* On a phone the bar is 64px and its content is the 44px tap target, so 36px
   fits inside it with room and needs no negative margin at all. */
@media (max-width: 48rem) { .logo--nav { height: 2.25rem; margin-block: 0; }}



/* IN THE FOOTER: his name, at the top of the band, large enough to read as a
   signature on the page rather than as a second piece of navigation. Capped in
   WIDTH as well as height so it never runs the full width of a wide screen --
   a 4.7:1 mark at 78rem would be a banner, which this is not. */
.foot-logo { display: block; width: fit-content; }
.logo--foot { height: 2.5rem; max-width: 100%; }
@media (max-width: 48rem) { .logo--foot { height: 1.9rem; }}



/* AN ARTWORK'S NAME IS NOT METADATA. The spec set titles at 12px uppercase --
   the same treatment as the measurements -- which files the name of a painting
   under the same heading as its dimensions. It stays in the serif, which is
   what makes a caption read as a wall label instead of a product listing. */
.cap-title {
  font-family: var(--serif);
  font-size: var(--t-title);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -.01em;
  text-transform: none;
  margin: 0;
}

/* --- SECTION NUMBERS ----------------------------------------------------- */
main { counter-reset: sec; }
.section-head .h2{ counter-increment: sec; }


.section-head .h2::before{
  display: block;
  font-family: var(--sans);
  font-size: .75rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 1.25rem;
}



/* 4:5 plate. Portrait, because nine of the twelve works are. The painting is
   CONTAINED, never cropped -- a cropped painting is the one thing an artist's
   site may not do -- and the paper it sits on is the mount. */
/* THE PHOTOGRAPH IS ITS OWN SHAPE. The 4:5 cell and its padding existed to
   make unequal photographs share a card; with the card gone there is nothing
   to make them share, and a fixed cell would letterbox a wide mural again.
   `width`/`height` on the img keep the space reserved, so nothing shifts. */
.frame img { width: 100%; height: auto; }

/* On a phone the works stack one per screen, so there is no row to close and
   nothing to compare a work against. Scaling there only makes small work hard
   to see, so each one takes the plate it needs. */
@media (max-width: 40rem) {
  .frame { aspect-ratio: auto; }
  .frame img { width: 100%; }}



/* ==========================================================================
   THE EDITORIAL HOME PAGE — 2026-09-02, from JP's render.

   Everything above this block still governs the other four pages. This block
   adds the bands, the hang and the split sections the home page needs, and
   overrides the earlier grid only where the render replaces it.
   ========================================================================== */

/* --- BANDS ---------------------------------------------------------------
   The page is a stack of full-bleed bands, alternating paper and ink. This is
   the whole structural idea: a site with no colour of its own still needs a
   rhythm, and value gives it one without a single coloured pixel entering the
   interface. The dark bands also separate the ARGUMENT from the HANG, so a
   curator reading only the type never scrolls through anything that sells. */

/* 72px at 1363, 48px at 390 -- the two ends of the spacing spec, solved rather
   than picked. It was 123px top AND bottom, so every junction between two
   sections cost 246px of nothing before a reader reached the next thing. The
   paintings did not get smaller to buy that back; the emptiness around them
   did. */
.band { padding-block: clamp(3rem, 5.3vw, 4.5rem); }

.band--paper { background: var(--paper); color: var(--ink); }

.band--ink {
  background: var(--ink);
  color: var(--paper);
  /* The rule and the soft ink both have to be redefined, not merely inherited:
     #5A574F on near-black measures 2.7:1 and #CFC9BC is a hairline meant for
     paper. Redefining the tokens on the band keeps every child correct without
     a single component knowing which ground it is on.
     24/09: the soft tier on every dark ground is ONE token, #D6D1C8 (12.95:1 on
     ink), the value the colour band already needed -- JP's unify brief. */
  --ink-soft: var(--soft-on-dark);
  --rule: #34322D;
}
.band--ink a { color: var(--paper); }
.band--ink .go { border-bottom-color: var(--paper); }

/* --- THE COLOUR BAND ------------------------------------------------------
   An ink band that carries the footer's palette instead of ink, and moves
   through it AS THE READER SCROLLS PAST. JP, 2026-09-15.

   IT IS DRIVEN BY THE READER, NOT BY A CLOCK. A timed cycle has to guess how
   long the band is on screen: too slow and a reader scrolling past sees one
   slow drift inside a single colour and reads it as nothing happening, too
   fast and it pulls at someone trying to read the paragraph. `view()` runs
   whole turn across the time the band is crossing the viewport, so every
   reader sees it exactly once at their own scrolling speed, and it settles
   when they stop to read.

   YELLOW IS NOT IN THE CYCLE, and that is measured, not taste. #FFD400 puts
   body text at 1.27:1 and the soft tier at 1.77:1. The footer can flip to
   dark text at the yellow because it has ONE text tier and a hard cut. A band
   has THREE and it cross-fades, so there is no frame where the flip is safe:
   the best any text colour can do against the orange-to-yellow midpoint is
   4.28:1. Dark colours only, white text, no compromise at any frame.

   ALL THREE TEXT TIERS ARE REDEFINED. This is the part that breaks silently
   if it is left out -- the band's tokens are tuned for near-black, and the
   worst frame of the cycle is the orange. Measured across the whole cycle,
   not at the stops:

     body and links  #F4F1EA -> #FFFFFF   6.21:1 -> 7.01:1
     --ink-soft      #A8A296 -> #D6D1C8   2.76:1 -> 4.61:1  (FAILED before)
     --rule          #34322D -> #8A8479   1.00:1 -> 1.89:1  (VANISHED before)

   #D6D1C8 is the DARKEST tone that clears AA across every frame, so the soft
   tier is only slightly quieter than the body here rather than genuinely
   soft. That tier largely does not survive a colour ground; it is the price.

   NEVER PUT THIS ON A BAND THAT CARRIES A PAINTING. Five of the twelve ink
   bands hold an image, the home page's investigation band among them -- and
   that one holds the single monochrome work precisely because black is the
   only ground that does not fight it. A moving colour behind a painting is
   the one thing this effect must not do. */
/* THE BLOCK ABOVE DESCRIBED THIS RULE; IT DID NOT EXIST (found 17/09). The
   class had never been applied to an element, so nothing ever exercised it:
   the tier values were written in the comment, the reduced-motion FALLBACK was
   implemented, and the animated state -- the one the comment is about -- had
   no `animation` and no tier overrides at all. A band given the class would
   have rendered as a plain ink band wearing near-black tokens. Prose cannot
   fail; only a rule can.

   IT LIVES INSIDE `no-preference` ON PURPOSE. The reduced-motion block ~370
   lines above sets these same three tokens back to their ink values, and a
   media query adds no specificity -- so an unconditional rule down here would
   simply out-order it and hand a reader who asked for calm the colour-ground
   tiers on a black band. Each state declares its own; neither can reach the
   other. */
@media (prefers-reduced-motion: no-preference) {
  .band--cycle {
    animation: band-cycle 12s linear infinite;
    color: #FFFFFF;
    --ink-soft: #D6D1C8;
    --rule: #8A8479;
  }
  .band--cycle a { color: #FFFFFF; }
  .band--cycle .go { border-bottom-color: #FFFFFF; }

  /* IN COLOUR TAKES ITS COLOURS FROM THE PAINTING ABOVE IT (JP, 17/09). The
     group whose subject is colour was cycling the site's page colours, which
     are the same four everywhere and have nothing to do with the work on that
     page. These five are JP's, given 17/09; see the keyframes for which two
     ship exactly as he wrote them and which three had to come down in
     lightness to carry white type.
     ANIMATION-NAME ONLY. `animation` is a shorthand, so restating it here would
     silently reset the 12 seconds and the timing declared above, and the band
     would drift out of step with every footer on the site. */
  .band--cycle-obra { animation-name: obra-cycle; }
  /* EACH CITY TAKES ITS COLOURS FROM ITS OWN PHOTOGRAPH (JP, 22/09). */
  .band--cycle-barcelona { animation-name: city-barcelona; }
  .band--cycle-caracas   { animation-name: city-caracas;   }
  .band--cycle-madrid    { animation-name: city-madrid;    }
  .band--cycle-miami     { animation-name: city-miami;     }
  .band--cycle-panama    { animation-name: city-panama;    }
  .band--cycle-encargos  { animation-name: encargos-cycle; }}

/* COMMISSIONS, FROM ITS HERO CLIP (JP, 22/09): the ochre ground, the painting's
   blue, its red, the room's shadow -- sampled from the clip's last frame and
   deepened to white-safe. Worst frame across every transition 7.31:1. */
@keyframes encargos-cycle {
  0%,100% { background-color: #724E00; }
  25%     { background-color: #395B69; }
  50%     { background-color: #9F2C04; }
  75%     { background-color: #2A2118; }
}

/* A CITY HERO PAINTS ITSELF ON (JP, 22/09). The paintings' heroes are clips of
   the work being painted; a city's is a photograph, and it sat there static. So
   on load the script in base.html lays the photograph down in broad bristled
   strokes, top to bottom, in about two seconds, and then leaves it alone.
   HIDDEN ONLY WHILE A SCRIPT IS PAINTING IT. `html.js` is set in the head and
   `is-painting` by the painter itself; if the painter never starts, the
   failsafe fades the photograph in at 1.5s, and with scripting off or reduced
   motion none of this applies at all. */
@media (prefers-reduced-motion: no-preference) {
  .js [class*="hero-figure--ciudad-"]:not(.is-painted) .hero-still {
    opacity: 0; animation: paint-failsafe .4s 1.5s forwards;
  }
  .js [class*="hero-figure--ciudad-"].is-painting .hero-still { animation: none; }}
@keyframes paint-failsafe { to { opacity: 1; } }
.paint-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 2; pointer-events: none; display: block;
}

/* CARACAS SHOWS MORE OF ITSELF (JP, 22/09): el Avila, the cloud on it and the
   park under it only read together, so this band is taller than the others on a
   wide screen -- 46vw, never past 82% of the screen's height. At 1440x900 that
   shows 69% of the photograph's height instead of 52%. */
@media (min-width: 40.01rem) {
  .hero-figure.hero-figure--ciudad-caracas img { height: min(max(clamp(340px, 56vh, 620px), 46vw), 82vh); }}

/* THE COMMISSIONS HERO SHOWS THE ROOM (JP, 22/09, second pass). The first
   pass aimed a crop at the canvas and cut the sofa away, and the sofa is the
   point: it is what says this is a work made FOR a space. So:
   - THE CLIP ITSELF IS CROPPED, not the band. The canvas sat 5% right of
     centre in the generated frame; 262px came off its left edge (2560 -> 2298)
     so the canvas is at exactly 50%, under the centred "Commissions" heading.
   - ON A WIDE SCREEN THE BAND TAKES THE CLIP'S OWN SHAPE, 1920x1204, capped at
     88% of the screen's height -- at 1440x900 that shows 88% of the frame,
     canvas, wall, sculpture and sofa.
   TWO CLASSES, ON PURPOSE: `.hero-figure img` further down the file sets
   `object-position: center` and a height at the same one-class weight, and the
   later rule wins -- so a one-class version of this was silently ignored. */
.hero-figure.hero-figure--encargos img, .hero-figure.hero-figure--encargos video { object-position: 50% 40%; }
@media (min-width: 40.01rem) {
  /* THE SOFA STAYS IN, WHOLE (JP, 22/09: "if you need to go back to the bigger
     hero, it's fine -- just make sure it looks nice"). Measured on the frame,
     the sofa runs from 83% to 100% of its height, so any band shorter than the
     frame cut it; fitting the band to the screen showed only its back. So the
     band is the frame MINUS its top 9% -- wall above the canvas, which starts at
     12.2% -- at full width: 57.06vw tall, bottom-aligned. On a 1440x900 laptop
     that is the screen; on wider screens the sofa's base is a short scroll. */
  .hero-figure.hero-figure--encargos img { height: calc(100vw * 1204 / 1920 * .91); }
  .hero-figure.hero-figure--encargos img, .hero-figure.hero-figure--encargos video { object-position: 50% 100%; }}

/* THE CITY PALETTES (JP, 22/09). Four colours per city, read out of that city's
   hero photograph by median-cut quantising and then DEEPENED -- same hue, a
   little more saturation, less light -- until white type clears 7:1. Sampled
   at 60 steps across every transition: the worst frame on any city is 7.11:1.
   Ordered so each step moves far enough to be seen (channel distance 79-190).
   Four stops over the shared 12 seconds is 3s a colour. */
@keyframes city-barcelona {           /* roofs, park, sandstone, shadow */
  0%,100% { background-color: #7A3522; }
  25%     { background-color: #2F4A3A; }
  50%     { background-color: #724E3B; }
  75%     { background-color: #1F2A33; }
}
@keyframes city-caracas {             /* el Ávila, the park's shade, cloud, the lawn */
  0%,100% { background-color: #2E5192; }
  25%     { background-color: #16280F; }
  50%     { background-color: #4A4F90; }
  75%     { background-color: #335E17; }
}
@keyframes city-madrid {              /* sky, stone, gold, slate */
  0%,100% { background-color: #295982; }
  25%     { background-color: #5C564E; }
  50%     { background-color: #7A4E22; }
  75%     { background-color: #2F4052; }
}
@keyframes city-miami {               /* dusk, sunset, mauve, night */
  0%,100% { background-color: #404D8C; }
  25%     { background-color: #8A4520; }
  50%     { background-color: #6F4C66; }
  75%     { background-color: #203467; }
}
@keyframes city-panama {              /* sea, palms, deep water, cloud */
  0%,100% { background-color: #0E5985; }
  25%     { background-color: #285C2C; }
  50%     { background-color: #0E3F4F; }
  75%     { background-color: #49585F; }
}

/* THE CITY HEAD is only a name and a line, so it takes less height than a band
   that carries a hang. */
.city-head { padding-block: clamp(2rem, 3.5vw, 3rem); }
.city-head .group-head { margin-bottom: 0; padding-bottom: 0; border-bottom: 0; }
.city-pdf { margin: 1.5rem 0 0; }
/* THE STATEMENT NOW FOLLOWS THE RECORD (Nico, 01/10), two paper bands in a row,
   so a rule and its own top padding keep them two sections, as on .city-more. */
.band.band--paper.band--after-record { border-top: 1px solid var(--rule); padding-top: clamp(3rem, 5.3vw, 4.5rem); }

/* THE OTHER CITIES, AS PICTURES. A rule and its own top padding, because two
   paper bands in a row otherwise lose the space between them. */
.band.band--paper.city-more { border-top: 1px solid var(--rule); padding-top: clamp(3rem, 5.3vw, 4.5rem); }
.city-cards {
  list-style: none; margin: 1.25rem 0 2.5rem; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.25rem;
}
@media (max-width: 48rem) { .city-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }}
.city-card { display: block; color: inherit; text-decoration: none; }
.city-card img {
  display: block; width: 100%; aspect-ratio: 3 / 2; height: auto;
  object-fit: cover; object-position: center;
  transition: opacity .3s ease;
}
.city-card:hover img, .city-card:focus-visible img { opacity: .85; }
.city-card-name {
  display: block; padding-block: .75rem .25rem;
  text-transform: uppercase; letter-spacing: .08em; font-size: .9rem;
}
/* A PHOTOGRAPH UNDER A LICENCE THAT ASKS TO BE NAMED says so where it is used. */
.city-credit { margin: 2.5rem 0 0; font-size: .75rem; color: var(--ink-soft); }
.city-credit a { color: inherit; }
.city-card:hover .city-card-name, .city-card:focus-visible .city-card-name { text-decoration: underline; text-underline-offset: .3em; }



/* THREE GROUNDS, NOT FOUR -- THE BLUE IS OUT (JP, 17/09). It was the loudest
   and the most saturated of the five page colours, and as the first stop it was
   also where the cycle sat whenever it was not mid-turn, so a reader met the
   blue and inferred the rest. Green, purple and orange are the three that read
   as one family; the blue read as a brand colour arriving on top of them.

   THE FLOOR DOES NOT MOVE. Measured across 201 samples of each transition, the
   worst frame of the three-colour cycle is identical to the four-colour one --
   7.01:1 white, 4.61:1 soft tier, both at the orange itself. The blue sat at
   7.30:1 and was never the constraint, so removing it costs nothing and the
   tier values below stand unchanged.

   The blue is NOT retired from the site: `index` still takes it as its static
   footer ground under reduced motion, and it is still the home page's colour in
   `.foot--index`. It is out of the TRAVELLING set only. */
/* JP'S FIVE, AT THE DEPTH WHITE TYPE NEEDS (JP, 17/09 -- replaces the set
   sampled from Tumulto earlier the same day).

   HE GAVE FIVE: #03092c #441307 #e3c725 #d74512 #307160. Two carry white type
   as they are and ship untouched -- the navy at 19.46:1 and the dark red at
   15.65:1. THREE DO NOT, and the yellow is not a near miss: white on #e3c725
   measures 1.69:1, which is type nobody can read. #d74512 is 4.42:1 and #307160
   is 5.74:1, both under the 7.01:1 this site already holds everywhere else.

   So those three keep their HUE and their SATURATION and come down in lightness
   only: #e3c725 -> #605510, #d74512 -> #99310D, #307160 -> #285D4F. His colours,
   deep enough to read on. This is a readability decision and not a taste one,
   and it is one line to reverse if he wants the literal five.

   IN HUE ORDER RATHER THAN THE ORDER GIVEN, so the cycle travels the short way
   round the wheel -- 12deg, 16deg, 51deg, 164deg, 231deg. The listed order goes
   yellow, then orange, then back out past both, which reads as a stumble rather
   than as a turn.

   THE STOPS ARE NOT THE TEST. A cross-fade spends nearly all its time between
   two colours: on the site's own cycle the worst frame is the orange STOP at
   7.01:1. Sampled 201 frames of each of the five transitions here -- worst
   anywhere is 7.46:1 white and 4.91:1 on the soft tier, against the 7.01 and
   4.61 that are live. Five stops over the same 12 seconds is 2.4s a colour. */
@keyframes obra-cycle {
  0%   { background-color: #441307; }  /* his #441307, exactly            */
  20%  { background-color: #99310D; }  /* his #d74512, deepened           */
  40%  { background-color: #605510; }  /* his #e3c725, deepened           */
  60%  { background-color: #285D4F; }  /* his #307160, deepened           */
  80%  { background-color: #03092C; }  /* his #03092c, exactly            */
  100% { background-color: #441307; }
}

@keyframes band-cycle {
  0%     { background-color: #0E3B2E; }  /* obra     verde oscuro */
  33.33% { background-color: #4A1E6E; }  /* artista  morado       */
  66.67% { background-color: #A23207; }  /* encargos naranja      */
  100%   { background-color: #0E3B2E; }
}

/* THE SCROLL TIMELINE IS GONE -- EVERYTHING IS ON THE CLOCK (JP, 17/09).
   A band used to turn as the reader scrolled past it while the footer turned on
   a 12-second timer, and the argument for the split was that a reader is moving
   at one and stationary at the other. In practice it made the SAME effect behave
   two different ways on one page, so the colour read as a reaction to scrolling
   in one place and as a property of the site in the other -- and a reader who
   stopped mid-band simply froze it on a colour nobody chose.

   One driver now: `animation: band-cycle 12s linear infinite`, declared once
   above and shared by every colour band and every footer. Four seconds a colour.
   Nothing here overrides it. */

/* The statement sits directly under the hero, so it opens tighter than a band
   that follows type. */
/* The compact band: 64px at 1363, 40px at 390, and symmetric. It used to open
   on 82px and close on 109px, which made the page's opening argument sit in a
   deeper hole than any section below it. */
.center { text-align: center; }
.center .display,
.center .h2 { margin-inline: auto; }

/* --- FULL BLEED ----------------------------------------------------------
   OUTSIDE the wrapper, never escaping it with a negative margin: the margin
   trick measured 4vw past the viewport on both sides at every width. */
.bleed { width: 100%; margin: 0; }
.bleed img { display: block; width: 100%; height: auto; }

/* --- SECTION HEADS -------------------------------------------------------
   Label left, heading right, one rule under both. The number is information —
   it says how far through the page you are — so it is set as data, not as
   decoration, and it shares a baseline with the heading it names. */
.rule-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding-bottom: clamp(1.25rem, 2.5vw, 2rem);
  border-bottom: 1px solid var(--rule);
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
}
.rule-head .h2 { margin: 0; }
/* CENTRED, AND THE COUNT STAYS WITH ITS LABEL (15/09). `space-between` threw
   the label to the far left of the band and the number to the far right, with
   a metre of nothing between them, while every other heading on the site was
   centred. They are one caption; they sit together, on the same axis as the
   rest. */
.rule-head--split {
  border-bottom: 0; padding-bottom: 0;
  justify-content: center;
  gap: 1rem;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}

/* The earlier pass numbered sections with a generated ::before. The render puts
   the number in the eyebrow itself, where it can sit beside the heading rather
   than stacked above it, so the generated one comes off. */
.section-head .h2::before{ content: none; }



/* --- THE HANG ------------------------------------------------------------
   Works stand on a SHARED BASELINE, ragged at the top, which is how a wall is
   actually hung and the only way a row closes without cropping anything. The
   caption sits under the baseline, so all three captions align even though no
   two works are the same height.

   The width of each work comes from build.py `wf`, solved from its real square
   metreage and its photograph's aspect. Three works to a row, so a work never
   has to carry more than a third of the column and the 800px files hold. */
.hang {
  display: grid;
  align-items: end;
  /* Row 64px, column unchanged. The row value is the ONE place vertical space
     between works is decided: the card no longer pads, and the gap between two
     separate row containers below matches it, so a wrapped row and a new row
     are the same distance apart instead of 80px plus two lots of padding. */
  row-gap: 4rem;
  column-gap: clamp(1.5rem, 3vw, 2.5rem);
  list-style: none;
  margin: 0 0 4rem;
  padding: 0;
}
.hang:last-of-type { margin-bottom: 0; }

.work { display: flex; flex-direction: column; justify-content: flex-end; }
.work a { text-decoration: none; color: inherit; display: block; }

/* The plate is only an alignment device: the image sits on its bottom edge and
   grows upward. No fixed ratio, so nothing is ever cropped to fit. */
.plate { display: flex; align-items: flex-end; }
.plate img {
  display: block;
  width: calc(var(--w, 1) * 100%);
  height: auto;
  max-width: 100%;
  transition: transform 1.1s var(--ease);
}

.work .cap, .room .cap, .studio-shot .cap {
  margin-top: 1rem;
  padding-top: .75rem;
  border-top: 1px solid var(--rule);
}
/* THE HELD LINE. An empty `.cap-meta` collapses to nothing -- an empty block
   has no line box -- so it is given the meta line's own height and nothing
   else. It carries no text and `aria-hidden`, so it is a spacer to the eye and
   does not exist to a screen reader. */
.cap-meta--hold { min-height: calc(var(--hold-lines, 1) * 1lh); }

/* THE BASELINE, HELD BY THE GRID INSTEAD OF BY COUNTING LINES (23/09).
   Everything above reserves caption lines by predicting how many there will
   be, and a prediction breaks the moment a line WRAPS: the Spanish captions
   are longer ("Impresión 3D sobre acrílico", "Actualmente en Caracas"), so at
   1024px eight rows of es/obra.html stood 21px out -- one line -- while every
   English row was level. Measured, not guessed.

   Subgrid removes the prediction. Each work spans two rows of its hang and
   shares them with its neighbours: row one is as tall as the tallest plate and
   every photograph sits on its floor; row two is as tall as the longest
   caption and every rule starts at its top. The images line up whatever the
   captions say, in either language. Browsers without subgrid keep the old
   flex behaviour, which is where the held lines still earn their place. */
@supports (grid-template-rows: subgrid) {
  .hang .work, .hang .work > a {
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    row-gap: 0;
  }
  .hang .work > a > .plate { align-self: stretch; }
  .hang .work > a > .cap { align-self: start; }
}

/* --- SPLIT SECTIONS ------------------------------------------------------
   A vertical rule, name on one side, facts on the other. The rule is the whole
   device; it does the work a box would otherwise do, and costs nothing. */
.split-rule {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
}
/* GAP ZERO, AND THE MARGINS OWN THE SPACING (15/09). This carried a 48px flex
   gap on top of the eyebrow's own 12px bottom margin, which is why the label
   sat 60px above his name here and 12px above every other heading on the site.
   The column still pushes `.eyebrow--foot` to the bottom with `margin: auto`,
   which needs no gap to work. */
.split-rule-name {
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* The body column's gap is the body-to-action relationship, and the brief
   gives that one 24px on both desktop and mobile. It was 40px at this width. */
.split-rule-body {
  border-left: 1px solid var(--rule);
  padding-left: clamp(2rem, 5vw, 5rem);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.split-rule-body .prose p { max-width: 34rem; }
.eyebrow--foot { margin: auto 0 0; }

/* His name is the one place on the page a heading may run to two lines on
   purpose, so it is allowed to break where it likes. */
.h2--name { text-wrap: initial; }

/* THE HOME PAGE'S CLOSE IS `.split-rule` AGAIN (JP, 16/09). The centred
   one-column variant that replaced it on 15/09 is gone with its markup; only
   the portrait below is specific to this section.

   HIS PHOTOGRAPH, IN THE NAME COLUMN. `margin-top: auto` is deliberate and it
   is what `.eyebrow--foot` used to do alone: the column is a flex stack, so the
   picture is pushed to the bottom and its top edge lands wherever his name
   ends. It never stretches -- a portrait scaled to match a column of text is a
   portrait cropped by a paragraph length, which changes with the language. */
/* IT FILLS THE NAME COLUMN (JP, 16/09). Capped at 22rem it was already flush
   with the left edge of his name -- measured at nine widths, all of them 0px
   off -- but it stopped 183px short of the right, and against a 535px column of
   type that reads as a picture pushed inboard. Filling the column puts BOTH
   edges on the text, which is what "aligned" is being asked for here. */
.close-portrait {
  margin: var(--gap-group) 0 0;
  max-width: 100%;
}
.close-portrait img {
  width: 100%;
  height: auto;
  display: block;
}
/* The rule pushes the location line to the bottom of the column when there is
   no portrait; with one, the portrait is the last thing and takes that job. */
.split-rule-name:has(.close-portrait) .eyebrow--foot { margin: 0; }

/* THE TWO-PORTRAIT SPLIT (JP, 02/10). The studio portrait is the floor; the
   portrait at his wall sits on top, cut by `--x` from the left, so moving the
   line uncovers one room and covers the other. Everything is achromatic, like
   the rest of the interface: a white line and a white knob with a dark ring,
   readable on the near-black studio wall and on the white mural alike, because
   the ring carries the edge on white and the fill carries it on black. */
.reveal-stage {
  position: relative;
  overflow: hidden;
  cursor: ew-resize;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.reveal-stage img { -webkit-user-drag: none; pointer-events: none; }
.reveal .reveal-top {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  clip-path: inset(0 0 0 var(--x));
}
.reveal-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--x);
  width: 2px;
  margin-left: -1px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35);
  pointer-events: none;
}
.reveal-knob {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 2px #141414, 0 4px 14px rgba(0, 0, 0, .35);
}
/* Two chevrons, pointing out: the knob says "this goes both ways" without a word. */
.reveal-knob::before,
.reveal-knob::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  margin-top: -4px;
  border: solid #141414;
  border-width: 0 0 2px 2px;
}
.reveal-knob::before { left: 11px; transform: rotate(45deg); }
.reveal-knob::after { right: 11px; transform: rotate(-135deg); }
.reveal.is-gliding .reveal-top { transition: clip-path 1s cubic-bezier(.65, 0, .35, 1); }
.reveal.is-gliding .reveal-line { transition: left 1s cubic-bezier(.65, 0, .35, 1); }
/* The range is the keyboard's and the screen reader's way in. It is invisible
   but focusable, and focus draws a ring on the photograph, which is what moves. */
.reveal-range {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
}
.reveal { position: relative; }
.reveal:has(.reveal-range:focus-visible) .reveal-stage { outline: 2px solid #141414; outline-offset: 3px; }


/* THE BODY SETS ON THE MIDDLE OF THE COLUMN BESIDE IT (JP, 16/09). The name
   column is taller than the text, because it carries a photograph; top-aligned,
   the three lines of type ended a picture-height above the bottom of the band
   and the section read as two columns of different lengths rather than one
   row. Centring is scoped to `--close`: `.split-rule` is used elsewhere on the
   site where the two columns are the same height and centring would do nothing
   but risk a change nobody asked for. */
.split-rule--close .split-rule-body { justify-content: center; }
/* THE SAME HEADING, NOW AT THE TOP OF ITS BAND (16/09). `.h2--close` carried a
   large top margin because it was the second half of a section and needed
   separating from the first; opening the band it needs none -- the band's own
   padding is the space above it. */
.h2--open { margin-top: 0; }

.display--record {
  font-family: var(--sans);
  font-size: var(--t-lede);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -.01em;
  color: var(--ink-soft);
  margin: 0;
  text-wrap: balance;
}
/* THE WRAPPER, NOT ONLY THE PARAGRAPH. `.prose` is 34rem wide and the
   paragraph inside it had `margin-inline: auto` -- which centres a paragraph
   inside a 34rem box that was itself flush against the left of a 1139px band.
   The text was centred; the column it sat in was 594px off-centre, in both
   languages, which is what reads as the section being crooked. */
.prose--center { margin-inline: auto; }
.prose--center p { margin-inline: auto; max-width: 34rem; }
/* THE CENTRED PROSE IS THE HEADER GROUP'S CONTENT, so the gap above it is the
   site's group-to-content token, not a private clamp. It carried its own
   20px from before the type system existed, which read as a heading-to-
   subtitle gap under a heading that has no subtitle. Only the home page's
   investigation band matches this selector, in both languages. (15/09) */
.center .prose { margin-top: var(--gap-group); }

.section-foot { margin: clamp(1.5rem, 3vw, 2.5rem) 0 0; }
/* SUBTITLE TO ACTION IS 24px ON BOTH WIDTHS, and it is a RELATIONSHIP, so it
   is declared once here rather than as a third per-band override. `.band--
   statement` and the hero panel each carry their own copy of this value
   because the generic 40px reached them first; the commissions close was
   the third context to need it, which is the point at which a private
   override becomes a rule. Higher specificity than `.section-foot`, so it
   wins wherever the two actually meet. (15/09) */
.group-sub + .section-foot { margin-top: 1.5rem; }
@media (max-width: 34rem) {
  .hang {  gap: clamp(2rem, 6vw, 3rem); }
  .plate img { width: 100%; }
  .split-rule { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .split-rule-body { border-left: 0; border-top: 1px solid var(--rule); padding-left: 0; padding-top: 2rem; }
  .eyebrow--foot { margin-top: 0; }}



/* --- EDITORIAL HOME, second pass ------------------------------------------ */

/* THE STATEMENT BREAKS ONTO TWO LINES ON PURPOSE. One line puts the roman and
   the italic on the same rule and the lean stops reading as a shift in voice;
   two lines give "my own way" a line of its own, which is what the render
   draws and what the sentence actually does. */
/* RESTORED 15/09. Deleted when the second-pass review folded the headline into
   an ivory panel beside the painting; JP reversed that the same day, so the
   band that carries the line is back and needs its own quieter padding again --
   it is a sentence under a picture, not a chapter. */
.band--statement { padding-block: clamp(2.5rem, 4.7vw, 4rem); }
/* An action under the sentence is the brief's 24px, the same on both widths.
   Inside a statement band it was picking up `.section-foot`'s generic 40px. */
.band--statement .section-foot { margin-top: 1.5rem; }
/* 15ch WAS AN ENGLISH MEASURE (JP, 16/09). At 72px it comes to 497px, which
   holds "A work that begins with the space." on two lines and pushes "Una obra
   que comienza en el espacio." onto three -- the same heading, set differently
   in the two languages, because Spanish runs longer for the same sentence and
   nothing here was reading in Spanish when the number was chosen.

   19ch is the widest that still keeps every one of these headings on TWO lines
   rather than collapsing a short one onto one: measured across both languages,
   the English encargos heading becomes a single line at about 800px, so the
   measure has to stay well under that. Character units, not pixels, so it
   tracks the type size on a phone as it always did. */
.band--statement .display { max-width: 19ch; }
.band--statement .display em { display: block; }

/* THREE COUNTED LINES, ONE FACT EACH. The record band is the only place on the
   page where numbers carry the argument alone, and three sentences wrapped
   into two lines read as a paragraph rather than as a list. */

/* THE FOOT IS THE LAST BAND. It used to take the ink like the others, so the
   page ended on his name rather than on furniture.

   SINCE 2026-09-14 IT TAKES ONE COLOUR PER PAGE (Nico's ask, JP confirmed), and
   ink is only the fallback for a page with no colour assigned. This block is
   where the footer colour actually broke: it sits ~480 lines BELOW the
   `.foot--` palette and set `background: var(--ink)` outright, so every footer
   painted ink and the five colours never appeared on screen once. The palette
   was correct, the class was on the element, and the later declaration won.
   `--foot-bg` now carries ink as its own fallback instead, so there is one
   place that decides and nothing downstream to override it. */
.foot {
  background: var(--foot-bg, var(--ink));
  color: var(--foot-fg, var(--paper));
  --ink-soft: #A8A296;
  --rule: #34322D;
  border-top: 0;
  /* SMALLER (JP, 15/09). It was clamp(3rem, 6vw, 5rem) -- 80px top and bottom at
     1363px, more than a major content section gets, for a colour band holding an
     address, three links and a copyright line. The footer is the quietest thing
     on the site and should take the least room of anything that is not a rule. */
  padding-block: clamp(2rem, 3.5vw, 3rem);
  margin-top: 0;
}

/* --- THE FOOTER MOVES THROUGH THE PALETTE (JP, 16/09) ---------------------
   The same three grounds, on the same keyframes, as the colour band: green,
   purple, orange. Not a second set of colours to keep in step with the first --
   `band-cycle` is re-used exactly as it is, which is why the footer and the
   band can never drift apart, and why dropping the blue moved both at once.

   TIME, NOT SCROLL. The band turns as the reader scrolls past it; a footer is
   the last thing on the page and a reader is usually stationary by the time
   they reach it, so scrolling would leave it frozen on one colour. 12 seconds
   for the full circuit -- four per colour now the blue is out, which is quick
   enough to notice without becoming the thing you watch.

   EVERY FRAME IS WHITE-SAFE, AND THAT IS WHY THESE THREE. Computed across 201
   samples of each transition: the worst point in the whole cycle is 7.01:1
   against white, at the orange itself. The stops ARE the extremes --
   an sRGB interpolation between any two of them is darker than both -- so no
   mid-turn colour can drop below a stop that already passes. The yellow of the
   contact footer is deliberately NOT in this set: it is the one ground on the
   site that needs near-black type, and a cycle that has to change its text
   colour halfway round is a cycle that fails somewhere.

   REDUCED MOTION KEEPS THE PAGE'S OWN COLOUR. The global reduced-motion rule
   turns the animation off, and the footer falls back to `--foot-bg` -- the
   ground that page has always had, contact included, with its own text colour.
   Nothing is lost by asking for calm; the colour simply stops travelling. */
/* ---------------------------------------------- A CYCLE PER PAGE (JP, 21/09)
   Every footer used to run the SAME three grounds, so the one band that was
   supposed to say which page you were on said the same thing on all of them.
   The five per-page colours existed but only a reader who had turned motion
   off ever saw them. Six cycles now, and each one OPENS ON ITS OWN PAGE'S
   COLOUR -- `0%` is the ground that page has always had, so arriving on a page
   shows you its colour and then takes you somewhere.

   THE RULES THESE HAD TO SATISFY, both measured rather than judged:

   1. WHITE AT EVERY FRAME, NOT JUST AT THE STOPS. A 12s cycle spends almost
      all its time BETWEEN the colours someone chose, and sRGB interpolation
      can pass somewhere neither stop warned about. All six were sampled at 60
      steps per transition against white: the worst frame anywhere in the six
      is 7.01:1, at the orange, which is the same floor the single cycle had.

   2. THE MOVEMENT HAS TO BE VISIBLE. Three shades of one hue clears contrast
      easily and reads as nothing happening. Measured as the channel distance
      between consecutive stops: the shipping cycle's smallest step was 153,
      and no cycle here steps less than that. The first draft of this -- each
      page travelling inside its own hue family -- scored 18 on `obra` and was
      thrown away.

   3. NO CYCLE CHANGES ITS TEXT COLOUR HALFWAY ROUND. That rule is why the
      contact yellow was left out of the original set and it is why it is still
      out: it is the one ground that needs near-black. Contact keeps its yellow
      as its reduced-motion ground and travels through dark grounds like the
      rest, which is exactly what it did before.

   `band-cycle` itself is untouched -- `.band--cycle` on the Work page heading
   still uses it, and these are additions beside it rather than an edit to it. */
/* THE ELECTRIC BLUE LEFT HOME, COMMISSIONS AND CONTACT (JP, 24/09). The other
   three footers keep it; he named these three. Re-measured with the same two
   rules: worst frame 7.49 / 7.01 / 7.01:1 against white, smallest step 153 / 153
   / 191. Home loses the orange as well, because ochre-to-orange is a step of 83
   and reads as nothing happening. */
@keyframes foot-index {
  0%,100% { background-color: #724E00; }  /* ocre */
  33.33%  { background-color: #4A1E6E; }
  66.67%  { background-color: #0E3B2E; }
}
@keyframes foot-obra {
  0%,100% { background-color: #0E3B2E; }  /* verde oscuro */
  33.33%  { background-color: #4A1E6E; }
  66.67%  { background-color: #A23207; }
}
/* THE BLUE LEFT THE ARTIST PAGE TOO (JP, 02/10: "i dont like it", asked for
   yellow). A true yellow needs near-black type, which rule 3 forbids, so it is
   the ochre -- the darkest yellow white type reads on, 7.49:1. Orange left with
   it: ochre beside orange is a step of 83 and reads as nothing happening.
   Steps 198 / 165 / 153. */
@keyframes foot-artista {
  0%,100% { background-color: #4A1E6E; }  /* morado */
  33.33%  { background-color: #724E00; }  /* ocre */
  66.67%  { background-color: #0E3B2E; }  /* verde oscuro */
}
@keyframes foot-encargos {
  0%,100% { background-color: #A23207; }  /* naranja */
  33.33%  { background-color: #4A1E6E; }
  66.67%  { background-color: #0E3B2E; }
}
@keyframes foot-contacto {
  0%,100% { background-color: #0B3A45; }  /* verde azulado */
  33.33%  { background-color: #A23207; }
  66.67%  { background-color: #702C91; }  /* violeta */
}
@keyframes foot-ciudad {
  0%,100% { background-color: #7A1230; }  /* burdeos */
  33.33%  { background-color: #0B3A45; }
  66.67%  { background-color: #1536F5; }
}

@media (prefers-reduced-motion: no-preference) {
  .foot {
    /* The shorthand sets the timing for every footer AND names a fallback. The
       per-page names come AFTER it, further down this block, and that order is
       load-bearing: `animation` is a shorthand, so it RESETS `animation-name`,
       and `.foot--index` and `.foot` have identical specificity. Written above
       this rule, the six page cycles were silently overwritten by the fallback
       and all seven page types cycled green-purple-orange exactly as before --
       the CSS was valid, the build passed, and only sampling the rendered
       colour on each page showed it. */
    animation: band-cycle 12s linear infinite;
    /* The cycle never visits a light ground, so the type is white throughout --
       including on `contacto`, whose static yellow needs near-black and whose
       animated state never shows it. `.foot a` and `.foot-small` inherit. */
    color: #FFFFFF;
  }

  /* AFTER the shorthand, never before it -- see the note above. */
  .foot--index              { animation-name: foot-index;    }
  .foot--obra, .foot--obras { animation-name: foot-obra;     }
  .foot--artista            { animation-name: foot-artista;  }
  .foot--encargos           { animation-name: foot-encargos; }
  .foot--contacto           { animation-name: foot-contacto; }
  .foot--ciudad             { animation-name: foot-ciudad;   }}


/* Both inherit, so they follow the ground the footer is actually on. On yellow
   that is near-black; hard-coding paper here made every link on the contacto
   footer white on yellow. */
.foot a { color: inherit; }
.foot .foot-small { color: inherit; }

/* The hang's own captions keep their rule on ink as well as on paper: both are
   redefined by the band, so nothing here needs to know which ground it is on. */

/* --- EDITORIAL HOME, third pass ------------------------------------------- */

/* CONSECUTIVE BANDS OF THE SAME GROUND SHARE ONE GAP. Two paper bands in a row
   each contributed a full pad, so the seam between them opened to roughly
   twice the space of every other seam and read as a missing section. */
.band--paper + .band--paper { padding-top: 0; }
/* The band under the full-bleed hero opens on the COMPACT value, the same one
   `.band--statement` uses: it was 82px, which is neither of the two numbers the
   rest of the page is built from. */
.bleed + .band { padding-top: clamp(2.5rem, 4.7vw, 4rem); }

/* The record lines break at the full stop, not at whatever width the column
   happens to be. */
.display--record { max-width: none; }
.display--record span { display: block; }

/* The document ends on ink, so the ground beyond the last band does too --
   otherwise an over-scroll on a phone, or any viewport taller than the page,
   shows a strip of paper under a dark footer. */
html { background: var(--ink); }
body { background: var(--paper); }

/* THE MONOCHROME WORK CARRIES THE INVESTIGATION BAND. It replaces two
   paragraphs of argument, so it is set at reading size rather than at gallery
   size -- large enough to be looked at, small enough that the band still reads
   as a statement and not as a second hang. */
.aside-work a { display: block; text-decoration: none; color: inherit; }
.aside-work img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 1.1s var(--ease);
}
.aside-work .cap {
  margin-top: 1rem;
  padding-top: .75rem;
  border-top: 1px solid var(--rule);
}

@media (max-width: 34rem) {
  .aside-work { max-width: 100%; }}



/* --- EDITORIAL HOME, fifth pass ------------------------------------------- */

/* THE HANG CENTRES. Each work sits centred in its own column and its label
   centres under it, so six works of six different widths still read as one
   row rather than as six left edges that happen to share a baseline. */
.work { align-items: center; text-align: center; }
.work a { width: 100%; }
.plate { justify-content: center; }
.work .cap { width: 100%; }

/* The monochrome work on the ink band takes the same treatment: its label is a
   wall label under a hung work, and a hung work is centred under it. */
.aside-work .cap { text-align: center; }

/* HIS OWN WORDS, AND THEY ARE NOW SET LIKE WORDS (second-pass review, 15/09).
   This was serif italic at 26px, the most expressive treatment on the site,
   reserved for an attributed statement. The review's finding is that reserving
   it was not enough: a leaning serif at 26px beside an upright serif at 72px
   and an upright sans at 18px is a third reading treatment, and the quotation
   is read, not announced. It takes the body role now.
   WHAT IT KEEPS is everything that is not typography -- the measure, so it
   still sets as a spoken line rather than a paragraph, the full-strength ink
   that separates it from supporting copy, and its attribution in the markup.
   Meaning survives the treatment coming off; that was the brief's condition. */
.said {
  font-family: var(--sans);
  font-style: normal;
  font-size: var(--t-body);
  line-height: 1.6;
  letter-spacing: -.005em;
  /* NO ABSOLUTE COLOUR. This was `var(--ink)`, which is #0B0B0B, and it worked
     only for as long as the quotation lived on a paper band. The 15/09
     restructure moved the home page's artist section onto ink, and the sentence
     rendered black on black at 1.00:1 -- invisible, and caught by
     contrast-check rather than by reading the rule.
     Inheriting is the fix AND the rule: `.band--ink` already redefines the
     foreground for everything inside it, so a component that inherits is
     correct on both grounds and a component that names a colour is correct on
     one. Full strength is what separates it from supporting copy, and
     inheriting gives it full strength on whichever ground it lands. */
  max-width: 44ch;
  margin: 0;
  text-wrap: balance;
}

/* HIS VOICE (JP, 02/10). The home page's quotation in the display face's italic,
   larger than body and inside curly quotes, so it reads as Nico speaking rather
   than as one more line of the site describing him. The face is the one his name
   is set in, which ties the words to the name above them. */
.said--voice { margin: 1.5rem 0 0; }
.said--voice p {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.5rem, 1.1rem + 1.2vw, 2.125rem);
  line-height: 1.25;
  letter-spacing: 0;
  text-wrap: balance;
}

/* --- THREE ACROSS, AS WIDE AS THREE ACROSS CAN GO -------------------------
   THE ARITHMETIC, because it is the whole answer: `.wrap` is 78rem, so at 1440
   the column is about 1120px and each of three works gets a third of it minus
   the gaps -- 351px. There is no slack inside that. The images were already at
   100% of their track, so "make them bigger" and "keep three across" pull
   against each other, and two across was the only route to +56%.

   Three across is back at JP's instruction. The hang now takes a container of
   its own, wider than the reading column and with tighter gaps, which is every
   pixel three columns can have on a 1440 screen: 435px a work, +24%. The text
   above it keeps the narrower measure, because a line of prose 1300px long is
   unreadable and a painting 1300px wide is not. */
.wrap--hang {
  width: 100%;
  padding-inline: clamp(1.25rem, 3vw, 3rem);
}
.wrap--hang .hang {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 2.2vw, 2rem) clamp(1.25rem, 1.8vw, 1.5rem);
}

/* --- THE HERO COMES DOWN BY HALF -----------------------------------------
   It was full-bleed: 1440 wide and 878 tall at desktop, which is most of a
   screen before a word is read. Halving the HEIGHT without cropping means
   halving the width, so it stops touching the edges and becomes a plate on
   paper -- 720px and 439px tall, exactly half.

   The painting is still whole. Cropping it to a shorter band would have kept
   the full bleed and is the one thing an artist's site may not do. */

/* The two-column rule above belongs to the version that traded three across for
   size. Three across is back at JP's instruction, so it is overridden here
   rather than deleted, and the wider container is what buys the size instead. */
.hang { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 52rem) { .hang { grid-template-columns: repeat(2, minmax(0, 1fr)); }}


@media (max-width: 34rem) { .hang { grid-template-columns: minmax(0, 1fr); }}


.hero-figure img {
  width: 100%;
  height: clamp(340px, 56vh, 620px);
  object-fit: cover;
  object-position: center;
}

/* A HERO THAT IS NOT CROPPED (JP, 16/09). Commissions opens on a photograph of
   a canvas hanging on a wall, and the whole argument of that picture is the
   whole canvas -- a band of fixed height cut a third of its height away and the
   page opened on a painting with its top and bottom missing.

   NO HEIGHT, NO `object-fit`, NO CROP AT ANY WIDTH. The figure is capped by
   WIDTH and the picture keeps its own proportions, so what a reader sees at
   390px is what they see at 1920px. 68rem holds it to about 607px tall on a
   laptop, inside the range the cropped heroes occupy, and it comes down with the
   viewport from there. */
.hero-figure--whole { max-width: min(100%, 68rem); margin-inline: auto; }
.hero-figure--whole img { width: 100%; height: auto; object-fit: fill; }

/* The label sits on the paper under the band, never on the painting: type over
   a painting is a poster, and a poster is a thing being sold. */

@media (max-width: 34rem) {
  .hero-figure img { height: clamp(280px, 46vh, 420px); }
  /* EXCEPT THE ONE THAT IS NOT CROPPED. This phone rule sets a height, and a
     height is a crop -- it took the uncropped commissions hero from 1.79:1 back
     to 1.01:1 and cut the canvas in half again on the one screen where a reader
     is closest to it. `auto` is the whole point of that hero and it has to be
     restated here, because this rule is more specific than the one that set it. */
  .hero-figure--whole img { height: auto; }}



/* HIS FULL STATEMENT, UNDER THE THESIS. `.said` is a left-set line in the home
   page's split column; here it sits centred under a centred display line, so
   it takes the axis of the thing above it. The measure stays his, not the
   prose measure — it is a sentence he said, not body copy. */
/* THE COUNTS ARE THE HEADING HERE. On the home page the record band carries a
   label and a link either side of a rule; on this page the CV underneath is
   the link, so the eyebrow sits directly above the counts and needs the gap a
   rule used to hold open. */
/* THE PAINTING BESIDE THE PROFILE. It takes the home page's plate wholesale --
   no ratio box, no crop, its caption under a hairline -- so the one image on
   this page is hung the way every image in the hang is. */
.split-plate { margin: 0; }
.split-plate a { display: block; text-decoration: none; color: inherit; }
.split-plate .plate { display: flex; align-items: flex-end; }
.split-plate .plate img { display: block; width: 100%; height: auto; transition: transform 1.1s var(--ease); }
.split-plate .cap { margin-top: 1rem; padding-top: .75rem; border-top: 1px solid var(--rule); }
/* Removed 15/09: a fifth private value for label-to-heading, on one element.
   `.eyebrow` owns that gap for the whole site now. */


/* ==========================================================================
   THE INNER PAGES, ON THE HOME PAGE'S GRAMMAR — 2026-09-03.

   Obra, encargos, contacto and every work page were rebuilt out of the bands
   the home page already had, so almost nothing new is needed here. What is
   below exists because three things on those pages have no equivalent on the
   home page: a painting shown whole rather than cropped, a gallery label under
   it, and a list of delivery facts that are sentences rather than counts.
   ========================================================================== */

/* THE WORK, ALONE ON ITS BAND. The old layout put the specification list beside
   the painting from 56rem up, so a table of measurements sat level with the
   canvas's centre and the eye had two things to read at once. The painting now
   has the column to itself and the label sits underneath, which is where a
   gallery puts it. Capped at 68rem: past that a 3000px photograph is being
   shown larger than the wall it hangs on, and the page stops being a page. */
.work-figure--alone {
  margin: 0 auto;
  max-width: min(68rem, 100%);
}
.work-figure--alone img { width: 100%; height: auto; }

/* THE LABEL. Title on the left, facts on the right, divided by the same rule
   the split sections use. It stacks on a phone with the title first, because
   the one thing a reader wants under a painting is its name. */
.work-label {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: clamp(2rem, 4vw, 3.5rem);
  padding-top: clamp(1.5rem, 3vw, 2.5rem);
  border-top: 1px solid var(--rule);
  max-width: min(68rem, 100%);
  margin-inline: auto;
}
@media (min-width: 48rem) {
  .work-label { grid-template-columns: minmax(0, 1fr) minmax(18rem, .8fr); }}


.work-label .h2--name { margin: 0; }
.work-label .said { margin-top: 1.25rem; }
.work-label .spec div:first-child { padding-top: 0; }

/* THE HANG WAS THREE ACROSS ON A PHONE, ON EVERY PAGE THAT USES IT.
   `.wrap--hang .hang` is two classes deep and the responsive rules above are
   one, so from the day the wider hang container was added the 52rem and 34rem
   breakpoints stopped applying: at 390px three paintings shared the screen at
   about 110px each, with four-line captions under them. Nothing reported it
   because the page does not overflow -- it just becomes unreadable. Re-stated
   here at the same depth as the rule that was winning.

   A GROUP OF ONE, AND A GROUP OF TWO. The hang is three columns because a wall
   holds three; a single sculpture in the first of three cells reads as two
   photographs that failed to load. The row narrows to what it actually holds,
   and the work keeps its true width inside it rather than growing to fill the
   page. */
.wrap--hang .hang--single { grid-template-columns: minmax(0, 22rem); justify-content: center; }
.wrap--hang .hang--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 60rem; margin-inline: auto; }

@media (max-width: 52rem) {
  .wrap--hang .hang, .wrap--hang .hang--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }}


@media (max-width: 34rem) {
  .wrap--hang .hang,
  .wrap--hang .hang--pair,
  .wrap--hang .hang--single { grid-template-columns: minmax(0, 1fr); }}



/* The work page's own navigation sits under a hang rather than under a page, so
   it does not need the full step above it as well as the hang's bottom margin. */
.band--ink .hang + .work-nav { margin-top: clamp(2rem, 4vw, 3rem); }

/* THE ADDRESS, SET AS TYPE. Long enough at 29 characters that the display size
   has to come down; the rule under it is the same hairline the .go links carry,
   so it still reads as the thing to click. */
.mail-line {
  display: inline-block;
  font-family: var(--serif);
  font-size: var(--t-h3);
  line-height: 1.15;
  letter-spacing: -.015em;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: .15em;
  word-break: break-word;
}
.mail-line:hover { opacity: .55; }


/* ==========================================================================
   INTERACTION — 2026-09-03.

   THE THESIS: the hairline is this site's material. Every rule on the page is
   one pixel of --rule: under a caption, between CV years, down the middle of a
   split section. The page's one authored motion is the uncover -- a clip path
   that draws a painting up from its baseline. So every interactive state is the
   same gesture at small scale: a rule that draws itself in from the left.

   WHY NOT WHAT THE REST OF THE WORLD DOES. A colour hover is unavailable by
   rule: every colour on this site comes from inside a frame, and a link that
   turns blue on hover breaks the one promise the interface makes. An opacity
   fade -- what was here before -- is worse than nothing on paper: the text
   simply loses contrast for as long as you are pointing at it, which reads as
   the site going faint rather than as an answer.

   Two states, not one. HOVER is a pointer; FOCUS-VISIBLE is a keyboard, and
   before this pass the site had no focus styling at all -- tabbing through it
   was invisible, which fails 2.4.7 outright and makes the site unusable
   without a mouse.
   ========================================================================== */

/* The drawn rule. On a pseudo-element so it works on inline links, never moves
   layout, and can sit under text that already carries a border. */
.nav a, .nav-cities > summary, .lang, .wordmark, .foot a, .social a, .cv-note a, .mail-line, .go {
  position: relative;
  transition: color .25s var(--ease);
}
.nav a::after, .lang::after, .wordmark::after, .foot a::after, .social a::after,
.mail-line::after, .go::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -.15em;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .42s var(--ease);
}
.nav a:hover::after, .lang:hover::after, .wordmark:hover::after,
.foot a:hover::after, .social a:hover::after, .mail-line:hover::after,
.go:hover::after,
.nav a:focus-visible::after, .lang:focus-visible::after, .wordmark:focus-visible::after,
.foot a:focus-visible::after, .social a:focus-visible::after,
.mail-line:focus-visible::after, .go:focus-visible::after { transform: scaleX(1); }

/* THE PAGE YOU ARE ON KEEPS ITS RULE DRAWN. The navigation used to mark the
   current page by colour alone -- #5A574F against #0B0B0B, a difference a
   reader has to look for and a colour-blind reader may not get at all. */
.nav a[aria-current]::after { transform: scaleX(1); }
.nav a[aria-current] { color: var(--ink); }

/* `.go` and `.mail-line` already carry a static rule, so the drawn one has to
   land ON it rather than beside it: same offset, full ink, drawn over the
   hairline. The underline moves off the descenders either way. */
.go::after { bottom: -1px; }

/* THE HIT AREA IS BIGGER THAN THE TEXT, AND MOVES NOTHING.
   Measured across all 272 pages at 390px and 360px: 2,170 tap targets under
   the 24px AA floor, from four elements that repeat in the shared chrome --
   every `.go` link at 22px tall, the wordmark at 23, the footer email at 22,
   and the link to X at TEN PIXELS WIDE, because its whole label is one letter.

   On a pseudo-element, not on padding. This site's vertical rhythm is tuned to
   the pixel in several places and padding would move all of it; a transparent
   ::before inside the anchor enlarges what a thumb can hit and changes no
   layout at all. `::after` is taken -- it draws the hover rule.

   PLAIN INSETS, AND NO TRANSFORM. The first version centred a 24px box with
   `top: 50%` and `translateY(-50%)`. It looked identical and it measured wrong:
   mobile-check reads the pseudo-element's own top and bottom and cannot see a
   transform, so a 23px link reported a 35px box, every neighbour then read as
   3px away, and 2,168 size failures became 3,264 spacing ones. Two pixels top
   and bottom needs no transform to be true. */
.nav a::before, .lang::before, .wordmark::before, .foot a::before,
.social a::before, .mail-line::before, .go::before {
  content: "";
  position: absolute;
  /* -4px, not -2px, and the 2px came back from the type pass: at the shared
     13px navigation role the label box is 18px, so the old expander landed at
     22px and fell under the 24px AA floor. -4px puts it at 26px. NOT deeper:
     `.social` is a flex row with a 1rem gap, so ±4px still leaves the 8px
     minimum between two wrapped rows, and widening further would close it. */
  inset-block: -4px;
  inset-inline: 0;
}
/* The X widener that used to live here is gone with the X link itself: Nico's
   own list of accounts is Instagram, TikTok, YouTube and email. It existed
   because a single-letter label made a ten-pixel target -- a problem no
   remaining link has. */
.mail-line::after { bottom: -1px; height: 1px; }
.foot a:hover, .social a:hover { text-decoration: none; }

/* A WORK ANSWERS BY RISING, AND ITS LABEL BY DRAWING ITS RULE. The old hover
   moved the painting 0.4% and scaled it 1.2% -- measured on a 435px plate that
   is under two pixels, which reads as nothing happening. A painting on a wall
   does not scale when you approach it, so the lift is the whole move: 8px, on
   the curve everything else uses, with the caption's rule filling in under it. */
/* ONE HOVER FOR EVERY IMAGE ON THE SITE. The paintings rose 8px and the
   photographs did nothing at all, which is the difference a reader reads as
   "these are the real ones and those are filler". Same distance, same curve,
   same focus behaviour for a keyboard. */
.work a .plate img, .split-plate a .plate img, .aside-work a img,
.shot img {
  transition: transform .6s var(--ease);
}
.work a:hover .plate img, .work a:focus-visible .plate img,
.split-plate a:hover .plate img, .aside-work a:hover img,
.shot:hover img, .shot:focus-visible img {
  transform: translateY(-8px);
}

/* THE LINK ITSELF CARRIES NOTHING. It exists to make the photograph openable
   and to give the rise something to hang off; the site's drawn-rule hover is
   for text links, so it is explicitly not inherited here. */
.shot { display: block; text-decoration: none; color: inherit; }
.shot::after { content: none; }
/* EVERY PICTURE'S CAPTION CARRIES THE SAME RULE (JP, 16/09). This was keyed on
   `.work`, so the paintings got a hairline that drew itself left to right when
   the pointer arrived and the room and studio photographs got nothing -- the
   same "these are the real ones and those are filler" split the 8px rise was
   fixed for on 15/09, one layer down. `.shot .cap` is the photographs' card now
   that the caption lives inside the link. */
.work .cap, .room .cap, .studio-shot .cap { position: relative; }
.work .cap::after, .room .cap::after, .studio-shot .cap::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: -1px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--ease);
}
.work a:hover .cap::after, .work a:focus-visible .cap::after,
/* THE SIBLING COMBINATOR IS THE POINT. The caption is the link's NEXT sibling,
   not its child, so the photograph keeps its own box and its own accessible
   name -- see `_parts.html` for what happened when it was a child. */
.shot:hover + .cap::after, .shot:focus-visible + .cap::after { transform: scaleX(1); }

/* THE WORK NAVIGATION MOVES THE WAY IT IS POINTING. Previous steps left, next
   steps right: the only two links on the site whose direction is their meaning,
   so the acknowledgement carries it. */
/* Display is NOT set here. It was `inline-block`, which sat after the layout
   rule above and quietly cancelled the flex row the thumbnail needs -- the
   later declaration wins, and the thumbnail would have stacked. */
.work-nav-side { transition: transform .35s var(--ease); }
.work-nav-side:hover, .work-nav-side:focus-visible { transform: translateX(-.4rem); }
.work-nav-next:hover, .work-nav-next:focus-visible { transform: translateX(.4rem); }

/* A CV ROW LIGHTS ITS OWN RULE. The record is the one part of this site built
   to be scanned line by line, and forty rows of identical hairline give the eye
   nothing to hold its place with. */
.cv-row { transition: border-color .3s var(--ease); }
.cv-row:hover { border-bottom-color: var(--ink); }

/* KEYBOARD FOCUS, WHICH DID NOT EXIST HERE.
   Drawn in ink on paper and in paper on ink, so it survives the dark bands, and
   offset far enough to clear a painting's own edge rather than sitting on it. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 1px;
}
.band--ink :focus-visible, .foot :focus-visible { outline-color: var(--paper); }
.work a:focus-visible, .split-plate a:focus-visible, .aside-work a:focus-visible,
.shot:focus-visible {
  outline-offset: 6px;
}

/* The skip link is the first thing a keyboard reader meets. It was a bare box
   at the top-left corner; it now arrives on the page like a control. */
.skip:focus {
  left: 0;
  outline: 2px solid var(--paper);
  outline-offset: -6px;
}

/* TOUCH HAS NO HOVER. Every state above answers to :active as well, so a tap on
   a phone acknowledges itself instead of jumping straight to the next page. */
@media (hover: none) {
  .work a:active .plate img { transform: translateY(-4px); }
  .go:active::after, .mail-line:active::after, .nav a:active::after { transform: scaleX(1); }}



/* ==========================================================================
   PHOTOGRAPHS THAT ARE NOT PAINTINGS — 2026-09-03.

   A room with his work in it, and the painter at work. Both are documents
   rather than works, and the difference has to be visible or the page starts
   offering a photograph of a living room as if it were for sale.

   So they are the one place on this site where an image sits INSIDE a frame
   with a ratio: the hang exists to show a painting at its own shape and true
   size, and a snapshot of a wall borrowing that treatment would read as one
   more piece in the catalogue.
   ========================================================================== */

/* THEY HANG NOW, THEY DO NOT TILE (JP, 16/09). Every photograph used to be
   stretched to the full width of its cell, so a row aligned along its TOP edge
   and ended wherever each aspect ratio happened to leave it -- a portrait shot
   ran half a screen deeper than the landscape beside it, and the eye read that
   as "this one is more important". Nobody could name it; it is simply the
   opposite rule to the one `obra` runs on.

   This is `.hang--even`, the treatment `obra` gives a work whose real size
   nobody has stated: a shared bottom baseline, each image at its own shape and
   never cropped, and a ceiling on the height so no single frame can dominate a
   row. A photograph has no square metreage either, so it is the same problem
   and it takes the same answer. */
.rooms, .studio {
  display: grid;
  align-items: end;
  gap: clamp(1.5rem, 3vw, 2.5rem) clamp(1.25rem, 2vw, 2rem);
  list-style: none;
  margin: 0;
  padding: 0;
  grid-template-columns: minmax(0, 1fr);
}
.room, .studio-shot { display: flex; flex-direction: column; justify-content: flex-end; }
/* TWO ACROSS, NOT THREE (JP, 16/09 -- reverses the three-across of the same
   day). Three columns plus a height ceiling made every photograph land at the
   SAME height, and a row of identical rectangles is what he saw and called
   "extremely squared". The hang on `obra` looks better for one reason: no two
   paintings are the same size, so the row has a shape.

   Two columns is what gives these that back. The picture fills the column, so
   its height is its OWN proportion -- a 16:9 room lands near 315px, a 4:3 near
   420px, a portrait hits the ceiling -- and `align-items: end` still stands
   them all on one line. Bigger, and no longer uniform. */
@media (min-width: 40rem) {
  .rooms, .studio { grid-template-columns: repeat(2, minmax(0, 1fr)); }}



/* NEVER CROPPED. A photograph of a room is a document of what happened in it,
   so it keeps its own proportions -- which is now simply what it does, with no
   cell to fit and no ground to sit on.

   THE CEILING IS THE SAME NUMBER `obra` USES, deliberately: the two pages are
   meant to read at one scale, and two different caps would be the difference
   JP could see and could not name. */
.room .shot, .studio-shot .shot { display: block; }
/* CENTRED, AND THE CAPTION WITH IT (JP, 16/09, asked twice). The first reading
   of "centred with them" was "aligned with them", so these went left like the
   hang on `obra` -- but he means the axis, not the edge. At two columns a
   landscape photograph fills its cell and nothing moves; it is the one tall
   portrait, stopped by the ceiling, that this decides, and it now sits on the
   column's centre with its words under the middle of it. */
.frame--room, .frame--studio { display: flex; align-items: flex-end; justify-content: center; }
/* THE HANG'S OWN CEILING, THE SAME NUMBER (JP, 16/09): "use even the same
   typography and everything. Same alignments, same measurements." So this is
   `min(52vh, 30rem)`, read off `.plate img` on `obra`, not a second number
   invented for photographs.

   IT ONLY BINDS ON A PORTRAIT. `width: auto` with both maxes set is an
   aspect-preserving fit: a landscape photograph is stopped by the column and
   never reaches this, so the ceiling does not flatten the row -- it only stops
   the one tall shot that would otherwise run 840px in a two-column layout. */
.frame--room img, .frame--studio img {
  width: auto;
  max-width: 100%;
  max-height: min(52vh, 30rem);
  height: auto;
  margin-inline: auto;
}
/* A CAPTION IS TWO LINES OF ROOM WHETHER IT USES THEM OR NOT. Every one of
   these photographs carries a caption from 16/09, and at a 252px column some of
   them wrap and some do not -- which would put the row's baseline back exactly
   where `obra`'s was before the held meta line fixed it. Reserving the second
   line costs one blank line under the short ones and keeps every image in a row
   standing on the same edge. `baseline-check.py` is what catches it if this
   number ever stops being enough. */
/* THE SPACE ABOVE IS `.cap`'S NOW -- this margin would come on top of it. The
   two reserved lines stay: at a 252px column some captions wrap and some do
   not, and an uneven caption puts the row's baseline back where `obra`'s was
   before the held meta line fixed it. `baseline-check.py` catches it if two
   lines ever stop being enough. */
.room .cap-meta, .studio-shot .cap-meta { margin-top: 0; min-height: 2lh; text-align: center; }

/* AN EVEN HANG, FOR WORKS WITH NO MEASUREMENTS. The hang's whole argument is
   that a bigger painting is bigger on screen, which needs a number nobody has
   given yet for these. Equal widths and a ceiling on the height is the honest
   placeholder: it says "these are works", not "these are this size". */
.wrap--hang .hang--even .plate { justify-content: center; }
.wrap--hang .hang--even .plate img {
  width: auto;
  max-width: 100%;
  max-height: min(52vh, 30rem);
  margin-inline: auto;
}


/* --- GROUP HEADS AND THE FOLD CONTROL ON THE WORK PAGE -------------------
   A group opens the way every other section on the site opens: heading, then
   one line under it. `.h2` and `.said` are reused rather than re-specified, so
   the scale gains nothing new and the heads stay in step with the rest of the
   page when that scale moves.

   COLOUR IS INHERITED, NOT SET. `.h2` never declares one, and `.said` is
   overridden to currentColor here -- it hardcodes `var(--ink)`, which is not
   redefined on an ink band and would have printed near-black on near-black. */
.group-head {
  text-align: center;
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
  /* More air above than below is wrong for a heading INSIDE a band, which
     already carries its own padding: the band gives the space above, the head
     gives the space down to the work it introduces. */
}
.group-head .h2 { margin: 0; text-wrap: balance; }
.group-head .said {
  color: currentColor;
  margin: clamp(.75rem, 2vw, 1.25rem) auto 0;
  max-width: 34ch;          /* a single line of lede, never a paragraph */
  opacity: .78;             /* recedes from the heading without a second colour */
}

/* A GROUP HEAD ALONE IN A BAND CARRIES NEITHER THE RULE NOR THE GAP (17/09).
   Both were correct while the head sat at the top of the hang: the rule cut it
   from the work below, and the bottom margin was the distance down to the first
   plate. `In colour` now takes a statement band of its own, so there is nothing
   under either of them -- the margin became a strip of moving colour with no
   content in it, and the border a hairline across an empty band at 1.89:1.

   The home page's statement band, which this one is built to match, has no rule
   under its heading for the same reason: nothing follows it inside the band. */
.band--statement .group-head,
.band--statement > .wrap > .section-head:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: 0;
}

/* The fold. Each group shows its first row and holds the rest behind a native
   <details>: no script, every plate still in the DOM, and a page that ran
   42,000px on a phone comes down to a readable length. */
.more-works { margin-top: clamp(2rem, 5vw, 3.5rem); }
.more-works > summary {
  list-style: none;
  cursor: pointer;
  display: block;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  padding: clamp(.9rem, 2.2vw, 1.1rem) clamp(1.75rem, 5vw, 2.75rem);
  border: 1px solid currentColor;
  font: 500 var(--t-nav)/1.4 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: center;
  transition: background-color .25s var(--ease), color .25s var(--ease);
}
.more-works > summary::-webkit-details-marker { display: none; }
/* THE INVERSION IS THE AFFORDANCE. Ground and figure swap on hover, which is
   the one interaction on this site that has to be unmistakable -- everything
   behind it is unreachable if the reader does not press it. */
.band--paper .more-works > summary:hover,
.band--paper .more-works > summary:focus-visible { background: var(--ink); color: var(--paper); }
.band--ink .more-works > summary:hover,
.band--ink .more-works > summary:focus-visible { background: var(--paper); color: var(--ink); }
.more-works[open] > summary { margin-bottom: clamp(2rem, 5vw, 3.5rem); }
/* THESE THREE MUST SAY `> summary`, NEVER A BARE DESCENDANT. The control is
   RECURSIVE -- every `details` holds the next nine works AND, inside itself, the
   control for the nine after that -- so a descendant rule written on the OPEN
   outer one reaches into the SHUT inner one and relabels it too. Opening the
   first block therefore turned every control below it into "Show less", with
   works still hidden behind them: pressing a button that said show less was the
   only way to see more. Nico reported it; found 22/09. */
.more-works > summary .more-works-shut { display: none; }
.more-works[open] > summary .more-works-open { display: none; }
.more-works[open] > summary .more-works-shut { display: inline; }
.more-works .hang:last-of-type { margin-bottom: 0; }


/* --- STICKY MASTHEAD ------------------------------------------------------
   The bar follows the reader instead of scrolling away with the first work.
   On a 131-piece site the navigation was reachable only from the top of the
   page, which on a long gallery means scrolling back through the whole body
   of work to leave it.

   It starts INVISIBLE and materialises on scroll. At rest the page should read
   as one uninterrupted sheet of paper; a permanent bar puts a lid on it. Past
   the first 24px there is content sliding underneath, and the bar has to hold
   its own ground or the wordmark sits on top of a painting.

   NO JAVASCRIPT REQUIRED. The attribute is absent until the script sets it, and
   `:not([data-scrolled="false"])` treats absent as "show the background" — so
   with the script blocked the bar is simply always solid, which is the safe
   state, never the illegible one. The script only buys the transparent rest
   state, and losing it costs an effect, never a reader. */

.masthead-bar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: transparent;
  transition: background var(--reveal) var(--ease),
              box-shadow var(--reveal) var(--ease);
}
/* NO transition on the height. The bar carries a backdrop-filter, which lives on
   its own GPU layer, and animating the box that layer occupies makes the browser
   rasterise the blur at one size and stretch it to the next — which reads as dirty,
   smeared type for the length of the transition. The background and the shadow
   still fade, and neither of those touches layout. */
.masthead-bar .masthead { transition: none; }

.masthead-bar:not([data-scrolled="false"]) {
  /* --paper at 88%: the works show through as movement, not as detail. */
  background: rgba(244, 241, 234, .88);
  -webkit-backdrop-filter: blur(12px) saturate(120%);
          backdrop-filter: blur(12px) saturate(120%);
  box-shadow: 0 1px 0 var(--rule), 0 10px 24px rgba(11, 11, 11, .06);
}
.masthead-bar:not([data-scrolled="false"]) .masthead {
  padding-block: clamp(.75rem, 2vw, 1.125rem);
}

/* A sticky bar hides whatever an in-page link lands on, so every anchor target
   clears its own height. */
html { scroll-padding-top: 6rem; }

@media (prefers-reduced-motion: reduce) {
  .masthead-bar, .masthead-bar .masthead { transition: none; }}




/* ============================================================
   THE REVEAL
   Sections and works rise as they arrive. app-side, base.html puts
   [data-rise] on the bands and [data-stagger] on the hang, then adds
   .in when each one crosses the line.

   EVERY HIDDEN STATE IS GATED ON `html.js`. With the script off none of
   these rules match, the page renders exactly as it did before, fully
   visible, and a crawler sees the whole thing. A reveal that can leave
   content hidden is not a reveal, it is a blank page.

   28px and 720ms are deliberate. Smaller numbers are not "restrained",
   they are invisible — the reader sees nothing happen and the work was
   spent for nothing. Restraint here is in WHERE the motion goes: whole
   sections and the hang, never individual words, never the navigation,
   and never a painting on its own.
   ============================================================ */
:root {
  --rise-y: 28px;
  --rise-t: 720ms;
  --rise-step: 70ms;
}

.js .band, .js .aside-work, .js .split-plate,
.js [data-rise] {
  opacity: 0;
  transform: translate3d(0, var(--rise-y), 0);
  transition: opacity var(--rise-t) var(--ease), transform var(--rise-t) var(--ease);
}
.js [data-rise].in { opacity: 1; transform: none; }

/* The hang arrives piece by piece rather than as a slab. Eight steps is where it
   stops reading as a sequence and starts reading as a wait, so it repeats after
   that instead of growing. */
.js .hang > *,
.js [data-stagger] > * {
  opacity: 0;
  transform: translate3d(0, var(--rise-y), 0);
  transition: opacity var(--rise-t) var(--ease), transform var(--rise-t) var(--ease);
}
.js [data-stagger].in > * { opacity: 1; transform: none; }
.js [data-stagger].in > *:nth-child(8n+1) { transition-delay: 0ms; }
.js [data-stagger].in > *:nth-child(8n+2) { transition-delay: calc(var(--rise-step) * 1); }
.js [data-stagger].in > *:nth-child(8n+3) { transition-delay: calc(var(--rise-step) * 2); }
.js [data-stagger].in > *:nth-child(8n+4) { transition-delay: calc(var(--rise-step) * 3); }
.js [data-stagger].in > *:nth-child(8n+5) { transition-delay: calc(var(--rise-step) * 4); }
.js [data-stagger].in > *:nth-child(8n+6) { transition-delay: calc(var(--rise-step) * 5); }
.js [data-stagger].in > *:nth-child(8n+7) { transition-delay: calc(var(--rise-step) * 6); }
.js [data-stagger].in > *:nth-child(8n+8) { transition-delay: calc(var(--rise-step) * 7); }

@media (prefers-reduced-motion: reduce) {
  .js .band, .js .aside-work, .js .split-plate, .js .hang > *,
  .js [data-rise], .js [data-stagger] > * {
    opacity: 1 !important; transform: none !important;
    transition: none !important; transition-delay: 0ms !important;
  }}



/* ============================================================================
   THE INTEGRATED HERO (second-pass review, 15/09)

   The opening used to be TWO full-bleed bands: a painting at 62svh, then a
   separate statement band underneath carrying the label, the headline and the
   location line. On a laptop the two halves never appeared together -- the
   reader met a cropped painting with no name on it, scrolled past the fold, and
   met a sentence with no painting. They are one composition now.

   60/40. The art takes the larger share because the art is the argument; the
   panel takes enough to set three lines without the headline wrapping to five.

   MIN-HEIGHT, NEVER HEIGHT. The target is 520-580px, and the text decides where
   inside that it lands. A fixed height would have to be solved twice, because
   the Spanish runs longer than the English on nearly every line of this page,
   and solving it once is how a panel ends up with copy overflowing it.
   ========================================================================= */
/* THE PHOTOGRAPH MUST NOT SET THE HERO'S HEIGHT. With the image in normal flow,
   the grid row grows to the image's natural height at its column width -- so a
   PORTRAIT room shot made the commissions hero 1090px tall against a 580px
   target, while the home page's landscape painting happened to land at 559px
   and looked like the rule working. Taking the image out of flow leaves the row
   measured by the text panel and the min-height, which is what the brief asks
   for: "allowing text to determine the actual height". */
/* STACKED, AND STILL ONE SECTION. The two halves sit inside the same <section>
   on a phone, with no band boundary drawn between them -- the review is
   explicit that the stack must not reintroduce the artificial break the desktop
   layout just removed. */

/* THE SECOND ACTION IN A FOOT. The record link sits beside "About the artist"
   as the smaller, secondary item the review asks for -- same role and size, so
   it is not a sixth text treatment, but the quieter ink and no uppercase, so it
   does not read as an equal choice. */
.section-foot .go + .go--quiet { margin-left: 2rem; }
.go--quiet { color: var(--ink-soft); text-transform: none; letter-spacing: .02em; }

/* THE CITY ROW at the foot of Work. A row of links, not a control strip: the
   five city pages are part of the site from here, and the eye should read them
   as a sentence of place names rather than as filters over an inventory. The
   gap is the same 2rem that already separates two links in a section foot. */
.cities { display: flex; flex-wrap: wrap; gap: 1rem 2rem; margin: 0; }
/* Five cities on a phone wrapped four and one, leaving Panama alone on the
   second row -- the same stray-last-word fault in link form (24/09). Three and
   two instead. */
@media (max-width: 40rem) { .cities { display: grid; grid-template-columns: repeat(3, max-content); } }
/* TALL ENOUGH TO HIT, AND FAR ENOUGH APART. Measured at 390px and 360px: the
   row wraps on a phone, and at the old .35rem padding the links were 35px tall
   with 4px between Barcelona and Panama -- half the 8px WCAG 2.5.5 asks between
   neighbouring targets, on the one row whose whole job is being tapped by a
   buyer looking for their own city. The padding fixes both numbers at once. */
.cities a { padding-block: .6rem; }

/* THE PAGE HEAD. A title, one sentence and the links into the page, on a band
   that does not pretend to be a chapter of its own: the review removed the
   hero crop and the statement band above every one of these, so what is left
   introduces the page once and gets out of the way. Same top padding as a major
   section, less underneath, because the content it introduces begins
   immediately below it rather than after a boundary. */
section.band--head { padding-block: clamp(3rem, 5.3vw, 4.5rem) clamp(2rem, 3.5vw, 3rem); }

/* ============================================================================
   THE ARTIST PAGE'S INTRODUCTION (second-pass review, 15/09)

   A photograph of Nico on one side, his name, identity line and biography on
   the other. It replaces four sections: a bleed crop, a statement band, a
   Practice band on a cycling colour, and a profile that introduced his name for
   the first time after three screens of type about him.

   40/60 -- the reverse of the home page's hero, because here the words are the
   subject and the photograph is the evidence. The columns are `start`-aligned
   rather than centred so the biography can run longer than the portrait without
   dragging the picture down the page with it; the review asks specifically that
   the text not be forced into a fixed height.
   ========================================================================= */
.intro-split {
  display: grid;
  grid-template-columns: 40fr 60fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.intro-portrait { margin: 0; }
.intro-portrait img { display: block; width: 100%; height: auto; }
/* The biography's paragraphs are the only thing in this column that is not the
   header group, so the gap above them is the header-to-content gap. */
.intro-text .prose { margin-top: var(--gap-group); }
@media (max-width: 60rem) {
  .intro-split { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  /* THE WORDS COME FIRST ON A PHONE (JP, 17/09). In two columns the portrait
     sits beside the biography and neither leads. Stacked, the picture was on
     top -- so a reader arriving on the artist page met a photograph of a man in
     a studio and had to scroll past it to find out who he is and what the work
     argues. The thesis is the reason a curator keeps reading, and it is now the
     first thing on the page.
     ORDER, NOT A SECOND MARKUP BLOCK. The figure stays first in the document,
     which is what a screen reader follows and what the two-column layout wants;
     only the painted order changes, and only below 60rem. */
  .intro-text { order: -1; }}


.mail-line { margin-top: var(--gap-group); }

/* ============================================================================
   THE ENQUIRY FORM (15/09)

   Set like the rest of the site and not like a form: no boxes with rounded
   corners, no grey fills, no placeholder text standing in for a label. A field
   is a rule with a label over it, which is the same device the record and the
   specifications already use -- the page gains a form without gaining a second
   design language.

   EVERY CONTROL CLEARS 44px. The review's floor is 24px and that is the legal
   minimum; a form is the one place on a site where a missed target costs the
   owner an enquiry, so the targets here are sized for a thumb rather than for
   the audit.
   ========================================================================= */
/* THE FORM IS CENTRED ON THE PAGE'S AXIS (15/09). At 40rem inside a 78rem
   wrap it sat 498px left of centre under two centred header groups, which
   is what read as the page being out of alignment. The FIELDS inside it
   stay left-aligned: a centred label over a full-width input has no edge
   to follow down the form. */
.enquiry { margin-top: var(--gap-group); max-width: 40rem; margin-inline: auto; text-align: left; }
.field { border: 0; padding: 0; margin: 0 0 2rem; }
.field > label, .field legend {
  display: block;
  font-size: var(--t-label);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 var(--gap-label);
  padding: 0;
}
.field-note {
  display: block;
  font-size: var(--t-meta);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  margin: .75rem 0 0;
}
.enquiry input[type="text"],
.enquiry input[type="email"],
.enquiry select,
.enquiry textarea {
  width: 100%;
  font: 400 var(--t-body)/1.6 var(--sans);
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  padding: .75rem 0;
  /* Safari rounds a text input and tints a select on its own; both would be the
     only rounded corners on the site. */
  -webkit-appearance: none;
  appearance: none;
}
.enquiry select {
  /* With the native arrow suppressed the control needs one drawn back, or it
     reads as a text field that will not accept typing. */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
                    linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: right 4px center, right 0 center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 1.5rem;
}
.enquiry textarea { resize: vertical; }
.enquiry input:focus-visible,
.enquiry select:focus-visible,
.enquiry textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* --- THE FORM ON PAPER (JP, 21/09) ----------------------------------------
   The page went white. The boxes stayed, and that was deliberate: JP's
   instruction on 17/09 was "make sure you can see the boxes", and a field a
   reader cannot find is the same fault on any ground. What changes here is
   only which colours draw them.

   AN UNDERLINE IS NOT AN INVITATION. The base rule sets a field as a label
   over a bottom rule, which is right for the record and the specifications --
   they are things to read. A form is a thing to DO, and a reader has to see
   where the typing goes before reading a single label. Four sides and a ground
   one step off the page say that without an instruction on the screen.

   MEASURED, not estimated, against #F4F1EA:
     field ground  ink at 3%          -> #EDEAE3
     border        #8A8479            -> 3.29:1 on paper, 3.09:1 on the field,
                                        clearing the 3:1 WCAG asks of a
                                        control's boundary on both sides of it
     typed text    --ink   #0B0B0B    -> 16.38:1
     placeholder   --ink-soft #5A574F -> 6.00:1, quiet but never decorative
   #8A8479 is not a new colour: it is the rule the cycle band already carries.

   THE TINT IS ink AT 3%, not a named grey, so the treatment stays correct if
   this band is ever put back on a colour. */
.band--form .enquiry input[type="text"],
.band--form .enquiry input[type="email"],
.band--form .enquiry select,
.band--form .enquiry textarea {
  background: rgba(11, 11, 11, .03);
  border: 1px solid #8A8479;
  color: var(--ink);
  padding: .7rem .85rem;
}
.band--form .enquiry select {
  /* The drawn arrow is built from --ink-soft, so it follows the ground without
     being restated here. */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
                    linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: right .85rem center, right .55rem center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 2rem;
}
/* A select's own dropdown is drawn by the OS, not by this stylesheet. Stated
   rather than left to inherit: it is one line and it cannot go wrong. */
.band--form .enquiry select option { color: #141414; background: #FFFFFF; }
.band--form .enquiry ::placeholder { color: var(--ink-soft); opacity: 1; }
.band--form .enquiry input:hover,
.band--form .enquiry select:hover,
.band--form .enquiry textarea:hover { border-color: var(--ink-soft); }
.band--form .enquiry input:focus-visible,
.band--form .enquiry select:focus-visible,
.band--form .enquiry textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* --- ONE BRANCH AT A TIME (JP, 21/09) -------------------------------------
   The form asked an investment range, a delivery month and a readiness score
   of somebody whose answer was "that painting, the one on the page I came
   from". None of the three has an answer for an existing work, and a question
   with no answer is what makes a form feel like a form.

   PURE CSS, because the page still ships no script of its own and a reveal
   that needs one would leave a reader with scripting off staring at a fork
   that goes nowhere.

   GATED ON @supports, WHICH IS THE WHOLE SAFETY. Without `:has()` these rules
   never apply and BOTH branches stay on screen -- longer than intended, and
   completely usable. Written the other way round, a browser that did not
   understand the selector would hide two thirds of the form and keep it
   hidden, and the enquiry would be lost rather than lengthened. */
@supports selector(:has(*)) {
  .enquiry .branch { display: none; }
  .enquiry:has(#p-existing:checked) .only-existing { display: block; }
  .enquiry:has(#p-custom:checked) .only-commission { display: block; }
}

/* MORE ROOM BEFORE THE FIRST FIELD (JP, 17/09). The form opened one group-gap
   under the head; now that the head is a band of its own, that gap sits on top
   of the band's own padding and the two together were still tight, because the
   colour above draws the eye and the first label has to clear it. */
.band--form .enquiry { margin-top: clamp(1rem, 2.5vw, 2rem); }

/* A CHOICE IS A WHOLE LINE, NOT A 13px DOT. The label wraps the input, so the
   text is part of the target: 44px tall and as wide as the words. */
.choices { display: flex; flex-wrap: wrap; gap: .25rem 2rem; }
.choices--stack { flex-direction: column; gap: .25rem; }
.choice {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 2.75rem;
  font-size: var(--t-body);
  line-height: 1.4;
  cursor: pointer;
}
.choice input { width: 1.125rem; height: 1.125rem; accent-color: var(--ink); margin: 0; flex: none; }

/* THE READINESS SCALE. Five radios rather than a range input: a slider has no
   visible value without JavaScript and this page has none. */
.scale { display: flex; gap: .5rem; }
/* THE FIVE BOXES HAVE TO LOOK LIKE FIVE BUTTONS (JP, 21/09). They were drawn
   in `--rule`, the hairline that separates two paragraphs: #CFC9BC measures
   1.46:1 on paper, so the only thing telling a reader these were pressable was
   the digit inside them. A control's boundary wants 3:1, and #8A8479 -- the
   same border the fields above now carry -- measures 3.29:1. The scale reads as
   part of the form instead of as five numbers in a row. */
.scale-step {
  flex: 1 1 0;
  display: flex; align-items: center; justify-content: center;
  min-height: 2.75rem;
  border: 1px solid #8A8479;
  font-size: var(--t-body);
  cursor: pointer;
}
.scale-step:hover { border-color: var(--ink); }
.scale-step input { position: absolute; opacity: 0; pointer-events: none; }
.scale-step:has(input:checked) { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.scale-step:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
.scale-ends {
  display: flex; justify-content: space-between;
  font-size: var(--t-meta); color: var(--ink-soft);
  margin-top: .75rem;
}

.submit {
  font: 500 var(--t-nav)/1.4 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 0;
  padding: 1rem 2rem;
  min-height: 2.75rem;
  cursor: pointer;
}
.submit:hover { background: transparent; color: var(--ink); }
.submit:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* THE ADDRESS UNDER THE FORM SITS ON THE PAGE'S AXIS, not against the left
   edge of a 78rem wrap. The declaration belongs HERE and not beside the
   base `.mail-line` rule: this one comes later in the file and re-declares
   `display`, so a centring rule written up there lost the cascade and the
   address stayed exactly where it was. (15/09) */
.mail-line--under { display: block; width: max-content; max-width: 100%;
                    margin: 2rem auto 0; }

/* THE CONFIRMATION, WITHOUT A LINE OF SCRIPT. Web3Forms redirects back to this
   page at `#sent`; `:target` is what makes that visible. It is display:none
   until then, so a reader who has not sent anything never meets a thank-you. */
.sent { display: none; }
/* ONCE SENT, THE THANK-YOU IS THE WHOLE PAGE (JP, 22/09). The page used to
   show the confirmation ABOVE the heading and the full form again, which read
   as "did it go?". Now the heading and the form step aside and the two lines
   stand alone, centred. The form band is reached with `:has()`; a browser
   without it keeps the form under the thank-you, which is where it was. */
.sent:target {
  display: block; text-align: center;
  max-width: 40rem; margin: 0 auto; padding-block: clamp(2rem, 6vw, 5rem);
}
.sent:target .group-sub { margin-inline: auto; }
.sent:target + .section-head { display: none; }
body:has(.sent:target) .band--form { display: none; }

/* ============================================================================
   THE HERO CLIP (15/09)

   The video and the still occupy the same box. Which one the reader sees is a
   stylesheet decision, not a template one, because there is no way to refuse an
   autoplay from CSS -- so under `prefers-reduced-motion` the clip is taken out
   and the painting is put back, rather than a paused frame being left on screen
   pretending to be a design.

   BOTH ARE `object-fit: cover` AND ABSOLUTELY POSITIONED, so neither can set the
   hero's height. That is the same rule the still already follows and the reason
   a portrait photograph made this hero 1090px tall before it did.
   ========================================================================= */
.hero-video {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center;
}
/* The still is what sets the hero's height -- `.hero-figure img` gives it
   clamp(340px, 56vh, 620px) -- and the clip is laid over it, so a missing or
   slow video can never collapse the band. */
.hero-figure { position: relative; }
/* The still sits under the clip, so the painting is on screen from the first
   paint rather than after the video's first frame decodes. It is not hidden:
   hiding it would mean an empty box for as long as the network takes. */
.hero-still--under { z-index: 0; }
.hero-video { z-index: 1; }
/* NO PLAY BUTTON, EVER (22/09). When an iPhone refuses an autoplay -- Low Power
   Mode refuses every one -- Safari paints its own play button over the clip, and
   the hero reads as broken until it is tapped. The script in base.html starts
   the clip on the first touch anywhere; until then this keeps the painting on
   screen with nothing drawn over it. */
.hero-video::-webkit-media-controls-start-playback-button { display: none !important; -webkit-appearance: none; }
.hero-video::-webkit-media-controls { display: none !important; }
.hero-video::-webkit-media-controls-overlay-play-button,
.hero-video::-webkit-media-controls-play-button,
.hero-video::-webkit-media-controls-panel,
.hero-video::-webkit-media-controls-enclosure { display: none !important; -webkit-appearance: none; opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* THE PAINTING, NOT A FROZEN CLIP. A reader who has asked their system for
     less movement gets the hero the site shipped with for a fortnight, which is
     a finished thing in its own right and not a degraded version of anything. */
  .hero-video { display: none; }}



/* ============================================================================
   THE TWO PRESS ITEMS THAT ARE LINKS (15/09)

   Everything else under "In print" is a screenshot standing in for proof that
   cannot be linked yet. These two can: the El Universal interview and the
   Casapais issue whose cover he painted. So they are bigger, they are
   clickable, and each carries a LINE rather than a URL -- the reason to click,
   not the address. A pasted address on a page whose job is being believed is
   something to squint at.
   ========================================================================= */
/* TWO PRESS ITEMS, AT THUMBNAIL SIZE, UNDER THE RECORD'S PRESS LIST.
   72px is not a new number: it is what `.work-nav-thumb` already uses for the
   previous and next painting, and it is this site's established size for a
   picture that stands in for a page somewhere else. The row reads like one more
   record line with a picture on it, which is what it is. */
.press-thumbs {
  list-style: none; margin: 1.25rem 0 0; padding: 0;
  display: grid; gap: .85rem;
}
.press-thumb {
  display: flex; align-items: center; gap: .9rem;
  text-decoration: none; color: inherit;
  padding-block: .15rem; margin-block: -.15rem;   /* 24px of target, as the film rows get */
}
.press-thumb::after { content: none; }            /* the drawn-rule hover is for text links */
.press-thumb-img { flex: 0 0 72px; width: 72px; height: 54px; display: block; overflow: hidden; }
.press-thumb-img img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.press-thumb-line {
  font-size: var(--t-meta); line-height: 1.5; color: var(--ink-soft);
  text-decoration: underline; text-underline-offset: .22em;
  text-decoration-thickness: 1px; text-decoration-color: var(--rule);
}
.press-thumb:hover .press-thumb-line,
.press-thumb:focus-visible .press-thumb-line { text-decoration-color: currentColor; color: var(--ink); }
@media (min-width: 40rem) { .press-thumbs { grid-template-columns: repeat(2, minmax(0, 1fr)); }}



/* The process terms and steps, no longer in the right half of a split rule. */
/* 38rem, NOT 44rem (15/09). The body was 44rem and the paragraph inside it
   took the site's 38rem measure cap, so the terms sentence and the numbered
   steps under it were two different widths on two different axes. Matching
   the body to the measure makes them one column. */
.process-body { max-width: 38rem; margin-inline: auto; }
.process-body .steps { margin-top: var(--gap-group); max-width: none; }
/* THE TERMS PARAGRAPH SHARES THE STEPS' AXIS. It carried `.prose`'s 34rem
   measure inside a 44rem body and sat flush left, so the sentence started
   on the same line as the numbered steps but ended 160px short of them --
   the one thing in the section that lined up with nothing. (15/09) */
.process-body .prose { max-width: none; }
.prose--fit { text-align: center; }
.prose--fit p { margin-inline: auto; text-wrap: balance; }

/* ---------------------------------------------------------------------------
   THE LAST LINE IS NEVER ONE WORD (JP, 24/09). Everything short -- headings,
   descriptions, captions, notes, labels -- balances its lines, so a two-line
   block is two even lines rather than a full one and a stray word. Running
   text uses `pretty`, which keeps paragraphs natural and only pulls words
   down to stop the last line being a single one. The work title used to be
   exempt (`initial`, so the artist's name could break anywhere); it is not
   any more, because "Interpretacion del terremoto en" / "Venezuela" is exactly
   what this forbids. build.py also joins the last two words of every block
   with a no-break space, for the browsers that ignore these properties.
   --------------------------------------------------------------------------- */
h1, h2, h3, .h2, .h2--name, .display, .lede, .group-sub, .said, .cap-title,
.cap-meta, .work-note, .eyebrow, figcaption, dd, dt { text-wrap: balance; }
p, li, blockquote { text-wrap: pretty; }
.lede, .group-sub, .said, .cap-title, .cap-meta, .work-note { text-wrap: balance; }

/* ---------------------------------------------------------------------------
   THE PROCESS DIAGRAM (encargos, JP 24/09). A line of four stations: a serif
   numeral in a ring, the ring threaded on a hairline, the step underneath in
   the site's running text (.prose p: Inter, body size, 1.6). Across on a
   desktop, down on a phone, where the hairline runs vertically behind the
   rings. Achromatic like everything that is not a painting.
   --------------------------------------------------------------------------- */
.process {
  list-style: none; margin: var(--gap-group) auto 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem;
  max-width: 68rem; position: relative;
}
.process::before {
  content: ""; position: absolute; top: 1.5rem; left: 12.5%; right: 12.5%;
  border-top: 1px solid var(--rule);
}
.process-step { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 1.25rem; }
.process-n {
  width: 3rem; height: 3rem; border-radius: 50%; display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--ink); position: relative;
  font: 400 1.5rem/1 var(--serif); color: var(--ink);
}
.process-step p {
  margin: 0; max-width: 16rem;
  font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; letter-spacing: -.005em;
  color: var(--ink); text-wrap: balance;
}
@media (max-width: 48rem) {
  .process { grid-template-columns: 1fr; gap: 1.75rem; max-width: 30rem; }
  .process::before { top: 1.5rem; bottom: 1.5rem; left: 1.5rem; right: auto; border-top: 0; border-left: 1px solid var(--rule); }
  .process-step { flex-direction: row; align-items: flex-start; text-align: left; gap: 1.25rem; }
  .process-n { flex: none; }
  .process-step p { max-width: none; padding-top: .55rem; text-wrap: pretty; }
}

/* PRIVACY AND COOKIES (01/10). The banner sits on paper at the foot of the
   screen, achromatic like everything that is not a painting. Buttons carry the
   #8A8479 border (3.29:1 on paper -- clears the 3:1 a control needs; --rule does
   not) and a 44px minimum height so a thumb can hit them. Hidden by the
   `hidden` attribute until the script decides to ask. */
.consent {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--paper); color: var(--ink);
  border-top: 1px solid #8A8479;
  padding: 16px max(16px, env(safe-area-inset-left)) calc(16px + env(safe-area-inset-bottom));
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 24px;
  font-size: 15px; line-height: 1.45;
}
.consent[hidden] { display: none; }
.consent-text { margin: 0; max-width: 46rem; text-wrap: pretty; }
.consent-text a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.consent-actions { display: flex; gap: 12px; }
.consent-btn {
  min-height: 44px; padding: 0 20px; font: inherit; cursor: pointer;
  background: transparent; color: var(--ink); border: 1px solid #8A8479; border-radius: 0;
}
.consent-btn--yes { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.consent-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.foot-legal { display: block; margin-top: 6px; }
.foot-legal a { color: inherit; }
.legal { max-width: 44rem; }
.legal-updated { color: var(--ink-soft); margin-top: 0; }
.legal-title { font-size: 1.15rem; margin: 2rem 0 .5rem; }
.legal p a { color: inherit; }


/* --- THE SLIDER (JP, 02/10) ------------------------------------------------
   Commissions page, rooms and murals. A full-width strip of photographs at one
   height, each at its own shape, snapping one at a time. The strip runs to the
   screen edge on the right so the next photograph is visibly waiting; on the
   left it starts on the page's own margin, so the first photograph lines up
   with the heading above it. Colour comes from the band: on ink everything is
   paper, on paper everything is ink, and nothing here names a colour. */
.band--slider .section-head { margin-bottom: clamp(2rem, 4vw, 3.5rem); }
.slider { --edge: max(var(--gutter), calc((100% - 78rem) / 2 + var(--gutter))); }
.slider-track {
  display: flex;
  align-items: flex-start;
  gap: clamp(1rem, 2.4vw, 2.25rem);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding: clamp(1rem, 2vw, 1.75rem) var(--edge);
  scrollbar-width: none;
  cursor: grab;
}
.slider-track::-webkit-scrollbar { display: none; }
.slider-track.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.slider-track.is-dragging .slide img { transition: none; }
.slider-track:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }
.slide {
  flex: none;
  margin: 0;
  scroll-snap-align: center;
}
.slide .shot { display: block; }
.slide img {
  display: block;
  height: clamp(20rem, 70vh, 50rem);
  width: auto;
  max-width: 80vw;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
  transform-origin: 50% 50%;
  transition: transform .7s cubic-bezier(.22, .61, .36, 1), opacity .7s ease, filter .7s ease;
}
/* ONE PHOTOGRAPH IN THE LIGHT (JP, 02/10). The centred one sits at full size and
   full strength; the others step back -- smaller, fainter, a shade darker -- so
   the eye has one place to land. Hovering the centred one lifts it a little
   more, which is the cue that a click opens it. */
.js .slide:not(.is-current) img { transform: scale(.9); opacity: .4; filter: brightness(.8) saturate(.7); }
.js .slide.is-current img { transform: scale(1); }
.js .slide.is-current .shot { cursor: zoom-in; }
@media (hover: hover) {
  .js .slide.is-current .shot:hover img { transform: scale(1.03); }
  .js .slide:not(.is-current) .shot:hover img { opacity: .6; }
}
/* THE CAPTION IN THE WORK TITLES' FACE (JP, 02/10): the serif the paintings'
   names are set in, so a room reads like a plate in a catalogue. */
.slide-cap {
  margin-top: 1rem;
  text-align: center;
  font-family: var(--serif);
  font-size: var(--t-title);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -.01em;
  opacity: 0;
  transition: opacity .6s ease;
}
.slide.is-current .slide-cap { opacity: 1; }
html:not(.js) .slide-cap { opacity: 1; }
.slider-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
}
.slider-count {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.75rem, 1.2rem + 1.4vw, 2.75rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.slider-of { opacity: .5; }
.slider-nav { display: flex; gap: .75rem; }
.slider-btn {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font-size: 1.125rem;
  cursor: pointer;
  transition: background-color .25s ease, color .25s ease, opacity .25s ease;
}
.band--ink .slider-btn:hover:not(:disabled) { background: var(--paper); color: var(--ink); }
.band--paper .slider-btn:hover:not(:disabled) { background: var(--ink); color: var(--paper); }
.slider-btn:disabled { opacity: .3; cursor: default; }
.slider-btn:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
html:not(.js) .slider-bar { display: none; }
@media (prefers-reduced-motion: reduce) {
  .slide img, .slide-cap { transition: none; }
  .js .slide:not(.is-current) img, .js .slide.is-current .shot:hover img { transform: none; }
}


/* --- THE PROCESS, DRAWN (JP, 02/10) ----------------------------------------
   From clients/nico/process-iconography/integration/process.css, minus the
   preview page's own section, heading and intro rules: the site's section
   head and fit paragraph stay as they are. Four across, two on a tablet, one
   on a phone. */
.nico-process-list{margin-top:clamp(2.5rem,5vw,4rem)!important;text-align:center}
.nico-process-step>p{font-family:var(--sans)}
/* Scoped layout for the supplied fragment. Use the site's existing heading/font tokens. */
.nico-process-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:24px;margin:0;padding:0;list-style:none}
.nico-process-step{min-width:0}
.nico-process-icon{display:block;width:100%;height:auto;aspect-ratio:5/7;overflow:visible}
/* ONE AFTER ANOTHER (JP, 02/10). Each drawing plays at 0.4x its supplied
   length (about 1.3s), the next waits for the one before it, and a step's
   number, label and paragraph fade in once its drawing is finished. The
   script sets data-text; without it, or with reduced motion, everything shows. */
.nico-process-icon{--pace:.4}
@media(prefers-reduced-motion:no-preference){
.nico-process-step[data-text]>:not(svg){transition:opacity .35s ease,transform .35s ease}
.nico-process-step[data-text="wait"]>:not(svg){opacity:0;transform:translateY(8px)}
}
.nico-process-number{display:block;font-family:var(--serif,"Instrument Serif",Georgia,serif);font-size:22px;margin:12px 0 8px}
.nico-process-step h3{font-family:var(--serif,"Instrument Serif",Georgia,serif);font-weight:400;font-size:clamp(28px,2.6vw,36px);line-height:1.12;margin:0 0 12px;text-wrap:balance}
.nico-process-step>p{font-size:16px;line-height:1.55;margin:0 auto;max-width:30ch;text-wrap:pretty}
@media(max-width:900px) and (min-width:641px){.nico-process-list{grid-template-columns:repeat(2,minmax(0,1fr));gap:42px}.nico-process-icon{max-width:310px;margin-inline:auto}}
@media(max-width:640px){.nico-process-list{grid-template-columns:1fr;gap:38px}.nico-process-icon{width:min(100%,240px);margin-inline:auto}.nico-process-step h3{font-size:34px}.nico-process-step>p{font-size:17px}}

