/* Self-hosted, not fetched from Google.
   The live theme pulls Open Sans via `@import url(fonts.googleapis.com/…)`
   inside its CSS — two render-blocking third-party requests, and a GDPR
   consideration for a Dutch site. Google now ships Open Sans as a VARIABLE
   font, so one 43KB latin-subset file covers the 300/400/700 the theme
   actually uses. Declaring font-family without self-hosting would silently
   fall back on any machine lacking Open Sans, changing how the site looks. */
@font-face {
  font-family: 'Open Sans';
  src: url('/fonts/open-sans-latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

/* Design tokens lifted from the live theme's custom.css: dark charcoal page,
   mid-blue accent, cards floated on the dark background. --gap is a fluid
   rebuild of the theme's spacing, used on non-grid pages. --tile-gap and
   --tile-pad are deliberately NOT fluid: the verbatim theme CSS puts
   `margin:8px` on every masonry article, which (both sides touching)
   produces a 16px gap between adjacent tiles, and `padding:20px` on every
   masonry card (#mainMenu, #masonry article .data, .termsBox, .intro) —
   see .grid/.tile below. No border-radius anywhere in this file: the live
   design is all sharp rectangles.
   --font-size-base is the live theme's `body { font-size:12px }` — kept as
   one named property so changing it later (the owner has been told 12px
   is below typical accessibility guidance) is a one-line edit. */
:root {
  --gap: clamp(0.5rem, 1.5vw, 1.25rem);
  --tile-gap: 16px;
  --tile-pad: 20px;
  --wrap: 1290px;
  --font-size-base: 12px;
  --measure: 62ch;
  --bg: #222;
  --card: #fff;
  --card-ink: #222;
  --accent: #44abe1;
  --filter: #333;
  --ink: #e9e9e9;
  --muted: #999;
  font-family: "Open Sans", -apple-system, BlinkMacSystemFont, Helvetica, sans-serif;
}
*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0; min-height: 100vh; color: var(--ink); background: var(--bg);
  font-size: var(--font-size-base); line-height: 20px;
  display: flex; flex-direction: column; gap: var(--gap);
  padding: var(--gap);
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

/* The live theme's `#wrap`: a CENTRED, FIXED-width band that steps at three
   breakpoints, with everything on the page inside it. It is what
   decides how many tiles fit per row and how much dark background shows
   either side — reproducing the tile metrics without it still gives the
   wrong layout, because the column count comes from the band, not the
   viewport. Verbatim from custom.css lines 565-576:
     >=1700px -> 1600px    1400-1699 -> 1290px    1000-1399 -> 1000px
   The fourth band is the one deliberate change. Live pins 200-999px to a
   FIXED 648px, so every phone narrower than that scrolls sideways — the
   theme's own `max-width:699px` override that would have fixed it is
   commented out in custom.css. `min(100%, …)` keeps 648 where it fits and
   goes fluid below it. `max-width:1399px` and `max-width:999px` both match
   under 1000px, so the 648 rule must come second — the cascade, not
   specificity, is what picks it. */
@media (max-width: 1399px) { :root { --wrap: 1000px; } }
@media (max-width:  999px) { :root { --wrap:  648px; } }
@media (min-width: 1700px) { :root { --wrap: 1600px; } }

/* The homepage wordmark (base.njk renders it there and nowhere else). Outside
   the band, like the live theme's `#banner` — full-bleed and centred on the
   viewport, not on --wrap. The cap is the wordmark's own natural 768x150:
   `#banner #logo img { max-width:100% }` sets no width, so live renders it at
   natural size. */
.site-header { text-align: center; }
.wordmark img { width: 100%; max-width: min(768px, 100%); height: auto; margin: 0 auto; }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: var(--gap); top: var(--gap); background: var(--card); color: var(--card-ink);
  padding: 0.5rem; z-index: 10; }

/* The blue nav bar — only bodyClass "notfound" (404.njk) still uses it now.
   Every other page renders the tile instead: see nav-tile.njk and the
   .nav-tile rules below. */
.nav-card { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap);
  background: var(--accent); padding: var(--gap); }
/* No size override on the logo: the live theme's `#mainMenu img` sets none
   either (`float:left; margin-top:10px`), so it renders at its natural
   120x85 — the width/height attributes on the <img> already provide that. */
.nav-card ul { display: flex; flex-wrap: wrap; gap: var(--gap); list-style: none;
  margin: 0 0 0 auto; padding: 0; }
.nav-card a { color: #fff; text-decoration: none; font-size: 20px; line-height: 36px; }
.nav-card a:hover { color: #444; }
.nav-card [aria-current="page"] { text-decoration: underline; text-underline-offset: 0.2em; }

/* The whole page lives in the centred band — see --wrap. */
main#main { display: flex; flex-direction: column; gap: var(--gap);
  width: min(100%, var(--wrap)); margin-inline: auto; }

/* `p { font-size:14px; line-height:21px }` with `@media (min-width:1000px)
   and (max-width:1399px) { font-size:12px; line-height:18px }` — both
   verbatim. `body { font-size:12px }` is only the inherited base on live;
   every paragraph overrides it. Body copy was rendering a size and a half
   too small everywhere without this. Elements that set their own size —
   .tile-meta at 10px, the tile titles at 24px — are class-scoped and still
   win. */
p { font-size: 14px; line-height: 21px; }
@media (min-width: 1000px) and (max-width: 1399px) {
  p { font-size: 12px; line-height: 18px; }
}

h1, h2 { font-weight: 300; }
h1 { font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem); line-height: 1.15; margin: 0 0 0.5em; }
h2 { font-size: clamp(1.1rem, 0.9rem + 0.8vw, 1.5rem); }

/* Prose blocks are the theme's white cards. Tag-scoped to div (not a bare
   .prose class rule): project.njk's article.prose sits inside
   .project-content, which is already the white card for that page — card-
   ifying it too would nest a white box inside a white box. Only 404.njk
   uses a bare `<div class="prose">` now — page.njk's blocks moved to
   .block/.blocks below, matching the live site's tile treatment. */
div.prose { max-width: var(--measure); background: var(--card);
  color: var(--card-ink); padding: var(--gap); }
.prose h1, .prose h2 { color: var(--accent); }

/* ============================================================
   Grid pages: the whole page is ONE masonry
   flow. The nav card, the filter/tag card and the intro card are
   tiles in that same flow — siblings of the project/material
   tiles — not page-level bars above it, matching the live site
   where the whole homepage is one masonry column of cards. CSS
   multi-column packs tiles of varying height without the ragged
   same-row gaps a fixed-track grid produces, and reflows at any
   width instead of snapping between fixed breakpoints. Gutters are the
   small, fixed --tile-gap (16px — the live theme's `margin:8px` on every
   masonry article, both sides touching, so adjacent tiles sit 16px apart),
   not the fluid --gap used elsewhere.
   ============================================================ */
.grid { columns: 260px; column-gap: var(--tile-gap); }
.tile { break-inside: avoid; margin: 0 0 var(--tile-gap); }
/* js/masonry.js adds this once it has positioned the tiles, to reproduce the
   live site's shortest-column packing (CSS multi-column fills column-major,
   which puts the tall intro card under the nav instead of beside it). The
   rules above stay the default and are a complete layout on their own — if
   the script never runs, nothing here applies and the page is fine. */
.grid.is-masonry { columns: auto; position: relative; }
.grid.is-masonry > .tile { margin: 0; }
/* Same for .blocks (contact/werkwijze) — its fallback is a real CSS grid, so
   masonry has to switch `display` off as well as take over placement. */
.blocks.is-masonry { display: block; position: relative; }
.blocks.is-masonry > * { margin: 0; }
/* The nav+filter pair is one grid item (see nav-block.njk). Its two cards keep
   the shared .tile bottom margin so they sit --tile-gap apart, exactly as two
   loose tiles would; only the trailing one is dropped. */
.nav-block > :last-child { margin-bottom: 0; }

/* The nav tile: KW mark top-left (no size override — natural 120x85, same
   as the bar version above), links stacked and right-aligned below.
   `#mainMenu a { font-size:20px; line-height:36px }` verbatim — the
   generous line-height (not extra margin) is what gives the stacked links
   their vertical rhythm. Explicit px, not rem: rem resolves against the
   root element, not body, so it wouldn't track a future --font-size-base
   change, and these are meant to match the live values exactly regardless. */
.nav-tile { background: var(--accent); color: #fff; padding: var(--tile-pad);
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--tile-pad); }
/* Side by side, not stacked: `.menuBox img { float:left }` +
   `.menuBox nav { float:right }` put the mark and the link list in one row,
   which is what makes the live tile roughly square rather than tall. The
   links were below the mark here, adding ~80px of height to every page's
   first tile. `margin-top:10px` on the mark is verbatim too. */
.nav-tile .logo-mark { margin-top: 10px; }
/* The KW mark links home from every page. Live's is a bare <img> with no
   anchor at all, so there is nothing to copy here and nothing that says the
   mark is clickable — its 120x85 box is already a generous target, but it
   gave no hover or focus feedback, which is what made it read as inert.
   Opacity rather than a colour shift: `.menuBox a:hover { color:#444 }` is
   the live hover, and colour does nothing to an image. */
.logo-mark { transition: opacity 0.2s ease; }
.logo-mark:hover { opacity: 0.7; }
.logo-mark:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.nav-tile ul { list-style: none; margin: 0; padding: 0; text-align: right; }
.nav-tile a { color: #fff; text-decoration: none; font-size: 20px; line-height: 36px; }
.nav-tile a:hover { color: #444; }
.nav-tile [aria-current="page"] { text-decoration: underline; text-underline-offset: 0.2em; }

/* The filter/tag tile: real links to the real /projectType/ pages (see
   filter.njk), plain inline text separated by a middot — not pills.
   `.termsBox a { font-size:14px; line-height:20px; color:white }`, hover
   `color:#44abe1` verbatim — explicit px, same reasoning as .nav-tile a. */
.filter-tile { background: var(--filter); color: #fff; padding: var(--tile-pad); }
.filter-tile p { margin: 0; }
.filter-tile a { color: #fff; text-decoration: none; font-size: 14px; line-height: 20px; }
.filter-tile a:hover { color: var(--accent); }
.filter-tile [aria-current="page"] { text-decoration: underline; font-weight: 700; }

/* The intro tile: small accent-coloured heading (not a large white one
   above the grid) followed by the page's intro text, if any.
   `#masonry article header { font-size:24px; line-height:1.5em;
   font-weight:300 }` verbatim — this is the SAME rule the tile title below
   uses; `.intro header` only overrides the colour to accent. Explicit px,
   not the fluid clamp() this used before: matching live parity is the
   point here, not fluid type. */
.intro-tile { background: var(--card); color: var(--card-ink); padding: var(--tile-pad); }
.intro-tile h1 { color: var(--accent); font-size: 24px; line-height: 1.5em;
  font-weight: 300; margin: 0 0 0.5em; }
.intro-tile p { margin: 0 0 1em; }
.intro-tile p:last-child { margin-bottom: 0; }
/* `#masonry .intro img { width:300px; left:-20px; max-width:300px }` — the
   swatch is full-bleed across the card, escaping the card's own 20px
   padding on both sides and at the bottom. Negative margins rather than
   `left`, which does nothing on a statically positioned image. */
.intro-swatch { margin: 0 calc(-1 * var(--tile-pad)) calc(-1 * var(--tile-pad)); }

/* Project/material tiles. Verbatim live CSS:
     #masonry article               { background:#44abe1; position:relative; }
     #masonry article .masonryImage { z-index:1; position:relative; }
     #masonry article .data         { bottom:0; position:absolute; }
   The blue is the tile's OWN permanent background — not a hover overlay.
   The image sits on top (z-index:1) hiding it and .data by default; .data
   has no z-index, so it paints *behind* the image. Hovering was meant to
   fade the image out, revealing the blue card and its text underneath. The
   live JS that drove that (Isotope) is gone from the site — this
   reimplements the same effect in pure CSS.
   Scoped to `article.tile` (not a bare `.tile` class rule): nav-tile/
   filter-tile/intro-tile also carry the shared `.tile` masonry-item class
   above, and a bare `.tile a { display: block }` here once forced every
   inline link in the filter tile's running text onto its own line. Only
   the actual image tiles are `<article>`s. */
article.tile { background: var(--accent); }
article.tile a { position: relative; display: block; overflow: hidden; text-decoration: none; }
/* materialen.njk's fallback for mdf's null swatch: same square shape as a
   real swatch image (WordPress swatches are 300x300), so the tile keeps its
   neighbours' footprint — and, like the image, sits above .tile-data and
   fades out the same way on hover/focus. */
.tile-placeholder { display: block; aspect-ratio: 1 / 1; background: var(--filter); }
article.tile img, article.tile .tile-placeholder { position: relative; z-index: 1;
  transition: opacity 0.2s ease; }
/* Fades to 0.2, not 0: `.single-kw_project .postInfo .image .text` (the
   live theme's analogous project-page hover) is `background-color:#44abe1;
   opacity:.80`, i.e. blue at 80% with the photo showing through at 20% —
   not a fully solid card. */
article.tile:hover img, article.tile:hover .tile-placeholder,
article.tile:focus-within img, article.tile:focus-within .tile-placeholder { opacity: 0.2; }
/* .tile-data stays in the DOM and keeps its normal accessible name at all
   times, so keyboard and screen-reader users always have it — it's only
   *visually* hidden, by the opaque image sitting above it, not by
   `visibility` or `display`. */
.tile-data { position: absolute; inset: 0; display: flex; flex-direction: column;
  justify-content: flex-end; padding: var(--tile-pad); }
.tile-title { color: #fff; font-size: 24px; font-weight: 300; line-height: 1.5em; margin: 0; }
.tile-meta { color: #fff; font-size: 10px; line-height: 1.5em; margin: 0.5em 0 0; }

/* `.royalSlider { background: #333 }` at a size fixed per breakpoint —
   1248x932 and 932x695 on the two widest, 616x600 and 616x616 below. The
   photo is NOT stretched to fill it (`.royalSlider img { width:auto }`): it
   sits at its own size, centred, letterboxed against the grey. That grey
   band is the most recognisable thing about the live project page and was
   missing entirely — the photo was filling the column edge to edge.
   Reproduced as a fluid band at the same two aspect ratios rather than four
   fixed pixel sizes: ~4:3 where the page is two columns, square below,
   matching where live's own numbers change shape. */
.gallery { position: relative; background: var(--filter); }
/* No visible scrollbar — live has none, and the buttons carry the
   affordance. Trackpad and touch scrolling still work. */
.gallery-track { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  list-style: none; margin: 0; padding: 0; scrollbar-width: none; }
.gallery-track::-webkit-scrollbar { display: none; }
/* Full width of the track, not `min(60ch, 90%)`: the live gallery is a
   carousel showing one image at a time, not a strip with several visible.
   gallery.js's step() already scrolls by `track.clientWidth` per press,
   which is exactly one slide at this width — no JS change needed. */
.gallery-item { flex: 0 0 100%; scroll-snap-align: center;
  aspect-ratio: 1 / 1; position: relative; }
@media (min-width: 60rem) { .gallery-item { aspect-ratio: 4 / 3; } }
/* The <picture> is the box that gets filled, not the <img>: `max-height:100%`
   on the image alone resolves against <picture>, whose height is auto, so the
   cap silently did nothing and portrait photos still rendered at full column
   width. Absolutely filling the item gives object-fit a definite box to work
   against, and `contain` letterboxes against the grey exactly as live does. */
.gallery-item picture { position: absolute; inset: 0; display: block; }
.gallery-item img { width: 100%; height: 100%; object-fit: contain; }
.gallery button { position: absolute; top: 50%; translate: 0 -50%; z-index: 2;
  border: 0; background: rgba(255,255,255,0.85); font-size: 1.5rem;
  width: 2.5rem; height: 2.5rem; cursor: pointer; }
.gallery button:disabled { opacity: 0.3; cursor: default; }
.gallery-prev { left: 0; } .gallery-next { right: 0; }

/* Project page: nav tile + white content card share the left column (see
   .project-left below), gallery on the dark background to the right — a
   fluid grid with a single content-driven breakpoint (not five fixed
   ones): one column on narrow viewports, two once there's room, gallery
   always pinned to the second column. `#main`, not a bare `main` tag:
   `main#main` above sets `display: flex` and an ID beats a class+tag on
   specificity, so a plain `body.project main` selector here was silently
   losing that fight — display never actually became grid.
   Exactly two direct children (.gallery and .project-left — see
   project.njk), and BOTH axes given explicitly on both items —
   grid-column AND grid-row, not just column. Column alone wasn't enough
   and measurably still broke: even with only these two children, auto-
   placement still put them on separate rows (verified via
   getBoundingClientRect, not just by eye — .project-left's top sat below
   .gallery's full height exactly as before). That's the auto-placement
   cursor: `.gallery` is first in DOM order, and once an item with a
   definite column is placed, the cursor advances in a way that pushes a
   later auto-row item onto a new row rather than backtracking to the
   free cell in row 1 — the same underlying mechanic as the `grid-row:
   1 / -1` bug this replaced (`-1` resolves against the *explicit* grid,
   which has no declared row tracks). Pinning row:1 on both items removes
   the auto-placement cursor from the equation entirely, rather than
   depending on it. Avoid `grid-row: 1 / span 2` or a declared
   `grid-template-rows` if this needs revisiting — both encode the current
   child count and would silently break again the next time something is
   added to the left column; explicit row:1 on both items doesn't. :has()
   drops the second column entirely for the one project with an empty
   gallery instead of leaving it a dead 42%-wide gap. */
body.project #main { display: grid; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 60rem) {
  /* `#singleSide { width:300px; float:left }` — the left column is exactly
     one tile wide on live, fixed, with the gallery taking whatever is left.
     It was `minmax(0,1fr)` against a 42% gallery, which made the white card
     roughly 500px: half again as wide as live's, and the most obvious
     difference on the page. */
  body.project #main:has(> .gallery) { grid-template-columns: 300px minmax(0, 1fr); }
  body.project #main > .gallery { grid-column: 2; grid-row: 1; }
  body.project #main > .project-left { grid-column: 1; grid-row: 1; }
}
/* The left column: nav tile above the white content card, at the same
   measure as the card itself (rather than stretching to the full grid-
   column width) so both read as "the same narrow column". */
body.project .project-left { display: flex; flex-direction: column; gap: var(--gap);
  max-width: 100%; }
/* Its masonry-context bottom margin (from the shared .tile class) is
   dropped in favour of .project-left's own gap, so it isn't double-spaced
   from the content card below it. */
body.project .nav-tile { margin: 0; }

/* The white content card itself: title (accent, via .prose h1 above),
   description, and the materiaal/type sections all live directly on it —
   not as separate floating white boxes. */
/* `.single-kw_project .postInfo { padding:20px; width:260px; background:#fff }`
   — 260 + 40 = one 300px tile, the same width as the nav tile above it. The
   type scale is verbatim too: the title is `postInfo h2 { font-size:18px;
   color:#44abe1; font-weight:300 }`, not the page-wide clamp()'d h1 that was
   rendering it at 40px, and the section labels are `postInfo h3
   { font-size:14px; color:black; font-weight:300 }` — light, not the browser
   default bold. */
.project-content { background: var(--card); color: var(--card-ink);
  padding: var(--tile-pad); }
.project-content h1 { font-size: 18px; color: var(--accent); font-weight: 300;
  line-height: 1.5em; margin: 0 0 1em; }
.project-content h3 { font-size: 14px; color: #000; font-weight: 300;
  margin: 1.5em 0 0.5em; }

/* Materials as image swatches, not text — the live page links each material
   to /materiaal/<slug>/ via a 260x80 thumbnail with the name in a blue
   overlay revealed on hover. Reuses the article.tile hover mechanic built
   for the masonry grid (permanent blue background, image fades to reveal
   it) rather than a new one; only the label size differs (14px/400, not
   24px/300) at this much smaller scale. */
/* `.postInfo .image { margin-bottom:20px; width:250px }` — the swatches stack
   down the card at a fixed 250px, they don't wrap into rows. `max-width:100%`
   keeps them inside the card once it goes full-width on narrow viewports.

   NAMED `.material-list`, NOT `.materials`: /materialen/ carries
   `bodyClass: materials`, so `<body class="materials">` matched a
   `.materials .tile` descendant selector and pinned every tile on that page
   to 250px inside a 310px column — narrow swatches with wide dark gutters,
   on the one page where the tiles are the content. A page-level bodyClass
   and a component class are in the same namespace; keep component names
   distinct from every bodyClass value. */
.material-list { display: flex; flex-direction: column; list-style: none;
  margin: 0; padding: 0; }
.material-list .tile { width: 250px; max-width: 100%; margin: 0 0 20px; }
.material-swatch img, .material-swatch .tile-placeholder { aspect-ratio: 260 / 80; object-fit: cover; }
.material-swatch .tile-title { font-size: 14px; font-weight: 400; }

/* "type" is not on the live page at all — added deliberately as internal
   linking to the 24 /projectType/ pages promoted to indexable (see
   project.njk) — restyled to match materiaal's plain-link pattern: a small
   h3 label with plain links, not pills. */
.meta { display: flex; flex-wrap: wrap; gap: calc(var(--gap) / 2); padding: 0;
  margin: 0; list-style: none; }
.meta a { color: var(--accent); text-decoration: underline; }

/* contact/werkwijze/homepage-afblijven (page.njk): every live page uses the
   tile treatment, so these are a grid of blocks — not the CSS multi-column
   masonry .grid uses (multi-column can't span a specific number of tracks,
   which .wide/.double needs), a real grid instead: auto-fill columns at
   >=260px, wide blocks spanning two. Blue by default, matching
   `#masonry article { background:#44abe1 }`; white only when the live
   markup carries white/intro (b.white, sourced from pages.json in
   page.njk, which guards for it being absent — so this rule just doesn't
   match until the data has it). */
.blocks { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--tile-gap); align-items: start; }
/* Nav tile's masonry-context bottom margin (from the shared .tile class) is
   dropped in favour of .blocks' own gap, same reasoning as .project-left. */
.blocks > .nav-tile { margin: 0; }
/* `align-items: start` above, not the grid default `stretch`: werkwijze's five
   photo blocks are 300x300 and 300x450, and stretching made every short one a
   blue box with the photo floating in it. Live packs them with a JS masonry;
   a row grid can't, so the leftover falls to the dark page background — which
   is what shows between live's tiles anyway. */
.block { background: var(--accent); padding: var(--tile-pad); }
.block.wide { padding: 10px; }
/* `span 2` only once two 260px tracks actually fit (2*260 + one 16px gap =
   536, plus body padding). Below that, auto-fill has produced a single
   column and a span-2 item would create an IMPLICIT second track — the
   grid keeps its container width, so the row simply overflows the viewport
   sideways. Every /contact/ block is wide, so this is the whole page. */
@media (min-width: 560px) { .block.wide { grid-column: span 2; } }
.block.white { background: var(--card); }
/* An image with no text is edge-to-edge on live: `#masonry article` is
   `padding:0` there, and only the text cards (.intro/.double/.data) add
   their own. page.njk tags these so the rule keys off the block's content
   rather than guessing from a selector. */
.block.image-only { padding: 0; }
/* `p { color:#454545 }` and `a:link { color:#444444 }` verbatim, NOT white:
   live's blue page cards carry dark grey body text and only the header goes
   white. This also happens to be the better of the two — #454545 on #44abe1
   measures 3.78:1 where white on the same blue is 2.58:1. Underline kept on
   links, which live drops entirely (`text-decoration:none` at 3.4:1 against
   the surrounding text leaves nothing but colour to mark a link). */
.block p, .block li, .block td { color: #454545; }
.block a { color: #444; }
.block p { margin: 0 0 1em; }
/* `#masonry article header { font-size:24px; line-height:1.5em; font-weight:300;
   color:white; margin:20px 0 }` and `.white header { color:#44abe1 }` verbatim.
   The page's <h1> is the first block's header on every live page — see
   page.njk — so both tags take the rule. */
.block h1, .block h2 { color: #fff; font-size: 24px; line-height: 1.5em;
  font-weight: 300; margin: 20px 0; }
.block.white h1, .block.white h2 { color: var(--accent); }
/* The /contact/ Google Maps embed is hard-coded width="600" height="280" in
   the extracted markup and overflows every phone. Override to fluid — this
   is one of the concrete "responsive issues" on the current site. */
.block iframe { width: 100%; max-width: 100%; height: auto; aspect-ratio: 600 / 280;
  border: 0; display: block; }

/* `footer { text-align:center; color:#44abe1 }` verbatim. Live's is empty; the
   one line of contact detail here is an addition, so it gets the live footer's
   own styling rather than a rule of its own. */
.site-footer { padding: var(--gap); color: var(--accent); text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .gallery-track { scroll-behavior: auto; }
  article.tile img, article.tile .tile-placeholder { transition: none; }
  .logo-mark { transition: none; }
}
