/* ============================================================
   ALINA SZAPOCZNIKOW — Expositions index : Liste + Galerie
   Loaded on expositions.html only (like home.css on index.html). Replaced the
   old Grille/Liste split (the .exh-toolbar / .exh-grid / .exh-card path in
   wireframe.css, still used by actualites.html). Origin: the prototype in
   _prototypes/expositions-index/, itself built from the reference in
   _references/expositions index prototype/. Engine: expo-index.js.

   LISTE   = archivio-uno row rollover   (grid-template-rows 0fr → 1fr, pure CSS), the preview
             floating over the rows below since v110 (meeting 1 Oct: the list never moves)
   GALERIE = centrephotogeneve card, sticky-stacked by default, image entière
   FICHE   = bespoke side panel (header · title · dates over image | fields+desc),
             overlapping the index at 85% (NOT the shared fiche.js — it stacks the
             image as a full-width hero, unreadable at this width).

   The toolbar sticks UNDER the site topbar (var(--topbar-h) from tweaks-apply.js);
   the sticky-stack cards clear topbar + toolbar.

   ⚠ CLASS NAMESPACING — do not remove. wireframe.css already owns
   .reveal .row .yr .hide .on .note .meta; `.reveal{opacity:0}` is only
   lifted by the reveal-on-scroll observer, so anything reusing that name
   lays out and paints nothing. Everything here is prefixed x*.
   ============================================================ */

.xsheet { padding: 0 var(--xedge, 10px); --xedge: 10px; }

/* ONE image scale for every list reveal. Sizing method (shared by all four lists):
   fix the HEIGHT, let width:auto + object-fit:contain keep the true aspect ratio —
   the archive mixes portrait sculpture shots with landscape installation views, so a
   common height gives a tidy baseline without ever cropping. Source is M_ (815px) in
   every case, so 240px is well within resolution. Change the scale here, once. */
:root { --xthumb: 240px; }

.xhead { padding: clamp(18px, 3.5vh, 40px) 0 4px; }
.xhead h1 { margin: 0; font-size: clamp(1.8rem, 4vw, 3rem); letter-spacing: .01em; }
.xhead p  { margin: 6px 0 0; font-family: var(--ui); font-size: var(--fs-meta); color: var(--ph-ink); }

/* ---- the page's TOOL, in the menu bar, like FR/EN (Seba 02.10) ----
   Liste/Galerie, the order (one toggle: the current order shows, a click flips it), the
   Galerie's columns, the type of actualité. It sits before FR/EN, set like it: mono, quiet,
   the chosen value in ink. tweaks-apply.js measures the bar: if it can't hold everything, the
   menu goes behind the menu button (.compact), then the tool goes into that panel too
   (.compact-tools, phones). Nothing stays at the bottom of the screen (meeting 1 Oct). */
.xtools { display: flex; align-items: baseline; gap: 6px 16px; flex-shrink: 0;
  font-family: var(--ui); font-size: var(--fs-meta); letter-spacing: .05em; }
.topbar > .xtools { margin-left: auto; }                       /* the right-hand group: the tool, then FR/EN */
/* a bar that carries a tool spaces its groups a little closer (40 → 28px at most), so the MacBook
   (1512px) keeps its menu in the bar beside the tool (measured 02.10: 24px short with 40px gaps) */
.topbar:has(> .xtools), .topbar:has(> .topnav > .xtools) { gap: clamp(16px, 2vw, 28px); }
@media (max-width: 340px) {   /* the smallest phones keep wireframe.css's 10px (320px overran with 16) */
  .topbar:has(> .xtools), .topbar:has(> .topnav > .xtools) { gap: 10px; }
}
.topbar > .xtools ~ .lang { margin-left: 0; }
body[data-view] .xsheet { padding-bottom: clamp(24px, 4vh, 48px); }
.xtools .xgrp { display: flex; gap: 6px; align-items: baseline; }
.xtools .sep { color: var(--rule); }
.xtools button { font: inherit; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--mut); white-space: nowrap; letter-spacing: .05em; }
.xtools button:hover { color: var(--ink); }
.xtools button.is-on { color: var(--ink); font-weight: 600; }
/* one toggle (expo-index.js flips it), as wide as its longer label whichever shows, so using the
   tool never changes the bar's layout */
.xtools .xsort { display: grid; }
.xtools .xsort button { grid-area: 1 / 1; justify-self: start; }
.xtools .xsort button:not(.is-on) { visibility: hidden; }
.xtools .gal-only { display: none; }
body[data-view="gallery"] .xtools .gal-only, .xtools.xmeasure .gal-only { display: flex; }   /* xmeasure: tweaks-apply.js sizes the bar for it */
.xtools .xsel-wrap { position: relative; display: flex; align-items: baseline; }
.xtools .xsel { color: var(--ink); }
.xtools .xsel-ar { margin-left: 6px; color: var(--mut); }
.xtools .xmenu { position: absolute; top: calc(100% + 16px); right: 0; z-index: 41;   /* drops from the bar */
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px; min-width: 13rem;
  padding: 12px 16px 14px; background: var(--bg); border: 1px solid var(--rule);
  box-shadow: 0 10px 30px rgba(26,26,26,.10); }
.xtools .xmenu[hidden] { display: none; }
/* in the menu-button panel (phones): its own row above the links */
.topnav > .xtools { flex-wrap: wrap; padding: 14px 2px; border-bottom: 1px solid var(--rule); font-size: 0.98rem; }
.topnav > .xtools .xmenu { left: 0; right: auto; top: calc(100% + 8px); }

/* ============================================================
   LISTE — archivio-uno mechanism, pure CSS
   ============================================================ */
.xlist { display: flex; flex-direction: column; }
.xitem { border-bottom: 1px solid var(--rule); }
.xitem:first-child { border-top: 1px solid var(--rule); }
.xitem.xhide { display: none; }

.xrow {
  display: grid;
  grid-template-columns: 4.4rem minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, .9fr) 10.5rem 1rem;
  column-gap: 20px; align-items: baseline;
  /* no horizontal inset: row text sits on the same 10px axis as the brand + section bars */
  padding: 7px 0; text-decoration: none; color: var(--ink);
  transition: background-color 160ms ease, opacity 160ms ease;
}
/* keyboard: the row the keyboard is on (:focus-visible), never one a mouse click left focused —
   :focus-within kept a clicked row lit and its preview open after the record closed (v110). Not
   the row a closing record hands the focus back to (.xquiet, tweaks-apply.js): closed with Esc,
   the browser counts that focus as keyboard focus and pinned its preview open over the list.
   Each :has() rule stands ALONE: in a list with :hover, a browser without :has() (Firefox ESR 115,
   Safari < 15.4) drops the whole rule, hover included (review 02.10). */
.xitem:hover > .xrow { background: var(--wash); opacity: .55; }
.xitem:not(.xquiet):has(> .xrow:focus-visible) > .xrow { background: var(--wash); opacity: .55; }
/* HOVER INTENT (see the .xrev note below) — the row state waits for the same rest delay,
   so a sweep across the list doesn't strobe a trail of highlights behind the pointer. */
.xitem:hover > .xrow { transition-delay: var(--xhover-intent, 160ms); }
/* an exhibition with no image, text or works: not clickable, no hover (client 3 Sept) */
.xitem.xstatic > .xrow { cursor: default; }
.xitem.xstatic:hover > .xrow { background: none; opacity: 1; }
.xitem:not(.xquiet):has(> .xrow:focus-visible) > .xrow { transition-delay: 0s; }
.xrow .xyr    { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); }
.xrow .xttl   { font-family: var(--body); font-size: var(--fs-body); }
.xrow .xlieu,
.xrow .xville,
.xrow .xtype  { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.xrow .xtype  { text-align: right; }
.xrow .xtick  { font-family: var(--ui); font-size: .6rem; color: var(--ph-ink); text-align: right; }

/* THE PREVIEW FLOATS OVER THE ROWS BELOW (meeting 1 Oct, v110). In the flow it pushed the next
   rows down, so the row you were heading for ran away under the pointer (Alexandra: "c'est pas
   possible de déplacer sa souris et que le truc il monte"). Now the list never moves: the preview
   lies over the rows below, on the right, where their year and title stay readable, and the
   pointer goes straight through it (pointer-events: none) to the next row, whose preview takes
   over. So nothing in it is a link: a click on the ROW opens the record. It opens below its row,
   or above it when the screen has no room below (.xup, measured on the preview's own height by
   tweaks-apply.js). Width per list: --xpeek-w (home.css sets Collections and Publications). */
.xitem { position: relative; }
/* THE MECHANISM: auto height animated as a grid track. The images inside load only once it
   opens, as they did when it was in the flow. The shadow is a filter, so a closed preview casts
   none; the frame is on the panel inside, so a closed preview shows no hairline. */
.xrev {   /* as wide as what it holds, up to --xpeek-w: works alone leave no empty band beside them */
  position: absolute; top: 100%; right: 0; z-index: 20; width: max-content; max-width: var(--xpeek-w, 56%);
  display: grid; grid-template-rows: 0fr; pointer-events: none;
  filter: drop-shadow(0 10px 22px rgba(26,26,26,.12));
  transition: grid-template-rows 320ms cubic-bezier(.4, 0, .2, 1);
}
.xitem.xup > .xrev { top: auto; bottom: 100%; }
.xitem:hover > .xrev { grid-template-rows: 1fr; }
.xitem:not(.xquiet):has(> .xrow:focus-visible) > .xrev { grid-template-rows: 1fr; }
/* HOVER INTENT — it opens only once the pointer RESTS on a row, so a sweep across the list
   shows nothing. The delay sits on the :hover rule ONLY: closing never waits, and the keyboard
   opens it at once (rule below wins). The keyboard's preview paints over a hover preview that the
   parked pointer opens at the same time. */
.xitem:hover > .xrev { transition-delay: var(--xhover-intent, 160ms); }
.xitem:not(.xquiet):has(> .xrow:focus-visible) > .xrev { transition-delay: 0s; z-index: 21; }
.xrev > .xinner { overflow: hidden; }

/* the panel: the images (or works) on the left, the dates and the start of the text beside them —
   always side by side, so a preview stays one compact band (with the text under three works it
   reached 440px and covered ten rows). Same paper, hairline and shadow as the bar's type menu. */
.xpeek { display: flex; align-items: flex-start; gap: 24px;
  padding: 14px 16px 16px; background: var(--bg); border: 1px solid var(--rule); }
.xpeek-text { flex: 1 0 26ch; min-width: 0; }
.xpeek-text:not(:has(.xteaser)) { flex: 0 0 auto; }   /* dates alone take only their width */
.xpeek-meta { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 0 0 6px; }
/* the text is CUT, so the record is worth the click (meeting 1 Oct): ~220 characters in the
   engine (teaser()), at most 3 lines here */
.xdesc.xteaser { margin: 0; display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }

/* The works (or the one image) at the shared --xthumb scale, each IDENTIFIED: title in italics,
   date (the Collections quick-look; moved here from home.css at v110 so every list has it).
   Works that need more than the panel's width shrink together, in proportion, instead of wrapping
   to a second row. Each figure carries its image's ratio (--r, set by the engines from the media's
   width/height): it is --xthumb high at full size, and the image fills its width at its own ratio,
   so a shrunk work is a smaller picture, never one in a grey box, and its place is held before it
   loads. All of them stand the same height, so they line up TOP and bottom whatever the length of
   their captions (aligned on the captions' foot, a four-line title pushed its picture 55px up). */
.xq-works { display: flex; gap: clamp(14px, 1.6vw, 26px); align-items: flex-start; flex: 0 1 auto; min-width: 0; }
/* a WIDTH, not a flex-basis: only a width counts in the row's own size, so the panel knows how
   much room the works want (with a basis, an image with no caption collapsed to nothing). Capped
   only for a panorama (ratio > 2): below that, every work keeps the common height. */
.xq-work { margin: 0; width: calc(var(--xthumb, 240px) * var(--r, .75)); max-width: calc(var(--xthumb, 240px) * 2); flex: 0 1 auto; min-width: 0; }
.xq-work img { display: block; width: 100%; height: auto; background: var(--ph); }
/* the box keeps the ratio the CMS states, loaded or not: the panel is measured (tweaks-apply.js)
   before its images load and never changes height after, and a media whose stated size is wrong
   (ASCRS427: 640×480 given, 480×640 real) is contained in its place instead of breaking the line */
.xq-work[style] img { aspect-ratio: var(--r); object-fit: contain; object-position: center bottom; }
/* a media without a known size (66): its own width at the fixed height, as before v110 (forced
   to the default ratio it sat in a grey band, review 02.10) */
/* (the same panorama cap as above; until it loads, a grey half-square holds its place) */
.xq-work:not([style]) { width: auto; min-width: calc(var(--xthumb, 240px) * .5); }
.xq-work img:not([height]) { width: auto; min-width: 100%; max-width: 100%; height: var(--xthumb, 240px); object-fit: contain; object-position: left bottom; }
.xq-work img.xbroken {
  background: repeating-linear-gradient(45deg, var(--ph), var(--ph) 5px, var(--ph-line) 5px, var(--ph-line) 6px); }
.xq-work figcaption { margin-top: 9px; display: flex; flex-direction: column; gap: 3px;
  font-family: var(--ui); font-size: .6rem; color: var(--mut);
  hyphens: auto; overflow-wrap: anywhere; }   /* a shrunk work is narrower than "pełnopostaciowy," */
.xq-artist {
  font-family: var(--ui); font-size: .6rem; letter-spacing: .02em; color: var(--ph-ink);
}
.xq-title { font-family: var(--body); font-size: var(--fs-meta); color: var(--ink); line-height: 1.45;
  /* 2 lines at most: the record has the whole title. A 101-character title in a narrow work ran
     to ten lines and lifted its preview under the bar (review 02.10). The date is its own line
     below, so the cut never takes it */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.xq-date { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; line-height: 1.45; }
.xq-title em { font-style: italic; }
.xq-more {
  flex: 0 0 auto; align-self: center; font-family: var(--ui); font-size: var(--fs-meta);
  letter-spacing: .04em; color: var(--mut); white-space: nowrap;
}

/* left column: the record's fields as a definition list */
.xfields { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut);
  display: grid; grid-template-columns: 7.2rem minmax(0, 1fr); gap: 2px 12px; margin: 0; }
.xfields dt { color: var(--ph-ink); letter-spacing: .02em; }
.xfields dd { margin: 0; color: var(--ink); }
.xfields .xrec-title { grid-column: 1 / -1; font-family: var(--body);
  font-size: var(--fs-body); color: var(--ink); margin-bottom: 8px; }

/* right column: the description, as the CMS wrote it (sanitised) */
.xdesc { font-family: var(--body); font-size: var(--fs-body); color: var(--ink);
  line-height: 1.55; max-width: 70ch; }
.xdesc p { margin: 0 0 .7em; }
.xdesc p:last-child { margin-bottom: 0; }
.xdesc a { color: var(--accent); }
/* a long URL in a description (ac-3's ticketing link) pushed the record 69px past a phone's edge */
.xdesc { overflow-wrap: anywhere; }
/* a title word wider than a phone's line ("GRUPPENAUSSTELLUNG", "elles@centrepompidou.") ran under the ✕
   and past the edge: broken where it must, hyphenated on phones — the design version's rule of 30.09 */
.xfiche-title { overflow-wrap: anywhere; }
@media (max-width: 900px) { .xfiche-title { hyphens: auto; } }
.xdesc .xnodesc { font-family: var(--ui); font-size: var(--fs-meta); color: var(--ph-ink); }

/* ============================================================
   GALERIE — centrephotogeneve model
   ============================================================ */
.xgal { display: grid; grid-template-columns: repeat(var(--cols, 2), 1fr); gap: var(--xedge, 10px); }

/* GALERIE card — image framed on top, record BELOW it (Seba, 2026-07-29). The old design
   floated the title OVER the image; on Alina's grey studio seamless that half-dissolved the
   text (the legibility problem the scrim/difference tricks were fighting). With the caption
   under the picture there is no overlap to fight, so the scrim + data-leg/fit/pos variants are
   gone. Images always `contain` (63% of the archive is portrait — never crop). */
.xcard { position: relative; display: flex; flex-direction: column;
  overflow: hidden; background: var(--bg); text-decoration: none; isolation: isolate; }
.xcard.xhide { display: none; }
.xcard img { display: block; width: 100%; object-fit: contain; background: var(--ph);
  transition: transform 600ms cubic-bezier(.22,.61,.36,1); }
.xcard:hover img { transform: scale(1.01); }

.xcard .xover {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-start;
  padding: 10px 12px 6px; color: var(--ink);
}
.xcard .xkick  { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 0; }
.xcard .xgttl  { font-family: var(--display); font-weight: 400; line-height: 1.05;
  font-size: clamp(1.15rem, 1.7vw, 1.9rem); margin: 4px 0 0; text-wrap: balance; }
.xcard .xvenue { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 8px 0 0; }

/* GRID (2 & 3 columns): a 4/3 frame keeps rows aligned; the image is shown WHOLE (contain),
   standing on the frame's baseline — works are never cropped (client 5 Sept p.05: "dans le
   menu grille 3, toutes les œuvres sont coupées"; was `cover` since v91). */
.xgal:not(.xstack) .xcard img { aspect-ratio: 4 / 3; height: auto; object-fit: contain;
  object-position: center bottom; background: transparent; }

/* cadence 1 = the sticky stack. Cards pin under the topbar (the tool is in it since v107) and slide over the last by DOM
   order (no z-index). The image is `contain` on WHITE; a white dwell zone (padding-bottom)
   sits under the caption so the incoming pile card crosses empty white before it reaches the
   caption — otherwise the next card sat flush against the caption and hid it the instant you
   scrolled (Seba). */
.xgal.xstack { display: block; }
.xgal.xstack .xcard {
  position: sticky; top: var(--topbar-h, 52px);
  height: calc(100dvh - var(--topbar-h, 52px));
  background: #fff; padding-bottom: 6vh;   /* small dwell — enough to protect the caption, not a big empty band */
}
.xgal.xstack .xcard img { flex: 1 1 auto; min-height: 0; height: auto; background: #fff; }
.xgal.xstack .xcard .xgttl { font-size: clamp(1.6rem, 3vw, 2.8rem); }

/* ---- view switch ------------------------------------------- */
body[data-view="gallery"] .xlist { display: none; }
body[data-view="list"]    .xgal  { display: none; }

.xwithheld { font-family: var(--ui); font-size: var(--fs-meta); color: var(--ph-ink);
  padding: 16px 4px; margin: 0; }

/* ============================================================
   FICHE — bespoke panel (ported from the reference), overlapping the index at 85%.
   NOT fiche.js: fiche.js stacks the image as a full-width hero on top, which is
   unreadable at this width (Seba's note on the screenshot). This lays the record
   out as a header (kicker · title · dates) over a two-column body (image | fields
   + description). Fixed overlay; the index underneath never moves, so the exposed
   left strip stays live (année + titre). Below 900px it goes near-full-width and
   the body stacks. On adoption this is what moves into the site (its own panel for
   the Expositions record. Since the 26 Aug API, an exhibition lists its works: the panel
   now also shows each work's record, with a back link — see "Œuvres présentées" below).
   ============================================================ */
.xfiche {
  position: fixed; top: 0; right: 0; z-index: 80;
  width: 85vw; height: 100vh; height: 100dvh;
  background: var(--bg); border-left: 1px solid var(--rule);
  box-shadow: -22px 0 70px rgba(26,26,26,0.20);
  overflow-y: auto; overflow-x: hidden;
  transform: translateX(100%);
  transition: transform .5s cubic-bezier(.77, 0, .175, 1);
}
body.xopen .xfiche:not(.xlayer), .xfiche.xlayer.xin { transform: none; }

/* CALQUES (branch wireframe/calques; engine: expo-index.js). A record opened from a record is a new
   sheet over the last, one tab narrower; the sheets below keep their left edge as a tab with their
   title (Alexandra: "l'indice de où on vient … comme des modèles de classeurs"). A covered sheet is
   unpainted and shadowless (only the top one casts the shadow); its tab is a separate fixed button
   on its edge. Desktop only: phones keep the single panel. */
.xfiche.xcovered { box-shadow: none; transition: transform .5s cubic-bezier(.77, 0, .175, 1), box-shadow 0s linear .5s; }
/* unpainted once the incoming sheet has slid in (0.5s), not at the click: the page you came from no
   longer goes blank under a sheet that has barely started to move (review 03.10); uncovering is
   instant (no transition on the plain state) */
.xfiche.xcovered > .xfiche-inner { visibility: hidden; transition: visibility 0s linear .5s; }
.xtab { position: fixed; top: 0; bottom: 0; width: var(--xtab, 40px); box-sizing: border-box; margin: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 18px 0;
  font: inherit; font-family: var(--ui); font-size: var(--fs-meta); letter-spacing: .04em; line-height: 1.2; color: var(--mut);
  background: var(--bg); border: 0; border-left: 1px solid var(--rule); cursor: pointer;
  transition: background-color .16s ease, color .16s ease; }
/* the vertical text is on the span, not the <button>: older Safari forces form controls horizontal */
.xtab span { writing-mode: vertical-rl; transform: rotate(180deg);   /* a spine read from the bottom up */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-height: calc(100vh - 36px); }
.xtab:hover, .xtab:focus-visible { background: var(--wash); color: var(--ink); }
.xfiche-inner { padding: 14px clamp(16px,3vw,40px) 20vh; min-height: 100%; }

/* just a cross — no "Fermer" label, no box (Seba). Sized as a comfortable tap target;
   the accessible name lives on aria-label since the glyph alone carries no meaning. */
.xfiche-close {
  position: sticky; top: 0; float: right; z-index: 5;
  font: inherit; font-family: var(--ui); font-size: 1.6rem; line-height: 1;
  background: none; border: 0; padding: 4px 2px 8px 14px;
  cursor: pointer; color: var(--mut); transition: color .18s ease;
}
.xfiche-close:hover, .xfiche-close:focus-visible { color: var(--ink); }

.xfiche-kick { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 0 0 8px; }
.xfiche-title { font-family: var(--display); font-weight: 400; line-height: 1.03;
  font-size: clamp(2rem, 5vw, 4.6rem); margin: 0; max-width: 22ch; text-wrap: balance; }
.xfiche-dates { font-family: var(--display); font-weight: 400; line-height: 1.05;
  font-size: clamp(1.4rem, 3.2vw, 3rem); margin: 18px 0 0; color: var(--ink); }

.xfiche-body { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 40px; margin-top: 34px; align-items: start; }
.xfiche-fig { margin: 0; }
.xfiche-fig img { width: 100%; height: auto; display: block; background: var(--ph); }
.xfiche-fig figcaption { font-family: var(--ui); font-size: .62rem; color: var(--mut); margin-top: 6px; }
/* the image series (several images per record, client 3 Sept): one at a time, ‹ n/N ›,
   each with its own caption/credit */
.xseries .xs-stage[data-step] { cursor: e-resize; }
.xseries figcaption { display: flex; flex-direction: column; gap: 6px; }
.xs-nav { display: flex; align-items: baseline; gap: 10px; }
.xs-btn { font: inherit; font-size: .95rem; line-height: 1; background: none; border: 0; padding: 2px 4px;
  cursor: pointer; color: var(--mut); }
.xs-btn:hover, .xs-btn:focus-visible { color: var(--ink); }
.xs-count { color: var(--ink); }
.xs-cap { line-height: 1.55; }
.xs-cap p { margin: 0; }
/* no image: one text column, never an empty image slot (client 3 Sept) */
.xfiche-body.noimg { grid-template-columns: minmax(0, 1fr); }
.xfiche-side .xfields { grid-template-columns: 7.6rem minmax(0, 1fr); margin-bottom: 26px; }
.xfiche-side .xdesc { max-width: 62ch; }

/* ---- Œuvres présentées (under an exhibition) + the work record (client V2; API 26 Aug).
        Engine: expo-index.js worksBlock()/workHTML(). Same panel, same x* kit. ---- */
.xworks { margin-top: clamp(44px, 7vh, 80px); padding-top: 16px; border-top: 1px solid var(--rule); }
.xrel-h { font-family: var(--ui); font-size: var(--fs-meta); font-weight: 400; color: var(--mut); letter-spacing: .02em; margin: 0 0 16px; }
.xfiche-side .xrel-h { margin-top: 34px; }
.xworks-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 30px 22px; align-items: start; }
/* a tile: the work stands on a common baseline in a square box (contain, never cropped) */
.xwork { font: inherit; display: block; width: 100%; text-align: left; background: none; border: 0;
  padding: 0; cursor: pointer; color: var(--ink); }
.xw-img { display: block; aspect-ratio: 1 / 1; }
.xw-img:empty { background: var(--ph); }          /* a work without an image keeps the grid's rhythm */
.xw-img img { width: 100%; height: 100%; object-fit: contain; object-position: center bottom;
  transition: opacity .18s ease; }
.xwork:hover .xw-img img, .xwork:focus-visible .xw-img img { opacity: .72; }
.xw-ttl { display: block; font-family: var(--body); font-style: italic; font-size: .92rem;
  line-height: 1.3; margin-top: 9px; }
.xw-date { display: block; font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); margin-top: 3px; }

.xfiche-link { margin: 22px 0 0; font-family: var(--ui); font-size: var(--fs-meta); }
.xfiche-link a { color: var(--accent); border-bottom: 1px solid var(--rule); }
/* a link that opens a record on this page is a button styled as the link (records.js) */
.xfiche-link button { font: inherit; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent); border-bottom: 1px solid var(--rule); }

/* ---- the sheet's tools: ✕, and "Tout fermer" once two sheets or more are stacked (Seba 03.10:
        "otherwise user needs to close one by one"). Sticky at the top right, as the ✕ was. ---- */
.xsheet-tools { position: sticky; top: 0; float: right; z-index: 5; display: flex; align-items: baseline; gap: 14px;
  background: linear-gradient(var(--bg) 70%, transparent); padding-left: 14px; }
.xsheet-tools .xfiche-close { position: static; float: none; }
.xclose-all { font: inherit; font-family: var(--ui); font-size: var(--fs-meta); letter-spacing: .02em; color: var(--mut);
  background: none; border: 0; padding: 4px 0; cursor: pointer; white-space: nowrap; }
.xclose-all:hover, .xclose-all:focus-visible { color: var(--ink); }
body:not(.xpile) .xclose-all { display: none; }
/* a relation whose data is still on its way (records.js): the click was heard */
.xwait { cursor: progress; opacity: .55; }

/* ---- a public collection's record (records.js; was home.css until v114: a collection now opens from
        a work on any page) ---- */
.xfiche-place { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 14px 0 0; }
.xcoll-sub { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; margin: 20px 0 0; }
.xcoll-ext { margin: 14px 0 0; font-family: var(--ui); font-size: var(--fs-meta); }
.xcoll-ext a { color: var(--accent); border-bottom: 1px solid var(--rule); }
.xcoll-works { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 30px 26px; margin-top: 30px; align-items: start; }
.xcoll-work { margin: 0; }
.xcoll-work img { width: 100%; height: auto; display: block; background: var(--ph); }
/* the IMAGE opens the work's record as a new sheet; the caption stays selectable text */
.xcoll-wlink { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; cursor: pointer; }
.xcoll-wlink img { transition: opacity .18s ease; }
.xcoll-wlink:hover img, .xcoll-wlink:focus-visible img { opacity: .72; }
.xcoll-work figcaption { font-family: var(--ui); font-size: .62rem; color: var(--mut); line-height: 1.55; margin-top: 8px; }
.xcoll-work figcaption em { font-style: italic; }
/* ‹ n/17 › through the list a record was opened from (collections); the record slides in from
   the side you go to */
.xseq { display: flex; align-items: baseline; gap: 10px; margin: 0 0 12px; font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); }
.x-from-r { animation: xFromR .32s cubic-bezier(.22,.61,.36,1); }
.x-from-l { animation: xFromL .32s cubic-bezier(.22,.61,.36,1); }
@keyframes xFromR { from { opacity: 0; transform: translateX(28px); } to { opacity: 1; transform: none; } }
@keyframes xFromL { from { opacity: 0; transform: translateX(-28px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .x-from-r, .x-from-l { animation: none; } }
.xback { font: inherit; font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); letter-spacing: .02em; background: none; border: 0; padding: 6px 0;
  margin: 0 0 18px; cursor: pointer; text-align: left; max-width: calc(100% - 3rem); display: block; }
.xback:hover, .xback:focus-visible { color: var(--ink); }
.xwk-title { font-style: italic; }
.xwk-figs { display: grid; gap: 30px; }
.xfiche-fig figcaption .xw-mcap { display: block; margin-top: 4px; line-height: 1.55; }
.xwk-cap { font-family: var(--ui); font-size: .72rem; line-height: 1.6; color: var(--mut); }
.xwk-cap em { color: var(--ink); }
.xrel { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); max-width: 62ch; }
.xrel li { border-bottom: 1px solid var(--rule); }
.xrel button, .xrel a, .xrel .xrel-row { font: inherit; display: grid; grid-template-columns: 3.4rem minmax(0, 1fr);
  column-gap: 12px; align-items: baseline; width: 100%; text-align: left; background: none; border: 0;
  padding: 7px 0; color: var(--ink); font-family: var(--body); font-size: .92rem; line-height: 1.35; }
.xrel button, .xrel a { cursor: pointer; transition: background-color .16s ease; }
.xrel button:hover, .xrel button:focus-visible, .xrel a:hover, .xrel a:focus-visible { background: var(--wash); }
.xrel .xyr { font-family: var(--ui); font-size: var(--fs-meta); color: var(--mut); }

@media (max-width: 900px) {
  .xfiche { width: 94vw; }                 /* near-full-screen; a sliver keeps the close affordance */
  .xfiche-body { grid-template-columns: 1fr; gap: 24px; }
  .xfiche-title { font-size: clamp(1.7rem, 8vw, 2.6rem); }
  .xfiche-dates { font-size: clamp(1.2rem, 5vw, 1.8rem); }
  .xworks-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 14px; }
  /* Phone: year + TITLE ONLY. The venue column used to take half the width, squeezing
     "Broken: The Power of the Fragment in Sculpture" into four wrapped lines and truncating
     the venue anyway ("NATIONAL GALL…"). Everything else is one tap away in the fiche. */
  .xrow { grid-template-columns: 3.6rem minmax(0, 1fr); }
  .xrow .xlieu, .xrow .xville, .xrow .xtype, .xrow .xtick { display: none; }
  .xrev { display: none; }              /* no hover on touch: tap opens the fiche */
  .xgal { grid-template-columns: 1fr !important; }
  .xgal.xstack .xcard { height: 90dvh; }   /* next card peeks in, as CPG does */
}
/* a screen nothing can hover (a touch tablet): a tap opens the record, and a hover the tap leaves
   behind would keep a preview floating over the list */
@media (any-hover: none) { .xrev { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .xrev { transition-duration: 1ms; }
  .xcard:hover img { transform: none; }
}
