/* main.css: reset + design system. Palette and ratios: docs/brand.md.
   Never `outline: none`; never hides the skip link.
   Contrast on --bg / --band-lift / --band-warm: --ink 17.84/19.16/16.96, --link 4.83/5.19/4.60,
   --brand (display only, needs 3) 3.60/3.87/3.43; --ink on a --brand fill 4.95.
   NOTE: --band-warm is the darkest flat band (--link 4.60); a gradient must clear 4.5 at every stop. */

/* ==========================================================================
   1. FONT FACES: GFS Didot (display, static 400) + Open Sans (body, 400-600)
   Greek + Latin subsets, self-hosted woff2. Swap = files + family name + --font-display/--font-body.
   WHY: Greek coverage is required; Playfair/Cormorant (the brief) have no Greek subset.
   ========================================================================== */

@font-face {
  font-family: 'GFS Didot';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/gfsdidot-latin.woff2') format('woff2');
  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;
}

@font-face {
  font-family: 'GFS Didot';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/gfsdidot-greek.woff2') format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
    U+03A3-03FF;
}

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/opensans-latin.woff2') format('woff2');
  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;
}

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/opensans-greek.woff2') format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
    U+03A3-03FF;
}

/* ==========================================================================
   2. TOKENS
   ========================================================================== */

:root {
  /* Surfaces: three, reused on every page type. */
  --bg: #FAF6F4;
  --band-lift: #FFFFFF;
  --band-warm: #F6F0EC;
  --hairline: #EBE1DC;
  /* Masthead/page-head meeting colour.
     NOTE: one value; both gradients meet here and a mismatch shows as a seam. */
  --head-band: #FBEEE6;
  /* Gradient shared by masthead and page head (one copy, so the join can't drift).
     WHY: flat ends, ramp in the middle; an even 0-100% ramp was invisible (0.075%/10px).
     NOTE: beige end can't darken: the language switch (--link) is 4.57 on --head-band. */
  --head-run: linear-gradient(
    to right,
    var(--band-lift) 0%,
    var(--band-lift) 40%,
    var(--head-band) 82%,
    var(--head-band) 100%
  );

  /* Ink */
  --ink: #100F0D;
  --body-ink: #4A423C;      /* body text: 9.16 on --bg */
  --accent: #B08D6A;        /* muted taupe, secondary accent (brand.md) */
  /* --accent darkened for control edges (1.4.11, 3:1): 3.87 on --bg, 3.68 on --band-warm.
     WHY: --accent is 2.85 on --bg. Slideshow dots, contact icons. */
  --accent-ui: #9B7550;
  --ink-soft: #5C5450;      /* secondary text: 6.89 on --bg */
  --brand: #D25C5C;         /* DISPLAY ONLY: 3.60 on --bg, fails body text */
  --link: #B04E4E;          /* links, small accents: 4.83 on --bg */

  /* Type */
  --font-display: 'GFS Didot', Georgia, 'Times New Roman', serif;
  --font-body: 'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Modular scale 1.2, base 16px; --step-4 ~33px.
     WHY: the rejected reference set its h1 at 72px. */
  --step--1: 0.833rem;
  --step-0: 1rem;
  --step-1: 1.2rem;
  --step-2: 1.44rem;
  --step-3: 1.728rem;
  --step-4: 2.074rem;

  /* Rhythm. Whitespace is the aesthetic («μη μπουκώνουν»). */
  --space-2xs: 0.375rem;
  --space-xs: 0.75rem;
  --space-s: 1.25rem;
  --space-m: 2rem;
  --space-l: 3.25rem;
  --space-xl: 5rem;

  --measure: 66ch;          /* reading column, within the 62–68ch brief */
  /* Width of every content photo. */
  --figure-max: 46rem;
  /* Masthead height: 72px logo + padding = 112px at every desktop width (nav never wraps).
     Used by the hero to float the header over the photograph. */
  --header-h: calc(72px + var(--space-s) * 2);
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --radius: 10px;
}

/* ==========================================================================
   3. RESET
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body,
h1, h2, h3, h4, h5, h6,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  margin: 0;
  padding: 0;
}

body {
  min-height: 100vh;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4,
button,
input,
label {
  line-height: 1.1;
}

h1, h2, h3, h4 {
  text-wrap: balance;
}

a:not([class]) {
  text-decoration-skip-ink: auto;
}

img,
picture,
svg,
video {
  max-width: 100%;
  display: block;
}

input,
button,
textarea,
select {
  font: inherit;
}

textarea:not([rows]) {
  min-height: 10em;
}

:target {
  scroll-margin-block: 5ex;
}

@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   4. BASE
   ========================================================================== */

body {
  background: var(--bg);
  color: var(--body-ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  /* 1.75: the reference she liked measured 1.8. */
  line-height: 1.75;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;          /* never bold display (she rejected it) */
  color: var(--ink);
}

h1 {
  font-size: clamp(var(--step-3), 1.4rem + 1.8vw, var(--step-4));
  line-height: 1.2;
  letter-spacing: -0.005em;
}

h2 {
  font-size: var(--step-2);
  line-height: 1.3;
}

h3 {
  font-size: var(--step-1);
  line-height: 1.35;
}

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

/* ==========================================================================
   5. FOCUS + SKIP LINK (a11y is contractual)
   ========================================================================== */

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: 0;
  z-index: 10;
  transform: translateY(-150%);
  display: inline-block;
  padding: var(--space-xs) var(--space-s);
  background: var(--band-lift);
  color: var(--link);
  border: 1px solid var(--hairline);
  border-radius: 0 0 var(--radius) var(--radius);
  text-decoration: none;
  font-size: var(--step--1);
}

.skip-link:focus {
  transform: translateY(0);
}

/* ==========================================================================
   6. HEADER, NAV, LANGUAGE SWITCH
   One bar: icon mark left (margin-right:auto), primary nav + language switch right.
   NOTE: the two navs are told apart by ORDER, never aria-label (per-language text).
   Icon-only, language-neutral mark; the tagline lives in the footer.
   ========================================================================== */

header {
  background: var(--band-lift);
  padding: var(--space-s) var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s) var(--space-m);
  /* Anchors the mobile menu panel (out of flow below the bar). */
  position: relative;
}

/* margin-right:auto pushes every following item to the right edge. */
.masthead-logo {
  display: block;
  flex: none;
  margin-right: auto;
  line-height: 0;
}

.masthead-logo img {
  display: block;
  width: 72px;
  height: 72px;
}

header nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-xs) var(--space-s);
}

/* Small uppercase, wide tracking. */
header nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
}

header nav a:hover {
  color: var(--link);
  border-bottom-color: var(--link);
}

/* Current page: aria-current="true" on articles, "page" elsewhere. */
header nav a[aria-current="page"],
header nav a[aria-current="true"] {
  color: var(--ink);
  border-bottom-color: var(--brand);
}

/* Language switch (second nav). */
header nav:nth-of-type(2) a {
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.3rem 0.85rem;
  color: var(--link);
  letter-spacing: 0.1em;
}

header nav:nth-of-type(2) a:hover {
  background: var(--band-warm);
  border-color: var(--link);
}

/* No bottom rule: masthead fades into --head-band, where the page head starts.
   NOTE: not on hero pages (the masthead floats on the photograph there). */
body:not(:has(.hero)) header {
  background: var(--head-run);
}

@media (forced-colors: active) {
  /* Gradients gone: the boundary returns as a system-colour rule. */
  header {
    border-bottom: 1px solid CanvasText;
  }
}

/* ==========================================================================
   7. MAIN, THE HERO, AND THE ARTICLE CARDS
   ========================================================================== */

/* Full-bleed grid via named lines.
   WHY: 100vw + negative margin overflows by the scrollbar width. */
main {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [content-start] minmax(0, 72rem) [content-end]
    minmax(var(--gutter), 1fr) [full-end];
  padding-bottom: var(--space-l);
}

main > * {
  grid-column: content-start / content-end;
}

/* Page head (non-home pages): headline + standfirst.
   NOTE: the rule separates sections from each other, not the head from the page. */
/* «Ποια είμαι»: the h1 sits in .about-lead (portrait-led); same voice, own spacing. */
main > h1,
.about-lead h1 {
  margin-bottom: var(--space-m);
  /* Display face at --body-ink, not the nav's sans at --ink-soft.
     WHY: lighter ink breaks a Didone's hairlines; uppercase sans reads as a label and empties sparse pages.
     NOTE: the -0.015em from § Greek micro-typography is inherited on purpose. */
  font-size: clamp(var(--step-3), 1.5rem + 2.2vw, calc(var(--step-4) * 1.25));
  color: var(--body-ink);
}

/* Only when the h1 opens the page (on «Ποια είμαι» the portrait leads). */
main > h1:first-child {
  margin-top: calc(var(--space-xl) * 1.35);
}

main > h1 + p {
  /* Grows on wide screens; --step-1 beside a 41px h1 read as a caption. */
  font-size: clamp(var(--step-1), 1.05rem + 0.45vw, var(--step-2));
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 46ch;
}

/* Page-head band on every non-hero page, starting at --head-band (where the masthead ends).
   NOTE: all non-hero pages, not only those with main > h1 («Ποια είμαι» has none).
   isolation keeps z-index -1 above the body background. */
body:not(:has(.hero)) main {
  position: relative;
  isolation: isolate;
}

body:not(:has(.hero)) main::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 30rem;
  z-index: -1;
  pointer-events: none;
  /* Left-to-right tint (matches the masthead, so the join is invisible) under a vertical fade to --bg.
     NOTE: the fade must reach --bg at exactly 100%, or it draws a hard edge.
     WHY: --band-warm was invisible and anything darker put --link at 4.37. --head-band is warmer at
     the same luminance: --link 4.57 at the beige end, 5.19 at the white. */
  background:
    linear-gradient(
      to bottom,
      rgb(250 246 244 / 0) 0%,
      rgb(250 246 244 / 0) 42%,
      rgb(250 246 244 / 1) 100%
    ),
    var(--head-run);
}

@media (forced-colors: active) {
  /* No palette to tint against; a forced band would fight the system background. */
  body:not(:has(.hero)) main::before {
    display: none;
  }
}

/* Head followed by air, not a rule.
   NOTE: both orders matched; the absolutely positioned .page-mark sits between and broke this once. */
main > h1 + p + section:not(.hero):not(.articles),
main > h1 + p + ul.post-list,
main > .page-mark + section:not(.hero):not(.articles),
main > .page-mark + ul.post-list {
  border-top: 0;
  padding-top: 0;
  /* One gap under the head on every page.
     NOTE: .post-list named explicitly, or its class margin outranks this selector. */
  margin-top: var(--space-xl);
}

/* Plain content sections only (hero and article grid space themselves). */
main > section:not(.hero):not(.articles) {
  padding-top: var(--space-l);
  margin-top: var(--space-l);
  border-top: 1px solid var(--hairline);
}

main > section h2 {
  margin-bottom: var(--space-xs);
}

main > section p + p {
  margin-top: var(--space-s);
}

/* --- the header over the hero -------------------------------------------
   On hero pages (body:has(.hero)) the header floats on the photograph; elsewhere a solid bar.
   Desktop only: below 46rem the hero has no scrim and the words sit under the photo.
   WHY: the scrim is functional. 0.85 top-down: nav links min 5.42, burger icon 13.88 (3:1),
   over the shipping painting @509dac5. Not enough for the language switch (own ground, below).
   NOTE: a new hero image means re-measuring. */
@media (min-width: 46rem) {
  body:has(.hero) header {
    position: absolute;
    inset-inline: 0;
    top: 0;
    z-index: 3;
    background: transparent;
    border-bottom: 0;
  }

  body:has(.hero) header::before {
    content: "";
    position: absolute;
    inset: 0 0 -2.5rem 0;
    z-index: -1;
    pointer-events: none;
    /* 0.85 across the bar; fade to nothing below it, where no text sits.
       WHY: 16a7803 lowered it from 0.97 unmeasured and the switch fell to 3.44-4.04.
       NOTE: anything new on this bar is measured over the photograph, never assumed. */
    background: linear-gradient(
      to bottom,
      rgb(250 246 244 / 0.85) 0%,
      rgb(250 246 244 / 0.85) 78%,
      rgb(250 246 244 / 0.55) 92%,
      rgb(250 246 244 / 0) 100%
    );
  }

  /* Language switch over hero: solid --bg ground.
     WHY: scrim passes on median only; antialiased min fails. 4.83 @509dac5 (4.60 on hover). */
  body:has(.hero) header nav:nth-of-type(2) a {
    background: var(--bg);
  }

  body:has(.hero) header nav:nth-of-type(2) a:hover {
    background: var(--band-warm);
  }

  /* Hero grows by the header band, so the photo below the header keeps its size.
     The picture clips; the image is min 53rem tall, top-anchored.
     WHY: face at 19% height was under the 152px scrim; at >= 848px it lands at >= 161px.
     NOTE: tuned to THIS picture. Zoom renders 94.25rem wide; `sizes` covers 46-60rem only
     (1440 file is within 5% above that). */
  body:has(.hero) .hero picture {
    height: calc(clamp(20rem, 56vh, 34rem) + var(--header-h));
    overflow: hidden;
  }

  body:has(.hero) .hero-image {
    height: max(calc(clamp(20rem, 56vh, 34rem) + var(--header-h)), 53rem);
  }

  /* Words move down by the same amount (h1 top was 80px vs header bottom 112px). */
  body:has(.hero) .hero-copy {
    padding-block-start: calc(var(--header-h) + var(--space-m));
  }
}

/* --- the hero ------------------------------------------------------------
   Full-bleed; headline at the left over a left-to-right scrim.
   WHY: the scrim is functional; the headline must not depend on the photograph behind it. */
.hero {
  position: relative;
  grid-column: full-start / full-end;
  margin-bottom: var(--space-xl);
  isolation: isolate;
}

.hero picture {
  display: block;
}

.hero-image {
  width: 100%;
  height: clamp(20rem, 56vh, 34rem);
  object-fit: cover;
  /* Face ~87% across, 19% down: top-anchored (clears the header scrim), 86% across (narrow crops left).
     NOTE: a new hero image needs this re-set. */
  object-position: 86% top;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Two scrims. First: the photo's foot dissolves into the page.
     NOTE: must reach 1 at exactly 100%, or it draws the hard edge it removes.
     Only lightens the ground under the copy (docs/AUDIT-a11y-2026-09-07.md). */
  background:
    linear-gradient(
      to bottom,
      rgb(250 246 244 / 0) 62%,
      rgb(250 246 244 / 0.55) 82%,
      rgb(250 246 244 / 1) 100%
    ),
    linear-gradient(
      to right,
      rgb(250 246 244 / 0.97) 0%,
      rgb(250 246 244 / 0.93) 28%,
      rgb(250 246 244 / 0.72) 46%,
      rgb(250 246 244 / 0.22) 66%,
      rgb(250 246 244 / 0) 82%
    );
}

.hero-copy {
  position: absolute;
  z-index: 2;
  inset-block: 0;
  inset-inline-start: 0;
  width: min(38rem, 82%);
  padding: var(--space-m) var(--space-m) var(--space-m) var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: var(--space-s);
}

.hero-copy h1 {
  margin: 0;
  max-width: 18ch;
  /* Larger than inner-page heads.
     WHY: Didot hairlines go sub-pixel at 33px on ~96dpi; no bolder weight, so size fixes it.
     NOTE: the steep vw term matters more than the ceiling (mid-range widths failed). */
  font-size: clamp(var(--step-3), 1.6rem + 2.6vw, calc(var(--step-4) * 1.45));
}

.hero-copy p {
  margin: 0;
  max-width: 34ch;
  color: var(--body-ink);
  font-size: var(--step-0);
  line-height: 1.7;
}

/* CTA pill: dark ink on taupe, 6.26:1.
   WHY: white on this taupe is 3.06:1, fails AA. See docs/brand.md. */
.cta,
a.cta {
  display: inline-block;
  background: var(--accent);
  color: var(--ink);
  text-decoration: none;
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  padding: 0.7rem 1.4rem;
  border-radius: 999px;
  border: 1px solid transparent;
}

/* Quieter pill for list rows; inherits the contrast decision above. */
.cta-small,
a.cta-small {
  padding: 0.45rem 1rem;
}

.cta:hover,
a.cta:hover {
  background: #C9AC8E;
  border-color: var(--ink);
  text-decoration: none;
}

/* Narrow: photo becomes its own band; words below it. */
@media (max-width: 46rem) {
  .hero-image {
    height: clamp(14rem, 38vh, 20rem);
  }

  .hero::after {
    display: none;
  }

  .hero-copy {
    position: static;
    width: 100%;
    inset: auto;
    padding: var(--space-m) var(--gutter) 0;
  }
}

/* --- article cards ------------------------------------------------------- */

.articles {
  padding-top: var(--space-l);
  margin-top: 0;
  border-top: 1px solid var(--hairline);
}

.articles > h2 {
  margin-bottom: var(--space-m);
}

.articles > h2 a {
  color: var(--ink);
  text-decoration-color: var(--accent);
  text-underline-offset: 0.2em;
}

/* Card RAIL, not a grid: scrolls sideways, every article on the homepage.
   NOTE: grid-auto-flow column + fixed track, so cards can't shrink. */
.card-grid {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(15rem, 20rem);
  gap: var(--space-m);
  list-style: none;
  margin: 0;
  /* Room for the scrollbar and the focus ring (clipped otherwise). */
  padding: 4px 4px var(--space-s);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: var(--accent) transparent;
}

/* Proximity, not mandatory: mandatory strands cards wider than a phone. */
.card-grid > .card {
  scroll-snap-align: start;
}

/* Focusable scroll region (tabindex="0" from build.py): visible ring. */
.card-grid:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
  border-radius: var(--radius);
}

@media (prefers-reduced-motion: no-preference) {
  .card-grid {
    scroll-behavior: smooth;
  }
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  position: relative;
}

/* Thumbnail link: display:block so the picture fills its grid/flex track. */
.thumb-link {
  display: block;
}

.card-thumb {
  display: block;
  width: 100%;
  /* height:auto makes aspect-ratio apply.
     WHY: <img> width/height attributes set CSS height, so aspect-ratio is ignored (363x613 vs 363x242). */
  height: auto;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius);
  object-fit: cover;
  margin-bottom: var(--space-xs);
}

/* Fallback thumbnail: aria-hidden span (no invented alt). One class per category_key.
   WHY: colours here, not inline style="": the CSP (style-src 'self') blocks inline styles.
   NOTE: an unknown key keeps the default pair, never a blank card. */
.card-thumb-fallback {
  --from: #B08D6A;
  --to: #C9AC8E;
  background: linear-gradient(135deg, var(--from), var(--to));
}

.category-exosomatiki { --from: #5B7F8C; --to: #7FA3AE; }
.category-mitrotita   { --from: #D9A277; --to: #E8C39E; }
.category-paidi       { --from: #9B8AB5; --to: #B9AACD; }
.category-sxeseis     { --from: #B08D6A; --to: #C9AC8E; }

.card-tag {
  align-self: flex-start;
  background: var(--accent);
  color: var(--ink);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  margin: 0;
  max-width: none;
}

.card h3 {
  margin: 0;
  font-size: var(--step-1);
  line-height: 1.3;
}

.card h3 a {
  color: var(--ink);
  text-decoration: none;
}

.card h3 a:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.card-date {
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--step--1);
}

.card-excerpt {
  margin: 0;
  color: var(--body-ink);
  font-size: var(--step--1);
  line-height: 1.7;
}

/* --- wide bar: logo left, nav CENTRED, language right --------------------
   Complementary to the burger query: one line here, burger below.
   Centring = two auto margins on the nav; logo and switch are flex:none.
   WHY: 76rem measured: EN wraps below 1012px, GREEK below 1184px; 1216px leaves 32px.
   NOTE: keep min/max complementary (starts at 1216.0625px) or burger and bar show at once. */
@media (min-width: 76.0625rem) {
  /* Logo margin overridden, not removed: the mobile bar needs it. */
  .masthead-logo {
    margin-right: 0;
  }

  header,
  #primary-nav {
    flex-wrap: nowrap;
  }

  header > nav:first-of-type {
    margin-inline: auto;
  }

  #primary-nav {
    justify-content: center;
  }
}

/* ==========================================================================
   8. LINKS
   ========================================================================== */

main a,
footer a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 1px;
}

main a:hover,
footer a:hover {
  text-decoration-thickness: 2px;
}

/* ==========================================================================
   9. FOOTER
   Grid: brand, navigation, location; legal row below a hairline.
   Nav generated from pages.json by build.py (can't drift from the header).
   WHY: grid, not space-between flex, which left the middle empty.
   ========================================================================== */

footer {
  /* Top rule fades out at both ends (a full-width hairline reads as a cut-off).
     NOTE: a 1px background layer, since borders can't carry a gradient. */
  background:
    linear-gradient(
      to right,
      transparent 0%,
      var(--hairline) 22%,
      var(--hairline) 78%,
      transparent 100%
    ) top / 100% 1px no-repeat,
    var(--band-warm);
  margin-top: var(--space-xl);
  padding: var(--space-l) var(--gutter);
  color: var(--ink-soft);
  font-size: var(--step--1);
}

@media (forced-colors: active) {
  /* Background images dropped: a real border restores the boundary. */
  footer {
    border-top: 1px solid CanvasText;
  }
}

.footer-inner {
  max-width: 78rem;
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr;          /* mobile first: one column */
  gap: var(--space-l) var(--space-m);
}

/* Mark in its own `auto` track, top-aligned with the column headings.
   WHY: centred inside the brand column, it misaligned all three regions. */
@media (min-width: 46rem) {
  .footer-inner {
    grid-template-columns: auto 1fr;
  }
}

/* Four tracks: mark, brand text (wider: carries the tagline), navigation, location. */
@media (min-width: 64rem) {
  .footer-inner {
    grid-template-columns: auto 1.4fr 1fr 1fr;
  }
}

/* No max-width: a 36ch cap left the brand 274px in a 488px track. */
.footer-brand {
  max-width: none;
}

.footer-brand p {
  margin: 0;
}

.footer-brand p + p {
  margin-top: var(--space-2xs);
}

/* Tagline (professional title) under the mark, spaced off the contact lines. */
.footer-brand .footer-tagline {
  margin-bottom: var(--space-s);
  letter-spacing: 0.06em;
  text-wrap: balance;
}

.footer-nav h2,
.footer-find h2 {
  margin: 0 0 var(--space-s);
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
}

.footer-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2xs);
}

/* Two columns of links, `max-content` tracks. */
@media (min-width: 30rem) {
  .footer-nav ul {
    grid-template-columns: repeat(2, max-content);
    column-gap: var(--space-l);
  }
}

/* --- where to find her ---------------------------------------------------
   A LINK OUT, never an embed.
   WHY: a maps iframe sets third-party cookies; the site makes zero third-party requests. */

.footer-find p {
  margin: 0;
}

.footer-find p + p {
  margin-top: var(--space-2xs);
}

.footer-address span {
  display: block;
}

.footer-map-link {
  margin-top: var(--space-xs);
}

.footer-map-link a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Slot for a static map PNG (<img class="footer-map"> inside the link, real width/height).
   Aspect ratio reserves the space; nothing renders until the image exists. */
.footer-map {
  display: block;
  width: 100%;
  max-width: 20rem;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  margin-bottom: var(--space-xs);
}

/* Matched to the header nav. */
.footer-nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
}

.footer-nav a:hover {
  color: var(--link);
  border-bottom-color: var(--link);
}

.footer-legal {
  max-width: 78rem;
  margin: var(--space-l) auto 0;
  padding-top: var(--space-s);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2xs) var(--space-s);
}

.footer-legal p {
  margin: 0;
}

/* ==========================================================================
   10. THE SERVICES SUBMENU
   Open by default; only .nav-enhanced (set by site-nav.js) collapses it.
   WHY: with JS off or broken the links stay visible; no dead control.
   ========================================================================== */

.has-submenu {
  position: relative;
}

.submenu {
  list-style: none;
  margin: var(--space-2xs) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2xs) var(--space-s);
}

.submenu a {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
}

.submenu-toggle {
  background: none;
  border: 0;
  padding: 0.25rem;
  margin-inline-start: 0.15rem;
  color: var(--ink-soft);
  cursor: pointer;
  line-height: 0;
}

.submenu-toggle svg {
  width: 0.6rem;
  height: 0.4rem;
  display: inline-block;
  transition: transform 0.15s ease;
}

.submenu-toggle:hover {
  color: var(--link);
}

/* --- enhanced: toggle exists, submenu can collapse ----------------------- */

.nav-enhanced .submenu {
  display: none;
}

.nav-enhanced .is-open .submenu {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: flex-start;
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.5rem);
  left: 50%;
  transform: translateX(-50%);
  min-width: max-content;
  background: var(--band-lift);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--space-xs) var(--space-s);
  gap: var(--space-2xs);
  box-shadow: 0 6px 20px rgb(16 15 13 / 0.08);
}

.nav-enhanced .is-open .submenu-toggle svg {
  transform: rotate(180deg);
}

/* Stacked nav: open submenu stays in flow and indents (no overlay). */
@media (max-width: 76rem) {
  .nav-enhanced .is-open .submenu {
    position: static;
    transform: none;
    box-shadow: none;
    border: 0;
    background: none;
    padding: var(--space-2xs) 0 0;
    align-items: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .submenu-toggle svg {
    transition: none;
  }
}

/* ==========================================================================
   11. THE ABOUT PAGE: portrait-led, with a mid-page breather
   The still-life is decorative (alt=""), a pacing device.
   ========================================================================== */

.about-lead {
  display: grid;
  gap: var(--space-m);
  align-items: start;
  margin-top: var(--space-xl);
}

.about-lead-copy > p {
  /* Same standfirst as every page head (main > h1 + p). */
  font-size: clamp(var(--step-1), 1.05rem + 0.45vw, var(--step-2));
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 46ch;
}

.portrait {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

@media (min-width: 52rem) {
  .about-lead {
    grid-template-columns: 22rem minmax(0, 1fr);
    gap: clamp(2rem, 5vw, 3.5rem);
  }
}

/* ==========================================================================
   11b. PHOTOS IN CONTENT SECTIONS, AND THE SPACE GALLERY
   .section-figure sits inside its section, so text and photo reveal together.
   One class for hand-written and generated sections.
   ========================================================================== */

/* Capped below the 72rem column (3:2 there is 768px tall). */
.section-figure img {
  width: 100%;
  max-width: var(--figure-max);
  height: auto;
  border-radius: var(--radius);
}

.section-figure {
  margin: var(--space-m) 0 0;
}

/* --- service line drawings ------------------------------------------------
   mix-blend-mode: multiply removes the jpg's white (no alpha).
   NOTE: figure background is load-bearing: reveal.js transforms create a stacking context;
   without it the art flashes white during the fade.
   Floated so the copy wraps. */
section.service .section-figure {
  float: inline-end;
  width: min(34%, 15rem);
  margin: 0 0 var(--space-s) var(--space-m);
  background: var(--bg);
}

section.service .section-figure img {
  /* No radius (a corner reads as a card edge). */
  border-radius: 0;
  mix-blend-mode: multiply;
  /* One frame for all (art is 16:9, 2:1, 1:1).
     WHY: contain, not cover: cover crops line art; the letterbox vanishes under multiply.
     NOTE: hence aspect: null in plan.json; the crop lives here. */
  aspect-ratio: 4 / 3;
  object-fit: contain;
}

/* Section contains its float.
   NOTE: hooks on class="service" (SECTION_KINDS), never the id: that is her anchor (e24c1d8 broke it). */
section.service {
  overflow: hidden;
  /* Content box narrowed so the float lands beside the text, not at the 72rem edge.
     WHY: padding, not max-width: border-top paints on the border box and must stay full width.
     NOTE: max() floors at 0 below the float breakpoint. */
  padding-inline-end: max(0rem, 100% - (var(--measure) + 15rem + var(--space-m) * 2));
}

/* Narrow: a 15rem float leaves ~20ch; the drawing goes above, centred, small. */
@media (max-width: 46rem) {
  section.service .section-figure {
    float: none;
    width: min(60%, 12rem);
    margin: var(--space-s) auto 0;
  }
}

/* Forced colors: no cream to multiply against; plain image. */
@media (forced-colors: active) {
  section.service .section-figure img {
    mix-blend-mode: normal;
  }
}

/* --- the space gallery ---------------------------------------------------
   Nothing counts photos: auto-FILL with a minimum track, so additions flow.
   WHY: auto-fit stretches a lone photo across the row. */
.space-gallery {
  display: grid;
  /* 17rem measured: 3 tiles at 362px; 16rem stranded the fifth photo on a row of four. */
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--space-m);
  margin-top: var(--space-l);
  list-style: none;
  padding: 0;
}

/* One ratio for the set; object-fit crops. */
.space-gallery img {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius);
}

/* Homepage slideshow: one frame, CSS cross-fade, radios + labels as dots.
   WHY: no JS, keyboard-operable (arrow keys), announced as a labelled control. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.space-slideshow {
  margin-top: var(--space-m);
  max-width: var(--figure-max);
}

/* Off-screen but focusable (ring drawn on the dot).
   NOTE: never display:none; it leaves the tab order. */
.space-slide-input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* Frame holds the aspect ratio (no shift). All photos are 3:2. */
.space-frame {
  position: relative;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius);
  overflow: hidden;
}

/* Each slide links to the space page.
   NOTE: visibility, not opacity alone: opacity 0 is still clickable and focusable. */
.space-slide {
  position: absolute;
  inset: 0;
  display: block;
  opacity: 0;
  visibility: hidden;
}

.space-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Slide 1 is checked in the HTML, so it shows even without :checked support. */
/* Enumerated to 12: "Nth radio checked -> Nth slide" needs one selector per N.
   WHY: inline <style> is blocked by the CSP; a preprocessor is a build dependency.
   NOTE: build.py fails past SLIDESHOW_MAX. Raise it = SLIDESHOW_MAX + these three lists. */
#space-slide-1:checked ~ .space-frame .space-slide:nth-child(1),
#space-slide-2:checked ~ .space-frame .space-slide:nth-child(2),
#space-slide-3:checked ~ .space-frame .space-slide:nth-child(3),
#space-slide-4:checked ~ .space-frame .space-slide:nth-child(4),
#space-slide-5:checked ~ .space-frame .space-slide:nth-child(5),
#space-slide-6:checked ~ .space-frame .space-slide:nth-child(6),
#space-slide-7:checked ~ .space-frame .space-slide:nth-child(7),
#space-slide-8:checked ~ .space-frame .space-slide:nth-child(8),
#space-slide-9:checked ~ .space-frame .space-slide:nth-child(9),
#space-slide-10:checked ~ .space-frame .space-slide:nth-child(10),
#space-slide-11:checked ~ .space-frame .space-slide:nth-child(11),
#space-slide-12:checked ~ .space-frame .space-slide:nth-child(12) {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

@media (prefers-reduced-motion: no-preference) {
  .space-slide {
    /* visibility flips after the fade out, so the outgoing slide stays painted. */
    transition: opacity 600ms ease, visibility 0s linear 600ms;
  }
}

.space-dots {
  display: flex;
  justify-content: center;
  margin-top: var(--space-2xs);
}

/* Dot 10px, target 44px: the label is the hit area, ::before draws the dot.
   WHY: a bare dot measured a 13px tap target at 390px wide. */
.space-dot {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  cursor: pointer;
}

.space-dot::before {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  border: 1px solid var(--accent-ui);
}

@media (prefers-reduced-motion: no-preference) {
  .space-dot::before {
    transition: background-color 200ms ease, transform 200ms ease;
  }
}

.space-dot:hover::before {
  background: var(--accent-ui);
}

/* Current dot: filled AND larger (not colour alone). */
#space-slide-1:checked ~ .space-dots li:nth-child(1) .space-dot::before,
#space-slide-2:checked ~ .space-dots li:nth-child(2) .space-dot::before,
#space-slide-3:checked ~ .space-dots li:nth-child(3) .space-dot::before,
#space-slide-4:checked ~ .space-dots li:nth-child(4) .space-dot::before,
#space-slide-5:checked ~ .space-dots li:nth-child(5) .space-dot::before,
#space-slide-6:checked ~ .space-dots li:nth-child(6) .space-dot::before,
#space-slide-7:checked ~ .space-dots li:nth-child(7) .space-dot::before,
#space-slide-8:checked ~ .space-dots li:nth-child(8) .space-dot::before,
#space-slide-9:checked ~ .space-dots li:nth-child(9) .space-dot::before,
#space-slide-10:checked ~ .space-dots li:nth-child(10) .space-dot::before,
#space-slide-11:checked ~ .space-dots li:nth-child(11) .space-dot::before,
#space-slide-12:checked ~ .space-dots li:nth-child(12) .space-dot::before {
  background: var(--accent-ui);
  transform: scale(1.3);
}

/* Focus ring on the dot (the input is off-screen). */
#space-slide-1:focus-visible ~ .space-dots li:nth-child(1) .space-dot::before,
#space-slide-2:focus-visible ~ .space-dots li:nth-child(2) .space-dot::before,
#space-slide-3:focus-visible ~ .space-dots li:nth-child(3) .space-dot::before,
#space-slide-4:focus-visible ~ .space-dots li:nth-child(4) .space-dot::before,
#space-slide-5:focus-visible ~ .space-dots li:nth-child(5) .space-dot::before,
#space-slide-6:focus-visible ~ .space-dots li:nth-child(6) .space-dot::before,
#space-slide-7:focus-visible ~ .space-dots li:nth-child(7) .space-dot::before,
#space-slide-8:focus-visible ~ .space-dots li:nth-child(8) .space-dot::before,
#space-slide-9:focus-visible ~ .space-dots li:nth-child(9) .space-dot::before,
#space-slide-10:focus-visible ~ .space-dots li:nth-child(10) .space-dot::before,
#space-slide-11:focus-visible ~ .space-dots li:nth-child(11) .space-dot::before,
#space-slide-12:focus-visible ~ .space-dots li:nth-child(12) .space-dot::before {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

.pacing {
  margin: var(--space-l) 0 0;
  padding-top: var(--space-l);
  border-top: 1px solid var(--hairline);
}

.pacing img {
  width: 100%;
  /* --figure-max like every content photo (was 1152px vs 736px); height-capped, reads as a band. */
  max-width: var(--figure-max);
  max-height: 20rem;
  height: auto;
  object-fit: cover;
  border-radius: var(--radius);
}

/* ==========================================================================
   12. FOOTER LOGO
   The masthead mark, smaller, left-aligned; alt="" (the header link names the practice).
   ========================================================================== */

.footer-logo {
  display: block;
  width: 64px;
  height: 64px;
  margin: 0;
}

/* ==========================================================================
   13. THE MOBILE MENU
   Burger is display:none by default; .nav-enhanced (site-nav.js) collapses the list
   below the breakpoint only. JS off: the list stays visible and wraps.
   ========================================================================== */

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 0.5rem 0.7rem;
  color: var(--ink);
  cursor: pointer;
  line-height: 0;
}

.nav-toggle svg {
  width: 1.25rem;
  height: 0.875rem;
}

.nav-toggle:hover {
  border-color: var(--link);
  color: var(--link);
}

@media (max-width: 76rem) {
  /* Visual order only: burger rightmost, switch inboard. DOM/tab order unchanged. */
  header nav:nth-of-type(2) {
    order: 2;
  }

  header nav:nth-of-type(1) {
    order: 3;
  }

  .nav-enhanced .nav-toggle {
    display: inline-flex;
    align-items: center;
  }

  .nav-enhanced #primary-nav {
    display: none;
  }

  /* Out of flow: the panel drops below the header, full width, on its ground. */
  .nav-enhanced.is-menu-open #primary-nav {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-xs);
    position: absolute;
    z-index: 30;
    top: 100%;
    left: 0;
    right: 0;
    padding: var(--space-s) var(--gutter);
    background: var(--band-lift);
    border-bottom: 1px solid var(--hairline);
    box-shadow: 0 6px 20px rgb(16 15 13 / 0.08);
  }
}

/* ==========================================================================
   14. CROSS-LANGUAGE MARKER
   Greek-only article on an English surface is flagged. --ink-soft 6.89 on --bg.
   ========================================================================== */

.lang-flag {
  display: inline-block;
  vertical-align: middle;
  margin-left: 0.5em;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* ==========================================================================
   12. THE ARTICLE: the reading template
   Prose sits in <article class="prose">; one flow rule spaces whatever she writes.
   WHY: as bare children of <main> it missed every `main > section` rhythm rule.
   ========================================================================== */

.article-kicker {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: var(--space-xl);
  margin-bottom: var(--space-2xs);
}

/* No top margin: the kicker already opened the page. */
.article-kicker + h1 {
  margin-top: 0;
}

.article-date {
  font-family: var(--font-body);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  margin-top: var(--space-2xs);
}

/* Lead = the standfirst. */
.article-lead {
  font-size: var(--step-1);
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 46ch;
  margin-top: var(--space-s);
}

/* ==========================================================================
   12b. THE ARTICLE INDEX: image left, text right
   One column on mobile, two from 46rem.
   ========================================================================== */
.post-list {
  list-style: none;
  margin: var(--space-l) 0 0;
  padding: 0;
}

.post {
  display: grid;
  gap: var(--space-xs) var(--space-m);
  padding-top: var(--space-l);
  margin-top: var(--space-l);
  border-top: 1px solid var(--hairline);
}

.post:first-child {
  padding-top: 0;
  margin-top: 0;
  border-top: 0;
}

.post-thumb {
  display: block;
  width: 100%;
  /* Same presentational-hint trap as .card-thumb. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius);
}

.post-tag {
  font-size: var(--step--1);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.post h2 {
  font-size: var(--step-2);
}

/* Ink, not link-red, like every heading; accent on hover. */
.post h2 a {
  color: var(--ink);
  text-decoration: none;
}

.post h2 a:hover {
  color: var(--link);
  text-decoration: underline;
}

.post-date {
  font-size: var(--step--1);
  color: var(--ink-soft);
}

.post-excerpt {
  max-width: 60ch;
}

/* Text stacks itself, so the row has two children. */
.post-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  align-items: start;
}

@media (min-width: 46rem) {
  .post {
    grid-template-columns: 16rem minmax(0, 1fr);
    align-items: start;
  }
}

/* Article photo between standfirst and body. */
.article-figure {
  margin-top: var(--space-m);
}

/* Matches the TEXT it leads, not --figure-max (fixed 736px was wrong in both layouts).
   Single column: the measure. */
.article-figure img {
  width: 100%;
  max-width: var(--measure);
  /* Same presentational-hint trap as .card-thumb. */
  height: auto;
  border-radius: var(--radius);
}

/* Two columns: full content column (same breakpoint as the columns). */
@media (min-width: 78rem) {
  .article-figure img {
    max-width: none;
  }
}

/* --- the prose flow ------------------------------------------------------
   `* + *` spaces every sibling after the first, known element or not. */
.prose {
  margin-top: var(--space-l);
}

.prose > * + *,
.rich > * + * {
  margin-block-start: var(--space-s);
}

/* Subheads get more room above.
   NOTE: markdown headings are demoted one level: `##` lands as h3, `###` as h4.
   h4 names the display face (the base rule covers h1-h3 only). */
.prose > h2,
.prose > h3,
.prose > h4 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--ink);
}

.prose > h2 {
  font-size: var(--step-3);
  line-height: 1.3;
  margin-block-start: var(--space-l);
}

.prose > h3 {
  font-size: var(--step-2);
  line-height: 1.3;
  margin-block-start: var(--space-l);
}

.prose > h4 {
  font-size: var(--step-1);
  line-height: 1.35;
  margin-block-start: var(--space-m);
}

.prose > h2 + *,
.prose > h3 + *,
.prose > h4 + * {
  margin-block-start: var(--space-xs);
}

/* --- page and section prose ----------------------------------------------
   .rich = .prose one level down (top_level=3): `#` -> h3, `##` -> h4, `###` -> h5.
   Sizes step down from the section h2 (--step-2). h5 styled, or it drops to bold body type. */
.rich > h3,
.rich > h4,
.rich > h5 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--ink);
}

.rich > h3 {
  font-size: var(--step-1);
  line-height: 1.35;
  margin-block-start: var(--space-m);
}

.rich > h4,
.rich > h5 {
  font-size: var(--step-0);
  line-height: 1.4;
}

.rich > h4 {
  margin-block-start: var(--space-m);
}

.rich > h5 {
  margin-block-start: var(--space-s);
}

.rich > h3 + *,
.rich > h4 + *,
.rich > h5 + * {
  margin-block-start: var(--space-xs);
}

/* The h2's margin-bottom supplies the gap; no extra top margin. */
.rich > :first-child {
  margin-block-start: 0;
}

/* Empty .rich (heading-only section in a hand-written template) takes no space. */
.rich:empty {
  display: none;
}

/* <strong> in --link, 600: emphasis via the Bold button, no new syntax.
   WHY: --link 4.83 vs --accent 3.60 at body size; Open Sans is declared 400-600 (700 clamps). */
.prose strong,
.rich strong {
  color: var(--link);
  font-weight: 600;
}

.prose ul,
.prose ol,
.rich ul,
.rich ol {
  padding-left: 1.4em;
}

.prose li + li,
.rich li + li {
  margin-top: var(--space-2xs);
}

.prose li::marker,
.rich li::marker {
  color: var(--accent);
}

/* Quiet pull-quote: accent rule, no quotation marks, no italics. */
.prose blockquote,
.rich blockquote {
  margin-block-start: var(--space-m);
  padding-left: var(--space-s);
  border-left: 2px solid var(--accent);
  color: var(--ink-soft);
  font-size: var(--step-1);
  line-height: 1.6;
}

.prose blockquote p + p,
.rich blockquote p + p {
  margin-top: var(--space-xs);
}

.prose p > img,
.rich p > img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

.prose figure,
.rich figure {
  margin-block-start: var(--space-m);
}

.prose figure img,
.rich figure img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

.prose figcaption,
.rich figcaption {
  margin-top: var(--space-2xs);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

.prose > :last-child,
.rich > :last-child {
  margin-bottom: 0;
}

/* --- the magazine setting -------------------------------------------------
   Lead photo full width above; body in two columns from 78rem.
   NOTE: accepted trade-off: columns taller than the viewport force scroll-back (Chris's call).
   Longest article (501 words): 816px vs an 800px viewport. If pieces grow, raise the breakpoint.
   WHY: 78rem: each column 550px = 63ch; at 64rem it was 54ch (brief: 62-68ch). */
@media (min-width: 78rem) {
  .prose {
    column-count: 2;
    column-gap: var(--space-l);
  }

  /* Global 66ch cap dropped: the column sets the measure. */
  .prose > p,
  .prose > ul,
  .prose > ol,
  .prose > blockquote {
    max-width: none;
  }

  /* Nothing that reads as one object splits across columns. */
  .prose figure,
  .prose blockquote,
  .prose li,
  .prose p > img {
    break-inside: avoid;
  }

  /* No subhead stranded at a column foot. */
  .prose > h2,
  .prose > h3,
  .prose > h4 {
    break-after: avoid;
  }

  /* No flow margin at a column top, so both columns start level. */
  .prose > :first-child {
    margin-block-start: 0;
  }
}

/* Source credit: quiet, above the back link. */
.article-source {
  margin-top: var(--space-m);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* --- foot of the article ------------------------------------------------- */

.article-back {
  margin-top: var(--space-l);
  padding-top: var(--space-s);
  border-top: 1px solid var(--hairline);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
}

.related {
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: 1px solid var(--hairline);
}

.related h2 {
  font-size: var(--step--1);
  font-family: var(--font-body);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: var(--space-xs);
}

.related ul {
  list-style: none;
  padding: 0;
}

.related li + li {
  margin-top: var(--space-xs);
}

.related a {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.35;
}

/* ==========================================================================
   13. GREEK MICRO-TYPOGRAPHY
   Tonos clips under tight line-heights; « » are the correct Greek quotation marks.
   ========================================================================== */

body {
  /* Kerning + default ligatures (Greek and Latin). */
  font-kerning: normal;
  font-feature-settings: "kern" 1, "liga" 1;
  text-rendering: optimizeLegibility;
}

/* `pretty` on body text, `balance` on headings. */
main p,
.prose li,
.rich li,
.article-lead {
  text-wrap: pretty;
}

/* Tighter tracking at display sizes only (Didot opens up). */
h1,
.hero h1 {
  letter-spacing: -0.015em;
}

/* Narrower headline, so `balance` avoids widows. */
main > h1,
.article-kicker + h1 {
  max-width: 24ch;
}

/* ==========================================================================
   14. MOTION: one reveal, used everywhere
   Content is visible by default; hidden only with no reduced-motion AND .js-reveal on <html>.
   WHY: if reveal.js is blocked or fails, nothing was ever hidden.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .js-reveal .reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 500ms ease, transform 500ms ease;
  }

  .js-reveal .reveal.is-in {
    opacity: 1;
    transform: none;
  }
}

/* Hover: the underline draws in. */
main a:not(.cta):not([class*="card"]) {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size 220ms ease;
}

main a:not(.cta):not([class*="card"]):hover {
  background-size: 100% 1px;
}

.card-thumb {
  transition: transform 400ms ease;
}

.card:hover .card-thumb {
  transform: scale(1.03);
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .card-thumb,
  main a {
    transition: none !important;
  }

  .card:hover .card-thumb {
    transform: none;
  }
}

/* ==========================================================================
   14a. FOLDED SECTIONS
   Services, FAQ, about: native <details>, closed on load; the h2 in <summary> is the toggle.
   Keyboard-operable, announced, works without JS. site-nav.js opens a link's target,
   and every fold for print. Summary capped at the measure (chevron ends the text column).
   ========================================================================== */

.fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  max-width: var(--measure);
  cursor: pointer;
  /* list-style: Firefox/Chrome; ::-webkit-details-marker: Safari. */
  list-style: none;
}

.fold > summary::-webkit-details-marker {
  display: none;
}

/* Gap under the heading only when open. */
.fold > summary h2 {
  margin-bottom: 0;
}

.fold[open] > summary {
  margin-bottom: var(--space-xs);
}

/* Chevron drawn with borders (a glyph would take the face's metrics).
   --link 4.83 on --bg (3:1 needed). */
.fold > summary::after {
  content: "";
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border-right: 1.5px solid var(--link);
  border-bottom: 1.5px solid var(--link);
  transform: translateY(-0.2rem) rotate(45deg);
}

.fold[open] > summary::after {
  transform: translateY(0.15rem) rotate(-135deg);
}

.fold > summary:hover h2 {
  color: var(--link);
}

@media (prefers-reduced-motion: no-preference) {
  .fold > summary::after {
    transition: transform 200ms ease;
  }
}

/* ==========================================================================
   14b. PAGE WATERMARKS
   One glyph per page, via {{ICON:}} from src/assets/icons. «Ποια είμαι» has none (portrait).
   Elements, not CSS content: generated text is announced by some screen readers.
   WHY: 11% of --brand shifts the ground 11.4% (invisible below ~6%); head copy over it 8.2.
   ========================================================================== */

.page-mark {
  position: absolute;
  /* Pinned to the content column's right edge, not the viewport. */
  right: max(var(--gutter), calc((100% - 72rem) / 2));
  /* Level with the headline (same token as its top margin). */
  top: calc(var(--space-xl) * 1.35);
  z-index: -1;
  width: clamp(8rem, 13vw, 12rem);
  color: var(--brand);
  opacity: 0.11;
  pointer-events: none;
  user-select: none;
}

/* Glyphs fill the mark here (em-sized elsewhere). */
.page-mark .icon {
  width: 100%;
  height: auto;
  transform: none;
  /* Thinner stroke: it scales with the box. */
  stroke-width: 0.7;
}

@media (max-width: 60rem) {
  /* Hidden below the breakpoint (would sit under the copy). */
  .page-mark {
    display: none;
  }
}

@media (forced-colors: active), print {
  .page-mark {
    display: none;
  }
}

/* ==========================================================================
   15. ICONS
   Inline SVG via {{ICON:name}}; em-sized, currentColor (follows contrast and forced-colors).
   WHY: icon fonts and CDN sprites fail silently under the CSP (default-src 'self').
   ========================================================================== */

.icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  /* Optical alignment: 0.14em drop beside 16px text. */
  transform: translateY(0.14em);
}

/* Align to the first line; a wrapped address indents under itself. */
.with-icon {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
}

.with-icon .icon {
  /* --accent-ui, not --accent (2.85 on --bg, 2.71 on --band-warm).
     NOTE: decorative (aria-hidden, labelled), so 1.4.11 doesn't bind; --accent-ui clears 3.0 on both anyway. */
  color: var(--accent-ui);
}

/* --- card category glyph -------------------------------------------------
   Only where a thumbnail is missing; white at low opacity over the category gradient. */
.card-thumb-fallback {
  display: grid;
  place-items: center;
}

.card-thumb-icon {
  width: 34%;
  max-width: 4.5rem;
  height: auto;
  color: #FFFFFF;
  opacity: 0.62;
  stroke-width: 1.1;
}

@media (forced-colors: active) {
  /* Forced colors: no gradient, so the white glyph would vanish. */
  .card-thumb-icon {
    color: CanvasText;
    opacity: 1;
  }
}

/* ==========================================================================
   16. HIGH CONTRAST AND FORCED COLORS
   Honours the visitor's OS settings; no overlay widget, no third-party script.
   Reasoning: docs/AUDIT-a11y-2026-09-07.md.
   ========================================================================== */

/* --- prefers-contrast: more -------------------------------------------------
   Tokens, not rules: redefines seven values. Figures measured on --bg. */
@media (prefers-contrast: more) {
  :root {
    --body-ink: #2E2724;      /*  9.16 -> 13.66 */
    --ink-soft: #3D3733;      /*  6.89 -> 10.91 */
    --link:     #7C2E2E;      /*  4.83 ->  8.55: least headroom */
    --brand:    #A33F3F;      /*  3.60 ->  5.85: the aria-current underline */
    --accent:   #6B4F33;      /*  2.85 ->  7.00: the li::marker */
    --accent-ui: #6B4F33;     /*  3.87 ->  7.00: dots, contact icons */
    --hairline: #8A7A71;      /*  1.20 ->  3.83: a real boundary under 1.4.11 */
  }

  /* --accent is a BACKGROUND on the pill and the card tag, so darkening it inverts them.
     WHY: --ink on the new accent 2.55 (fails), white 7.52. The tag is 0.7rem: no large-text allowance. */
  .cta,
  a.cta,
  .card-tag {
    color: var(--band-lift);
  }

  .cta,
  a.cta {
    border-color: var(--ink);
  }

  .cta:hover,
  a.cta:hover {
    background: #55402A;
    color: var(--band-lift);
  }

  /* No photo bleeds into the masthead.
     NOTE: not a fix; nothing fails at 0.85 (nav min 5.42, burger 13.88 @509dac5).
     Hero scrim untouched: copy ends at 21-37% width where it is 0.85+; text 6.89 worst-case. */
  body:has(.hero) header::before {
    background: var(--bg);
  }
}

/* --- forced-colors: active ------------------------------------------------
   Palette replaced wholesale; only the places where meaning lives in a background are undone. */
@media (forced-colors: active) {
  /* Header back in flow: forced ink over a cream scrim fails on dark themes. */
  body:has(.hero) header {
    position: static;
    background: Canvas;
    border-bottom: 1px solid CanvasText;
  }

  body:has(.hero) header::before {
    display: none;
  }

  /* Hero and image back to their own height (no floating bar, no scrim). */
  body:has(.hero) .hero picture {
    height: auto;
  }

  body:has(.hero) .hero-image {
    height: clamp(20rem, 56vh, 34rem);
  }

  /* Pill fill is gone: an edge gives the shape. */
  .cta,
  a.cta {
    border-color: ButtonText;
  }

  /* Open submenu needs its own background. */
  .nav-enhanced .is-open .submenu {
    border: 1px solid CanvasText;
  }

  /* System highlight, not a forced --link. */
  :focus-visible {
    outline-color: Highlight;
  }
}

/* ==========================================================================
   17. PRINT: the words, the address, and where each link went
   ========================================================================== */

@media print {
  header,
  footer,
  .skip-link,
  .article-back,
  .related,
  /* .hero-image (the real class); .hero-media matched nothing. */
  .hero-image,
  .card-thumb {
    display: none !important;
  }

  /* One column on paper.
     NOTE: the min-width query should already exclude print; stated explicitly, unverified. */
  .prose {
    column-count: 1;
  }

  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
    line-height: 1.5;
  }

  main {
    display: block;
    max-width: none;
    margin: 0;
    padding: 0;
  }

  h1, h2, h3 {
    color: #000;
    page-break-after: avoid;
  }

  .prose > * + * {
    margin-block-start: 0.6em;
  }

  p, blockquote, figure {
    page-break-inside: avoid;
  }

  /* Printed links show their address; internal links get the origin. */
  main a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    word-break: break-all;
  }

  main a[href^="/"]::after {
    content: " (mariasouropani.gr" attr(href) ")";
    font-size: 9pt;
  }

  main a {
    text-decoration: underline;
    background-image: none;
  }
}
