@charset "utf-8";

/* ==================================================================================================
   AmCore: the single stylesheet for the whole site (REQ-002).

   Hand-written, no build step, no framework, no @import, no CDN and no third-party request of any
   kind (ADR-0002, ADR-0003, REQ-012). The two type families are self-hosted files in
   site/assets/fonts/, referenced relatively from this file; the site loads nothing from the network
   except the OpenStreetMap iframe on locatie.html.

   Nothing in this file is copied or adapted from the SysCore website or from any other site.
   It implements docs/design/Visual-design.md: the "unit plate" concept: an industrial estate
   identifies itself with signage, so the address is the hero, set large in a condensed face, and the
   decisive facts sit beside it as a specification plate. Type, numbers and structure carry every
   page; AmCore's photographs (fotos.html, and three on the start page) support them without taking
   over: square corners, no shadows, no frames, no card kit.

   Order of the file:
     0. Web fonts (@font-face)     5. Header, navigation, skip link
     1. Design tokens (:root)      6. Content components
     2. Reset and base             7. Footer
     3. Typography                 8. Responsive, motion, print
     4. Layout primitives
   ================================================================================================== */


/* --------------------------------------------------------------------------------------------------
   0. WEB FONTS: IBM Plex Sans and IBM Plex Sans Condensed, SIL OFL 1.1

   Self-hosted woff2 in ../fonts/, licence shipped alongside as ofl.txt (lowercase because every
   filename under site/ is lowercase ASCII, ADR-0004 #1; the OFL prescribes no filename). Relative paths only, so the
   folder keeps working from any webserver, any subdirectory and from file:// (ADR-0002). No CDN, no
   @import, no Google Fonts request: a webfont request is a third-party request, and this site has
   exactly one of those (the map). font-display: swap so the text is readable immediately in the
   system fallback and simply re-renders when Plex arrives; nothing is ever invisible while loading.
   -------------------------------------------------------------------------------------------------- */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans Condensed";
  src: url("../fonts/ibm-plex-sans-condensed-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans Condensed";
  src: url("../fonts/ibm-plex-sans-condensed-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}


/* --------------------------------------------------------------------------------------------------
   1. DESIGN TOKENS

   Every colour, type and spacing decision for the whole site lives in this one block: there is no
   literal colour or font-size below it, and there is no style="" attribute in any page (REQ-005).

   Palette: pale concrete, green-black, deep teal-green, one machine amber. Verified with the WCAG
   2.x contrast formula on 2026-09-13; every pair the site actually uses is >= 4.5:1 (REQ-011, AA):

     ink        #16201D  on paper   #F2F4F1   15.1:1     body text, headings
     ink-soft   #4C5650  on paper   #F2F4F1    6.9:1     meta, captions, hints
     ink        #16201D  on surface #E4E8E3   13.5:1     text on the specification plate
     ink-soft   #4C5650  on surface #E4E8E3    6.2:1     meta on the plate, disabled button label
     accent     #0F4C45  on paper   #F2F4F1    8.9:1     links, heading rules
     accent     #0F4C45  on surface #E4E8E3    7.9:1     links inside a filled block
     paper      #F2F4F1  on accent  #0F4C45    8.9:1     header band, footer band, accent buttons
     surface    #E4E8E3  on accent  #0F4C45    7.9:1     secondary text in the footer band
     ink        #16201D  on signal  #E8A33D    7.7:1     the availability flag, the amber CTA
     accent     #0F4C45  on signal  #E8A33D    4.6:1     focus ring on an amber surface (>= 3:1 needed)
     signal     #E8A33D  on accent  #0F4C45    4.6:1     focus ring on the accent bands (>= 3:1 needed)

   --line #C7CEC7 is a hairline only: it never carries text, so its 1.5:1 against paper is not a
   contrast failure. Borders that must be perceivable on their own (form fields) use --line-strong.
   -------------------------------------------------------------------------------------------------- */
:root {
  /* -- Colour ------------------------------------------------------------------------------------ */
  --ink:          #16201D;   /* green-black: body text, headings, not a tinted near-black */
  --ink-soft:     #4C5650;   /* secondary text, captions, hints                            */
  --paper:        #F2F4F1;   /* pale concrete, faintly green: page background              */
  --surface:      #E4E8E3;   /* the specification plate, table stripes, filled bands       */
  --line:         #C7CEC7;   /* hairlines                                                  */
  --line-strong:  #8C968E;   /* borders that must read on their own: inputs, the ladder axis */
  --accent:       #0F4C45;   /* deep teal-green: header band, footer band, heading rules   */
  --accent-deep:  #0B3A34;   /* hover/active of accent surfaces                            */
  --signal:       #E8A33D;   /* machine amber: exactly one moment per page                 */

  /* -- Type --------------------------------------------------------------------------------------
     IBM Plex Sans (400/600) for body, IBM Plex Sans Condensed (400/600) for display and data
     labels: an engineered, signage-clear family, and the condensed width is the business-park
     idiom: unit numbers, floor plans, technical drawings. The fallback stack is a real one, so a
     visitor whose browser blocks the woff2 still gets a sane interface font at the same sizes. */
  --font-body: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, sans-serif;
  --font-display: "IBM Plex Sans Condensed", "IBM Plex Sans", ui-sans-serif, system-ui,
                  "Segoe UI Semibold", "Arial Narrow", Arial, sans-serif;

  /* A 1.2 scale on a 17px base; the address plate is fluid so a tablet gets a headline sized for a
     tablet rather than a desktop one shrunk by a media query. */
  --size-100: 0.8125rem;   /* fine print                          */
  --size-200: 0.9375rem;   /* meta, captions, nav, table headers   */
  --size-300: 1.0625rem;   /* body                                 */
  --size-400: 1.1875rem;   /* lead paragraph, plate values         */
  --size-500: 1.375rem;    /* h3                                   */
  --size-600: 1.6875rem;   /* h2                                   */
  --size-700: clamp(1.75rem, 1.35rem + 1.6vw, 2.375rem);          /* h1 on the inner pages */
  --size-address: clamp(2.75rem, 1.6rem + 5.6vw, 5.25rem);        /* the address plate     */

  --weight-normal: 400;
  --weight-bold:   600;     /* Plex ships 400 and 600 here; there is no 700 file to load */

  --leading-tight: 1.02;
  --leading-snug:  1.25;
  --leading-body:  1.6;

  --measure: 68ch;          /* the design spec's maximum measure */

  /* -- Space: a 4px base, used for every margin, padding and gap in the file ---------------------- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;

  --wrap-max: 68rem;
  --rule: 4px;              /* the weight of an accent rule above a heading */
}


/* --------------------------------------------------------------------------------------------------
   2. RESET AND BASE
   -------------------------------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  font-size: 106.25%;           /* 17px base */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--size-300);
  font-weight: var(--weight-normal);
  line-height: var(--leading-body);
  /* Nothing on this page may push the viewport sideways at 360px (REQ-011). */
  overflow-wrap: break-word;
}

img,
iframe { max-width: 100%; }

/* Focus is visible everywhere and never removed. Two rings: accent on light backgrounds, amber on
   the accent bands, both well over the 3:1 a focus indicator needs against what it sits on. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.site-header :focus-visible,
.site-footer :focus-visible,
.cta--signal:focus-visible {
  outline-color: var(--signal);
}
.cta:focus-visible { outline-color: var(--accent-deep); }

/* A browser that predates :focus-visible still gets a ring. */
:focus { outline: 3px solid var(--accent); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }

/* main gets tabindex="-1" as the skip-link target; that must not draw a ring on mouse click. */
main:focus { outline: none; }
main:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }


/* --------------------------------------------------------------------------------------------------
   3. TYPOGRAPHY
   -------------------------------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
  line-height: var(--leading-snug);
  margin: 0 0 var(--space-4);
  text-wrap: balance;
}

h1 {
  font-size: var(--size-700);
  line-height: var(--leading-tight);
  margin-bottom: var(--space-5);
}

h2 {
  font-size: var(--size-600);
  border-top: var(--rule) solid var(--accent);
  padding-top: var(--space-3);
  margin-top: var(--space-7);
}

/* A filled block supplies its own edge, so the rule above the heading would be a second line. */
.band h2,
.band h3,
.plate h2 {
  border-top: 0;
  padding-top: 0;
  margin-top: 0;
}

h3 {
  font-size: var(--size-500);
  margin-top: var(--space-6);
}

h4 {
  font-size: var(--size-400);
  margin-top: var(--space-5);
}

p, ul, ol, dl, table, figure {
  margin: 0 0 var(--space-4);
}

p, li { max-width: var(--measure); }

.lead {
  font-size: var(--size-400);
  max-width: 60ch;
}

.meta {
  font-size: var(--size-200);
  color: var(--ink-soft);
}

strong, b { font-weight: var(--weight-bold); }

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover { color: var(--accent-deep); text-decoration-thickness: 2px; }

/* Numbers that are compared (prices, areas, distances, registration numbers) line up. */
.num,
.plate dd,
.spec-table td,
.ladder-value {
  font-variant-numeric: tabular-nums;
}

ul.plain,
ul.stack {
  list-style: none;
  padding-left: 0;
}
ul.stack > li + li { margin-top: var(--space-3); }

.prose ul,
.prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: var(--space-2); }


/* --------------------------------------------------------------------------------------------------
   4. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: clamp(var(--space-4), 4vw, var(--space-7));
}

.page {
  display: block;
  padding-block: var(--space-7) var(--space-9);
}

.section { margin-block: var(--space-7); }
.section > :last-child { margin-bottom: 0; }

.prose { max-width: var(--measure); }

/* A filled band: the design uses solid blocks rather than hairlines everywhere. No card, no shadow,
   no rounded corner anywhere in this file. */
.band {
  background: var(--surface);
  padding: var(--space-5) clamp(var(--space-4), 3vw, var(--space-6));
  border-left: var(--rule) solid var(--accent);
  margin-block: var(--space-6);
}
.band > :last-child { margin-bottom: 0; }

.band--quiet { border-left-color: var(--line-strong); }

/* Two columns where there is room, one column below ~46rem; no media query needed. */
.columns {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5) var(--space-6);
}
.columns > * {
  flex: 1 1 22rem;
  min-width: 0;
}
/* Inside a column pair the blocks sit side by side, so their own vertical rhythm would push them
   out of line with each other. */
.columns > .band { margin-block: 0; }


/* --------------------------------------------------------------------------------------------------
   5. HEADER, NAVIGATION, SKIP LINK
   -------------------------------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--signal);
  color: var(--ink);
  font-weight: var(--weight-bold);
  padding: var(--space-3) var(--space-4);
  z-index: 10;
}
.skip-link:focus {
  left: var(--space-3);
  top: var(--space-3);
}

.site-header {
  background: var(--accent);
  color: var(--paper);
}
.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  padding-block: var(--space-4);
}

.wordmark {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: 1.75rem;
  letter-spacing: -0.01em;
  color: var(--paper);
  text-decoration: none;
}
.wordmark:hover {
  color: var(--paper);
  text-decoration: underline;
  text-decoration-thickness: 2px;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-nav li { max-width: none; }
.site-nav a {
  display: inline-block;
  color: var(--paper);
  font-size: var(--size-200);
  text-decoration: none;
  padding-block: var(--space-1);
  border-bottom: 2px solid transparent;
}
.site-nav a:hover {
  color: var(--paper);
  border-bottom-color: var(--paper);
}
/* The current page is marked with weight and a rule in paper, not in amber: the amber is one
   moment per page and the navigation is not it. */
.site-nav a[aria-current="page"] {
  font-weight: var(--weight-bold);
  border-bottom-color: var(--paper);
}


/* --------------------------------------------------------------------------------------------------
   6. CONTENT COMPONENTS
   -------------------------------------------------------------------------------------------------- */

/* -- The hero: the address is the plate ----------------------------------------------------------
   A business park identifies itself with signage: a painted unit number, a plate beside the door.
   So the address is set very large in the condensed face and everything else orbits it. */
.hero { margin-bottom: var(--space-7); }

.hero h1 { margin-bottom: var(--space-3); }

.hero-orientation {
  display: block;
  font-family: var(--font-body);
  font-size: var(--size-400);
  font-weight: var(--weight-normal);
  letter-spacing: 0;
  line-height: var(--leading-snug);
  margin-bottom: var(--space-3);
}

.hero-address {
  display: block;
  font-size: var(--size-address);
  line-height: var(--leading-tight);
  letter-spacing: -0.015em;
}

.hero-place {
  font-size: var(--size-400);
  color: var(--ink-soft);
  max-width: 40ch;
}

/* -- The specification plate ----------------------------------------------------------------------
   A business tenant compares specifications, so this is a real definition list on the plate colour,
   never a row of decorative stat cards. */
.plate {
  background: var(--surface);
  padding: var(--space-5) clamp(var(--space-4), 3vw, var(--space-6));
  margin-block: var(--space-6);
}

.plate dl {
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) 1fr;
  gap: 0;
  margin: 0;
}
.plate dt,
.plate dd {
  margin: 0;
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
}
.plate dt {
  font-family: var(--font-display);
  color: var(--ink-soft);
  padding-right: var(--space-4);
}
.plate dd {
  font-size: var(--size-400);
  font-weight: var(--weight-bold);
}
.plate dt:first-of-type,
.plate dt:first-of-type + dd { border-top: 0; }

/* The single amber moment on the start page: the unit is vacant, which is the one fact that decides
   whether the rest of the page is worth reading. */
.flag {
  display: inline-block;
  background: var(--signal);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  padding: var(--space-1) var(--space-3);
}

/* -- Specification tables -------------------------------------------------------------------------- */
.spec-table {
  width: 100%;
  border-collapse: collapse;
  margin-block: var(--space-5);
}
.spec-table caption {
  text-align: left;
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  color: var(--ink-soft);
  padding-bottom: var(--space-2);
}
.spec-table th,
.spec-table td {
  text-align: left;
  vertical-align: top;
  padding: var(--space-3) var(--space-4) var(--space-3) 0;
  border-top: 1px solid var(--line);
  max-width: 42ch;
}
.spec-table thead th {
  font-family: var(--font-display);
  font-size: var(--size-200);
  color: var(--ink-soft);
  border-top: 0;
  border-bottom: 2px solid var(--line-strong);
}
.spec-table tbody th {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  color: var(--ink);
  width: 14rem;
}
.spec-table tbody tr:nth-child(odd) { background: var(--surface); }
.spec-table th:first-child,
.spec-table td:first-child { padding-left: var(--space-3); }

/* -- The distance ladder (locatie.html) -----------------------------------------------------------
   The one memorable element. Every bar width below is the real distance measured against a shared
   scale of 4,5 km, so the device encodes the information instead of decorating it: the bus stop bar
   really is one twentieth of the station bar. Widths are classes rather than inline styles because
   no page on this site carries a style attribute (REQ-005), and because a named distance is
   readable in the markup.
   Ranges are drawn at their midpoint; the exact range is always written out next to the bar, which
   is also what a screen reader gets (the bars themselves are aria-hidden). */
.ladder {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  border-left: 2px solid var(--line-strong);   /* the zero point of the scale */
}
.ladder > li {
  display: grid;
  /* A fixed label column, so the zero point of the scale below lines up with the start of every
     bar: the axis label is positioned with the same measurement (11rem + gap + the li padding). */
  grid-template-columns: 11rem 1fr;
  gap: var(--space-1) var(--space-4);
  align-items: baseline;
  max-width: none;
  padding: var(--space-3) 0 var(--space-3) var(--space-4);
  border-top: 1px solid var(--line);
}
.ladder > li:first-child { border-top: 0; }

.ladder-label {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
}
.ladder-track { min-width: 0; }

.ladder-bar {
  display: block;
  height: 0.75rem;
  min-width: 3px;
  background: var(--accent);
  margin-bottom: var(--space-2);
}
.ladder-bar--0-2km { width: 4.4%; }    /* 200 m van 4,5 km */
.ladder-bar--1km   { width: 22.2%; }   /* 1 km            */
.ladder-bar--2-5km { width: 55.6%; }   /* 2–3 km          */
.ladder-bar--4-5km { width: 100%; }    /* 4–5 km          */

.ladder-value {
  font-size: var(--size-200);
  color: var(--ink-soft);
}
.ladder-scale {
  display: flex;
  justify-content: space-between;
  font-size: var(--size-100);
  color: var(--ink-soft);
  border-top: 2px solid var(--line-strong);
  padding-top: var(--space-1);
  margin-left: calc(11rem + var(--space-4) + var(--space-4));
}

/* -- Call to action -------------------------------------------------------------------------------- */
.cta {
  display: inline-block;
  background: var(--accent);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: var(--size-400);
  font-weight: var(--weight-bold);
  text-decoration: none;
  padding: var(--space-3) var(--space-5);
}
.cta:hover {
  background: var(--accent-deep);
  color: var(--paper);
  text-decoration: underline;
  text-decoration-thickness: 2px;
}
/* The amber call to action, used on the pages whose one accent moment is the invitation itself. */
.cta--signal {
  background: var(--signal);
  color: var(--ink);
}
.cta--signal:hover {
  background: var(--signal);
  color: var(--ink);
}

/* -- Notices: something is missing and the visitor should know why --------------------------------- */
.notice {
  background: var(--surface);
  border-left: var(--rule) solid var(--accent);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-5);
}
.notice > :last-child { margin-bottom: 0; }
.notice-title {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--size-500);
  margin-bottom: var(--space-2);
}

/* -- The documents register ------------------------------------------------------------------------ */
.docs {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
}
.docs > li {
  max-width: none;
  padding: var(--space-4) 0;
  border-top: 1px solid var(--line);
}
.docs > li:first-child { border-top: 2px solid var(--line-strong); }
.docs > li:last-child { border-bottom: 1px solid var(--line); }

.doc-name {
  font-family: var(--font-display);
  font-size: var(--size-500);
  font-weight: var(--weight-bold);
  margin-bottom: var(--space-1);
}
.doc-what { margin-bottom: var(--space-2); }
.doc-meta {
  font-size: var(--size-200);
  color: var(--ink-soft);
  margin-bottom: 0;
}
.doc-meta .num { font-variant-numeric: tabular-nums; }

/* Documents that exist but were not supplied: no link, and visibly so: a download link to a file
   that is not there is worse than an honest sentence (REQ-007). */
.docs--onrequest > li { border-top-style: dashed; }
.docs--onrequest .doc-name { font-size: var(--size-400); }

/* -- Photographs ----------------------------------------------------------------------------------
   Files come from ./amcore photos (scripts/site/photos.py): sRGB JPEGs, 640 and 1280 px on the long
   side, no metadata. The gallery is one grid of one photo per space, in walking order, with no
   headings between tiles. The tiles are a uniform 4:3 crop so a mix of portrait and landscape
   still lines up; each tile links to the whole, uncropped file, which fotos.js opens in the pop-up
   below when JavaScript runs (ADR-0009) and the browser opens as a plain JPEG when it does not. The
   --surface fill shows while a lazy image loads, so a slow connection sees a calm block, not a gap.
   Square corners and no shadows here as everywhere else. */
.gallery {
  display: grid;
  /* min(100%, …) keeps a single column from ever exceeding a 360px viewport (REQ-011). */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-5) var(--space-4);
}
.gallery figure {
  margin: 0;
  min-width: 0;
}
.gallery a {
  display: block;
  background: var(--surface);
}
.gallery a:focus-visible { outline-offset: 3px; }
.gallery img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.gallery a:hover img { opacity: 0.88; }
/* A portrait whose subject sits low (the toilet): move the 4:3 window down instead of cutting it off. */
.gallery img.focus-low { object-position: 50% 85%; }
.gallery figcaption {
  font-size: var(--size-200);
  line-height: var(--leading-snug);
  color: var(--ink-soft);
  padding-top: var(--space-2);
  max-width: none;
}

/* The start page's exterior: full content width, cropped to 3:2 so the specification plate still
   arrives soon after it. The crop sits a little above centre to keep the doors whole. */
.hero-photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: 50% 40%;
  background: var(--surface);
  margin: 0;
}

/* One photograph heading each floor's band on the start page. */
.band-photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--paper);
  margin-bottom: var(--space-4);
}

.more-link { margin-top: var(--space-5); }

/* -- The photo pop-up (fotos.html, assets/js/fotos.js, ADR-0009) ----------------------------------
   A native <dialog>, built by the script, never present without it. The ::backdrop is solid --ink,
   so the photo sits on green-black, not on a greyed-out page; the dialog itself is transparent and
   is the "panel" that flies in over it.

   Fitting the screen, always, without scrolling: the dialog is pinned to the *visible* viewport
   (inset 0, 100dvh with a 100vh fallback; dvh excludes a phone's address bar, vh does not), every UA
   default that could shrink or offset it is reset (margin, max-width, max-height), and it never
   scrolls (overflow hidden). Inside, a grid: controls / photo / caption and navigation. The chrome
   rows are auto; the photo row is minmax(0, 1fr), so it takes what is left and can shrink to nothing
   rather than push a button off the screen. The <img> box fills that row and the photo is contained
   in it (object-fit), never cropped and never larger than the box. Below 500px of height (a phone in
   landscape) the chrome collapses to one row under the photo.

   --lightbox-styled is the handshake with fotos.js: the script takes over a tile link only when it
   can see this property, so a stale cached stylesheet (without these rules) leaves the plain links
   working instead of opening an unstyled, scrolling UA dialog.

   Text is paper on ink (> 15:1), the counter surface on ink (> 13:1); button borders are line-strong
   on ink (5.5:1, >= 3:1 for a control boundary). Focus ring amber on ink (7.7:1), as on the dark bands.
   Square corners, no shadows. Motion: one easing curve and its time-reverse, no bounce; none at all
   with prefers-reduced-motion (the script then adds no motion classes either). */
.lightbox {
  --lightbox-styled: 1;
  --lightbox-ease-out: cubic-bezier(.2, .8, .2, 1);    /* arriving: fast start, soft landing */
  --lightbox-ease-in:  cubic-bezier(.8, 0, .8, .2);    /* leaving: the same curve, time-reversed */
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding:
    max(var(--space-3), env(safe-area-inset-top))
    max(var(--space-4), env(safe-area-inset-right))
    max(var(--space-4), env(safe-area-inset-bottom))
    max(var(--space-4), env(safe-area-inset-left));
  overflow: hidden;
  overscroll-behavior: contain;
  border: 0;
  background: transparent;
  color: var(--paper);
  /* Swipes reach the script (next/previous); pinch-zoom stays native. Nothing here pans. */
  touch-action: pinch-zoom;
}
/* Only when open: display on a closed <dialog> would override the browser's display: none. */
.lightbox[open] {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  grid-template-areas:
    "count   close"
    "photo   photo"
    "caption caption"
    "prev    next";
  gap: var(--space-3);
}
.lightbox::backdrop { background: var(--ink); }
/* The page behind must not scroll under the pop-up (the class is set by the script, :has() is the
   belt to its braces). */
html.lightbox-open,
html:has(.lightbox[open]) { overflow: hidden; }

.lightbox-img,
.lightbox-leaving {
  grid-area: photo;
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
}
/* The previous photo, fading out under the next one during a change; gone after ~160ms. */
.lightbox-leaving { pointer-events: none; }
.lightbox-count {
  grid-area: count;
  align-self: center;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--size-300);
  color: var(--surface);
  font-variant-numeric: tabular-nums;
}
.lightbox-caption {
  grid-area: caption;
  margin: 0;
  max-width: none;
  text-align: center;
  font-size: var(--size-300);
  line-height: var(--leading-snug);
  color: var(--paper);
  overflow-wrap: anywhere;
}
.lightbox button {
  min-height: 2.75rem;          /* ~47px: large enough to hit with a thumb */
  padding: var(--space-2) var(--space-4);
  font-size: var(--size-300);
  color: var(--paper);
  background: transparent;
  border: 2px solid var(--line-strong);
  white-space: nowrap;
}
.lightbox button:hover:enabled {
  background: var(--paper);
  color: var(--ink);
}
.lightbox :focus-visible { outline-color: var(--signal); }
.lightbox-close { grid-area: close; justify-self: end; }
.lightbox-prev  { grid-area: prev; }
.lightbox-next  { grid-area: next; }

@media (min-width: 40rem) {
  .lightbox {
    padding:
      max(var(--space-4), env(safe-area-inset-top))
      max(var(--space-5), env(safe-area-inset-right))
      max(var(--space-5), env(safe-area-inset-bottom))
      max(var(--space-5), env(safe-area-inset-left));
  }
  .lightbox[open] {
    grid-template-columns: minmax(10rem, auto) minmax(0, 1fr) minmax(10rem, auto);
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "count .       close"
      "photo photo   photo"
      "prev  caption next";
  }
  .lightbox-caption { align-self: center; }
}

/* Short screens (a phone on its side, a small laptop window): every control on one row under the
   photo, less padding, slightly lower buttons; the photo gets the height. */
@media (max-height: 31.25rem) {
  .lightbox {
    padding:
      max(var(--space-2), env(safe-area-inset-top))
      max(var(--space-3), env(safe-area-inset-right))
      max(var(--space-2), env(safe-area-inset-bottom))
      max(var(--space-3), env(safe-area-inset-left));
  }
  .lightbox[open] {
    grid-template-columns: auto auto minmax(0, 1fr) auto auto;
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas:
      "photo photo photo   photo photo"
      "count prev  caption next  close";
    gap: var(--space-2) var(--space-3);
  }
  .lightbox button {
    min-height: 2.5rem;         /* 40px: still a comfortable thumb target */
    padding: var(--space-1) var(--space-3);
  }
  .lightbox-caption { align-self: center; }
}

/* Motion. fotos.js sets these classes only when the visitor has not asked for reduced motion, and
   removes each one on animationend (with a timeout as a safety net). */
@media (prefers-reduced-motion: no-preference) {
  .lightbox.is-opening                 { animation: lightbox-panel-in 280ms var(--lightbox-ease-out); }
  .lightbox.is-opening::backdrop       { animation: lightbox-fade-in 280ms var(--lightbox-ease-out); }
  .lightbox.is-closing                 { animation: lightbox-panel-out 180ms var(--lightbox-ease-in) forwards; }
  .lightbox.is-closing::backdrop       { animation: lightbox-fade-out 180ms var(--lightbox-ease-in) forwards; }
  .lightbox-img.is-from-next           { animation: lightbox-from-next 220ms var(--lightbox-ease-out); }
  .lightbox-img.is-from-prev           { animation: lightbox-from-prev 220ms var(--lightbox-ease-out); }
  .lightbox-leaving.is-to-prev         { animation: lightbox-to-prev 160ms var(--lightbox-ease-in) forwards; }
  .lightbox-leaving.is-to-next         { animation: lightbox-to-next 160ms var(--lightbox-ease-in) forwards; }
}
@keyframes lightbox-panel-in  { from { opacity: 0; transform: translateY(16px) scale(.96); } }
@keyframes lightbox-panel-out { to   { opacity: 0; transform: translateY(16px) scale(.96); } }
@keyframes lightbox-fade-in   { from { opacity: 0; } }
@keyframes lightbox-fade-out  { to   { opacity: 0; } }
/* "Next" arrives from the right and pushes the old photo out to the left; "previous" mirrors it. */
@keyframes lightbox-from-next { from { opacity: 0; transform: translateX(24px); } }
@keyframes lightbox-from-prev { from { opacity: 0; transform: translateX(-24px); } }
@keyframes lightbox-to-prev   { to   { opacity: 0; transform: translateX(-24px); } }
@keyframes lightbox-to-next   { to   { opacity: 0; transform: translateX(24px); } }

/* -- The map --------------------------------------------------------------------------------------- */
.map {
  margin-block: var(--space-5);
  border: 2px solid var(--line-strong);
  background: var(--surface);
}
.map iframe {
  display: block;
  width: 100%;
  height: 26rem;
  border: 0;
}

/* -- The form (contact.html) -----------------------------------------------------------------------
   mailto: only. No backend, no storage, no third-party form service, no JavaScript: what the visitor
   types goes into their own mail client and nowhere else. Keyboard-first: one column, generous hit
   areas, labels above fields, and validation feedback from the browser itself. */
.form {
  max-width: 34rem;
  margin-block: var(--space-5);
}
.form fieldset {
  border: 0;
  border-top: 2px solid var(--line-strong);
  margin: 0 0 var(--space-6);
  padding: var(--space-4) 0 0;
}
.form legend {
  font-family: var(--font-display);
  font-size: var(--size-500);
  font-weight: var(--weight-bold);
  padding: 0 var(--space-3) 0 0;
}

.field { margin-bottom: var(--space-5); }
.field label {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  margin-bottom: var(--space-1);
}
.hint {
  display: block;
  font-size: var(--size-200);
  color: var(--ink-soft);
  margin-bottom: var(--space-2);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="date"],
textarea {
  display: block;
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 2px solid var(--line-strong);
  padding: var(--space-3);
}
input:hover,
textarea:hover { border-color: var(--ink-soft); }

/* Instant, honest validation: :user-invalid only fires once the visitor has actually interacted with
   a field, so an untouched empty form is never painted red. A browser without :user-invalid simply
   shows its own message on submit; nothing here depends on it. */
input:user-invalid,
textarea:user-invalid {
  border-color: var(--accent-deep);
  border-width: 3px;
}
input:user-invalid + .field-error,
textarea:user-invalid + .field-error { display: block; }
.field-error {
  display: none;
  font-size: var(--size-200);
  font-weight: var(--weight-bold);
  color: var(--ink);
  background: var(--surface);
  border-left: var(--rule) solid var(--accent);
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
}

.required-mark { font-weight: var(--weight-bold); }

button {
  font-family: var(--font-display);
  font-size: var(--size-400);
  font-weight: var(--weight-bold);
  color: var(--paper);
  background: var(--accent);
  border: 0;
  padding: var(--space-3) var(--space-5);
  cursor: pointer;
}
button:hover:enabled { background: var(--accent-deep); }
button:disabled {
  background: var(--surface);
  color: var(--ink-soft);
  border: 2px dashed var(--line-strong);
  cursor: not-allowed;
}


/* --------------------------------------------------------------------------------------------------
   7. FOOTER
   -------------------------------------------------------------------------------------------------- */
.site-footer {
  background: var(--accent);
  color: var(--paper);
  margin-top: var(--space-9);
  padding-block: var(--space-7);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
}
.site-footer > .wrap > * { flex: 1 1 16rem; min-width: 0; }

.site-footer h2 {
  font-size: var(--size-500);
  color: var(--paper);
  border-top: 0;
  padding-top: 0;
  margin: 0 0 var(--space-3);
}
.site-footer a { color: var(--paper); }
.site-footer a:hover { color: var(--paper); }
.site-footer p { color: var(--surface); }

.site-footer dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto;
  gap: 0;
}
.site-footer dt {
  font-family: var(--font-display);
  font-size: var(--size-200);
  color: var(--surface);
}
.site-footer dd {
  margin: 0 0 var(--space-3);
  font-weight: var(--weight-bold);
}
.footer-note p {
  font-size: var(--size-200);
  max-width: 46ch;
}


/* --------------------------------------------------------------------------------------------------
   8. RESPONSIVE, MOTION, PRINT

   The layout is fluid by construction (flex-wrap, minmax, clamp), so there is very little here: the
   two places that genuinely need a breakpoint are the plate/ladder grids, which become one column on
   a narrow phone, and the header, which stacks. Everything stays readable at 360px with no sideways
   scroll (REQ-011).
   -------------------------------------------------------------------------------------------------- */
@media (max-width: 34rem) {
  .site-header .wrap {
    flex-direction: column;
    align-items: flex-start;
  }
  .site-nav ul { gap: var(--space-2) var(--space-4); }

  .plate dl { grid-template-columns: 1fr; }
  .plate dt {
    padding-bottom: 0;
    border-top: 1px solid var(--line);
  }
  .plate dd {
    padding-top: var(--space-1);
    border-top: 0;
  }
  .plate dt:first-of-type + dd { border-top: 0; }

  .ladder > li { grid-template-columns: 1fr; }
  .ladder-scale { margin-left: var(--space-4); }

  .spec-table tbody th,
  .spec-table tbody td {
    display: block;
    width: auto;
    max-width: none;
  }
  .spec-table tbody td { border-top: 0; padding-top: 0; }

  .map iframe { height: 18rem; }
}

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

@media print {
  /* The navigation, the map and the call to action are of no use on paper; the address, the
     specification and the documents list are. */
  .site-header,
  .site-nav,
  .skip-link,
  .map,
  .cta { display: none; }

  body {
    background: #FFFFFF;
    color: #000000;
    font-size: 11pt;
  }
  .site-footer {
    background: #FFFFFF;
    color: #000000;
    border-top: 1pt solid #000000;
    margin-top: 1.5rem;
  }
  .site-footer h2,
  .site-footer a,
  .site-footer p,
  .site-footer dt { color: #000000; }
  .band,
  .plate,
  .notice {
    background: #FFFFFF;
    border: 1pt solid #000000;
  }
  a { text-decoration: underline; }
}
