/* =========================================================================
   Mesogeiako — site styles
   Components reference tokens.css only; no raw colour or size values here.
   ========================================================================= */

/* ---------------------------------------------------------------- reset */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-height) + var(--space-4));
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
::selection { background: var(--color-selection-bg); color: var(--brand-900); }

/* -------------------------------------------------------- justification
   Justified prose is the house style. It is applied to running text only:
   headings, navigation, buttons and single-line UI would break under it
   (last-line gaps, rivers), so those stay left-aligned. `hyphens: auto`
   with a correct `lang` attribute is what keeps justified Greek and English
   from opening rivers between words.                                      */

p,
.prose,
.prose li,
.prose blockquote,
.lede,
.card__text,
.section__intro {
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
  hyphenate-limit-chars: 6 3 3;
  text-wrap: pretty;
}

/* Never justify these. Justification needs a run of text to distribute space
   across; on a single line it only opens gaps, and on a control it misaligns
   the label. These are all one- or two-line UI, so they stay left-aligned even
   though they contain <p> elements. */
h1, h2, h3, h4, h5, h6,
.btn, .btn p, .nav__link, .topbar, .topbar p, .footer__meta, .footer__meta p,
th, .card__title, .card__meta, .eyebrow, .stat, .stat p, .badge,
figcaption, .pagination,
.team__name, .team__role, .team__email,
.tool__title, .tool__text,
.mobile-nav, .mobile-nav p,
.admin p.field__hint {
  text-align: left;
  hyphens: manual;
}

/* Narrow columns cannot justify without rivers; fall back below 34rem. */
@media (max-width: 34rem) {
  .prose, .prose p, .prose li, .lede, .card__text, .section__intro {
    text-align: left;
  }
}

/* ------------------------------------------------------------ typography */

h1, h2, h3, h4, h5, h6 {
  color: var(--color-heading);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
h5 { font-size: var(--text-lg); }
h6 { font-size: var(--text-base); letter-spacing: var(--tracking-wide); text-transform: uppercase; }

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

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

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--azure-700);
}
.eyebrow::before {
  content: "";
  width: var(--space-8);
  height: 2px;
  background: var(--color-rule-accent);
}

.lede {
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
}

/* ---------------------------------------------------------------- layout */

.container {
  width: min(100% - (var(--gutter) * 2), var(--container-max));
  margin-inline: auto;
}
.container--wide { width: min(100% - (var(--gutter) * 2), var(--container-wide)); }
.container--text { width: min(100% - (var(--gutter) * 2), var(--container-text)); }

.section { padding-block: var(--section-y); }
.section--tight { padding-block: calc(var(--section-y) * 0.6); }
.section--sunken { background: var(--color-bg-sunken); }
.section--raised { background: var(--color-bg-raised); }
.section--accent {
  background: linear-gradient(160deg, var(--brand-600), var(--brand-800));
  color: var(--color-text-inverse);
}
.section--accent h1, .section--accent h2, .section--accent h3 { color: var(--color-text-inverse); }
.section--accent .eyebrow { color: var(--gold-300); }
.section--accent .lede { color: var(--brand-100); }

.section__head { margin-bottom: var(--space-10); max-width: 62ch; }
.section__head > * + * { margin-top: var(--space-4); }
.section__head--center { margin-inline: auto; text-align: center; }
.section__head--center .eyebrow { justify-content: center; }

.stack > * + * { margin-top: var(--space-4); }
.stack-lg > * + * { margin-top: var(--space-8); }

.grid { display: grid; gap: var(--space-6); }
@media (min-width: 40rem) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 40rem) { .grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 40rem) { .grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .grid--4 { grid-template-columns: repeat(4, 1fr); } }

/* ------------------------------------------------------------ skip link */

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-2);
  z-index: var(--z-toast);
  padding: var(--space-3) var(--space-5);
  background: var(--brand-700);
  color: var(--color-text-inverse);
  border-radius: var(--radius-md);
  font-weight: var(--weight-semibold);
  transform: translateY(-150%);
  transition: transform var(--duration-fast) var(--ease-out);
}
.skip-link:focus-visible { transform: translateY(0); color: var(--color-text-inverse); }

/* --------------------------------------------------------------- topbar
   Scroll-reactive: slides away as the visitor reads down, returns the moment
   they scroll back up. Contact details and social links live here.        */

.topbar {
  background: var(--brand-800);
  color: var(--brand-100);
  font-size: var(--text-sm);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.topbar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-6);
  min-height: var(--topbar-height);
  padding-block: var(--space-1);
}
.topbar__group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5); }
.topbar__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--brand-100);
  text-decoration: none;
  padding-block: var(--space-1);
}
.topbar__link:hover { color: var(--neutral-0); text-decoration: underline; }
.topbar__link svg { width: 1em; height: 1em; flex: none; opacity: 0.8; }

.social { display: flex; align-items: center; gap: var(--space-1); }
.social__link {
  display: grid;
  place-items: center;
  width: var(--space-8);
  height: var(--space-8);
  border-radius: var(--radius-full);
  color: var(--brand-100);
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.social__link:hover, .social__link:focus-visible {
  background: rgba(255, 255, 255, 0.12);
  color: var(--neutral-0);
}
.social__link svg { width: 1.05rem; height: 1.05rem; }

/* --------------------------------------------------------------- header */

.site-head {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  transition: transform var(--duration-base) var(--ease-out);
}
/* Applied by JS when scrolling down past the topbar. */
.site-head.is-condensed { transform: translateY(calc(var(--topbar-height) * -1 - 1px)); }

.header {
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--color-border);
  transition: box-shadow var(--duration-base) var(--ease-out),
              background var(--duration-base) var(--ease-out);
}
.site-head.is-scrolled .header { box-shadow: var(--shadow-sm); background: rgba(255, 255, 255, 0.97); }

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  min-height: var(--header-height);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  flex: none;
}
/* Logo only. The name and tagline that sat beside the mark were removed on
   2026-09-09 — the artwork already carries the name — and their rules went
   with them rather than being left behind as dead selectors. `gap` above is
   now inert with a single child, and is kept so a second brand element can be
   added back without rediscovering the spacing. */
/* 56px, up from 46px on 2026-09-09 — with the name and tagline gone the mark
   was carrying the header on its own and looked undersized. It stays below
   the 78px `--header-height`, so the row does not grow and the sticky/condense
   maths and `scroll-padding-top` are unaffected. It is also still under the
   artwork's native 106px, so this is a downscale: no softening, unlike the
   footer copy which is now past 1:1. */
.brand img { height: 56px; width: auto; }

/* ------------------------------------------------------------------ nav */

/* The nav appears only once it genuinely fits.
   It used to switch on at 62rem (992px), but the Greek labels are long —
   "Έργα Κατάρτισης - Συμβουλευτικής" alone is 30 characters — and the six of
   them need 870px. With the logo (79) and the language switcher (85) plus two
   24px gaps that is 1082px of content, against a container of only 940px at
   992px wide. The header overflowed and the whole page scrolled sideways
   between roughly 992px and 1150px.

   75rem (1200px) leaves ~49px of slack after the fluid gutter. Below it the
   hamburger is used, which is the honest behaviour: a menu that works beats a
   nav bar that pushes the document off-screen. If a nav item is ever added or
   renamed, re-measure — this breakpoint is sized to the content, not chosen
   for tidiness. */
.nav { display: none; }
@media (min-width: 75rem) {
  .nav { display: flex; align-items: center; gap: var(--space-1); }
}
.nav__link {
  position: relative;
  display: inline-block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--neutral-700);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  white-space: nowrap;
}
.nav__link::after {
  content: "";
  position: absolute;
  left: var(--space-3);
  right: var(--space-3);
  bottom: 4px;
  height: 2px;
  background: var(--color-rule-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out);
}
.nav__link:hover, .nav__link:focus-visible { color: var(--brand-700); }
.nav__link:hover::after, .nav__link[aria-current="page"]::after { transform: scaleX(1); }
.nav__link[aria-current="page"] { color: var(--brand-700); font-weight: var(--weight-semibold); }

.header__actions { display: flex; align-items: center; gap: var(--space-2); }

.lang {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.lang__item {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
  text-decoration: none;
  min-height: var(--tap-target-min);
  display: inline-flex;
  align-items: center;
}
.lang__item[aria-current="true"] { background: var(--brand-600); color: var(--color-text-inverse); }

/* Burger — visible below the nav breakpoint. */
.burger {
  display: inline-grid;
  place-items: center;
  width: var(--tap-target-min);
  height: var(--tap-target-min);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: transparent;
  cursor: pointer;
}
/* Must match the .nav breakpoint exactly. If these drift apart there is a
   band with no navigation at all — nav hidden, burger hidden. */
@media (min-width: 75rem) { .burger { display: none; } }
.burger span { display: block; width: 20px; height: 2px; background: var(--neutral-700); position: relative; }
.burger span::before, .burger span::after {
  content: ""; position: absolute; left: 0; width: 20px; height: 2px; background: inherit;
  transition: transform var(--duration-base) var(--ease-out), top var(--duration-base) var(--ease-out);
}
.burger span::before { top: -6px; }
.burger span::after { top: 6px; }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); background: var(--neutral-700); }
.burger[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); background: var(--neutral-700); }

.mobile-nav {
  display: block;
  background: var(--color-bg-raised);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.mobile-nav[hidden] { display: none !important; }
@media (min-width: 75rem) { .mobile-nav { display: none !important; } }
.mobile-nav__list { padding: var(--space-3) 0 var(--space-5); }
.mobile-nav__link {
  display: block;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
  color: var(--neutral-800);
  font-weight: var(--weight-medium);
  text-decoration: none;
  min-height: var(--tap-target-min);
}
.mobile-nav__link[aria-current="page"] { color: var(--brand-700); font-weight: var(--weight-semibold); }

/* -------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target-min);
  padding: var(--space-3) var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary { background: var(--brand-600); color: var(--color-text-inverse); }
.btn--primary:hover { background: var(--brand-700); color: var(--color-text-inverse); }

.btn--secondary {
  background: transparent;
  color: var(--brand-700);
  border-color: var(--brand-300);
}
.btn--secondary:hover { background: var(--brand-50); border-color: var(--brand-500); color: var(--brand-700); }

/* --------------------------------------------------- buttons on dark ground
   `.btn--secondary` is styled for a light page. Dropped onto a dark one it
   used to be patched with an inline `style="color:…"`, and that quietly broke
   the hover: an inline declaration outranks a `:hover` class rule, so the
   hover's `background` applied while its `color` did not — light text landed
   on a near-white fill at 1.16:1, which is invisible.

   Fixed by context rather than per button, so it also covers the next one
   somebody drops into a dark section. Anything that sets its colours inline
   will break this again — use the class, not a style attribute. */

.page-head .btn--secondary,
.section--accent .btn--secondary,
.footer .btn--secondary,
.btn--on-dark {
  background: transparent;
  color: var(--brand-100);
  border-color: rgba(255, 255, 255, 0.42);
}
.page-head .btn--secondary:hover,
.page-head .btn--secondary:focus-visible,
.section--accent .btn--secondary:hover,
.section--accent .btn--secondary:focus-visible,
.footer .btn--secondary:hover,
.footer .btn--secondary:focus-visible,
.btn--on-dark:hover,
.btn--on-dark:focus-visible {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.85);
  color: var(--neutral-0);
}

.btn--ghost { background: transparent; color: var(--azure-700); padding-inline: var(--space-2); }
.btn--ghost:hover { color: var(--brand-700); }

.btn--on-accent { background: var(--neutral-0); color: var(--brand-700); }
.btn--on-accent:hover { background: var(--gold-100); color: var(--brand-800); }

.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }

/* A button's own label wraps inside a text row: project bodies can carry a
   label long enough (the machine-translated "(in Greek)" suffix included)
   to overflow a phone-width screen under the .btn default below. Header,
   footer and card buttons are untouched and stay on one line. */
.actions .btn { white-space: normal; }

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

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: transform var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out);
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--brand-200); }

.card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--brand-50);
  overflow: hidden;
}
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--duration-slow) var(--ease-out); }
.card:hover .card__media img { transform: scale(1.04); }
.card__media--empty { display: grid; place-items: center; background: linear-gradient(140deg, var(--brand-50), var(--azure-100)); }
.card__media--empty svg { width: 40%; max-width: 96px; opacity: 0.35; }

.card__body { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-6); flex: 1; }
.card__title { font-size: var(--text-lg); color: var(--brand-700); line-height: var(--leading-snug); }
.card__title a { color: inherit; text-decoration: none; }
.card__title a::after { content: ""; position: absolute; inset: 0; }
.card__text { font-size: var(--text-sm); color: var(--color-text-muted); }
.card__meta {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-xs); color: var(--color-text-muted);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.card__foot { margin-top: auto; padding-top: var(--space-2); }
.card { position: relative; }

/* ------------------------------------------------------------ sub-projects */

.subprojects { margin-top: var(--space-16); }
.subprojects__title { font-size: var(--text-2xl); margin-bottom: var(--space-8); }

/* Sub-project thumbnails are often logos: show them whole on white rather
   than cropped to the card's 16:10 frame. The empty placeholder keeps its
   gradient. */
.card--subproject .card__media:not(.card__media--empty) { background: var(--neutral-0); }
.card--subproject .card__media img { object-fit: contain; padding: var(--space-4); }

/* Two lines, agreed with the 140-character excerpt in
   templates/partials/subproject-card.php. Change both together. */
.card__text--clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* A sub-project's thumbnail at its natural size, never wider than the text. */
.subproject-figure { margin-bottom: var(--space-10); max-width: var(--container-text); }
.subproject-figure img { width: auto; max-width: 100%; height: auto; border-radius: var(--radius-lg); }

.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--gold-100);
  color: var(--gold-900);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.badge--active { background: var(--success-50); color: var(--success-500); }
/* On the dark page head, for a project's inactive state. */
.badge--on-dark { background: rgba(255, 255, 255, 0.14); color: var(--neutral-0); }
.page-head__status { margin-bottom: var(--space-4); }

/* ---------------------------------------------------------------- stats */

.stat { text-align: center; }
.stat__value {
  font-size: var(--text-4xl);
  font-weight: var(--weight-bold);
  color: var(--gold-400);
  line-height: 1;
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: tabular-nums;
}
.stat__label {
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  color: var(--brand-100);
  letter-spacing: var(--tracking-wide);
}

/* ---------------------------------------------------------- feature trio */

/* Left-aligned throughout. The icon used to be centred while the heading and
   body copy under it were not — headings are left-aligned globally and
   `.feature p` is justified — so the icon was the only centred thing in the
   block and read as a misalignment rather than a choice. */
.feature { text-align: left; padding: var(--space-8) var(--space-6); }
.feature__icon {
  width: 84px; height: 84px; margin: 0 0 var(--space-5);
  display: grid; place-items: center;
  border-radius: var(--radius-full);
  background: var(--brand-50);
  border: 1px solid var(--brand-100);
}
.feature__icon img { width: 48px; height: 48px; object-fit: contain; }
.feature h2, .feature h3 { font-size: var(--text-lg); margin-bottom: var(--space-3); }
.feature p { font-size: var(--text-sm); color: var(--color-text-muted); text-align: justify; hyphens: auto; }

/* ---------------------------------------------------------------- prose */

.prose { max-width: var(--container-text); }
.prose > * + * { margin-top: var(--space-5); }
.prose h2 { font-size: var(--text-2xl); margin-top: var(--space-12); }
.prose h3 { font-size: var(--text-xl); margin-top: var(--space-10); }
.prose h4 { font-size: var(--text-lg); margin-top: var(--space-8); }
.prose ul, .prose ol { padding-left: var(--space-6); }
.prose li + li { margin-top: var(--space-2); }
.prose img { border-radius: var(--radius-md); }
.prose figure { margin-block: var(--space-8); }
.prose figcaption {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  border-left: 2px solid var(--color-rule-accent);
  padding-left: var(--space-3);
}
.prose blockquote {
  margin-block: var(--space-8);
  padding: var(--space-5) var(--space-6);
  border-left: 3px solid var(--color-rule-accent);
  background: var(--gold-50);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-lg);
}
.prose table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.prose th, .prose td { padding: var(--space-3); border-bottom: 1px solid var(--color-border); text-align: left; }
.prose th { background: var(--brand-50); font-weight: var(--weight-semibold); color: var(--brand-700); }
.table-scroll { overflow-x: auto; }
.prose iframe { width: 100%; aspect-ratio: 16 / 9; height: auto; border: 0; border-radius: var(--radius-md); }

/* --------------------------------------------------------- page heading */

.page-head {
  padding-block: calc(var(--section-y) * 0.75) var(--section-y);
  background: linear-gradient(155deg, var(--brand-700), var(--brand-900) 70%);
  color: var(--color-text-inverse);
  position: relative;
  overflow: hidden;
}
.page-head::after {
  content: "";
  position: absolute;
  right: -8%;
  top: -40%;
  width: 42rem; height: 42rem;
  background: radial-gradient(circle, rgba(178,152,104,0.22), transparent 62%);
  pointer-events: none;
}
.page-head h1 { color: var(--color-text-inverse); max-width: 22ch; }
.page-head .lede { color: var(--brand-100); max-width: 60ch; margin-top: var(--space-5); }
.page-head__inner { position: relative; z-index: 1; }

.breadcrumb { margin-bottom: var(--space-5); font-size: var(--text-sm); }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; padding: 0; margin: 0; }
.breadcrumb li { display: flex; align-items: center; gap: var(--space-2); color: var(--brand-200); }
.breadcrumb li + li::before { content: "/"; opacity: 0.5; }
.breadcrumb a { color: var(--brand-100); text-decoration: none; }
.breadcrumb a:hover { color: var(--neutral-0); text-decoration: underline; }
.breadcrumb [aria-current="page"] { color: var(--gold-300); }

/* ----------------------------------------------------------- pagination */

.pagination { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; margin-top: var(--space-12); }
.pagination a, .pagination span {
  min-width: var(--tap-target-min);
  min-height: var(--tap-target-min);
  display: inline-flex; align-items: center; justify-content: center;
  padding-inline: var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  text-decoration: none;
  color: var(--neutral-700);
}
.pagination a:hover { border-color: var(--brand-500); color: var(--brand-700); background: var(--brand-50); }
.pagination [aria-current="page"] { background: var(--brand-600); border-color: var(--brand-600); color: var(--color-text-inverse); font-weight: var(--weight-semibold); }
.pagination .is-disabled { opacity: 0.4; pointer-events: none; }

/* ---------------------------------------------------------- filter tabs
   The projects index's Active / Inactive switch. Plain links, one URL per
   state; the selected one carries aria-current.                          */

.filter-tabs {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  padding: var(--space-1);
  margin-bottom: var(--space-10);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-sunken);
}
.filter-tabs__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-target-min);
  padding-inline: var(--space-5);
  border-radius: var(--radius-full);
  color: var(--neutral-700);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.filter-tabs__link:hover { background: var(--neutral-0); color: var(--brand-700); }
/* After :hover, so the selected tab keeps its fill under the pointer. */
.filter-tabs__link[aria-current] { background: var(--brand-600); color: var(--color-text-inverse); }
/* The global focus ring squares the corners off; keep the pill. */
.filter-tabs__link:focus-visible { border-radius: var(--radius-full); }
.filter-tabs__count {
  min-width: var(--space-6);
  padding-inline: var(--space-2);
  border-radius: var(--radius-full);
  background: var(--neutral-200);
  color: var(--neutral-800);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.filter-tabs__link[aria-current] .filter-tabs__count {
  background: rgba(255, 255, 255, 0.2);
  color: var(--neutral-0);
}

/* --------------------------------------------------------------- footer */

.footer {
  background: var(--brand-900);
  color: var(--brand-200);
  padding-block: var(--section-y) var(--space-8);
  font-size: var(--text-sm);
}
.footer h2, .footer h3 { color: var(--neutral-0); font-size: var(--text-base); letter-spacing: var(--tracking-wide); text-transform: uppercase; margin-bottom: var(--space-5); }
.footer a { color: var(--brand-100); text-decoration: none; }
.footer a:hover { color: var(--neutral-0); text-decoration: underline; }
.footer__grid { display: grid; gap: var(--space-10); }
@media (min-width: 48rem) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
/* Doubled from 54px on 2026-09-09 at the client's request. The source file is
   only 150x106 (see docs/HANDOVER.md item 5 — there is no larger copy of this
   logo anywhere, including on the live site), so at 108px tall it is being
   upscaled and will look soft, more so on a retina screen. A vector or a
   600px-wide PNG is the real fix. */
.footer__brand img { height: 108px; width: auto; margin-bottom: var(--space-4); background: var(--neutral-0); padding: var(--space-3); border-radius: var(--radius-md); }
.footer__list li + li { margin-top: var(--space-3); }
.footer__meta {
  margin-top: var(--space-12);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex; flex-wrap: wrap; gap: var(--space-4); justify-content: space-between;
  color: var(--brand-300);
  font-size: var(--text-xs);
}
.footer .social__link { color: var(--brand-100); }

/* ----------------------------------------------------------------- misc */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

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

.empty-state { padding: var(--space-16) var(--space-6); text-align: center; color: var(--color-text-muted); }

/* ------------------------------------------------------- GSAP entrances
   Elements start hidden only when JS is active and motion is allowed, so a
   failed script or a reduced-motion preference can never leave the page
   blank. `html.js` is set by an inline snippet in the head.               */

@media (prefers-reduced-motion: no-preference) {
  html.js [data-animate] { opacity: 0; }
}

/* ------------------------------------------------------------ icon sizing
   Inline SVGs have no intrinsic size, so they must be constrained wherever
   they sit beside text or they will stretch and squeeze the label. */

.btn svg, .topbar__link svg, .card__title svg {
  width: 1.15em;
  height: 1.15em;
  flex: none;
}
.btn { white-space: nowrap; }
.card__foot .btn { padding-left: 0; }

/* --------------------------------------------------- contact card targets
   On the contact page the phone/email link is the card's only control and is
   the thing a visitor taps on a phone. A bare inline link renders ~22px tall,
   just under the WCAG 2.2 minimum, so it gets explicit padding to clear it. */

.card__title a[href^="tel:"],
.card__title a[href^="mailto:"] {
  display: inline-block;
  min-height: var(--tap-target-min);
  padding-block: var(--space-2);
  line-height: 1.4;
}

/* ------------------------------------------------------------------ team
   The staff list on the contact page. A member whose photo is missing (one
   of the source images no longer exists on the old server) simply renders
   without one rather than leaving a broken frame. */

.team { display: grid; gap: var(--space-6); margin-top: var(--space-8); padding: 0; list-style: none; }
@media (min-width: 40rem) { .team { grid-template-columns: repeat(2, 1fr); } }

.team__member {
  display: flex;
  gap: var(--space-5);
  align-items: flex-start;
  padding: var(--space-5);
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}
.team__photo {
  width: 88px; height: 88px; flex: none;
  object-fit: cover;
  border-radius: var(--radius-full);
  border: 2px solid var(--gold-200);
}
.team__body { min-width: 0; }
.team__name { color: var(--brand-700); font-size: var(--text-base); }
.team__role {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-align: left;
  hyphens: manual;
}
.team__email { margin-top: var(--space-2); font-size: var(--text-sm); word-break: break-word; }
.prose .team li + li { margin-top: 0; }

/* -------------------------------------------------- narrow-column justify
   Justified text is the house style, but it only reads as deliberate when
   the column is wide enough to absorb the extra word spacing. A 300px card
   on a 1440px screen opens rivers, and a viewport media query cannot see
   that — the viewport is wide, the column is not.

   So card-like components declare themselves as containers and the fallback
   is driven by the column's own inline size. Any component that opts in by
   adding `container-type: inline-size` gets the behaviour for free, which is
   what makes this scale as the design system grows.

   Placed last so it wins ties against the component rules above; the
   `.prose` prefixes exist because `.prose p` (0,1,1) would otherwise
   outrank a bare class selector on the same element. */

.card,
.feature,
.team__member {
  container-type: inline-size;
}

/* The narrow-column fallback now covers only the components whose text is
   genuinely too short to justify — a two-word role, a card meta line. Card and
   feature body copy stays justified even in a narrow column, which is what the
   client asked for on 2026-09-09; it does open the occasional wide word space
   at ~300px, and that is the accepted trade. */
@container (max-width: 34rem) {
  .team__role,
  .prose .team__role,
  .card__meta,
  .tool__text {
    text-align: left;
    hyphens: manual;
  }
}

/* A phone is a narrow column even where nothing declared a container. */
@media (max-width: 34rem) {
  .prose, .prose p, .prose li, .lede, .card__text, .section__intro {
    text-align: left;
  }
}

/* The staff cards sit two-up inside the prose measure, which leaves the text
   column too narrow for a full address on one line. Trimming the avatar and
   the padding buys back the ~30px that keeps emails unbroken. */
.team__photo { width: 72px; height: 72px; }
.team__member { padding: var(--space-4); gap: var(--space-4); }

/* ------------------------------------------------------- self-help tools
   The Εργαλεία Αυτοβοήθειας index. A list rather than a card grid: the
   entries are titles of varying length with no imagery, and a grid of
   text-only cards would leave ragged whitespace where the pictures aren't.
   The whole row is the target, which clears the WCAG 2.2 minimum easily. */

.tool-list {
  list-style: none;
  margin: var(--space-10) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
@media (min-width: 56rem) {
  .tool-list { grid-template-columns: repeat(2, 1fr); }
}

.tool__link {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  height: 100%;
  padding: var(--space-5);
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}
.tool__link:hover,
.tool__link:focus-visible {
  border-color: var(--brand-300);
  box-shadow: var(--shadow-sm);
  transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) {
  .tool__link { transition: none; }
  .tool__link:hover, .tool__link:focus-visible { transform: none; }
}

.tool__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: var(--radius-full);
  background: var(--brand-50);
  border: 1px solid var(--brand-100);
  color: var(--brand-700);
}
.tool__icon svg { width: 22px; height: 22px; }

.tool__body { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }

.tool__title {
  font-weight: var(--weight-semibold);
  color: var(--brand-700);
  line-height: var(--leading-tight);
  text-wrap: balance;
}
.tool__text {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-align: left;
}

.tool__arrow {
  flex: none;
  margin-left: auto;
  color: var(--gold-700);
  display: grid;
  place-items: center;
}
.tool__arrow svg { width: 20px; height: 20px; }

/* ------------------------------------------------- page hero with an image
   Opt-in per page via `pages.cover_media_id`. The photograph sits under a
   navy scrim heavy enough that white heading text clears WCAG AA regardless
   of what the image is doing beneath it — heroes get swapped for atmosphere
   and nobody re-measures contrast afterwards, so the guarantee cannot be
   allowed to depend on the picture. */

.page-head--image { background: var(--brand-900); }

/* A hero whose photograph should actually be seen. Instead of lifting the
   scrim everywhere — which bottoms out at 0.70 before white text drops under
   AA — the scrim is made directional: opaque across the left half where the
   heading sits, clearing across the right half where there is nothing but
   picture. The text keeps its contrast and the image is properly visible,
   which a uniform overlay cannot give you at the same time.

   The stops are tied to the text column, so if the heading ever runs wider
   than ~55% the hold percentage has to move with it. */
.page-head--image.page-head--photo::after {
  background: linear-gradient(
    100deg,
    rgba(8, 38, 92, 0.94) 0%,
    rgba(9, 44, 104, 0.90) 34%,
    rgba(10, 48, 112, 0.62) 62%,
    rgba(10, 40, 92, 0.34) 100%
  );
}

.page-head__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Each hero crops to a different part of its photo, so the focal point is a
     variable rather than a fixed value: the tools photo wants the upper third
     (the projected slide), the home photo the lower half (the audience — the
     top of that frame is an empty wall). */
  object-position: center var(--page-head-focus, 30%);
  z-index: 0;
}

/* The scrim. This replaces the gold glow that ::after draws on the plain
   band — over a photograph it reads as a smudge rather than a highlight. */
.page-head--image::after {
  /* `inset` already resets the offsets the plain band sets for its gold glow.
     Do NOT add `right: auto` / `top: auto` after this line — they override
     `inset` and collapse the scrim to nothing, which silently drops the
     heading onto the bare photograph. */
  inset: 0;
  width: auto;
  height: auto;
  /* Scrim strength is per page, because it depends on the photograph. The
     default is heavy: it suits a busy picture (the tools hero sits over a
     first-aid slide covered in its own text and icons, which competes with the
     heading if you let too much through). A calm photograph can opt into a
     lighter one by setting the two variables — the home hero does.

     Measured worst case, a pure-white pixel under the lightest end:
       0.88 -> 8.24:1     0.74 -> 5.47:1     0.70 -> 4.87:1
     Do not go past 0.70; 0.66 is 4.35:1 and fails AA. */
  background: linear-gradient(
    var(--page-head-scrim-angle, 155deg),
    rgba(11, 53, 126, var(--page-head-scrim-start, 0.88)) var(--page-head-scrim-hold, 0%),
    rgba(6, 30, 74, var(--page-head-scrim-end, 0.94)) 70%
  );
  z-index: 0;
}

/* A touch more height so the photograph has room to be a photograph. */
@media (min-width: 48rem) {
  .page-head--image { padding-block: calc(var(--section-y) * 1.1) calc(var(--section-y) * 1.2); }
}

/* The address card on the contact page carries a fact rather than a control,
   so it drops the link colouring the other card titles inherit. */
.card__title--plain {
  color: var(--color-heading);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
}

/* The "Opening hours:" lead-in in the footer. Dimmer than the value beside it
   so the hours themselves are what the eye lands on. */
.footer__label { color: var(--brand-300); }

/* ------------------------------------------------------------ team section
   Lifted out of the prose measure by View::splitOut() so the staff cards get
   the full body width instead of a 68ch column, with their heading as part of
   the same block. Two columns from 48rem — the cards hold a portrait and three
   short lines, and a third column would squeeze the roles into slivers. */

.team-section { margin-top: var(--space-16); }
.team-section > :first-child { margin-bottom: var(--space-8); }
.team-section .team { margin-top: 0; }
@media (min-width: 48rem) {
  .team-section .team { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================== about page
   A long institutional page — six sections, ~10,000 characters. Poured into a
   single 68ch column it had no hierarchy: every heading weighed the same and
   there was no sense of position on a 6,000px page.

   The fix is structural, not decorative. Headings move into a left rail so
   they form a spine down the page; the prose keeps its own measure beside
   them; and the grounds alternate so each section reads as a section. No new
   colours or typefaces — this page uses the same system as the rest of the
   site, which is the point. */

.about-band { padding-block: clamp(var(--space-12), 7vw, var(--space-24)); }
.about-band--sunken { background: var(--color-bg-sunken); }

.about-band__inner { display: grid; gap: var(--space-8); }

@media (min-width: 62rem) {
  .about-band__inner {
    grid-template-columns: minmax(0, 19rem) minmax(0, 1fr);
    gap: clamp(var(--space-10), 5vw, var(--space-20));
    align-items: start;
  }
  /* The heading tracks the reader down its own section. Offset clears the
     sticky site header; it releases at the section end because the rail is a
     grid item, not a fixed element. */
  .about-band__rail {
    position: sticky;
    top: calc(var(--header-height) + var(--space-8));
  }
  /* A card grid has no use for a rail — the heading sits above it instead. */
  .about-band--wide .about-band__inner { grid-template-columns: minmax(0, 1fr); }
  .about-band--wide .about-band__rail { position: static; }
}

.about-band__title {
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  color: var(--brand-700);
  text-wrap: balance;
}
/* The gold rule is the same device the eyebrow uses elsewhere on the site, so
   the rail reads as part of the existing language rather than a new one. */
.about-band__title::before {
  content: "";
  display: block;
  width: var(--space-10);
  height: 3px;
  margin-bottom: var(--space-4);
  background: var(--color-rule-accent);
  border-radius: var(--radius-full);
}

.about-band__body .prose { max-width: 64ch; }
.about-band__body .prose > :first-child { margin-top: 0; }
/* Inside a band the section heading already provides the level, so the body's
   own subheadings step down rather than competing with it. */
.about-band__body .prose h2,
.about-band__body .prose h3 {
  font-size: var(--text-lg);
  color: var(--brand-700);
  margin-top: var(--space-10);
}

/* Long lists of short items read as a wall in one column. */
@media (min-width: 62rem) {
  .about-band__body .prose ul { columns: 2; column-gap: var(--space-10); }
  .about-band__body .prose ul li { break-inside: avoid; margin-top: 0; margin-bottom: var(--space-2); }
}

.about-band__body .prose figure { margin-block: var(--space-8); }
.about-band__body .prose figure img { border-radius: var(--radius-md); }

/* ------------------------------------------------------- programme cards
   Three EU programme families, each a logo, a name and a link. As a vertical
   run they read as three unrelated asides; as a row they read as a set, which
   is what they are. */

.programme-grid { display: grid; gap: var(--space-6); }
@media (min-width: 48rem) { .programme-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .programme-grid { grid-template-columns: repeat(3, 1fr); } }

.programme {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-8);
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}
.programme figure { margin: 0; }
.programme img {
  height: 76px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  object-position: left center;
}
.programme h2, .programme h3 {
  font-size: var(--text-base);
  color: var(--brand-700);
  line-height: var(--leading-snug);
  margin: 0;
}
.programme p { margin: 0; text-align: left; }
/* The link is the card's action; it sits at the foot whatever the name length. */
.programme p:last-child { margin-top: auto; padding-top: var(--space-2); }
