/* ============================================================================
   Doha MUN 2027 — page design layer

   Everything below <main>. The header, the footer and their deviations live in
   pue-chrome-overrides.css; the tokens this file consumes live in qf-tokens.css
   and are never redefined here.

   Written against the Qatar Foundation design system's house style rather than
   away from it: square corners, hairlines instead of shadows, Sidra green doing
   the structural work, QF yellow as the one editorial accent, and a lot of air.
   The energy comes from motion, scale and rhythm — not from rounding the corners
   and adding a gradient, which is how a serious institution's site ends up
   looking like a startup's.

   Direction: logical properties throughout (padding-inline, margin-block,
   inset-inline-start), so the Arabic page mirrors without a second stylesheet.
   dohamun-rtl.css exists only for the handful of things logical properties cannot
   express — marquee direction, icon flips, one gradient.
   ============================================================================ */

/* ---------------------------------------------------------------- 1. Base
   Astra's stylesheet loads before this one and sets its own body type, heading
   scale and link colour. These declarations are not defensive over-reach; they
   are the base layer this design assumes, stated once. */

.dm {
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--qf-ink);
  background: var(--surface-page);
  /* Nothing on this page may cause a horizontal scrollbar. The hero canvas and
     the marquee both deliberately overflow their container. */
  overflow-x: clip;
}

/* ── :where(), and why every element reset below uses it ─────────────────────
   These rules exist to flatten browser and Astra defaults, not to compete with
   this file's own components. Written as `.dm p` they were doing both: `.dm p`
   is (0,1,1), a bare `.dm-lede` is (0,1,0), so the reset won and every declared
   margin in the design layer resolved to 0. Twenty-six rules were affected — most
   of the vertical rhythm on the site, plus `.dm-timeline`'s left gutter, which is
   the space its rail and nodes are positioned against, so the deadline list came
   out with the nodes hanging outside the text column.

   It hid for as long as it did because nothing looks *broken*: every element is
   present and legible, just tighter than drawn, and there is no reference to
   compare against in the browser.

   `:where()` contributes zero specificity, so each reset is (0,1,0) — the `.dm`
   class alone. That still beats Astra's element selectors (0,0,1), which is the
   whole job, and it ties with a bare component class, which the cascade then
   settles on source order. Since this base layer is the first section in the file
   and every component comes after it, components win. New component rules are
   safe by default rather than safe if someone remembers.

   Astra's own content selectors (`.entry-content h2` and friends) are (0,1,1) and
   would beat these — but this theme emits neither `.entry-content` nor
   `.ast-container`; page.php calls the_content() directly inside `.dm-prose`. If a
   future template ever reintroduces an Astra wrapper, re-check this. */

.dm :where(h1, h2, h3, h4, h5, h6) {
  font-family: var(--font-sans);
  font-weight: var(--weight-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-display);
  color: var(--qf-ink);
  margin: 0;
  text-wrap: balance;
}

.dm :where(p) { margin: 0; }
.dm :where(ul, ol) { margin: 0; padding: 0; list-style: none; }

.dm a { color: var(--text-link); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
.dm a:hover { color: var(--text-link-hover); }

/* max-width stays at full strength: it is an overflow guard, not a default, and a
   component that wants to beat it should have to say so deliberately. */
.dm :is(img, svg, canvas) { max-width: 100%; }
.dm :where(img) { height: auto; }

/* Arabic sets a touch larger: at the same point size Naskh forms read smaller
   than Latin, and the two languages have to feel like equals on this site. */
.dm-lang-ar { font-family: var(--font-arabic); font-size: 1.05rem; }

/* ------------------------------------------------------------- 2. Sections
   One rhythm object, four grounds. */

.dm-section {
  position: relative;
  padding-block: var(--section-y);
  background: var(--surface-page);
}

.dm-section--tight { padding-block: var(--space-16); }
.dm-section--tint { background: var(--surface-tint); }

.dm-section--brand {
  background: var(--surface-brand);
  color: var(--text-on-dark);
}

.dm-section--ink {
  background: var(--surface-inverse);
  color: var(--text-on-dark);
}

.dm-section--brand :is(h1, h2, h3, h4),
.dm-section--ink :is(h1, h2, h3, h4) { color: var(--text-on-dark); }

.dm-section-inner { position: relative; z-index: 1; }

/* The hairline that separates one band from the next. Only between two bands of
   the same ground — a green band beside a white one draws its own edge. */
.dm-section + .dm-section:not(.dm-section--tint, .dm-section--brand, .dm-section--ink) > .dm-section-inner::before,
.dm-section--tint + .dm-section--tint > .dm-section-inner::before {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--section-y) * -0.5);
  inset-inline: 0;
  border-block-start: var(--border-hairline);
}

.dm-section-more { margin-block-start: var(--space-10); }

/* -------------------------------------------------------------- 3. Type
   The pieces every section is built from. */

.dm-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-brand);
  margin-block-end: var(--space-5);
}

.dm-section--brand .dm-eyebrow { color: var(--qf-yellow); }
.dm-section--ink .dm-eyebrow { color: var(--qf-mint); }
.dm-lang-ar .dm-eyebrow { text-transform: none; letter-spacing: var(--tracking-normal); }

/* A short rule that draws itself in when the eyebrow arrives. */
.dm-eyebrow-tick {
  flex: 0 0 auto;
  inline-size: var(--space-8);
  block-size: 2px;
  background: currentColor;
  transform-origin: inline-start;
}

.dm-motion [data-dm-reveal] .dm-eyebrow-tick,
.dm-motion .dm-eyebrow[data-dm-reveal] .dm-eyebrow-tick { transform: scaleX(0); }
.dm-motion .dm-eyebrow[data-dm-reveal].is-in .dm-eyebrow-tick {
  transform: scaleX(1);
  transition: transform 0.5s var(--ease-out) 0.15s;
}

/* The bilingual heading — the design's signature.

   Structure borrowed from the official PUE lockup, which is itself Arabic over
   English divided by a hairline rule. The site's headings say their name the way
   the logo above them does. */
.dm-bititle {
  font-size: var(--text-display-2);
  margin-block-end: var(--space-6);
}

.dm-bititle-primary { display: block; }

.dm-bititle-rule {
  display: block;
  inline-size: clamp(3rem, 8vw, 5.5rem);
  block-size: 1px;
  background: currentColor;
  opacity: 0.32;
  margin-block: var(--space-4) var(--space-3);
  transform-origin: inline-start;
}

.dm-bititle-secondary {
  display: block;
  font-family: var(--font-serif-display);
  font-size: 0.44em;
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-normal);
  line-height: var(--leading-tight);
  opacity: 0.62;
}

/* The Arabic secondary line stays in the Arabic face and separates itself by
   weight and size instead of by serif. That was originally because the QF family
   had no serif companion; it stays true under the identity's own faces for a
   better reason — Latin display is set in a serif and Arabic never is, which is
   the deliberate pairing dm-identity.css §4 explains. */
.dm-lang-en .dm-bititle-secondary { font-family: var(--font-arabic); font-size: 0.4em; }

/* The second line carries dir of its own — it has to, or the browser orders the
   run against the page and the Arabic comes out backwards. But dir also moves the
   text to the far edge of the block, which left the Arabic stranded across the
   column from the heading and the rule it belongs to.

   So: direction stays with the language, alignment stays with the page. These are
   physical keywords on purpose. Inside a dir="rtl" element `text-align: start`
   resolves to the right, which is the behaviour being corrected here, so a logical
   keyword cannot express it. */
.dm-lang-en .dm-bititle-secondary { text-align: left; }
.dm-lang-ar .dm-bititle-secondary { text-align: right; }

.dm-motion .dm-bititle .dm-bititle-rule { transform: scaleX(0); }
.dm-motion .dm-bititle.is-in .dm-bititle-rule { transform: scaleX(1); transition: transform 0.6s var(--ease-out) 0.25s; }

.dm-lede {
  font-size: var(--text-body-lg);
  line-height: var(--leading-body);
  color: var(--text-muted);
  max-inline-size: 62ch;
  margin-block-end: var(--space-10);
}

.dm-section--brand .dm-lede,
.dm-section--ink .dm-lede { color: rgba(255, 255, 255, 0.82); }

.dm-prose {
  font-size: var(--text-body-lg);
  color: var(--text-muted);
  max-inline-size: 64ch;
  margin-block-end: var(--space-6);
}

.dm-textlink {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--weight-medium);
  text-decoration: none;
  border-block-end: 1px solid currentColor;
  padding-block-end: 2px;
}

.dm-textlink .dm-inline-arrow { transition: transform var(--duration-base) var(--ease-out); }
.dm-textlink:hover .dm-inline-arrow { transform: translateX(4px); }

.dm-section--brand .dm-textlink,
.dm-section--ink .dm-textlink { color: var(--qf-yellow); }

/* A two-column heading/body split. Below 900px it stacks and the heading keeps
   its own line, which is why the head column is not simply floated. */
.dm-split {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--space-12) var(--space-16);
  align-items: start;
}

.dm-deflist { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2) var(--space-6); margin-block-end: var(--space-6); }
.dm-deflist dt { font-size: var(--text-caption); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--text-subtle); }
.dm-deflist dd { margin: 0; color: var(--qf-ink); }
.dm-lang-ar .dm-deflist dt { text-transform: none; letter-spacing: var(--tracking-normal); }

/* -------------------------------------------------------- 4. Motion primitives

   Every start state below is behind .dm-motion, which the boot script adds to
   <html> in the head — before first paint, and only when the reader has not asked
   for reduced motion. Script blocked, script failed, script still downloading:
   none of these rules apply and every element is simply visible. No text on this
   site is ever invisible waiting for JavaScript. */

.dm-motion [data-dm-reveal] {
  opacity: 0;
  transform: translateY(20px);
}

.dm-motion [data-dm-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

.dm-motion [data-dm-reveal="stagger"] { opacity: 1; transform: none; }
.dm-motion [data-dm-reveal="stagger"] > * { opacity: 0; transform: translateY(24px); }

.dm-motion [data-dm-reveal="stagger"].is-in > * {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
  transition-delay: calc(var(--dm-i, 0) * 65ms);
}

/* Word-level heading reveal. The script wraps each word in .dm-word (a clipping
   box) around .dm-word-i (the thing that slides). Word level and never character
   level: Arabic shapes its letters according to their neighbours inside a word,
   so a span between two letters breaks the ligature and the word renders wrong. */
.dm-word {
  display: inline-block;
  overflow: hidden;
  /* Descenders would otherwise be clipped by the overflow that makes the mask
     work. Padding gives them room, negative margin takes the line back. */
  padding-block-end: 0.14em;
  margin-block-end: -0.14em;
}

.dm-motion [data-dm-split] .dm-word-i {
  display: inline-block;
  transform: translateY(105%);
  opacity: 0;
}

.dm-motion [data-dm-split].is-in .dm-word-i {
  transform: none;
  opacity: 1;
  transition: transform 0.75s var(--ease-out), opacity 0.5s linear;
  transition-delay: calc(var(--dm-i, 0) * 42ms);
}

/* ------------------------------------------------------------- 5. Buttons
   The DS button, one size larger for the page body. The chrome's own buttons are
   untouched — these only apply where .dm-btn-lg is asked for. */

.dm .qf-btn.dm-btn-lg {
  font-size: var(--text-body-lg);
  padding: var(--space-4) var(--space-8);
  gap: var(--space-3);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/* A wipe that crosses the button on hover, in the reading direction. Square, not
   a glow: the DS has no soft shadows and adding one here would be the first
   thing that looked borrowed from somewhere else. */
.dm .qf-btn.dm-btn-lg::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: currentColor;
  opacity: 0.12;
  transform: scaleX(0);
  transform-origin: inline-start;
  transition: transform var(--duration-base) var(--ease-out);
}

.dm .qf-btn.dm-btn-lg:hover::after { transform: scaleX(1); }

.dm .qf-btn.dm-btn-lg svg { transition: transform var(--duration-base) var(--ease-out); }
.dm .qf-btn.dm-btn-lg:hover svg { transform: translateX(4px); }

/* ---------------------------------------------------------------- 6. Hero */

.dm-hero {
  position: relative;
  display: flex;
  align-items: center;
  /* Not 100vh. A full-viewport hero on a laptop pushes the first real content
     below the fold and tells the reader nothing they did not already know from
     the header. This leaves the top of the marquee showing, which is what makes
     people scroll. */
  min-block-size: min(82vh, 780px);
  padding-block: var(--space-20) var(--space-24);
  overflow: hidden;
  background: var(--surface-page);
}

.dm-hero-canvas {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  display: block;
}

/* Keeps the headline legible over the busiest part of the diagram, and fades the
   diagram out at the top and bottom edges so it does not collide with the header
   or the marquee.

   Built entirely from --surface-page and transparent, never from a literal white.
   A hardcoded rgba(255,255,255,…) here paints a white cloud across the dark theme,
   which is exactly what it did before this comment existed. The page ground is a
   token because it has two values. */
.dm-hero-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Fallback for engines without color-mix: the vertical fade alone, which is the
     half that does the legibility work. */
  background: linear-gradient(to bottom, var(--surface-page) 0%, transparent 24%, transparent 60%, var(--surface-page) 100%);
  background:
    linear-gradient(to bottom, var(--surface-page) 0%, transparent 24%, transparent 60%, var(--surface-page) 100%),
    radial-gradient(120% 90% at 20% 45%,
      var(--surface-page) 0%,
      color-mix(in srgb, var(--surface-page) 74%, transparent) 40%,
      transparent 74%);
}

.dm-hero-inner { position: relative; z-index: 2; }

.dm-hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-brand);
  border: var(--border-hairline);
  border-color: currentColor;
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-2);
  margin-block-end: var(--space-6);
}

.dm-lang-ar .dm-hero-eyebrow { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-hero-sdg {
  display: grid;
  place-items: center;
  inline-size: 26px;
  block-size: 26px;
  /* Not --text-brand, and not the brand colour either. This is the badge for
     Sustainable Development Goal 17, whose official colour is a dark navy, and the
     chamber ground is within a few percent of it — so the chip is both correct
     about what it refers to and part of this identity rather than a quotation from
     another one. It also has to be a fixed dark value in both themes, because it
     carries white text and a theme-aware tint would take that to 2:1. */
  background: var(--dm-chamber);
  color: var(--qf-white);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-bold);
  letter-spacing: 0;
}

.dm-hero-title {
  font-size: var(--text-display-1);
  line-height: var(--leading-display);
  letter-spacing: -0.025em;
  max-inline-size: 18ch;
  margin-block-end: var(--space-6);
}

.dm-hero-line { display: block; }

/* The second line carries the yellow underscore — the DS Highlight, kept to a
   line rather than a word because the whole phrase is the claim. */
.dm-hero-line--accent {
  position: relative;
  display: inline-block;
}

/* The offset is measured from the bottom of the line box, not from the baseline,
   and the line box here is taller than the type: each word is wrapped in a
   .dm-word clipping box that carries 0.14em of bottom padding so the mask does
   not shear the descenders. Sitting the bar at 0.06em put it in that padding —
   a yellow rule floating under the sentence rather than a marker struck through
   it. 0.3em clears the padding and lands the bar across the bottom of the
   glyphs. Both values are em, so they hold as the display size clamps. */
.dm-hero-line--accent::after {
  content: "";
  position: absolute;
  inset-inline: -0.06em;
  inset-block-end: 0.3em;
  block-size: 0.2em;
  background: var(--qf-yellow);
  z-index: -1;
  transform: scaleX(0);
  transform-origin: inline-start;
}

.dm-motion .dm-hero-title.is-in .dm-hero-line--accent::after {
  transform: scaleX(1);
  transition: transform 0.9s var(--ease-out) 0.55s;
}

.dm-hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  margin-block-end: var(--space-6);
}

.dm-hero-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}

.dm-hero-chip svg { color: var(--text-brand); flex: 0 0 auto; }

.dm-hero-lede {
  font-size: var(--text-body-lg);
  color: var(--text-muted);
  max-inline-size: 56ch;
  margin-block-end: var(--space-8);
}

.dm-hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-block-end: var(--space-16);
}

/* Countdown */

.dm-countdown { border-block-start: var(--border-hairline); padding-block-start: var(--space-6); max-inline-size: 34rem; }

.dm-countdown-label {
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-subtle);
  margin-block-end: var(--space-4);
}

.dm-lang-ar .dm-countdown-label { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-countdown-units { display: flex; gap: var(--space-8); }

.dm-countdown-unit { display: flex; flex-direction: column; gap: var(--space-1); }

.dm-countdown-value {
  font-size: var(--text-title-1);
  font-weight: var(--weight-bold);
  line-height: 1;
  /* Tabular figures, or the seconds digit shifts the whole row every tick. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  color: var(--qf-ink);
}

.dm-countdown-name {
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.dm-lang-ar .dm-countdown-name { text-transform: none; letter-spacing: var(--tracking-normal); }

/* The seconds unit gets a one-frame tick so the page reads as live without
   anything actually moving. */
.dm-countdown-value.is-tick { animation: dm-tick 0.35s var(--ease-out); }

@keyframes dm-tick {
  0% { opacity: 0.35; transform: translateY(-2px); }
  100% { opacity: 1; transform: none; }
}

.dm-hero-scroll {
  position: absolute;
  inset-block-end: var(--space-6);
  inset-inline-start: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
  text-decoration: none;
  z-index: 2;
}

.dm-lang-ar .dm-hero-scroll { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-hero-scroll-line {
  inline-size: 1px;
  block-size: var(--space-10);
  background: linear-gradient(to bottom, var(--qf-ink-30), transparent);
  position: relative;
  overflow: hidden;
}

.dm-hero-scroll-line::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  block-size: 40%;
  background: var(--text-brand);
  animation: dm-scroll-cue 2.2s var(--ease-standard) infinite;
}

@keyframes dm-scroll-cue {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(250%); }
}

/* ------------------------------------------------------------- 7. Marquee */

.dm-marquee {
  border-block: var(--border-hairline);
  background: var(--surface-brand);
  color: var(--text-on-dark);
  overflow: hidden;
  padding-block: var(--space-4);
  /* The strip is a decorative repetition of facts stated elsewhere; it is
     aria-hidden in the markup, so it is also removed from the tab order here. */
  user-select: none;
}

.dm-marquee-track { display: flex; inline-size: max-content; animation: dm-marquee 46s linear infinite; }
.dm-marquee:hover .dm-marquee-track { animation-play-state: paused; }

.dm-marquee-run { display: flex; align-items: center; gap: var(--space-6); padding-inline-end: var(--space-6); }

.dm-marquee-item {
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}

.dm-lang-ar .dm-marquee-item { text-transform: none; letter-spacing: var(--tracking-normal); }
.dm-marquee-dot { color: var(--qf-yellow); }

@keyframes dm-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* --------------------------------------------------------------- 8. Stats */

.dm-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-8);
}

.dm-stat { border-block-start: 2px solid var(--text-brand); padding-block-start: var(--space-5); }

.dm-stat-value {
  display: flex;
  align-items: baseline;
  font-size: var(--text-display-2);
  font-weight: var(--weight-bold);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text-brand);
  margin-block-end: var(--space-3);
}

.dm-stat-suffix { color: var(--qf-orange); }

.dm-stat-label { font-size: var(--text-title-3); font-weight: var(--weight-semibold); margin-block-end: var(--space-2); }
.dm-stat-note { font-size: var(--text-body-sm); color: var(--text-subtle); }

/* --------------------------------------------------- 9. Theme band + wheel */

.dm-theme-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-16);
  align-items: center;
}

.dm-pills { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.dm-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  padding: var(--space-2) var(--space-4);
  border: 1px solid currentColor;
}

.dm-pill--outline { color: rgba(255, 255, 255, 0.88); }
.dm-pill--outline svg { color: var(--qf-mint); }

.dm-wheel { display: grid; place-items: center; }
.dm-wheel-svg { inline-size: min(100%, 22rem); block-size: auto; overflow: visible; }

.dm-wheel-ring { fill: none; stroke: rgba(255, 255, 255, 0.16); stroke-width: 1; }

.dm-wheel-spoke {
  stroke: rgba(255, 255, 255, 0.42);
  stroke-width: 2;
  stroke-linecap: butt;
  transform-origin: 100px 100px;
}

.dm-wheel-spoke.is-key { stroke: var(--qf-yellow); stroke-width: 5; }

/* Each spoke draws itself outward, in order, and the seventeenth arrives last —
   the goal that only works once the other sixteen are on the board. */
.dm-motion .dm-wheel[data-dm-reveal] .dm-wheel-spoke { opacity: 0; transform: scale(0.55); }

.dm-motion .dm-wheel[data-dm-reveal].is-in .dm-wheel-spoke {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s var(--ease-out), transform 0.7s var(--ease-out);
  transition-delay: calc(var(--dm-i) * 55ms);
}

.dm-wheel-num {
  font-family: var(--font-sans);
  font-size: 44px;
  font-weight: var(--weight-bold);
  fill: var(--qf-yellow);
  letter-spacing: -0.02em;
}

.dm-motion .dm-wheel[data-dm-reveal] .dm-wheel-num { opacity: 0; }
.dm-motion .dm-wheel[data-dm-reveal].is-in .dm-wheel-num { opacity: 1; transition: opacity 0.6s var(--ease-out) 1.1s; }

/* ------------------------------------------------------------ 10. Triptych */

.dm-triptych {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-10);
  margin-block-start: var(--space-16);
}

.dm-tri { border-block-start: var(--border-hairline); padding-block-start: var(--space-6); position: relative; }

/* The hairline above each card extends to green as it arrives — a rule being
   drawn, which is the gesture the whole page repeats. */
.dm-tri::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: 2px;
  background: var(--text-brand);
  transform: scaleX(0);
  transform-origin: inline-start;
}

.dm-motion [data-dm-reveal="stagger"].is-in .dm-tri::before {
  transform: scaleX(1);
  transition: transform 0.8s var(--ease-out);
  transition-delay: calc(var(--dm-i, 0) * 65ms + 200ms);
}

.dm-tri-n {
  display: block;
  font-family: var(--font-serif-display);
  font-size: var(--text-title-2);
  /* Faint, but not below legibility. --qf-ink-30 is the ramp for hairlines and
     disabled marks; a visible ordinal sits one step up. */
  color: var(--text-subtle);
  margin-block-end: var(--space-3);
}

.dm-tri-title { font-size: var(--text-title-2); margin-block-end: var(--space-3); }
.dm-tri-body { color: var(--text-muted); }

/* ------------------------------------------------------------ 11. Placards

   The delegate nameplate, which is the one object every person in the room has in
   front of them. Square, hairline-edged, standing on a base. */

.dm-placards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--space-6);
}

.dm-placard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--surface-card);
  border: var(--border-hairline);
  border-block-start: 3px solid var(--text-brand);
  padding: var(--space-6) var(--space-6) var(--space-8);
  transition: transform var(--duration-base) var(--ease-out), box-shadow var(--duration-base) var(--ease-out);
}

/* The working language is the single most useful thing to know at a glance, so it
   is encoded in the top edge as well as in the badge. */
.dm-placard--ar { border-block-start-color: var(--qf-orange); }
.dm-placard--both { border-block-start-color: var(--qf-mint); }

/* Raising the placard is how a delegate asks to be recognised. */
.dm-placard:hover { transform: translateY(-6px); box-shadow: var(--shadow-card); }

.dm-placard-stand {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 22%;
  block-size: 4px;
  background: var(--qf-ink);
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-out);
}

.dm-placard:hover .dm-placard-stand { opacity: 0.12; }

.dm-placard-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }

.dm-placard-abbr {
  font-size: var(--text-caption);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-eyebrow);
  color: var(--text-subtle);
}

.dm-placard-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.dm-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-micro);
  font-weight: var(--weight-medium);
  padding: 3px var(--space-2);
  border: var(--border-hairline);
  color: var(--text-muted);
  white-space: nowrap;
}

.dm-tag--lang[data-lang="ar"] { border-color: var(--qf-orange); color: var(--qf-orange); }
.dm-tag--lang[data-lang="both"] { border-color: var(--text-brand); color: var(--text-brand); }
.dm-tag--level[data-level="advanced"] { border-color: var(--qf-adham); color: var(--qf-adham); }

.dm-placard-name { font-size: var(--text-title-3); line-height: var(--leading-tight); }
.dm-placard-remit { font-size: var(--text-body-sm); color: var(--text-subtle); }
.dm-placard-blurb { font-size: var(--text-body-sm); color: var(--text-muted); margin-block-start: var(--space-2); }

.dm-placard-subhead {
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
  margin-block-start: var(--space-3);
}

.dm-lang-ar .dm-placard-subhead { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-topics { display: grid; gap: var(--space-3); }
.dm-topics li { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3); font-size: var(--text-body-sm); align-items: start; }

.dm-topics-n {
  inline-size: 22px;
  block-size: 22px;
  display: grid;
  place-items: center;
  background: var(--surface-tint);
  font-size: var(--text-micro);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
}

.dm-placard-foot {
  margin-block-start: auto;
  padding-block-start: var(--space-4);
  border-block-start: var(--border-hairline);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.dm-placard-meta { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-micro); color: var(--text-muted); }
.dm-placard-meta--muted { color: var(--text-subtle); }
.dm-placard-meta em { font-style: normal; }

/* --------------------------------------------------------------- 12. Steps */

.dm-steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-8);
  counter-reset: dm-step;
}

.dm-step { position: relative; padding-inline-end: var(--space-6); }

.dm-step-n {
  display: grid;
  place-items: center;
  inline-size: 46px;
  block-size: 46px;
  border: 2px solid var(--text-brand);
  color: var(--text-brand);
  font-size: var(--text-title-3);
  font-weight: var(--weight-bold);
  margin-block-end: var(--space-4);
  background: var(--surface-page);
  position: relative;
  z-index: 1;
}

/* The connector between steps draws left to right as the row arrives, so the
   sequence reads as a sequence rather than as four unrelated cards. */
.dm-step-link {
  position: absolute;
  inset-block-start: 23px;
  inset-inline-start: 46px;
  inline-size: calc(100% - 46px);
  block-size: 1px;
  background: var(--qf-line);
  transform: scaleX(0);
  transform-origin: inline-start;
}

.dm-motion .dm-steps.is-in .dm-step-link {
  transform: scaleX(1);
  transition: transform 0.6s var(--ease-out);
  transition-delay: calc(var(--dm-i, 0) * 65ms + 260ms);
}

.dm-step-title { font-size: var(--text-title-3); margin-block-end: var(--space-3); }
.dm-step-body { font-size: var(--text-body-sm); color: var(--text-muted); }

/* ------------------------------------------------------- 13. Rules of the floor */

.dm-floor { --dm-rule-line: rgba(255, 255, 255, 0.16); }

.dm-rules {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 0;
  border-block-start: 1px solid var(--dm-rule-line);
}

/* A dense table of calls, gridded by hairlines rather than boxed into cards —
   this is a reference, and a reference should look like one. */
.dm-rule {
  position: relative;
  padding: var(--space-6);
  border-block-end: 1px solid var(--dm-rule-line);
  border-inline-end: 1px solid var(--dm-rule-line);
  transition: background var(--duration-base) var(--ease-out);
}

.dm-rule:hover { background: rgba(255, 255, 255, 0.04); }

.dm-rule-call {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  color: var(--qf-white);
  margin-block-end: var(--space-3);
}

.dm-rule-quote { font-family: var(--font-serif-display); font-size: 1.6em; line-height: 0; color: var(--qf-yellow); }
.dm-rule-use { color: rgba(255, 255, 255, 0.8); margin-block-end: var(--space-2); }
.dm-rule-note { font-size: var(--text-body-sm); color: rgba(255, 255, 255, 0.55); }

.dm-rule-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-block-start: var(--space-4);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--qf-orange);
}

.dm-lang-ar .dm-rule-flag { text-transform: none; letter-spacing: var(--tracking-normal); }

/* --------------------------------------------------------------- 14. Roles */

.dm-roles { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--space-6); }

.dm-role {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  border: var(--border-hairline);
  padding: var(--space-6);
  background: var(--surface-card);
  transition: border-color var(--duration-base) var(--ease-out);
}

.dm-role:hover { border-color: var(--text-brand); }

.dm-role-icon { color: var(--text-brand); display: block; }
.dm-role-name { font-size: var(--text-title-3); }
.dm-role-body { font-size: var(--text-body-sm); color: var(--text-muted); }

.dm-role-meta { display: grid; gap: var(--space-1); font-size: var(--text-micro); margin-block-start: auto; padding-block-start: var(--space-4); }
.dm-role-meta dt { color: var(--text-subtle); letter-spacing: var(--tracking-wide); text-transform: uppercase; }
.dm-role-meta dd { margin: 0; color: var(--qf-ink); margin-block-end: var(--space-2); }
.dm-lang-ar .dm-role-meta dt { text-transform: none; letter-spacing: var(--tracking-normal); }

/* Status pills. Colour is never the only signal — each carries its own word. */
.dm-pill--open { color: var(--text-brand); border-color: currentColor; }
.dm-pill--upcoming { color: var(--text-subtle); border-color: var(--qf-line); }
/* --text-subtle, not --qf-ink-30. "Closed" is a word a reader has to be able to
   read — it is the answer to "can I still apply". The faint ink ramp put it at
   2.4:1, which is fine for a decorative numeral and not for a status. */
.dm-pill--done { color: var(--text-subtle); border-color: var(--qf-line); }

.dm-pill-dot { inline-size: 7px; block-size: 7px; background: currentColor; border-radius: var(--radius-circle); flex: 0 0 auto; }

/* Only the open one pulses, so the eye lands on the deadline that can still be
   met rather than on all of them at once. */
.dm-pill--open .dm-pill-dot { animation: dm-pulse 2.4s var(--ease-standard) infinite; }

/* The halo is drawn from currentColor, not from a literal green. The pill it sits in
   is --text-brand, which the dark theme lifts to a legible tint — a hardcoded
   rgba(3,70,56) halo was a dark-green glow on a near-black page, i.e. nothing. */
@keyframes dm-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 45%, transparent); }
  70% { box-shadow: 0 0 0 7px color-mix(in srgb, currentColor 0%, transparent); }
}

/* ------------------------------------------------------------ 15. Timeline */

.dm-timeline { position: relative; display: grid; gap: var(--space-10); padding-inline-start: var(--space-12); }

.dm-timeline-rail {
  position: absolute;
  inset-block: var(--space-2) 0;
  inset-inline-start: 9px;
  inline-size: 2px;
  background: var(--qf-line);
  overflow: hidden;
}

/* Fills as the section scrolls past — the reader's own progress through the year
   is the progress bar. Height is set by the script; the transition keeps it from
   stuttering on a fast scroll. */
.dm-timeline-fill {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: var(--dm-progress, 0%);
  background: var(--text-brand);
  transition: block-size 0.12s linear;
}

.dm-timeline-item { position: relative; }

.dm-timeline-node {
  position: absolute;
  inset-inline-start: calc(var(--space-12) * -1 + 4px);
  inset-block-start: 6px;
  inline-size: 12px;
  block-size: 12px;
  border: 2px solid var(--qf-line);
  background: var(--surface-page);
  border-radius: var(--radius-circle);
}

.dm-timeline-item.is-open .dm-timeline-node { border-color: var(--text-brand); background: var(--text-brand); }
.dm-timeline-item.is-done .dm-timeline-node { border-color: var(--qf-ink-30); background: var(--qf-ink-30); }

.dm-timeline-date {
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  color: var(--text-brand);
  margin-block-end: var(--space-2);
}

.dm-timeline-item.is-done .dm-timeline-date { color: var(--text-subtle); }
.dm-timeline-title { font-size: var(--text-title-2); margin-block-end: var(--space-2); }
.dm-timeline-title a { text-decoration: none; display: inline-flex; align-items: center; gap: var(--space-2); }
.dm-timeline-title a:hover .dm-inline-arrow { transform: translateX(4px); }
.dm-timeline-title .dm-inline-arrow { transition: transform var(--duration-base) var(--ease-out); }
.dm-timeline-note { color: var(--text-muted); max-inline-size: 58ch; margin-block-end: var(--space-3); }

/* A passed deadline recedes rather than disappearing: the sequence is the story,
   and hiding the first three steps makes the fourth look like the first.

   0.7 rather than 0.55 — opacity multiplies against the text contrast underneath,
   so 0.55 dragged a 4.5:1 status pill down to roughly 2.5:1 and the recession
   stopped being a visual weighting and started being an accessibility problem. The
   item still clearly reads as past. */
.dm-timeline-item.is-done { opacity: 0.7; }

/* --------------------------------------------------------------- 16. Venue */

.dm-venue { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); gap: var(--space-16); align-items: center; }

/* A drawn plan rather than an embedded map: no third-party script, no consent
   banner, no layout shift when a tile server is slow. */
.dm-plan {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface-tint);
  border: var(--border-hairline);
  overflow: hidden;
}

.dm-plan-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--qf-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--qf-line) 1px, transparent 1px);
  background-size: 32px 32px;
  opacity: 0.55;
}

/* The blocks are <button>s now, so the plan is explorable: hover, focus or tap one and
   the caption strip at the foot of the plan becomes that space's name and note. All of
   it in CSS — see the note on dm_plan() for why there is no script here. */
.dm-plan-block {
  position: absolute;
  display: grid;
  place-items: center;
  appearance: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--text-brand);
  /* Tinted from the theme-aware token so the wash survives the dark ground. */
  background: color-mix(in srgb, var(--text-brand) 10%, transparent);
  font-family: inherit;
  font-size: var(--text-micro);
  font-weight: var(--weight-semibold);
  color: var(--text-brand);
  cursor: pointer;
  transition:
    background var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}

/* Hover and focus land on the same state on purpose: a keyboard reader and a mouse
   reader are asking the plan the same question. */
.dm-plan-block:is(:hover, :focus) {
  background: color-mix(in srgb, var(--text-brand) 22%, transparent);
  border-color: var(--text-brand);
  /* Lifts a hair towards the reader rather than growing, which would make the block
     overlap its neighbours and misstate the plan. */
  transform: translateY(-2px);
}

.dm-plan-block em { font-style: normal; }
/* ---- Where the blocks sit ----

   Everything stays above 78%, because the caption strip owns the bottom of the plan and
   a block underneath it would be covered by the very panel that describes it — hovering
   the quiet rooms would hide the quiet rooms. The strip is two lines at its tallest,
   which is about 16% of the shorter plan, so 78% is the line with a margin. */
.dm-plan-block--hall { inset-inline-start: 12%; inset-block-start: 18%; inline-size: 38%; block-size: 34%; }
.dm-plan-block--rooms { inset-inline-start: 56%; inset-block-start: 26%; inline-size: 30%; block-size: 36%; }
.dm-plan-block--atrium { inset-inline-start: 16%; inset-block-start: 58%; inline-size: 30%; block-size: 18%; background: color-mix(in srgb, var(--accent-editorial) 18%, transparent); border-color: var(--accent-editorial); }
.dm-plan-block--atrium { color: var(--accent-editorial); }
.dm-plan-block--atrium:is(:hover, :focus) { background: color-mix(in srgb, var(--accent-editorial) 32%, transparent); border-color: var(--accent-editorial); }

/* Added with the interaction: the prayer and quiet rooms were a facility the venue page
   listed in words and the plan did not show at all. It sits under the committee rooms,
   in the one part of the drawing that was empty. */
.dm-plan-block--quiet { inset-inline-start: 56%; inset-block-start: 66%; inline-size: 30%; block-size: 12%; }

/* Beside the entrance, not in the middle of the hall.
   It used to sit at 30%/33% — dead centre of the General Assembly block, which is also
   where that block centres its own label, so the dot printed straight through the "GA"
   and made it unreadable. It never mattered while the blocks were decorative spans; it
   does now that the label is the visible name of a control. Out here it reads as what a
   pulsing dot on a plan should read as: this is where you arrive. */
.dm-plan-pulse {
  position: absolute;
  inset-inline-start: 8%;
  inset-block-start: 66%;
  inline-size: 10px;
  block-size: 10px;
  background: var(--qf-orange);
  border-radius: var(--radius-circle);
  animation: dm-pulse-orange 2.6s var(--ease-standard) infinite;
}

@keyframes dm-pulse-orange {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 103, 31, 0.5); }
  70% { box-shadow: 0 0 0 12px rgba(255, 103, 31, 0); }
}

/* Top corner, not bottom: the caption strip owns the bottom edge now, and two pieces of
   type in one corner read as a collision rather than as a plan. */
.dm-plan-label {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-end: var(--space-4);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
}

/* ---- The caption strip ----

   One strip at the foot of the plan, with every panel stacked in it and only the active
   one at full opacity. The panels are emitted after every button so the general sibling
   combinator can reach them, which is the whole mechanism: no script, no state, and it
   works before motion.js has loaded.

   opacity rather than display or visibility, because these panels are the targets of
   aria-describedby on the buttons — kept in the accessibility tree and readable while
   they are invisible, so a screen reader hears each space's note without any of them
   ever being announced twice. */
.dm-plan-cap {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: var(--space-4) var(--space-5);
  background: var(--surface-inverse);
  color: var(--text-on-dark);
  font-size: var(--text-micro);
  line-height: 1.5;
  text-align: start;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out);
}

.dm-plan-cap strong { display: block; font-weight: var(--weight-semibold); }

/* The hint holds the strip until the reader asks it something. */
.dm-plan-cap--hint { opacity: 1; }
.dm-plan-block:is(:hover, :focus) ~ .dm-plan-cap--hint { opacity: 0; }

.dm-plan-block--hall:is(:hover, :focus) ~ .dm-plan-cap--hall,
.dm-plan-block--rooms:is(:hover, :focus) ~ .dm-plan-cap--rooms,
.dm-plan-block--atrium:is(:hover, :focus) ~ .dm-plan-cap--atrium,
.dm-plan-block--quiet:is(:hover, :focus) ~ .dm-plan-cap--quiet { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .dm-plan-block, .dm-plan-cap { transition: none; }
  .dm-plan-block:is(:hover, :focus) { transform: none; }
  .dm-plan-pulse { animation: none; }
}

/* ----------------------------------------------------------------- 17. FAQ */

.dm-faq { border-block-start: var(--border-hairline); }

.dm-faq-item { border-block-end: var(--border-hairline); }

.dm-faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-block: var(--space-5);
  cursor: pointer;
  list-style: none;
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  transition: color var(--duration-fast) var(--ease-out);
}

.dm-faq-item summary::-webkit-details-marker { display: none; }
.dm-faq-item summary:hover { color: var(--text-brand); }

/* A plus that becomes a minus. Two bars, one of which rotates — cheaper than an
   icon swap and it animates. */
.dm-faq-mark { position: relative; flex: 0 0 auto; inline-size: 16px; block-size: 16px; }

.dm-faq-mark::before,
.dm-faq-mark::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: 1.5px;
  background: currentColor;
  transition: transform var(--duration-base) var(--ease-out);
}

.dm-faq-mark::after { transform: rotate(90deg); }
.dm-faq-item[open] .dm-faq-mark::after { transform: rotate(0deg); }

.dm-faq-a { padding-block-end: var(--space-6); color: var(--text-muted); max-inline-size: 68ch; }
.dm-faq-item[open] .dm-faq-a { animation: dm-faq-open 0.35s var(--ease-out); }

@keyframes dm-faq-open {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

/* ----------------------------------------------------------------- 18. CTA */

.dm-cta { overflow: hidden; }

.dm-cta-grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--space-12); align-items: center; }
.dm-cta-actions { display: flex; flex-wrap: wrap; gap: var(--space-4); }

.dm-cta .dm-lede { margin-block-end: 0; }

/* The drifting radial glow that used to sit here is gone, along with its keyframes.
   It was the one element on the site whose shape had no reason behind it — a blurred
   circle slowly scaling in a design made of hairlines and right angles. The chamber
   pattern (part three) took the job, and it means something. */

/* --------------------------------------------------- 19. Interior page hero */

.dm-pagehero { padding-block: var(--space-16) var(--space-12); }
.dm-pagehero .dm-bititle { font-size: var(--text-display-2); }
.dm-pagehero .dm-lede { margin-block-end: 0; }

.dm-pagehero-rule {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: 1px;
  background: var(--qf-line);
}

/* --------------------------------------------------------- 20. Editor content
   Interior pages may carry block-editor content beneath the template sections.
   It inherits the same measure and rhythm rather than Astra's. */

.dm-entry { max-inline-size: var(--container-text); }
.dm-entry > * + * { margin-block-start: var(--space-6); }
.dm-entry :is(h2, h3) { margin-block-start: var(--space-12); }
.dm-entry p { color: var(--text-muted); font-size: var(--text-body-lg); }
.dm-entry :is(ul, ol) { list-style: revert; padding-inline-start: var(--space-6); color: var(--text-muted); }
.dm-entry li + li { margin-block-start: var(--space-2); }

/* ------------------------------------------------------------ 21. Responsive */

@media (max-width: 1100px) {
  .dm-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--space-12); }
  /* The connector only makes sense along an unbroken row. */
  .dm-step-link { display: none; }
  .dm-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .dm-section { padding-block: var(--section-y-sm); }
  .dm-split,
  .dm-theme-grid,
  .dm-venue,
  .dm-cta-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-10); }
  .dm-triptych { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); margin-block-start: var(--space-10); }
  .dm-wheel-svg { inline-size: min(100%, 17rem); }
  .dm-hero { min-block-size: auto; padding-block: var(--space-12) var(--space-16); }
  .dm-hero-title { font-size: var(--text-display-2); max-inline-size: none; }
  .dm-hero-scroll { display: none; }
}

@media (max-width: 620px) {
  .dm-stats { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .dm-steps { grid-template-columns: minmax(0, 1fr); }
  .dm-placards { grid-template-columns: minmax(0, 1fr); }
  .dm-countdown-units { gap: var(--space-5); }
  .dm-countdown-value { font-size: var(--text-title-2); }
  .dm-hero-actions .qf-btn.dm-btn-lg { inline-size: 100%; justify-content: center; }
  .dm-timeline { padding-inline-start: var(--space-8); }
  .dm-timeline-node { inset-inline-start: calc(var(--space-8) * -1 + 3px); }
  .dm-timeline-rail { inset-inline-start: 5px; }
  .dm-rule { border-inline-end: 0; }
}

/* ------------------------------------------------- 22. Reduced motion, print

   qf-chrome.css already collapses every transition and animation inside
   .qf-page, which covers this file too. What that cannot do is neutralise a
   start state, so anything holding an element at opacity 0 or off its position
   is released here — otherwise a reader who asks for less motion gets a blank
   page instead of a still one. motion.js makes the same check before it starts
   any JavaScript-driven animation. */

@media (prefers-reduced-motion: reduce) {
  .dm-motion :is([data-dm-reveal], [data-dm-reveal] > *, [data-dm-split] .dm-word-i, [data-dm-reveal="stagger"] > *) {
    opacity: 1 !important;
    transform: none !important;
  }

  .dm-motion :is(.dm-eyebrow-tick, .dm-bititle-rule, .dm-tri::before, .dm-step-link, .dm-hero-line--accent::after) {
    transform: none !important;
  }

  .dm-motion .dm-wheel .dm-wheel-spoke,
  .dm-motion .dm-wheel .dm-wheel-num { opacity: 1 !important; transform: none !important; }

  .dm-marquee-track { animation: none; transform: none; }
  .dm-hero-scroll-line::after,
  .dm-pill--open .dm-pill-dot,
  .dm-now-dot,
  .dm-plan-pulse { animation: none; }
  .dm-now-progress-fill { transition: none; }
}

@media print {
  .dm-hero-canvas,
  .dm-hero-scrim,
  .dm-marquee,
  .dm-hero-scroll,
  .dm-plan { display: none; }

  .dm-section { padding-block: var(--space-8); break-inside: avoid; }
  .dm-section--brand,
  .dm-section--ink { background: none; color: var(--qf-ink); }
  .dm-section--brand :is(h1, h2, h3), .dm-section--ink :is(h1, h2, h3) { color: var(--qf-ink); }
  .dm-faq-a { display: block; }
}

/* ============================================================================
   PART TWO — interior page components

   Everything above is the front page's vocabulary, most of which the interior
   pages reuse. What follows is the set of things only one or two pages need. They
   are here rather than in per-page stylesheets because they share the same tokens
   and the same three or four structural habits — hairline edges, square corners,
   a coloured top rule carrying meaning — and splitting them across files is how a
   design system quietly turns into five design systems.
   ============================================================================ */

/* -------------------------------------------------------- 23. Committee key */

.dm-key {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-8);
  padding-block: var(--space-5);
  border-block: var(--border-hairline);
}

.dm-key-item { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-body-sm); }

/* The same three colours the placards carry on their top edge, so the key is
   genuinely a key and not a second, unrelated legend. */
.dm-key-swatch { inline-size: var(--space-8); block-size: 3px; background: var(--text-brand); }
.dm-key-swatch[data-lang="ar"] { background: var(--qf-orange); }
.dm-key-swatch[data-lang="both"] { background: var(--qf-mint); }

.dm-key-count {
  min-inline-size: 22px;
  padding-inline: 6px;
  text-align: center;
  background: var(--surface-tint);
  font-size: var(--text-micro);
  font-weight: var(--weight-semibold);
  color: var(--text-muted);
}

.dm-key-item--total { margin-inline-start: auto; color: var(--text-brand); font-weight: var(--weight-medium); }

/* Full cards run wider: two topics and a blurb do not fit a 17rem column. */
.dm-placards--full { grid-template-columns: repeat(auto-fill, minmax(23rem, 1fr)); }

/* ------------------------------------------------------------- 24. Schedule */

.dm-tablist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  border-block-start: var(--border-hairline);
  margin-block-end: var(--space-12);
}

.dm-tab {
  appearance: none;
  background: none;
  border: 0;
  border-block-start: 3px solid transparent;
  border-inline-end: var(--border-hairline);
  padding: var(--space-5) var(--space-4);
  text-align: start;
  font-family: inherit;
  cursor: pointer;
  display: grid;
  gap: var(--space-1);
  transition: background var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out);
}

.dm-tab:last-child { border-inline-end: 0; }
.dm-tab:hover { background: var(--surface-tint); }

.dm-tab[aria-selected="true"] {
  border-block-start-color: var(--text-brand);
  background: var(--surface-tint);
}

.dm-tab-day {
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.dm-lang-ar .dm-tab-day { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-tab-weekday { font-size: var(--text-title-3); font-weight: var(--weight-semibold); color: var(--qf-ink); }
.dm-tab[aria-selected="true"] .dm-tab-weekday { color: var(--text-brand); }
.dm-tab-date { font-size: var(--text-body-sm); color: var(--text-subtle); }

.dm-tabpanel:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 4px; }

/* The panel fades in on switch, so the change registers without the layout
   jumping. One property, one short duration — a slide here would fight the
   reveals already running down the page. */
.dm-tabpanel.is-in { animation: dm-panel 0.32s var(--ease-out); }

@keyframes dm-panel {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.dm-day-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-4);
  margin-block-end: var(--space-8);
}

.dm-day-title { font-size: var(--text-display-3); }

.dm-agenda { display: grid; }

.dm-agenda-row {
  display: grid;
  grid-template-columns: 5.5rem auto minmax(0, 1fr);
  align-items: start;
  gap: var(--space-5);
  padding-block: var(--space-5);
  border-block-end: var(--border-hairline);
}

.dm-agenda-row:first-child { border-block-start: var(--border-hairline); }

.dm-agenda-time {
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--text-brand);
}

/* A short vertical tick rather than a full rail: the rows already have hairlines
   between them, and a second continuous line would box the table in. */
.dm-agenda-rule { inline-size: 2px; block-size: 1.4em; background: var(--qf-line); margin-block-start: 0.15em; }

.dm-agenda-body { display: grid; gap: var(--space-2); }
.dm-agenda-name { font-size: var(--text-body-lg); }

.dm-agenda-where {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-body-sm);
  color: var(--text-subtle);
}

/* Same "now" the live card above shows, on the row itself — a box-shadow inset
   rather than a border, so the highlight never nudges the grid's own columns. */
.dm-agenda-row.is-now {
  background: var(--surface-tint);
  box-shadow: inset 3px 0 0 0 var(--text-brand);
}

.dm-agenda-row.is-now .dm-agenda-time { color: var(--text-brand); }
.dm-agenda-row.is-past { opacity: 0.55; }

/* -------------------------------------------------------- 24b. Happening now */

.dm-now {
  display: grid;
  gap: var(--space-3);
  border: var(--border-hairline);
  background: var(--surface-card);
  padding: var(--space-6);
}

.dm-now-kicker {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.dm-lang-ar .dm-now-kicker { text-transform: none; letter-spacing: var(--tracking-normal); }

.dm-now-kicker--live { color: var(--text-brand); }

.dm-now-dot {
  inline-size: 7px;
  block-size: 7px;
  background: currentColor;
  border-radius: var(--radius-circle);
  flex: 0 0 auto;
  animation: dm-pulse 2.4s var(--ease-standard) infinite;
}

.dm-now-headline,
.dm-now-title { font-size: var(--text-title-2); font-weight: var(--weight-semibold); }

.dm-now-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-body-sm);
  color: var(--text-subtle);
}

.dm-now-meta svg { flex: 0 0 auto; }
.dm-now-sep { color: var(--qf-line); }
.dm-now-also { font-size: var(--text-body-sm); color: var(--text-subtle); }

.dm-now-preview { margin-block-start: var(--space-1); font-size: var(--text-body-sm); }

.dm-now-next {
  display: grid;
  gap: var(--space-2);
  border-block-start: var(--border-hairline);
  padding-block-start: var(--space-4);
  margin-block-start: var(--space-2);
}

/* Same custom-property convention as .dm-timeline-fill: the script only ever
   sets --dm-progress, never touches the element's other styling. */
.dm-now-progress {
  position: relative;
  inline-size: 100%;
  block-size: 4px;
  background: var(--qf-line);
  overflow: hidden;
}

.dm-now-progress-fill {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--dm-progress, 0%);
  background: var(--text-brand);
  transition: inline-size 0.3s var(--ease-standard);
}

/* ----------------------------------------------------------------- 25. Fork */

.dm-fork {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  gap: var(--space-8);
}

.dm-fork-side {
  border: var(--border-hairline);
  border-block-start: 3px solid var(--qf-ink);
  padding: var(--space-8);
  display: grid;
  gap: var(--space-3);
  align-content: start;
}

.dm-fork-side--school { border-block-start-color: var(--text-brand); }

.dm-fork-icon { color: var(--text-brand); }
.dm-fork-title { font-size: var(--text-title-1); }
.dm-fork-body { color: var(--text-muted); }

.dm-fork-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-2);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  color: var(--qf-orange);
}

/* The "or" sits on the axis between the two panels, on its own rule. */
.dm-fork-or {
  align-self: center;
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border: var(--border-hairline);
  background: var(--surface-page);
  font-size: var(--text-body-sm);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-subtle);
}

.dm-lang-ar .dm-fork-or { text-transform: none; letter-spacing: var(--tracking-normal); }

/* --------------------------------------------------------------- 26. Notice */

/* The accent edge goes on the top, not the side.

   Everywhere else on this site a 3px coloured edge sits on the top of a block and
   encodes something: the placard's working language, the desk that is safeguarding
   rather than general enquiries, whether an application route runs through a school
   or through you, which day of the schedule is showing. This notice was the one
   place with the accent on the inline-start edge, which made it the only decorative
   use of the device and gave the page two conventions where it should have one. The
   orange icon beside the heading already carries the signal. */
.dm-notice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-4);
  margin-block-start: var(--space-12);
  padding: var(--space-6);
  border: var(--border-hairline);
  border-block-start: 3px solid var(--qf-orange);
  background: var(--surface-card);
}

.dm-notice-icon { color: var(--qf-orange); }
.dm-notice-title { font-weight: var(--weight-semibold); margin-block-end: var(--space-2); }
.dm-notice-body { color: var(--text-muted); margin-block-end: var(--space-3); }

/* ------------------------------------------------------------- 27. Glossary */

.dm-glossary { margin-block-start: var(--space-16); border-block-start: 1px solid var(--dm-rule-line); padding-block-start: var(--space-8); }

.dm-glossary-title {
  font-size: var(--text-title-2);
  color: var(--qf-white);
  margin-block-end: var(--space-6);
}

.dm-glossary-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); gap: 0; }

/* Each pair is a row of two, divided by a hairline — the same Arabic/English
   division the headings and the lockup use, at reference-table density. */
.dm-glossary-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--dm-rule-line);
  border-inline-end: 1px solid var(--dm-rule-line);
  padding-inline-end: var(--space-4);
}

.dm-glossary-row dt { color: rgba(255, 255, 255, 0.9); font-size: var(--text-body-sm); }
.dm-glossary-row dd {
  margin: 0;
  color: var(--qf-mint);
  font-family: var(--font-arabic);
  font-size: var(--text-body-sm);
  text-align: end;
}

/* ------------------------------------------------- 28. Language split figure */

/* Eight cells, one per committee, coloured by working language. A bar chart would
   need a scale and an axis to say the same thing; eight squares say it at a
   glance, which is all this is for. */
.dm-langsplit {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2);
  max-inline-size: 22rem;
  margin-inline-start: auto;
}

.dm-langsplit-cell {
  aspect-ratio: 1;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.dm-langsplit-cell[data-lang="ar"] { background: var(--qf-orange); border-color: var(--qf-orange); }
.dm-langsplit-cell[data-lang="both"] { background: var(--qf-mint); border-color: var(--qf-mint); }

.dm-motion .dm-langsplit[data-dm-reveal] .dm-langsplit-cell { opacity: 0; transform: scale(0.7); }

.dm-motion .dm-langsplit[data-dm-reveal].is-in .dm-langsplit-cell {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s var(--ease-out), transform 0.55s var(--ease-out);
  transition-delay: calc(var(--dm-i) * 70ms);
}

/* -------------------------------------------------------- 29. Vacant posts */

.dm-role--vacant { border-style: dashed; }

.dm-role-vacant {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: auto;
  padding-block-start: var(--space-4);
  font-size: var(--text-body-sm);
  color: var(--text-subtle);
}

/* An open square, not a filled dot: the post is empty, and the mark says so. */
.dm-role-vacant-mark {
  inline-size: 9px;
  block-size: 9px;
  border: 1.5px solid var(--qf-ink-30);
}

.dm-cta-deadline { font-size: var(--text-body-sm); color: rgba(255, 255, 255, 0.82); inline-size: 100%; }
.dm-cta-deadline strong { color: var(--qf-yellow); font-weight: var(--weight-semibold); }

/* ------------------------------------------------------------ 30. Documents */

.dm-docs { display: grid; border-block-start: var(--border-hairline); }

.dm-doc {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-6);
  padding-block: var(--space-6);
  border-block-end: var(--border-hairline);
}

.dm-doc-icon { color: var(--text-brand); }
.dm-doc-title { font-size: var(--text-title-3); margin-block-end: var(--space-2); }
.dm-doc-note { color: var(--text-muted); font-size: var(--text-body-sm); max-inline-size: 62ch; }

/* A pending document recedes but stays legible: the reader is being told when it
   arrives, which is information, not an apology. */
.dm-doc--pending .dm-doc-icon { color: var(--qf-ink-30); }

.dm-doc-due { text-align: end; }

.dm-doc-due-label {
  display: block;
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.dm-lang-ar .dm-doc-due-label { text-transform: none; letter-spacing: var(--tracking-normal); }
/* No nowrap. "With assignments, December 2026" is the longest string this slot
   ever holds and it fits a phone column only just; one longer date phrase, or the
   Arabic equivalent in a wider face, and a nowrap here would push the page
   sideways. Wrapping a date over two lines costs nothing. */
.dm-doc-due-when { display: block; font-size: var(--text-body-sm); color: var(--qf-ink); text-wrap: balance; }
.dm-doc-action { white-space: nowrap; }

/* ----------------------------------------------------------------- 31. Desks */

.dm-desks { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: var(--space-6); }

.dm-desk {
  display: grid;
  gap: var(--space-3);
  align-content: start;
  border: var(--border-hairline);
  border-block-start: 3px solid var(--text-brand);
  padding: var(--space-6);
}

/* Safeguarding is picked out, because somebody looking for it is usually looking
   for it in a hurry and should not have to read four cards to find it. */
.dm-desk--priority { border-block-start-color: var(--qf-adham); background: var(--surface-tint); }
.dm-desk--priority .dm-desk-icon { color: var(--qf-adham); }

.dm-desk-icon { color: var(--text-brand); }
.dm-desk-title { font-size: var(--text-title-3); }
.dm-desk-note { font-size: var(--text-body-sm); color: var(--text-muted); }

.dm-desk-mail {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-2);
  font-weight: var(--weight-medium);
  word-break: break-word;
  border-block-end: 1px solid currentColor;
  padding-block-end: 2px;
  justify-self: start;
}

.dm-plan--lg { aspect-ratio: 3 / 2; }
.dm-empty { color: var(--text-subtle); font-style: italic; }

/* ---------------------------------------------------- 32. Responsive, part two */

@media (max-width: 1000px) {
  .dm-glossary-list { grid-template-columns: minmax(0, 1fr); }
  .dm-langsplit { margin-inline-start: 0; }
}

@media (max-width: 900px) {
  /* The fork stops being a fork and becomes a sequence; the "or" turns into a
     divider between them rather than a hinge between columns. */
  .dm-fork { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .dm-fork-or { justify-self: center; }
  .dm-placards--full { grid-template-columns: minmax(0, 1fr); }
  .dm-doc { grid-template-columns: auto minmax(0, 1fr); }
  .dm-doc-action, .dm-doc-due { grid-column: 2; text-align: start; }
}

@media (max-width: 620px) {
  /* Four tabs in a row at 375px gives each 80px, which fits neither a weekday nor
     a date. Two rows of two keeps both readable. */
  .dm-tablist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dm-tab { border-inline-end: var(--border-hairline); border-block-end: var(--border-hairline); }
  .dm-tab:nth-child(2n) { border-inline-end: 0; }

  .dm-agenda-row { grid-template-columns: 4rem minmax(0, 1fr); gap: var(--space-3); }
  .dm-agenda-rule { display: none; }
  .dm-agenda-time { font-size: var(--text-body); }
  .dm-day-title { font-size: var(--text-title-1); }
  .dm-key-item--total { margin-inline-start: 0; }
  .dm-glossary-row { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); padding-inline-end: 0; border-inline-end: 0; }
  .dm-glossary-row dd { text-align: start; }
}

@media (prefers-reduced-motion: reduce) {
  .dm-motion .dm-langsplit .dm-langsplit-cell { opacity: 1 !important; transform: none !important; }
  .dm-tabpanel.is-in { animation: none; }
}

/* ============================================================================
   PART THREE — image areas and the chamber pattern

   The design was correct and airless: eleven pages of hairlines and type with
   nothing for the eye to rest on. These are the slots that fix that, and the
   pattern that fills them until the conference owns photographs of its own.

   The pattern is assets/img/pattern-chamber.svg — the concentric seating arcs of a
   General Assembly hall, generated to the same hairline weight as the rest of the
   system. It is applied through `mask-image` rather than `background-image`, which
   is the whole trick: the mark takes its colour from a token, so it is Sidra green
   on the light theme and a lifted tint on the dark one without a second asset and
   without a colour hardcoded anywhere.
   ============================================================================ */

/* ------------------------------------------------------------- 33. Figures */

.dm-figure {
  position: relative;
  display: block;
  margin: 0;
  aspect-ratio: var(--dm-ratio, 16 / 9);
  background: var(--surface-tint);
  border: var(--border-hairline);
  overflow: hidden;
  isolation: isolate;
}

/* block-size: 100% is load-bearing and was being lost to the element reset at the
   top of this file — see the note there. Without it the image sized itself from its
   own intrinsic ratio instead of filling the frame, `overflow: hidden` clipped the
   remainder, and `object-fit: cover` appeared broken when it was simply never
   running: cover has nothing to do when the box already matches the image's
   proportions. */
.dm-figure-img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* A photograph arrives with its own colour temperature and this site is built on
     one accent. A touch of desaturation settles a warm image into the palette
     without turning the page monochrome. */
  filter: saturate(0.94);
  transition: transform 1.2s var(--ease-out), filter var(--duration-slow) var(--ease-out);
}

/* Slow, small, and only on a band — a whole page of zooming photographs is the
   thing that makes a site feel like a template. */
.dm-figure--band:hover .dm-figure-img { transform: scale(1.02); filter: saturate(1); }

/* The reveal: a wipe from the leading edge rather than a fade. Rectangular, in the
   reading direction, and it matches the rules that draw themselves in elsewhere.

   ── The clip goes on the contents, never on the figure ──────────────────────
   This rule used to put `clip-path: inset(0 100% 0 0)` on the figure itself, and
   that was a deadlock: the figure is the element `motion.js` hands to an
   IntersectionObserver, and an element clipped to zero area has an intersection
   rectangle of zero, so the observer never reports it as intersecting, so `.is-in`
   is never added, so the clip is never lifted. The band stayed empty permanently —
   invisible because it had not been revealed, and unrevealable because it was
   invisible.

   It survived review because the pattern state has no photograph in it: a clipped
   empty frame and an unclipped empty frame look identical. The first real image put
   into a band is what showed it.

   So the observed element keeps its full area and its children carry the wipe. The
   visual result is better anyway — the frame's hairline border and ground are
   present from the start and the content wipes in *within* them, rather than the
   whole panel growing out of nothing.

   The general rule this is an instance of: never let a reveal start state remove the
   observed element's area. Opacity and transform are safe; clip-path, `scale(0)` and
   zero height are not. */
.dm-motion .dm-figure[data-dm-reveal] {
  opacity: 1;
  transform: none;
  clip-path: none;
}

.dm-motion .dm-figure[data-dm-reveal] > * { clip-path: inset(0 100% 0 0); }

.dm-motion .dm-figure[data-dm-reveal].is-in > * {
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.9s var(--ease-out);
}

/* The caption sits on the photograph, so the scrim under it is load-bearing rather
   than decorative.

   --scrim-bottom is the design system's token and it is tuned for a large hero: it
   reaches full strength at the bottom edge and is fully transparent 60% of the way
   up. Over a caption box that is only one line and 64px tall, that means the top of
   the text has almost no scrim at all — which was invisible the first time a real
   photograph went into a band, because the crop landed on the marble wall of the
   QNCC atrium and white text met a near-white ground.

   So the gradient is stated here instead: still transparent at the top so it does
   not read as a bar, but holding above 55% opacity across the whole height the text
   actually occupies. The text-shadow is the belt to that braces — one line, and it
   costs nothing on a ground that is already dark. */
.dm-figure-caption {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: var(--space-5) var(--space-6);
  background: linear-gradient(
    to top,
    rgba(11, 16, 21, 0.88) 0%,
    rgba(11, 16, 21, 0.62) 62%,
    rgba(11, 16, 21, 0) 100%
  );
  color: var(--qf-white);
  font-size: var(--text-body-sm);
  text-shadow: 0 1px 3px rgba(11, 16, 21, 0.55);
}

/* ---- The pattern state ---- */

.dm-figure--pattern {
  background: var(--surface-tint);
  display: grid;
  place-items: center;
}

.dm-figure-pattern {
  position: absolute;
  inset: 0;
  /* mask, not background — see the note at the top of this part. */
  -webkit-mask-image: url("../img/pattern-chamber.svg");
  mask-image: url("../img/pattern-chamber.svg");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  /* Sized off the *height*, at a percentage chosen so the framing is identical at
     every aspect ratio this pattern is used at.

     For a background/mask percentage position the offset is
     (container − image) × position, so with the image at 170% of the container both
     terms scale with the container and 31% lands the podium just above the top edge
     with four arcs of seats below it — whether the frame is a 21:9 band or a 4:3
     portrait. Sizing off the width instead made the chamber a postage stamp in a
     wide band and overflowed a narrow one. */
  -webkit-mask-position: 50% 31%;
  mask-position: 50% 31%;
  -webkit-mask-size: auto 170%;
  mask-size: auto 170%;
  background: var(--text-brand);
  opacity: 0.16;
}

/* On the green and ink grounds the mark has to lift off the surface instead of
   sinking into it. */
.dm-section--brand .dm-figure--pattern,
.dm-section--ink .dm-figure--pattern { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.18); }
.dm-section--brand .dm-figure-pattern,
.dm-section--ink .dm-figure-pattern { background: var(--qf-mint); opacity: 0.22; }

/* A single yellow seat in the chamber — the one delegate with the floor. It is the
   only thing that moves in the pattern, and it is the same accent the headline and
   the open deadline use, spent once more. */
.dm-figure-mark {
  position: absolute;
  inset-block-start: 17%;
  inset-inline-start: 50%;
  inline-size: 14px;
  block-size: 5px;
  transform: translateX(-50%);
  background: var(--qf-yellow);
  opacity: 0.9;
  animation: dm-seat 4.2s var(--ease-standard) infinite;
}

@keyframes dm-seat {
  0%, 62%, 100% { opacity: 0.35; }
  70% { opacity: 1; }
}

/* Editors only. A visitor never sees this. */
.dm-figure-hint {
  position: absolute;
  inset-block-end: var(--space-3);
  inset-inline-start: var(--space-3);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px var(--space-3);
  background: var(--surface-page);
  border: var(--border-hairline);
  font-size: var(--text-micro);
  color: var(--text-subtle);
  max-inline-size: calc(100% - var(--space-6));
}

/* ---------------------------------------------------------------- 34. Bands */

/* The one thing on the site allowed out of the 1180px shell, which is what makes it
   read as a breath rather than as another block. .qf-main is already full-bleed
   here, so the band simply does not open a shell. */
.dm-band { position: relative; background: var(--surface-page); }
.dm-band .dm-figure { border-inline: 0; }

/* The band is sized by height, not by ratio.

   A ratio alone is wrong once the frame is full-bleed: 21:9 across a 1920px monitor
   is an 820px-tall photograph, which is most of a laptop screen spent on one image.
   Capping it with max-block-size looked like the fix and is not — Chrome honours the
   aspect ratio by pulling the *width* in with the height, so the band stopped being
   full-bleed and sat 350px short of the viewport edge.

   An explicit fluid height has no such coupling: 240px on a phone, 512px at the top
   end, 30vw between, and object-fit: cover takes the crop. */
.dm-figure--band {
  aspect-ratio: auto;
  block-size: clamp(15rem, 30vw, 32rem);
}

/* A band between two same-ground sections needs no hairlines of its own; between a
   tinted one and a white one it does. */
.dm-section--tint + .dm-band .dm-figure { border-block-start: 0; }

/* The clamp above already floors the band at 240px, so there is no narrow-screen
   letterbox to correct. */

/* -------------------------------------------------------------- 35. Gallery */

.dm-gallery {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-4);
  margin-block-start: var(--space-10);
}

.dm-gallery-item {
  position: relative;
  margin: 0;
  aspect-ratio: 1;
  overflow: hidden;
  border: var(--border-hairline);
  background: var(--surface-tint);
}

/* One lead image gives the row a subject. A uniform grid of six photographs reads
   as a contact sheet. */
.dm-gallery-item--lead { grid-column: span 2; grid-row: span 2; aspect-ratio: auto; }

.dm-gallery-img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  filter: saturate(0.94);
  transition: transform var(--duration-slow) var(--ease-out), filter var(--duration-slow) var(--ease-out);
}

.dm-gallery-item:hover .dm-gallery-img { transform: scale(1.03); filter: saturate(1); }

.dm-gallery-caption {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--scrim-bottom);
  color: var(--qf-white);
  font-size: var(--text-micro);
}

@media (max-width: 900px) {
  .dm-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dm-gallery-item--lead { grid-column: span 2; grid-row: auto; aspect-ratio: 3 / 2; }
}

/* --------------------------------------------------- 36. Pattern as ground */

/* The same mark, behind a band of type rather than inside a frame.

   Only ever on a Sidra-green or ink ground, never on a white or tinted section. That
   is the rule that keeps it from becoming wallpaper: the pattern belongs to the
   brand ground, so it appears at most once or twice per page and always where the
   page has already changed colour. */
.dm-pattern-ground {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: url("../img/pattern-chamber.svg");
  mask-image: url("../img/pattern-chamber.svg");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  /* Sized off the height for the same reason the framed version is, and pushed to
     the trailing edge so the arcs sweep in behind the type rather than sitting
     under it. Positioned at 108% before this, which pushed the whole chamber off
     the canvas and left only the rostrum showing — a stray grey rectangle in the
     corner that read as a rendering fault, because that is what it looked like. */
  -webkit-mask-position: 92% 38%;
  mask-position: 92% 38%;
  -webkit-mask-size: auto 165%;
  mask-size: auto 165%;
  background: var(--qf-white);
  opacity: 0.08;
}

/* RTL: the chamber is symmetrical about its own axis so it needs no mirroring, but
   its off-centre placement does — otherwise the watermark lands under the text
   instead of opposite it. */
.dm-lang-ar .dm-pattern-ground { -webkit-mask-position: 8% 38%; mask-position: 8% 38%; }

@media (prefers-reduced-motion: reduce) {
  /* Releases the children, because that is where the clip now lives. Left on the
     figure it would release nothing and a reader asking for less motion would get a
     permanently empty frame. */
  .dm-motion .dm-figure[data-dm-reveal] > * { clip-path: none !important; }
  .dm-figure-mark { animation: none; opacity: 0.9; }
  .dm-figure-img, .dm-gallery-img { transition: none; }
}

@media print {
  .dm-figure--pattern, .dm-pattern-ground { display: none; }
}

/* ------------------------------------------- 37. Ghost buttons on dark bands

   The DS ghost variant is transparent with no border, which is right on a white
   page — the shape comes from the surrounding hairlines. On the Sidra-green and ink
   bands there are none, so "Email the secretariat" rendered as a line of text
   floating beside a solid orange button and read as a broken control rather than a
   secondary one. A hairline in the on-dark rule colour gives it back its edges
   without competing with the primary action. */

.dm-section--brand .qf-btn.qf-btn--ghost,
.dm-section--ink .qf-btn.qf-btn--ghost {
  border: 1px solid rgba(255, 255, 255, 0.42);
  color: var(--qf-white);
}

.dm-section--brand .qf-btn.qf-btn--ghost:hover,
.dm-section--ink .qf-btn.qf-btn--ghost:hover {
  border-color: var(--qf-white);
  color: var(--qf-white);
  background: rgba(255, 255, 255, 0.08);
}

/* The wipe on .dm-btn-lg paints with currentColor, which on these bands is white at
   12% over green — close enough to the hover background to double up. */
.dm-section--brand .qf-btn.dm-btn-lg::after,
.dm-section--ink .qf-btn.dm-btn-lg::after { opacity: 0.16; }

/* ---------------------------------------------------- 38. Also on the site

   The row that replaced four home-page bands.

   The rules of the floor, the roles, the venue and the FAQ each had a full band on the
   home page, and each was a shorter retelling of a page that says the same thing
   properly. They came out; this row is what keeps those four pages one click from home.

   Deliberately not cards. Those bands were cut for height, and a card grid with a
   figure or an icon per route hands most of that height straight back — which is how a
   compact links row quietly becomes a fifth band. A heading, four links, four notes,
   and nothing that needs an image.

   The links themselves are .dm-textlink, not a new component: it already carries the
   hairline underline, the arrow nudge on hover and the RTL handling for both. */

.dm-also-heading {
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
  margin-block-end: var(--space-8);
}

/* Two columns, not four. Four routes across the full shell puts a link and its note
   ~340px apart and the pairing stops reading as a pair; two columns keep each note
   under the link it belongs to. */
.dm-also-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-8) var(--space-16);
  list-style: none;
}

.dm-also-note {
  margin-block-start: var(--space-3);
  max-inline-size: 52ch;
  font-size: var(--text-body-sm);
  color: var(--text-muted);
}

@media (max-width: 720px) {
  .dm-also-list { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); }
}

/* --------------------------------------------------------------- 39. Photo reel

   The front page's photograph band, as a row wider than the screen.

   ── Why a row and not the grid it replaced ──────────────────────────────────────
   The band was a four-frame asymmetric grid and it had no room for a fifth frame:
   everything that composition could hold it was already holding, and every way of
   adding to it turned a page into a contact sheet. A row has no such ceiling — the
   ninth frame costs what the fifth would have — and it says out loud what the grid
   could only imply, that there is more here than fits on the screen.

   ── Four things move, on four elements, because they cannot share a transform ────

     .dm-reel         the scroll position: dragged with a pointer, scrolled natively,
                      or advanced by motion.js while the band is on screen.
     .dm-reel-frame   opacity and lift, from the shared [data-dm-reveal="stagger"]
                      rules — the frames cascade in 65ms apart.
     .dm-reel-shift   the *vertical* parallax, driven by --dm-shift (set on the band by
                      motion.js from scroll position) times --dm-depth (set per frame in
                      PHP). Also the wipe. Vertical on a row that travels sideways: a
                      rail whose contents all move together is a conveyor, and the
                      difference between neighbours is the only place depth comes from.
     .dm-reel-img     the crop — object-position and zoom around --dm-focus.

   The lead frame's slow 24s scale drift did not survive the grid, and should not come
   back: the row itself is now moving, and a photograph breathing inside a moving row
   is two animations doing one job.

   ── The row is a real scroll container ──────────────────────────────────────────
   Native overflow, not a transformed track. So touch scrolling, momentum, a trackpad
   swipe, shift+wheel, arrow keys and Home/End all work before motion.js has loaded and
   if it never loads at all. The drag and the auto-advance are both written in terms of
   scrollLeft on this same element, so neither can disagree with the browser about where
   the row is — which is the failure mode of every transform-based carousel.

   The element the observer watches is .dm-reel and nothing clips it. The wipe is one
   level down, inside each frame. That is the rule the figure reveal deadlock produced
   and it is the one thing in this section not to change: an element clipped to zero
   area is never reported as intersecting, so it is never revealed, so it never regains
   its area. */

/* The band's heading sits in the shell while the frames stay full-bleed, which is the
   point: the type lines up with every other section's heading, and the photographs
   still run to the edge of the screen. Padding rather than the section rhythm — the
   band is not a .dm-section and should not open as much air as one. */
.dm-reel-head {
  padding-block: var(--space-12) var(--space-6);
}

/* The hint is the affordance and is styled to be read, not admired: a rule, then a
   sentence, at caption size in muted ink. A row of photographs cut off by the edge of
   the screen is only obviously draggable to somebody who has already tried it. */
.dm-reel-hint {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block: var(--space-4) var(--space-8);
  font-size: var(--text-caption);
  color: var(--text-muted);
}

.dm-reel-hint-rule {
  flex: 0 0 auto;
  inline-size: var(--space-8);
  block-size: 1px;
  background: currentColor;
  opacity: 0.55;
}

.dm-reel {
  display: flex;
  gap: var(--space-2);
  /* The row's height is every frame's height, so it is also what sets every frame's
     width — and the number that decides how many photographs are on screen at once.
     46vw was the grid's height and it put one and a bit frames in view on a laptop,
     which is a slideshow. 30vw puts two and a half to three in view at every width
     from a phone to a monitor, which is the least a row has to show to read as one. */
  block-size: clamp(15rem, 30vw, 24rem);
  overflow-x: auto;
  overflow-y: hidden;
  /* A drag or a swipe that runs out of row scrolls the row, never the page behind it
     and never the browser's back gesture. */
  overscroll-behavior-inline: contain;
  background: var(--surface-page);
  cursor: grab;
  /* The scrollbar is the one part of a native scroller this band does not want: a grey
     bar drawn under a full-bleed row of photographs, on a page that shows no other
     scrollbars. What the bar afforded is still said twice — the row visibly overflows
     the screen, and the hint above says so in words. */
  scrollbar-width: none;
}

.dm-reel::-webkit-scrollbar { display: none; }

/* Focusable because it scrolls; see the note in media.php. The ring is the shared one,
   inset so it is not clipped by the band's own edge. */
.dm-reel:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: -4px;
}

/* While a drag is in progress the pointer owns the row and nothing else may react to
   it: no text selection, no image ghost, and no hover magnification chasing the
   cursor across nine frames. The hover rules below are scoped to :not(.is-dragging)
   for the same reason. */
.dm-reel.is-dragging {
  cursor: grabbing;
  user-select: none;
}

.dm-reel.is-dragging .dm-reel-img { pointer-events: none; }

/* Each frame is its own shape. --dm-ratio comes from the window it shows, or from an
   uploaded photograph's real proportions — see dm_reel_ratio(). The height is the
   row's; the width follows from the ratio, which is what makes the row read as a
   sequence of photographs rather than as a filmstrip of identical cells. */
.dm-reel-frame {
  position: relative;
  flex: 0 0 auto;
  margin: 0;
  block-size: 100%;
  aspect-ratio: var(--dm-ratio, 4 / 3);
  overflow: hidden;
  isolation: isolate;
  border: var(--border-hairline);
  background: var(--surface-tint);
  transition: border-color var(--duration-base) var(--ease-out);
}

/* The parallax layer is oversized by twice the maximum drift, top and bottom, so a
   frame that has slid 44px has not slid its own edge into view. */
.dm-reel-shift {
  position: absolute;
  inset-inline: 0;
  inset-block: -3rem;
  display: block;
  transform: translate3d(0, calc(var(--dm-shift, 0px) * var(--dm-depth, 0)), 0);
  will-change: transform;
}

.dm-reel-img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* Both from the same custom property: object-position decides which part of the
     photograph the frame holds, transform-origin makes the zoom grow around that
     same point instead of around the middle of the box. */
  object-position: var(--dm-focus, 50% 50%);
  transform-origin: var(--dm-focus, 50% 50%);
  transform: scale(var(--dm-zoom, 1));
  filter: saturate(0.94);
  transition: transform 1.1s var(--ease-out), filter var(--duration-slow) var(--ease-out);
  /* A photograph in a draggable row must not start a native image drag under the
     pointer. motion.js cancels dragstart as well; this is the half that works with
     the script switched off. */
  -webkit-user-drag: none;
}

/* ---- Hover: one frame comes forward, the rest step back ----

   No transform on the frame itself. The reveal owns it at (0,3,0) — .dm-motion
   [data-dm-reveal="stagger"].is-in > * — and a hover rule that has to out-specify the
   thing that makes the band visible is a hover rule that will one day win at the wrong
   moment. The lift is a border and a magnification instead, which is quieter anyway
   and cannot strand a frame mid-reveal. */
.dm-reel:not(.is-dragging) .dm-reel-frame:hover { border-color: var(--dm-brass); }

.dm-reel:not(.is-dragging) .dm-reel-frame:hover .dm-reel-img {
  filter: saturate(1);
  transform: scale(calc(var(--dm-zoom, 1) * 1.05));
}

.dm-reel:not(.is-dragging):hover .dm-reel-frame:not(:hover) .dm-reel-img {
  filter: saturate(0.62) brightness(0.94);
}

/* ---- The wipe ----

   Each frame's contents wipe down from the top edge, in the stagger's order. Down
   rather than sideways: a horizontal wipe on a row that also scrolls horizontally is
   two sideways movements at once, and it read as a loading skeleton.

   inset() and not opacity, because the frames already fade in from the shared stagger
   rules and doing it twice makes a slow band rather than a layered one. */
.dm-motion .dm-reel .dm-reel-shift { clip-path: inset(0 0 100% 0); }

.dm-motion .dm-reel.is-in .dm-reel-shift {
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.9s var(--ease-out);
  transition-delay: calc(var(--dm-i, 0) * 90ms);
}

/* Clones. motion.js appends copies of the leading frames so the auto-advance can wrap
   without a seam; they are aria-hidden and they arrive after the reveal has indexed
   its children, so they carry no --dm-i and must not sit at a hidden start state
   waiting for one. */
.dm-motion .dm-reel .dm-reel-frame--clone .dm-reel-shift { clip-path: none; }
.dm-motion [data-dm-reveal="stagger"] > .dm-reel-frame--clone { opacity: 1; transform: none; }

/* ---- Narrow screens ----

   Shorter, so the widest frames stop being two screens across, and the row keeps the
   one thing it is for: several photographs visible at once. */
@media (max-width: 900px) {
  .dm-reel { block-size: clamp(15rem, 60vw, 20rem); }

  /* Less drift on a phone: the frames are wider relative to the viewport, so the same
     44px reads as twice the movement. Halved on the band, not per frame, so the depth
     relationships between frames are unchanged. */
  .dm-reel-shift { inset-block: -2rem; }

  .dm-reel-head { padding-block: var(--space-10) var(--space-5); }
}

@media (prefers-reduced-motion: reduce) {
  /* The clip release is the one that matters: left in its start state it would hide
     every frame's contents permanently, which is exactly what a reader asking for less
     motion did not ask for. The reel still scrolls and still drags — those are the
     reader's own movements, and motion.js is what declines to move it for them. */
  .dm-motion .dm-reel .dm-reel-shift,
  .dm-motion .dm-reel.is-in .dm-reel-shift { clip-path: none; transition: none; }
  .dm-reel-shift { transform: none; }
  .dm-reel-img { transition: none; }
}

@media print {
  /* Nine windows on one photograph is a page of ink, and a scroll container prints
     whatever happened to be scrolled into view. The lead says the same thing.

     The lead needs a box of its own once the row stops giving it one: its only child
     is absolutely positioned, so a bare block would collapse to nothing and the band
     would print as an empty hairline rectangle. */
  .dm-reel-frame:not(.dm-reel-frame--lead) { display: none; }
  .dm-reel { display: block; block-size: auto; overflow: visible; }
  .dm-reel-frame--lead { inline-size: 100%; aspect-ratio: 16 / 9; }
  .dm-reel-shift { inset-block: 0; }
  .dm-reel-hint { display: none; }
}

/* The maps button sits under the address list, not beside the link. */
.dm-plan-away { margin-block-start: var(--space-6); }

/* ------------------------------------------------------- 40. Search results page

   The server-rendered results, for a reader without JavaScript and for anyone who asks
   the overlay for the full list. The overlay's own styling is chrome and lives in
   dm-identity.css; this is the page underneath it.

   The two deliberately do not look identical. The overlay is a ranked run of rows read
   in one pass; this page is grouped, roomier, and sits inside the shell like every other
   band on the site — because a reader who arrived here did so on purpose. */

.dm-searchpage-form {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: var(--border-hairline);
  background: var(--surface-page);
  max-inline-size: 44rem;
}

.dm-searchpage-icon { display: inline-flex; color: var(--text-brand); }

.dm-searchpage-input {
  appearance: none;
  inline-size: 100%;
  padding: var(--space-2) 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: var(--text-body-lg);
  color: var(--qf-ink);
}

.dm-searchpage-input::placeholder { color: var(--text-subtle); }

.dm-searchpage-start,
.dm-searchpage-none { margin-block-start: var(--space-12); }

.dm-searchpage-label {
  margin-block-end: var(--space-4);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-subtle);
}

.dm-searchpage-none-title {
  font-family: var(--font-display);
  font-size: var(--text-title-2, 1.5rem);
  margin-block-end: var(--space-4);
}

.dm-searchpage-group { margin-block-start: var(--space-12); }

.dm-searchpage-group-title {
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-brand);
  padding-block-end: var(--space-3);
  border-block-end: var(--border-hairline);
}

.dm-searchpage-list { list-style: none; }

/* A hairline between rows, not around them: a grouped list of links is a list, and
   boxing each one turns eight results into eight cards to look at. */
.dm-searchpage-item + .dm-searchpage-item { border-block-start: var(--border-hairline); }

.dm-searchpage-link {
  display: grid;
  gap: 4px;
  padding: var(--space-4) var(--space-4) var(--space-4) 0;
  text-decoration: none;
  color: inherit;
  border-inline-start: 2px solid transparent;
  padding-inline-start: var(--space-4);
  transition: background var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out);
}

.dm-searchpage-link:hover {
  background: var(--surface-tint);
  border-inline-start-color: var(--dm-maroon);
}

.dm-searchpage-title {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  line-height: 1.3;
  color: var(--qf-ink);
}

.dm-searchpage-meta {
  font-size: var(--text-body-sm);
  color: var(--text-brand);
}

.dm-searchpage-snippet {
  font-size: var(--text-body-sm);
  color: var(--text-muted);
  max-inline-size: 78ch;
}

/* The suggestion chips are shared with the overlay, but here they are links rather than
   buttons — there is no script to hand a query to, so each one is a URL. */
.dm-searchpage-start .dm-search-chip { display: inline-block; text-decoration: none; }

@media (max-width: 620px) {
  .dm-searchpage-form {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: var(--space-3);
  }

  .dm-searchpage-form .qf-btn { grid-column: 1 / -1; }
}
