/* Director — the design's typeface (assets/fonts/Director/). woff first, otf fallback. */
@font-face {
  font-family: "Director";
  src: url("../fonts/Director/Director-Regular.woff") format("woff"),
       url("../fonts/Director/Director-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Director";
  src: url("../fonts/Director/Director-Light.woff") format("woff"),
       url("../fonts/Director/Director-Light.otf") format("opentype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Director";
  src: url("../fonts/Director/Director-Bold.woff") format("woff"),
       url("../fonts/Director/Director-bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Miranda Sans — display face for name, bio, titles, descriptions
   (assets/fonts/Miranda_Sans/). Static weights: regular/bold + italics. */
@font-face {
  font-family: "Miranda Sans";
  src: url("../fonts/Miranda_Sans/static/MirandaSans-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Miranda Sans";
  src: url("../fonts/Miranda_Sans/static/MirandaSans-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Miranda Sans";
  src: url("../fonts/Miranda_Sans/static/MirandaSans-Italic.ttf") format("truetype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Miranda Sans";
  src: url("../fonts/Miranda_Sans/static/MirandaSans-BoldItalic.ttf") format("truetype");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

:root {
  --color-bg: #fff;
  --color-fg: #000;
  --color-muted: #000;        /* design is pure black; dim via opacity, not grey */
  --color-line: #cfcfcf;      /* thin row rules */
  --font-body: "Director", ui-monospace, "SF Mono", Menlo, monospace;
  --font-display: "Miranda Sans", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --gap: 1.5rem;
  --page-pad: 2rem;
  --color-ochre: #A38973;     /* ochre row-hover highlight */
  --row-cover-width: 300px;   /* hover cover width; other rows' lines sit 20px past it */
  --color-grey: #8a8a8a;      /* bio + project side text */
  --grid-top: 63px;           /* top start height: image grid + project gallery */
  --grid-img-height: 270px;   /* image-grid cover height */
  --title-tracking: 5.76px;   /* letter-spacing on the uppercase project title */

  /* ── Typographic system (monotonic: 12, 12, 10, 10, 10) ──────────────────
     Edit a variable → the heading AND every matching element update.        */
  --h1-family: var(--font-body);      /* name — 12pt Director */
  --h1-size: 12pt;
  --h1-transform: none;
  --h1-tracking: 0;
  --h1-weight: 400;

  --h2-family: var(--font-display);   /* project title — 12pt Miranda */
  --h2-size: 12pt;
  --h2-transform: uppercase;
  --h2-tracking: var(--title-tracking);
  --h2-weight: 400;

  --h3-family: var(--font-display);   /* project title − 2pt — 10pt Miranda */
  --h3-size: 10pt;
  --h3-transform: uppercase;
  --h3-tracking: var(--title-tracking);
  --h3-weight: 400;

  --h4-family: var(--font-body);      /* tags + footer — 10pt Director */
  --h4-size: 10pt;
  --h4-transform: none;               /* preserve capitals as typed */
  --h4-tracking: 0;
  --h4-weight: 400;

  --h5-family: var(--font-display);   /* 8pt Miranda uppercase */
  --h5-size: 8pt;
  --h5-transform: uppercase;
  --h5-tracking: var(--title-tracking);
  --h5-weight: 400;
}


* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.45;
  overflow-x: clip;   /* full-bleed images use 100vw; never show a h-scrollbar */
}

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

body { font-size: 16px; letter-spacing: 0; }

/* Typographic system — headings + their matching named elements, all driven by
   the --hN-* variables above. */
h1, .brand, .col-types {
  font-family: var(--h1-family);
  font-size: var(--h1-size);
  text-transform: var(--h1-transform);
  letter-spacing: var(--h1-tracking);
  font-weight: var(--h1-weight);
}
h2, .col-title, .ph-title, .cap-title {
  font-family: var(--h2-family);
  font-size: var(--h2-size);
  text-transform: var(--h2-transform);
  letter-spacing: var(--h2-tracking);
  font-weight: var(--h2-weight);
}
h3 {
  font-family: var(--h3-family);
  font-size: var(--h3-size);
  text-transform: var(--h3-transform);
  letter-spacing: var(--h3-tracking);
  font-weight: var(--h3-weight);
}
h4, .cap-tags, .site-footer {
  font-family: var(--h4-family);
  font-size: var(--h4-size);
  text-transform: var(--h4-transform);
  letter-spacing: var(--h4-tracking);
  font-weight: var(--h4-weight);
}
h5 {
  font-family: var(--h5-family);
  font-size: var(--h5-size);
  text-transform: var(--h5-transform);
  letter-spacing: var(--h5-tracking);
  font-weight: var(--h5-weight);
}

/* NAME — on home/design it lives in the header row (.controls-bar), so the
   standalone fixed copy is hidden there; project pages keep the fixed copy. */
.site-name {
  position: fixed;
  top: 14px;
  left: 12px;
  z-index: 30;
  line-height: 1;   /* match the controls-bar so the name sits at the same height */
}
body:has(.controls-bar) .site-name { display: none; }

.brand {
  color: inherit;   /* font comes from the h1 type rule */
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
  line-height: 1;   /* home name is a <button>; without this its UA line-height
                       shifts the baseline vs the <a> on project/paintings pages */
}

/* emoticon after the name — hidden with visibility (not display) so toggling it
   off keeps its space and never shifts the header layout */
.name-emoticon.is-hidden { visibility: hidden; }

/* BIO — fixed left block. Vertically centered to the viewport using its own
   hug-height (top:50% + translateY centers regardless of height). JS enforces a
   floor: if centering would raise the top above 113px, it pins to 113px and the
   text flows downward from there (see placeSideText in app.js). */
.site-bio {
  position: fixed;
  left: 24px;
  top: 50%;
  transform: translateY(-50%);
  width: 225px;
  z-index: 30;
  line-height: 1.3;
  font-size: 10pt;   /* Director (inherited), 10pt */
  color: var(--color-grey);
  mix-blend-mode: difference;   /* grey source → grey on white, inverts over images */
  scrollbar-width: none;        /* Firefox: hide scrollbar (still scrollable) */
}
.site-bio::-webkit-scrollbar { display: none; }   /* WebKit: hide scrollbar */

/* when pinned & scrollable, fade the clipped edge(s) to transparent. JS sets
   --fade-top / --fade-bottom to the fade size only when there's more text to
   scroll in that direction (0 at the very top / very bottom). */
.site-bio.is-clipped {
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0, #000 var(--fade-top, 0px),
    #000 calc(100% - var(--fade-bottom, 0px)), transparent 100%);
          mask-image: linear-gradient(to bottom,
    transparent 0, #000 var(--fade-top, 0px),
    #000 calc(100% - var(--fade-bottom, 0px)), transparent 100%);
}
.site-bio p { margin: 0 0 0.85rem; }
.site-bio p:last-child { margin-bottom: 0; }
.site-bio a { text-decoration: none; }
.site-bio a:hover { text-decoration: underline; }
/* the sound link (#sound) is underlined while activated (aria-pressed) — and,
   like other bio links, on hover (handled by the .site-bio a:hover rule above) */
.site-bio a[href="#sound"][aria-pressed="true"] { text-decoration: underline; }

/* Blocks typography (bio + project text). Tuned for the narrow side column.
   These styles carry over anywhere the .site-bio block set is rendered. */
/* headings in the bio/text blocks take their font from the global type system;
   here we only add block spacing */
.site-bio h1,
.site-bio h2,
.site-bio h3,
.site-bio h4,
.site-bio h5,
.site-bio h6 {
  line-height: 1.2;
  margin: 1.1rem 0 0.35rem;
}
.site-bio > :first-child { margin-top: 0; }

.site-bio ul,
.site-bio ol { margin: 0 0 0.85rem; padding-left: 1.2rem; }
.site-bio li { margin: 0 0 0.15rem; }

.site-bio blockquote {
  margin: 0 0 0.85rem;
  padding-left: 0.75rem;
  border-left: 1px solid currentColor;
}

.site-bio hr {
  border: none;
  border-top: 1px solid currentColor;
  opacity: 0.4;
  margin: 1rem 0;
}

/* custom blocks */
.block-indent { padding-left: 1.6rem; margin: 0 0 0.85rem; }
.block-caption { font-size: 0.8em; opacity: 0.55; margin: 0 0 0.85rem; }

/* about tooltip — follows the cursor on hover (position set by JS), ignored on touch */
.about-tip {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 70;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
  font-family: var(--font-body);   /* Director */
  font-size: 10pt;
  color: #fff;
  background: var(--color-ochre);  /* ochre highlight */
  padding: 0.1rem 0.3rem;
}

.about-tip.is-active {
  opacity: 1;
  visibility: visible;
}

/* header row — name · sort · filter · view options, pinned to the top.
   Flexible: the four items are spread with equal spacing between them and
   scale with the viewport. */
.controls-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  line-height: 1;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  padding: 14px 12px;
}

/* Fixed widths sized to the EXPANDED state, so neither control ever changes
   size between closed/open — the flex row never reflows and "sort by" / "filter"
   stay left-anchored in both states. flex-shrink:0 keeps the widths on wide
   screens (narrow screens handled later in the responsive pass). */
.controls-bar .sort-control {
  flex: 0 0 auto;
  width: 16rem;              /* fits "sort by year, AtoZ, kind" */
  justify-content: flex-start;
}
.controls-bar .filter-control {
  flex: 0 0 auto;
  width: 32rem;              /* "filter (N)" + gap + the 400px dropdown, reserved */
}

/* compact-header toggle: hidden on desktop; the menu wrapper is display:contents
   so on desktop its children (sort/filter/view) are direct flex items of the
   header, exactly as before. Both flip in the <900px media query. */
.menu-toggle {
  display: none;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}
.menu-toggle::before { content: "\2261"; }                       /* ≡ */
.controls-bar.is-menu-open .menu-toggle::before { content: "\00d7"; }  /* × */
.controls-menu { display: contents; }

/* studiolin-style difference blend on the header + side text: rendered white and
   inverted against whatever sits behind it — black over the white page, inverted
   over the list/images that scroll beneath. No `isolation: isolate` anywhere, so
   the blend keeps the page as its backdrop (that's what makes it show up). */
.controls-bar,
.project-header,
.site-name {
  mix-blend-mode: difference;
  color: #fff;
}

/* bottom sticky bar — same padding as the top header, grey text (h4), a hairline
   along the top, items bottom-aligned so the © sits on the date's line */
.site-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 20;
  line-height: 1.3;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  padding: 14px 12px;
  color: var(--color-grey);
}

/* project page header — › TITLE (just after the name) · year (centre) · category (right) */
.project-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 40px;
  z-index: 20;
  line-height: 1;
}
.ph-crumb { position: absolute; left: 313px; top: 14px; }
.ph-year  { position: absolute; right: 12px;  top: 14px; }  /* right, where category was */
.ph-title {
  margin-left: 60px;   /* gap between the ">" and the project title */
  text-transform: uppercase;
  letter-spacing: var(--title-tracking);
}

/* filter — hover-reveal. Header reads "filter +" (closed & empty) or
   "filter (N)"; the option list opens inline to the right. */
.filter-control {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;           /* kerning between "filter (N)" and the dropdown */
}
.filter-toggle { flex: 0 0 auto; }

.filter-toggle {
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
  color: inherit;
  white-space: nowrap;
}

/* "+" shows only while closed AND nothing selected; otherwise "(N)" shows
   (including while the menu is open) */
.filter-count { display: none; }
.filter-control.has-filters .filter-plus,
.filter-control:hover .filter-plus,
.filter-control:focus-within .filter-plus,
.filter-control.is-open .filter-plus { display: none; }
.filter-control.has-filters .filter-count,
.filter-control:hover .filter-count,
.filter-control:focus-within .filter-count,
.filter-control.is-open .filter-count { display: inline; }

/* option list — an in-flow flex child right after "filter (N)" (so its spacing
   is the .filter-control gap, and it lives inside the control's fixed width).
   Wraps within 400px; the extra lines overflow downward. */
.filter-dropdown {
  display: none;
  flex: 0 0 auto;
  align-self: baseline;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 1px 6px;
  width: 450px;
  z-index: 40;
}

/* open on hover (or the touch toggle) only — NOT focus-within, so that after
   clicking an option the menu closes as soon as the cursor leaves, rather than
   staying open because the clicked option still holds focus */
.filter-control:hover .filter-dropdown,
.filter-control.is-open .filter-dropdown {
  display: flex;
}

/* option: unselected dim to 20%, selected solid + underlined (word only) */
.filter-option {
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
  color: inherit;
  white-space: nowrap;
  opacity: 0.2;
}
.filter-option[aria-pressed="true"] { opacity: 1; }
.filter-option[aria-pressed="true"] .opt { text-decoration: underline; }
.filter-option:hover { opacity: 1; }
.filter-option:hover .opt { text-decoration: underline; }
.filter-option:not(:last-child)::after { content: ","; }
/* the painting option carries an arrow link, so its comma is rendered after
   the arrow instead (in the snippet) — suppress the auto one here */
.filter-option.no-comma::after { content: none; }

/* arrow link to the Paintings page, sits right after the "painting" option */
.filter-link {
  margin-left: 0.15em;
  text-decoration: none;
  cursor: pointer;
  opacity: 0.2;   /* dim like a deselected filter option */
}
.filter-link:hover { opacity: 1; text-decoration: underline; }

/* the painting option's trailing comma is rendered after the arrow (not on the
   option), so dim it like a deselected option; brighten when painting is on */
.filter-comma { opacity: 0.2; }
.filter-option.no-comma[aria-pressed="true"] ~ .filter-comma { opacity: 1; }

/* sort control — inline hover-expand menu.
   Collapsed: "sort by year" — only the selected option.
   Expanded (hover/focus): "sort by year, AtoZ, kind" — selected first + solid +
   underlined; the rest dim to 20%, comma-separated. */
.sort-control {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
}

.sort-by { margin-right: 10px; }

/* "about" (bio toggle) + sort kept adjacent as one flex item, so the header's
   space-between doesn't split them. Reads "about, sort by …". */
/* "about" (bio toggle) + sort. On desktop the group is display:contents, so
   about and sort are separate flex items distributed by the header's
   space-between. On mobile JS moves the group into the archive where it becomes a
   flex box (media query) and reads "about, sort by" with a comma. */
.sort-group { display: contents; }
.about-toggle {
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
  color: inherit;
  white-space: nowrap;
}
/* underlined while the bio is shown (aria-pressed) or on hover */
.about-toggle[aria-pressed="true"] .opt,
.about-toggle:hover .opt { text-decoration: underline; }
/* "about" off → hide the bio */
body.bio-hidden .site-bio { display: none; }

.sort-list {
  display: inline-flex;
  align-items: baseline;
}

.sort-option {
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
  color: inherit;
  white-space: nowrap;
  opacity: 0.2;             /* non-selected dimmed */
}

.sort-option[aria-pressed="true"] { opacity: 1; }
.sort-option[aria-pressed="true"] .opt { text-decoration: underline; }

/* hover state: any option the cursor is over lifts to full opacity + underline */
.sort-option:hover { opacity: 1; }
.sort-option:hover .opt { text-decoration: underline; }

/* comma AFTER each option except the last (visual order = DOM order; the selected
   is moved to the front in JS). It sits on the button, so it's never underlined —
   only .opt is. */
.sort-option:not(:last-child)::after { content: ",\00a0"; }

/* collapsed: show only the selected option (no brackets) */
.sort-control:not(:hover):not(:focus-within):not(.is-open) .sort-option:not([aria-pressed="true"]) {
  display: none;
}
/* clicking an option force-closes the menu even while still hovering
   (cleared on mouseleave so the next hover re-opens it) */
.sort-control.just-picked .sort-option:not([aria-pressed="true"]) {
  display: none;
}
/* closed state shows only the selected option — drop its trailing comma
   (the "isLast" variant) */
.sort-control:not(:hover):not(:focus-within):not(.is-open) .sort-option::after,
.sort-control.just-picked .sort-option::after {
  content: none;
}

/* view options — "list, image", the active word underlined (not the comma) */
.view-toggle {
  display: flex;
}

.view-toggle button {
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
  color: inherit;
  padding: 0;
}

/* comma is on the button, so it never inherits the .opt underline */
.view-toggle button:not(:last-child)::after { content: ",\00a0"; }

.view-toggle button[aria-pressed="true"] .opt,
.view-toggle button:hover .opt {
  text-decoration: underline;
}

/* list mode — full-width hairline rules; content indented into the right area,
   clearing the fixed bio column on the left. */
.project-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.project-list li { position: relative; }
/* row hairline — top line only, inset on the left, extended out to just past
   the bio column (kept right of the bio so it doesn't cross the bio text) */
.project-list li::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(var(--row-cover-width) + 20px);   /* 20px past the image's right edge */
  right: 0;
  border-top: 1px solid var(--color-line);
}

/* columns: [left indent] year · TITLE; · types · icon */
.project-list a {
  display: grid;
  grid-template-columns: 25rem 3.5rem 24rem 1fr 1.75rem;
  gap: 1.5rem;
  align-items: start;    /* top-align; types can wrap to a 2nd line */
  min-height: 29px;
  /* small top padding keeps the row's top line close to the text; larger
     bottom padding gives the gap before the next row's line; right padding
     pulls the icon in from the edge */
  padding: 4px 56px 22px 0;
}

.project-list .col-year  { grid-column: 2; white-space: nowrap; }
.project-list .col-title { grid-column: 3; }
.project-list .col-types { grid-column: 4; }
.project-list .col-icon  { grid-column: 5; display: flex; justify-content: center; }

/* uppercase, widely tracked project title, with a trailing semicolon */
.project-list .col-title {
  text-transform: uppercase;
  letter-spacing: var(--title-tracking);
}

/* types — own column, lowercase, comma-separated, wraps within the column */
.project-list .col-types {
  text-transform: lowercase;
  line-height: 1.3;
}

.type-icon {
  display: inline-block;
  line-height: 1;
}

/* ── alternate hover: the row's top line extends full-left, the cover drops down
   from it on the left (bio kept), and year/title/tags get an ochre highlight ── */

/* line extends all the way to the left */
.project-list li:hover::before { left: 0; }

/* cover image drops down from the row's line, fixed width, flush to the left */
.row-cover {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--row-cover-width);
  height: auto;
  display: none;
  z-index: 31;          /* above the bio; adjustable */
  pointer-events: none;
}
.project-list li:hover .row-cover { display: block; }

/* ochre highlight over the row's year / title / tags on hover. fit-content keeps
   the box tight to the text; box-shadow paints the ochre "padding" outward
   without pushing the layout (so hovering never shifts the text). */
.project-item:hover .col-year,
.project-item:hover .col-title,
.project-item:hover .col-types {
  width: fit-content;
  background: var(--color-ochre);
  box-shadow: 0 0 0 0.25em var(--color-ochre);
  color: #fff;
}

/* grid mode — centered, wrapping grid that scrolls vertically. 220px margins on
   each side; every image is 350px tall, width follows its ratio; rows centered. */
.project-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;   /* centre each row */
  align-content: flex-start;
  gap: var(--gap);
  padding: var(--page-pad) 150px;   /* 150px side margins */
}

.project-grid figure {
  margin: 0;
  flex: 0 0 auto;            /* natural width, never shrink */
}
.project-grid a { display: block; }

.project-grid img,
.project-grid .grid-cover {              /* .grid-cover = a video cover */
  height: var(--grid-img-height);   /* fixed image height */
  width: auto;         /* width follows the image's own ratio */
  display: block;
  background: var(--color-bg);   /* pure white behind transparent/loading images */
}

/* caption under each cover: PROJECT TITLE (uppercase, tracked) then
   "YEAR; Type, Type" — left-aligned, wraps within the image width.
   width:0 + min-width:100% keeps the caption from stretching the figure wider
   than the image, so long type lists wrap at the image's right edge instead. */
.project-grid figcaption {
  margin-top: 0.9rem;
  text-align: left;
  line-height: 1.35;
  width: 0;
  min-width: 100%;
  overflow-wrap: break-word;
}
/* line 1: "TITLE, YYYY" at 12pt — title Miranda (uppercase, tracked), year Director */
.project-grid figcaption { font-size: 12pt; }
.project-grid .cap-title { display: inline; }   /* font from the h2 type rule */
.project-grid .cap-year { font-family: var(--font-body); }
/* line 2: "(tag, tag, tag)" at 8pt Director */
.project-grid .cap-tags {
  display: block;
  margin-top: 1px;   /* ~2px tighter than before */
  /* font/size/transform come from the h4 type rule */
}

/* hovered cover: ochre rectangle over the whole "TITLE, YEAR" line (mimics the
   list hover). The geometry (padding) is applied ALWAYS with a matching negative
   side-margin, so hover only adds colour and nothing shifts. box-decoration-break:
   clone gives each wrapped line its own even box — so a two-line title extends to
   the left on EVERY line (plain box-shadow didn't on soft-wrap lines), and the
   comma between title and year is inside the box, so it's highlighted too.
   figure:hover covers BOTH the homepage grid (caption inside the <a>) and the
   paintings grid (caption beside the button); .paintings-grid is a .project-grid. */
.project-grid .cap-line {
  padding: 0.15em 0.25em;
  margin: 0 -0.25em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.project-grid figure:hover .cap-line {
  background: var(--color-ochre);
  color: #fff;
}

.empty-note { color: var(--color-grey); }

/* paintings grid caption: title/year use the shared grid rules above; the
   medium + size tail (cap-rest) sits on its own line under the title in the same
   small font as the home-grid tag line (h4: 10pt Director). */
.paintings-grid .cap-rest {
  display: block;
  margin-top: 1px;   /* match .cap-tags */
  font-family: var(--h4-family);
  font-size: var(--h4-size);
  text-transform: var(--h4-transform);
}
/* keep the size (e.g. "24 × 60 in") whole — never break it mid-value */
.paintings-grid .cap-size { white-space: nowrap; }

/* each painting image is a button that opens the slideshow */
.painting-open {
  display: block;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  width: 100%;
}
.painting-open img { display: block; }

/* SLIDESHOW view (not an overlay): swapped in when the view toggle = slideshow.
   Large painting centred, arrows flanking it, metadata in a fixed left column
   at the same placement as the homepage bio. */
.paintings-slideshow { display: none; }
.archive.is-slideshow .paintings-grid { display: none; }
/* slideshow uses the left column for the painting's metadata, so hide the bio
   (it's a sibling of .archive, hence :has on the body) */
body:has(.archive.is-slideshow) .site-bio { display: none; }
/* fixed, solid-white layer under the header — no reflow/scroll-jump when it
   opens, and a stable white backdrop for the header's blend (fixes the flicker) */
.archive.is-slideshow .paintings-slideshow {
  position: fixed;
  inset: 0;
  z-index: 10;                 /* below the header (20), meta (30), arrows (31) */
  background: var(--color-bg); /* pure white, solid */
  display: flex;
  align-items: center;
  justify-content: center;     /* image always centred in the viewport */
}

.slide-img {
  max-width: 60vw;
  max-height: 78vh;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* metadata — single column at the bio placement; fixed, so it overlays without
   pushing the centred image */
.slide-meta {
  position: fixed;
  left: 24px;
  top: 113px;
  width: 225px;
  z-index: 30;
  font-family: var(--font-body);   /* Director */
  font-size: 10pt;
  color: var(--color-grey);
  line-height: 1.5;
}
.slide-meta span { display: block; }

/* arrows — fixed (static) so they never move with the image */
.slideshow-prev,
.slideshow-next {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #000;
  cursor: pointer;
  font: inherit;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0.5rem;
  z-index: 31;
}
.slideshow-prev { left: 2rem; }
.slideshow-next { right: 2rem; }

.is-grid .project-list,
.is-list .project-grid { display: none; }

/* clear the fixed header row so the list starts below it */
.archive { padding-top: 176px; padding-bottom: 4rem; }   /* clear the fixed footer */
/* image view starts higher than the list */
.archive.is-grid { padding-top: var(--grid-top); }

/* ── 900px: bio un-fixes and stacks above the list ─────────────────────────
   Below this width the fixed left bio + the list's left indent stop making
   sense, so the bio flows in-document above the archive and the list reclaims
   the full width. */
@media (max-width: 900px) {
  /* bio flows in-document ABOVE the archive (the fixed left bio + list indent
     don't make sense at this width) */
  .site-bio {
    position: static;
    top: auto;
    transform: none;            /* cancel the desktop vertical-centering transform */
    width: auto;
    max-width: 40rem;
    margin: 3.5rem 0 2rem;      /* top clears the fixed header; bottom = gap before list */
    padding: 0 12px;            /* 12px left (and right) indent */
    mix-blend-mode: normal;     /* in-flow over white — no blend needed */
    color: var(--color-grey);
  }

  /* the bio provides the top clearance, so the archive doesn't */
  .archive,
  .archive.is-grid { padding-top: 0; }

  /* project pages: hide the desktop title/year bar; the project name leads the
     side text instead (extra specificity so it beats the base display:none that
     sits later in the file) */
  .project-header { display: none; }
  .site-bio .bio-project-title { display: block; }

  /* footer: no longer sticky — a plain block at the bottom of the page, with the
     copyright stacked on its own line below the "Last edited / date" */
  .site-footer {
    position: static;
    display: block;
    align-items: initial;
    padding: 2rem 12px;
  }
  .site-footer .footer-left,
  .site-footer .footer-right { display: block; }
  .site-footer .footer-year { display: none; }   /* copyright without the year on mobile */
  /* "Last edited, date" on one line (comma instead of the desktop line break).
     Extra specificity so it beats the base ".le-comma { display:none }" later
     in the file. */
  .site-footer .footer-left .le-comma { display: inline; }
  .footer-left .le-br { display: none; }

  /* project pages: swap "↑ Top" for "← Back to archive" (extra specificity so it
     beats the base ".back-archive { display:none }" that sits later in the file) */
  .scroll-top-wrap .scroll-top { display: none; }
  .scroll-top-wrap .back-archive { display: inline; }

  /* per-block "Hide on mobile" toggle (set in the side-text block editor) */
  .site-bio .hide-mobile { display: none; }

  /* mobile header: just name + sort — no filter, no view toggle, no hamburger */
  .menu-toggle,
  .filter-control,
  .view-toggle { display: none; }
  .controls-menu { display: flex; }           /* sort shows inline (top-right) */
  .controls-bar .sort-control { width: auto; min-width: 0; }

  /* mobile sort: closed by default (only the selected option, via the desktop
     collapse rule); tap "sort by" to open (.is-open) and the options stack
     vertically under the selected one, e.g.
       sort by year
               AtoZ
               kind
     Picking an option closes it again. JS keeps the selected option first. */
  .sort-list { flex-direction: column; align-items: flex-start; }
  .sort-list .sort-option::after { content: none; }   /* no commas when stacked */

  /* JS moves the about+sort group into the archive (below the bio); left-align it
     with the image grid (12px) and add a gap before the images start */
  .archive > .sort-group {
    display: flex;
    align-items: flex-start;   /* keep "about" at the top when sort is expanded */
    margin: 0 12px 1.5rem;
  }
  .about-toggle::after { content: ",\00a0"; }   /* "about, sort by" when grouped */
  /* when the bio is hidden the group would ride up under the fixed name — pad the
     archive so it collapses to just below the name */
  body.bio-hidden .archive,
  body.bio-hidden .archive.is-grid { padding-top: 3.5rem; }

  /* grid only (list removed), single centered column */
  .archive .project-list { display: none; }
  .archive .project-grid {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 12px 2rem;
  }
  .project-grid figure { width: 100%; max-width: 40rem; }
  .project-grid img,
  .project-grid .grid-cover { width: 100%; height: auto; }

  /* paintings: no slideshow on mobile — always the grid, with the full
     metadata (medium + size) reincluded under each painting */
  .archive.is-slideshow .paintings-slideshow { display: none; }
  .archive.is-slideshow .paintings-grid { display: flex; }
  .paintings-grid .cap-rest { display: block; margin-top: 0.15rem; }
}


/* CV sections, built into the page rather than a separate route */
.cv-section {
  padding: var(--page-pad);
  border-top: 1px solid var(--color-line);
  white-space: pre-line;
  font-size: 0.9rem;
  max-width: 40em;
}

/* project detail page — 1200px column, centred in the viewport */
.project-detail {
  /* top matches the image grid's start height exactly: the grid sits at
     --grid-top plus the grid's own --page-pad, so mirror that here. No side
     padding so images can reach 1200px. */
  padding: calc(var(--grid-top) + var(--page-pad)) 0 4rem;   /* bottom clears the footer */
  max-width: 1200px;
  margin: 0 auto;      /* centre the column */
}
/* "Start at the top" toggle: drop the top spacing so a full-width first image
   begins at the very top of the viewport (behind the fixed header) */
.project-detail.flush-top { padding-top: 0; }

/* Plain BLOCK flow — no flexbox, so max-height/max-width behave predictably
   (flex items have min-*:auto floors that silently override max-*). Each image:
   - max-height 690px  → never taller than 690 (the priority)
   - max-width 100%    → never wider than the 1200px column, so it can't overflow
   - width/height auto → ratio always preserved, never stretched
   Because nothing overflows the column, margin:0 auto centres EVERY image, wide
   ones included (they cap to 1200 wide with a reduced height). */
.project-detail .gallery img,
.project-detail .gallery video {
  display: block;
  max-height: 690px;
  max-width: 100%;
  width: auto;
  height: auto;
  margin: 0 auto var(--gap);
}

/* per-item "Full width" toggle: span the whole viewport width, breaking out of
   the centered 1200px column (margin trick) */
.project-detail .gallery img.full-width,
.project-detail .gallery video.full-width {
  max-width: none;
  max-height: none;
  width: 100vw;
  margin: 0 calc(50% - 50vw) var(--gap);
}


.footer-left .le-comma { display: none; }   /* desktop uses the line break */

/* bottom action: "↑ Top" (desktop) / "← Back to archive" (mobile). Same look. */
.scroll-top-wrap { text-align: center; }   /* centre the button on the page */
.scroll-top,
.back-archive {
  font: inherit;
  font-size: 0.85rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-muted);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
}
.back-archive { display: none; }   /* desktop shows the scroll-top instead */

/* underline on hover, like the list / image toggle */
.scroll-top:hover,
.back-archive:hover {
  color: var(--color-fg);
  text-decoration: underline;
}

/* the project name at the top of the side text (font from the global h2 rule =
   the old header title style: Miranda, uppercase, tracked) */
/* the project name in the side text is MOBILE only; on desktop the fixed
   .project-header carries the title + year instead */
.bio-project-title { display: none; margin-bottom: 0.85rem; }

