/* ==========================================================================
   Portfolio — Apple HIG-derived dark theme
   Type scale, system colours and easing follow Apple's Human Interface
   Guidelines (dark appearance). No external dependencies.
   ========================================================================== */

:root {
  /* --- Apple system colours, dark appearance ---------------------------- */
  --bg:                 #000000;   /* systemBackground */
  --bg-elevated:        #1C1C1E;   /* secondarySystemBackground */
  --bg-raised:          #2C2C2E;   /* tertiarySystemBackground */
  --fill-quaternary:    rgba(118, 118, 128, 0.18);

  --label:              #FFFFFF;
  --label-secondary:    rgba(235, 235, 245, 0.60);  /* 6.3:1 on black */
  /* Apple's tertiaryLabel is 0.30, which measures ~1.9:1 on pure black — under
     WCAG AA. This is used for real text (footer, captions, meta), so it is
     raised to the lowest alpha that clears 4.5:1. */
  --label-tertiary:     rgba(235, 235, 245, 0.50);  /* 4.6:1 on black */
  --separator:          rgba(84, 84, 88, 0.65);

  --accent:             #0A84FF;   /* systemBlue, dark */

  /* --- Materials -------------------------------------------------------- */
  --material-thick:     rgba(20, 20, 22, 0.72);
  --material-ultrathin: rgba(10, 10, 12, 0.55);

  /* --- Type scale (SF) --------------------------------------------------- */
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
          "Helvetica Neue", "Segoe UI", Roboto, system-ui, sans-serif;

  --text-large-title: 3.25rem;
  --text-title-1:     2.125rem;
  --text-title-2:     1.5rem;
  --text-title-3:     1.25rem;
  --text-body:        1.0625rem;  /* 17px — Apple body size */
  --text-subhead:     0.9375rem;
  --text-footnote:    0.8125rem;
  --text-caption:     0.75rem;

  /* --- Motion ------------------------------------------------------------ */
  --ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1);
  --ease-spring:   cubic-bezier(0.32, 0.72, 0, 1);   /* Apple sheet curve */
  --dur-fast:   0.22s;
  --dur-medium: 0.42s;
  --dur-slow:   0.7s;

  /* --- Layout ------------------------------------------------------------ */
  --gutter: 20px;
  --max-width: 1680px;
  /* Wider screens get more breathing room at the edges — 20px against a
     1440px viewport reads as cramped. Set below the :root block. */
  --nav-height: 52px;
  --radius: 14px;
}

@media (min-width: 900px)  { :root { --gutter: 34px; } }
@media (min-width: 1300px) { :root { --gutter: 48px; } }

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--label);
  font-family: var(--font);
  font-size: var(--text-body);
  line-height: 1.5;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img { display: block; max-width: 100%; height: auto; }

a { color: inherit; text-decoration: none; }

::selection { background: var(--accent); color: #fff; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.shell {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ==========================================================================
   Navigation — translucent material bar
   ========================================================================== */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--nav-height);
  background: var(--material-ultrathin);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}

.nav.is-scrolled {
  background: var(--material-thick);
  border-bottom-color: var(--separator);
}

/* Three columns: menu button, centred wordmark, call to action. The wordmark
   stays optically centred regardless of how wide the outer two get. */
.nav__inner {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
}

.nav__menu-btn {
  justify-self: start;
  appearance: none;
  border: 0;
  cursor: pointer;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  gap: 4px;
  border-radius: 50%;
  background: var(--label);
  color: #000;
  transition: transform var(--dur-fast) var(--ease-spring),
              background var(--dur-fast) var(--ease-standard);
}

.nav__menu-btn:hover  { background: rgba(255, 255, 255, 0.86); }
.nav__menu-btn:active { transform: scale(0.92); }

.nav__menu-btn span {
  display: block;
  width: 15px;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur-medium) var(--ease-spring),
              opacity var(--dur-fast) var(--ease-standard);
}

/* Morph to a cross while the menu is open. */
body.menu-open .nav__menu-btn span:nth-child(1) { transform: translateY(2.75px) rotate(45deg); }
body.menu-open .nav__menu-btn span:nth-child(2) { opacity: 0; }
body.menu-open .nav__menu-btn span:nth-child(3) { transform: translateY(-2.75px) rotate(-45deg); }

.nav__wordmark {
  grid-column: 2;
  justify-self: center;
  font-size: 1.0625rem;
  font-weight: 700;
  font-style: italic;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.nav__cta {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 17px;
  border-radius: 999px;
  background: var(--label);
  color: #000;
  font-size: var(--text-caption);
  font-weight: 500;
  letter-spacing: -0.005em;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-spring);
}

.nav__cta:hover  { background: rgba(255, 255, 255, 0.86); }
.nav__cta:active { transform: scale(0.96); }

@media (max-width: 520px) {
  .nav__wordmark { font-size: 0.9375rem; }
  .nav__cta { padding: 0 13px; font-size: 0.6875rem; }
}

/* Touch: both controls go to the 44pt minimum. The nav bar is only 52px tall,
   so the button keeps its 40px disc and gains the extra as an invisible
   outset ring rather than growing the visible circle. */
@media (pointer: coarse) {
  .nav__menu-btn {
    position: relative;
    width: 40px;
    height: 40px;
  }
  .nav__menu-btn::after {
    content: "";
    position: absolute;
    inset: -2px;
    min-width: 44px;
    min-height: 44px;
  }
  .nav__cta { min-height: 44px; }
}

/* ==========================================================================
   Slide-down menu
   ========================================================================== */

.menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: none;
  background: var(--material-thick);
  backdrop-filter: saturate(180%) blur(26px);
  -webkit-backdrop-filter: saturate(180%) blur(26px);
  opacity: 0;
  transition: opacity var(--dur-medium) var(--ease-standard);
}

.menu.is-open  { display: block; }
.menu.is-shown { opacity: 1; }

.menu__inner {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  padding: var(--nav-height) var(--gutter) 0;
  max-width: var(--max-width);
  margin: 0 auto;
}

.menu__link {
  display: block;
  padding: 10px 0;
  font-size: clamp(2rem, 8vw, 4rem);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
  color: var(--label-secondary);
  transform: translateY(14px);
  opacity: 0;
  transition: color var(--dur-fast) var(--ease-standard),
              transform var(--dur-medium) var(--ease-spring),
              opacity var(--dur-medium) var(--ease-standard);
}

.menu.is-shown .menu__link { transform: none; opacity: 1; }
.menu__link:hover { color: var(--label); }

/* Stagger the entrance a little — it reads as deliberate rather than abrupt. */
.menu.is-shown .menu__link:nth-child(1) { transition-delay: 0.04s; }
.menu.is-shown .menu__link:nth-child(2) { transition-delay: 0.08s; }
.menu.is-shown .menu__link:nth-child(3) { transition-delay: 0.12s; }
.menu.is-shown .menu__link:nth-child(4) { transition-delay: 0.16s; }

.menu__meta {
  margin-top: 40px;
  font-size: var(--text-footnote);
  color: var(--label-tertiary);
}

.menu__meta a { color: var(--accent); }

/* ==========================================================================
   Page head — no hero image. The grid starts almost immediately, so this
   just clears the fixed nav.
   ========================================================================== */

.page-top { height: calc(var(--nav-height) + 26px); }

@media (max-width: 768px) {
  .page-top { height: calc(var(--nav-height) + 12px); }
}

/* ==========================================================================
   Filter pills — segmented-control feel
   ========================================================================== */

.filters {
  position: sticky;
  top: var(--nav-height);
  z-index: 50;
  padding: 26px 0 22px;
  background: var(--material-thick);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
}

.filters__track {
  display: flex;
  justify-content: center;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}

.filters__track::-webkit-scrollbar { display: none; }

/* Plain letterspaced text, no chrome. The generous padding keeps a 44pt tap
   target even though the ink is small. */
.pill {
  flex: 0 0 auto;
  scroll-snap-align: start;
  appearance: none;
  border: 0;
  background: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 14px;
  color: var(--label-tertiary);
  font-family: inherit;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard);
}

.pill:hover { color: var(--label-secondary); }

.pill[aria-pressed="true"] { color: var(--label); }

@media (max-width: 620px) {
  .filters { padding: 18px 0 14px; }
  .filters__track { justify-content: flex-start; }
}

/* ==========================================================================
   Masonry gallery — CSS columns, no layout JS
   ========================================================================== */

/* CSS Grid rather than multicolumn, because multicolumn makes every item
   exactly one column wide — there is no way to let a strong photo take more
   room. Row spans are computed from each image's aspect ratio in app.js, which
   gives a masonry wall where any photo can be marked to run wider.

   grid-template-columns is set by the script so it always agrees with the span
   arithmetic; the value here is just a sensible pre-layout default. */
/* 1px rows with no row-gap: the row quantum is what limits how closely a tile
   can match its photo's aspect ratio, and a 12px gap plus an 8px row made that
   quantum 20px — about 12px of crop on a small tile. The vertical gutter is a
   margin on the tile instead, which lives inside the spanned rows. */
.gallery {
  padding: 8px 0 90px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 1px;
  column-gap: 12px;
  row-gap: 0;
  /* Deliberately NOT `row dense`. It was tried and measured no better here
     (identical 226px bottom-edge variance and identical wall height), and dense
     packing lets visual order drift from source order — which matters when the
     order in gallery.json is a curatorial choice. */
}

/* A photo marked "size": "large" in gallery.json takes two columns instead of
   one. Not a full-width band — just more weight than its neighbours.

   grid-column-end, NOT the `grid-column` shorthand: the shorthand would set
   grid-column-START to `span 2`, which the script's grid-column-end cannot
   override. On a one-column layout the large tile would then still claim two
   columns and squeeze its neighbours to zero width. */
.tile--large { grid-column-end: span 2; }

.tile {
  /* figure carries a UA margin of 1em 40px. Left in place it silently shrinks
     every tile inside its grid cell and the computed row spans stop matching
     the images. */
  margin: 0 0 12px;   /* the vertical gutter; row-gap is 0 by design */
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-elevated);
  cursor: zoom-in;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease-standard),
              transform var(--dur-slow) var(--ease-standard);
}

.tile.is-visible { opacity: 1; transform: none; }

.tile.is-hidden { display: none; }

/* The tile's height comes from its computed row span, which is derived from
   this image's own aspect ratio — so "cover" here crops by at most a rounding
   remainder, never a meaningful part of the frame. */
.tile__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-medium) var(--ease-standard);
  will-change: transform;
}

.tile:hover .tile__img { transform: scale(1.035); }

/* Caption veil — pointer devices only; on touch it just covers the photo */
.tile__caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 46px 16px 14px;
  background: linear-gradient(to top, rgba(0,0,0,0.78), transparent);
  font-size: var(--text-footnote);
  font-weight: 500;
  letter-spacing: -0.005em;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--dur-medium) var(--ease-standard),
              transform var(--dur-medium) var(--ease-standard);
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .tile:hover .tile__caption { opacity: 1; transform: none; }
}

.tile__collection {
  display: block;
  font-size: var(--text-caption);
  font-weight: 400;
  color: var(--label-secondary);
  margin-top: 2px;
}

.gallery__empty {
  columns: 1;
  padding: 60px 0;
  color: var(--label-tertiary);
  font-size: var(--text-subhead);
}

/* ==========================================================================
   Lightbox
   ========================================================================== */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  background: rgba(0, 0, 0, 0.94);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  opacity: 0;
  transition: opacity var(--dur-medium) var(--ease-standard);
}

.lightbox.is-open { display: block; }
.lightbox.is-shown { opacity: 1; }

.lightbox__stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 72px 24px 96px;
}

.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 6px;
  transform: scale(0.97);
  opacity: 0;
  transition: transform var(--dur-medium) var(--ease-spring),
              opacity var(--dur-medium) var(--ease-standard);
}

.lightbox__img.is-loaded { transform: none; opacity: 1; }

.lightbox__bar {
  position: absolute;
  inset: auto 0 0 0;
  padding: 18px var(--gutter) 26px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  background: linear-gradient(to top, rgba(0,0,0,0.85), transparent);
}

.lightbox__caption {
  font-size: var(--text-subhead);
  letter-spacing: -0.01em;
  margin: 0;
  min-height: 1.4em;
}

.lightbox__source {
  display: inline-block;
  margin-top: 4px;
  font-size: var(--text-caption);
  color: var(--accent);
}

.lightbox__counter {
  flex: 0 0 auto;
  font-size: var(--text-caption);
  color: var(--label-tertiary);
  font-variant-numeric: tabular-nums;
}

/* Circular glass controls — 44px minimum hit target per HIG */
.lb-btn {
  position: absolute;
  z-index: 2;
  appearance: none;
  border: 0;
  cursor: pointer;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(120, 120, 128, 0.32);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--label);
  transition: background var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-spring),
              opacity var(--dur-fast) var(--ease-standard);
}

.lb-btn:hover  { background: rgba(120, 120, 128, 0.52); }
.lb-btn:active { transform: scale(0.92); }
.lb-btn[disabled] { opacity: 0.28; cursor: default; }
.lb-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor;
              stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.lb-btn--close { top: 16px; right: var(--gutter); }
.lb-btn--prev  { top: 50%; left: var(--gutter);  transform: translateY(-50%); }
.lb-btn--next  { top: 50%; right: var(--gutter); transform: translateY(-50%); }
.lb-btn--prev:active, .lb-btn--next:active { transform: translateY(-50%) scale(0.92); }

@media (max-width: 620px) {
  .lightbox__stage { padding: 64px 12px 110px; }
  /* Arrows drop to the bottom on phones so they sit in the thumb arc */
  .lb-btn--prev, .lb-btn--next { top: auto; bottom: 30px; transform: none; }
  .lb-btn--prev:active, .lb-btn--next:active { transform: scale(0.92); }
  .lb-btn--prev { left: var(--gutter); }
  .lb-btn--next { right: var(--gutter); }
  .lightbox__bar { padding-bottom: 88px; }
  .lightbox__counter { display: none; }
}

/* ==========================================================================
   Prose pages (About)
   ========================================================================== */

.page { padding: calc(var(--nav-height) + 12vh) 0 90px; }

.prose { max-width: 62ch; }

.prose h1 {
  margin: 0 0 28px;
  font-size: var(--text-title-1);
  font-weight: 600;
  letter-spacing: -0.025em;
}

.prose h2 {
  margin: 52px 0 14px;
  font-size: var(--text-title-3);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.prose p {
  margin: 0 0 18px;
  color: var(--label-secondary);
  line-height: 1.62;
}

.prose a { color: var(--accent); }
.prose a:hover { text-decoration: underline; }

.contact-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--separator);
}

.contact-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 20px;
  padding: 13px 0;
  border-bottom: 1px solid var(--separator);
  font-size: var(--text-subhead);
}

.contact-value {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.contact-value a { color: var(--accent); }
.contact-value a:hover { text-decoration: underline; }

.contact-list span { color: var(--label-tertiary); }

/* --- Centred variant ------------------------------------------------------
   The contact page is a short block rather than a column of reading text, so
   it is centred on the page. Scoped to a modifier class: .prose is shared with
   the privacy page, which is long-form and stays left-aligned because centred
   body copy is hard to read past a couple of lines. */

.prose--centred {
  margin-inline: auto;
  text-align: center;
}

/* The row layout is a left/right split (label one end, value the other), which
   reads as two ragged columns once the page has a centred axis. Stacking the
   label above its value keeps everything on that axis. */
.prose--centred .contact-list li {
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 16px 0;
}

.prose--centred .contact-value { justify-content: center; }

/* ==========================================================================
   Social rail — fixed to the right edge on wide screens
   ========================================================================== */

.rail {
  position: fixed;
  z-index: 60;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.rail a {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--label-secondary);
  transition: color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-spring);
}

.rail a:hover {
  color: var(--label);
  background: var(--fill-quaternary);
}

.rail a:active { transform: scale(0.9); }

.rail svg { width: 16px; height: 16px; fill: currentColor; }

/* Below the point where the rail would sit over the photos, drop it. The
   same links live in the footer and the menu, so nothing is lost. */
@media (max-width: 1100px) {
  .rail { display: none; }
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer-cta {
  border-top: 1px solid var(--separator);
  padding: 12vh var(--gutter) 10vh;
  text-align: center;
}

.footer-cta__label {
  margin: 0 0 22px;
  font-size: var(--text-caption);
  font-weight: 500;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--label-tertiary);
}

.footer-cta__email {
  display: inline-block;
  font-size: clamp(1.25rem, 4.4vw, 2.75rem);
  font-weight: 400;
  letter-spacing: 0.055em;
  line-height: 1.2;
  word-break: break-word;
  transition: opacity var(--dur-fast) var(--ease-standard);
}

.footer-cta__email:hover { opacity: 0.62; }

/* Copy-to-clipboard control. Sits beside every email address, because a
   mailto: link silently does nothing when no mail client is registered. */
.copy-btn {
  appearance: none;
  cursor: pointer;
  border: 1px solid var(--separator);
  background: none;
  color: var(--label-secondary);
  border-radius: 999px;
  min-height: 32px;
  padding: 0 14px;
  font-family: inherit;
  font-size: var(--text-caption);
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-spring);
}

.copy-btn:hover  { color: var(--label); border-color: var(--label-tertiary); }
.copy-btn:active { transform: scale(0.95); }

.copy-btn.is-copied {
  color: #000;
  background: var(--label);
  border-color: var(--label);
}

@media (pointer: coarse) { .copy-btn { min-height: 44px; padding: 0 18px; } }

.footer-cta__actions {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

/* The fixed nav must not cover an anchored heading. */
[id] { scroll-margin-top: calc(var(--nav-height) + 24px); }

.footer-cta__wordmark {
  margin-top: 9vh;
  font-size: 1.0625rem;
  font-weight: 700;
  font-style: italic;
  letter-spacing: 0.04em;
}

.footer {
  padding: 26px 0 42px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  justify-content: space-between;
  font-size: var(--text-caption);
  color: var(--label-tertiary);
}

.footer a:hover { color: var(--label-secondary); }

/* ==========================================================================
   Cookie consent banner
   Only ever rendered when analytics is switched on in assets/js/consent.js.
   ========================================================================== */

.consent {
  position: fixed;
  z-index: 300;
  left: var(--gutter);
  right: var(--gutter);
  bottom: var(--gutter);
  max-width: 620px;
  margin: 0 auto;
  padding: 18px 20px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 20px;
  border-radius: var(--radius);
  border: 1px solid var(--separator);
  background: var(--material-thick);
  backdrop-filter: saturate(180%) blur(24px);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-medium) var(--ease-standard),
              transform var(--dur-medium) var(--ease-spring);
}

.consent.is-shown { opacity: 1; transform: none; }

.consent__text {
  flex: 1 1 260px;
  margin: 0;
  font-size: var(--text-footnote);
  line-height: 1.45;
  color: var(--label-secondary);
}

.consent__text a { color: var(--accent); }
.consent__text a:hover { text-decoration: underline; }

.consent__actions {
  flex: 0 0 auto;
  display: flex;
  gap: 8px;
}

/* Both buttons are deliberately the same size and weight. Making "decline"
   harder to find than "accept" is precisely what regulators object to. */
.consent__btn {
  appearance: none;
  border: 0;
  cursor: pointer;
  min-height: 36px;
  padding: 0 16px;
  border-radius: 999px;
  font-family: inherit;
  font-size: var(--text-footnote);
  font-weight: 500;
  letter-spacing: -0.01em;
  background: var(--fill-quaternary);
  color: var(--label);
  transition: background var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-spring);
}

.consent__btn:hover  { background: rgba(120, 120, 128, 0.42); }
.consent__btn:active { transform: scale(0.96); }

.consent__btn--primary {
  background: var(--label);
  color: #000;
}

.consent__btn--primary:hover { background: rgba(255, 255, 255, 0.86); }

@media (pointer: coarse) {
  .consent__btn { min-height: 44px; padding: 0 20px; }
}

@media (max-width: 480px) {
  .consent { flex-direction: column; align-items: stretch; }
  .consent__actions { display: grid; grid-template-columns: 1fr 1fr; }
}

/* ==========================================================================
   Accessibility — honour reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  .tile { opacity: 1; transform: none; }
  .lightbox__img { opacity: 1; transform: none; }
}
