@charset "UTF-8";

/* Exhibition (MoXoW) page theme, shared by the exhibition sites
 * (invitation-au-japon, carnaval-venitien, et-la-lumiere-fut).
 * Copyright (c) 2009-2026 Stephane D'Alu — http://www.sdalu.com/
 *
 * Design: "La Cimaise" — the lit gallery wall. A warm spotlight on a
 * dark wall, photographs matted and framed like physical prints,
 * captions as museum wall labels, the enter button a brass plaque.
 *
 * The blocks of a room, top to bottom — each has its own section in
 * this file, and the design rules plus the measured sign-off live in
 * EXHIBITION.md beside it:
 *
 *   ┌ wall — the spotlight ground ──────────────────────┐
 *   │ masthead    show name over room name, the cartel  │
 *   │ ┌ figure-band ─────────────────────────────────┐  │
 *   │ └───────────────── 2.39:1 panorama, chosen crop┘  │
 *   │ two-up ······· ┆ ·······     columns: 46ch        │
 *   │ [mat][mat][mat][mat]         the strip            │
 *   │ ┌ doorway ─────┐ ┌ poster ─┐ ┌ acquisition ────┐  │
 *   │ │ ENTER plaque │ │  ╳  PDF │ │ lead │ tariff   │  │
 *   │ └──────────────┘ └─────────┘ └─────────────────┘  │
 *   │ invitation — the closing block, to the next room  │
 *   └───────────────────────────────────────────────────┘
 *
 * This file is one cascade layer, `theme`, between `mxw` and `site` in
 * the order MoXoW declares inline (m:head-layers, html-head-body.xsl). It used to be deliberately unlayered, which
 * bought the same thing by a blunter route — an unlayered rule beats every
 * layered one whatever its specificity — at the price of also beating the
 * site sheets, which then had to out-specify it to say anything, and of
 * beating third-party widgets that had styled themselves perfectly well.
 * Named instead, it decorates the gallery component (`mxw-gallery`, before
 * it) and yields to the exhibition that loads it (`site`, after it).
 *
 * The body below is not indented into the layer block. It is the whole
 * file, so a level of indentation would say nothing and would reflow three
 * thousand lines of hand-aligned comments to say it. */

/* Self-hosted faces (OFL), the full masters ResourceBuilder publishes
 * to /common/fonts/ — one location for every family, rather than these
 * three keeping a second latin-subset copy of themselves under
 * /common/3rd-party/, a directory since retired entirely. Unsubsetted, so they carry roughly five times the
 * glyphs and four times the bytes of the subsets they replace; trim with
 * ResourceBuilder's deploy:fonts SUBSET=latin if that ever matters more
 * than having one copy. The stacks below still keep system fallbacks for
 * glyphs no latin face has (e.g. Japanese). */
@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 300 700;          /* variable */
  font-display: swap;
  src: url("/common/fonts/CormorantGaramond-wght.woff2") format("woff2");
}

@font-face {
  font-family: "Alegreya";
  font-style: normal;
  font-weight: 400 900;          /* variable */
  font-display: swap;
  src: url("/common/fonts/Alegreya-wght.woff2") format("woff2");
}

@font-face {
  font-family: "Alegreya";
  font-style: italic;
  font-weight: 400 900;          /* variable */
  font-display: swap;
  src: url("/common/fonts/Alegreya-Italic-wght.woff2") format("woff2");
}

@font-face {
  font-family: "Alegreya Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/common/fonts/AlegreyaSans-Regular.woff2") format("woff2");
}

@font-face {
  font-family: "Alegreya Sans";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/common/fonts/AlegreyaSans-Italic.woff2") format("woff2");
}

@font-face {
  font-family: "Alegreya Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/common/fonts/AlegreyaSans-Bold.woff2") format("woff2");
}

@layer theme {

/* Design tokens — "La Cimaise": the lit gallery wall. A dim, warmly lit
 * exhibition room; photographs matted and framed like physical prints,
 * captions as museum wall labels on mat board, the enter button a brass
 * plaque. */
:root {
  /* the wall is dark: let scrollbars and native controls follow it
   * instead of rendering as light UI on #16130f */
  color-scheme: dark;

  --color-wall:       #16130f;    /* deep wall shadow */
  --color-spotlight:  #3a332b;    /* lit center of the wall */
  --color-mat:        #efe9dc;    /* mat board: placards, print mats */
  --color-mat-ink:    #241f1a;    /* text on mat board */
  --color-gilt:       #cdab55;    /* titles, links, active nav */
  --color-brass:      #b6934a;    /* plaque body, placard rule */
  --color-brass-hi:   #d8bd7a;    /* plaque top light */
  /* rings, borders and hairlines only: on mat board it is 4.02:1, which
   * clears the 3:1 asked of a non-text boundary and misses the 4.5:1
   * asked of text. Text on a mat takes --color-mat-brass below. */
  --color-brass-edge: #8a6d33;
  /* Brass belongs on the dark wall, where #b6934a reads at 6.4:1. The
   * same pigment on mat board is 2.4:1, so the placards get their own
   * ink: same hue, darkened until it clears 4.5:1 on every mat backdrop
   * — plain #efe9dc (5.01), the translucent card (5.47) and the
   * gilt-tinted selected card (4.65). Never darken --color-brass itself;
   * it is correct where it lives. */
  --color-mat-brass:  #775f30;    /* brass for text and rings ON mat */
  --color-mat-ink-muted: #5f5545; /* quiet text on a mat: 6.04:1, the
                                     step under --color-mat-ink */
  --color-mat-rule:   rgb(138 109 51 / 0.45);  /* brass hairline drawn
                                     on mat: the edge of a control */
  --color-brass-lit:  #e6cd8b;    /* the lit end of a brass gradient,
                                     and brass brightening on a wall */
  --color-frame:      #574a33;    /* gilt frame ring around prints */
  --color-label:      #bfb49e;    /* quiet nav/labels on the wall */
  --color-accent:     var(--color-gilt);

  --color-hairline: rgb(239 233 220 / 0.25);
  --line: 1px solid var(--color-hairline);

  --font-display: "Cormorant Garamond", "Iowan Old Style",
                  "Palatino Linotype", Palatino, Georgia, serif;
  --font-body: "Alegreya Sans", "Gill Sans", "Trebuchet MS",
               Verdana, sans-serif;
  /* long-form paragraphs: the serif sibling, designed for literature */
  --font-text: "Alegreya", "Iowan Old Style", "Palatino Linotype",
               Palatino, Georgia, serif;

  --shadow-hung: 0 22px 40px rgb(0 0 0 / 0.6);      /* framed print */
  --shadow-placard: 0 4px 10px rgb(0 0 0 / 0.45);   /* wall label */
}

/*== Amazon product table (was _amazon.scss) ==========================*/
.amazon {
  margin-inline-start: 1em;
  text-align: left;

  & caption {
    font-variant: small-caps;
    border-block-end: 1px solid grey;
  }

  /* covers lift off the shelf on hover (or keyboard focus) */
  & img {
    margin: 5px;
    border: 1px solid grey;
    box-shadow: 3px 3px 3px #555;
    transition: translate 0.2s ease-out, box-shadow 0.2s ease-out,
                border-color 0.2s ease-out;
  }

  & img:hover,
  & a:focus-visible img {
    translate: 0 -4px;
    border-color: var(--color-gilt);
    box-shadow: 0 10px 18px rgb(0 0 0 / 0.55);
  }
}

/*== TOC ==============================================================*/
/* "Plan de visite": the table of contents as a wall label — mat board
 * under a brass rule, like the theme's other placards. */
.mxw-toc {
  /* Not a float. It used to be one, and the text wrapped round it; the
   * page that has a TOC now sets its prose in columns, and a multicol
   * block is a formatting-context root — it lines up BESIDE a float
   * instead of flowing round it, for its whole height. Every float on
   * these pages has gone for that reason and this is the last of them.
   * A block pushed to the rail keeps the placard where it was and lets
   * the columns start underneath it. */
  inline-size: fit-content;
  margin-block-end: 0.5ex;
  margin-inline-start: auto;
  padding: 0.8em 1em;
  max-inline-size: 22em;
  text-align: left;
  color: var(--color-mat-ink);
  background: var(--color-mat);
  border-block-start: 3px solid var(--color-brass);
  box-shadow: var(--shadow-placard);

  /* the title (server-emitted handle div) */
  & > div:first-child {
    margin-block-end: 0.4em;
    padding-block-end: 0.3em;
    font-family: var(--font-display);
    font-variant: small-caps;
    letter-spacing: 0.05em;
    font-size: 1.05rem;
    border-block-end: 1px solid rgb(36 31 26 / 0.2);
  }

  & ul {
    margin: 0;
    padding: 0;
    list-style: none;

    li + li { border-block-start: 1px solid rgb(36 31 26 / 0.1); }

    a {
      display: block;
      padding: 0.25em 0;
      font-family: var(--font-body);
      font-size: 0.85rem;
      color: var(--color-mat-ink);
      text-decoration: none;

      &:hover, &:focus-visible {
        color: var(--color-mat-brass);
        text-decoration: none;
      }
    }
  }
}

/* Anything sharing the TOC's rail (e.g. an ad block), floated under the
 * placard instead of sitting on its mat board. */
.toc-rail {
  float: inline-end;
  clear: inline-end;
  margin-block-start: 0.5em;
  margin-inline-start: 1em;
}

/*== References =======================================================*/
/* One quiet line: a tracked-caps label, then the links spread with
 * room to breathe (the 2010 link icon is gone). */
.m-link-references {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4em 1em;
  margin-block: 0.6em;
  font-family: var(--font-body);
  font-size: 1rem;               /* the links are real targets */

  & > div:first-child {
    font-size: 0.8rem;           /* proportionate to the 1rem links */
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-label);
  }

  & ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4em 1.2em;
    margin: 0;
    padding: 0;
    list-style: none;
  }
}

/*== Pretty table =====================================================*/
/* The registry: gilt small-caps caption, a dark header band under the
 * brass rule with tracked-caps column labels, comfortable cells and a
 * faint stripe. */
table.pretty {
  margin-block: 1em;
  border-collapse: collapse;
  border: var(--line);

  /* A registry has as many columns as it has, and its cells hold names
   * that will not wrap much further ("Encéphalite japonaise", "3ème lundi
   * de septembre"): below some width it cannot fit, and what it must not
   * do is widen the page. As a block it becomes its own scroll container
   * — fit-content so it still shrink-wraps its content on a wide page, as
   * a table does, and scrolls only once there is no room. The rows inside
   * keep their table layout: display:block on the table element leaves
   * the anonymous table box in place.
   *
   * Measured on invitation-au-japon /info/, which has the only two: the
   * page was 710px wide at every viewport below 700 and is now clear down
   * to 320. */
  display: block;
  inline-size: fit-content;
  max-inline-size: 100%;
  overflow-x: auto;

  & caption {
    margin-block-end: 0.4em;
    font-family: var(--font-display);
    font-variant: small-caps;
    letter-spacing: 0.05em;
    font-size: 1.15rem;
    color: var(--color-gilt);
    text-align: start;
  }

  & thead th {
    padding: 0.45em 0.9em;
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-align: start;
    color: var(--color-label);
    background-color: #241f1a;
    border-block-end: 2px solid var(--color-brass);
  }

  & td, & tbody th {
    padding: 0.35em 0.9em;
    vertical-align: top;
  }

  & tbody tr:nth-child(even) {
    background-color: rgb(239 233 220 / 0.04);
  }
}

/*== Page frame =======================================================*/
/* The wall: a warm spotlight falling on the upper center, fading into
 * shadow. Fixed so the light source doesn't scroll with the page. */
html {
  min-block-size: 100%;
  background: var(--color-wall)
    radial-gradient(60% 55% at 50% 30%,
      var(--color-spotlight), #241f1a 55%, var(--color-wall))
    no-repeat fixed;
}

/* Smooth anchor scrolling (TOC links) for those who accept motion;
 * a little air above the targeted heading. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

:target { scroll-margin-block-start: 1em; }

body {
  color: #e9e2d3;               /* warm off-white: less glare than pure
                                   white on the dark wall */
  font-family: var(--font-text); /* serif by default: general text is
                                    long-form; chrome opts into the sans */
  line-height: 1.6;
}

#body {
  margin: 0 auto;
  color: white;
  background: transparent;
}

/* The room: menu, content and footer share ONE bounded column whose
 * edges are visible — a faintly lighter wall panel between hairlines,
 * running the full viewport height. The margins outside it read as
 * chosen, not as leftover; the nav no longer starts at the viewport
 * edge. */
#mxw-page {
  max-inline-size: 72em;
  min-block-size: 100dvh;
  margin-inline: auto;
  background: rgb(239 233 220 / 0.025);
  border-inline: 1px solid rgb(239 233 220 / 0.08);
}

/* :where(), so these three carry no weight at all. They are the default
 * for a link anywhere on the page, and a default should lose to anything
 * that has an opinion: stated as plain selectors they were (0,1,1), which
 * a component rule ties rather than beats, and three rules downstream had
 * to say !important to get their own links back — the poster, the enter
 * plaque and a heading that is a link. Those three are plain declarations
 * again. */
:where(a, a:visited, a:link, a:hover, a:active) {
  color: var(--color-accent);
  text-decoration: none;
}
:where(a:visited) { color: #fffcca; }
:where(a:hover)   { text-decoration: underline; }

/* Colour alone does not say "link". Measured on /visit/, the accent
 * stands 1.70:1 against the body text, where 3:1 is what is asked of a
 * colour carrying the distinction on its own -- and until the pointer
 * arrives, colour was all there was.
 *
 * So a hairline under the words at rest: thin, offset clear of the
 * descenders, and dimmed to about half so a paragraph with three links
 * in it is not hatched through. Under the pointer it comes up to full
 * gilt, the same brightening the picture ribbons use.
 *
 * Prose only. A menu tab, a thumbnail, a brass plaque and a tariff chip
 * each carry their own affordance, and an underline through them would
 * be noise.
 *
 * The home page writes its prose straight into the section div rather
 * than into paragraphs, so the description is named here as well: five
 * links on the front page were the only ones on the site still carrying
 * nothing but their colour. */
#mxw-content :is(p, dd, li, blockquote, .m-exhibition-description) a {
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in oklab, currentColor 45%, transparent);
  transition: color 0.2s ease-out, text-decoration-color 0.2s ease-out;

  &:hover,
  &:focus-visible {
    text-decoration-color: currentColor;
  }
}

img { border: none; }

ul {
  margin-inline-start: 0;
  padding-inline-start: 1ex;
  text-align: left;
  list-style: square inside none;
}

/* Content photos (floated info-page pictures) wear the same mat ribbon
 * as the gallery thumbnails — see the shared .mat-frame rule below. */

/*== Cart =============================================================*/
/* Show/hide the basket: a bordered plaque with a Font Awesome cart
 * glyph above the label (replaces the 2010 cart PNG background). */
.cart-toggler {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35em;
  inline-size: 138px;
  padding: 0.7em 0.5em;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: bold;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  color: var(--color-label);
  border: var(--line);
  border-radius: 2px;
  cursor: pointer;
  transition: color 0.2s ease-out, border-color 0.2s ease-out;

  &::before {
    font-family: "Font Awesome 7 Pro";
    font-weight: 900;
    content: "\f218";                 /* fa-cart-arrow-down */
    font-size: 1.7rem;
    color: var(--color-brass);
    transition: color 0.2s ease-out;
  }

  &:hover { color: var(--color-gilt); border-color: var(--color-gilt); }
  &:hover::before { color: var(--color-gilt); }
}

/* The basket: a mat-board order slip pinned beside the gallery, with
 * receipt-style item lines and a printed-bill total. */
/* Gallery beside its basket: the Sidebar pattern. The gallery keeps at
 * least 60% of the group or the two wrap, so the basket drops under the
 * pictures on its own — no breakpoint, and every width in between is a
 * layout somebody tested. Source order is gallery-then-basket, which is
 * both the stacked order and the wide left-to-right order, so nothing
 * here diverges from reading or tab order. */
.gallery-with-basket {
  display: flex;
  flex-wrap: wrap;
  gap: 1em 2.1em;
  align-items: flex-start;

  & > mxw-gallery {
    flex: 999 1 0;
    min-inline-size: 60%;
  }

  & > .cart-basket { flex: 1 1 18.75rem; }
}

.cart-basket {
  box-sizing: border-box;
  /* sticky so the basket follows the gallery scroll; a flex column caps
   * it to the viewport and lets the item list scroll inside while the
   * totals footer stays put */
  position: sticky;
  inset-block-start: 1em;
  display: flex;
  flex-direction: column;
  max-block-size: calc(100dvh - 2em);
  color: var(--color-mat-ink);
  background: var(--color-mat);
  border: 1px solid var(--color-brass-edge);
  border-block-start: 3px solid var(--color-brass);
  border-radius: 2px 2px 3px 3px;
  box-shadow: var(--shadow-placard);
  overflow: hidden;
}

/* The 334px pin that used to sit here existed because the gallery shrank
 * beside a sticky FLOAT, and Firefox re-resolved that float's exclusion
 * mid-scroll, re-packing the justified rows and yanking the scroll back.
 * There is no float any more — the basket is a flex item — so the
 * exclusion is gone and the pin with it — confirmed in Firefox, the
 * scroll holds. */

/* The fold. The basket sits in the way in two different manners, so it
 * has two ways of getting out of it.
 *
 * Stacked under the gallery it is a panel between the reader and the
 * pictures — 391px of it on a 390px phone — and folds down to its bar.
 *
 * Standing beside the gallery it costs a column instead: 301px of the
 * row that the pictures would otherwise have. There it folds sideways,
 * to a rail two icons wide carrying the cart and the count, and the
 * gallery takes the width back on its own — flex-grow 999 was already
 * waiting for it. Someone who came to look rather than to buy gets the
 * whole row, and the rail says where the basket went.
 *
 * Which of the two it is, cart.js decides by measuring: the
 * basket is stacked when it spans the whole row. */
.cart-basket-toggle {
  display: flex;
  align-items: center;
  gap: 0.6em;
  inline-size: 100%;
  min-block-size: 2.75rem;      /* the touch floor, as .print-specs-link */
  padding: 0.5em 0.7em;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
  background: none;
  border: none;
  border-block-end: 1px solid var(--color-brass-edge);

  & .cart-basket-name {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  & .cart-basket-tally {
    margin-inline-start: auto;
    font-variant-numeric: tabular-nums;
  }

  /* the rail's own tally: a bare count under the cart, empty when the
     basket is */
  & .cart-basket-count {
    display: none;
    font-family: var(--font-body);
    font-size: 0.82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  /* the chevron points where the panel is about to go */
  & .cart-basket-chevron { transition: rotate 0.2s ease-out; }
}

.cart-basket.is-stacked:not(.is-collapsed) .cart-basket-chevron { rotate: 180deg; }
.cart-basket:not(.is-stacked):not(.is-collapsed) .cart-basket-chevron { rotate: -90deg; }

/* Folded down to a bar: the bar is all there is, since the panel it
 * replaces would sit between the reader and the pictures either way. */
.cart-basket.is-stacked.is-collapsed {
  & > :is(.cart-basket-items, .cart-basket-checkout, .cart-basket-rail) {
    display: none;
  }

  & .cart-basket-toggle { border-block-end: none; }
  & .cart-basket-chevron { rotate: 0deg; }
}

/* Folded aside to a rail. A rail keeps its column whether or not it uses
 * it, so it uses it: the pictures in the basket run down it, one per
 * photograph however many formats of it were taken, and the checkout
 * button stays at the foot where it always is. The way back out sits at
 * the top, above what it opens. */
.cart-basket:not(.is-stacked).is-collapsed {
  flex: 0 0 auto;
  inline-size: 3.5rem;

  & .cart-basket-toggle {
    flex-direction: column;
    gap: 0.3em;
    padding-inline: 0;
    text-align: center;
  }

  & .cart-basket-chevron { order: -1; rotate: 90deg; }

  & .cart-basket-name,
  & .cart-basket-tally { display: none; }

  & .cart-basket-count { display: block; }

  & > .cart-basket-items { display: none; }
  & > .cart-basket-rail { display: block; }

  /* The footer keeps both its buttons, one above the other since neither
   * would be a target at half of 3.5rem, and drops the totals slip that
   * has no room to be read. The trash keeps its own comings and goings:
   * cart.js hides it inline while the basket is empty, which is
   * exactly when a rail has nothing to empty. */
  & > .cart-basket-checkout {
    flex-direction: column;
    gap: 0.35em;
    padding: 0.4em 0.35em;

    & .cart-checkout { display: none; }

    /* One column, so the two are one button twice. Along the row the
     * trash is a 2.7em square beside a checkout that fills what is left,
     * and both of those measurements are about a row: stacked they came
     * out 34x30 under a 42x30. */
    & :is(.cart-checkout-validate, .cart-checkout-empty) {
      inline-size: 100%;
      min-block-size: 1.9rem;
      padding-inline: 0;

      & span { display: none; }
    }
  }
}

/* The pictures in the rail. It takes the room between the head and the
 * checkout and scrolls inside it, so a basket of thirty prints is as
 * tall as one of three. */
.cart-basket-rail {
  display: none;
  flex: 1 1 auto;
  min-block-size: 0;
  margin: 0;
  padding: 0.4em 0 0.15em;
  overflow-y: auto;
  cursor: pointer;
  list-style: none;

  /* Empty, the rail would be two rules with nothing between them, which
   * reads as something broken rather than as an empty basket. An empty
   * frame says it: the same 2.5rem slot the pictures sit in, drawn and
   * unfilled. */
  &:empty::before {
    content: "";
    display: block;
    inline-size: 2.5rem;
    aspect-ratio: 3 / 2;
    margin: 0.15em auto;
    border: 1px dashed var(--color-brass-edge);
    border-radius: 1px;
    opacity: 0.5;
  }

  & li {
    position: relative;
    inline-size: 2.5rem;
    margin: 0 auto 0.4em;
  }

  & img {
    display: block;
    inline-size: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border: 1px solid var(--color-brass-edge);
    border-radius: 1px;
  }

  /* how many of that picture, when it is more than one */
  & .cart-rail-qty {
    position: absolute;
    inset-block-end: -3px;
    inset-inline-end: -5px;
    min-inline-size: 1.1rem;
    padding: 0 0.2em;
    font-family: var(--font-body);
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--color-mat-ink);
    text-align: center;
    background: linear-gradient(160deg, var(--color-brass-lit), var(--color-brass));
    border-radius: 1rem;
    box-shadow: inset 0 0 0 1px var(--color-brass-edge);
  }
}

.cart-basket-items {
  flex: 1 1 auto;
  min-block-size: 0;            /* let the flex item shrink so it scrolls */
  overflow-y: auto;
  padding: 0.3em 0.7em;
}

/* A line whose quantity fell to 0 dims and its brass hairline drains
 * for the grace period (6s = GRACE in cart.js), then leaves —
 * pressing + meanwhile restores it untouched. */
@keyframes cart-expire { from { inline-size: 100%; } to { inline-size: 0; } }
.cart-basket .cart-item.is-expiring {
  opacity: 0.6;

  &::after {
    content: "";
    display: block;
    block-size: 2px;
    background: var(--color-brass);
    animation: cart-expire 6s linear forwards;
  }
}
.mxw-cart-slip .mxw-cart-variant.is-expiring td { opacity: 0.55; }
@media (prefers-reduced-motion: reduce) {
  .cart-basket .cart-item.is-expiring::after { animation: none; }
}

/* one ordered print, as a receipt line: thumb | name+size+sums | ▲🗑▼ */
.cart-item {
  padding-block: 0.55em;
  border-block-end: 1px solid rgb(138 109 51 / 0.28);   /* brass hairline */
  transition: height 0.28s ease-out, padding-block 0.28s ease-out,
              opacity 0.2s ease-out;

  /* shrink out on removal: cart.js pins the current height then
   * collapses it to 0 while the padding and opacity fall away, so the
   * list closes the gap smoothly; the node drops on transitionend */
  &.removing {
    opacity: 0;
    padding-block: 0;
    border-block-end-color: transparent;
  }

  &:last-child { border-block-end: none; }

  & > table { inline-size: 100%; border-collapse: collapse; }
  & td { vertical-align: top; }

  .cart-thumbnail {
    inline-size: 46px;
    padding-inline-end: 0.6em;

    & img {
      display: block;
      inline-size: 46px;
      block-size: 46px;
      object-fit: cover;
      border: 2px solid #fff;
      box-shadow: 0 1px 3px rgb(0 0 0 / 0.4);
    }
  }
  .cart-name {
    font-family: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono",
                 Menlo, Consolas, monospace;
    font-size: 0.92rem;
    font-weight: 700;
    line-height: 1.15;
  }
  /* #5f5545 is this sheet's muted mat ink (6.04:1); #7a6d5a was the
   * outlier at 4.17:1, and #9a8c73 — the operator between the quantity
   * and the price, on this line and on the totals slip — was 2.72:1 on
   * the mat and 2.43:1 on the checkout band, under even the 3:1 asked of
   * something that is not text. It is text. */
  .cart-info { font-size: 0.76rem; color: var(--color-mat-ink-muted); }
  .cart-object, .cart-cost { font-variant-numeric: tabular-nums; }
  .cart-quantity, .cart-price { text-align: end; white-space: nowrap; }
  .cart-cost .cart-price { font-weight: 700; }
  .cart-operator { padding-inline: 0.35em; text-align: center; color: var(--color-mat-ink-muted); }

  /* the ▲ 🗑 ▼ control column */
  .cart-panel {
    inline-size: 1.6em;
    padding-inline-start: 0.4em;
    text-align: center;

    & table { inline-size: 100%; }
    & td {
      padding: 0.1em 0;
      color: var(--color-mat-brass);
      cursor: pointer;
      transition: color 0.15s ease-out;
    }
    & td:hover { color: var(--color-gilt); }
    & .a-del:hover { color: #b23b2e; }
  }
}

/* printed bill: labels left, amounts right, a rule before the total */
.cart-checkout-summary {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;

  & .cart-description { text-align: start; color: var(--color-mat-ink-muted); }
  & .cart-operator { text-align: center; color: var(--color-mat-ink-muted); }
  & .cart-price { text-align: end; white-space: nowrap; }

  & .cart-cost {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 700;

    & td { padding-block-start: 0.3em; border-block-start: 1px solid var(--color-brass); }
  }
}

/* basket footer: the totals slip, a full-width Passer-commande plaque,
 * and a quiet "vider le panier" link tucked at the bottom-right */
.cart-basket-checkout {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.5em;
  padding: 0.55em 0.7em 0.7em;
  background: rgb(36 31 26 / 0.06);
  border-block-start: 1px solid var(--color-brass-edge);

  & .cart-checkout { flex-basis: 100%; }       /* totals slip on its own row */
  & .cart-checkout:empty { display: none; }

  /* Passer commande fills the row; the trash sits to its right */
  & .cart-checkout-validate {
    flex: 1 1 auto;
    box-sizing: border-box;
  }
  & .cart-checkout-empty {
    flex: 0 0 auto;
    align-self: stretch;         /* match the validate height */
    inline-size: 2.7em;
    padding: 0;
    color: #7a6d5a;
    background: none;
    border: 1px solid var(--color-brass-edge);
    border-radius: 2px;
    box-shadow: none;

    & span { display: none; }    /* icon-only; the title carries the label */
    &:hover, &:focus-visible { color: #b23b2e; border-color: #b23b2e; }
  }
}

/* exhibition.js puts this on the region when the basket is dismissed */
.gallery-only .cart-basket { display: none; }

/*== Exhibition entry (m:poster) ======================================*/
/* The front-page poster: the enter button ("Entrez") appears over the
 * picture when the poster is hovered (or the link keyboard-focused).
 * Restored from the retired Compass build (MoXoW layout/exhibition),
 * which the sites' style.css used to bundle. */
/* Direct flex child of .m-exhibition (the table-era holder divs are
 * gone — they only ever carried the gutter, now the flex gap). */
.m-exhibition-poster {
  position: relative;

  /* The artwork keeps its size while the line can hold it: with wrap on,
   * a description that no longer fits goes below rather than squeezing
   * it. Shrinking is the last resort, for a line narrower than the
   * poster itself, and it has to be allowed or the poster pushes the
   * page wider instead. */
  flex: 0 1 auto;
  min-inline-size: 0;

  /* The two stand level at their middles rather than at their tops. The
   * description is usually the taller of the pair, so aligning at the
   * top left the picture riding high against a column of text that ran
   * on past it: 600 against 711 at 900px wide. Only the poster is
   * centred, so where the picture is the taller one nothing moves. */
  align-self: center;
  text-align: center;

  &:hover .m-exhibition-enter { opacity: 1; visibility: visible; }

  a { text-decoration: none; }
}

/* The poster as a framed print: the LINK carries the mat board, thin
 * dark lip, gilt frame ring and hung shadow, so the artwork <img>
 * keeps a clean box of its own — the overlays and the enter plaque
 * anchor to the artwork itself, immune to the frame's geometry. */
.m-exhibition-poster-frame {
  display: inline-block;
  box-sizing: border-box;
  max-inline-size: 100%;
  padding: 14px;
  background: var(--color-mat);
  border: 1px solid #0c0a08;
  box-shadow: 0 0 0 6px var(--color-frame), var(--shadow-hung);
}

.m-exhibition-poster-img {
  /* the aspect ratio drives the height: the artwork scales, it is
   * NEVER cropped or distorted, whatever the column width */
  max-inline-size: 100%;
  block-size: auto;
  max-block-size: 570px;        /* 600px framed, mat and border deducted */
  vertical-align: bottom;       /* no baseline gap below the artwork */
  anchor-name: --mxw-poster;
}

/* Where / when overlaid on the poster: it IS a poster — posters carry
 * their own information. Each page positions the two blocks by hand
 * into ITS artwork's free space (deliberate: the clear areas differ
 * from poster to poster) and may tune colors to match the art. */
.m-exhibition-poster-where {
  position: absolute;
  display: block;
  /* the containing block becomes the artwork box itself: page-tuned
   * top/left address the artwork's own pixel space, whatever the
   * frame's mat/border/margin geometry */
  position-anchor: --mxw-poster;
  position-area: center;
  font-family: sans-serif;
  /* the address is written in the picture-s own pixels where the site
     defines them, and stays 0.875rem where it does not: 14 x 0.0625rem
     is the size this always was. Pinned in rem it kept full size while
     the picture shrank, and on carnaval-venitien at 390 the four lines
     of the venue ran off the bottom of the artwork. */
  font-size: calc(14 * var(--poster-px, 0.0625rem));
  line-height: 1.35;
  color: black;
  text-align: start;

  .venue { font-weight: bold; }
  .subtitle {
    padding-inline-start: 1em;
    font-size: 0.8em;
    font-style: italic;
    font-weight: bold;
  }
}

/* Dates panel over a dimmed patch of the art: the original design's
 * translucent white (plus a soft blur) keeps the type readable
 * without hiding the poster. Pages may retint the border via
 * border-color. */
.m-exhibition-poster-when {
  position: absolute;
  position-anchor: --mxw-poster;
  position-area: center;
  border: 1px solid var(--color-brass);
  padding: 0.5em 0.8em;
  color: black;
  background: rgb(255 255 255 / 0.75);
  backdrop-filter: blur(2px);
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.35);
  text-align: start;
  font-family: sans-serif;
  cursor: default;
  user-select: none;

  .conditions {
    padding-block-end: 0.5ex;
    font-weight: bold;
    font-size: 0.9375em;
  }
  .period { font-size: 0.8125em; }
  .timetable {
    display: grid;
    grid-template-columns: max-content max-content;
    gap: 0.15em 0.8em;
    align-items: baseline;
    margin: 0;
    font-size: 0.8125em;

    dt, dd { margin: 0; }
    dd { font-variant-numeric: tabular-nums; }
  }
}

/* The enter button as a brass plaque (em padding/tracking: the pages
 * set their own font-size, and the plaque scales with it). */
.m-exhibition-enter {
  position: absolute;          /* the page chooses the vertical (top) */
  z-index: 10;                 /* above the where/when overlays (the
                                  link precedes them in DOM order) */
  display: inline-block;
  /* anchored to the artwork box: the page-tuned top addresses artwork
   * pixels (immune to the frame's geometry) and the plaque centers on
   * the artwork — no per-page (and per-language!) left coordinates.
   * Both engines have this: Chrome since 125, Firefox since 147. An
   * install older than that falls back to the poster block. */
  position-anchor: --mxw-poster;
  position-area: center;
  justify-self: anchor-center;
  padding: 0.3em 0.7em 0.35em;
  font-family: var(--font-body);
  font-weight: bold;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--color-mat-ink);
  text-decoration: none;
  cursor: pointer;
  background: linear-gradient(to bottom,
    var(--color-brass-hi), var(--color-brass));
  border: 1px solid var(--color-brass-edge);
  border-radius: 2px;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.55),
              0 3px 8px rgb(0 0 0 / 0.5);

  /* hidden until the poster is hovered or the link itself focused */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease-out, visibility 0.3s ease-out,
              filter 0.2s ease-out;

  /* the link states must outrank the page-frame a:visited rule */
  &:link, &:visited { color: var(--color-mat-ink); }

  &:hover         { filter: brightness(1.12); }
  &:focus-visible { opacity: 1; visibility: visible; }
}

/*== Exhibition component (m:exhibition) ==============================*/
/* Inner exhibition pages: layout table, description, access tables,
 * info popups, date toggler... Restored from the same retired Compass
 * bundle as the poster above. */
/* Two-column flex: poster beside description, centered as a pair;
 * wraps to a stack when the column gets narrow. */
.m-exhibition {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 2em;

  /* Full width with the line centred, rather than a shrink-wrapped box
   * centred by auto margins. The two look the same, and this one has a
   * width a child can measure against: fit-content cannot be a query
   * container, since inline-size containment tells a box to size itself
   * without looking at its contents and a shrink-wrapped box has
   * nothing else to go on. A poster that scales itself needs to know
   * how much room it has. */
  inline-size: 100%;

  /* Past this width nothing grows but the description: the poster holds
   * at 410 and the gap at 2em, so every further pixel goes to the text
   * alone. Given the page's full 1116 it ran 672px wide, 85 characters
   * to the line, where this theme calls 46ch a column of prose.
   *
   * The cap is written as what it has to hold rather than as a round
   * number, because it holds something: the venue and the times inside
   * the description stand side by side only while they have 28rem, and
   * a flat 55rem left them 436px and stacked them. 30rem clears that
   * with 2rem to spare, which is room for an address longer than this
   * one before the row gives way. */
  max-inline-size: calc(410px + 2em + 30rem);
  margin-inline: auto;

  container: exhibition / inline-size;
}

.m-exhibition-off { display: none; }

.m-exhibition-description {
  /* A hint, not a width. The description grows into whatever the poster
   * leaves and shrinks with the line; what this number decides is the
   * width it would rather have, and so the point at which it gives up
   * the line and drops below the poster instead of narrowing further.
   * Measured: 20em drops at about 800px and holds a 340px column to the
   * last, 26em drops at 920 and holds 460.
   *
   * Write it here rather than as a width on the page: for a flex item
   * the basis is the main size and a width is ignored, so a page that
   * states one is stating nothing. */
  flex: 1 1 var(--description-measure, 20em);
  min-inline-size: 0;
  /* flush-left body and headings: a ragged LEFT edge would lose the
   * eye's return point. The heading rules stay full width. */
  text-align: start;

  hr {
    block-size: 1px;
    inline-size: 75%;
    border: none;
    background-color: var(--color-hairline);
  }
}

/* One access record: the venue beside its schedule (markup is divs +
 * a definition-list timetable; layout lives here). */
.m-exhibition-access {
  /* The venue and the times stand side by side while the block is wide
   * enough to hold both, and one above the other when it is not.
   *
   * They used to be side by side always, the venue column giving way so
   * that the times never had to. The times cannot give way — the
   * timetable is a max-content grid and stops at 224px — so every pixel
   * came out of the venue: measured at 320, a 39px column, the venue
   * name broken over nine lines, the address over eight, the block 542px
   * tall and 4px wider than its container. A column of text one word
   * wide is not a compromise, so below the threshold they stack. */
  display: flex;
  gap: 0.5em 1.2em;
  margin-block: 0.8em;

  /* Where no ancestor is a query container the block is on its own: the
   * basis below is what makes the times wrap rather than starve the
   * venue. It is set under the query's threshold so that where there is
   * a container the query always acts first, and the two mechanisms
   * never disagree about which line the times belong on. */
  flex-wrap: wrap;

  /* The two take half the block each, so the rule between them falls
   * down the middle. Equal basis and equal growth is what says half:
   * the free space is shared rather than handed to the venue, which
   * used to take everything the times did not need (427 against 224 at
   * 1400).
   *
   * Half is what they get when nothing objects. The times cannot go
   * under the width of their timetable, and where half is less than
   * that they keep their content's width and the venue takes the rest.
   * That is why the times no longer set min-inline-size: 0 — the
   * automatic minimum IS the constraint, and zeroing it would let the
   * timetable spill out of its own column. */
  .m-exhibition-access-where {
    flex: 1 1 12rem;
    min-inline-size: 0;

    .venue {
      display: block;
      font-family: var(--font-display);
      font-size: 1.05rem;
      font-weight: 600;
    }

    .subtitle {
      font-style: italic;
      color: var(--color-label);
    }
  }

  .m-exhibition-access-when {
    flex: 1 1 12rem;
    padding-inline-start: 1.2em;
    border-inline-start: var(--line);

    .period {
      margin-block-end: 0.3em;
      font-family: var(--font-body);
      font-size: 0.72rem;
      font-weight: 600;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: var(--color-label);
    }

    .timetable {
      display: grid;
      grid-template-columns: max-content max-content;
      gap: 0.15em 1em;
      align-items: baseline;
      margin: 0;

      dt, dd { margin: 0; line-height: 1.6; }
      dt { color: var(--color-label); }
      dd { font-variant-numeric: tabular-nums; }
    }
  }

  /* 28rem is where the venue name stops fitting on one line beside a
   * 224px timetable: measured, 448px leaves it 199px and one line, and
   * 354px leaves it 109px and two. Stacked, the rule that separated the
   * columns lies across instead of down. */
  @container access (inline-size < 28rem) {
    flex-direction: column;

    /* The bases above are widths, and turning the axis makes them
     * heights: measured, a 192px tall venue block with 90px of nothing
     * between the address and the rule, and a 192px tall times block
     * holding 57px of timetable. Both go back to their content. */
    .m-exhibition-access-where,
    .m-exhibition-access-when {
      flex: 0 1 auto;
    }

    .m-exhibition-access-when {
      padding-inline-start: 0;
      border-inline-start: none;
      padding-block-start: 0.5em;
      border-block-start: var(--line);
    }
  }
}

.m-exhibition-section-info { float: inline-end; }

.m-exhibition-section-advertisement {
  margin-block-start: 1em;
  padding-block-start: 1em;
  text-align: center;
  border-block-start: var(--line);
}

/* Hover bubbles and info popups become wall labels too. */
/* Info popup: a wall label revealed by CSS alone — hover or keyboard
 * focus anywhere in the infobox, with a short delay both ways so it
 * doesn't flicker (this replaces the old jQuery bubble + fade). */
.m-exhibition-infobox { position: relative; }

.m-exhibition-infobox-trigger { cursor: pointer; }

.m-exhibition-infobox-popup {
  position: absolute;
  z-index: 50;
  font-family: var(--font-body);
  font-size: 0.8rem;
  line-height: 1.35;
  color: var(--color-mat-ink);
  background: var(--color-mat);
  border-block-start: 3px solid var(--color-brass);
  box-shadow: var(--shadow-placard);

  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s ease-out 0.2s, visibility 0.2s ease-out 0.2s;
}

.m-exhibition-infobox:hover .m-exhibition-infobox-popup,
.m-exhibition-infobox:focus-within .m-exhibition-infobox-popup {
  opacity: 1;
  visibility: visible;
}

.m-exhibition-download-poster {
  .m-exhibition-infobox-popup {
    /* below the trigger (the infobox is exactly the trigger's box),
       never over its text; the reveal delay covers the small gap */
    inset-inline-end: 0;
    inset-block-start: calc(100% + 0.3em);
    display: grid;
    /* left: the poster thumb spanning both rows;
       right: the text above the format icons */
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    gap: 0.4em 0.8em;
    align-items: center;
    inline-size: max-content;
    max-inline-size: 24em;
    padding: 10px;

    & > img {
      grid-row: 1 / -1;         /* -1 needs the explicit rows above */
      border: 1px solid var(--color-mat-ink);
    }

    & > p { margin: 0; text-align: center; }
  }

  .m-exhibition-format-selector {
    display: flex;
    justify-content: center;
    gap: 0.5em;
  }

  .m-exhibition-infobox-trigger {
    margin-block-start: 4px;

    /* Icon and label on one line: the download glyph is an inline SVG sized
       in em (emitted by the add-on's m:icon-download), so the trigger no
       longer needs a fixed gutter for a bitmap. */
    a {
      display: inline-flex;
      gap: 0.4em;
      align-items: center;
    }
  }
}

/* Current / previous dates, with the arrow toggler between them. Both
 * are query containers so the access block inside can ask how much room
 * it has: they are block boxes as wide as the description column, which
 * is the width that decides whether the venue and the times fit side by
 * side. The access block cannot ask about itself. */
.m-exhibition-date-current {
  position: relative;
  container: access / inline-size;
}

.m-exhibition-date-previous {
  position: relative;
  container: access / inline-size;

  hr { inline-size: 50%; }
}

.m-exhibition-date-toggler {
  position: absolute;
  inset-inline-start: 50%;
  inset-block-end: -6px;
  translate: -50% 0;           /* center on the 50% anchor */
  inline-size: 32px;
  block-size: 32px;
  visibility: visible;
  background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAABnhJREFUWMPlV1lsVFUY/s6593aWzj4du6EsKbSltBURUXCLuw/EB1IlYLDBFPXBF40PuAXDAxqDiWgwmhirRgMuD8Y1Ro0xAR/cQGVpLUsFW7rMtJ2lc2fmLv7nzHTaKcMSUWPiSc6ce9b/O9+/nH+A/3th57No27ZtDUyxnqLPRgZ21FTw+KMPP9o7e90zz2xtthnfSp/zqB6yTf7E5s2bj5/tbH4u4Vu2bHFGasKf33jDjeu67t20rCoS6eCm/dbsdbZtM5spuxsXNa25f9MDy6679vq7mWJ/RPsrLgiAy6Wt0tPp+XQwenp7EAwExPDlzz67dX4JS9u3NROM1oaGBvT+1ovmpsXQNLXF6VGvvCAANkd1TXUNHA4XCAh0PV24sTKnRJe2WSdayzKRSCTgdrtRX1cPZvLQBQGAieipoVPI5TKIjY0hnkgWhpmr1JhYJeechCepxpHNZnBqaBAWN8fPdrx6bhNUTiWTSaRSKVknJvLnZSYzX81cpaeMT51uhhMnf4dhmAQ2RmxlYCvKwF8C0HHXGtqr4NeDP2PJkhZMpifp4CxisTH09/eLJbm16+4srj/ce1C2ExMTaGpqwsjIsOwf+OmXHjoL7+5+n503gI6ODpeqcmPniztVKnjp5Z1IEQumZWFJyxI88diTYHQcEz+CfMZkX2h01ztvw7ZsRKNRMkIN3a91Y0PnBqOzs9PZ3d2tn9MGdqxXNrZrXw7X11SpiqKS7nPwerwk3EaajNC0DJimqKaswugsAmbRvG1bZJ0W5s6dh6GhYTgdDnCuYO6cGnVR5oORHeu1jWcNRM91IKQ61BOe+svd1sINxMQ6KSwYDJdsSiQm6Ma8cPPS6nA4S9YKcLt3vwnj0BsYP/bNpJExLn7oXcTKMsBVdZnX6zMSpgfz5i0QzibHBwf/wOjoMOLxcWnhs4ULIfI29J3LZclWcuQFWTkuxhoaGpG03fAFwoaQcUYVEJFtPq/XGdWd5Pw1IrpJFfx64BdJd9+RPoyPjyGZSuL7H76Th+/9do9c099/HMMjIxgYGEBfXx/+GDiJo0ePyDW1tfWIpR3EZMgpZJzRCDWFrfJ4/RXRWIVYLMcEpSuuuEoetGhhY/HWVyxfIdurV10jGVmwoKGsSkQJBoOI6Rp8taEKTeOr6KrbywKgCy/1+PwYTyvwVHqLtJarr3a/TkapI63rGBoexgNdXRR+G08TLsrI6BBG4xZ8wSqKmHxpWQZe3gRNT7F6Q/Oj5qIIhPsJ2k8Xntd/18aNshXB6bnnd+BwTw8WNzeVCDbIgI8fP4pj/UcQEIxW6LBsu17Iuu8V5EoATCbR4vH49VjC0hrlTchAeHnhU/XzL76SD08oFEImkymO/7T/e4xGR+QlRCwQpb2tFdH4Xrg9QT0RH26hoX0lABiUtkAoyEYTFuZftnAG/fyMarjtlptw+603yzXr7ulEW2srWilqqqqG1pZ2epA8xMwBOJ0uuDQXft/zNcKRapaMR8kQzX2zbMBe7vOHK4+MKFhZf/GMCHd6/fDjT8gjyMIpyCjiAaIoubS9XdrAlO8LRgbpMUokJ9C4aDGMoIUfkxbaqqorTxw7uJyWvVECQOV8hdcfYqP9FURpuKjLcgDuWL26rLFNlSQJTSQT8umuvqhaMuDwOjCaIk9YGGEK4yvEe1oCwLTR7PEFMa7n4CdPKC+cl3WzGVkRevoO0cOVlrqvratFwB+Eo6ICblclopMMXn8VDJJV4gUvrEWd6nSrIpansvmXbYyeU65wGcsFzVwptNQX7754KWVb6E/NOzQHGhuaZF/OM4USGR2mYZErZqEq5AwOj/rC2rG6B3dhQEbCHFPb/IFwNqunCLkib/J3FwFYHGvl0ghWVWeFzCIDjFtLA8Eqt5gEKiW14XCk4IY8f0NRBe2yzfcZzctvoRolPz89V+iLbzYd8S0jjXBVjXvwZJ8ISJ9JABrnK73+sGrocYpsOUrDn/7H/gcYmUn4QtWqpvCVRQbIay71BsIwooPoat6PpG6RUTLhiMISpxMP2Z9ORApZiXzT8vbISpIUuTdvzaR7Dq9bA7d88IfmkDrYpUUAlMFEuG3Ad8lVVAvZDSsILAGB6f5sMHldTgMp7pveMwUsnRyDZZqRIoBMjm3/8rP3HiFYGv6FQjaRyxp8+8yMSAAReb7//DLlCzMDkbtSPSm+WZkklf3DAOwCiP9G+ROgAIF8ThngzAAAAABJRU5ErkJggg==') no-repeat center center;

  span { visibility: hidden; }

  /* The hint. exhibition.js adds .is-hinted when the pointer arrives on
   * the current date, to say where the all-dates control is. It used to
   * be toggler.effect('frame'), a jQuery UI plugin that appended a div
   * to the body and animated its offset, size, border and opacity —
   * this is the same expanding, fading rectangle drawn by the element
   * itself, and it costs no library.
   *
   * The ring is an ::after so it can grow past the 32px button without
   * moving it, and it is inert to the pointer. */
  &.is-hinted::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    border: 0 solid var(--exh-hint-color, #c3daf9);
    animation: m-exhibition-hint 500ms ease-out;
  }
}

@keyframes m-exhibition-hint {
  from { inset: 0;      border-width: 0;    opacity: 1; }
  to   { inset: -20px;  border-width: 10px; opacity: 0; }
}

/* An attention flourish is exactly what reduced motion asks not to be
 * shown, and it carries no information the title attribute does not. */
@media (prefers-reduced-motion: reduce) {
  .m-exhibition-date-toggler.is-hinted::after { animation: none; content: none; }
}

.m-exhibition-format-selector a {
  img {
    margin: 7px;
    padding-block-end: 7px;
    border-block-end: none;
  }

  &:hover img {
    padding-block-end: 2px;
    border-block-end: 5px solid var(--color-accent);
  }
}

/* Compact "message" variant: a matted poster thumbnail beside a short
 * description — a flex pair, wrapping to a stack on narrow columns. */
.m-exhibition-message {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 3em;
  inline-size: fit-content;
  margin: 2em auto 0;

  .m-exhibition-message-poster {
    flex-shrink: 0;
    text-align: center;

    img {
      inline-size: 250px;
      max-inline-size: 100%;    /* the mat is 8px a side: below a 266px
                                   column the picture gives way too */
      padding: 8px;
      background: var(--color-mat);
      box-shadow: var(--shadow-placard);
    }
  }

  .m-exhibition-message-description {
    /* A ceiling, not a width. Stated as a width it also became this
     * block's minimum — a fixed-width child has a min-content of its own
     * width — and the fit-content wrapper above could not clamp below it:
     * measured at 320, the wrapper held 300px inside a 286px column and
     * finished 3px from the window edge. As a maximum the line still
     * settles at 300 wherever the text is longer than that, which is
     * everywhere it is used, and gives way when the column is narrower. */
    max-inline-size: 300px;
    align-self: flex-start;
  }
}

.m-exhibition-soon {
  h1 {
    margin-block: 0 1ex;
    border-block: var(--line);
  }

  p { text-align: start; }
}

/*== Misc (was MoXoW sass/main) =======================================*/
.m-custom-box { position: relative; }

#mxw-global-warning .m-warning {
  border: 3px solid #d00;
  background: #fdd url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAY1SURBVFjDtZdrjBZXGcd/Z+bMvPPOe9n7HfbCLrtQrgvdqv3QmLR8a1rrhQSjGCyhaloxmCoWUkM/VFNiI9o00Rg/mZh4SYwmxm9KbAHBbROktlpggd0XKFt232V5LzNzLn54d5fF4mXp8iRPnjPPnPP8f+eZSWaOsNZyN1b+ljhgXe+gI31sXHo5fNEeuKtC1tole+mbPF5+9SMVde6PVo0dtdHPd1TK+3nibmqJJXdgu3BLq93zwc7fdpvLb4A1OD0PEv1q95Vw9OJKfmH1Uso5S+3YbB875fDn2jAKW7yEnRmHpIq8f1dTuZ9dS623NIBDwnf81EtyyxdSpjAKMgWOjxk/iRx4xBcta17ikAjuGUAl4iveyJ48lSK2egPrBljHR5fex8y+hxzZnS3Fcu89AZg8JLImlXvB3fgZX0+cwgJWOFhHYBEkF4/hdD/oifb1z0/vF3XLDpCOeFaO7AnM1HlMeQqjFW7bAG77ENZoTGkKNfkO7vBOXzr+wWUFmH1ONGmv8Vl3YJunLp7A6AQcF9ncjWzpBdfDGEUy9jpO63pJx+anSwdE27IBJBHPew886emrZzCVIkbFyM4hEIAQyK61WJWgy0WSwpvIjdu9qg6+sywA1/eJLp1r3yNXPiCTSycxKkb4IbKpG7BgLV5LLyLIYnRCNHYCUdftio5NO67tE6s+NEDV8N1gy2c9NTGKqd7AqBivez2JVly+VuTy5AxKa1K9mzAqRkezRBeO4933mJ846e9/KICJvWK1U9f9adk65EbjpzAqxsnW4zV2MnuzzNcP/4Z9h39NqVzCa+zEzTVjVUI0Pgphg+N2bN429lWx6a4BEs3L4aZP+MnF49iohFExqb7NoBMaMg7GKKzW5AMHaxLSA8MYFaHjCtVzfyZY83BKiOCHdwVw9sti2G3se8TNtzlx4TRGxbgN7chcE9YkYBR1GUku7YBVYBK8fBNeUxdGxUSFv2GFFG7X5vvf/ZJ4aMkA2nIku25bKho7ho4rGJ2Q7h8Gk8x5TFPOoy70QEdgYtAJmaGtGJVgkojy2aOkekfSyjqvLAng7d3iIa9lYKvrp0R85S2sivHbepCZXE3IxKBjmvM+dRm3BqRjMBFekCLV2Ew8NU7p3T+hZt9Dtg72n35SPPZ/AygrXskOfDSsnj+GURFGKzL9m+dE4oXY2eCTlQlUp6DyPpSvQTRN/dBGjFEYYymdfY1035bQCucHHBLO/wR444viUdnW3+/YiHjyHEbFpFesxk35oCsQ34R4GiqTfOpjjXx8Qx5UCUx17l3QyDBD3eAwxkJSvIy+OYlsW9Ny8jyf/+8Ah4RjrThS17MurI4dR8dVrIrIrhqEeAaiGUhugqpgVMzP/nCGt8cmwdSEsbe8cd0IwkthLJQu/JVwxVAoHHn479uF/x8BTvyTHV7LqnZRnSKenkAnVTKr7sP1ZE3E6oVdnjhT4BuvvsbeI0c5fe7aQn4+ur5H09qttS6UpkmKE/htq7NFydN3BBh9SnjGcb/X0NUXVgunMRYcPyC/euPtu5sTGVyRo60hTVdzht6W9G3i8/MaBzfgBiHGQqXwFunWlWkj/W+//rjIfQBgdsZ5KmjtyVG5jqrMYnDIr92CI12sNVhrwBiYi815jzd/8klGf/wE+VAu5OejtQbhOrRsGMHgoOIq8fQEQfuAr0Jn/20Av9zemnVk8ELjyt4wLhbAC8ELCTt6MMpgtMZojdJqwbXSONaA0Wil0Gr+Xm2e1hqtDdmuHvBr9aLiVcLm9kD7ua/9fldrO4AUQojfbfefCTv6QweNCepxgnoACqdGWfhntiyM7dzYLsrPj7lD3st33ppjErIdq7zq2DsHhRDPSMBF20czuUzKGoMI66l96GsrxCJRFsGIO8HMRXEHMEvtDGKMxQ/TntbmYUBKQBZumkJd4ZLuGlzrOmEjzqLFdlEFsUhkXlDcoTMf6NgCiMComOlL/9BXZ/UY4EnAHj6uf/qcuD5yo/iXbld4QgjBvTCLxRhlr9xQ4y+etD+qIYELNAB9YcrtyAdusGizy2oC7I2KjsqxvgpcAK6LuUfmAmkgmLu+Ny249TSqc64WzoZCCOcei/87hLXW2qUfTpfZ/gU0rIYTkbcTTwAAAABJRU5ErkJggg==') no-repeat 4px center;
  min-block-size: 40px;
  padding: 0.5ex;
  padding-inline-start: 40px;    /* room for the warning icon */
  color: black;
}

/*== Header ===========================================================*/
/* The bar: the menu takes what it needs, the switcher closes the line.
 *
 * Both are IN FLOW. The switcher used to be position:absolute at the
 * top right corner of #mxw-page (which carries the layout's inline
 * position:relative) with a z-index to sit over whatever it landed on,
 * and that is what it did: the menu is a cluster that wraps, so at 320
 * the switcher was painted across the end of INFORMATION. Nothing was
 * gained by pinning it — it sits where the flow already puts it.
 *
 * The bar the switcher sits in, and the query container the names are
 * hidden by. Named, so that query cannot match a nearer container. */
#mxw-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  container: headerbar / inline-size;

  /* The menu wraps INSIDE itself rather than push the switcher onto a
     line of its own. The basis is 0, not auto: line breaking happens
     BEFORE shrinking, so a flex item asking for its content width takes
     the whole bar and sends the next item to the next line, however
     shrinkable it is. Asking for nothing and growing into what is left
     is what keeps the two on one bar. min-inline-size, because a flex
     child otherwise refuses to go under its longest tab. */
  & > #mxw-nav-menu {
    flex: 1 1 0;
    min-inline-size: 0;
  }

  /* to the far end. Not justify-content: space-between — the layout
     still emits a float-clearing div after the switcher, and
     space-between would hand the end of the bar to that empty box and
     strand the switcher in the middle. */
  & > #mxw-nav-lang-switcher { margin-inline-start: auto; }
}

/* The two flags are one row of choices, not a stack. Stacked, the
 * switcher stood 95px tall inside a 51px header and hung down into
 * the masthead band, leaving a flag floating beside the title. */
.mxw-lang-switcher {
  display: flex;
  gap: 0.75em;
  margin: 10px;
  padding: 0;
  list-style: none;

  & li { margin: 0; }


  /* Flag and name become flex items so the space between them can be a
     gap; the markup carries no separator. align-items also centres the
     flag on the text rather than sitting it on the baseline.

     The link, not the flag, carries the hit area: an 18x12 flag is half
     the 24px minimum on both axes, and under 30rem the flag is all
     there is to aim at. Same answer the other three sites give. */
  & a {
    /* the rest of the anchor's shape is in mxw-lang-switcher.css */
    justify-content: center;
    min-inline-size: 1.5rem;
    min-block-size: 1.5rem;
    font-family: var(--font-body);
    color: var(--color-label);
    /* the link wraps a flag image; an underline would run under it */
    text-decoration: none;
    border-block-end: 1px solid transparent;
    transition: color 0.2s ease-out, border-color 0.2s ease-out;
  }

  /* Which language you are READING, not just which ones exist.
     Both entries took the generic link gilt, so the switcher offered a
     choice and never answered it — and the flag cannot answer it
     either, being decoration with an empty alt. Marked the way
     #mxw-menu marks its selected tab, the two navs in this bar being
     one row of choices apiece: the quiet label steps up to gilt AND a
     gilt rule closes the line.

     Two cues rather than one, deliberately, and the RULE is the one
     that carries it: under 30rem the name is hidden and the flag is all
     that shows, where a text colour has nothing to colour. The rule
     sits under the link in both states.

     Reserving it as `transparent` on the other entries costs no layout
     and is a forced-colors trap — see the forced-colors block, which
     names both navs. */
  & > li.active > a {
    color: var(--color-gilt);
    border-block-end-color: var(--color-gilt);
  }

  /* Hover and focus brighten the OTHER language — the one a click would
     get. Brightening the current one too would spend the only mark that
     answers the question. */
  & > li:not(.active) > a:is(:hover, :focus-visible) {
    color: #efe9dc;
    border-block-end-color: var(--color-hairline);
  }
}

/* Under 30rem of header the names go and the flags stay. The threshold
   is the header's, not the viewport's: this sheet is shared by four
   sites and the header is the box that actually holds the switcher. */
@container headerbar (inline-size < 30rem) {
  & .mxw-lang-name {
/* Heard but not seen: the flag's alt is empty by design, so this
   span IS the link's accessible name. display:none would take it
   out of the accessibility tree and leave an unnamed link. */
position: absolute;
inline-size: 1px;
block-size: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
  }
}

/* Touch: 24px is the floor, 44px is the working size. */
@media (pointer: coarse) {
  .print-specs-link {
    min-inline-size: 2.75rem;
    min-block-size: 2.75rem;
  }
}

/*== Menu =============================================================*/
/* In flow at the top of the page (the old absolute 4px/4px corner
 * pinning belonged to the icon-tab design): a quiet row of tracked
 * capitals with room to breathe, as in the design mockup. */
#mxw-menu {
  display: flex;
  /* a cluster: the row reflows onto a second line rather than running
   * off the edge — the last tab overshot 320px by 8px */
  flex-wrap: wrap;
  gap: 0.2rem;
  margin: 0;
  padding: 0.6rem 0.8rem;
  list-style: none;

  & > li > :first-child {
    display: block;
    padding: 6px 10px 5px;
    font-family: var(--font-body);
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-label);
    text-decoration: none;
    border: none;
    border-block-end: 1px solid transparent;
    transition: color 0.2s ease-out, border-color 0.2s ease-out;
  }

  & > li.active > :first-child {
    color: var(--color-gilt);
    border-block-end-color: var(--color-gilt);
  }

  & > li:hover > :first-child,
  & > li > :first-child:focus-visible {
    color: #efe9dc;
    border-block-end-color: var(--color-hairline);
  }
}

/*== Footer ===========================================================*/
/* "Cartel de sortie": the hairline is interrupted at its center by a
 * small brass lozenge — the ornament marking the end of the show —
 * then one quiet line of tracked capitals. */
#mxw-footer {
  position: relative;
  margin-block-start: 1.2rem;
  padding: 1.4rem 1.5rem;
  text-align: center;

  /* the hairline, with a 28px central gap for the lozenge */
  &::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: 1px;
    background: linear-gradient(to right,
      var(--color-hairline) calc(50% - 14px), transparent calc(50% - 14px),
      transparent calc(50% + 14px), var(--color-hairline) calc(50% + 14px));
  }

  /* the brass lozenge, centered on the hairline */
  &::after {
    content: "";
    position: absolute;
    inset-block-start: -3px;
    inset-inline-start: calc(50% - 3.5px);
    inline-size: 7px;
    block-size: 7px;
    rotate: 45deg;
    background: var(--color-brass);
  }

  & .mxw-footer-pageinfo {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.4rem 2rem;
    margin: 0;
    padding: 0;
    font-family: var(--font-body);
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    list-style: none;
    /* A step quieter than --color-label — but the wall behind it is a
     * FIXED gradient, so what this line sits on is decided by the window
     * height, not by where the footer is in the page. On a tall window
     * the footer lands on the lit patch instead of the shadow, and there
     * #8d8371 measured 3.11:1 (4.11 on the mid band, 4.71 on the wall
     * itself, the #mxw-page wash counted in). Reproduced at 1280x1400 on
     * all three home pages, and at 1280x900 on et-la-lumiere-fut, whose
     * page is shortest. #b0a591 is 4.78 on the lit patch and 7.25 on the
     * wall, and still the step down from the labels' 5.67 / 8.59. */
    color: #b0a591;
  }

  & a {
    color: var(--color-label);
    text-decoration: none;
    transition: color 0.2s ease-out;

    &:hover, &:focus-visible { color: var(--color-gilt); }
  }
}

/* Whole-line gaps inside a two-up block, so a column break leaves both
 * columns on the same baseline grid. The theme usual 7.68px paragraph
 * gap is not a multiple of the 27.2px line, and put the history block
 * on two grids 19px apart. */
.two-up :is(p, dd) { margin-block: 0 var(--baseline); }

/* A gallery in a column of prose says which text it goes with, and the
 * air around it says the same. Two kinds of air, and the difference
 * matters more than the amount:
 *
 *   the NEAR side, against the text it belongs to: half a line, as
 *   padding on the gallery. It is the bond, and it never goes away.
 *
 *   the FAR side, against text it does not belong to: a whole line, as a
 *   margin on THAT text. A margin beside a column break is truncated
 *   where padding is not, so this line removes itself exactly when the
 *   gutter has already done the separating, or when there is no such
 *   text at all.
 *
 *   with-text-above   near above, far below
 *   with-text-below   near below, far above
 *   with-text-both    near on both sides, no far side
 *   with-text-none    far on both sides, no bond. What it gets unasked
 *
 * Totals: six lines for the three that have a far side, five for
 * with-text-both, and one less wherever a far side has been truncated.
 * All whole, which is the point. A picture pushes the text under it in
 * its own column by exactly what it occupies while the other column
 * carries on where it was, so a half line anywhere in that sum would put
 * the two columns half a line apart. Left to itself a strip is 120px
 * against a 27.19px line, which is 4.41, and they came out 11px and 23px
 * apart. */
.two-up mxw-gallery {
  padding-block: calc(var(--baseline) / 2);

  /* The same statement decides where a column may break. A gallery that
   * belongs to the text above must not be parted from it by the gutter,
   * and one that belongs to the text below must not be parted from
   * that: measured at 1100px one strip was left at the head of a column
   * with its paragraph at the foot of the one before, and at 1000px
   * two were. A gallery that belongs to neither may break anywhere,
   * which is the whole difference between saying so and not. */
  &.with-text-above {
    padding-block: calc(var(--baseline) / 2);
    break-before: avoid;
  }

  &.with-text-below {
    padding-block: calc(var(--baseline) / 2);
    break-after: avoid;
  }

  /* belongs to neither, so there is no bond to keep: both sides are
   * far sides, carried by the neighbours */
  &.with-text-none { padding-block: 0; }

  /* both: tight on each side, and the only one of the four that spends a
   * single line rather than two. Still whole, so the column still lands
   * back in step. */
  &.with-text-both {
    padding-block: calc(var(--baseline) / 2);
    break-before: avoid;
    break-after: avoid;
  }

}

/* The paragraph hands its space to the gallery under it, or the gap
 * would be the paragraph's whole line plus the gallery's own. */
.two-up :is(p, dd):has(+ mxw-gallery) { margin-block-end: 0; }

/* The far side of a picture's air: the line that holds it clear of text
 * it does not belong to. It sits on that text, as a margin, rather than
 * under the picture as padding, and the difference is what happens at a
 * column break.
 *
 * Padding survives a break; a margin beside one is truncated. So when
 * the gutter falls between a picture and the text after it, this line
 * disappears by itself -- the text is at the head of the next column,
 * where nothing needs holding off, and the picture ends its column
 * flush. When nothing follows at all, there is no element to carry it
 * and the same thing happens. Six lines when it is needed, five when it
 * is not, both whole. */
.two-up mxw-gallery:is(.with-text-above, .with-text-none) + * {
  margin-block-start: var(--baseline);
}

.two-up :is(p, dd):has(+ mxw-gallery:is(.with-text-below, .with-text-none)) {
  margin-block-end: var(--baseline);
}

/* A strip in a block is four lines tall, so that with its two lines of
 * air it comes to six and the column lands back on the grid. It also
 * moves whole: left to fragment it was cut across the gutter, half its
 * pictures in each column. */
.two-up mxw-gallery[layout="strip"] {
  --mxw-gallery-strip-height: calc(4 * var(--baseline));

  /* A whole line between rows as well. In a column narrow enough to
   * wrap the strip, the component gap of 1em is not a multiple of
   * the line, so a second row of photographs put the block on nine
   * baseline phases: each row is four lines and each gap one, so
   * any number of rows still lands on the grid. */
  row-gap: var(--baseline);
  margin-block: 0;
  break-inside: avoid;
}
.two-up :is(p, dd):last-child { margin-block-end: 0; }

/*== Content ==========================================================*/
/* Two-up: a short block set in two columns.
 *
 * This buys a readable measure without narrowing the page -- splitting
 * 1150px gives about 60 characters a line where the full width gives
 * 124 -- and without the wobbling silhouette a centred narrow column
 * produced, since both row types keep the same outer edges.
 *
 * It only works while BOTH columns fit on one screen: the reader's trip
 * back to the top of the second column has to be an eye movement, not a
 * scroll. On this page the tallest such block is 287px per column
 * against a 900px viewport, so there is room to spare -- but a section
 * that grows past a screenful should drop the class rather than keep it.
 * Single-column sections sit beside two-up ones without looking odd,
 * because nothing about the outer edges changes. */
/* Section figures. The picture belongs to its heading, so the two are
 * grouped; the class on the <img> chooses how it sits. Floating is not
 * among the choices: the text below is a multicol block, and multicol is
 * a formatting-context root, so it lines up BESIDE a float instead of
 * flowing round it -- which is what looked wrong.
 *
 *   .figure-band      a cropped strip the width of the section, above
 *                     the columns. Suits a landscape picture; crops a
 *                     portrait hard.
 *   .figure-plate     above the columns at its own size, centred. Every
 *                     shape survives, at the cost of vertical space and
 *                     air either side of a portrait.
 *   .figure-heading   small, on the heading own line. Suits a portrait
 *                     and costs almost nothing; too small to carry a
 *                     picture worth looking at.
 *
 * Sizes are custom properties so a page can tune them per section. */
.section-figure { display: block; margin-block: 0.8em 0; }

  /*
   * above a multicol .two-up (columns: 46ch) -- a float sits BESIDE
   * the columns, not flowed round, so these three are the fits
   *
   *   .figure-band       .figure-plate  .figure-heading
   *  ┌───────────────┐   ┌────────┐   text   ┌────┐
   *  │///////////////│   │  plate │   wraps  │ img│
   *  └───────────────┘   └────────┘   here   └────┘
   *
   *   inline: 100%,      block: 8em,         max-block-size:
   *   ratio 2.39 / 1     inline: auto,       4.5em, on the
   *   capped at 35vh     margin-inline:      heading own line;
   *   (--figure-band-    auto (--figure-     capped at 33% of
   *   max); cover at a   plate-height, 8em);  it (--figure-
   *   chosen --figure-   every shape         heading-share)
   *   band-focus         survives
   */
.figure-band {
  /* air below, so the text starts clear of the picture rather than hard
   * against it; --figure-band-gap tunes this band alone */
  margin-block-end: var(--figure-band-gap, var(--figure-gap));
  inline-size: 100%;

  /* A panorama, not a ruler-fixed ribbon (2026-08-05; block-size was
   * 11em). The ratio keeps ONE framing at every width: the em band
   * cropped 75% of a 3:2 picture on desktop but 55% on a phone, so no
   * two readers saw the same picture. The cap keeps the band from
   * taking more than about a third of a desktop screen; under it the
   * crop widens back toward the ribbon. What the crop keeps is chosen
   * per photograph: every band img sets --figure-band-focus, so
   * nothing is cropped blind. */
  block-size: auto;
  aspect-ratio: 2.39 / 1;
  max-block-size: var(--figure-band-max, 35vh);
  object-fit: cover;
  object-position: var(--figure-band-focus, 50% 50%);
}

.figure-plate {
  inline-size: auto;
  block-size: var(--figure-plate-height, 8em);
  margin-inline: auto;
}

/* Something that shares the heading's line: a small figure, or a card
 * like an operator's logo. One role, so the arithmetic is stated once
 * whatever the thing turns out to be -- the heading takes what is left,
 * the companion sits on the heading's baseline, and it never takes more
 * than --figure-heading-share of the line, because it is an accent and
 * not the subject.
 *
 * It is allowed to shrink (flex 0 1), which it was not: with the share
 * capped and no shrink, a wide companion simply overflowed. */
.section-head:has(.beside-heading) {
  display: flex;
  align-items: end;
  gap: 1.5em;

  & > :first-child { flex: 1 1 auto; }

  & > .beside-heading {
    box-sizing: border-box;
    flex: 0 1 auto;
    max-inline-size: var(--figure-heading-share, 33%);
    margin-block: 0 0.4em;
  }
}

/* A picture on a heading line is an accent, not the subject, so it never
 * takes more than a third of the line. Both axes are maxima and both
 * sizes are auto, which is what makes it scale down whole: whichever
 * limit binds first, the other follows and the picture keeps its shape.
 * Give it a definite height instead and a narrow container squashes it.
 *
 * A portrait at 4.5em is a twentieth of a wide column and a fifth of a
 * phone, so the cap never bites; a landscape one, or a card like a
 * sponsor logo, reaches 72% at 320px without it. The width limit itself
 * comes from .beside-heading above. */
.figure-heading {
  inline-size: auto;
  block-size: auto;
  max-block-size: var(--figure-heading-height, 4.5em);
}


/* The way out of a room: the closing block of a page, pointing at
 * another room. No heading, because it is not a section of this page; a
 * rule and some air are enough to say the reading is over and the door
 * is here.
 *
 * It is also the container the strip below measures against, so the
 * thumbnails pick their column count from THIS block rather than the
 * window, and are still right in a narrower column.
 *
 * It lived in the nacelles stylesheet while one page of one site had a
 * doorway, on the rule that it would move here the day a second
 * exhibition grew one. carnaval-venitien did. */
.doorway {
  container: doorway / inline-size;
  margin-block-start: 2.6em;
  padding-block-start: 1.5em;
  border-block-start: var(--line);
}

/* The invitation's thumbnails, as a strip across it rather than a block
 * floated beside it. The float had to go: the invitation text is a
 * two-up block, and a multicol block is a formatting-context root — it
 * lines up BESIDE a float instead of flowing round it.
 *
 * The column count is stepped, not auto-fit: eight pictures only make
 * full rows at 8, 4 or 2 across, and auto-fit would cheerfully pick 7
 * and leave an orphan on a line of its own. Every step is a divisor of
 * eight, so the strip stays rectangular. A strip of a different length
 * sets --strip-columns itself. The steps are read from the doorway's
 * width, not the window's. */
  /*
   * .gallery-strip  grid-template-columns:
   *   repeat(var(--strip-columns), minmax(0, var(--strip-frame-size, 9rem)))
   *
   *  doorway <= 28rem       doorway > 28rem        doorway > 58rem
   *  --strip-columns: 2     --strip-columns: 4     --strip-columns: 8
   *  □ □                    □ □ □ □                □ □ □ □ □ □ □ □
   *  □ □                    □ □ □ □
   *  □ □
   *  □ □
   *  4 rows x 2 cols         2 rows x 4 cols         1 row x 8 cols
   *
   * every step (2, 4, 8) divides 8, so the eight pictures always fill
   * whole rows -- never the orphan a plain auto-fit could leave
   */
.gallery-strip {
  --strip-columns: 2;

  /* frames fill their track and take their height from the 3:2 of the
   * pictures, instead of the fixed box the grid layout assumes */
  --mxw-gallery-gap: 1ex;
  --mxw-gallery-frame-width: 100%;
  --mxw-gallery-frame-height: auto;
  --mxw-gallery-frame-ratio: 3 / 2;

  display: grid;
  /* A ceiling on the track, not a share of the row: without it the step
   * from 8 across to 4 doubled the pictures, and a strip that changes
   * SIZE that much reads as a different thing rather than the same
   * thing rearranged. Capped, the thumbnail stays about 130px at every
   * width and only the shape of the block changes. */
  grid-template-columns: repeat(var(--strip-columns), minmax(0, var(--strip-frame-size, 9rem)));
  justify-content: center;
  gap: var(--mxw-gallery-gap);

  /* The same air a section figure leaves under itself: these pictures
   * introduce the invitation the way a band introduces its section. */
  margin-block-end: var(--figure-gap);

  /* cover, not contain: the mat ribbon is drawn on the picture itself,
   * so the box left inside it is 8px short on each axis and no longer
   * exactly 3:2 — contain would letterbox against the mat and show a
   * sliver of it down the long edges. What cover crops instead is about
   * a pixel top and bottom. Give it landscape pictures: a portrait one
   * cropped to 3:2 loses more than half its height. */
  & img { object-fit: cover; }

  @container doorway (inline-size > 28rem) { --strip-columns: 4; }
  @container doorway (inline-size > 58rem) { --strip-columns: 8; }
}


.two-up {
  /* Do not cut a paragraph until at least four lines have been set.
   * That is the rule; orphans is how CSS spells it, counting the lines
   * left at the FOOT of a column, where widows counts those carried to
   * the HEAD of the next. The names are the easiest thing here to get
   * backwards, and they decide opposite ends of the same break.
   *
   * Two are allowed to come over, because the paragraph has already
   * earned its four lines before the cut and what follows is a
   * continuation the reader is looking for, not an arrival they have to
   * make sense of. Measured on the flight page it turns 3+4 into 5+2 and
   * 4+4 into 5+3; the info page has no cut paragraph at any two-column
   * width and is untouched.
   *
   * Chrome only: caniuse has Firefox at no support in any version, 2 to
   * 155, with the Mozilla bug still open. Firefox therefore sees the
   * unguarded break, which is what these pages looked like until now, so
   * nothing may depend on it. Do not raise it much either: asked for six
   * either side, Chrome turned a 5+3 split into 7+1, an unmeetable
   * constraint being abandoned rather than approximated. */
  orphans: 4;
  widows: 2;

  /* A column WIDTH, not a count: the browser fits as many columns as
   * there is room for and drops to one by itself, so no breakpoint is
   * needed and the collapse happens per block -- a block sitting
   * beside a floated photograph has less room and gives up its second
   * column earlier than one that has the full width. Expressed in ch
   * because what matters is the measure, not a pixel count. */
  /* Justified, which two columns and hyphens: auto make workable --
   * measured worst gap 1.9x a normal space at desktop, 2.6x on a
   * phone where the block is single-column and narrowest. */
  text-align: justify;

  columns: 46ch;
  column-gap: 2.5em;



  /* a question is never parted from its answer, nor a description
   * from the photographs that illustrate it -- those sit inside the
   * description, so break-inside keeps the pair together */
  & dt { break-after: avoid; }
  & dt, & dd { break-inside: avoid; }
}

#mxw-content {
  /* The reading line, shared by everything that has to sit on the same
   * baseline grid. Stated in rem rather than 1lh because 1lh resolves
   * against each element own line-height, and the questions in a
   * definition list are set larger than the prose. 1.7rem is the prose
   * line: 1.6 leading at the 1.0625rem reading size. */
  --baseline: 1.7rem;

  /* Half a line under a picture, or a row of them, that introduces the
   * text beneath it: enough to detach the two, not enough to disown
   * them. Half rather than whole is safe wherever the picture sits
   * OUTSIDE a two-up block, since it moves both columns down together
   * and cannot put them out of step. It is a token because the section
   * figures and the invitation strip have to agree; tune it in one
   * place or they drift. */
  --figure-gap: calc(var(--baseline) / 2);

  position: relative;
  max-inline-size: 70em;        /* the gallery column */
  margin-inline: auto;
  padding: 1em;
  /* ragged-right: justification dug loose lines in the narrower
   * columns (description, floats); hyphenation stays to tighten the
   * rag (the pages carry lang, so it works in both languages) */

  /* Long-form reading: a step larger than the 16px base; face and
   * leading come from the body default. */
  font-size: 1.0625rem;
  hyphens: auto;

  /* definition lists (e.g. city guides) as titled paragraphs — data
   * dls are excluded: the access timetable, and readouts like the
   * flight instruments, which carry their own layout */
  & dl:not(.timetable, .readout) dt {
    margin-block: 1em 0.3em;
    font-family: var(--font-display);
    font-variant: small-caps;
    letter-spacing: 0.05em;
    font-size: 1.15rem;
    color: var(--color-gilt);

    &:first-child { margin-block-start: 0.4em; }
  }
    /* On the grid inside a two-up block: a question takes a whole line
     * and the gaps are whole lines, so a column break leaves both
     * columns in step. Stated here, beside the rules it replaces --
     * from outside it could not out-specify them. */
    & dl.two-up:not(.timetable, .readout) dt {
      margin-block: var(--baseline) 0;
      line-height: var(--baseline);

      &:first-child { margin-block-start: 0; }
    }

  & dl:not(.timetable, .readout) dd {
    margin-inline-start: 1em;
  }

  /* local terms carrying a transliteration tooltip */
  & .latin {
    cursor: help;
    text-decoration: underline dotted rgb(239 233 220 / 0.5);
    text-underline-offset: 3px;
  }

  /* The pair sizes to whichever of the two is wider, so the label can
   * never end up a few pixels inside the title's edges — a near-miss
   * reads as a mistake where an obvious difference does not. */
  .masthead {
    /* A one-column grid, not a fit-content block with auto margins.
     * Both forms say the same thing -- size the pair to whichever of
     * the two is wider, then centre it -- but the block form makes the
     * centring depend on shrink-to-fit and auto margins resolving
     * together, and Firefox put the result over to the left where
     * Chrome centred it. Here the track does the sizing and
     * justify-content does the centring, and neither needs the other.
     * fit-content(100%), not max-content: a long title still has to
     * wrap rather than push out of the column. */
    display: grid;
    grid-template-columns: fit-content(100%);
    justify-content: center;
    /* stated here rather than only on the title, so everything the
     * masthead carries is centred by being in it */
    text-align: center;
  }

  /* Entrance cartel: the show's name carried in a short rule above the
   * room's. It mirrors the exit cartel in the footer, where the same
   * hairline is broken by a brass lozenge — one device, both ends of
   * the page. Capped well inside the measure so it reads as a label
   * around a name, not as another section divider. */
  .maintitle-show {
    --tracking: 0.24em;
    /* Three tracks rather than a flex row. A flex container holding
     * grow items was the second place this stylesheet asked an engine
     * to derive a width from flexed children, and Firefox still put
     * the label left of centre after the masthead itself was fixed. A
     * grid derives its intrinsic width from the track minimums, which
     * the two engines agree on, and the fr tracks still hand the rules
     * whatever room is left over. */
    display: grid;
    grid-template-columns: minmax(2.5rem, 1fr) auto minmax(2.5rem, 1fr);
    align-items: center;
    gap: 1.1em;
    margin: 0 0 0.3em;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: var(--tracking);
    text-transform: uppercase;
    color: var(--color-brass);

    /* The rules take the name's own colour, not the divider hairline:
     * they belong to the label, not to the page's section grid. And
     * 2.5rem is their floor, not their length — they grow to meet a
     * title wider than the label. ch and % are no use in that minimum,
     * since both resolve against this element's own 0.7rem. */
    &::before,
    &::after {
      content: "";
      border-block-start: 1px solid var(--color-brass-edge);
    }

    & span {
      /* Letter-spacing lays its space after the LAST letter as well, so
       * the word sits in a box a whole tracking wider than its ink, and
       * centring that box leaves the ink hugging the left rule -- 2px
       * here, which the eye reads as a mistake. An equal indent at the
       * start puts the ink back in the middle. */
      padding-inline-start: var(--tracking);
    }
  }

  .maintitle {
    --tracking: 0.05em;
    margin: 0 0 0.5ex;
    font-family: var(--font-display);
    font-size: xx-large;
    font-weight: 600;
    font-variant: small-caps;
    letter-spacing: var(--tracking);
    color: var(--color-gilt);
    text-align: center;
    /* the same trailing-space correction as the cartel above; padding
     * rather than text-indent so a title that wraps shifts every line */
    padding-inline-start: var(--tracking);
    border: none;
  }

  & h1 {
    margin-block: 1.4em 0.8em;
    padding-block: 0.35em;       /* air between the text and its rules */
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    border-block: var(--line);
  }

  :first-child > h1 { margin-block-start: 0; }

  /* Sections one level down: same face and size, but ruled underneath
   * only. h1 sits in a full band of two rules, h2 rests on one — the
   * level reads from how much furniture the heading carries, without
   * shrinking type that is still a section heading. (h1 keeps the band
   * for pages that head their sections with it and have no room name
   * of their own, the front page among them.) */
  & h2 {
    margin-block: 1.4em 0.8em;
    padding-block: 0 0.35em;
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    border-block-end: var(--line);
  }

  :first-child > h2 { margin-block-start: 0; }

}

/* Maps and charts hang as framed documents on the wall (their inner
 * captions and axis text read in mat ink, not the wall's white). */
mxw-map,
mxw-climate-chart {
  color: var(--color-mat-ink);
  border: 1px solid #0c0a08;
  box-shadow: var(--shadow-placard);
}

/* the chart sits on a mat; the map fills its frame edge to edge */
mxw-climate-chart {
  padding: 10px;
  background: var(--color-mat);
}

/* Checkout: text plaques instead of the 2010 icon buttons. */
.cart-checkout-validate,
.cart-checkout-empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  inline-size: auto;
  block-size: auto;
  padding: 0.45em 1em;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: bold;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  cursor: pointer;
  opacity: 1;
  background-image: none;
  border-radius: 2px;

  & span { visibility: visible; }
  & i { font-size: 0.95em; }
}

.cart-checkout-validate {
  color: var(--color-mat-ink);
  background: linear-gradient(to bottom,
    var(--color-brass-hi), var(--color-brass));
  border: 1px solid var(--color-brass-edge);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.55),
              0 2px 6px rgb(0 0 0 / 0.5);
  transition: filter 0.2s ease-out;

  &:hover, &:focus-visible { filter: brightness(1.12); }
}

.cart-checkout-empty {
  color: var(--color-label);
  background: transparent;
  border: var(--line);
  transition: color 0.2s ease-out, border-color 0.2s ease-out;

  &:hover, &:focus-visible {
    color: var(--color-gilt);
    border-color: var(--color-gilt);
  }
}

/* Empty-basket hint (replaces the old step-by-step ordering guide): a
 * quiet centred prompt pointing at the per-photo panel. */
.cart-empty {
  padding: 2em 1.2em;
  text-align: center;
  color: var(--color-mat-ink-muted);   /* was #7a6d5a: 4.17:1 on mat */

  & > i {
    font-size: 2.4rem;
    color: var(--color-brass);
    opacity: 0.75;
  }
  & p { margin-block: 0.35em 0; }
  & .cart-howto-paths {
    margin: 0.8em 0 0;
    padding: 0;
    list-style: none;
    text-align: start;    /* two actions read as rows, not as a
                             centered ragged paragraph */
    font-size: 0.82rem;
    line-height: 1.45;

    & li {
      display: grid;
      grid-template-columns: 1.6em 1fr;
      column-gap: 0.5em;
      align-items: start;
      padding-block: 0.35em;

      & + li { border-block-start: 1px solid rgb(36 31 26 / 0.08); }
      & i {
        margin-block-start: 0.15em;
        justify-self: center;
        color: var(--color-brass);
      }
    }
  }
  & .cart-empty-title {
    margin-block-start: 0.6em;
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-mat-ink);
  }
}

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

/* The theme animates only background-colors and the enter-button
 * reveal: switch them off for reduced-motion users. */
@media (prefers-reduced-motion: reduce) {
  .m-exhibition-enter,
  #mxw-menu > li > :first-child,
  .mxw-lang-switcher a,
  #mxw-footer a,
  .amazon img,
  .cart-item,
  .cart-checkout-validate,
  .cart-checkout-empty,
  .m-exhibition-infobox-popup {
    transition: none;
    translate: none;
  }
}



/* ====================================================================
 * Gallery (<mxw-gallery> web component)
 * ====================================================================
 * The component ships neutral in a cascade layer; the theme decorates
 * it from outside: grid thumbnails hang as small matted prints, strip
 * thumbnails get the mat ribbon border. Knobs first, direct rules for
 * what has no knob. */

/* Photos wear the mat ribbon directly — grid and strip alike; the
 * grid frame stays a bare layout cell, the border hugs the picture. */
/* the mat ribbon width, as a token so layouts that compute frame sizes
 * (e.g. .gallery-by-4) can account for it; set on the gallery so those
 * rules can read it */
mxw-gallery {
  --mxw-gallery-accent: var(--color-brass);
  /* fa-image bookends on the thumb resizer, small-to-large */
  --mxw-gallery-resizer-icon: "\f03e";
  --mxw-gallery-resizer-icon-font: "Font Awesome 7 Pro";
  --mxw-gallery-resizer-icon-weight: 900;
  /* lightbox: cream mat around the enlarged print, wall-label caption */
  --mxw-gallery-lightbox-mat: var(--color-mat);
  --mxw-gallery-lightbox-caption-font: var(--font-body);
  --mxw-gallery-lightbox-caption-color: var(--color-label);
}
mxw-gallery { --mxw-gallery-border-width: 4px; }

/* the floating thumb-resizer rides the section heading: lift it from
 * the gallery top into the h1 border band (h1 margin + centring) */
mxw-gallery.with-resizer-floating { --mxw-gallery-resizer-raise: 30px; }

/* The mat ribbon, defined once and worn by both the gallery thumbnails
 * and floated content photos (.mat-frame), so the two always read
 * identically. (.mat-frame sits outside a gallery, so it takes the 4px
 * fallback; the border-box keeps the ribbon inside the cell/size.) */
.mat-frame,
mxw-gallery mxw-photo img {
  box-sizing: border-box;
  border: var(--mxw-gallery-border-width, 4px) solid var(--color-mat);
  border-radius: 0.5ex;
  transition: border-color 0.2s ease-out;
}

/* The ribbon lights up to say the picture goes somewhere, so only when
   it actually does: a mat inside a link, or a gallery thumbnail. A
   figure that is just a figure stays put under the pointer. */
a .mat-frame:hover,
mxw-gallery mxw-photo:hover img { border-color: var(--color-gilt); }

/* Per-photo order slip (cart.js): a panel over the picture bottom
 * listing each print size with -/quantity/+ controls, revealed on hover.
 * The modern re-build of the old thumb-add panel. */
/* Quick add: gilt cart button in the picture corner, shown on hover
 * or keyboard focus — one click adds the default format. */
mxw-gallery mxw-photo .mxw-cart-quick {
  position: absolute;
  inset-block-end: 8px;
  inset-inline-end: 8px;
  z-index: 6;
  display: grid;
  place-items: center;
  inline-size: 30px;    /* integer px: fractional em sizes leave
                           asymmetric antialiasing on so small a
                           circle (and FF rounds axes apart) */
  aspect-ratio: 1;      /* not a block-size: FF rounds fractional em
                           w/h separately and the circle goes oval */
  padding: 0;
  font-size: 13px;
  color: var(--color-mat-ink);
  cursor: pointer;
  background: linear-gradient(160deg, var(--color-brass-lit), var(--color-brass));
  background-clip: padding-box;   /* keep the light gradient from
                                     fringing past the border curve */
  border: none;             /* ring via inset shadow: a bordered
                               radius fringes the light gradient
                               past the curve in Firefox */
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--color-brass-edge),
              0 1px 3px rgb(0 0 0 / 0.45);
  opacity: 0;
  transition: opacity 0.15s ease-out;
}
mxw-gallery mxw-photo:hover .mxw-cart-quick,
mxw-gallery mxw-photo .mxw-cart-quick:focus-visible { opacity: 1; }
mxw-gallery mxw-photo .mxw-cart-quick:hover {
  color: #241f1a;
  box-shadow: inset 0 0 0 1.5px var(--color-gilt),
              0 1px 3px rgb(0 0 0 / 0.45);
}

mxw-gallery mxw-photo {
  & .mxw-cart-panel {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 5;
    display: none;
    font-family: var(--font-body);
    font-size: 0.7rem;
    color: var(--color-mat-ink);
    background: rgb(239 233 220 / 0.94);           /* mat board, sheer */
    border-block-start: 2px solid var(--color-brass);
    box-shadow: var(--shadow-placard);
  }
  &:hover .mxw-cart-panel,
  & .mxw-cart-panel:hover { display: block; }

  & .mxw-cart-panel table { inline-size: 100%; border-collapse: collapse; }
  & .mxw-cart-panel td { padding: 0.15em 0.35em; vertical-align: middle; }
  & .mxw-cart-desc { text-align: start; white-space: nowrap; }
  & .mxw-cart-price { margin-inline-start: 0.35em; color: #6d6152; }
  & .mxw-cart-qty { padding: 0; }
  & .mxw-cart-count {
    display: grid;
    place-items: center;
    inline-size: 1.7rem;
    block-size: 1.55rem;  /* same rem as the buttons: equal heights */
    font-variant-numeric: tabular-nums;
    background: rgb(255 255 255 / 0.5);
    border-block: 1px solid var(--color-mat-rule);
  }
  & .mxw-cart-variant.has-qty { font-weight: bold; }
  & :is(.a-inc, .a-dec) {
    inline-size: 1.7em;
    text-align: center;
    color: var(--color-mat-brass);
    cursor: pointer;

    &:hover { color: var(--color-gilt); }
  }

  /* panel actions: quick-add and remove-all, below the size rows */
  & .mxw-cart-actions {
    display: flex;
    gap: 0.35em;
    padding: 0.3em 0.35em;
    border-block-start: 1px solid rgb(138 109 51 / 0.3);

    & button {
      padding: 0.25em 0.4em;
      font: inherit;
      color: var(--color-mat-brass);
      background: none;
      border: 1px solid var(--color-mat-rule);
      border-radius: 2px;
      cursor: pointer;
      transition: color 0.15s ease-out, border-color 0.15s ease-out;
    }
    & .a-add { flex: 1 1 auto; }
    & button:hover, & button:focus-visible {
      color: var(--color-gilt);
      border-color: var(--color-gilt);
    }
  }

  /* In-cart marker: a gilt "reserved" tick pinned to the print corner
   * (shown by .in-cart). Pointing at the reserved print — or focusing the
   * mark — arms it into a red ✕ that removes the whole photo. */
  & .mxw-cart-mark {
    position: absolute;
    /* straddle the corner: shift out by half the mark so its centre sits
     * on the corner point (fallback anchors to the frame; see below) */
    inset-block-start: -0.6em;
    inset-inline-end: -0.6em;
    z-index: 6;
    display: none;
    place-items: center;
    inline-size: 24px;   /* integer px, as .mxw-cart-quick */
    aspect-ratio: 1;    /* same rounding guard as .mxw-cart-quick */
    padding: 0;
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 1;
    color: var(--color-mat-ink);
    background: linear-gradient(160deg, var(--color-brass-lit), var(--color-brass));
    border: none;             /* ring via inset shadow, as the
                                 quick-add: no radius fringe */
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px var(--color-brass-edge),
                0 2px 5px rgb(0 0 0 / 0.5),
                inset 0 1px 0 rgb(255 255 255 / 0.5);
    cursor: pointer;
    transition: background 0.15s ease-out, color 0.15s ease-out,
                transform 0.12s ease-out;

    & .rest { font-weight: 900; }
    & .act  { display: none; font-weight: 700; }
  }
  &.in-cart .mxw-cart-mark { display: grid; }

  /* point at the reserved print → the tick arms into a red remove ✕ */
  &.in-cart:hover .mxw-cart-mark,
  & .mxw-cart-mark:focus-visible {
    color: #fff;
    box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.35),
                0 2px 5px rgb(0 0 0 / 0.5);
    background: radial-gradient(circle at 35% 30%, #e24a3b, #b0201a 72%);
    transform: scale(1.12);

    & .rest { display: none; }
    & .act  { display: block; }
  }
}

@media (prefers-reduced-motion: reduce) {
  mxw-gallery mxw-photo .mxw-cart-mark { transition: none; }
  mxw-gallery mxw-photo .mxw-cart-quick { transition: none; }
  mxw-gallery mxw-photo.in-cart:hover .mxw-cart-mark,
  mxw-gallery mxw-photo .mxw-cart-mark:focus-visible { transform: none; }
}

/* The discs draw themselves out of a gradient and an INSET shadow ring —
 * the photo-disc recipe in CSS.md, where a real border was what fringed
 * the rim in Firefox. Forced colours removes both: measured in Chromium
 * with forced-colors: active, .mxw-cart-quick came back
 * background-image: none, box-shadow: none, border-width: 0 — a 30px
 * hole over the print, and the award seal a glyph with nothing under it.
 *
 * There the rim trouble cannot arise (no gradient is left to fringe), so
 * the ring becomes a border and the disc takes a system surface. The
 * selectors match the ones they override; a bare class would lose to
 * them. box-sizing is border-box throughout, so the 30px stays 30px. */
@media (forced-colors: active) {
  mxw-gallery mxw-photo :is(.mxw-cart-quick, .mxw-cart-mark),
  .acq-tariff li.signee::after {
    background-color: ButtonFace;
    border: 1px solid ButtonText;
  }

  /* Both header navs mark their current entry with a rule and reserve
     the same rule in `transparent` on the others, so the mark costs no
     layout. Forced colours replaces EVERY colour, transparent included:
     measured in Chromium, all three menu tabs and both languages came
     back with a 1px LinkText rule under them, and a bar where
     everything is marked marks nothing.
     Canvas is the backdrop's own colour, so the reserved rule keeps its
     1px and stops being visible, while the current entry stays named in
     a system colour. */
  #mxw-menu > li:not(.active) > :first-child,
  .mxw-lang-switcher > li:not(.active) > a {
    border-block-end-color: Canvas;
  }
  #mxw-menu > li.active > :first-child,
  .mxw-lang-switcher > li.active > a {
    border-block-end-color: LinkText;
  }
}

/* Grid frames are fixed boxes with the picture letter-boxed inside, so the
 * corner of mxw-photo isn't the corner of the picture. Where anchor
 * positioning is available, pin the marker to the real picture
 * (--mxw-gallery-pic, as the popover caption does); the frame-corner
 * fallback above stands otherwise. */
@supports (anchor-name: --x) {
  mxw-gallery mxw-photo .mxw-cart-mark {
    position-anchor: --mxw-gallery-pic;
    inset-block-start: auto;
    inset-inline-end: auto;
    top: calc(anchor(top) - 0.6em);
    right: calc(anchor(right) - 0.6em);
  }
}

/* The lightbox order slip: cart.js slots ONE wall-label card
 * (slot="lightbox") into the zoom dialog, hung beside the enlarged
 * print like a museum label — constant width whatever the thumbnail
 * was, and buying works on touch. The rows speak the tariff placard's
 * voice: text-face format, dotted leader, display-face price, the
 * signed edition on its gilt-tinted row. */
mxw-gallery > .mxw-cart-slip {
  inline-size: 24em;     /* a proper side panel: the typeset rows,
                            pill stepper and totals need real room */
  max-inline-size: calc(100dvw - 2em);
  padding: 1.1em 1.3em 1em;
  font-family: var(--font-body);
  font-size: 0.875rem;   /* 14px base: the panel reads at body size */
  color: var(--color-mat-ink);
  text-align: start;
  background: var(--color-mat);
  border: 1px solid var(--color-brass-edge);
  border-block-start: 3px solid var(--color-brass);
  border-radius: 2px 2px 3px 3px;
  box-shadow: var(--shadow-placard);

  & .mxw-cart-slip-eyebrow {
    margin: 0;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--color-mat-brass);
  }
  & .mxw-cart-slip-title {
    margin: 0.1em 0 0.7em;
    font-family: var(--font-display);
    font-size: 1.45rem;
    font-weight: 600;
    color: var(--color-mat-ink);
  }

  & table { inline-size: 100%; border-collapse: collapse; }
  & .mxw-cart-variant td {
    padding-block: 0.5em;
    vertical-align: middle;
  }
  & .mxw-cart-desc {
    padding-inline-end: 0.5em;
    font-family: var(--font-text);
    font-size: 1rem;
    white-space: nowrap;
  }
  & .mxw-cart-lead {
    border-block-end: 1px dotted rgb(36 31 26 / 0.32);
  }
  & td.mxw-cart-lead {
    inline-size: 100%;
    border: none;    /* leaders stay in the footer only: at card
                        width the row leader degrades to crumbs */
  }
  & .mxw-cart-price {
    padding-inline: 0.5em 0.7em;
    text-align: end;
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  /* the stepper: remove / count / add joined into one pill */
  & .mxw-cart-ctl button {
    display: grid;
    place-items: center;
    inline-size: 1.8rem;    /* rem: the em would track the button font,
                               not the slip, and the pill middle (sized
                               by the slip font) would sit taller */
    block-size: 1.8rem;
    padding: 0;
    font-size: 0.85rem;
    color: var(--color-mat-brass);
    cursor: pointer;
    background: none;
    border: 1px solid var(--color-mat-rule);

    &:hover, &:focus-visible {
      color: var(--color-brass);
      background: rgb(255 255 255 / 0.55);
      border-color: var(--color-brass);
    }
  }
  & .mxw-cart-ctl:has(.a-dec) button {
    border-start-start-radius: 999px;
    border-end-start-radius: 999px;
    border-inline-end: none;
  }
  & .mxw-cart-ctl:has(.a-inc) button {
    border-start-end-radius: 999px;
    border-end-end-radius: 999px;
    border-inline-start: none;
  }
  & .mxw-cart-qty { padding: 0; }
  & .mxw-cart-count {
    display: grid;
    place-items: center;
    inline-size: 2rem;
    block-size: 1.8rem;   /* same rem as the buttons: equal heights */
    font-variant-numeric: tabular-nums;
    background: rgb(255 255 255 / 0.5);
    border-block: 1px solid var(--color-mat-rule);
  }

  & .mxw-cart-desc::before {   /* dot slot always reserved: content
                                  appearing must not shift the row */
    content: "";
    display: inline-block;
    inline-size: 0.45em;
    aspect-ratio: 1;
    margin-inline-end: 0.4em;
    vertical-align: 0.08em;
    background: transparent;
    border-radius: 50%;
  }
  & .mxw-cart-variant.has-qty {
    & .mxw-cart-desc::before { background: var(--color-brass); }
    & .mxw-cart-count { font-weight: 700; color: var(--color-mat-brass); }
  }

  /* the signed edition, on its gilt-tinted row like the placard */
  & .mxw-cart-variant.is-signed {
    background: color-mix(in oklch, var(--color-gilt) 12%, transparent);

    & .mxw-cart-desc {
      font-family: var(--font-display);
      font-size: 1.1rem;
      font-weight: 600;
    }
    & .mxw-cart-price { font-size: 1.15rem; font-weight: 700; }
  }

  & .mxw-cart-slip-foot {
    display: flex;
    align-items: baseline;
    gap: 0.5em;
    margin: 0.85em 0 0;
    padding-block-start: 0.6em;
    font-size: 0.8rem;
    color: var(--color-mat-ink-muted);
    border-block-start: 1px solid rgb(36 31 26 / 0.16);

    & .mxw-cart-lead { flex: 1; translate: 0 -0.25em; }
    & b {
      font-family: var(--font-display);
      font-size: 1.1rem;
      font-weight: 700;
      font-variant-numeric: tabular-nums;
      color: var(--color-mat-ink);
    }
  }
}

/* Reserve a label column beside the enlarged print on wide screens
 * (the caps pierce the component shadow as custom properties); on
 * narrow ones the slip wraps under the photo and the dialog scrolls.
 *
 * The threshold is in rem because the reservation is in em. `30em` is
 * counted on the picture, so it grows with the reader's font size while
 * a pixel breakpoint does not, and the two drift apart exactly where it
 * hurts: measured at a 24px default font, the rule engaged at 900px and
 * left the enlarged print 135px wide beside a 504px label. In rem the
 * two move together — 56rem is 896px for a reader at 16px, 1344px for
 * one at 24px, and in both cases it is the width at which the 30em
 * column and a picture of at least 26em both fit. */
@media (width >= 56rem) {
  mxw-gallery {
    --mxw-gallery-lightbox-img-max-inline: calc(100dvw - 30em);
  }
}

/* The popover caption as a wall label floating off the print: dark
 * card, brass hairline, a breath of blur — the component owns its
 * anchoring and reveal, the theme only paints it. */
@supports (anchor-name: --x) {
  mxw-gallery[captions="popover"] mxw-photo
      :is([slot="headline"], [slot="description"]) {
    background: linear-gradient(rgb(40 36 30 / 0.92), rgb(20 18 14 / 0.92));
    border: 1px solid rgb(182 147 74 / 0.6);      /* brass */
    box-shadow: 0 0.4em 1.2em rgb(0 0 0 / 0.55);
    backdrop-filter: blur(3px);
  }
}

/*== Acquisition panel (exhibition "visit" print sales) ==============*
 * Flat "cartel": a small print sample + a dotted-leader tariff + the
 * signed edition highlighted + the buy action, in one light panel.
 * Scoped to class="acquisition". The tariff is a STATIC price list
 * (informational — ordering is per-photo in the gallery + the floating
 * basket); keep its figures in sync with sc_pricing (data.php). */
/* The invitation line lives on the wall, above the tariff card — the
 * card itself is purely the chooser. It leads the prose, so it is set
 * larger than the prose: at 0.98rem it was 15.7px against a 17px column,
 * a standfirst receding from the text it introduces. */
.acq-standfirst {
  /* 37em holds the line to the 720px it has always been measured at,
   * now that the em it is counted in is a bigger one. */
  max-inline-size: 37em;
  margin: 0.4rem 0 1rem;
  font-size: 1.15em;
  line-height: 1.45;
  color: var(--color-label);
  text-wrap: pretty;

  & .print-specs-link { color: var(--color-gilt); }
  & .print-specs-link:hover { color: var(--color-brass-lit); }
}

  /*
   * .acquisition  flex, flex-wrap: wrap; container: acquisition/inline-size
   *
   *  card >= 49rem                     card < 49rem
   *  ┌─────────┬────────────────┐      ┌───────────────────────┐
   *  │ acq-lead│   acq-tariff   │      │       acq-lead        │
   *  │ (cues)  │  chip chip chip│      ├───────────────────────┤
   *  └─────────┴────────────────┘      │  chip    chip    chip │
   *                                    └───────────────────────┘
   * lead 245px + gap 2em + tariff 505px = 49rem card, the wrap point
   *     (15.3rem)  (2.1rem)   (31.6rem)
   *
   * chip grid: 3-up above 31.6rem of CARD, 1-col stacked below it --
   * the same 31.6rem, so the two thresholds cannot disagree
   */
.acquisition {
  /* The cues beside the chips, and under them when the card cannot hold
   * both. It was two grid tracks and a window query, and a grid cannot
   * wrap: the switch had to be stated as a width, the width stated was
   * the window's, and the two did not line up. Measured on /visit/, the
   * chips gave up their third column at 860 while the tracks held to
   * 848, so between those the card showed two chips and an orphan.
   *
   * The Sidebar pattern instead, where the wrap IS the switch and the
   * numbers are the ones the content actually has: the cues shrink-wrap
   * to 245px, the gap is 2em, and three chips need 505px (three 9.5em
   * tracks and two 0.6em gaps, in the card's own 17px em). 15.3 + 2.1 +
   * 31.6 is 49rem, so under 49rem of CARD — not of window, so it is
   * still right in a narrower column — the two can no longer share a
   * line and the chips take the next one, still three abreast.
   *
   * grow 999 on the chips is what keeps the cues at their content width
   * while they share the line: every spare pixel goes to the chips, and
   * the 21em cap is left for a cue block longer than this one. */
  display: flex;
  flex-wrap: wrap;
  gap: 1em 2em;
  align-items: center;
  margin-block: 1.1em 1em;
  padding: clamp(0.8rem, 2vw, 1.1rem) clamp(0.9rem, 2.4vw, 1.4rem);
  color: var(--color-mat-ink);
  background: var(--color-mat);
  border: 1px solid var(--color-brass);
  border-radius: 4px;

  /* the chips ask the card how much room it has, never the window */
  container: acquisition / inline-size;
}
/* the offer wrapper is markup only: the row wants the cues and the
   chips as its items */
.acquisition > .acq-offer { display: contents; }
.acq-offer { min-inline-size: 0; }

/* tariff: each format joined to its price by a dotted leader */
/* The chooser: three format chips in a row — the checked one is the
 * quick-add default. Selection wears the brass frame + gilt tint; the
 * radio itself is visually hidden, the chip is the control (keyboard
 * focus rings the chip). */
/* Lead-in inside the card: two icon cues — the formats popover
 * trigger, and the quick-add role of the checked chip. */
.acq-lead {
  margin: 0;
  padding: 0;
  /* The cues are a block of two short lines, not a banner: shrink-wrapped
   * to their longest line while they stand beside the chips, which a
   * basis of auto against the chips' grow 999 gives for nothing. The cap
   * is for a cue block longer than this one. */
  flex: 1 1 auto;
  max-inline-size: 21em;
  list-style: none;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--color-mat-ink-muted);

  & li {
    display: grid;
    grid-template-columns: 1.5em 1fr;
    column-gap: 0.45em;
    align-items: baseline;
    padding-block: 0.15em;

    & i { justify-self: center; color: var(--color-brass); }
    & .print-specs-link { justify-self: start; }
  }

  /* Under the chips rather than beside them, the cues are a full-width
   * band and not a column, so they sit at either end of it instead of
   * huddling at the left, and wrap back to a stack when the two no
   * longer fit abreast. 49rem is the same arithmetic the wrap above
   * uses, so the band arrives on exactly the line the cues drop to —
   * the two mechanisms cannot disagree because they count the same
   * three numbers. */
  @container acquisition (inline-size < 49rem) {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.15em 1.5em;
    max-inline-size: none;
  }
}

.acq-tariff {
  /* 31.6rem is what three chips need — three 9.5em tracks and two 0.6em
   * gaps, 505px in the card's 17px em. As a basis it is also what makes
   * the cues drop to their own line rather than squeezing the chips to
   * two: the row wraps as soon as 245 + 34 + 505 no longer fits. grow
   * 999 takes every spare pixel afterwards, which is what leaves the
   * cues at their content width. */
  flex: 999 1 31.6rem;
  min-inline-size: 0;

  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5em, 1fr));
  gap: 0.6em;
  margin: 0;
  padding: 0;
  list-style: none;

  & label {
    display: grid;
    gap: 0.1em;
    justify-items: center;
    padding: 0.7em 0.6em 0.6em;
    text-align: center;
    cursor: pointer;
    background: rgb(255 255 255 / 0.45);
    border: 1px solid rgb(138 109 51 / 0.35);
    border-radius: 4px;
    transition: border-color 0.15s ease, background 0.15s ease;
  }
  & li:hover label { border-color: var(--color-brass); }

  /* the signed edition stands apart: gilt frame + a gilt award seal
     straddling the top-right corner (the photo-mark idiom) — the
     tint wash drowned in the mat, a corner object does not. Rows
     keep the shared sizes so the three chips stay aligned. */
  & li.signee { position: relative; }
  & li.signee label {
    border-color: var(--color-gilt);
  }
  & li.signee::after {
    content: "\f559";           /* fa-award, solid face */
    position: absolute;
    inset-block-start: -10px;
    inset-inline-end: -10px;
    display: grid;
    place-items: center;
    inline-size: 26px;           /* the photo-disc recipe: integer px,
                                    aspect-ratio, inset-shadow ring */
    aspect-ratio: 1;
    font: 900 12px/1 "Font Awesome 7 Pro";
    color: var(--color-mat-ink);
    background: linear-gradient(160deg, var(--color-brass-lit), var(--color-brass));
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px var(--color-brass-edge),
                0 1px 3px rgb(0 0 0 / 0.45);
  }
  & li.signee .tag  { color: var(--color-mat-brass); }

  & input[name="format"] {
    position: absolute;
    opacity: 0;               /* the chip is the visible control */
  }
  & li:has(input:checked) label {
    /* border grows 1px: shave it off the padding so nothing shifts */
    padding: calc(0.7em - 1px) calc(0.6em - 1px) calc(0.6em - 1px);
    background: color-mix(in oklch, var(--color-gilt) 14%, var(--color-mat));
    border: 2px solid var(--color-brass);
  }
  & li:has(input:focus-visible) label {
    /* the ring sits on mat board: brass would be 2.39:1, under the 3:1
     * that 1.4.11 asks of a focus indicator */
    outline: 2px solid var(--color-mat-brass);
    outline-offset: 2px;
  }

  & .fmt {
    font-family: var(--font-body);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-mat-ink-muted);
  }
  & .dim { font-family: var(--font-text); font-size: 0.98rem; }
  & .prix {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  & .tag {
    font-family: var(--font-body);
    font-size: 0.6rem;
    font-style: normal;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-mat-brass);
  }

  /* Below the width that holds three, the chips stop being a row of
   * cards and become full-width lines. The same 31.6rem as the basis
   * above, and it has to be: auto-fit would otherwise pass through two
   * abreast and an orphan on a line of its own, which is the state this
   * card should never show. Three, then one each to a line, nothing in
   * between. It used to fire at a 45rem WINDOW, which was a card of
   * about 39rem — the chips were being folded away with 120px of room
   * still under them. */
  @container acquisition (inline-size < 31.6rem) {
    grid-template-columns: 1fr;

    & label {
      grid-template-columns: max-content 1fr max-content;
      column-gap: 0.6em;
      align-items: baseline;
      justify-items: start;
      text-align: start;
    }
    & .prix { justify-self: end; }
    & .tag  { grid-column: 1 / -1; }
  }
}

/* Both of the window queries that used to stand here are gone: the card
 * now wraps on its own account and the chips ask it, not the window, how
 * much room they have. See .acquisition and .acq-tariff above. */

/* Print presentation ("Les tirages"): a mat-board placard opened as a
 * native popover from the tariff intro. Its window shows the three
 * formats hung on the dark wall at TRUE relative proportions (1cm =
 * --ps-unit, fluid so the whole set scales down on narrow viewports),
 * so the size difference between a 10-euro photo and the signed 40x60
 * dibond is seen, not read. */
.print-specs-link {
  padding-inline: 0;
  padding-block: 2px;        /* measured: 21.6px of text, so 1px a side
                                came to 23.6 and missed the 24 of 2.5.8
                                by a rounding error. 2 makes it 25.6. */
  font: inherit;
  color: var(--color-mat-brass);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  background: none;
  border: none;
  cursor: pointer;
}
/* gilt would drop to 1.8:1 here — on mat, hover darkens instead */
.print-specs-link:hover { color: var(--color-mat-ink); }

.print-specs {
  /* 83 = 75cm of prints + 8cm of gaps; keep the set inside the card */
  --ps-unit: clamp(3.6px, (92vw - 5.5em) / 83, 0.34em);

  inline-size: min(36em, 92vw);
  max-block-size: 90dvh;
  overflow: auto;
  padding: 1.1em 1.4em 1.2em;
  color: var(--color-mat-ink);
  background: var(--color-mat);
  border: none;
  border-block-start: 3px solid var(--color-brass);
  border-radius: 2px 2px 3px 3px;
  box-shadow: var(--shadow-placard);

  &::backdrop {
    background: rgb(10 8 6 / 0.55);
    backdrop-filter: blur(3px);
  }

  /* entry: rise from the wall (discrete-display transition) */
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.2s ease-out, translate 0.2s ease-out,
              display 0.2s allow-discrete, overlay 0.2s allow-discrete;
  @starting-style { opacity: 0; translate: 0 0.6em; }

  & .ps-close {
    float: inline-end;
    margin-inline-start: 1em;
    padding: 0 0.2em;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--color-mat-brass);
    background: none;
    border: none;
    cursor: pointer;
  }
  & .ps-close:hover { color: var(--color-gilt); }

  & .ps-eyebrow {
    margin: 0 0 0.2rem;
    font-family: var(--font-body);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--color-mat-brass);
  }
  & .ps-title {
    margin: 0 0 0.9rem;
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.05;
    border: none;
  }

  /* The wall window. A grid with one column per format and dedicated
   * rows — rail, size, price, edition tag — so the prints hang from a
   * shared baseline and every caption line aligns across formats. */
  /*
   * .ps-wall  grid-template-rows: 1fr auto auto auto   row-gap: 0.12em
   *          1                2                 3          <- grid-column
   *                                         ┌──────────┐      ┐
   *                        ┌────────┐       │          │      │ row 1  1fr
   *       ┌──────┐         │        │       │   big    │      │ (.ps-print,
   *       │ small│         │ larger │       │          │      │  align-self:
   *       │      │         │        │       │          │      │  end)
   *    ┄┄┄└──────┘┄┄┄┄┄┄┄┄┄└────────┘┄┄┄┄┄┄┄└──────────┘┄┄┄┄┄┄┘  shared rail
   *       20x30, 24EUR     30x45, ...       40x60, ...        row 2  .ps-size
   *       STANDARD         STANDARD         SIGNED            row 3/4  b / i
   *
   * column-gap: var(--ps-unit) * 4      inline-size: ps-w * ps-unit
   * --ps-unit: 1cm at true scale        aspect-ratio: ps-w / ps-h
   * page sets --ps-w/--ps-h inline;     defaults 20 / 30 when it forgets
   */
  & .ps-wall {
    position: relative;
    display: grid;
    grid-template-rows: 1fr auto auto auto;
    row-gap: 0.12em;
    justify-content: safe center;  /* start-aligned when the set overflows, so the scroll reaches the left edge */
    column-gap: calc(var(--ps-unit) * 4);
    padding: 2.2em 1.2em 0.9em;
    overflow-x: auto;
    background: var(--color-wall)
      radial-gradient(120% 100% at 50% 0%,
        var(--color-spotlight), var(--color-wall) 75%);
    border-radius: 2px;
  }
  & .ps-sample,
  & .ps-sample figcaption { display: contents; }
  & .ps-sample:nth-of-type(1) :is(.ps-print, .ps-size, b, i) { grid-column: 1; }
  & .ps-sample:nth-of-type(2) :is(.ps-print, .ps-size, b, i) { grid-column: 2; }
  & .ps-sample:nth-of-type(3) :is(.ps-print, .ps-size, b, i) { grid-column: 3; }
  & .ps-print {
    display: block;
    grid-row: 1;
    align-self: end;
    justify-self: center;
    margin-block-end: 0.5em;
    /* --ps-w/--ps-h are set inline on the element by the page. A page
       that forgets them used to get an invalid aspect-ratio and a
       zero-width box, silently; these are the documented defaults. */
    inline-size: calc(var(--ps-w, 20) * var(--ps-unit));
    aspect-ratio: var(--ps-w, 20) / var(--ps-h, 30);
    box-shadow: 0 3px 8px rgb(0 0 0 / 0.5);
  }
  & .ps-print img {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    border: 3px solid #fff;
    box-sizing: border-box;
  }
  & .ps-signed .ps-print img { outline: 1px solid var(--color-gilt); }
  & .ps-size {
    grid-row: 2;
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--color-label);
  }
  & .ps-sample figcaption b {
    grid-row: 3;
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--color-mat);
    font-variant-numeric: tabular-nums;
  }
  & .ps-sample figcaption i {
    grid-row: 4;
    font-style: normal;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-gilt);
  }
  & :is(.ps-size, .ps-sample figcaption b, .ps-sample figcaption i) {
    justify-self: center;
    line-height: 1.4;
    text-align: center;
  }
  & .ps-scale {
    position: absolute;
    inset-block-start: 0.6em;
    inset-inline-end: 0.9em;
    margin: 0;
    font-family: var(--font-body);
    font-size: 0.68rem;
    font-style: italic;
    letter-spacing: 0.06em;
    color: rgb(191 180 158 / 0.85);
  }

  & .ps-matter {
    margin: 1rem 0 0;

    & dt {
      margin-block-start: 0.6em;
      font-family: var(--font-display);
      font-size: 1.02rem;
      font-weight: 600;
    }
    & dd {
      margin: 0.15em 0 0;
      font-size: 0.9rem;
      line-height: 1.5;
    }
  }
  & .ps-foot {
    margin: 1rem 0 0;
    padding-block-start: 0.7rem;
    font-family: var(--font-body);
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--color-mat-ink-muted);
    border-block-start: 1px solid rgb(36 31 26 / 0.16);

    & a { color: var(--color-mat-brass); text-underline-offset: 2px; }
  }
}

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

} /* @layer theme */
