/* Quire — an editorial theme set in one measured column.
   Magazine conventions on screen: a controlled measure in ch, a display serif
   carrying the hierarchy, pull quotes and plates breaking the column, and a
   dense index that keeps its figures readable. No theme JavaScript: what moves
   is the platform's own motion runtime, and it is off under reduced motion.

   Every colour, size, radius, shadow and duration below is a custom property.
   Component rules read tokens and never literals, so a look is one edit. */

/* ── Tokens ─────────────────────────────────────────────────── */
:root {
  /* Type scale: a 1.243 ratio, shipped as the fluid value rather than the
     desktop pixel size, because re-deriving it by hand is where it drifts. */
  --fs-display: clamp(39px, calc(39px + 32 * ((100vw - 400px) / 1040)), 71px);
  --fs-h1:      clamp(31px, calc(31px + 26 * ((100vw - 400px) / 1040)), 57px);
  --fs-h2:      clamp(25px, calc(25px + 21 * ((100vw - 400px) / 1040)), 46px);
  --fs-h3:      clamp(22px, calc(22px + 15 * ((100vw - 400px) / 1040)), 37px);
  /* The standfirst sits two steps of the same 1.243 ratio below H3
     (37 / 1.243 / 1.243 ≈ 24), which is the step the published scale skips
     between H3 and Body large. It is on the scale, not beside it. */
  --fs-body-xl:  clamp(17px, calc(17px + 7 * ((100vw - 400px) / 1040)), 24px);
  --fs-body-lg: 16px;
  --fs-body:    13px;
  --fs-ui:      12px;
  --fs-caption: 11px;

  --lh-display: 1.05; --lh-h1: 1.15; --lh-h2: 1.2; --lh-h3: 1.3;
  --lh-body-lg: 1.6; --lh-body: 1.65; --lh-ui: 1.4; --lh-caption: 1.45;
  --tr-display: -.015em; --tr-h1: -.02em; --tr-h2: -.015em; --tr-h3: -.01em;
  --tr-caps: .14em;

  /* Spacing. Base unit 4px; every value below is a multiple of it. */
  --space-1: 4px;  --space-2: 8px;   --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px;  --space-7: 48px; --space-8: 64px;
  --space-9: 96px; --space-10: 128px;

  /* Shape. The radius scale steps from --radius-md, set in the layout. */
  --radius-md: 4px;
  --radius-sm: 2px; --radius-lg: 6px; --radius-xl: 9px; --radius-pill: 999px;
  --border-width: 1px;
  --shadow-sheet: 0 1px 2px rgb(0 0 0 / .06);

  /* Motion. Exits run at about two thirds of an entrance. */
  --dur-control: 150ms;
  --dur-surface: 210ms;
  --dur-reveal:  500ms;
  --dur-page:    650ms;
  --dur-exit:    100ms;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-out: var(--ease);

  /* State. Defaults, not derived from the palette — they are never the only
     signal, so each one is paired with a word and a mark. */
  --success: #0f7b45;
  --warning: #9a6200;
  --danger:  #b3261e;

  --measure: 68ch;
  --page-max: 720px;
  --section-pad: 32px;
  --pad: clamp(16px, 4vw, 32px);
  --grain: 2%;
  --grid-gap: var(--space-5);
  --card-radius: var(--radius-lg);
  --media-radius: var(--radius-md);
}

/* Semantic colour tokens, bound where the platform sets a scheme. Naming them
   for their role rather than their hue is what makes a palette one edit. */
.ab-scheme {
  --background: var(--color-background);
  --surface: var(--color-surface);
  --surface-elevated: color-mix(in oklch, var(--surface) 92%, black);
  --border: var(--color-border);
  --text-primary: var(--color-text);
  --text-secondary: var(--color-muted);
  --accent: var(--color-accent);
  --accent-hover: color-mix(in oklch, var(--accent) 86%, black);
  --accent-contrast: var(--color-accent-text, #fff);
  --focus-ring: var(--accent);
  background: var(--background);
  color: var(--text-primary);
}

/* ── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--space-9); }
body {
  margin: 0;
  font-family: var(--font-body-font, system-ui, sans-serif);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}
/* A <figure> carries `margin: 1em 40px` by default, and that 40px is what a
   full-bleed plate was inset by — the bleed track was doing its job and the
   figure sitting inside it was not. Every grouping element that ships with a
   margin is zeroed here rather than per component, because the next one added
   would inherit the same surprise. */
figure, blockquote, dl, dd, fieldset { margin: 0; }
fieldset { padding: 0; border: 0; min-width: 0; }
img, svg, video, iframe { max-width: 100%; }
img { display: block; height: auto; }
a { color: inherit; text-underline-offset: .18em; text-decoration-thickness: from-font; }
button, input, textarea, select { font: inherit; color: inherit; }
button, summary { cursor: pointer; }
a, button, input, textarea, summary { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  /* The second ring is the page ground, so the indicator clears 3:1 against
     the element it sits on and against whatever is behind it. */
  box-shadow: 0 0 0 4px var(--background);
}
::selection { background: var(--accent); color: var(--accent-contrast); }
.skip-link {
  position: fixed; top: -8rem; left: var(--space-4); z-index: 10001;
  padding: var(--space-3) var(--space-5);
  background: var(--text-primary); color: var(--background);
  border-radius: var(--radius-md); text-decoration: none;
}
.skip-link:focus { top: var(--space-4); }

/* The paper. Fibre laid over the ground and multiplied into it, so it darkens
   where the sheet is light and disappears where it is already dark — which is
   what keeps the dark region out of visible noise. Measured against the
   darkest patch of the grain, not its average. */
.q-grain {
  position: fixed; inset: 0; z-index: 2; pointer-events: none;
  opacity: var(--grain); mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23f)'/%3E%3C/svg%3E");
}
@media print { .q-grain { display: none; } }

/* ── Typography ─────────────────────────────────────────────── */
h1, h2, h3, h4, .h1, .h2, .h3, .h4, .q-display {
  font-family: var(--font-display-font, Georgia, serif);
  font-weight: var(--display-weight, 400);
  margin: 0;
  text-wrap: balance;
  overflow-wrap: break-word;
}
.q-display { font-size: var(--fs-display); line-height: var(--lh-display); letter-spacing: var(--tr-display); }
h1, .h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--tr-h1); }
h2, .h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--tr-h2); font-weight: 500; }
h3, .h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--tr-h3); font-weight: 600; }
h4, .h4 { font-size: var(--fs-body-lg); line-height: var(--lh-body-lg); letter-spacing: 0; font-weight: 600; }
p { margin: 0; }
p + p, .rte > * + * { margin-block-start: var(--space-4); }
.muted { color: var(--text-secondary); }
.measure { max-width: var(--measure); }
.measure--center { margin-inline: auto; }
.text-center { text-align: center; }
.rte a { color: var(--accent); text-decoration: underline; }
.rte a:hover { color: var(--accent-hover); }
.rte ul, .rte ol { margin: 0; padding-inline-start: var(--space-5); }
.rte li + li { margin-block-start: var(--space-2); }
.rte blockquote {
  margin: 0; padding-inline-start: var(--space-4);
  border-inline-start: var(--border-width) solid var(--accent);
  font-family: var(--font-display-font, Georgia, serif); font-style: italic;
}

/* A label: letterspaced capitals, set with letter-spacing and never by putting
   spaces inside the words, so a screen reader still reads them as words. */
.eyebrow, .q-label {
  display: block; margin: 0;
  font-size: var(--fs-ui); line-height: var(--lh-ui); font-weight: 500;
  color: var(--text-secondary);
}
.q-caps .eyebrow, .q-caps .q-label { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.q-label--accent { color: var(--accent); }
.q-caption { font-size: var(--fs-caption); line-height: var(--lh-caption); letter-spacing: .01em; color: var(--text-secondary); }

/* ── The column ─────────────────────────────────────────────── */
/* One measure, a full-bleed track either side. No 100vw anywhere: that
   technique overflows by the width of a scrollbar and fails reflow. */
.q-flow {
  display: grid;
  overflow-x: clip;
  grid-template-columns:
    [full-start] minmax(var(--pad), 1fr)
    [content-start] min(100% - var(--pad) * 2, var(--measure), var(--page-max))
    [content-end] minmax(var(--pad), 1fr)
    [full-end];
}
.q-flow > * { grid-column: content; min-width: 0; }
.q-flow > .q-bleed { grid-column: full; }
.q-section { padding-block: var(--section-pad); }
.q-section--tall { padding-block: calc(var(--section-pad) * 2); }
.page-width { width: min(100% - var(--pad) * 2, var(--page-max)); margin-inline: auto; }
/* The trim, not the text block. A running head and a colophon span the width
   of the sheet the way a magazine's do; only the reading column is measured. */
.q-trim { width: min(100% - var(--pad) * 2, var(--trim-max, 1180px)); margin-inline: auto; }
.section { padding-block: calc(var(--section-pad) * 1.5); }
.q-stack > * + * { margin-block-start: var(--space-5); }
.q-stack--tight > * + * { margin-block-start: var(--space-3); }

/* An opener: label, heading, standfirst, then the ornament. */
.q-opener { display: grid; gap: var(--space-3); }
.q-opener__intro { color: var(--text-secondary); max-width: var(--measure); font-size: var(--fs-body-xl); line-height: 1.5; }
.section-heading { display: grid; gap: var(--space-3); margin-block-end: var(--space-6); }
.section-head { display: grid; gap: var(--space-3); margin-block-end: var(--space-6); }
.section-head__intro { color: var(--text-secondary); margin: 0; }

/* ── Ornament (1925 Paris, stepped and symmetrical) ─────────── */
.q-orn { display: block; height: 16px; margin-block-start: var(--space-4); color: var(--accent); }
.q-orn-none .q-orn { display: none; }
.q-orn svg { display: block; height: 100%; width: auto; margin-inline: auto; overflow: visible; }
.q-orn--left svg { margin-inline: 0 auto; }
.q-orn path, .q-orn line, .q-orn rect { stroke: currentColor; fill: none; stroke-width: 1.1; vector-effect: non-scaling-stroke; }
.q-rule { border: 0; border-block-start: var(--border-width) solid var(--border); margin: 0; }
.q-rule--accent { border-color: var(--accent); }

/* ── Buttons ────────────────────────────────────────────────── */
/* Printed, not raised: a fill and a rule, a colour change on press. */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px; min-width: 44px; padding: var(--space-3) var(--space-5);
  border: var(--border-width) solid var(--color-button);
  border-radius: var(--radius-md);
  background: var(--color-button); color: var(--color-button-text);
  font-size: var(--fs-ui); line-height: var(--lh-ui); font-weight: 500;
  text-decoration: none; text-align: center;
  transition: background var(--dur-control) var(--ease), color var(--dur-control) var(--ease),
              border-color var(--dur-control) var(--ease), transform var(--dur-control) var(--ease);
}
.q-caps .button { text-transform: uppercase; letter-spacing: .08em; }
.button--secondary { background: transparent; color: var(--text-primary); border-color: var(--border); }
.button--quiet {
  min-height: 0; min-width: 0; padding: 0 0 2px; border: 0;
  border-block-end: var(--border-width) solid var(--accent);
  border-radius: 0; background: none; color: var(--accent);
}
.button--small { min-height: 36px; padding: var(--space-2) var(--space-4); }
.button-group { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-block-start: var(--space-5); }
@media (hover: hover) and (pointer: fine) {
  .button:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
  .button--secondary:hover { color: var(--accent-contrast); }
  .button--quiet:hover { background: none; color: var(--accent-hover); transform: none; }
}
.button:active { transform: translateY(1px); }
.button[aria-disabled="true"] { opacity: .55; pointer-events: none; }
.text-link {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--fs-ui); font-weight: 500; color: var(--accent); text-decoration: none;
  min-height: 24px;
}
.q-caps .text-link { text-transform: uppercase; letter-spacing: .1em; }
.text-link::after { content: "\2192"; transition: transform var(--dur-control) var(--ease); }
@media (hover: hover) and (pointer: fine) { .text-link:hover::after { transform: translateX(3px); } }

/* ── Forms: ruled fields, like a printed form ───────────────── */
.form { display: grid; gap: var(--space-5); }
/* Two fields across a row keep their labels, their rules and their hints on
   the same three lines. Without subgrid a hint under one field drops that
   field's rule below its neighbour's, which reads as a printing fault. */
.form__row { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
.field { display: grid; gap: var(--space-2); min-width: 0; align-content: start; }
@supports (grid-template-rows: subgrid) {
  .form__row { grid-template-rows: auto auto auto; }
  .form__row > .field { grid-row: span 3; grid-template-rows: subgrid; }
}
.field > label { font-size: var(--fs-ui); line-height: var(--lh-ui); font-weight: 500; color: var(--text-secondary); }
.q-caps .field > label { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.field__req { color: var(--accent); font-weight: 500; }
/* The field's rule is ink, not a tint. A hairline in --border is a divider —
   fine between rows, and not enough on its own to identify a control: WCAG asks
   for 3:1 on the visual boundary of a user-interface component, and a faint
   rule on paper is nearer 1.4:1. Drawing it in the supporting text colour
   clears that and is what a printed form looks like anyway. */
.field input, .field textarea, .field select {
  width: 100%; padding: var(--space-2) 0;
  border: 0; border-block-end: var(--border-width) solid var(--text-secondary);
  border-radius: 0; background: transparent; color: var(--text-primary);
  font-size: var(--fs-body-lg);
  transition: border-color var(--dur-control) var(--ease);
}
.field textarea { resize: vertical; }
.field input:hover, .field textarea:hover { border-color: var(--text-primary); }
.field input:focus-visible, .field textarea:focus-visible, .field select:focus-visible {
  outline: 2px solid var(--focus-ring); outline-offset: 4px; border-color: var(--accent);
}
.field__hint { font-size: var(--fs-caption); color: var(--text-secondary); }
.form__notice {
  display: grid; gap: var(--space-1); margin: 0;
  padding: var(--space-3) var(--space-4);
  border-inline-start: 3px solid var(--success);
  background: var(--surface); color: var(--text-primary);
  font-size: var(--fs-body-lg);
}
.form__notice--error { border-inline-start-color: var(--danger); }
.form__notice strong { font-weight: 600; }
.form__inert { font-size: var(--fs-caption); }

/* ── Cards, media and grids (shared by the list sections) ───── */
.card {
  border: var(--border-width) solid var(--border);
  border-radius: var(--card-radius);
  background: var(--surface);
  box-shadow: var(--shadow-sheet);
  padding: var(--space-4);
}
.grid { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(var(--columns-mobile, 1), minmax(0, 1fr)); }
@media (min-width: 750px) { .grid { grid-template-columns: repeat(min(var(--columns, 3), 2), minmax(0, 1fr)); } }
@media (min-width: 990px) { .grid { grid-template-columns: repeat(var(--columns, 3), minmax(0, 1fr)); } }
.media { position: relative; overflow: hidden; border-radius: var(--media-radius); background: var(--surface); }
.media > img, .media > svg { width: 100%; height: 100%; object-fit: cover; }
.media--square { aspect-ratio: 1; }
.media--portrait { aspect-ratio: 4 / 5; }
.media--landscape { aspect-ratio: 3 / 2; }
.media--wide { aspect-ratio: 16 / 9; }
.media--natural { aspect-ratio: auto; }
.media--natural > img { height: auto; }

/* ── Masthead (header) ──────────────────────────────────────── */
.site-header { border-block-end: var(--border-width) solid var(--border); position: relative; z-index: 60; }
.site-header--sticky { position: sticky; top: 0; }
.header-inner { display: flex; align-items: center; gap: var(--space-4); min-height: 64px; }
.wordmark {
  flex: 0 1 auto; min-width: 0;
  font-family: var(--font-display-font, Georgia, serif); font-weight: var(--display-weight, 400);
  font-size: var(--fs-body-lg); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.q-caps .wordmark { text-transform: uppercase; letter-spacing: .12em; }
.wordmark img { width: auto; max-width: 160px; max-height: 36px; object-fit: contain; }
.desktop-nav { display: flex; align-items: center; gap: var(--space-5); margin-inline-start: auto; font-size: var(--fs-ui); }
.desktop-nav a { position: relative; display: inline-flex; align-items: center; min-height: 24px; padding-block: var(--space-2); text-decoration: none; white-space: nowrap; }
/* The current page is marked with a rule as well as a colour. */
.desktop-nav a[aria-current] { color: var(--accent); }
.desktop-nav a[aria-current]::after {
  content: ""; position: absolute; inset-inline: 0; bottom: 0; height: 2px; background: currentColor;
}
@media (hover: hover) and (pointer: fine) { .desktop-nav a:hover { color: var(--accent); } }
.header-actions { display: flex; align-items: center; gap: var(--space-2); margin-inline-start: auto; }
.header-actions .desktop-nav { margin-inline-start: 0; }
.mobile-nav { display: none; position: relative; }
.mobile-nav > summary {
  list-style: none; display: grid; place-items: center; width: 44px; height: 44px;
  border: var(--border-width) solid var(--border); border-radius: var(--radius-md);
}
.mobile-nav > summary::-webkit-details-marker { display: none; }
.burger { display: grid; gap: 4px; width: 16px; }
.burger span { display: block; height: 1px; background: currentColor; }
.mobile-nav__panel {
  position: absolute; inset-inline: auto 0; top: calc(100% + var(--space-2)); z-index: 70;
  display: grid; gap: var(--space-1); min-width: 15rem; max-width: 20rem;
  padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--background);
  border: var(--border-width) solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sheet);
}
.mobile-nav__panel a:not(.button) {
  display: block; padding-block: var(--space-3);
  border-block-end: var(--border-width) solid var(--border);
  font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-body-lg); text-decoration: none;
}
.mobile-nav__panel a[aria-current] { color: var(--accent); font-style: italic; }
.mobile-nav__panel .button { margin-block-start: var(--space-3); }
@media (max-width: 989px) {
  .header-inner { min-height: 56px; }
  .desktop-nav { display: none; }
  .mobile-nav { display: block; }
}

/* ── Footer ─────────────────────────────────────────────────── */
.site-footer { border-block-start: var(--border-width) solid var(--border); }
.site-footer .q-section { padding-block: calc(var(--section-pad) * 1.5); }
.site-footer .q-opener, .site-footer .footer-columns, .site-footer .footer-bottom { max-width: none; }
.footer-columns { display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); }
.footer-label { margin: 0 0 var(--space-3); font-size: var(--fs-ui); font-weight: 500; color: var(--text-secondary); }
.q-caps .footer-label { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.footer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); font-size: var(--fs-body-lg); }
.site-footer nav { display: grid; gap: var(--space-2); font-size: var(--fs-body-lg); }
.site-footer a { text-decoration: none; }
@media (hover: hover) and (pointer: fine) { .site-footer a:hover { color: var(--accent); text-decoration: underline; } }
.footer-title { font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-h3); line-height: var(--lh-h3); margin: 0; }
.footer-bottom {
  display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5); justify-content: space-between;
  margin-block-start: var(--space-6); padding-block-start: var(--space-4);
  border-block-start: var(--border-width) solid var(--border);
  font-size: var(--fs-caption); color: var(--text-secondary);
}

/* ── Prose: the reading column ──────────────────────────────── */
.q-prose { font-size: var(--fs-body-lg); line-height: var(--lh-body-lg); }
.q-prose > * + * { margin-block-start: var(--space-4); }
.q-prose h2 { margin-block-start: var(--space-7); }
.q-prose h3 { margin-block-start: var(--space-6); }

/* The raised initial. It is the paragraph's own first letter — never a
   duplicated decorative span, which a screen reader reads as its own word and
   which splits the opening sentence in two. */
.q-drop > p:first-of-type::first-letter {
  initial-letter: 3 3;
  -webkit-initial-letter: 3;
  font-family: var(--font-display-font, Georgia, serif);
  font-weight: var(--display-weight, 400);
  color: var(--accent);
  margin-inline-end: .07em;
}
@supports not ((initial-letter: 3 3) or (-webkit-initial-letter: 3)) {
  .q-drop > p:first-of-type::first-letter {
    float: inline-start; font-size: 3.1em; line-height: .84; padding-inline-end: .06em; padding-block-start: .06em;
  }
}

/* ── Plate: a full-bleed image interrupting the text ────────── */
.q-plate { position: relative; display: grid; }
.q-masthead + .q-plate { margin-block-start: 0; }
.q-plate__frame { position: relative; overflow: hidden; background: var(--surface); }
.q-plate__frame > img, .q-plate__frame > svg { width: 100%; height: 100%; object-fit: cover; }
.q-plate--short .q-plate__frame { aspect-ratio: 21 / 9; }
.q-plate--tall .q-plate__frame { aspect-ratio: 4 / 3; }
.q-plate--square .q-plate__frame { aspect-ratio: 1; }
@media (max-width: 749px) { .q-plate--short .q-plate__frame { aspect-ratio: 3 / 2; } }
/* The grade: lifted blacks and grain over the picture, never over live text —
   which is why the caption sits beside the column and the overlay stops at the
   frame. */
.q-plate--film .q-plate__frame::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  opacity: .22; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
}
.q-plate--film .q-plate__frame > img { filter: contrast(.94) saturate(.92) brightness(1.04); }
/* A scrim, because the contrast of text over a photograph otherwise depends on
   whichever picture the owner uploads that day. */
.q-plate__over {
  position: absolute; inset: auto 0 0 0; display: grid; gap: var(--space-3);
  padding: var(--space-8) var(--pad) var(--space-6);
  background: linear-gradient(to top, rgb(0 0 0 / .72), rgb(0 0 0 / .42) 45%, rgb(0 0 0 / 0));
  color: #fff;
}
.q-plate__over > * { width: min(100% , var(--page-max)); margin-inline: auto; }
.q-plate__over .q-label { color: rgb(255 255 255 / .86); }
/* The caption sits under the plate, on the paper, sharing the column's edge —
   never over the picture. A full-bleed plate has no margin to set a caption in,
   and text laid on a photograph has whatever contrast the owner's upload
   happens to give it. Only the heading gets to sit on the picture, and only
   because it brings a scrim with it. */
.q-plate__caption {
  display: grid; gap: var(--space-1);
  width: min(100% - var(--pad) * 2, var(--page-max)); margin-inline: auto;
  padding-block-start: var(--space-3);
  font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--text-secondary);
}
.q-plate__credit { font-variant-numeric: tabular-nums; }
@media (min-width: 750px) {
  /* Caption and credit on one line, set to the outer edge of the column, the
     way a magazine runs them along the foot of a plate. */
  .q-plate--aside .q-plate__caption {
    grid-auto-flow: column; justify-content: space-between; align-items: baseline; gap: var(--space-5);
  }
  .q-plate--aside .q-plate__credit { text-align: end; }
}

/* ── Pull quote: breaking out of the reading column ─────────── */
.q-pullquote { display: grid; gap: var(--space-4); padding-block: calc(var(--section-pad) * 1.25); }
.q-pullquote blockquote {
  margin: 0;
  font-family: var(--font-display-font, Georgia, serif);
  font-weight: var(--display-weight, 400);
  font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--tr-h2);
  text-wrap: balance;
}
.q-pullquote figcaption { display: grid; gap: var(--space-1); margin-block-start: var(--space-2); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-secondary); }
.q-pullquote__who { font-weight: 500; color: var(--text-primary); }
.q-pullquote--ruled { border-block: var(--border-width) solid var(--border); }
@media (min-width: 990px) {
  /* The gutter either side of the measure is wide at this width, so the quote
     can step into it. The step is two units of the spacing scale rather than a
     share of the viewport: a box measured in vw is a box that can outgrow the
     gutter it is stepping into, and then the page scrolls sideways. */
  .q-pullquote { margin-inline: calc(var(--space-8) * -1); }
  .q-pullquote--right { margin-inline-start: 0; }
  .q-pullquote--left { margin-inline-end: 0; }
}

/* ── Contents ───────────────────────────────────────────────── */
.q-contents { list-style: none; margin: 0; padding: 0; display: grid; }
.q-contents li { border-block-end: var(--border-width) solid var(--border); }
.q-contents li:first-child { border-block-start: var(--border-width) solid var(--border); }
.q-contents__row {
  display: grid; grid-template-columns: 2.5rem 1fr auto; align-items: baseline; gap: var(--space-3);
  padding-block: var(--space-3); text-decoration: none; min-height: 44px;
}
.q-contents__no { font-variant-numeric: tabular-nums; font-size: var(--fs-ui); color: var(--accent); }
.q-contents__title { display: flex; align-items: baseline; gap: var(--space-3); min-width: 0; font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-body-lg); }
/* The leader. It is drawn, so it cannot be read aloud as a row of full stops
   the way a line of typed dots would be. */
.q-contents__title::after { content: ""; flex: 1 1 auto; align-self: center; height: 0; border-block-end: 1px dotted var(--border); }
.q-contents__note { font-size: var(--fs-caption); color: var(--text-secondary); grid-column: 2; margin-block-start: calc(var(--space-1) * -1); }
.q-contents__at { font-size: var(--fs-ui); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
@media (hover: hover) and (pointer: fine) { .q-contents__row:hover .q-contents__title { color: var(--accent); text-decoration: underline; } }

/* ── The index: data dense ──────────────────────────────────── */
/* A wide table cannot live in a reading measure, so it takes a full-width
   breakout with its own scroll region rather than shrinking the type. It sits
   above the paper grain on a plain fill: grain blurs the edges of small
   tabular figures, which is exactly the type that needs them crisp. */
.q-index { display: grid; gap: var(--space-4); }
.q-index__sheet {
  position: relative; z-index: 3;
  width: min(100% - var(--pad) * 2, 1100px); margin-inline: auto;
  background: var(--background);
  border: var(--border-width) solid var(--border); border-radius: var(--radius-lg);
}
.q-index__scroll { overflow-x: auto; overscroll-behavior-x: contain; }
.q-index table {
  width: 100%; border-collapse: collapse;
  font-size: var(--fs-body); line-height: var(--lh-body);
  font-variant-numeric: tabular-nums lining-nums;
}
.q-index thead th {
  position: sticky; top: 0; z-index: 1;
  padding: var(--space-2) var(--space-3); height: 30px;
  background: var(--background);
  border-block-end: 2px solid var(--text-primary);
  font-family: var(--font-body-font, system-ui, sans-serif);
  font-size: var(--fs-ui); font-weight: 500; text-align: start; white-space: nowrap;
  color: var(--text-secondary);
}
.q-caps .q-index thead th { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.q-index tbody th, .q-index td {
  height: 30px; padding: var(--space-1) var(--space-3);
  border-block-end: var(--border-width) solid var(--border);
  text-align: start; font-weight: 400;
}
.q-index tbody tr:last-child th, .q-index tbody tr:last-child td { border-block-end: 0; }
.q-index tbody th { font-weight: 500; }
.q-index .q-num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
.q-index a { color: inherit; text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .q-index tbody tr:hover { background: var(--surface); }
  .q-index a:hover { color: var(--accent); text-decoration: underline; }
}
.q-index__lbl { display: none; }
.q-index__note { font-size: var(--fs-caption); color: var(--text-secondary); text-align: center; }
/* A forty-column grid cannot reflow, so the phone gets a different view — one
   stacked record per row, with every value carrying its own label. */
@media (max-width: 749px) {
  .q-index__sheet { border: 0; border-radius: 0; width: 100%; padding-inline: var(--pad); }
  .q-index__scroll { overflow-x: visible; }
  .q-index table, .q-index tbody, .q-index tr, .q-index tbody th, .q-index td { display: block; width: auto; }
  .q-index thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .q-index tbody tr {
    padding-block: var(--space-3);
    border-block-end: var(--border-width) solid var(--border);
  }
  .q-index tbody th, .q-index td {
    height: auto; padding: 0; border: 0;
    display: grid; grid-template-columns: 6.5rem 1fr; gap: var(--space-3); align-items: baseline;
    min-height: 24px;
  }
  .q-index tbody th + td, .q-index td + td { margin-block-start: var(--space-1); }
  .q-index tbody th { font-size: var(--fs-body-lg); grid-template-columns: 1fr; }
  .q-index .q-num { text-align: start; }
  .q-index__lbl { display: block; font-size: var(--fs-caption); color: var(--text-secondary); }
  .q-caps .q-index__lbl { text-transform: uppercase; letter-spacing: var(--tr-caps); }
  .q-index tbody th .q-index__lbl { display: none; }
}

/* ── Colophon: the one dark region ──────────────────────────── */
/* Elevation here is a border as well as a fill: a slightly lighter surface
   alone disappears on a bright display or in daylight. */
.q-colophon { display: grid; gap: var(--space-6); }
.q-colophon__figures { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); margin: 0; }
.q-figure {
  display: grid; gap: var(--space-1); padding: var(--space-4);
  background: var(--surface); border: var(--border-width) solid var(--border); border-radius: var(--radius-md);
}
.q-figure dt { order: 2; font-size: var(--fs-ui); color: var(--text-secondary); }
.q-caps .q-figure dt { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.q-figure dd {
  order: 1; margin: 0;
  font-family: var(--font-display-font, Georgia, serif); font-weight: var(--display-weight, 400);
  font-size: var(--fs-h3); line-height: 1; font-variant-numeric: tabular-nums;
}
.q-credits { list-style: none; margin: 0; padding: 0; display: grid; }
.q-credits li {
  display: grid; grid-template-columns: minmax(6rem, 10rem) 1fr; gap: var(--space-4);
  padding-block: var(--space-2); border-block-start: var(--border-width) solid var(--border);
  font-size: var(--fs-body); line-height: var(--lh-body);
}
.q-credits dt, .q-credits__role { color: var(--text-secondary); }
.q-caps .q-credits__role { text-transform: uppercase; letter-spacing: var(--tr-caps); font-size: var(--fs-ui); }

/* ── Offering (services and products) ───────────────────────── */
.q-offer { list-style: none; margin: 0; padding: 0; display: grid; counter-reset: offer; }
.q-offer > li { border-block-start: var(--border-width) solid var(--border); padding-block: var(--space-4); }
.q-offer > li:last-child { border-block-end: var(--border-width) solid var(--border); }
.q-offer__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-4); }
.q-offer--numbered > li { counter-increment: offer; }
.q-offer--numbered .q-offer__head::before {
  content: counter(offer, decimal-leading-zero);
  font-size: var(--fs-ui); font-variant-numeric: tabular-nums; color: var(--accent);
}
.q-offer--numbered .q-offer__note, .q-offer--numbered .q-offer__actions { padding-inline-start: calc(var(--space-4) + 1.4em); }
.q-offer__name { font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-body-lg); font-weight: var(--display-weight, 400); margin: 0; }
.q-offer__price { margin-inline-start: auto; font-variant-numeric: tabular-nums; font-size: var(--fs-ui); color: var(--text-secondary); white-space: nowrap; }
.q-offer__note { margin-block-start: var(--space-2); font-size: var(--fs-body); color: var(--text-secondary); }
.q-offer__group { margin-block-start: var(--space-6); }
.q-offer__group:first-child { margin-block-start: 0; }
.q-offer__actions { margin-block-start: var(--space-3); }

/* ── Questions ──────────────────────────────────────────────── */
.q-faq { display: grid; }
.q-faq details { border-block-start: var(--border-width) solid var(--border); }
.q-faq details:last-of-type { border-block-end: var(--border-width) solid var(--border); }
.q-faq summary {
  list-style: none; display: flex; gap: var(--space-4); align-items: baseline; justify-content: space-between;
  padding-block: var(--space-4); min-height: 44px;
  font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-body-lg);
}
.q-faq summary::-webkit-details-marker { display: none; }
.q-faq summary::after { content: "+"; color: var(--accent); font-family: var(--font-body-font, system-ui); }
.q-faq details[open] summary::after { content: "\2212"; }
.q-faq__answer { padding-block: 0 var(--space-4); color: var(--text-secondary); max-width: var(--measure); }

/* ── Invitation: the one glass layer, and it never sits on paper ── */
.q-invite { position: relative; display: grid; }
.q-invite__frame { position: relative; overflow: hidden; background: var(--surface); }
.q-invite__frame > img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 21 / 9; }
@media (max-width: 749px) { .q-invite__frame > img { aspect-ratio: 4 / 5; } }
.q-invite__panel {
  position: absolute; inset-block: 0; inset-inline-start: 50%; transform: translateX(-50%);
  align-self: center; display: grid; gap: var(--space-4); align-content: center;
  width: min(100% - var(--pad) * 2, 30rem); padding: var(--space-6);
  border-radius: var(--radius-xl); border: var(--border-width) solid rgb(255 255 255 / .28);
  /* Without backdrop-filter a browser renders the low-alpha fill alone and the
     text becomes unreadable, so the opaque scrim is the default and the blur
     is the enhancement. */
  background: rgb(18 14 10 / .9); color: #fff;
  inset-block: var(--space-5);
}
@supports (backdrop-filter: blur(6px)) or (-webkit-backdrop-filter: blur(6px)) {
  .q-invite__panel {
    /* 0.72, not a fashionable 0.5: the panel has to hold white text at 4.5:1
       over the lightest photograph an owner might upload, and the blur cannot
       be counted on for any of that. Over pure white this composites to
       roughly 7.7:1; at 0.5 it would be 4.0:1 and fail. */
    background: rgb(18 14 10 / .72);
    -webkit-backdrop-filter: blur(14px) saturate(1.1);
    backdrop-filter: blur(14px) saturate(1.1);
  }
}
.q-invite__panel .q-label { color: rgb(255 255 255 / .82); }
.q-invite__panel .q-invite__note { color: rgb(255 255 255 / .88); font-size: var(--fs-body); line-height: var(--lh-body); }
.q-invite__panel h2 { color: #fff; }
.q-invite__panel .field > label { color: rgb(255 255 255 / .82); }
.q-invite__panel .field input { color: #fff; border-block-end-color: rgb(255 255 255 / .72); }
.q-invite__panel .field input::placeholder { color: rgb(255 255 255 / .6); }
.q-invite__panel .button { background: #fff; border-color: #fff; color: #17120e; }
.q-invite__panel .form__notice { background: rgb(255 255 255 / .14); color: #fff; }
.q-invite__panel :focus-visible { box-shadow: 0 0 0 4px rgb(18 14 10 / .9); outline-color: #fff; }
.q-invite--plain .q-invite__panel {
  position: static; transform: none; inset: auto; width: 100%; background: var(--surface); color: inherit;
  border-color: var(--border); backdrop-filter: none; -webkit-backdrop-filter: none;
}
.q-invite--plain .q-invite__panel h2, .q-invite--plain .q-invite__panel .q-label,
.q-invite--plain .q-invite__panel .field > label { color: inherit; }
.q-invite--plain .q-invite__panel .field input { color: inherit; border-block-end-color: var(--text-secondary); }
.q-invite--plain .q-invite__panel .button { background: var(--color-button); border-color: var(--color-button); color: var(--color-button-text); }

/* ── Masthead section ───────────────────────────────────────── */
.q-masthead { display: grid; gap: var(--space-5); padding-block: calc(var(--section-pad) * 2) var(--section-pad); }
.q-masthead__dateline {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); justify-content: space-between;
  padding-block-end: var(--space-3); border-block-end: 2px solid var(--text-primary);
  font-size: var(--fs-ui); color: var(--text-secondary);
}
.q-caps .q-masthead__dateline { text-transform: uppercase; letter-spacing: var(--tr-caps); }
.q-masthead__standfirst { font-size: var(--fs-body-xl); line-height: 1.5; color: var(--text-secondary); max-width: var(--measure); font-family: var(--font-body-font, system-ui); font-weight: 400; letter-spacing: 0; }
.q-masthead__byline { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); font-size: var(--fs-ui); color: var(--text-secondary); }

/* ── Marginalia ─────────────────────────────────────────────── */
.q-note { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-secondary); }
.q-note__inner {
  display: grid; gap: var(--space-1);
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--accent);
}
.q-note__label { font-size: var(--fs-caption); color: var(--accent); }
.q-caps .q-note__label { text-transform: uppercase; letter-spacing: var(--tr-caps); }
@media (min-width: 1240px) {
  /* Beside the column, in the gutter the single column leaves free. The note
     is pushed across by a margin rather than positioned absolutely: taken out
     of the flow it stopped contributing any height, so its tail ran past the
     foot of its own section and the next section's ground painted straight
     over it. Offsetting it keeps its height in the flow, keeps source order —
     which is the order a keyboard and a screen reader follow — and cannot
     collide with anything. The offset is smaller than the gutter at this
     width, and .q-flow clips horizontally in any case. */
  .q-note--aside { margin-inline-start: calc(100% + var(--space-5)); width: 13rem; }
}

/* ── Gallery and album lists ────────────────────────────────── */
.gallery-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-block-end: var(--grid-gap); }
.gallery-grid { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(var(--columns, 3), minmax(0, 1fr)); }
.gallery-grid--masonry { display: block; columns: var(--columns, 3); column-gap: var(--grid-gap); }
.gallery-grid--masonry > figure { break-inside: avoid; margin: 0 0 var(--grid-gap); }
.gallery-item { margin: 0; display: grid; gap: var(--space-2); }
.gallery-item__bar { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-3); font-size: var(--fs-caption); color: var(--text-secondary); }
.gallery-item__tools { display: inline-flex; align-items: center; gap: var(--space-3); margin-inline-start: auto; }
.gallery-item__favorite { margin: 0; }
.gallery-item__favorite button { display: inline-grid; place-items: center; width: 32px; height: 32px; border-radius: var(--radius-pill); border: var(--border-width) solid var(--border); background: transparent; }
.gallery-item__favorite svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.gallery-item__favorite button[aria-pressed="true"] { color: var(--accent); }
.gallery-item__favorite button[aria-pressed="true"] svg { fill: currentColor; }
.gallery-item__download { font-size: var(--fs-caption); }
.gallery-item--favorite .media { outline: 2px solid var(--accent); outline-offset: -2px; }
.gallery-gate, .gallery-favorites { max-width: 30rem; margin-inline: auto; display: grid; gap: var(--space-4); }
.gallery-favorites { margin-block-start: var(--space-8); }
.video-poster > summary { position: relative; display: block; list-style: none; border-radius: var(--media-radius); overflow: hidden; }
.video-poster > summary::-webkit-details-marker { display: none; }
.video-poster > summary img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.video-poster[open] > summary { display: none; }
.video-poster__play { position: absolute; inset: 50% auto auto 50%; width: 56px; height: 56px; margin: -28px 0 0 -28px; border-radius: var(--radius-pill); background: rgb(0 0 0 / .62); }
.video-poster__play::after { content: ""; position: absolute; left: 22px; top: 17px; border: 11px solid transparent; border-left: 16px solid #fff; border-right: 0; }
.video-frame { position: relative; aspect-ratio: 16 / 9; border-radius: var(--media-radius); overflow: hidden; }
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.album-list, .collection-list { list-style: none; margin: 0; padding: 0; }
.album-tile__link { display: grid; gap: var(--space-3); color: inherit; text-decoration: none; height: 100%; }
.album-tile__media { position: relative; }
.album-tile__lock { position: absolute; left: var(--space-2); top: var(--space-2); padding: 2px var(--space-2); border-radius: var(--radius-pill); background: rgb(var(--color-background-rgb) / .9); font-size: var(--fs-caption); }
.album-tile__title, .collection-entry__title { margin: 0; }
.album-tile__meta, .album-tile__description, .collection-entry .rte { margin: 0; font-size: var(--fs-body); }
.album-tile__body, .collection-entry__body { display: grid; gap: var(--space-1); }
.collection-entry { display: grid; gap: var(--space-3); min-width: 0; }
.collection-entry__title a { color: inherit; text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .album-tile__link:hover .album-tile__title, .collection-entry__title a:hover { color: var(--accent); text-decoration: underline; }
}
.collection-entry--draft { outline: var(--border-width) dashed var(--border); outline-offset: 6px; }
.collection-entry__note, .album-list__empty, .collection-list__empty { font-size: var(--fs-caption); color: var(--text-secondary); }
.album-list__empty, .collection-list__empty { padding: var(--space-6); border: var(--border-width) dashed var(--border); border-radius: var(--card-radius); text-align: center; }
.album-list--list .album-tile__link, .collection-list--list .collection-entry { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); align-items: center; }
@media (max-width: 749px) {
  .album-list--list .album-tile__link, .collection-list--list .collection-entry { grid-template-columns: minmax(0, 1fr); }
}

/* ── 404 and page openers ───────────────────────────────────── */
.q-404 { display: grid; gap: var(--space-4); padding-block: calc(var(--section-pad) * 3); }
.q-404__slate { font-family: var(--font-display-font, Georgia, serif); font-size: var(--fs-display); line-height: 1; color: var(--accent); }

/* ── Flexible content ───────────────────────────────────────── */
.q-flex-grid { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(1, minmax(0, 1fr)); }
@media (min-width: 750px) { .q-flex-grid { grid-template-columns: repeat(var(--columns, 2), minmax(0, 1fr)); } }
.content-card { display: grid; gap: var(--space-3); align-content: start; min-width: 0; }
.content-card > .media { margin-block-end: var(--space-1); }
.text--small { font-size: var(--fs-body); }
.text--large { font-size: var(--fs-body-xl); line-height: 1.5; }

/* ── Motion ─────────────────────────────────────────────────── */
/* Only transform and opacity move. Everything that reveals does so once, and
   the platform's runtime replaces every entrance with the element simply being
   present under prefers-reduced-motion. */
/* The platform starts a fade at zero and travels 24px. Both are turned down
   here on purpose, and the theme's stylesheet is loaded after the platform's,
   so these win:

   — an element waiting to reveal is still an element someone may be reading,
     and a page that arrives blank is a page that has not finished loading. The
     floor is .62, which keeps every word legible the instant it appears while
     the fade still registers;
   — 12px of travel, because more than about that reads as a layout settling
     rather than an entrance.

   The clip reveals are left alone: they are already opacity 1 and carry their
   motion in clip-path. Under prefers-reduced-motion the platform sets the
   revealed state as the initial state, so nothing here animates and — the
   part that matters — nothing stays hidden. */
html.ab-motion [data-ab-anim=fade],
html.ab-motion [data-ab-anim=fade-up],
html.ab-motion [data-ab-anim=fade-down],
html.ab-motion [data-ab-anim=fade-left],
html.ab-motion [data-ab-anim=fade-right],
html.ab-motion [data-ab-anim=slide-up],
html.ab-motion [data-ab-anim=scale],
html.ab-motion [data-ab-anim=zoom] { opacity: .62; }
html.ab-motion [data-ab-anim=fade-up] { transform: translateY(12px); }
html.ab-motion [data-ab-anim=fade-down] { transform: translateY(-12px); }
html.ab-motion [data-ab-anim=fade-left] { transform: translateX(12px); }
html.ab-motion [data-ab-anim=fade-right] { transform: translateX(-12px); }
html.ab-motion [data-ab-anim=slide-up] { transform: translateY(16px); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
}
