/* 2200 — how the page looks. The fonts are in fonts.css.

   Tokens · Base · Menu and footer · Colour switch · Top of the page · Sections ·
   Big pictures · Fact lists · Residencies · Round buttons · Photo strips · Lists · Artists ·
   Get in touch · Buttons · Popups · Imprint and privacy · Picture viewer · Caption bubble ·
   Smaller screens */

/* ==========================================================================
   Tokens
   ========================================================================== */
:root {
  --paper: #FFFFFF;
  --ink: #0D0D0D;                   /* a hair softer than black (and the dark colours' background) */
  --grey: #666666;
  --line: #D6D6D6;
  --frame: #F0F0EF;
  --backdrop: rgba(255, 255, 255, 0.86);   /* the page behind a popup */
  --head: "Sparco", "Arial Black", "Helvetica Neue", Arial, sans-serif;
  --text: "Editorial New", "Times New Roman", Georgia, serif;

  /* Type. Editorial: --e1 (text) and --e2 (opening text, popups). Nothing else.
     Sparco: --s-label (smaller than the text), --s-head (twice the text), --disp (big):
     9.6 % of the page's width, 119px at most (worked out from the screen's width here,
     for browsers without container units; see @supports below). */
  --e1: 19px;
  --e2: 44px;
  --s-label: 11px;
  --s-head: 40px;
  --disp: min(calc((min(100vw, var(--max) + 2 * var(--gutter)) - 2 * var(--gutter)) * 0.096), 120px);

  /* Spacing: every distance on the page is one of these five, each twice the one before
     (8 / 16 / 32 / 64 / 128 on a computer, 6 / 12 / 24 / 48 / 96 on a phone), or the page
     margin. They are measured between what you see — from a line, a frame or a baseline to
     the top of the capitals — not between boxes.
       --g0  inside the small pills: above and below their text, the dot and the text
       --g1  a line and the label under it, a label and what it names, rows of a list,
             inside buttons and caption bubbles, between photos, between buttons
       --g2  around big type, a black line and the first row of a list, a heading and its
             text, paragraphs, between columns (--col), inside popups
       --g3  between parts of a section
       --g4  between sections and between the residencies
     --gutter  the page margin: left and right of everything, and above the 2200 (between
               the photos of a slider on a phone: a quarter more)
     In between, on purpose: the menu bar (--g1 + --g0 above and below its words) and the
     picture viewer (half the page margin around the photo).
     Small things (buttons, pills, bubbles) stay compact; the airiness is between the parts. */
  --g1: clamp(12px, 8px + 0.6vw, 16px);
  --g0: calc(var(--g1) / 2);
  --g2: calc(var(--g1) * 2);
  --g3: calc(var(--g1) * 4);
  --g4: calc(var(--g1) * 8);
  --col: var(--g2);
  --gutter: clamp(16px, 4vw, 48px);
  /* the page margin, but never under the camera of a phone held sideways */
  --gutter-l: max(var(--gutter), env(safe-area-inset-left, 0px));
  --gutter-r: max(var(--gutter), env(safe-area-inset-right, 0px));

  --max: 1240px;                    /* the page's width inside its margins */
  --measure: 56ch;                  /* the longest line of text */
  --gallery-h: clamp(240px, 40vw, 560px);
  --radius: 16px;                   /* popups and caption bubbles */
  --hit: 14px;                      /* invisible room around small buttons, so they are easy to hit */
}
@supports (width: 1cqi) {
  :root { --disp: min(9.6cqi, 120px); }
}

/* Dark scheme: the same page with background, text and icons inverted, once the visitor
   chooses it with the switch in the menu (a juror in their page's menu). Light until then,
   whatever their system's setting (1.18.25, as you asked on 3 Nov; until then it followed
   that). My panel in the back office too since 1.18.28 (from 1.18.25 it followed the system,
   html.sys): dark there with the back office's switch. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #0D0D0D;                 /* near black: no smear on OLED screens when scrolling */
  --ink: #EBEBEB;                   /* soft white: no glow around the letters */
  --grey: #999999;
  --line: #303030;
  --frame: #1C1C1C;
  --backdrop: rgba(13, 13, 13, 0.86);
}
@media (max-width: 900px) {
  :root { --e1: 18px; --e2: 28px; --s-head: 34px; }
}

/* ==========================================================================
   Base
   ========================================================================== */
* { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;          /* with a visible scrollbar (Windows), nothing shifts when it's locked */
  scroll-padding-top: calc(var(--bar-h, 64px) + var(--g2));   /* a link from elsewhere to #flims doesn't land under the menu (--bar-h: set by the script) */
}
/* While a dialog is open the page doesn't scroll (set by the script). Only the page itself:
   the menu bar stays put. */
html.locked { overflow: hidden; overscroll-behavior: none; }
body {
  margin: 0;
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--text);
  font-weight: 200;
  font-size: var(--e1);
  line-height: 1.42;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; }
[hidden] { display: none !important; }
h1, h2, h3, h4, p, dl, dd, ol, figure { margin: 0; }
a { color: inherit; text-underline-offset: 4px; text-decoration-thickness: 1px; }
button { color: var(--ink); background: var(--paper); cursor: pointer; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
[tabindex="-1"]:focus { outline: none; }   /* where the script puts the focus (popup texts, headings, the viewer) */
/* For screen readers only */
.vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

h1, h2, h3, h4, .label, .status, nav, button, .btn, .s-head, .s-display {
  font-family: var(--head);
  font-weight: 400;
  text-transform: uppercase;
}
.label, .status, nav, button, .btn {
  font-size: var(--s-label);
  letter-spacing: 0.08em;
  line-height: 1.3;
}
.label { color: var(--grey); }
h2, h4, .s-head { font-size: var(--s-head); line-height: 1.05; }
.s-display { font-size: var(--disp); line-height: 0.92; }
.lede, .pop-q { font-size: var(--e2); line-height: 1.12; }

/* Every text block ends at the top of its capitals and at its baseline, so the
   distances above and below are the ones you see, and text next to a line starts
   level with it. */
h2, h4, p, dt, .spec dd, .label, .s-head, .s-display,
figcaption > span, .idx > span:not(.status) {
  text-box: trim-both cap alphabetic;
}
/* Browsers without that (Firefox, Safari before 18.2): the same, worked out from the
   fonts' line metrics set in @font-face above */
@supports not (text-box: trim-both cap alphabetic) {
  p, .spec dd, figcaption > span:not(.label), .idx > span:not(.status) { margin-top: -0.2em; margin-bottom: -0.42em; }
  .lede, .pop-q { margin-top: -0.05em; margin-bottom: -0.27em; }
  .label, dt { margin-top: -0.35em; margin-bottom: -0.25em; }
  h2, h4, .s-head { margin-top: -0.225em; margin-bottom: -0.125em; }
  .fact-num .s-head { margin-top: -0.2em; margin-bottom: -0.1em; }
  .s-display { margin-top: -0.16em; margin-bottom: -0.06em; }
}

/* ==========================================================================
   Page and menu
   ========================================================================== */
.wrap {
  container-type: inline-size;
  max-width: calc(var(--max) + 2 * var(--gutter));
  margin-inline: auto;
  padding: 0 var(--gutter-r) var(--g4) var(--gutter-l);
}

/* Menu: always visible, in the inverted colours. The footer looks just the same, at the end of
   the page (Imprint · Privacy Policy · Cookies, spread across like the menu). */
.navbar, .footbar {
  background: var(--ink);
  color: var(--paper);
}
.navbar {
  position: sticky;
  top: 0;
  z-index: 110;
  padding-top: env(safe-area-inset-top, 0px);
}
.footbar { padding-bottom: env(safe-area-inset-bottom, 0px); }   /* clear of a phone's home bar */
.foot { min-height: calc(2 * (var(--g1) + var(--g0)) + 0.9em); }   /* as tall as the menu, whose colour switch is a little taller than its letters */
.navbar :focus-visible, .footbar :focus-visible { outline-color: var(--paper); }   /* on the bar's colour */
.navbar-inner {
  max-width: calc(var(--max) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter-l) var(--gutter-r);
}
.top, .foot { padding-block: calc(var(--g1) + var(--g0)); }   /* the one in-between distance: --g2 made the bar too tall, --g1 too cramped on a phone */
.top nav, .foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--g1) var(--g2); }
.top nav a, .foot a { position: relative; text-decoration: none; text-box: trim-both cap alphabetic; }   /* the switch centres on the capitals */
.top nav a::after, .foot a::after { content: ""; position: absolute; inset: calc(-1 * (var(--g1) + var(--g0))) calc(-1 * var(--g0)); }   /* a tap anywhere in the bar's height counts */
@supports not (text-box: trim-both cap alphabetic) {
  .top nav a, .foot a { margin-block: -0.35em -0.25em; }
}
@media (hover: hover) {
  .top nav a:hover, .foot a:hover { text-decoration: underline; }
}

/* ---------- Colour switch ---------- */
.theme-toggle {
  display: inline-flex;
  padding: var(--hit);
  margin: calc(-1 * var(--hit));    /* easier to hit, without moving the icon */
  border: 0;
  background: none;
  color: var(--paper);
  view-transition-name: theme-toggle;   /* stays in sight and turning while the page washes over */
}
.theme-toggle svg {
  display: block;
  width: 0.9em;                     /* a little taller than the capitals of the menu */
  height: 0.9em;
  overflow: visible;
}
.theme-toggle .half-dark { fill: #0D0D0D; }
.theme-toggle .half-light { fill: #FFFFFF; }
.theme-toggle .ring { fill: none; stroke: currentColor; }

/* The new colours grow out of the switch as a circle (both ways) */
::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-new(root) {
  animation: wash-circle 1.2s cubic-bezier(0.9, 0, 0.1, 1) both;   /* slow start, fast middle, slow finish */
}
@keyframes wash-circle {
  from { clip-path: circle(0px at var(--wash-x, 100%) var(--wash-y, 0px)); }
  to { clip-path: circle(var(--wash-r, 150vmax) at var(--wash-x, 100%) var(--wash-y, 0px)); }
}
::view-transition-old(theme-toggle) { display: none; }
::view-transition-new(theme-toggle) { animation: none; }
/* Browsers without page transitions: a circle in the new colour grows out of the switch,
   then the page in its new colours shows through it as it fades. It stays under the menu
   bar, so the switch keeps turning in sight. */
.curtain { position: fixed; inset: 0; z-index: 105; pointer-events: none; }

/* ==========================================================================
   Top of the page: 2200, opening text, the three places
   ========================================================================== */
.hero { display: grid; row-gap: var(--g3); padding-top: var(--gutter); }   /* above the 2200: the same space as at its sides */
.hero h1 svg { display: block; width: 100%; height: auto; overflow: visible; fill: currentColor; }
.lede { max-width: 34ch; }
/* The browser's own help with line breaks: no lone word on a last line, an even right edge.
   The script adds the typesetting rules on top (see "Typesetting" there). */
p, dd, figcaption > span, .idx > span:not(.status) { text-wrap: pretty; }
.index { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--col); }
.idx {
  display: grid;
  gap: var(--g1);
  align-content: start;
  justify-items: start;
  padding-top: var(--g1);
  border-top: 1px solid var(--ink);
}
.idx .idx-name { position: relative; color: var(--ink); text-decoration: none; }
.idx-name::after { content: ""; position: absolute; inset: calc(-1 * var(--g0)) 0; }   /* a taller tap area */
@media (hover: hover) {
  .idx-name:hover { text-decoration: underline; }
}

/* Status pills */
.status {
  display: inline-flex;
  align-items: center;
  gap: var(--g0);
  /* --g0 from the frame to the top of the capitals and from the baseline to the frame,
     --g1 at the sides (the em values are what the font adds above and below) */
  padding: calc(var(--g0) - 0.21em) var(--g1) calc(var(--g0) - 0.09em);
  border: 1px solid var(--ink);
  border-radius: 999px;
  line-height: 1;
  white-space: nowrap;
  background: var(--paper);
}
.status .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ink); flex: none; }
.status.soon { border-style: dashed; }
button.status { position: relative; }
@media (hover: hover) {
  button.status:hover { background: var(--frame); }
}
.status svg { width: 12px; height: 8px; flex: none; }
/* The words of a pill or button (put into <span class="words"> by the script) are trimmed to
   their capitals and baseline, so the same distance above and below centres them exactly, in
   every browser and with either set of font metrics. Browsers without trimming keep the em
   values above, worked out for Sparco as Chrome and Firefox set it. */
@supports (text-box: trim-both cap alphabetic) {
  .status > .words, .btn > .words { text-box: trim-both cap alphabetic; }
  .status:has(> .words) { padding-block: var(--g0); }
  .btn:has(> .words) { padding-block: var(--g1); }
  .status svg { margin-block: -1px; }      /* the arrow (8px) doesn't make its pill taller than the capitals (7.7px) */
}
/* Clicked, the pill's outline grows into the popup's outline; it is then drawn again,
   anticlockwise from the middle of its top edge (see the script) */
.status.lifted, .status.redraw { border-color: transparent; }
.status .pill-line {
  position: absolute;
  inset: -1px;                      /* over the frame */
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  overflow: visible;
  fill: none;
  stroke: var(--ink);
  stroke-width: 1;
  pointer-events: none;
}

/* ==========================================================================
   Sections
   The page is built from a few elements, each always looking the same:
     top of the page (2200, opening text, the places)   one of a kind
     big picture                                        .feature
     section title, with optional text on the right     .intro (.head + .text)
     fact list (label, big word, text)                  .facts — "The project" and "How to apply"
     residency                                          .place
     list (label and text in rows)                      .spec — in the residencies and "What a residency includes"
     portrait slider                                    .gallery.artists
     get in touch                                       .contact
     footer (like the menu)                             .footbar
   Planned: a map overview, sponsors' logos.
   ========================================================================== */
section.block { padding-top: var(--g4); }
/* A short page (404): the footer still sits at the bottom of the screen */
body.short { display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
body.short main { flex: 1 0 auto; width: 100%; }

/* Section title: the line, label and title on the left, room for text on the right */
.intro {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--g2) var(--col);
  align-items: start;
  margin-bottom: var(--g3);
}
.head {
  display: grid;
  gap: var(--g1);
  justify-items: start;
  padding-top: var(--g1);
  border-top: 1px solid var(--ink);
}
.intro .text { display: grid; gap: var(--g2); max-width: var(--measure); }
h2 { max-width: 20ch; text-wrap: balance; }

/* ---------- Big pictures ---------- */
.feature { margin-bottom: var(--g3); }
.wrap > .feature { margin: var(--g4) 0 0; }                 /* between two sections */
.wrap > .feature:not([hidden]) + .block { padding-top: var(--g3); }
.feature img { display: block; width: 100%; height: auto; max-height: 88vh; max-height: 88svh; object-fit: cover; }

/* ---------- Fact lists: label, big word, text ("The project", "How to apply") ---------- */
.facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--g3) var(--col);
  padding: 0;
}
.facts > div, .facts > li {
  display: grid;
  gap: var(--g1);
  align-content: start;
  justify-items: start;
  padding-top: var(--g1);
  border-top: 1px solid var(--line);
}
.facts > * > :last-child { display: grid; gap: var(--g2); justify-items: start; }

/* ==========================================================================
   Residencies
   ========================================================================== */
.places { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--g4); }

/* Head: name, place and altitude under it, the round button on the right. The circle
   reaches from the top of the name's capitals to the baseline of the line below, and is
   never smaller than 92px, at which its lettering stays readable. */
.place-head {
  --badge: max(92px, calc(var(--disp) * 0.7 + var(--g2) + var(--e1) * 0.8));
  position: relative;
  min-height: calc(var(--g2) + var(--badge));
  padding-top: var(--g2);
  border-top: 1px solid var(--ink);
  margin-bottom: var(--g2);
}
.place-title {
  display: grid;
  gap: var(--g2);
  justify-items: start;
  padding-right: calc(var(--badge) + var(--g1));
}
/* The names stay on one line, all at the same size: where the longest one (--name-em, its
   width in ems, measured by the script) wouldn't fit next to the round button, all of them
   get a little smaller. Otherwise one place would look different from the others.
   (The first line is for browsers without container units.) */
.place-title .s-display {
  font-size: min(var(--disp), (100vw - var(--gutter-l) - var(--gutter-r) - var(--badge) - var(--g1)) / var(--name-em, 8.5));
  font-size: min(var(--disp), (100cqi - var(--badge) - var(--g1)) / var(--name-em, 8.5));
  white-space: nowrap;
}

/* Text, details and the number */
.place-body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--g3) var(--col);
  align-items: start;
  margin-top: var(--g3);
}
.p-text { display: grid; gap: var(--g2); justify-items: start; }
.p-text p { max-width: var(--measure); }
.fact { display: grid; gap: var(--g2); justify-items: start; padding-top: var(--g2); border-top: 1px solid var(--ink); }
.fact-num { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.12em; }   /* a word space between number and unit */
.fact-num .s-head { line-height: 1; }
.fact p { max-width: 36ch; }

/* ---------- Round buttons ---------- */
.badge {
  position: absolute;
  top: var(--g2);
  right: 0;
  width: var(--badge);
  height: var(--badge);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  /* drawn 8 % larger than the space it takes, from its middle: it reaches a little above the
     capitals, below the baseline and into the right margin, as round shapes do to look as
     tall as straight ones. Nothing else moves. */
  scale: 1.08;
}
.badge > svg { position: absolute; display: block; overflow: visible; }
.badge .badge-rings, .badge .badge-text { inset: 0; width: 100%; height: 100%; }
.badge-rings circle { fill: none; stroke: currentColor; stroke-width: 1; }
/* The lettering turns clockwise, 1.2 times a minute; the logo stands still. The turning
   happens inside the drawing (see the script), so nothing needs clipping: older Safari
   drew a dark fade across round, clipped boxes with something turning inside. */
.badge-text text {
  font-family: var(--head);
  font-kerning: none;
  fill: currentColor;
}
/* The logo sits in the optical middle: the script measures where its weight lies
   (a triangle looks low when its box is centred) and moves it by --logo-dx / --logo-dy. */
.badge .badge-logo {
  left: 50%;
  top: 50%;
  width: var(--logo-w, 30%);
  height: auto;
  transform: translate(calc(-50% + var(--logo-dx, 0%)), calc(-50% + var(--logo-dy, 0%)));
  fill: currentColor;
}
.badge.lifted .badge-rings .outer { opacity: 0; }   /* its outline is turning into the popup */
@media (hover: hover) {
  button.badge:hover .badge-rings .outer { stroke-width: 2; }
}

/* ==========================================================================
   Photo strips
   ========================================================================== */
.gallery { position: relative; display: flow-root; --bleed: 0px; --hang: 0px; }   /* the strip's room above and below stays inside */
.strip {
  display: flex;
  gap: var(--g1);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.strip::-webkit-scrollbar { display: none; }
.strip > * { flex: none; scroll-snap-align: start; scroll-snap-stop: always; }   /* one photo per swipe, however hard */
.shot {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--frame);
  position: relative;
  overflow: hidden;
  max-width: 100%;
  cursor: zoom-in;
}
.shot:focus-visible { outline-offset: -2px; }   /* inside the photo: the slider cuts off what is outside */
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.loc .shot { height: var(--gallery-h); }
.loc .strip { min-height: calc(var(--gallery-h) + 2 * var(--g1)); }   /* its room is there before the photos arrive */
.gallery.single .shot { cursor: default; }
/* Photos that open the viewer grow a little under the pointer. The strip gets --g1 of room
   above and below, so the grown photo isn't cut off, without moving anything. Sideways the
   strip still ends exactly at the page's edges: a photo touching an edge grows away from it
   (the script sets where it grows from). */
.gallery .strip {
  padding-block: var(--g1);
  margin-block: calc(-1 * var(--g1));
  margin-inline: calc(-1 * (var(--bleed) + var(--hang))) calc(-1 * var(--bleed));
  padding-inline: calc(var(--bleed) + var(--hang)) var(--bleed);
  scroll-padding-inline: calc(var(--bleed) + var(--hang)) var(--bleed);
  clip-path: inset(0 var(--bleed) 0 0);            /* the right margin stays empty */
}
/* The portraits' captions: the first letter of a line hangs out a hair past the page margin
   (see "Optical left edges" in the script). Where the slider ends at the margin, it gets 4px of
   room on the left, so no letter is cut; photos only pass through it while it moves. */
.gallery.artists { --hang: 4px; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .gallery.loc .shot { transition: transform 0.35s cubic-bezier(0.2, 0, 0, 1); }
  .gallery.loc:not(.single) .shot:hover { transform: scale(1.0125); }   /* only photos that open the viewer */
}
/* On a phone the sliders reach to the left edge of the screen, so a photo (and the text under
   a portrait) stays in view until it has left the screen; the photos still rest between the
   page margins. The gap between the photos is then a quarter wider than the page margin, so a
   photo leaving on the left is just gone when the next one arrives at the margin, with no
   sliver of it left at the screen's edge. On the right they end at the
   page margin as always: what lies beyond slides in from behind that edge. On larger screens
   the margin is wider than the gap between the photos, and the sliders end at the margins.
   --bleed: from the edge of the screen to the page margin (measured by the script). */
@media (max-width: 600px) {
  .gallery, .gallery.artists { --bleed: var(--bleed-px, var(--gutter)); --hang: 0px; }
  .gallery .strip { gap: calc(var(--gutter) * 1.25); }
}

/* Slider arrows: at 80 % of the photos' height (on a phone in the middle; the script puts
   them there), 60 % over the photos and 40 % beyond */
.slide-arrow {
  --arrow-h: calc(var(--disp) * 0.7);           /* the cap height of the big Sparco type */
  position: absolute;
  z-index: 3;
  top: 80%;
  width: calc(var(--arrow-h) * 1.0186);          /* the drawing's proportions */
  height: var(--arrow-h);
  padding: 0;
  border: 0;
  background: none;
}
/* a taller click area; and 6 px wider on the side the arrow steps away from under the mouse
   (the left arrow is turned round, so its "left" is on the right), so it doesn't step out
   from under the pointer and back */
.slide-arrow::after { content: ""; position: absolute; inset: calc(-1 * var(--hit)) 0 calc(-1 * var(--hit)) -6px; }
@media (pointer: coarse) {
  /* on touch screens: a tall strip around the arrow takes the tap, reaching well above and
     below it and a little over the photo, but never past the screen's edge */
  .slide-arrow::after { inset: -90px 0 -90px -18px; }
}
.slide-arrow svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.slide-arrow path { fill: currentColor; }
.slide-arrow.next { right: 0; transform: translate(40%, -50%); }
.slide-arrow.prev {
  left: 0;
  visibility: hidden;
  pointer-events: none;
  /* parked just outside the left edge of the screen (--off is set by the script) */
  transform: translate(calc(-40% - var(--off, 100vw)), -50%) rotate(180deg);
}
.slide-arrow.prev.in { visibility: visible; pointer-events: auto; transform: translate(-40%, -50%) rotate(180deg); }
@media (prefers-reduced-motion: no-preference) {
  .slide-arrow { transition: transform 0.2s ease; }
  .slide-arrow.prev:not(.settled) { transition: transform 0.6s cubic-bezier(0.34, 1.4, 0.64, 1), visibility 0s; }   /* sliding in, with a little bounce */
  .strip { scroll-behavior: smooth; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .slide-arrow.next:hover { transform: translate(calc(40% + 5px), -50%); }
  .slide-arrow.prev.in:hover { transform: translate(calc(-40% - 5px), -50%) rotate(180deg); }
}

/* ==========================================================================
   Lists: label and text in rows (in the residencies and "What a residency includes")
   ========================================================================== */
.spec { justify-self: stretch; border-top: 1px solid var(--ink); }
.spec > div {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  gap: var(--g1) var(--col);
  align-items: start;
  padding-block: var(--g1);
  border-bottom: 1px solid var(--line);
}
.spec > div:first-child { padding-top: var(--g2); }   /* room under the black line */
.spec dd { max-width: var(--measure); }
/* The label sits in the middle of the first line's capitals next to it, not at their top:
   (cap height of the text − cap height of the label) / 2, from the two fonts' cap heights.
   On a phone the label stands above its text instead (see Smaller screens). */
.spec dt { margin-top: calc((var(--e1) * 0.8 - var(--s-label) * 0.7) / 2); }
@supports not (text-box: trim-both cap alphabetic) {
  .spec dt { margin-top: calc((var(--e1) * 0.8 - var(--s-label) * 0.7) / 2 - 0.35em); }
}

/* ==========================================================================
   Artists
   ========================================================================== */
.artists .strip > figure {
  width: calc((100% - 2 * var(--g1)) / 3);
  display: grid;
  gap: var(--g1);
  align-content: start;
}
.artists .shot { width: 100%; aspect-ratio: 1 / 1; cursor: pointer; }   /* portraits open the artist's website */
.artists .shot:not([href]) { cursor: default; }
.artists .shot img { aspect-ratio: 1 / 1; }
.artists figcaption { display: grid; gap: var(--g1); justify-items: start; }
.artists figcaption .label { color: var(--ink); }
/* After the name, in the same line and style: " · " and the timeframe. The dot is tied to the
   words on both sides, so no line starts or ends with it. */
.artists figcaption .when::before { content: "\00a0·\00a0"; }
.artists figcaption .when:empty { display: none; }

/* ==========================================================================
   Get in touch
   ========================================================================== */
.contact {
  margin-top: var(--g3);
  padding-top: var(--g1);
  border-top: 1px solid var(--ink);
  display: grid;
  gap: var(--g2);
  justify-items: start;
}
/* "Get in touch!": the size of the big type, nervous when you point at it */
.get-in-touch {
  padding: 0;
  border: 0;
  background: none;
  letter-spacing: 0;
  text-align: left;
  white-space: nowrap;
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .get-in-touch:hover,
  .get-in-touch:focus-visible { animation: jitter 0.32s linear infinite; }
}
html.locked .get-in-touch { animation: none; }   /* calm while a popup is open */
@keyframes jitter {
  0%   { transform: translate(0, 0) rotate(0); }
  12%  { transform: translate(-2px, 1px) rotate(-0.4deg); }
  25%  { transform: translate(2px, -1px) rotate(0.3deg); }
  37%  { transform: translate(-1px, -2px) rotate(0.2deg); }
  50%  { transform: translate(1px, 2px) rotate(-0.3deg); }
  62%  { transform: translate(-2px, 0) rotate(0.4deg); }
  75%  { transform: translate(2px, 1px) rotate(-0.2deg); }
  87%  { transform: translate(0, -1px) rotate(0.3deg); }
  100% { transform: translate(0, 0) rotate(0); }
}

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* --g1 all round: from the frame to the top of the capitals, from the baseline to the
     frame, and at the sides (the em values are what the font adds above and below) */
  padding: calc(var(--g1) - 0.36em) var(--g1) calc(var(--g1) - 0.24em);
  border: 1px solid var(--ink);
  border-radius: 0;
  text-decoration: none;
}
@media (hover: hover) {
  .btn:hover { background: var(--frame); }
}
@media (pointer: coarse) {
  /* on touch screens the button takes taps a little above and below its frame,
     up to halfway to the next button, so a compact button is still easy to hit */
  .btn { position: relative; }
  .btn::after { content: ""; position: absolute; inset: calc(-1 * var(--g0)) 0; }
}

/* ==========================================================================
   Popups
   ========================================================================== */
dialog { max-width: none; max-height: none; margin: auto; padding: 0; border: 0; background: transparent; color: var(--ink); }
dialog::backdrop { background: transparent; }   /* the veil does it (below) */
/* The page behind a dialog: dimmed behind the popups, covered behind the picture viewer
   (put in place and faded by the script) */
.veil { position: fixed; inset: 0; z-index: 140; background: var(--backdrop); pointer-events: none; }
.veil.solid { background: var(--paper); }
/* A popup too tall for the screen scrolls */
dialog.pop {
  width: min(760px, calc(100% - 2 * var(--gutter)));
  max-height: calc(100% - 2 * var(--gutter));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.pop-box {
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  overflow: hidden;                  /* the text moves in from below its edge… */
  overflow: clip;                    /* …and the box can't be scrolled (Safari scrolled it to the text) */
  padding: var(--g2);
}
/* Room above and below the text for accents and descenders, which the box would otherwise cut
   off while the text moves (a technical allowance, not a distance you see) */
.pop-stage { position: relative; overflow: hidden; overflow: clip; padding-block: 4px 16px; margin-block: -4px -16px; }
.pop-step { display: grid; gap: var(--g2); }
.pop-actions { display: flex; flex-wrap: wrap; gap: var(--g1); }
/* on its way to the form ("Taking you there"): on one line, as wide as its words */
.pop-actions .btn.going { white-space: nowrap; }
.pop u,
.pop .mail {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.12em;
  white-space: nowrap;
}
.pop .may-break { white-space: normal; }   /* wider than the popup: it may break, only where the page allows */
.pop-q .keep { display: inline-block; }    /* moves to the next line as a whole; wraps inside only if it must */

/* Opening from a round button or a pill: its outline grows into the popup's outline (the
   popup's own box stays hidden meanwhile) */
.morph-ring { position: fixed; z-index: 141; border: 1px solid var(--ink); pointer-events: none; }
.pop.hidebox .pop-box { opacity: 0; }
/* Closing like an old television: the box closes into a line from above and below, cutting
   the text away, while its outline is drawn by a separate frame, so it stays a crisp line;
   then the line shrinks to a dot */
.tv-off {
  position: fixed;
  z-index: 141;
  border: 1px solid var(--ink);
  background: var(--paper);
  pointer-events: none;
}
.tv-off.tv-frame { background: transparent; }
.pop.squeeze .pop-box { border-color: transparent; }

/* ==========================================================================
   Imprint and privacy
   One popup for a long text: it takes the screen's height (less the page margin above and
   below) and the text scrolls inside its frame. At its top a bar like the menu, spread across:
   the three parts and the ×. The part being read shows in the text colour, the others grey.
   Inside, the page's own elements: a title, paragraphs, and the list with labels on the left.
   ========================================================================== */
dialog.pop.legal { height: calc(100% - 2 * var(--gutter)); overflow: hidden; }
.legal .pop-box { display: flex; flex-direction: column; height: 100%; padding: 0; }
.legal-bar {
  flex: none;
  margin-inline: var(--g2);
  padding-block: calc(var(--g1) + var(--g0));     /* as in the menu */
  border-bottom: 1px solid var(--line);           /* the text scrolls away under this line */
}
.legal-bar nav { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--g1) var(--g2); }
.legal-bar a { position: relative; text-decoration: none; }
.legal-bar a::after { content: ""; position: absolute; inset: calc(-1 * (var(--g1) + var(--g0))) calc(-1 * var(--g0)); }   /* a tap anywhere in the bar's height counts */
.legal-bar a[aria-current] { color: var(--ink); }
@media (hover: hover) {
  .legal-bar a:hover { text-decoration: underline; }
}
/* The ×: Sparco's, as in the picture viewer, as tall as the colour switch in the menu */
.pop-close {
  display: inline-flex;
  box-sizing: content-box;
  width: 0.9em;
  height: 0.9em;
  padding: var(--hit);
  margin: calc(-1 * var(--hit));                  /* easy to hit, without moving the × */
  border: 0;
  background: none;
}
.pop-close svg { display: block; width: 100%; height: 100%; }
.pop-close path { fill: currentColor; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pop-close { transition: transform 0.25s cubic-bezier(0.34, 1.4, 0.64, 1); }
  .pop-close:hover { transform: rotate(90deg); }
}
.legal .pop-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;                   /* the page behind stays put */
  padding: var(--g2) var(--g2) var(--g3);
  scrollbar-width: thin;
  scrollbar-color: var(--grey) transparent;
}
/* A text: title, opening paragraphs, then the list. The privacy notice follows the imprint at
   the distance between two sections of the page. */
.legal-doc { display: grid; gap: var(--g2); justify-items: start; }
.legal-doc + .legal-doc { margin-top: var(--g4); }
.legal-head { display: grid; gap: var(--g1); justify-items: start; }
/* A smaller heading with its paragraphs: --g1 under the heading (a label and what it names),
   --g2 between paragraphs, --g1 again from a sentence ending in a colon to its list */
.legal-sub { display: grid; gap: var(--g2); justify-items: start; }
.legal-sub > h4 { margin-bottom: calc(var(--g1) - var(--g2)); }
.legal-sub > p:has(+ ul) { margin-bottom: calc(var(--g1) - var(--g2)); }   /* a rule of its own: older browsers skip it */
.legal-lead { display: grid; gap: var(--g2); }
.legal .pop-scroll p, .legal ul { max-width: var(--measure); }
.legal .pop-scroll a:not(.label) { text-decoration-thickness: 1px; text-underline-offset: 0.12em; white-space: nowrap; }
/* The list: as in "What a residency includes", with room for paragraphs in each row */
.legal-rows { justify-self: stretch; border-top: 1px solid var(--ink); }
.legal-rows > div {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  gap: var(--g1) var(--col);
  align-items: start;
  padding-block: var(--g2);
  border-bottom: 1px solid var(--line);
}
.legal-rows > div > div { display: grid; gap: var(--g2); justify-items: start; }
/* A label sits in the middle of the first line's capitals next to it, as in the page's lists;
   a smaller heading starting a row sits level with the row's label */
.legal-rows h3,
.legal-rows > div > div > .legal-sub:first-child > h4 { margin-top: calc((var(--e1) * 0.8 - var(--s-label) * 0.7) / 2); }
.legal ul { display: grid; gap: var(--g1); margin: 0; padding: 0; list-style: none; }
.legal li { position: relative; padding-left: 1em; text-box: trim-both cap alphabetic; text-wrap: pretty; }
.legal li::before { content: "•"; position: absolute; left: 0; }
@supports not (text-box: trim-both cap alphabetic) {
  .legal-rows h3,
  .legal-rows > div > div > .legal-sub:first-child > h4 { margin-top: calc((var(--e1) * 0.8 - var(--s-label) * 0.7) / 2 - 0.35em); }
  .legal li { margin-top: -0.2em; margin-bottom: -0.42em; }
}

/* ==========================================================================
   Picture viewer
   ========================================================================== */
.lb {
  --lb-pad: calc(var(--gutter) / 2);              /* around the photo: half the page margin */
  --lb-y: var(--lb-pad);                          /* above and below the photo, in addition */
  --arrow-h: calc(min(9.6vw, 120px) * 0.7);       /* the viewer's arrows and its × */
  --arrow-w: calc(var(--arrow-h) * 1.0186);
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}
.lb[open] {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  padding: calc(var(--lb-pad) + env(safe-area-inset-top, 0px)) max(var(--lb-pad), env(safe-area-inset-right, 0px))
           calc(var(--lb-pad) + env(safe-area-inset-bottom, 0px)) max(var(--lb-pad), env(safe-area-inset-left, 0px));
}
/* The × in the top right corner, as far from the top as from the side; it lies over the
   right arrow's column, so it never covers the photo */
.lb-bar { position: absolute; z-index: 2; top: calc(var(--lb-pad) + env(safe-area-inset-top, 0px)); right: max(var(--lb-pad), env(safe-area-inset-right, 0px)); display: flex; }
.lb-stage { display: grid; grid-template-columns: var(--arrow-w) minmax(0, 1fr) var(--arrow-w); grid-template-rows: minmax(0, 1fr); align-items: center; gap: var(--g1); min-height: 0; }
/* The photos sit side by side on a track as wide as the screen, which scrolls sideways:
   with the arrows (the script glides it on), or with a swipe or a trackpad. One photo per
   stop. The arrows lie on top of it. The photo sits in the middle of the screen, as far
   from the top as from the bottom. */
.lb-media {
  grid-area: 1 / 1 / 2 / -1;
  align-self: stretch;
  min-height: 0;
  margin-inline: calc(-1 * var(--lb-pad));
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
.lb-media::-webkit-scrollbar { display: none; }
.lb-slide {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--lb-y) calc(var(--lb-pad) + var(--arrow-w) + var(--g1));   /* the photo keeps clear of the arrows */
  scroll-snap-align: center;
  scroll-snap-stop: always;
}
.lb-slide img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
.lb-stage .lb-arrow { position: relative; z-index: 1; grid-row: 1; }
.lb-stage .lb-arrow.prev { grid-column: 1; }
.lb-stage .lb-arrow.next { grid-column: 3; }
.lb-arrow {
  width: var(--arrow-w);
  height: var(--arrow-h);
  padding: 0;
  border: 0;
  background: none;
}
.lb-arrow svg { display: block; width: 100%; height: 100%; }
.lb-arrow path { fill: currentColor; }
.lb-arrow.prev svg { transform: rotate(180deg); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .lb-arrow { transition: transform 0.2s ease; }
  .lb-arrow.next:hover { transform: translateX(5px); }
  .lb-arrow.prev:hover { transform: translateX(-5px); }
}
/* Close: Sparco's ×, 40 % of the height of the arrows */
.lb-close {
  box-sizing: content-box;
  width: calc(var(--arrow-h) * 0.4);
  height: calc(var(--arrow-h) * 0.4);
  padding: var(--hit);
  margin: calc(-1 * var(--hit));   /* easy to hit, even on a phone, without moving the × */
  border: 0;
  background: none;
}
.lb-close svg { display: block; width: 100%; height: 100%; }
.lb-close path { fill: currentColor; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .lb-close { transition: transform 0.25s cubic-bezier(0.34, 1.4, 0.64, 1); }
  .lb-close:hover { transform: rotate(90deg); }
}
/* Opening and closing (see the script): the clicked photo flies between its place in the
   slider and the viewer while the page fades out behind it, and the slider's arrows fly to
   the viewer's arrows with it; the × slides in after. */
.lb-ghost { position: fixed; z-index: 5; display: block; object-fit: cover; background: var(--frame); pointer-events: none; }
.lb.lb-in .lb-media > *, .lb.lb-out .lb-media > * { opacity: 0; }
.lb.lb-in .lb-arrow, .lb.lb-in .lb-close { visibility: hidden; }
.lb-fly { position: fixed; z-index: 6; pointer-events: none; }   /* an arrow on its way, above the photo */
.lb-fly svg { display: block; width: 100%; height: 100%; }
.lb-fly path { fill: currentColor; }
.lb-fly.prev svg { transform: rotate(180deg); }
.gallery.lb-source .slide-arrow { opacity: 0; }   /* …and the slider's own arrows meanwhile */

/* ==========================================================================
   Caption bubble (big pictures, portraits): always black on white, also in dark colours
   ========================================================================== */
.tip {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 120;
  max-width: min(30ch, calc(100vw - 2 * var(--gutter)));
  padding: calc(var(--g1) - 0.095em) var(--g1) calc(var(--g1) - 0.405em);   /* --g1 to the capitals and from the baseline, as in the buttons */
  background: #FFFFFF;
  color: #0D0D0D;
  border: 1px solid #0D0D0D;
  border-radius: var(--radius);
  line-height: 1.3;
  white-space: pre-line;           /* a portrait's own second line starts on a line of its own */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.tip.on { opacity: 1; }
.tip.fade { transition-duration: 0.8s; }

/* ==========================================================================
   Smaller screens
   ========================================================================== */
@media (max-width: 1199px) {
  .index { grid-template-columns: 1fr; gap: 0; }
  .idx { grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--col); padding-block: var(--g1); }
  .idx .status { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  /* the next portrait always shows by about a quarter, so a swipe is obvious: no arrows */
  .gallery.artists .slide-arrow { display: none; }
  .intro, .place-body { grid-template-columns: 1fr; }
  .artists .strip > figure { width: 78%; }
}
@media (max-width: 600px) {
  /* "Get in touch" choices: one under the other, text on the left, each as wide as its text */
  #contact-pop .pop-actions { display: grid; grid-template-columns: minmax(0, max-content); justify-items: start; }
  #contact-pop .pop-actions .btn { justify-content: flex-start; text-align: left; }
  .top nav, .foot, .legal-bar nav { column-gap: var(--g0); letter-spacing: 0.04em; }
  .legal-bar .label { letter-spacing: inherit; }
  .idx { grid-template-columns: 1fr; }
  .idx .status { grid-column: 1; grid-row: auto; }
  .facts { grid-template-columns: 1fr; }
  .spec > div, .legal-rows > div { grid-template-columns: 1fr; }
  .spec dt,                                        /* the label stands above its text */
  .legal-rows h3,
  .legal-rows > div > div > .legal-sub:first-child > h4 { margin-top: 0; }
  @supports not (text-box: trim-both cap alphabetic) {
    .spec dt,
    .legal-rows h3,
    .legal-rows > div > div > .legal-sub:first-child > h4 { margin-top: -0.35em; }
  }
  .lb-stage { grid-template-columns: minmax(0, 1fr); }
  .lb-stage .lb-arrow { display: none; }
  /* no arrows on a phone: the photo goes almost edge to edge, and keeps clear of the × above
     it (the same room below, so it stays in the middle) */
  .lb { --lb-y: calc(var(--arrow-h) * 0.4 + var(--g1)); }
  .lb-slide { padding-inline: var(--lb-pad); }
}
