/* -------------------------------------------------------------
   NetSec — modern glassmorphism, Apple-inspired
   ------------------------------------------------------------- */

/* ── Self-hosted variable fonts ────────────────────────────────
   Inter (400–800) and Lexend (400–700), latin + latin-ext subsets
   only. Sourced from Google Fonts (SIL Open Font License) and
   committed at `assets/fonts/`. Removes the render-blocking
   `<link rel="stylesheet" href="fonts.googleapis.com/css2?…">`
   tag from every HTML page — Lighthouse Performance previously
   sat at 67–75 because that link blocked first paint while the
   third-party CSS resolved. With the files local the browser can
   start rendering immediately and only fetches the latin-ext
   subset on demand via the unicode-range filter.

   `font-display: swap` keeps text visible during the brief window
   between system-font render and webfont swap. Resolves #121. */
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:400 800;
  font-display:swap;
  src:url('../fonts/inter-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:'Inter';
  font-style:normal;
  font-weight:400 800;
  font-display:swap;
  src:url('../fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Lexend';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('../fonts/lexend-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:'Lexend';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('../fonts/lexend-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root{
  --bg-0:#f6f8fc;
  --bg-1:#eef2fb;
  --ink:#0b1220;
  --ink-2:#2b3850;
  --muted:#5a6679;
  --line:rgba(11,18,32,.08);
  --glass-bg:rgba(255,255,255,.55);
  --glass-bg-strong:rgba(255,255,255,.72);
  --glass-border:rgba(255,255,255,.6);
  --glass-shadow:0 10px 40px rgba(20,35,80,.10), 0 1px 2px rgba(20,35,80,.06);
  --accent:#003399;          /* EU/COST blue */
  --accent-2:#0a84ff;        /* Apple blue */
  --accent-glow:rgba(10,132,255,.35);
  --gold:#ffcc00;            /* EU stars */
  --radius:22px;
  --radius-sm:14px;
  --maxw:1180px;
  --ease:cubic-bezier(.22,.61,.36,1);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth;color-scheme:light dark;scroll-padding-top:90px}

/* Skip-to-content link — visible only when keyboard-focused */
.skip-link{
  position:absolute;left:50%;top:-60px;transform:translateX(-50%);
  background:var(--ink);color:#fff;padding:10px 18px;border-radius:10px;
  font-weight:600;font-size:.9rem;z-index:1000;
  transition:top .25s var(--ease);
}
.skip-link:focus{top:14px;outline:0;box-shadow:0 0 0 4px rgba(10,132,255,.45);opacity:1}

/* Global focus-visible — keyboard-only, never on mouse-click */
:focus{outline:0}
:focus-visible{
  outline:0;
  box-shadow:0 0 0 3px rgba(10,132,255,.45);
  border-radius:8px;
}

/* ──────────────────────────────────────────────────────────────
   External-link indicator. Any anchor that opens in a new tab
   AND points at an absolute URL (http(s):// or //protocol-
   relative) automatically gains a small "external link" icon
   after its text content, so visitors can tell at a glance that
   clicking will take them off the NetSec site.

   Implementation: a CSS-mask pseudo-element that inherits the
   text colour via `background-color: currentColor`, so the icon
   tints with whatever the link is using — works in both light
   and dark themes, on buttons, in body text, on tinted cards.

   The icon is the same Lucide "external-link" mark used in
   sitemap's Off-site card (URL-encoded inline so no external
   asset needed).

   Exclusions below cover contexts where the icon would be noise
   rather than signal: contact icons (already brand-recognisable),
   social icons, the brand logo, the language switcher, in-toolbar
   single-glyph buttons, and the welcome-strip body text.
   .grant-cta is excluded because it carries its own inline
   external-link SVG that participates in the hover translate
   animation.

   ❗ Content-authoring rule: do NOT type a trailing arrow
   (→ / ↗ / » / >>) in the link text. The auto-icon below already
   signals "this opens externally"; an arrow on top renders a
   double affordance. The lint at scripts/check-external-link-
   arrows.py (CI workflow external-link-arrows.yml) fails any PR
   that introduces one. */
/* Specificity note: the global selector is wrapped in :where() so it
   contributes 0 to specificity (only the ::after pseudo-element does).
   That way every per-context override below — .grant-cta::after,
   .cost-mark::after, .socials a::after, etc. — wins naturally without
   needing !important. Without :where(), the multi-attribute selector
   was (0,0,2,2), beating every exclusion in the list. */
:where(a[target="_blank"][href^="http"])::after,
:where(a[target="_blank"][href^="//"])::after{
  content:"";
  display:inline-block;
  /* In flex containers (e.g. .resource-card) the pseudo-element
     becomes a flex item and would otherwise shrink to 0; pin it. */
  flex:none;
  width:0.85em;height:0.85em;
  margin:0 0.05em 0 0.3em;
  vertical-align:-0.08em;
  background-color:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3h7v7'/%3E%3Cpath d='M10 14L21 3'/%3E%3Cpath d='M21 14v7H3V3h7'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3h7v7'/%3E%3Cpath d='M10 14L21 3'/%3E%3Cpath d='M21 14v7H3V3h7'/%3E%3C/svg%3E") center/contain no-repeat;
  opacity:.75;
}
/* Contexts where the icon would be noise rather than signal. */
.member-contact a::after,
.socials a::after,
.brand::after,
.cost-mark::after,
.eu-mark::after,
.lang-switch a::after,
.tour-trigger::after,
.grant-cta::after,
.welcome-strip-tips a::after{ content:none }
.btn:focus-visible,.nav-cta:focus-visible,.ca-badge:focus-visible,
.cost-mark:focus-visible,.event-link:focus-visible{
  box-shadow:0 0 0 3px rgba(10,132,255,.55);
}
.glass:focus-visible{box-shadow:0 0 0 3px rgba(10,132,255,.45),var(--glass-shadow)}
body{
  margin:0;
  font-family:'Inter','SF Pro Text','-apple-system','BlinkMacSystemFont',sans-serif;
  color:var(--ink);
  background:var(--bg-0);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  line-height:1.55;
  overflow-x:hidden;
}
h1,h2,h3,h4{font-family:'Lexend','Inter',sans-serif;font-weight:600;letter-spacing:-.02em;line-height:1.15;color:var(--ink)}
h1{font-size:clamp(2.4rem,5.2vw,4.4rem);font-weight:700;letter-spacing:-.035em}
h2{font-size:clamp(1.8rem,3.2vw,2.6rem);margin:0 0 .8rem}
h3{font-size:1.25rem;margin:0 0 .5rem}
p{margin:0 0 1rem;color:var(--ink-2)}
a{color:var(--accent-2);text-decoration:none;transition:opacity .25s var(--ease)}
a:hover{opacity:.7}
img{max-width:100%;display:block}
.container{max-width:var(--maxw);margin:0 auto;padding:0 24px}
.eyebrow{
  display:inline-block;
  font-size:.78rem;
  font-weight:600;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--accent);
  margin-bottom:.9rem;
  padding:.35rem .75rem;
  background:rgba(0,51,153,.08);
  border-radius:999px;
}

/* -------- Background ambience -------- */
.ambience{
  position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none;
  background:linear-gradient(180deg,#eef3fc 0%,#f6f8fc 40%,#fcfaf5 100%);
}
.blob{
  position:absolute;border-radius:50%;filter:blur(80px);opacity:.55;
  animation:drift 22s var(--ease) infinite alternate;
}
.blob.b1{width:520px;height:520px;background:#9bb8ff;top:-160px;left:-120px}
.blob.b2{width:460px;height:460px;background:#ffd8a8;top:30%;right:-140px;animation-duration:28s}
.blob.b3{width:380px;height:380px;background:#c9b6ff;bottom:-160px;left:30%;animation-duration:34s}
@keyframes drift{
  0%{transform:translate(0,0) scale(1)}
  100%{transform:translate(40px,-30px) scale(1.08)}
}

/* -------- Navigation -------- */
.nav{
  position:fixed;top:14px;left:50%;transform:translateX(-50%);
  /* max-width bumped from 1100 → 1200 so the 11-item Grants nav fits
     in FR/DE without the theme-toggle spilling out of the bubble on
     wide-desktop viewports. Page content keeps its 1100 max-width;
     the nav is slightly wider, which reads as "header overhang"
     rather than as misalignment. */
  width:calc(100% - 24px);max-width:1200px;z-index:100;
  background:var(--glass-bg-strong);
  backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  border:1px solid var(--glass-border);
  border-radius:18px;
  box-shadow:var(--glass-shadow);
  transition:box-shadow .3s var(--ease),transform .3s var(--ease);
}
/* Mobile top-scrim + nav reinforcement.
   On a narrow viewport, two things conspire to make the floating
   nav read poorly:
     1. The nav sits at top:14px, so a sliver of page content
        shows above the bubble.
     2. iOS Safari's backdrop-filter is real, but high-contrast
        text (like the bold dates in .details-grid) still ghosts
        through the .72 / .78 glass background.
   We address both at once. A fixed gradient layer fades the top
   of the viewport into the page background so scrolled content
   never lands in the gap above the nav, and the nav itself gets
   a more opaque background on mobile so it reads as a chip rather
   than a translucent overlay. Desktop keeps the lighter glass
   feel where it works. */
@media (max-width: 720px){
  body::before{
    content:'';
    position:fixed;
    inset:0 0 auto 0;
    height:72px;
    z-index:99; /* one below .nav (z:100) */
    pointer-events:none;
    background:linear-gradient(
      to bottom,
      var(--bg-0) 0%,
      var(--bg-0) 40%,
      color-mix(in oklab, var(--bg-0) 60%, transparent) 80%,
      transparent 100%
    );
  }
  .nav{
    background:color-mix(in oklab, var(--bg-0) 88%, transparent);
  }
}
/* Nav layout: brand on the left; everything else (nav-links and
   utility chips like the language switcher and theme toggle) on
   the right. We achieve this without changing the HTML source
   order by:
     - giving `.brand` `margin-right: auto` (pushes it as far left
       as possible),
     - using `order` so `.nav-actions` always renders to the right
       of `.nav-links`, regardless of source order.
   The previous layout used `justify-content: space-between`, which
   put the utility chips in the middle of the nav — counter to the
   convention of "brand left, utilities top-right". */
.nav-inner{display:flex;align-items:center;gap:14px;padding:10px 18px}
.nav-inner .brand{margin-right:auto;order:0}
.nav-inner .nav-links{order:1}
.nav-inner .nav-actions{order:2}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none}
/* Brand logo: three <img>s in the DOM, exactly one visible at a time.
     .brand-logo--light  → coloured lockup, light site theme, desktop
     .brand-logo--dark   → white lockup,    dark site theme,  desktop
     .brand-mark-only    → petal mark only, mobile (<700px), both themes
   The dark variant is keyed off `<html class="dark">` (the site's own
   theme toggle, not the OS `prefers-color-scheme`) so the logo
   follows whatever theme the visitor explicitly picked. The DOM
   carries both images so a theme toggle is purely a CSS-flip with
   no fetch round-trip. Browsers do load both PNGs — they're tiny
   (~35–100 KB) so the bandwidth cost is in the noise.
   We deliberately use distinct white/colour PNGs (not CSS
   `filter: invert()`) because inversion mangles the petal gradient. */
.brand-logo{
  /* Height drives the visual size; width auto-scales to lockup aspect.
     38 CSS px ≈ ~12 mm, comfortably above the 30 mm clearance-aware
     minimum once you count surrounding padding in the header pill. */
  display:none;height:38px;width:auto;
}
.brand-logo--light{display:block}
.dark .brand-logo--light{display:none}
.dark .brand-logo--dark{display:block}
.brand-mark-only{
  display:inline-block;width:32px;height:32px;
}
@media (min-width:700px){
  /* Desktop: show the full lockup, hide the mark-only fallback. */
  .brand-mark-only{display:none}
}
@media (max-width:699.98px){
  /* Mobile: hide both lockups (regardless of theme) and show the
     petal mark instead. Saves header real estate against the
     hamburger + language switcher + theme toggle. The aria-label
     on the parent <a> keeps AT users covered. */
  .brand-logo--light,
  .dark .brand-logo--dark{display:none}
}
/* The original `.brand-mark` rule lives on for any place still
   using the old NS-square pattern (defensive — nothing in repo
   uses it at time of writing). Kept as a graceful fallback. */
.brand-mark{
  width:34px;height:34px;border-radius:10px;
  background:linear-gradient(135deg,var(--accent) 0%,var(--accent-2) 100%);
  display:grid;place-items:center;color:#fff;font-weight:800;font-size:.78rem;letter-spacing:.04em;
  box-shadow:0 6px 16px var(--accent-glow);
}

/* Match the in-overlay snippet style for the on-page highlight
   Pagefind paints when a result link lands here. Pagefind's
   bundled script injects `:where(.pagefind-highlight){background:
   yellow; color: black}` by default — we re-paint with the same
   EU yellow used in the overlay's <mark>, with a soft ring so the
   landed term reads as a deliberate UI element rather than a
   browser default. The selector includes :where() at zero
   specificity from Pagefind's side, so our rule wins. */
.pagefind-highlight{
  background:rgba(255,204,0,.45);
  color:inherit;
  padding:0 2px;border-radius:3px;
  box-shadow:0 0 0 1px rgba(255,204,0,.6);
}
.dark .pagefind-highlight{background:rgba(255,204,0,.32);box-shadow:0 0 0 1px rgba(255,204,0,.45)}
.nav-links{display:flex;gap:4px;align-items:center}
.nav-links a{
  color:var(--ink-2);font-size:.92rem;font-weight:500;padding:8px 12px;border-radius:10px;
  white-space:nowrap;            /* don't let a label split mid-word */
  transition:background .2s var(--ease),color .2s var(--ease);
}
.nav-links a:hover{background:rgba(11,18,32,.05);color:var(--ink);opacity:1}
.nav-cta{
  background:var(--ink);color:#fff !important;padding:9px 16px !important;border-radius:10px;font-weight:600;
}
.nav-cta:hover{background:var(--accent);opacity:1 !important}
.nav-actions{display:flex;align-items:center;gap:2px}
.menu-toggle{display:none;background:none;border:0;padding:8px;cursor:pointer}
.menu-toggle span{display:block;width:22px;height:2px;background:var(--ink);margin:5px 0;border-radius:2px;transition:.3s var(--ease)}

/* Tighter nav typography on FR/DE pages.
   ─────────────────────────────────────────────────────────────
   FR/DE labels are 30–50 % longer than English ("Working Groups"
   → "Groupes de travail" / "Arbeitsgruppen"; "Roadmap" → "Feuille
   de route"). Apply the compact size at ALL desktop widths — the
   nav max-width is 1200 px, the brand+utility cluster needs ~250
   px of fixed width, and an 11-item Grants nav must fit in the
   remaining ~950 px even on a 4K monitor. Earlier versions only
   applied this below 1280 and overflowed on wider screens. */
:lang(fr) .nav-links a,
:lang(de) .nav-links a{
  font-size:.78rem;
  padding:5px 7px;
  letter-spacing:-.01em;
}
:lang(fr) .nav-links,
:lang(de) .nav-links{gap:0}

/* Small-laptop band (980–1100 px) — last stop before the
   hamburger drawer. Drop a non-essential item (Outputs /
   Productions / Ergebnisse) to free the last bit of width.
   The same item is reachable via the footer site map and via
   the home page anchor list. */
@media (max-width:1100px){
  :lang(fr) .nav-links a[href*="outputs"],
  :lang(de) .nav-links a[href*="outputs"]{display:none}
}

/* -------- Hero -------- */
.hero{padding:140px 0 80px;text-align:center;position:relative}
.hero .container{display:flex;flex-direction:column;align-items:center}
.hero h1{margin:0 auto 1.2rem;max-width:14ch;background:linear-gradient(180deg,#0b1220 0%,#3a4a6b 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.hero .lede{max-width:62ch;font-size:clamp(1.05rem,1.4vw,1.2rem);color:var(--ink-2)}
.hero-keywords{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:1.4rem}
.chip{
  font-size:.82rem;font-weight:500;color:var(--ink-2);
  background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--glass-border);border-radius:999px;padding:.4rem .9rem;
}
.hero-cta{display:flex;gap:12px;margin-top:2rem;flex-wrap:wrap;justify-content:center}
.btn{
  display:inline-flex;align-items:center;gap:8px;padding:13px 22px;border-radius:13px;
  font-weight:600;font-size:.95rem;cursor:pointer;border:0;transition:transform .2s var(--ease),box-shadow .2s var(--ease);
}
.btn-primary{background:var(--ink);color:#fff}
.btn-primary:hover{background:var(--accent);opacity:1;transform:translateY(-1px);box-shadow:0 10px 24px var(--accent-glow)}
.btn-ghost{
  background:var(--glass-bg);color:var(--ink);border:1px solid var(--glass-border);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
}
.btn-ghost:hover{opacity:1;transform:translateY(-1px);background:var(--glass-bg-strong)}

/* -------- Sections -------- */
section{padding:80px 0;position:relative}
.section-head{text-align:center;margin-bottom:48px}
.section-head p{max-width:60ch;margin:0 auto;color:var(--muted)}

/* -------- Glass cards --------
   `.glass` is a deliberately cross-cutting utility class (used on
   ~50 cards across the site: MC, country, event, member, founding-
   contributor cards). The :focus-visible variant near the top of
   the file lives with the other focus-visible rules so a11y
   conventions stay clustered; the main .glass + .glass:hover +
   the iOS Safari fallback live here with the component rules.
   The CSS class-collision lint flags this as a cross-cluster
   collision (the two clusters are >200 lines apart) but the
   split is intentional — see CLAUDE.md §3 *Naming convention*. */
/* css-collision-allow: .glass */
.glass{
  background:var(--glass-bg);
  backdrop-filter:saturate(160%) blur(18px);
  -webkit-backdrop-filter:saturate(160%) blur(18px);
  border:1px solid var(--glass-border);
  border-radius:var(--radius);
  box-shadow:var(--glass-shadow);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease),background .35s var(--ease);
}
/* css-collision-allow: .glass */
.glass:hover{transform:translateY(-4px);box-shadow:0 18px 50px rgba(20,35,80,.14);background:var(--glass-bg-strong)}

/* Performance: the Management Committee and Countries grids can render
   45+ cards simultaneously on screen. iOS Safari has been observed to
   give up compositing when there are too many `backdrop-filter` layers
   at once, blanking out the affected elements. For these specific
   card types we skip the live backdrop blur and use a slightly more
   opaque solid translucent background — visually almost identical
   when each card sits on the aurora background, but reliable. */
/* css-collision-allow: .glass */
.mc-card.glass,
.country-card.glass{
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
  background:rgba(255,255,255,.72);
}

/* Belt-and-braces fallback for any browser missing backdrop-filter
   entirely — make all glass surfaces opaque enough to read. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{background:rgba(255,255,255,.85)}
  .glass:hover{background:rgba(255,255,255,.92)}
  .nav,.toast{background:rgba(255,255,255,.92)}
}

/* -------- About -------- */
.about-grid{display:grid;grid-template-columns:1fr 1fr;gap:32px;align-items:center}
.about-card{padding:36px}
.about-card p{font-size:1.02rem}
.objectives{display:grid;gap:14px;margin-top:8px}
.objective{
  display:flex;gap:14px;padding:18px;border-radius:var(--radius-sm);
  background:rgba(255,255,255,.45);border:1px solid var(--glass-border);
}
.objective-num{
  flex-shrink:0;width:34px;height:34px;border-radius:10px;
  background:linear-gradient(135deg,var(--accent),var(--accent-2));color:#fff;
  display:grid;place-items:center;font-weight:700;font-size:.95rem;
}
.objective h4{margin:0 0 4px;font-size:1rem;font-weight:600}
.objective p{margin:0;font-size:.92rem;color:var(--muted)}

/* -------- Working groups -------- */
.wg-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(250px,100%),1fr));gap:22px}
.wg-card{padding:28px}
.wg-icon{
  width:52px;height:52px;border-radius:14px;display:grid;place-items:center;
  background:linear-gradient(135deg,rgba(0,51,153,.10),rgba(10,132,255,.10));
  color:var(--accent);margin-bottom:18px;
}
.wg-card h3{font-size:1.1rem}
.wg-card p{font-size:.93rem;margin:0;color:var(--muted)}
.wg-tag{font-size:.75rem;font-weight:600;letter-spacing:.1em;color:var(--accent);text-transform:uppercase;margin-bottom:8px;display:block}
.wg-leadership{
  margin-top:16px !important;padding-top:14px;border-top:1px solid var(--line);
  font-size:.86rem !important;color:var(--ink-2) !important;line-height:1.7;
}
.wg-leadership span{
  display:inline-block;min-width:62px;font-size:.7rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);
}

/* -------- Management Committee -------- */
.mc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:20px}
.mc-card{padding:24px;text-align:center}
.mc-avatar{
  width:84px;height:84px;border-radius:50%;margin:0 auto 14px;
  background:linear-gradient(135deg,#cfd9ee,#e8d8c2);
  display:grid;place-items:center;color:var(--accent);font-weight:700;font-size:1.4rem;
  border:2px solid rgba(255,255,255,.8);
  overflow:hidden;
}
.mc-avatar img{
  width:100%;height:100%;object-fit:cover;display:block;border-radius:50%;
}
.mc-card h3{font-size:1rem;margin:0 0 4px}
.mc-card .role{font-size:.82rem;color:var(--accent);font-weight:600;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}
.mc-card .org{font-size:.85rem;color:var(--muted);margin:0 0 10px}
.mc-card a.mc-mail{
  display:inline-block;margin-top:6px;font-size:.82rem;color:var(--accent-2);
  word-break:break-all;
}

/* -------- Working-group membership chips --------
   Injected by JS based on a name → WG map sourced from cost.eu. */
.wg-chips{display:inline-flex;flex-wrap:wrap;gap:4px}
.mc-card .wg-chips{
  display:flex;flex-wrap:wrap;justify-content:center;
  margin-top:10px;padding-top:10px;border-top:1px solid var(--line);
}
.wg-chip{
  font-family:'Inter',sans-serif;
  font-size:.66rem;font-weight:700;letter-spacing:.04em;
  padding:3px 7px;border-radius:6px;color:#fff;
  background:linear-gradient(135deg,var(--accent),var(--accent-2));
  box-shadow:0 1px 3px rgba(0,0,0,.12);
  white-space:nowrap;
}
/* Per-WG colour for at-a-glance distinction */
.wg-chip.wg-1{background:linear-gradient(135deg,#0a84ff,#5b8def)}
.wg-chip.wg-2{background:linear-gradient(135deg,#10b981,#34d399)}
.wg-chip.wg-3{background:linear-gradient(135deg,#8b5cf6,#a78bfa)}
.wg-chip.wg-4{background:linear-gradient(135deg,#f59e0b,#fbbf24);color:#3b2a00}

/* Country-grid chips: always stack BELOW the name, indented to match.
   (Earlier attempt with flex + margin-left:auto produced inconsistent
   rendering — chips sometimes inline, sometimes wrapping right-aligned
   on a second line, depending on string widths. Stacking below the
   name keeps every entry visually identical.) */
.country-card .wg-chips{
  display:flex;flex-wrap:wrap;gap:4px;
  margin-top:4px;margin-left:0;
}
.country-card .wg-chip{
  font-size:.6rem;padding:2px 6px;letter-spacing:.04em;
}
/* Flex layout (rather than inline-block + vertical-align) so the
   pseudo-element separator lines never wrap onto a second line on
   narrow screens. Previously a long heading like "Working Group
   Leadership" plus its two 48 px lines + 14 px margins would
   exceed iPhone-class widths and the trailing line would drop. */
.mc-subhead{
  display:flex;align-items:center;justify-content:center;gap:14px;
  font-family:'Lexend','Inter',sans-serif;font-weight:600;font-size:.78rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);text-align:center;
  margin:48px 0 22px;
}
.mc-subhead:first-of-type{margin-top:8px}
.mc-subhead::before,.mc-subhead::after{
  content:'';height:1px;background:var(--line);
  flex:0 0 48px;       /* fixed 48 px each; flex item can't wrap */
}
@media (max-width: 540px){
  .mc-subhead{font-size:.7rem;letter-spacing:.12em;gap:10px}
  .mc-subhead::before,.mc-subhead::after{flex:0 0 24px}
}

/* -------- Events / Outputs / News timeline + cards -------- */
.event-list,.output-list,.news-list{display:grid;gap:20px}
.event-list{grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr))}
.event-card,.output-card,.news-card{padding:28px;display:flex;flex-direction:column;gap:10px}
.event-date{
  display:inline-flex;align-items:baseline;gap:6px;
  font-size:.85rem;color:var(--accent);font-weight:600;
  background:rgba(0,51,153,.08);padding:5px 12px;border-radius:8px;align-self:flex-start;
}
.event-type{font-size:.75rem;color:var(--muted);text-transform:uppercase;letter-spacing:.1em;font-weight:600}
.event-card h3,.output-card h3,.news-card h3{font-size:1.1rem;margin:0}
.event-card p,.output-card p,.news-card p{font-size:.92rem;color:var(--muted);margin:0;flex-grow:1}
.event-loc{font-size:.85rem;color:var(--ink-2);display:flex;align-items:center;gap:6px}
.event-meta{display:flex;flex-direction:column;gap:8px;margin-top:6px;padding-top:14px;border-top:1px solid var(--line)}
.event-meta-row{display:flex;align-items:flex-start;gap:10px;font-size:.86rem;color:var(--ink-2)}
.event-meta-row svg{flex-shrink:0;margin-top:2px;color:var(--accent);width:15px;height:15px}
.event-meta-row strong{color:var(--ink);font-weight:600}
.event-link{
  display:inline-flex;align-items:center;gap:6px;margin-top:4px;
  font-size:.88rem;font-weight:600;color:var(--accent-2);
}
.event-link svg{width:14px;height:14px;transition:transform .2s var(--ease)}
.event-link:hover svg{transform:translateX(3px)}
.event-card.featured{
  background:linear-gradient(135deg,rgba(10,132,255,.06),rgba(0,51,153,.04)),var(--glass-bg-strong);
  border-color:rgba(10,132,255,.25);
}
.event-card.featured .event-date{background:var(--accent);color:#fff}

/* Subscribe-to-calendar affordance under the events grid.
   Centred CTA + supporting hint sentence beneath it. */
.event-subscribe-line{
  margin:36px auto 0;
  max-width:560px;
  display:flex;flex-direction:column;align-items:center;gap:10px;
  text-align:center;
  font-size:.9rem;color:var(--muted);
}
.event-subscribe{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  padding:12px 22px;border-radius:12px;
  background:var(--accent);
  border:1px solid var(--accent);
  color:#fff;font-weight:600;font-size:.95rem;
  text-decoration:none;
  box-shadow:0 4px 12px var(--accent-glow);
  transition:transform .15s var(--ease),box-shadow .15s var(--ease),background .15s var(--ease);
}
.event-subscribe:hover{
  background:var(--accent-2);border-color:var(--accent-2);
  transform:translateY(-1px);
  box-shadow:0 6px 18px var(--accent-glow);
  opacity:1;
}
.event-subscribe svg{width:18px;height:18px;color:#fff}
.event-subscribe-hint{line-height:1.5;max-width:48ch}
.event-subscribe-hint a{color:var(--ink-2);text-decoration:underline;text-decoration-color:var(--line)}
.event-subscribe-hint a:hover{color:var(--accent);text-decoration-color:var(--accent)}
.event-subscribe-hint code{font-size:.85em;background:rgba(0,0,0,.04);padding:1px 5px;border-radius:4px}
.dark .event-subscribe-hint code{background:rgba(255,255,255,.06)}

.output-list,.news-list{grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr))}
.output-kind{font-size:.75rem;font-weight:700;color:var(--accent-2);text-transform:uppercase;letter-spacing:.1em}
.news-date{font-size:.82rem;color:var(--muted)}
.news-card a{font-size:.9rem;font-weight:600;margin-top:auto}

/* ── Upcoming-event banner ────────────────────────────────────
   A single dynamic card slotted between the hero and Latest News
   on the home page. Reads `data/events.json`, picks the most-
   imminent event whose URL is hosted on netsec-cost.eu (so it
   never sends the visitor off-site without warning), and renders
   a state-aware strip: a countdown when the event is upcoming, a
   live indicator when it is happening, and a "concluded" archive
   pointer for up to ~30 days after.

   The banner is `hidden` by default; the inline JS in index.html
   reveals it only when a qualifying event exists. With JS off the
   strip never appears, the Latest News card still carries the
   conference information, and nothing breaks. */
.upcoming-event{
  margin:24px 0 0;
}
.ue-card{
  position:relative;
  display:grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap:24px;
  align-items:center;
  padding:22px 26px;
  border-radius:18px;
  overflow:hidden;
  background:
    linear-gradient(135deg, color-mix(in oklab, var(--accent-2) 18%, transparent), transparent 60%),
    linear-gradient(225deg, color-mix(in oklab, var(--gold) 12%, transparent), transparent 65%),
    var(--glass-bg-strong);
  border:1px solid color-mix(in oklab, var(--accent-2) 30%, var(--glass-border));
}
.dark .ue-card{
  background:
    linear-gradient(135deg, color-mix(in oklab, var(--accent-2) 30%, transparent), transparent 60%),
    linear-gradient(225deg, color-mix(in oklab, var(--gold) 18%, transparent), transparent 65%),
    var(--glass-bg-strong);
}
.ue-body{min-width:0}
.ue-status{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-size:.74rem;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--accent-2);
  margin-bottom:8px;
  /* Backing chip so the dot reads as part of a single pill rather
     than as a floating speck next to the label. Background tints
     are colour-mixed from `currentColor`, which the state modifiers
     below override (live → green, soon → amber, concluded → muted),
     so the chip stays in sync with whichever state is active. */
  padding:4px 10px 4px 8px;
  border-radius:999px;
  background:color-mix(in oklab, currentColor 10%, transparent);
  border:1px solid color-mix(in oklab, currentColor 22%, transparent);
}
.ue-status .dot{
  width:7px;height:7px;border-radius:50%;
  background:currentColor;
  flex:none;
}
/* When the event is live (`data-state="live"`), the pill turns
   green and the dot pulses — same colour family as the per-session
   `.programme-slot-livestream` badge on /essc-2026.html so the
   visual story stays coherent. */
.ue-card[data-state="live"] .ue-status{
  color:#15803d;
}
.dark .ue-card[data-state="live"] .ue-status{
  color:#52d775;
}
.ue-card[data-state="live"] .ue-status .dot{
  background:currentColor;
  box-shadow:0 0 0 0 currentColor;
  animation:ue-pulse 1.8s ease-out infinite;
}
@media (prefers-reduced-motion: reduce){
  .ue-card[data-state="live"] .ue-status .dot{animation:none}
}
@keyframes ue-pulse{
  0%   { box-shadow: 0 0 0 0   color-mix(in oklab, currentColor 50%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in oklab, currentColor 0%,  transparent); }
  100% { box-shadow: 0 0 0 0   color-mix(in oklab, currentColor 0%,  transparent); }
}
/* "Soon" state (≤ 7 days out) — amber rather than blue, to nudge
   the eye toward the imminence. */
.ue-card[data-state="soon"] .ue-status{
  color:#a85b00;
}
.dark .ue-card[data-state="soon"] .ue-status{
  color:#fbbf24;
}
.ue-card[data-state="soon"] .ue-status .dot{
  background:currentColor;
}
.ue-card[data-state="concluded"] .ue-status{
  color:var(--muted);
}
.ue-card[data-state="concluded"] .ue-status .dot{
  background:var(--muted);
}
.ue-headline{
  font-family:'Lexend','Inter',sans-serif;
  font-size:1.5rem;
  font-weight:600;
  letter-spacing:-.015em;
  margin:0 0 6px;
  color:var(--ink);
  line-height:1.2;
}
.ue-meta{
  margin:0;
  font-size:.92rem;
  color:var(--ink-2);
  line-height:1.5;
}
.ue-meta strong{color:var(--ink);font-weight:600}
.ue-cta{
  display:flex;
  flex-direction:column;
  gap:8px;
  align-items:stretch;
  min-width:160px;
}
.ue-cta .btn{
  text-align:center;
  white-space:nowrap;
}
/* "Add to calendar" carries a leading calendar glyph that matches
   the one used by `.event-subscribe` further down the page, so the
   two surfaces read as the same gesture. The SVG sits inline with
   the label via flex; size + spacing mirror the existing button
   icon convention. */
.ue-secondary{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:8px;
}
.ue-secondary svg{
  width:16px;
  height:16px;
  flex:none;
}
/* Narrow viewports: stack the CTA below the body so the card
   doesn't squeeze the headline into two illegible columns.
   The vertical rhythm above the banner is also tightened: the
   24+24 px combo from .details-strip and .upcoming-event reads
   as too much space on a small screen. */
@media (max-width: 720px){
  .upcoming-event{margin-top:8px}
  .ue-card{
    grid-template-columns: 1fr;
    padding:18px 20px;
  }
  .ue-cta{align-items:stretch}
  .ue-headline{font-size:1.25rem}
}
@media print{
  .upcoming-event{display:none}
}

/* -------- Contact -------- */
.contact-wrap{display:grid;grid-template-columns:1fr 1.2fr;gap:32px;align-items:start}
.contact-info{padding:36px}
.contact-info h3{font-size:1.5rem;margin-bottom:1rem}
.contact-info .item{display:flex;gap:14px;align-items:flex-start;margin:18px 0}
.contact-info .item-icon{
  width:38px;height:38px;border-radius:10px;flex-shrink:0;
  background:rgba(0,51,153,.08);color:var(--accent);
  display:grid;place-items:center;
}
.contact-info .item strong{display:block;font-size:.95rem;color:var(--ink);margin-bottom:2px}
.contact-info .item span{font-size:.9rem;color:var(--muted)}
.contact-info .item a{word-break:break-word;overflow-wrap:anywhere}
form{padding:36px;display:grid;gap:14px}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
label{font-size:.85rem;font-weight:500;color:var(--ink-2);display:block;margin-bottom:6px}
input,textarea{
  width:100%;padding:12px 14px;font:inherit;font-size:.95rem;color:var(--ink);
  background:rgba(255,255,255,.6);border:1px solid var(--glass-border);
  border-radius:12px;transition:border-color .2s var(--ease),background .2s var(--ease),box-shadow .2s var(--ease);
}
input:focus,textarea:focus{
  outline:0;border-color:var(--accent-2);background:#fff;
  box-shadow:0 0 0 4px rgba(10,132,255,.15);
}
textarea{min-height:140px;resize:vertical}
form .btn{justify-self:start;margin-top:6px}
form button:disabled{opacity:.65;cursor:wait}

/* -------- Toast notification -------- */
.toast{
  position:fixed;z-index:200;
  left:50%;bottom:24px;transform:translate(-50%,40px);
  display:flex;align-items:center;gap:12px;
  max-width:min(440px,calc(100% - 32px));
  padding:14px 16px 14px 14px;border-radius:14px;
  background:var(--glass-bg-strong);
  backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  border:1px solid var(--glass-border);
  box-shadow:0 18px 50px rgba(20,35,80,.20),0 4px 12px rgba(20,35,80,.10);
  opacity:0;pointer-events:none;
  transition:opacity .3s var(--ease),transform .3s var(--ease);
  color:var(--ink);
}
.toast.show{opacity:1;transform:translate(-50%,0);pointer-events:auto}
.toast .toast-icon{
  flex-shrink:0;width:32px;height:32px;border-radius:10px;
  display:grid;place-items:center;color:#fff;
}
.toast .toast-icon svg{width:18px;height:18px}
.toast[data-type=success] .toast-icon{background:linear-gradient(135deg,#16a34a,#22c55e)}
.toast[data-type=error]   .toast-icon{background:linear-gradient(135deg,#dc2626,#f87171)}
.toast .toast-msg{font-size:.92rem;font-weight:500;line-height:1.4;color:var(--ink)}
.toast .toast-close{
  margin-left:auto;flex-shrink:0;
  width:28px;height:28px;border-radius:8px;border:0;cursor:pointer;
  background:transparent;color:var(--muted);
  display:grid;place-items:center;
  transition:background .2s var(--ease),color .2s var(--ease);
}
.toast .toast-close:hover{background:rgba(11,18,32,.06);color:var(--ink)}
@media (max-width:540px){
  .toast{left:16px;right:16px;transform:translate(0,40px);max-width:none}
  .toast.show{transform:translate(0,0)}
}

/* -------- Footer (COST + EU obligations) -------- */
.footer{
  margin-top:60px;padding:60px 0 36px;
  background:linear-gradient(180deg,transparent 0%,rgba(255,255,255,.65) 30%);
  border-top:1px solid var(--line);
}
.footer-cobranding{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:48px;padding:36px 28px;margin-bottom:32px;
}
/* COST logo: VIG requires clearspace (x2 the cap-height around) and minimum size.
   We reserve generous clearspace via padding/gap above, and enforce a minimum width below.
   Min size ~120px width preserves legibility (well above the 30 mm A5 print minimum). */
.cost-mark{
  display:inline-flex;align-items:center;justify-content:center;
  padding:14px 18px;border-radius:14px;background:#fff;
  box-shadow:0 4px 14px rgba(20,35,80,.06);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease);
}
.cost-mark:hover{transform:translateY(-2px);box-shadow:0 8px 22px rgba(20,35,80,.10);opacity:1}
.cost-mark img{height:54px;width:auto;min-width:120px}     /* min-width = VIG minimum size */
.eu-mark{
  display:flex;align-items:center;gap:14px;
  padding:14px 18px;border-radius:14px;background:#fff;
  box-shadow:0 4px 14px rgba(20,35,80,.06);
}
.eu-flag{width:78px;height:52px;flex-shrink:0;display:block}
.eu-mark .eu-text{
  font-family:'Inter',sans-serif;font-weight:700;color:#003399;font-size:1.05rem;line-height:1.15;letter-spacing:-.01em;
}
.footer-text{
  max-width:780px;margin:0 auto;text-align:center;font-size:.9rem;color:var(--muted);
}
.footer-text p{margin:0 0 .8rem;color:var(--muted)}
.footer-text strong{color:var(--ink-2)}
.footer-credit{
  max-width:780px;margin:18px auto 0;text-align:center;
  font-size:.8rem;color:var(--muted);font-style:italic;letter-spacing:-.005em;
}
.footer-credit a{color:var(--ink-2);text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
.footer-credit a:hover{color:var(--accent);text-decoration-color:var(--accent)}
.footer-bottom{
  margin-top:36px;padding-top:24px;border-top:1px solid var(--line);
  display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;
  font-size:.82rem;color:var(--muted);
}
.footer-bottom .socials{display:flex;gap:8px}
.footer-bottom .socials a{
  width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  background:var(--glass-bg);border:1px solid var(--glass-border);color:var(--ink-2);
}
.footer-bottom .socials a:hover{background:var(--ink);color:#fff;opacity:1}

/* -------- Reveal on scroll -------- */
/* Reveal-on-scroll: default to VISIBLE. The fade-in only engages once
   JS has run successfully and added the `js-reveal` class to <html>.
   If JS fails for any reason, content stays visible — never invisible. */
.reveal{opacity:1;transform:none;transition:opacity .8s var(--ease),transform .8s var(--ease)}
.js-reveal .reveal:not(.in){opacity:0;transform:translateY(20px)}

/* -------- CA badge in hero -------- */
.ca-badge{
  display:inline-flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px;
  margin-top:18px;padding:8px 14px;border-radius:18px;max-width:100%;
  font-size:.82rem;font-weight:600;letter-spacing:.04em;color:var(--ink-2);
  text-align:center;
  background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--glass-border);
  transition:transform .2s var(--ease),box-shadow .2s var(--ease);
}
.ca-badge:hover{transform:translateY(-1px);box-shadow:0 8px 22px rgba(20,35,80,.10);opacity:1}
.ca-badge .dot{width:6px;height:6px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 4px rgba(34,197,94,.18)}
.ca-badge strong{color:var(--accent);font-weight:700}

/* -------- Action details strip -------- */
.details-strip{padding:24px 0 0}
@media (max-width: 720px){
  .details-strip{padding:12px 0 0}
}
.details-grid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:0;
  padding:20px 8px;border-radius:var(--radius);
}
.details-grid .item{padding:8px 24px;text-align:center;border-right:1px solid var(--line)}
.details-grid .item:last-child{border-right:0}
.details-grid .label{
  font-size:.7rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-bottom:4px;
}
.details-grid .value{
  font-family:'Lexend','Inter',sans-serif;font-weight:600;color:var(--ink);
  font-size:1.05rem;letter-spacing:-.01em;
}

/* -------- Roadmap Gantt -------- */
.gantt-intro{
  display:flex;flex-wrap:wrap;gap:10px;align-items:center;justify-content:center;
  margin:0 auto 22px;font-size:.82rem;color:var(--muted);
}
.gantt-key{
  display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:999px;
  background:var(--glass-bg);border:1px solid var(--glass-border);
}
.gantt-key .swatch{
  width:14px;height:14px;border-radius:4px;
  background:linear-gradient(135deg,var(--accent),var(--accent-2));
  box-shadow:0 2px 6px rgba(0,51,153,.30);
}
.scroll-hint{
  display:none;text-align:center;font-size:.78rem;color:var(--muted);
  margin:0 0 10px;letter-spacing:.04em;
}
.gantt-wrap{
  overflow-x:auto;
  border-radius:var(--radius);
  background:var(--glass-bg);
  backdrop-filter:saturate(160%) blur(18px);
  -webkit-backdrop-filter:saturate(160%) blur(18px);
  border:1px solid var(--glass-border);
  box-shadow:var(--glass-shadow);
  /* iOS rubber-band */
  -webkit-overflow-scrolling:touch;
}
.gantt{min-width:920px}
.g-row{display:grid;align-items:stretch}
.g-row-y{grid-template-columns:240px 1fr 1fr 1fr 1fr}
.g-row-q,.g-row-d{grid-template-columns:240px repeat(16,1fr)}

.g-label{
  padding:14px 16px;
  font-size:.86rem;
  color:var(--ink-2);
  position:sticky;left:0;z-index:2;
  background:var(--glass-bg-strong);
  border-right:1px solid var(--line);
  border-bottom:1px solid var(--line);
  display:flex;flex-direction:column;gap:2px;justify-content:center;
}
.g-label .d-id{font-size:.7rem;letter-spacing:.1em;color:var(--accent);font-weight:700}
.g-label .d-name{font-size:.86rem;color:var(--ink);font-weight:500;line-height:1.3}
.g-label-head{
  background:var(--glass-bg-strong);
  font-size:.72rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);
  flex-direction:row;align-items:center;
}

.g-year{
  text-align:center;
  font-weight:700;font-size:.86rem;color:var(--ink);
  padding:12px 8px;
  background:linear-gradient(180deg,rgba(0,51,153,.06),rgba(0,51,153,.02));
  border-right:1px solid var(--line);
  border-bottom:1px solid var(--line);
  letter-spacing:-.01em;
}
.g-year .y-sub{display:block;font-weight:500;font-size:.72rem;color:var(--muted);margin-top:2px;letter-spacing:0}
.g-year:last-child{border-right:0}

.g-q{
  text-align:center;font-size:.72rem;color:var(--muted);font-weight:600;
  padding:10px 4px;
  border-right:1px solid var(--line);
  border-bottom:1px solid var(--line);
  background:rgba(255,255,255,.35);
}
.g-q:last-child{border-right:0}

.g-cell{
  display:flex;align-items:center;justify-content:center;
  padding:10px 4px;
  border-right:1px solid var(--line);
  border-bottom:1px solid var(--line);
  min-height:50px;
}
.g-cell:last-child{border-right:0}
.g-row-d:last-child .g-cell,.g-row-d:last-child .g-label{border-bottom:0}

/* Year tint: Y2 and Y4 columns get a subtle wash so the eye groups them */
.g-row-d > .g-cell:nth-child(n+6):nth-child(-n+9),
.g-row-d > .g-cell:nth-child(n+14):nth-child(-n+17),
.g-row-q > .g-q:nth-child(n+6):nth-child(-n+9),
.g-row-q > .g-q:nth-child(n+14):nth-child(-n+17){
  background-color:rgba(0,51,153,.025);
}
/* Bolder vertical between years */
.g-row-d > .g-cell:nth-child(5),
.g-row-d > .g-cell:nth-child(9),
.g-row-d > .g-cell:nth-child(13),
.g-row-q > .g-q:nth-child(5),
.g-row-q > .g-q:nth-child(9),
.g-row-q > .g-q:nth-child(13){
  border-right:2px solid rgba(11,18,32,.10);
}

.milestone{
  font-family:'Inter',sans-serif;
  font-size:.7rem;font-weight:700;letter-spacing:.02em;
  color:#fff;
  background:linear-gradient(135deg,var(--accent),var(--accent-2));
  padding:5px 9px;border-radius:7px;
  box-shadow:0 4px 10px rgba(0,51,153,.28);
  white-space:nowrap;
  transition:transform .2s var(--ease),box-shadow .2s var(--ease);
}
.milestone:hover{transform:translateY(-1px);box-shadow:0 6px 14px rgba(0,51,153,.40)}

/* -------- Country grid (MC composition) -------- */
.country-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr));gap:14px;
  margin-top:8px;
}
.country-card{padding:18px 18px 16px;display:flex;flex-direction:column;gap:10px}
.country-card .country-head{display:flex;align-items:center;gap:10px}
.country-card .flag{
  width:28px;height:auto;border-radius:3px;flex-shrink:0;
  box-shadow:0 1px 3px rgba(0,0,0,.18);
  background:#e5e9f1;
}
.country-card .country-name{
  font-weight:600;font-size:.98rem;color:var(--ink);letter-spacing:-.01em;
}
.country-card ul{
  list-style:none;padding:0;margin:0;
  display:flex;flex-direction:column;gap:8px;
  border-top:1px solid var(--line);padding-top:10px;
}
.country-card li{
  font-size:.86rem;color:var(--ink-2);
  position:relative;
  padding-left:14px;          /* room for the bullet */
}
.country-card li::before{
  content:"·";color:var(--accent);font-weight:700;
  position:absolute;left:2px;top:0;line-height:inherit;
}

/* -------- Founding contributors (about.html #founding) --------
 * Reuses .country-grid / .country-card scaffolding from the MC
 * snapshot directly above; the differences (per-person affiliation
 * line, count badge, proposer badge) are layered on top here. */
.founding-country-card .country-head{position:relative}
.founding-country-count{
  margin-left:auto;
  font-size:.78rem;font-weight:600;color:var(--muted);
  background:var(--surface-2);
  border:1px solid var(--line);
  border-radius:10px;
  padding:2px 8px;line-height:1.6;
  min-width:1.8em;text-align:center;
}
.founding-list .founding-name{font-weight:500;color:var(--ink-2);display:block}
.founding-affiliation{
  display:block;
  font-size:.78rem;color:var(--muted);font-style:italic;
  margin-top:1px;line-height:1.35;
}
.founding-proposer-badge{
  display:inline-block;margin-left:6px;
  font-size:.7rem;font-weight:600;letter-spacing:.02em;
  text-transform:uppercase;
  color:#fff;background:var(--accent);
  border-radius:999px;padding:1px 8px;line-height:1.5;
  vertical-align:middle;
}
.founding-footnote{
  text-align:center;color:var(--muted);font-size:.86rem;
  max-width:60ch;margin:22px auto 0;line-height:1.55;
}

/* -------- MC by Country: intro paragraph + snapshot stats -------- */
.mc-intro{
  text-align:center;color:var(--muted);font-size:.92rem;
  max-width:60ch;margin:0 auto 22px;
}
.mc-stats{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:14px;
  max-width:760px;
  margin:0 auto 8px;
}
.mc-stat{
  padding:18px 16px 16px;
  text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:4px;
}
.mc-stat-num{
  font-size:1.9rem;font-weight:700;letter-spacing:-.02em;
  color:var(--ink);line-height:1.05;
}
.mc-stat-label{
  font-size:.86rem;color:var(--ink-2);letter-spacing:-.005em;
}
.mc-stats-note{
  text-align:center;color:var(--muted);
  font-size:.78rem;margin:6px auto 0;max-width:60ch;
}
@media (max-width:600px){
  .mc-stats{grid-template-columns:1fr;max-width:360px}
  .mc-stat-num{font-size:1.7rem}
}

/* -------- MC by Country: collapsible <details> -------- */
.mc-collapse{
  /* Match the breathing room between every other MC subsection so
     the country block reads as its own subsection rather than as a
     footnote to the snapshot stats. */
  margin-top:36px;
}
.mc-collapse > summary{
  list-style:none;          /* hide default disclosure triangle */
  cursor:pointer;
  display:block;
  text-align:center;
  padding:6px 0;
  margin-bottom:22px;
}
.mc-collapse > summary::-webkit-details-marker{display:none}
.mc-collapse > summary::marker{content:""}
.mc-collapse > summary:focus-visible{
  outline:0;
  box-shadow:0 0 0 3px rgba(10,132,255,.45);
  border-radius:18px;
}
.mc-collapse > summary .mc-subhead{margin:0 0 14px}
/* Hint pill: sized as a proper call-to-action, not a footnote chip. */
.mc-collapse-hint{
  display:inline-flex;align-items:center;gap:10px;
  padding:11px 22px;
  font-size:.95rem;font-weight:600;letter-spacing:-.005em;
  color:var(--ink-2);
  background:var(--glass-bg-strong);
  border:1px solid var(--glass-border);
  border-radius:999px;
  box-shadow:0 4px 14px rgba(20,35,80,.06);
  transition:color .2s var(--ease),background .2s var(--ease),transform .2s var(--ease),box-shadow .2s var(--ease);
}
.mc-collapse > summary:hover .mc-collapse-hint{
  color:var(--ink);
  background:#fff;
  transform:translateY(-2px);
  box-shadow:0 8px 22px rgba(20,35,80,.12);
}
.dark .mc-collapse > summary:hover .mc-collapse-hint{
  background:rgba(255,255,255,.10);
}
.mc-collapse-chevron{
  width:16px;height:16px;
  transition:transform .25s var(--ease);
}
.mc-collapse[open] .mc-collapse-chevron{transform:rotate(180deg)}
/* Toggle the two hint labels based on open state */
.mc-collapse-when-open{display:none}
.mc-collapse[open] .mc-collapse-when-closed{display:none}
.mc-collapse[open] .mc-collapse-when-open{display:inline}

/* When printing, force the section open so the directory makes it onto paper */
@media print{
  .mc-collapse > summary{display:none}
  .mc-collapse[open] > summary,
  .mc-collapse:not([open]) > *{display:block !important}
}

/* -------- Responsive --------
   Mobile-menu breakpoint widened from 880px → 980px to make room
   for the longer FR/DE nav labels. On English-only sites 880 was
   fine; with translations the inline nav stops fitting at ~960px,
   so we let the hamburger drawer take over a touch sooner. */
@media (max-width:980px){
  /* Mobile nav drawer.
     Near-opaque background (.97) rather than the .72/.78 glass
     tokens used elsewhere — the drawer sits absolutely positioned
     over the hero, and a translucent panel with backdrop-filter
     nested inside the bubble's own backdrop-filter does not
     restack reliably (Chromium, both viewport-sized + emulated
     mobile). Hero text bled through behind every nav item in
     dark mode. Surfaced by Phase 1 mobile sweep of the launch-QA
     pass (finding M-1 in docs/launch-qa-2026.md). Box-shadow
     bumped so the drawer reads as elevated over the page. */
  .nav-links{display:none;position:absolute;top:60px;left:0;right:0;flex-direction:column;align-items:stretch;background:rgba(246,248,252,.97);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-radius:14px;padding:10px;margin:0 8px;border:1px solid var(--glass-border);box-shadow:0 18px 40px rgba(20,35,80,.18)}
  .dark .nav-links{background:rgba(11,18,32,.97);box-shadow:0 18px 40px rgba(0,0,0,.55)}
  .nav-links.open{display:flex}
  .nav-links a{padding:12px 14px;font-size:.95rem}
  /* Override the FR/DE compact rule inside the mobile drawer: the
     drawer has plenty of room, so use the full label size there. */
  :lang(fr) .nav-links a, :lang(de) .nav-links a{font-size:.95rem;padding:12px 14px}
  .menu-toggle{display:block}
  .about-grid,.contact-wrap{grid-template-columns:1fr}
  .form-row{grid-template-columns:1fr}
  .hero{padding:120px 0 60px}
  section{padding:60px 0}
  .details-grid{grid-template-columns:repeat(2,1fr);gap:8px}
  /* Mobile separator pattern: items lose the desktop's vertical
     `border-right` and only the top row carries a horizontal
     border-bottom. The previous rule (every item gets a
     border-bottom, then strip from `:nth-child(2n)` + `:last-child`)
     left a half-line under the bottom-left item because that one
     matched neither stripping selector. `:nth-last-child(-n+2)`
     targets the final row (the last two items in a 2-col grid) so
     they shed the border regardless of item count. */
  .details-grid .item{border-right:0;border-bottom:1px solid var(--line);padding:14px}
  .details-grid .item:nth-last-child(-n+2){border-bottom:0}
  /* Gantt mobile tweaks.
     Year row uses `minmax(184px, 1fr)` so each year column is
     guaranteed to be exactly 4 × quarter min (46 × 4 = 184). Without
     this, the year row's 1fr cols would shrink below 184 px while
     the quarter row enforced its minmax(46, 1fr) — Year 1 Q4 would
     visibly bleed into the Year 2 column at narrow widths. */
  .scroll-hint{display:block}
  .g-row-y{grid-template-columns:180px repeat(4,minmax(184px,1fr))}
  .g-row-q,.g-row-d{grid-template-columns:180px repeat(16,minmax(46px,1fr))}
  .g-label{padding:10px 12px}
  .g-label .d-name{font-size:.78rem}
  .g-year{font-size:.78rem;padding:10px 4px}
  .g-year .y-sub{display:none}
  /* Match the year row's enforced min so the whole gantt is at least
     wide enough to keep year + quarter grids aligned. */
  .gantt{min-width:916px}
  .milestone{font-size:.62rem;padding:4px 6px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
  .blob{animation:none}
}

/* -------- Dark mode --------
   Activated by adding the `.dark` class to <html>. A tiny inline
   <head> script (in <head>, see top of body) sets the class on page
   load based on:
     • localStorage.netsec-theme === 'dark', OR
     • no localStorage entry AND OS prefers-color-scheme: dark
   The theme toggle in the nav writes to localStorage and toggles the
   class. The COST logo and EU emblem live in white containers per
   the VIG and stay light-on-white in both modes, as required. */
.dark{
  --bg-0:#0b1220;
  --bg-1:#101a30;
  --ink:#eef2f8;
  --ink-2:#c4cde0;
  --muted:#8b97b3;
  --line:rgba(255,255,255,.10);
  --glass-bg:rgba(22,32,55,.55);
  --glass-bg-strong:rgba(22,32,55,.78);
  --glass-border:rgba(255,255,255,.10);
  --glass-shadow:0 10px 40px rgba(0,0,0,.45),0 1px 2px rgba(0,0,0,.30);
  --accent:#6ea1ff;
  --accent-2:#82b7ff;
  --accent-glow:rgba(110,161,255,.30);
  color-scheme:dark;
}
.dark .ambience{background:linear-gradient(180deg,#0c1428 0%,#0b1220 45%,#161024 100%)}
.dark .blob{opacity:.32}
.dark .blob.b1{background:#3b5bdb}
.dark .blob.b2{background:#b35a2a}
.dark .blob.b3{background:#6b3aa6}
.dark .hero h1{background:linear-gradient(180deg,#f4f8ff 0%,#aeb7d6 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.dark .btn-primary{background:#f4f6fb;color:#0b1220}
.dark .btn-primary:hover{background:#fff;color:#0b1220}
.dark .nav-cta{background:#f4f6fb;color:#0b1220 !important}
.dark .nav-cta:hover{background:#fff;color:#0b1220 !important}
.dark input,.dark textarea{background:rgba(255,255,255,.06);color:var(--ink);border-color:rgba(255,255,255,.12)}
.dark input:focus,.dark textarea:focus{background:rgba(255,255,255,.10);border-color:var(--accent-2)}
.dark .eyebrow{background:rgba(110,161,255,.14);color:#a9c2ff}
.dark .objective,.dark .country-card ul{background:rgba(255,255,255,.03)}
.dark .footer{background:linear-gradient(180deg,transparent 0%,rgba(20,30,55,.65) 30%)}
.dark .cost-mark,.dark .eu-mark{background:#fff;box-shadow:0 4px 14px rgba(0,0,0,.4)}
.dark .eu-mark .eu-text{color:#003399}
.dark .g-q{background:rgba(255,255,255,.03)}
.dark .g-year{background:linear-gradient(180deg,rgba(110,161,255,.10),rgba(110,161,255,.04))}
.dark .g-row-d > .g-cell:nth-child(n+6):nth-child(-n+9),
.dark .g-row-d > .g-cell:nth-child(n+14):nth-child(-n+17),
.dark .g-row-q > .g-q:nth-child(n+6):nth-child(-n+9),
.dark .g-row-q > .g-q:nth-child(n+14):nth-child(-n+17){background-color:rgba(110,161,255,.06)}
.dark .milestone{background:linear-gradient(135deg,#3b6fe0,#82b7ff);color:#0b1220;box-shadow:0 4px 12px rgba(60,110,230,.45)}
.dark .ca-badge .dot{background:#22c55e;box-shadow:0 0 0 4px rgba(34,197,94,.25)}
.dark .toast{box-shadow:0 18px 50px rgba(0,0,0,.45),0 4px 12px rgba(0,0,0,.30)}
.dark .toast .toast-close:hover{background:rgba(255,255,255,.06)}
/* MC and country cards use a solid translucent bg in both modes (see
   performance override above); switch their colour for dark too. */
.dark .mc-card.glass,
.dark .country-card.glass{background:rgba(22,32,55,.78)}

/* -------- Theme toggle button -------- */
.theme-toggle{
  display:grid;place-items:center;
  width:36px;height:36px;margin-right:6px;
  background:transparent;border:0;cursor:pointer;border-radius:10px;
  color:var(--ink-2);
  transition:background .2s var(--ease),color .2s var(--ease);
}
.theme-toggle:hover{background:rgba(11,18,32,.06);color:var(--ink);opacity:1}
.theme-toggle svg{width:18px;height:18px}
.theme-toggle .icon-sun{display:none}
.theme-toggle .icon-moon{display:block}
.dark .theme-toggle:hover{background:rgba(255,255,255,.08)}
.dark .theme-toggle .icon-sun{display:block}
.dark .theme-toggle .icon-moon{display:none}

/* -------- Language switcher (EN · FR · DE) --------
   A small segmented pill in the nav. Lives next to the theme
   toggle. Each chip is a link to the same page in that language;
   the active chip is marked with aria-current="true" so screen
   readers announce it and the CSS visually elevates it. */
.lang-switch{
  display:inline-flex;align-items:center;gap:2px;
  margin-right:6px;padding:2px;
  background:rgba(11,18,32,.04);
  border-radius:999px;
}
.dark .lang-switch{background:rgba(255,255,255,.06)}
.lang-switch a{
  display:inline-block;
  font-size:.7rem;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;
  color:var(--muted);
  padding:4px 9px;border-radius:999px;
  transition:background .2s var(--ease),color .2s var(--ease);
}
.lang-switch a:hover{color:var(--ink);opacity:1}
.lang-switch a[aria-current="true"]{
  background:#fff;color:var(--ink);
  box-shadow:0 1px 3px rgba(11,18,32,.10);
}
.dark .lang-switch a[aria-current="true"]{
  background:rgba(255,255,255,.14);color:#fff;
}
.lang-switch a[aria-disabled="true"]{
  /* Visual cue for languages without a translation of this page yet —
     the chip still appears so users can switch their preference, but
     the click lands on the English version. */
  color:var(--muted);opacity:.55;
}

/* -------- Beta-translation ribbon --------
   Shown only when the page declares itself a non-authoritative
   translation via <html data-i18n-status="beta">. A thin strip
   above the nav explains the status and links to the English. */
.i18n-beta-ribbon{display:none}
[data-i18n-status="beta"] .i18n-beta-ribbon{
  display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;
  padding:7px 18px;
  /* Layered background: an accent tint sits above an opaque glass
     base so page content can't ghost through. Matches the floating
     nav's pattern (.nav uses var(--glass-bg-strong) + backdrop-
     filter for the same reason). Without the base, the accent
     gradient sat at ~5-15% alpha over nothing, and badges or text
     scrolled behind the ribbon stayed visible on FR/DE pages. */
  background:
    linear-gradient(135deg,rgba(0,51,153,.07),rgba(10,132,255,.05)),
    var(--glass-bg-strong);
  backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid var(--glass-border);
  font-size:.82rem;color:var(--ink-2);
  position:fixed;top:0;left:0;right:0;z-index:101;
  text-align:center;line-height:1.4;
}
.dark [data-i18n-status="beta"] .i18n-beta-ribbon{
  background:
    linear-gradient(135deg,rgba(10,132,255,.15),rgba(0,51,153,.10)),
    var(--glass-bg-strong);
  color:var(--ink);
}
/* Mobile: iOS Safari's backdrop-filter is honoured but inconsistent,
   so on small viewports we bump the base to a near-opaque page-bg
   tint (same trick as .nav). Content scrolling behind the ribbon
   stays hidden regardless of how the browser handles the blur. */
@media (max-width: 720px){
  [data-i18n-status="beta"] .i18n-beta-ribbon{
    background:
      linear-gradient(135deg,rgba(0,51,153,.07),rgba(10,132,255,.05)),
      color-mix(in oklab, var(--bg-0) 92%, transparent);
  }
  .dark [data-i18n-status="beta"] .i18n-beta-ribbon{
    background:
      linear-gradient(135deg,rgba(10,132,255,.15),rgba(0,51,153,.10)),
      color-mix(in oklab, var(--bg-0) 92%, transparent);
  }
}
.i18n-beta-ribbon-badge{
  display:inline-block;
  background:var(--accent);color:#fff;
  font-size:.62rem;font-weight:700;letter-spacing:.12em;
  padding:2px 8px;border-radius:6px;text-transform:uppercase;
}
.i18n-beta-ribbon a{color:var(--accent-2);text-decoration:underline}
/* When the ribbon is present, push the nav and the top of the page
   down so nothing sits underneath.
   `--ribbon-h` is set in JS (site.js) from the ribbon's measured
   offsetHeight and updated by a ResizeObserver — so the offset
   matches reality regardless of whether the ribbon wraps to one
   line (desktop) or two-plus lines (mobile, where the long
   "Traduction automatique…" sentence + link wrap).
   The fallback 38px matches a single-line desktop ribbon and only
   applies if the JS hasn't run yet. */
[data-i18n-status="beta"] body{padding-top:var(--ribbon-h,38px)}
[data-i18n-status="beta"] .nav{top:calc(var(--ribbon-h,38px) + 14px)}

/* -------- Licensing table (licensing page §1) --------
   A simple 3-column responsive table. Reuses prose-page typography
   for harmony with the surrounding text. */
.licence-table{
  width:100%;border-collapse:collapse;margin:1rem 0 1.4rem;
  font-size:.92rem;
}
.licence-table thead th{
  text-align:left;padding:10px 14px;
  font-size:.74rem;letter-spacing:.08em;text-transform:uppercase;
  color:#fff;background:var(--accent);font-weight:600;
}
.licence-table thead th:first-child{border-top-left-radius:8px}
.licence-table thead th:last-child{border-top-right-radius:8px}
.licence-table tbody td{
  padding:10px 14px;border-bottom:1px solid var(--line);
  vertical-align:top;color:var(--ink-2);background:#fff;
}
.dark .licence-table tbody td{background:rgba(22,32,55,.55);color:var(--ink-2)}
.licence-table tbody tr:last-child td{border-bottom:0}

/* -------- Prose pages (Accessibility Statement, Privacy Notice) --------
   Shared layout for content-heavy informational pages. */
.prose-page{padding:140px 0 80px}
.prose-page .container{max-width:820px}
.prose-page h1{font-size:clamp(2.2rem,4.4vw,3.2rem);margin:0 0 1rem}
.prose-page h2{font-size:1.35rem;margin:2.6rem 0 .8rem;letter-spacing:-.01em}
.prose-page h3{font-size:1.05rem;margin:1.4rem 0 .5rem;font-weight:600;letter-spacing:-.005em;color:var(--ink)}
.prose-page p,.prose-page li{font-size:1rem;line-height:1.65;color:var(--ink-2)}
.prose-page p{margin:0 0 1rem}
.prose-page .lede{font-size:1.1rem;color:var(--ink-2);max-width:65ch;margin-bottom:2rem}
.prose-page ul{padding-left:1.4rem;margin:0 0 1rem}
.prose-page li{margin-bottom:.45rem}
.prose-page code{
  font-family:ui-monospace,'SF Mono',Menlo,monospace;font-size:.88rem;
  padding:1px 6px;border-radius:5px;
  background:rgba(11,18,32,.06);color:var(--ink);
}
.dark .prose-page code{background:rgba(255,255,255,.08)}
.prose-page a{color:var(--accent-2);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}
.prose-page a:hover{opacity:.7}

/* Meta strip with status / controller / dates */
.prose-meta{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(180px,100%),1fr));
  gap:14px;padding:22px 24px;margin:8px 0 36px;
}
.prose-meta-item .label{
  display:block;font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);font-weight:600;margin-bottom:6px;
}
.prose-meta-item .value{font-family:'Lexend','Inter',sans-serif;font-weight:600;color:var(--ink);font-size:1rem;letter-spacing:-.01em}

/* Status chip (amber for "partially compliant", green for compliant, etc.) */
.prose-status{
  display:inline-flex;align-items:center;gap:8px;
  padding:5px 12px;border-radius:999px;
  font-size:.85rem;font-weight:600;
  background:linear-gradient(135deg,rgba(245,158,11,.18),rgba(245,158,11,.06));
  color:#b45309;
  border:1px solid rgba(245,158,11,.30);
}
.prose-status .dot{width:8px;height:8px;border-radius:50%;background:#f59e0b}
.dark .prose-status{color:#fbbf24}

/* Audit summary card (Accessibility Statement only, but harmless elsewhere) */
.audit-card{padding:20px 24px;margin:0 0 1.2rem}
.audit-card .grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:8px;
}
.audit-card .stat{text-align:center}
.audit-card .stat .num{font-family:'Lexend','Inter',sans-serif;font-weight:700;font-size:2rem;letter-spacing:-.02em;display:block;line-height:1}
.audit-card .stat .lbl{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:600;margin-top:4px;display:block}
.audit-card .stat.ok .num{color:#16a34a}
.audit-card .stat.warn .num{color:#d97706}
.audit-card .stat.neutral .num{color:var(--accent)}
@media (max-width:540px){
  .audit-card .grid{grid-template-columns:1fr;gap:12px}
  .prose-page{padding:120px 0 60px}
}

/* -------- Members directory (/people.html) -------- */
.people-page{padding:140px 0 80px}
.people-page .container{max-width:1100px}
.people-page h1{font-size:clamp(2.4rem,5vw,3.6rem);margin:0 0 1rem;text-align:center;background:linear-gradient(180deg,var(--ink) 0%,#3a4a6b 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.dark .people-page h1{background:linear-gradient(180deg,#f4f8ff 0%,#aeb7d6 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.people-page .lede{max-width:62ch;margin:0 auto;font-size:1.05rem;text-align:center;color:var(--ink-2)}

.members-toolbar{
  display:flex;flex-wrap:wrap;align-items:center;gap:14px;
  padding:14px 18px;margin:32px 0 18px;
}
.members-search{
  display:flex;align-items:center;gap:8px;flex:1 1 280px;min-width:0;
  padding:8px 14px;border-radius:12px;
  background:rgba(255,255,255,.55);border:1px solid var(--glass-border);
  color:var(--muted);
}
.dark .members-search{background:rgba(255,255,255,.06)}
.members-search svg{flex-shrink:0}
.members-search input{
  flex:1;border:0;background:transparent;outline:none;
  font:inherit;font-size:.95rem;color:var(--ink);min-width:0;
}
.members-filter{display:flex;flex-wrap:wrap;gap:6px}
.members-filter-chip{
  font:inherit;font-size:.82rem;font-weight:600;
  padding:7px 14px;border-radius:999px;border:1px solid var(--glass-border);
  background:transparent;color:var(--ink-2);cursor:pointer;
  transition:background .2s var(--ease),color .2s var(--ease);
}
.members-filter-chip:hover{background:rgba(11,18,32,.04);color:var(--ink)}
.dark .members-filter-chip:hover{background:rgba(255,255,255,.06)}
.members-filter-chip[aria-pressed="true"]{
  background:linear-gradient(135deg,var(--accent),var(--accent-2));
  color:#fff;border-color:transparent;
  box-shadow:0 4px 12px var(--accent-glow);
}
/* MC chip — subtle visual separator from WG chips. A thin dot before
   the label hints that it's a different axis (role, not WG). */
.members-filter-chip.is-mc{
  position:relative;padding-left:22px;
}
.members-filter-chip.is-mc::before{
  content:"";position:absolute;left:10px;top:50%;
  width:6px;height:6px;border-radius:50%;
  background:currentColor;opacity:.55;transform:translateY(-50%);
}
/* Country dropdown — matches the search field styling */
.members-country{
  display:flex;align-items:center;gap:8px;flex:0 1 220px;min-width:0;
  padding:6px 12px 6px 14px;border-radius:12px;
  background:rgba(255,255,255,.55);border:1px solid var(--glass-border);
  color:var(--muted);
}
.dark .members-country{background:rgba(255,255,255,.06)}
.members-country svg{flex-shrink:0}
.members-country select{
  flex:1;border:0;background:transparent;outline:none;
  font:inherit;font-size:.92rem;color:var(--ink);min-width:0;
  cursor:pointer;
  /* Strip the OS chrome a bit so the field reads as part of the toolbar. */
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:18px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237b8aab' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat:no-repeat;background-position:right 0 center;
}
.members-country select::-ms-expand{display:none}
/* Visually hidden helper — for labels that must reach screen readers
   but be off-screen for sighted users. */
.visually-hidden{
  position:absolute !important;width:1px;height:1px;
  margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);
  white-space:nowrap;border:0;
}
.members-count{text-align:center;font-size:.85rem;color:var(--muted);margin:0 0 24px}
.members-empty{padding:36px;text-align:center;margin:24px 0}
.members-empty h3{margin:0 0 8px}
.members-empty p{margin:0;color:var(--muted)}

.members-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(380px,100%),1fr));
  gap:22px;
}

.member-card{
  display:flex;flex-direction:column;padding:24px;
  scroll-margin-top:100px;  /* for deep-link landing */
}
.member-card .member-photo{
  position:relative;width:84px;height:84px;border-radius:50%;
  margin:0 auto 14px;overflow:hidden;
  background:linear-gradient(135deg,#cfd9ee,#e8d8c2);
  border:2px solid rgba(255,255,255,.8);
}
.member-card .member-photo img{
  width:100%;height:100%;object-fit:cover;display:block;border-radius:50%;
}
.member-photo-fallback{
  position:absolute;inset:0;display:grid;place-items:center;
  color:var(--accent);font-weight:700;font-size:1.4rem;font-family:'Lexend','Inter',sans-serif;
}
.member-card .member-body{display:flex;flex-direction:column;flex:1;text-align:center}
.member-card .member-name{
  font-size:1.1rem;margin:0 0 6px;font-weight:600;letter-spacing:-.01em;color:var(--ink);
  font-family:'Lexend','Inter',sans-serif;
}
.member-card .member-role{
  font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--accent);font-weight:700;margin:0 0 6px;
}
.member-card .member-affiliation{
  font-size:.88rem;color:var(--muted);margin:0 0 12px;line-height:1.45;
  display:inline-flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:6px;
}
/* Detailed mode shows the full position · affiliation · country
   string; the compact variant is hidden. The compact-mode block
   further down inverts these. */
.member-affiliation .aff-compact{display:none}
.member-affiliation .aff-full{display:inline}
.member-flag{
  width:18px;height:auto;border-radius:2px;
  box-shadow:0 1px 2px rgba(0,0,0,.18);
  vertical-align:middle;
}
.member-card .member-wgs{
  display:flex;flex-wrap:wrap;gap:4px;justify-content:center;margin:0 0 14px;
}
/* Research-interest keywords. Distinct from `.wg-chip` so visitors
   parse the two layers at a glance: WG chips are bright + bold
   gradient pills tied to the four working groups; keyword chips are
   subdued outlined pills tied to a member's own research interests.
   Compact view hides them entirely (handled below) since the small
   card is already dense with photo + name + WGs + chevron. */
.member-card .member-keywords{
  display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-start;
  margin:6px 0 14px;
}
.member-keyword-chip{
  font-family:'Inter',sans-serif;
  font-size:.74rem;font-weight:500;letter-spacing:-.005em;
  padding:2px 9px;border-radius:999px;
  color:var(--ink-2);
  background:color-mix(in oklab, var(--accent-2) 7%, transparent);
  border:1px solid color-mix(in oklab, var(--accent-2) 22%, transparent);
  white-space:nowrap;
  /* Phase 3: chips are buttons now (click to filter). Reset the
     UA button styling that creeps in (inherit colour, no shadow,
     pointer cursor) so they read identically to the old span. */
  cursor:pointer;
  font:inherit;font-size:.74rem;font-weight:500;letter-spacing:-.005em;
  line-height:1.4;
  transition:background-color .15s ease, border-color .15s ease, transform .12s ease;
}
.member-keyword-chip:hover{
  background:color-mix(in oklab, var(--accent-2) 14%, transparent);
  border-color:color-mix(in oklab, var(--accent-2) 38%, transparent);
}
.member-keyword-chip:active{ transform:translateY(1px); }
.member-keyword-chip:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;
}

/* Phase 3: research-interest filter chip row.
   Sits between the toolbar and the members count. Hidden when the
   aggregate is empty (no canonical keywords across the directory).
   The chip list is built dynamically in people.html; styles below
   handle the row itself + chip toggle state + the show-all toggle. */
.members-keyword-filter{
  margin:14px 0 18px;
  padding:14px 16px;
  border-radius:16px;
  background:color-mix(in oklab, var(--accent-2) 4%, transparent);
  border:1px solid color-mix(in oklab, var(--accent-2) 14%, transparent);
}
.members-keyword-filter-head{
  display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  margin-bottom:10px;
}
.members-keyword-filter-label{
  font-family:'Lexend',sans-serif;
  font-size:.78rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted);
}
.members-keyword-filter-clear{
  font-family:'Inter',sans-serif;
  font-size:.78rem;font-weight:500;
  color:var(--ink-2);
  background:transparent;border:0;padding:2px 6px;border-radius:6px;
  cursor:pointer;
}
.members-keyword-filter-clear:hover{ color:var(--ink); text-decoration:underline; }
.members-keyword-filter-clear:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;
}
.members-keyword-filter-chips{
  display:flex;flex-wrap:wrap;gap:8px;
}
.members-keyword-filter-chip{
  display:inline-flex;align-items:center;gap:6px;
  font-family:'Inter',sans-serif;
  font-size:.78rem;font-weight:500;letter-spacing:-.005em;line-height:1.4;
  padding:5px 11px;border-radius:999px;
  color:var(--ink);
  background:color-mix(in oklab, var(--bg) 70%, transparent);
  border:1px solid color-mix(in oklab, var(--accent-2) 24%, transparent);
  cursor:pointer;
  transition:background-color .15s ease, border-color .15s ease, color .15s ease, transform .12s ease;
}
.members-keyword-filter-chip:hover{
  background:color-mix(in oklab, var(--accent-2) 12%, transparent);
  border-color:color-mix(in oklab, var(--accent-2) 42%, transparent);
}
.members-keyword-filter-chip:active{ transform:translateY(1px); }
.members-keyword-filter-chip:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;
}
.members-keyword-filter-chip[aria-pressed="true"]{
  background:color-mix(in oklab, var(--accent) 22%, transparent);
  border-color:color-mix(in oklab, var(--accent) 60%, transparent);
  color:var(--ink);
}
.members-keyword-filter-chip[aria-pressed="true"]:hover{
  background:color-mix(in oklab, var(--accent) 30%, transparent);
}
.members-keyword-filter-chip .count{
  font-size:.7rem;font-weight:500;
  color:var(--muted);
  padding:0 4px;border-radius:6px;
  background:color-mix(in oklab, var(--ink) 8%, transparent);
}
.members-keyword-filter-chip[aria-pressed="true"] .count{
  color:var(--ink);
  background:color-mix(in oklab, var(--accent) 22%, transparent);
}
.members-keyword-filter-toggle{
  margin-top:10px;
  font-family:'Inter',sans-serif;
  font-size:.78rem;font-weight:500;
  color:var(--ink-2);
  background:transparent;border:0;padding:2px 0;
  cursor:pointer;
}
.members-keyword-filter-toggle:hover{ color:var(--ink); text-decoration:underline; }
.members-keyword-filter-toggle:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;
}
@media (max-width: 640px){
  .members-keyword-filter{ padding:12px 12px; margin:12px 0 14px; }
  .members-keyword-filter-chips{ gap:6px; }
  .members-keyword-filter-chip{ padding:4px 9px; font-size:.74rem; }
}
/* Compact (grid) view: keyword block hidden. Full keywords show on
   expand. The matcher (line 1885-ish, .is-compact .member-card:not
   (.is-expanded) …) is the canonical rule for "this card is in
   compact-collapsed state"; we mirror it here. */
.members-grid.is-compact .member-card:not(.is-expanded) .member-keywords{
  display:none;
}
.member-card .member-bio{
  font-size:.92rem;line-height:1.55;color:var(--ink-2);margin:0 0 6px;
  flex:1;text-align:left;
  /* Clamp to four lines by default; JS detects overflow and adds a
     "Show more" toggle that flips `.is-expanded`. */
  display:-webkit-box;
  -webkit-line-clamp:4;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
.member-card .member-bio.is-expanded{
  -webkit-line-clamp:unset;
  display:block;
  overflow:visible;
}
.member-card .member-bio.is-pending{
  color:var(--muted);font-style:italic;text-align:center;
  /* No clamping needed — pending placeholder is always short. */
  display:block;-webkit-line-clamp:unset;overflow:visible;
}
.member-bio-toggle{
  display:inline-flex;align-items:center;gap:4px;
  margin:0 0 12px;padding:2px 0;
  font:inherit;font-size:.82rem;font-weight:600;letter-spacing:-.005em;
  color:var(--accent-2);background:transparent;border:0;cursor:pointer;
  align-self:flex-start;
}
.member-bio-toggle:hover{opacity:.7}
.member-bio-toggle svg{
  width:12px;height:12px;
  transition:transform .2s var(--ease);
}
.member-bio-toggle.is-expanded svg{transform:rotate(180deg)}
.member-card .member-contact{
  display:flex;gap:6px;justify-content:center;flex-wrap:wrap;
  margin-top:auto;padding-top:12px;border-top:1px solid var(--line);
}
.member-card .member-contact a{
  width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(11,18,32,.04);color:var(--ink-2);
  transition:background .2s var(--ease),color .2s var(--ease),transform .2s var(--ease);
}
.member-card .member-contact a:hover{
  background:var(--accent);color:#fff;opacity:1;transform:translateY(-1px);
}
.dark .member-card .member-contact a{background:rgba(255,255,255,.06)}
.dark .member-card .member-contact a:hover{background:var(--accent)}
.member-card .member-contact a svg{width:16px;height:16px}
/* ORCID brand mark is always green — the inner glyph is white. The
   surrounding pill bg still tints on hover. */
.member-card .member-contact a.contact-orcid{color:#a6ce39}
.member-card .member-contact a.contact-orcid:hover{background:#a6ce39;color:#fff}
.dark .member-card .member-contact a.contact-orcid{color:#a6ce39}
.dark .member-card .member-contact a.contact-orcid:hover{background:#a6ce39}

/* Search-landing spotlight. Applied to the card a visitor lands
   on after clicking a search result that points at
   /people.html#<slug>. Auto-fades after ~3.5 s (the JS removes
   the class) so it confirms the landing without becoming a
   permanent selection state. Works in detailed AND compact view —
   in detailed view it's the only visual cue that this card is
   "the one you searched for". */
.member-card.is-search-landed{
  outline:2px solid var(--accent-2);
  outline-offset:3px;
  box-shadow:
    0 0 0 6px rgba(10,132,255,.20),
    0 14px 36px rgba(10,132,255,.18),
    var(--glass-shadow);
  background:color-mix(in oklab, var(--accent-2) 8%, var(--glass-bg));
  animation:search-landed-in .45s var(--ease);
  position:relative;z-index:2;
}
.dark .member-card.is-search-landed{
  background:color-mix(in oklab, var(--accent-2) 14%, var(--glass-bg));
}
@keyframes search-landed-in{
  from{transform:scale(.98);box-shadow:0 0 0 0 rgba(10,132,255,.55),var(--glass-shadow)}
  to  {transform:scale(1);
       box-shadow:
         0 0 0 6px rgba(10,132,255,.20),
         0 14px 36px rgba(10,132,255,.18),
         var(--glass-shadow)}
}
@media (prefers-reduced-motion: reduce){
  .member-card.is-search-landed{animation:none}
}

/* ─── Directory tour ──────────────────────────────────────────
   Trigger button in the toolbar; backdrop, spotlight, and
   tooltip are mounted to <body> by the engine in site.js when
   the tour starts. */
.tour-trigger{
  appearance:none;border:0;cursor:pointer;
  width:36px;height:36px;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(11,18,32,.04);color:var(--muted);
  font:inherit;font-size:1rem;font-weight:600;
  transition:background .2s var(--ease),color .2s var(--ease);
  align-self:center;
}
.tour-trigger:hover,
.tour-trigger:focus-visible{
  background:var(--accent-2);color:#fff;outline:none;
}
.dark .tour-trigger{background:rgba(255,255,255,.06);color:rgba(255,255,255,.85)}
.dark .tour-trigger:hover,
.dark .tour-trigger:focus-visible{background:var(--accent-2);color:#fff}

/* The `+` join-trigger is styled as a primary CTA, not as a hint
   button. It reads as the bright sibling next to the muted `?`. */
.tour-trigger-cta{
  background:var(--accent);color:#fff;
  font-size:1.15rem;
}
.tour-trigger-cta:hover,
.tour-trigger-cta:focus-visible{
  background:var(--accent-2);color:#fff;transform:translateY(-1px);
}
.dark .tour-trigger-cta{background:var(--accent);color:#fff}
.dark .tour-trigger-cta:hover,
.dark .tour-trigger-cta:focus-visible{background:var(--accent-2)}

/* Tour backdrop */
.tour-backdrop{
  position:fixed;inset:0;z-index:100;
  background:rgba(11,18,32,.55);
  opacity:0;pointer-events:none;
  transition:opacity .25s var(--ease);
}
.tour-backdrop.is-visible{opacity:1;pointer-events:auto}

/* Spotlight: a glowing ring around the highlighted target */
.tour-spotlight{
  position:fixed;z-index:101;
  border-radius:12px;
  pointer-events:none;
  box-shadow:
    0 0 0 3px rgba(10,132,255,.9),
    0 0 0 10px rgba(10,132,255,.35),
    0 0 30px 4px rgba(10,132,255,.45);
  transition:top .28s var(--ease),left .28s var(--ease),
             width .28s var(--ease),height .28s var(--ease);
}

/* Tooltip card */
.tour-tooltip{
  position:fixed;z-index:102;
  background:#ffffff;color:var(--ink);
  border-radius:14px;
  padding:18px 22px 16px;
  box-shadow:
    0 18px 50px rgba(11,18,32,.22),
    0 1px 3px rgba(11,18,32,.10);
  max-width:360px;
  font-size:.92rem;line-height:1.5;
  border:1px solid var(--line);
}
.dark .tour-tooltip{
  background:#1a2434;color:var(--ink);
  border-color:rgba(255,255,255,.10);
}
.tour-tooltip .tour-title{
  font-family:'Lexend','Inter',sans-serif;
  font-size:1.05rem;font-weight:600;letter-spacing:-.01em;
  margin:0 0 6px;color:var(--ink);
}
.tour-tooltip .tour-body{
  margin:0 0 14px;color:var(--ink-2);
}
.tour-tooltip .tour-footer{
  display:flex;justify-content:space-between;align-items:center;gap:10px;
  flex-wrap:wrap;
}
.tour-tooltip .tour-progress{
  font-size:.78rem;color:var(--muted);letter-spacing:.04em;text-transform:uppercase;font-weight:600;
}
.tour-tooltip .tour-actions{display:flex;gap:6px;flex-wrap:wrap}
.tour-btn{
  appearance:none;border:0;cursor:pointer;
  font:inherit;font-size:.85rem;font-weight:600;
  padding:7px 14px;border-radius:999px;
  transition:background .2s var(--ease),color .2s var(--ease),transform .2s var(--ease);
}
.tour-btn:focus-visible{outline:2px solid var(--accent-2);outline-offset:2px}
.tour-btn-primary{background:var(--accent);color:#fff}
.tour-btn-primary:hover{background:var(--accent-2)}
.tour-btn-ghost{background:transparent;color:var(--muted)}
.tour-btn-ghost:hover{background:rgba(11,18,32,.06);color:var(--ink)}
.dark .tour-btn-ghost:hover{background:rgba(255,255,255,.08);color:#fff}

/* Mobile: tooltip spans almost the full viewport. */
@media (max-width: 640px){
  .tour-tooltip{
    max-width:none;
    width:calc(100vw - 24px) !important;
    left:12px !important;right:12px;
    font-size:.88rem;
  }
}

/* Reduced motion: instant transitions for both spotlight and backdrop. */
@media (prefers-reduced-motion: reduce){
  .tour-backdrop,
  .tour-spotlight{transition:none}
}

/* ─── Welcome strip on the directory ──────────────────────────
   Shown once to first-time visitors above the directory toolbar.
   Dismiss is sticky via localStorage('netsec-directory-tour-seen').
   Returning visitors never see it; the next PR will add a `?`
   button in the toolbar that can re-open the tour from scratch. */
.welcome-strip{
  position:relative;
  margin:0 0 18px;
  padding:18px 56px 18px 22px;
  border-radius:14px;
  border-left:3px solid var(--accent-2);
  /* Subtle EU-blue tinted background so it reads as a temporary
     interstitial rather than blending into the toolbar below. */
  background:linear-gradient(180deg, rgba(10,132,255,.07), rgba(10,132,255,.02));
  animation:welcome-fade-in .28s var(--ease) both;
}
.welcome-strip[hidden]{display:none}
.dark .welcome-strip{
  background:linear-gradient(180deg, rgba(10,132,255,.14), rgba(10,132,255,.05));
}
@media (prefers-reduced-motion: reduce){
  .welcome-strip{animation:none}
}
@keyframes welcome-fade-in{
  from{opacity:0;transform:translateY(-4px)}
  to{opacity:1;transform:translateY(0)}
}
.welcome-strip-title{
  font-family:'Lexend','Inter',sans-serif;
  font-size:1.05rem;font-weight:600;letter-spacing:-.01em;
  margin:0 0 4px;color:var(--ink);
}
.welcome-strip-lede{
  margin:0 0 10px;color:var(--ink-2);font-size:.92rem;line-height:1.5;
  max-width:62ch;
}
.welcome-strip-tips{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:4px 18px;
  font-size:.88rem;color:var(--ink-2);line-height:1.45;
}
.welcome-strip-tips li{margin:0;padding:0}
.welcome-strip-tips li::marker{content:""}
.welcome-strip-tips strong{color:var(--ink);font-weight:600}
.welcome-strip-actions{
  display:flex;gap:8px;align-items:center;
  margin-top:14px;
  flex-wrap:wrap;
}
.welcome-strip-dismiss{
  appearance:none;border:0;cursor:pointer;
  background:transparent;color:var(--muted);
  font:inherit;font-size:.85rem;font-weight:600;
  padding:7px 14px;border-radius:999px;
  transition:background .2s var(--ease),color .2s var(--ease);
}
.welcome-strip-dismiss:hover,
.welcome-strip-dismiss:focus-visible{
  background:rgba(11,18,32,.06);color:var(--ink);outline:none;
}
.dark .welcome-strip-dismiss:hover,
.dark .welcome-strip-dismiss:focus-visible{
  background:rgba(255,255,255,.10);color:#fff;
}

/* ─── Compact directory mode ──────────────────────────────────
   A higher-density layout for the directory: each member becomes
   a single-row card (initials/photo on the left, name + affiliation
   + WG chips stacked on the right), with bio and contact icons
   hidden. Tighter grid (~3 cards across on a desktop, vs ~2 in the
   detailed view). Toggled via the .is-compact class on the grid,
   set by the view-mode toggle in the toolbar. Preference persists
   in localStorage.

   Every compact rule is scoped to `.member-card:not(.is-expanded)`
   so that one clicked card can revert to its detailed form
   in-place while the rest of the grid stays compact. See the
   `.is-expanded` block further down. */
.members-grid.is-compact{
  grid-template-columns:repeat(auto-fill, minmax(min(280px,100%), 1fr));
  gap:12px;
}
.members-grid.is-compact .member-card:not(.is-expanded){
  flex-direction:row;
  padding:12px 14px;
  gap:14px;
  align-items:center;
  cursor:pointer;            /* hint that clicking will expand */
}
.members-grid.is-compact .member-card:not(.is-expanded):hover{
  background:rgba(255,255,255,.04);
}
.members-grid.is-compact .member-card:not(.is-expanded):focus-visible{
  outline:2px solid var(--accent-2);outline-offset:2px;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-photo{
  width:46px;height:46px;
  margin:0;flex-shrink:0;
  border-width:1px;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-photo-fallback{
  font-size:.95rem;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-body{
  align-items:flex-start;text-align:left;
  flex:1;min-width:0;        /* min-width:0 lets the affiliation truncate */
  gap:2px;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-name{
  font-size:.95rem;margin:0;line-height:1.25;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-role{
  font-size:.66rem;margin:1px 0 0;letter-spacing:.04em;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-affiliation{
  font-size:.78rem;margin:0;line-height:1.35;
  justify-content:flex-start;
  /* Single line, with ellipsis when an affiliation runs long. */
  display:flex;flex-wrap:nowrap;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;
}
/* Compact mode drops position + country in full; the flag
   still conveys country implicitly and the affiliation is the
   one piece every card needs at a glance. */
.members-grid.is-compact .member-card:not(.is-expanded) .member-affiliation .aff-full{display:none}
.members-grid.is-compact .member-card:not(.is-expanded) .member-affiliation .aff-compact{display:inline}
.members-grid.is-compact .member-card:not(.is-expanded) .member-wgs{
  margin:4px 0 0;justify-content:flex-start;
}
.members-grid.is-compact .member-card:not(.is-expanded) .member-bio,
.members-grid.is-compact .member-card:not(.is-expanded) .member-bio-toggle,
.members-grid.is-compact .member-card:not(.is-expanded) .member-contact{
  display:none !important;
}

/* Click-to-expand: in compact mode, one card at a time can revert
   to the detailed layout in-place. Triggered by a click anywhere
   on the card (delegated handler in people.html), Enter/Space on a
   focused card, or a #slug hash in the URL. Esc collapses. */
.members-grid.is-compact .member-card.is-expanded{
  /* Spans two grid columns where the grid is wide enough to have
     them — gives the expanded card the room of a detailed one. */
  grid-column:span 2;
  cursor:default;
  outline:2px solid var(--accent-2);
  outline-offset:0;
  box-shadow:0 12px 30px rgba(11,18,32,.16);
}
.members-grid.is-compact .member-card.is-expanded:focus-visible{
  outline:3px solid var(--accent-2);
}
/* Make sure single-column grids (narrow viewports) don't try to
   span past the available columns. */
@media (max-width: 640px){
  .members-grid.is-compact .member-card.is-expanded{grid-column:auto}
}

/* Expand/collapse affordance on compact directory cards.
   Without it, visitors don't know that compact cards can be clicked
   to expand. A small chevron sits at the bottom-right of each card
   — pointing ▼ when the card is collapsed, rotating to ▲ when it's
   expanded. Hidden in detailed mode (no toggle behaviour there).
   `pointer-events: none` so the chevron never absorbs the click —
   the whole card is the hit target (delegated handler in
   people.html). */
/* css-collision-allow: .member-card */
.member-card{position:relative}
.member-toggle-chevron{display:none}
.members-grid.is-compact .member-toggle-chevron{
  display:grid;place-items:center;
  position:absolute;bottom:10px;right:12px;
  width:24px;height:24px;border-radius:50%;
  background:rgba(255,255,255,.65);
  border:1px solid var(--glass-border);
  color:var(--muted);
  pointer-events:none;
  transition:transform .25s var(--ease),background .2s var(--ease),color .2s var(--ease),border-color .2s var(--ease);
}
.dark .members-grid.is-compact .member-toggle-chevron{
  background:rgba(28,32,46,.55);
}
.members-grid.is-compact .member-toggle-chevron svg{width:14px;height:14px;display:block}
.members-grid.is-compact .member-card:hover .member-toggle-chevron{
  color:var(--accent);
  border-color:rgba(0,51,153,.30);
}
.dark .members-grid.is-compact .member-card:hover .member-toggle-chevron{
  color:#a9c2ff;
  border-color:rgba(110,161,255,.36);
}
.members-grid.is-compact .member-card.is-expanded .member-toggle-chevron{
  transform:rotate(180deg);
  color:var(--accent-2);
  border-color:rgba(10,132,255,.36);
  background:rgba(255,255,255,.85);
}
.dark .members-grid.is-compact .member-card.is-expanded .member-toggle-chevron{
  background:rgba(28,32,46,.75);
}
@media (prefers-reduced-motion: reduce){
  .members-grid.is-compact .member-toggle-chevron{transition:none}
}

/* View-mode toggle (segmented control in the toolbar) */
.view-toggle{
  display:inline-flex;
  border-radius:999px;
  background:rgba(11,18,32,.04);
  padding:3px;
  gap:2px;
  align-self:center;
}
.dark .view-toggle{background:rgba(255,255,255,.06)}
.view-toggle button{
  appearance:none;border:0;background:transparent;cursor:pointer;
  width:30px;height:30px;
  border-radius:999px;
  display:grid;place-items:center;color:var(--muted);
  transition:background .2s var(--ease),color .2s var(--ease);
}
.view-toggle button[aria-pressed="true"]{
  background:#ffffff;color:var(--accent);
  box-shadow:0 1px 2px rgba(11,18,32,.10);
}
.dark .view-toggle button[aria-pressed="true"]{
  background:rgba(255,255,255,.14);color:#fff;
}
.view-toggle button:hover:not([aria-pressed="true"]){color:var(--ink-2)}
.view-toggle button svg{width:16px;height:16px}

@media (max-width:540px){
  .people-page{padding:120px 0 60px}
  .members-toolbar{padding:12px 14px}
  .members-grid{grid-template-columns:1fr}
  .member-card{padding:20px}
}

/* Network-directory: soft "Network member" pill for cards without a
   formal role, and the "Join the network" CTA card. */
.member-card .member-role.is-soft{
  color:var(--muted);
  font-weight:600;
  letter-spacing:.05em;
}
.join-card{
  margin:48px auto 0;
  max-width:680px;
  padding:36px 32px;
  text-align:center;
  scroll-margin-top:100px;
}
.join-card h2{
  font-size:clamp(1.4rem,2.5vw,1.8rem);
  margin:0 0 .6rem;
  letter-spacing:-.02em;
}
.join-card p{
  margin:0 auto 1.2rem;
  max-width:54ch;
  color:var(--ink-2);
  font-size:1rem;
  line-height:1.55;
}
.join-card-cta{margin-top:6px}
.join-card-fineprint{
  margin-top:1.2rem !important;
  font-size:.85rem;
  color:var(--muted) !important;
}

/* -------- About > Find out more cards --------
   A four-card grid appended to the About section: short signposts
   to the FAQ, glossary, press kit, and members' Wiki. Lighter
   visual weight than .wg-card — these are reference shortcuts. */
.find-out-more{
  margin-top:48px;
  padding-top:32px;
  border-top:1px solid var(--line);
}
.find-out-more-head{
  margin:0 0 18px;
  font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);font-weight:700;text-align:center;
}
.find-out-more-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));
  gap:16px;
}
.find-card{
  padding:22px 22px 24px;
  display:flex;flex-direction:column;gap:10px;
  text-decoration:none;color:inherit;
  transition:transform .2s var(--ease),background .2s var(--ease);
}
.find-card:hover{
  transform:translateY(-2px);
  background:rgba(255,255,255,.78);
}
.dark .find-card:hover{background:rgba(28,32,46,.78)}
.find-card-icon{
  width:36px;height:36px;border-radius:10px;display:grid;place-items:center;
  background:linear-gradient(135deg,rgba(0,51,153,.10),rgba(10,132,255,.10));
  color:var(--accent);
}
.find-card-icon svg{width:18px;height:18px}
.find-card h3{
  margin:0;font-size:1rem;letter-spacing:-.005em;
  font-family:'Lexend','Inter',sans-serif;
}
.find-card p{margin:0;font-size:.86rem;color:var(--muted);line-height:1.5}

/* -------- For NetSec members (Wiki signposting) --------
   Sits between Outputs and Contact on the home page. Visually
   distinct (lightly tinted) so members notice it on first scroll. */
.members-strip{padding:60px 0}
.members-strip .members-card{
  padding:36px 40px;
  display:grid;
  grid-template-columns:1fr auto;
  gap:24px;align-items:center;
  background:
    linear-gradient(135deg,rgba(0,51,153,.06),rgba(10,132,255,.04)),
    var(--glass-bg-strong);
  border:1px solid var(--line);
  border-radius:16px;
}
.dark .members-strip .members-card{
  background:
    linear-gradient(135deg,rgba(10,132,255,.10),rgba(0,51,153,.05)),
    rgba(28,32,46,.6);
}
.members-strip .eyebrow{
  display:inline-block;
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--accent);font-weight:700;margin:0 0 8px;
}
.members-strip h2{
  margin:0 0 .4rem;
  font-size:clamp(1.3rem,2.2vw,1.6rem);
  letter-spacing:-.015em;
}
.members-strip p{
  margin:0;color:var(--ink-2);font-size:.97rem;line-height:1.55;
  max-width:62ch;
}
.members-strip .members-actions{
  display:flex;flex-direction:column;gap:8px;align-items:stretch;
  min-width:200px;
}
.members-strip .members-actions a{
  display:flex;align-items:center;justify-content:center;gap:8px;
  padding:11px 18px;border-radius:10px;
  font-size:.92rem;font-weight:600;text-decoration:none;
  white-space:nowrap;
  transition:transform .15s var(--ease),background .15s var(--ease);
}
.members-strip .members-actions a.primary{
  background:var(--accent);color:#fff;
}
.members-strip .members-actions a.primary:hover{
  background:var(--accent-2);transform:translateY(-1px);
}
.members-strip .members-actions a.secondary{
  background:rgba(255,255,255,.6);color:var(--ink);
  border:1px solid var(--line);
}
.dark .members-strip .members-actions a.secondary{background:rgba(255,255,255,.05);color:var(--ink)}
.members-strip .members-actions a.secondary:hover{
  background:rgba(255,255,255,.85);
}
.dark .members-strip .members-actions a.secondary:hover{background:rgba(255,255,255,.12)}
@media (max-width: 700px){
  .members-strip .members-card{
    grid-template-columns:1fr;
    padding:28px 24px;
  }
  .members-strip .members-actions{min-width:0}
}

/* ════════════════════════════════════════════════════════════════
   Site-wide search overlay
   ────────────────────────────────────────────────────────────────
   Modal dialog triggered by Cmd-K / Ctrl-K / "/" / .search-trigger
   button in the nav. Glassmorphic panel anchored to the top third
   of the viewport, with a list of result cards underneath an input.
   ════════════════════════════════════════════════════════════════ */
.search-trigger{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:9px;
  background:transparent;border:1px solid var(--line);
  color:var(--ink-2);cursor:pointer;
  transition:background .15s var(--ease),border-color .15s var(--ease),color .15s var(--ease);
}
.search-trigger:hover{background:var(--glass-bg);border-color:var(--accent);color:var(--ink)}
.search-trigger svg{width:16px;height:16px}
/* The ⌘K hint badge was previously visible above 880 px viewport, but
   it pushed the nav-actions cluster past the floating-header bubble
   on the home page (10 nav links + brand + actions = tight at 1200 px
   max-width). The badge is hidden by default; the keyboard shortcut
   is still discoverable via the button's `title` tooltip and via
   the *open* row inside the search overlay. */
.search-trigger kbd{display:none}

body.search-open{overflow:hidden}

.search-overlay{
  position:fixed;inset:0;z-index:1000;
  display:flex;align-items:flex-start;justify-content:center;
  padding:80px 16px 16px;
}
.search-overlay[hidden]{display:none}
.search-backdrop{
  position:absolute;inset:0;
  background:rgba(10,18,40,.45);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  animation:search-fade-in .15s var(--ease);
}
.dark .search-backdrop{background:rgba(0,4,12,.65)}
@keyframes search-fade-in{from{opacity:0}to{opacity:1}}

.search-panel{
  position:relative;
  width:min(640px,100%);
  max-height:min(calc(100vh - 96px),700px);
  display:flex;flex-direction:column;
  border-radius:16px;
  padding:0;
  animation:search-slide-in .18s var(--ease);
  overflow:hidden;
}
@keyframes search-slide-in{
  from{opacity:0;transform:translateY(-8px)}
  to{opacity:1;transform:translateY(0)}
}
@media (prefers-reduced-motion: reduce){
  .search-backdrop,.search-panel{animation:none}
}

.search-header{
  display:flex;align-items:center;gap:10px;
  padding:14px 16px;border-bottom:1px solid var(--line);
}
.search-input-icon{
  width:18px;height:18px;color:var(--muted);flex-shrink:0;
}
.search-input{
  flex:1;min-width:0;
  border:0;outline:0;background:transparent;
  font:500 1.05rem/1.3 'Inter',sans-serif;
  color:var(--ink);
}
.search-input::placeholder{color:var(--muted)}
.search-close{
  flex-shrink:0;
  width:32px;height:32px;border-radius:8px;
  border:0;background:transparent;
  color:var(--muted);cursor:pointer;
  display:grid;place-items:center;
  transition:background .15s var(--ease),color .15s var(--ease);
}
.search-close:hover{background:var(--glass-bg);color:var(--ink)}
.search-close svg{width:16px;height:16px}

.search-meta{
  padding:10px 18px;
  font-size:.8rem;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted);font-weight:600;
}

.search-results{
  list-style:none;padding:0;margin:0;
  overflow-y:auto;flex:1;
  border-top:1px solid var(--line);
}
.search-results li{margin:0;padding:0}
.search-results a{
  display:block;
  padding:14px 18px;
  text-decoration:none;color:inherit;
  border-bottom:1px solid var(--line);
  transition:background .12s var(--ease);
}
.search-results li:last-child a{border-bottom:0}
.search-results a:hover,
.search-results li.is-active a{
  background:linear-gradient(90deg,rgba(10,132,255,.10),rgba(10,132,255,.03));
}
.dark .search-results a:hover,
.dark .search-results li.is-active a{
  background:linear-gradient(90deg,rgba(10,132,255,.18),rgba(10,132,255,.04));
}
.search-result-head{
  display:flex;align-items:baseline;flex-wrap:wrap;gap:0 8px;
  font-size:.88rem;color:var(--muted);
  margin-bottom:4px;
}
.search-result-title{
  font-weight:600;color:var(--accent);
}
.search-result-sep{color:var(--muted);opacity:.6}
.search-result-section{color:var(--ink-2)}
.search-result-excerpt{
  font-size:.94rem;line-height:1.5;color:var(--ink);
}
.search-result-excerpt mark{
  background:rgba(255,204,0,.35);
  color:inherit;padding:0 2px;border-radius:3px;
}
.dark .search-result-excerpt mark{background:rgba(255,204,0,.22)}

/* Directory-bio result card. Used for hits whose Pagefind meta
   reports `kind:bio` — the search/bios/<lang>/<slug>.html stubs
   generated from data/bios.json by scripts/build-bio-search-stubs.
   The card uses the avatar + flag + WG chip language already
   established on the Network page, so a name search reads as
   "directory entry" at a glance, distinct from a page-content hit. */
.search-bio a{
  display:flex;align-items:center;gap:14px;
  padding:12px 18px;
}
.search-bio-photo{
  flex-shrink:0;
  width:48px;height:48px;border-radius:50%;
  object-fit:cover;
  background:linear-gradient(135deg,#cfd9ee,#e8d8c2);
  border:2px solid rgba(255,255,255,.7);
  box-shadow:0 1px 3px rgba(0,0,0,.08);
}
.dark .search-bio-photo{border-color:rgba(255,255,255,.15)}
.search-bio-photo-fallback{
  display:grid;place-items:center;
  color:var(--accent);font-weight:700;font-size:1rem;letter-spacing:.04em;
}
.search-bio-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.search-bio-head{display:flex;align-items:center;gap:8px}
.search-bio-name{
  font-weight:600;font-size:1rem;color:var(--ink);letter-spacing:-.01em;
  font-family:'Lexend','Inter',sans-serif;
}
.search-bio-flag{
  width:18px;height:14px;border-radius:2px;flex-shrink:0;
  box-shadow:0 0 0 1px rgba(0,0,0,.08);
}
.search-bio-subline,
.search-bio-affiliation{
  font-size:.85rem;color:var(--ink-2);line-height:1.4;
  overflow:hidden;text-overflow:ellipsis;
}
.search-bio-affiliation{color:var(--muted)}
.search-bio-wgs{display:flex;gap:4px;flex-wrap:wrap;margin-top:2px}
.search-bio-wg{
  font-size:.7rem;font-weight:700;letter-spacing:.04em;
  padding:2px 8px;border-radius:999px;
  background:rgba(10,132,255,.10);color:var(--accent);
}
.dark .search-bio-wg{background:rgba(10,132,255,.18)}

.search-hints{
  display:flex;flex-wrap:wrap;gap:6px 14px;
  padding:10px 18px;
  border-top:1px solid var(--line);
  font-size:.78rem;color:var(--muted);
}
.search-hints kbd{
  font:600 .7rem/1 'Inter',sans-serif;
  padding:2px 6px;border-radius:4px;
  background:rgba(0,0,0,.05);border:1px solid var(--line);
  color:var(--ink-2);
}
.dark .search-hints kbd{background:rgba(255,255,255,.06)}

@media (max-width: 520px){
  .search-overlay{padding:24px 12px 12px}
  .search-hints{display:none}
}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* -------- Public roadmap page (/roadmap.html) --------
   Visual timeline with colour-coded status pills. Companion to
   docs/roadmap-2026.md, intentionally simpler and audience-facing. */
.roadmap-page{padding:140px 0 80px}
.roadmap-page .container{max-width:920px}
.roadmap-page h1{
  font-size:clamp(2.4rem,4.6vw,3.4rem);margin:0 0 1rem;letter-spacing:-.02em;
  background:linear-gradient(180deg,var(--ink) 0%,#3a4a6b 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.dark .roadmap-page h1{
  background:linear-gradient(180deg,#f4f8ff 0%,#aeb7d6 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.roadmap-page .lede{
  font-size:1.1rem;color:var(--ink-2);max-width:65ch;
  margin:0 0 8px;line-height:1.55;
}
.roadmap-updated{
  font-size:.85rem;color:var(--muted);margin:0 0 32px;
}

/* Legend strip — colour key for the four statuses */
.rm-legend{
  display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center;
  padding:14px 18px;margin:0 0 40px;border-radius:14px;
  background:var(--glass-bg-strong);border:1px solid var(--line);
}
.rm-legend-label{
  font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-right:4px;
}

/* Status pill (shipped / in-progress / planned / deferred) */
.rm-pill{
  display:inline-flex;align-items:center;gap:7px;
  padding:5px 11px;border-radius:999px;
  font-size:.74rem;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;
  border:1px solid transparent;line-height:1.2;
  font-family:'Lexend','Inter',sans-serif;
}
.rm-pill .dot{
  width:7px;height:7px;border-radius:50%;background:currentColor;
  flex-shrink:0;box-shadow:0 0 0 2px rgba(255,255,255,.4);
}
.rm-pill.shipped{
  background:rgba(22,163,74,.12);color:#15803d;
  border-color:rgba(22,163,74,.30);
}
.rm-pill.in-progress{
  background:rgba(10,132,255,.12);color:#0a6cff;
  border-color:rgba(10,132,255,.30);
}
.rm-pill.planned{
  background:rgba(99,102,241,.10);color:#5a5fd6;
  border-color:rgba(99,102,241,.26);
}
.rm-pill.deferred{
  background:rgba(245,158,11,.14);color:#b45309;
  border-color:rgba(245,158,11,.32);
}
.dark .rm-pill.shipped{color:#4ade80;background:rgba(22,163,74,.18)}
.dark .rm-pill.in-progress{color:#7dd3fc;background:rgba(10,132,255,.18)}
.dark .rm-pill.planned{color:#a5b4fc;background:rgba(99,102,241,.18)}
.dark .rm-pill.deferred{color:#fbbf24;background:rgba(245,158,11,.18)}

/* Quarter heading band */
.rm-quarter{
  margin:44px 0 18px;display:flex;flex-wrap:wrap;align-items:baseline;gap:12px;
  padding-bottom:8px;border-bottom:1px solid var(--line);
}
.rm-quarter h2{
  font-size:1.35rem;letter-spacing:-.01em;margin:0;
  font-family:'Lexend','Inter',sans-serif;font-weight:600;color:var(--ink);
}
.rm-quarter .sub{
  font-size:.72rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);
}

/* Timeline (vertical, single column) */
.rm-timeline{
  position:relative;margin:0;padding:8px 0 8px 36px;list-style:none;
}
.rm-timeline::before{
  content:'';position:absolute;left:13px;top:6px;bottom:6px;width:2px;
  background:linear-gradient(180deg,var(--line) 0%,var(--line) 90%,transparent 100%);
  border-radius:2px;
}
.rm-entry{position:relative;margin:0 0 18px;padding:0}
.rm-entry:last-child{margin-bottom:0}
/* Marker is vertically centred on the status-pill row.
   Pill row sits at the top of the card (.rm-card has padding-top:16px);
   the pill is ~24px tall, so its visual centre lands ~28px below the
   card top. The marker top values below put each shape's centre at 28px:
     circle (18×18)   → top:19px  → centre 28px
     diamond (14×14)  → top:21px  → geometric centre 28px (rotated 45°) */
.rm-entry::before{
  content:'';position:absolute;left:-34px;top:19px;
  width:18px;height:18px;border-radius:50%;
  background:var(--accent);
  border:3px solid var(--bg-0);
  box-shadow:0 0 0 1px var(--line);
  z-index:1;
}
.rm-entry.shipped::before{background:#22c55e}
.rm-entry.in-progress::before{
  background:#0a84ff;
  box-shadow:0 0 0 1px var(--line),0 0 0 5px rgba(10,132,255,.18);
}
.rm-entry.planned::before{background:#8b8fe8}
.rm-entry.deferred::before{background:#f59e0b}
.rm-entry.rm-milestone::before{
  width:14px;height:14px;left:-32px;top:21px;
  background:var(--ink);border-radius:3px;transform:rotate(45deg);
  border-width:2px;
}
.dark .rm-entry::before{border-color:var(--bg-0)}
.dark .rm-entry.rm-milestone::before{background:#cbd5e1}

/* Collapsed shipped section. JS injects a toggle <li> at the top of
   any rm-timeline that contains shipped entries and sets
   data-shipped-state="collapsed" on the parent <ol>. The CSS below
   hides only entries marked .shipped, leaving in-progress, planned,
   and milestone entries visible. */
.rm-timeline[data-shipped-state="collapsed"] > .rm-entry.shipped{
  display:none;
}
/* The toggle itself sits in the timeline gutter like a regular entry
   but without the marker dot or the connector — it's chrome, not
   content. */
.rm-shipped-toggle{
  position:relative;
  list-style:none;
  margin:0 0 14px;
  padding:0;
}
.rm-shipped-toggle::before,
.rm-shipped-toggle::marker{content:none}
.rm-shipped-btn{
  display:inline-flex;
  align-items:center;
  gap:8px;
  padding:7px 14px;
  border:1px solid var(--line);
  border-radius:999px;
  background:transparent;
  color:var(--ink-2);
  font:inherit;
  font-size:.86rem;
  font-weight:500;
  cursor:pointer;
  transition:background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}
.rm-shipped-btn:hover,
.rm-shipped-btn:focus-visible{
  background:var(--glass-bg);
  border-color:var(--accent-2);
  color:var(--accent-2);
  opacity:1;
}
.rm-shipped-chevron{
  width:14px;height:14px;
  flex-shrink:0;
  transition:transform .2s var(--ease);
}
.rm-shipped-btn[aria-expanded="true"] .rm-shipped-chevron{
  transform:rotate(180deg);
}
@media (prefers-reduced-motion: reduce){
  .rm-shipped-chevron{transition:none}
}
@media print{
  /* Print should show the full history. */
  .rm-shipped-toggle{display:none}
  .rm-timeline[data-shipped-state="collapsed"] > .rm-entry.shipped{display:list-item}
}

.rm-card{
  padding:16px 20px;border-radius:14px;
  background:var(--glass-bg-strong);border:1px solid var(--line);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease),border-color .25s var(--ease);
}
.rm-card:hover{
  transform:translateY(-1px);
  box-shadow:0 8px 22px rgba(11,18,32,.07);
  border-color:rgba(0,51,153,.18);
}
.dark .rm-card:hover{box-shadow:0 8px 22px rgba(0,0,0,.35)}
/* "Milestone" cards on the public roadmap = Action events (Conference,
   MC plenary, Year-1 anniversary) — read as different from release
   cards via the diamond-shaped marker dot + a soft dashed border. The
   class is named `.rm-milestone` (NOT `.milestone`) to avoid colliding
   with the pre-existing `.milestone` pill used in the Gantt chart,
   which paints a saturated EU-blue → Apple-blue gradient directly on
   whichever element carries the class. That collision was the cause
   of the "milestone cards render as a strong blue panel with
   unreadable text" regression in PRs #95 / #97. */
.rm-entry.rm-milestone .rm-card{
  border-style:dashed;
  border-color:rgba(0,51,153,.22);
}
.dark .rm-entry.rm-milestone .rm-card{
  border-color:rgba(110,161,255,.30);
}
.rm-head{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:6px;
}
.rm-head .when{
  font-size:.82rem;font-weight:600;color:var(--muted);
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
}
.rm-card h3{
  margin:0 0 6px;font-size:1.02rem;letter-spacing:-.01em;
  color:var(--ink);font-family:'Lexend','Inter',sans-serif;font-weight:600;
  line-height:1.35;
}
.rm-card p{
  margin:0;font-size:.93rem;color:var(--ink-2);line-height:1.55;
}
.rm-card .notes-link{
  display:inline-block;margin-top:8px;font-size:.85rem;
  color:var(--accent-2);text-decoration:none;
  border-bottom:1px solid transparent;transition:border-color .2s var(--ease);
}
.rm-card .notes-link:hover{border-bottom-color:currentColor}

/* Considering-for-later — deferred / under-watch items */
.rm-later{
  margin-top:56px;padding:24px 26px;border-radius:16px;
  background:var(--glass-bg-strong);border:1px solid var(--line);
}
.rm-later h2{
  margin:0 0 .4rem;font-size:1.25rem;letter-spacing:-.01em;
  font-family:'Lexend','Inter',sans-serif;font-weight:600;color:var(--ink);
}
.rm-later > p{
  margin:0 0 16px;font-size:.92rem;color:var(--ink-2);line-height:1.55;max-width:60ch;
}
.rm-later-list{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:14px;margin:0;padding:0;list-style:none;
}
.rm-later-item{
  padding:14px 16px;border-radius:12px;
  background:rgba(245,158,11,.05);
  border:1px solid rgba(245,158,11,.22);
}
.dark .rm-later-item{background:rgba(245,158,11,.08);border-color:rgba(245,158,11,.30)}
.rm-later-item-head{
  display:flex;align-items:center;gap:8px;margin-bottom:6px;flex-wrap:wrap;
}
.rm-later-item h3{
  margin:0;font-size:.96rem;font-weight:600;
  font-family:'Lexend','Inter',sans-serif;color:var(--ink);letter-spacing:-.005em;
}
.rm-later-item p{
  margin:0;font-size:.86rem;color:var(--ink-2);line-height:1.5;
}

/* Roadmap signpost — small accent callout that sits at the foot of
   the Deliverables section on /about.html. Frames the public roadmap
   as the website + directory counterpart to the Action's
   deliverables timeline (the Gantt above). Stakeholders who arrive
   on /about.html for the deliverables view also see "here's the
   shipping cadence on the website itself". */
.deliverables-roadmap-link{
  margin:28px 0 0;
  padding:18px 22px;
  display:flex;flex-wrap:wrap;align-items:center;gap:14px;
  border-radius:14px;
  background:linear-gradient(135deg,rgba(0,51,153,.06),rgba(10,132,255,.04));
  border:1px solid rgba(10,132,255,.20);
}
.dark .deliverables-roadmap-link{
  background:linear-gradient(135deg,rgba(110,161,255,.10),rgba(10,132,255,.06));
  border-color:rgba(110,161,255,.30);
}
.deliverables-roadmap-link-icon{
  width:36px;height:36px;flex-shrink:0;border-radius:10px;
  display:grid;place-items:center;color:var(--accent);
  background:linear-gradient(135deg,rgba(0,51,153,.12),rgba(10,132,255,.12));
}
.deliverables-roadmap-link-icon svg{width:18px;height:18px}
.deliverables-roadmap-link-text{
  flex:1 1 320px;min-width:0;
  font-size:.95rem;color:var(--ink-2);line-height:1.5;
}
.deliverables-roadmap-link-text strong{color:var(--ink)}
.deliverables-roadmap-link-cta{
  flex-shrink:0;
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 16px;border-radius:10px;
  font-size:.92rem;font-weight:600;color:#fff;
  background:var(--accent);border:1px solid var(--accent);
  text-decoration:none;
  box-shadow:0 4px 12px var(--accent-glow);
  transition:background .2s var(--ease),border-color .2s var(--ease),transform .2s var(--ease);
}
.deliverables-roadmap-link-cta:hover{
  background:var(--accent-2);border-color:var(--accent-2);
  transform:translateY(-1px);
  box-shadow:0 6px 16px var(--accent-glow);
}
@media (prefers-reduced-motion: reduce){
  .deliverables-roadmap-link-cta{transition:none}
  .deliverables-roadmap-link-cta:hover{transform:none}
}

/* "Help shape this" card — invites community feedback / feature
   requests / issue reports via GitHub. Sits between the under-watch
   section and the docs footnote so the page closes on a participatory
   note rather than a one-way announcement. */
.rm-feedback{
  margin-top:36px;padding:24px 26px;border-radius:16px;
  background:linear-gradient(135deg,rgba(0,51,153,.06),rgba(10,132,255,.04));
  border:1px solid rgba(10,132,255,.20);
}
.dark .rm-feedback{
  background:linear-gradient(135deg,rgba(110,161,255,.10),rgba(10,132,255,.06));
  border-color:rgba(110,161,255,.30);
}
.rm-feedback h2{
  margin:0 0 .4rem;font-size:1.25rem;letter-spacing:-.01em;
  font-family:'Lexend','Inter',sans-serif;font-weight:600;color:var(--ink);
}
.rm-feedback > p{
  margin:0 0 18px;font-size:.95rem;color:var(--ink-2);line-height:1.55;max-width:60ch;
}
.rm-feedback-actions{
  display:flex;flex-wrap:wrap;gap:10px;
}
.rm-feedback-action{
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 16px;border-radius:10px;
  font-size:.92rem;font-weight:600;color:var(--ink);
  background:var(--glass-bg);border:1px solid var(--glass-border);
  text-decoration:none;
  transition:background .2s var(--ease),border-color .2s var(--ease),transform .2s var(--ease);
}
.rm-feedback-action:hover{
  background:var(--glass-bg-strong);
  border-color:rgba(10,132,255,.32);
  transform:translateY(-1px);
}
.rm-feedback-action.is-primary{
  background:var(--accent);border-color:var(--accent);color:#fff;
  box-shadow:0 4px 12px var(--accent-glow);
}
.rm-feedback-action.is-primary:hover{
  background:var(--accent-2);border-color:var(--accent-2);
  box-shadow:0 6px 16px var(--accent-glow);
}
.rm-feedback-action svg{flex-shrink:0;width:16px;height:16px}
@media (prefers-reduced-motion: reduce){
  .rm-feedback-action{transition:none}
  .rm-feedback-action:hover{transform:none}
}

/* Footer note pointing at the internal doc */
.rm-footnote{
  margin:48px 0 0;padding:18px 22px;border-radius:12px;
  background:rgba(0,51,153,.04);border:1px solid rgba(0,51,153,.14);
  font-size:.9rem;color:var(--ink-2);line-height:1.55;
}
.dark .rm-footnote{background:rgba(110,161,255,.08);border-color:rgba(110,161,255,.22)}
.rm-footnote a{color:var(--accent-2);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}

@media (max-width:640px){
  .roadmap-page{padding:120px 0 60px}
  .rm-timeline{padding-left:30px}
  /* Smaller card padding-top on mobile (14px) shifts the pill centre
     to ~26px; mirror that in marker top so centres still line up. */
  .rm-entry::before{left:-30px;width:16px;height:16px;top:18px}
  .rm-entry.in-progress::before{box-shadow:0 0 0 1px var(--line),0 0 0 4px rgba(10,132,255,.18)}
  .rm-entry.rm-milestone::before{left:-28px;width:12px;height:12px;top:20px}
  .rm-card{padding:14px 16px}
  .rm-card h3{font-size:.98rem}
  .rm-legend{padding:12px 14px;gap:8px}
}

@media (prefers-reduced-motion: reduce){
  .rm-card{transition:none}
  .rm-card:hover{transform:none}
}

/* -------- Dark-mode accent-bg CTA contrast fix --------
   In light mode the EU-blue accent (`--accent: #003399`) gives
   ~10.9:1 contrast with white text — solidly above the WCAG AA
   4.5:1 floor. In dark mode `--accent` is `#6ea1ff` (lighter, so
   that accent text reads against the dark page background), and a
   filled button using `background: var(--accent); color: #fff`
   collapses to **2.56:1** — failing AA.

   The dark-mode `.btn-primary` and `.nav-cta` already invert to
   light-bg + dark-text, side-stepping the problem. The CTAs below
   used `var(--accent)` directly with no dark override and silently
   regressed. Pinning their background to the brand EU-blue
   `#003399` in dark mode restores ~10.9:1 contrast while keeping
   the brand colour consistent across both modes (which feels
   right for the badge / pill / link-CTA family — they're more
   "site identity" than "page primary").

   Verified ≥ 4.5:1 with the in-browser contrast helper in
   docs/launch-qa-2026.md Phase 2. */
.dark .event-card.featured .event-date,
.dark .event-subscribe,
.dark #for-members .members-actions .primary,
.dark .tour-btn-primary,
.dark .tour-trigger-cta,
.dark .rm-feedback-action.is-primary,
.dark .deliverables-roadmap-link-cta{
  background:#003399;
  border-color:#003399;
  color:#fff;
}
.dark .event-subscribe:hover,
.dark #for-members .members-actions .primary:hover,
.dark .tour-btn-primary:hover,
.dark .rm-feedback-action.is-primary:hover,
.dark .deliverables-roadmap-link-cta:hover{
  /* Hover deepens to a darker blue (luminance ~0.06 → 11:1 with
     white text). Stays on-brand and passes AA. */
  background:#0a4ed0;
  border-color:#0a4ed0;
  color:#fff;
}

/* -------- ESSC 2026 page (essc-2026.html) -------- */

/* Hero — narrower than the home hero; this isn't the front door. */
.essc-hero{
  padding:140px 0 36px;
  position:relative;
}
.essc-hero h1{
  font-size:clamp(2rem,1.4rem+2.8vw,3.4rem);
  line-height:1.1;
  margin:0 0 1rem;
  background:linear-gradient(120deg,var(--ink) 30%,var(--accent-2) 100%);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
.essc-hero .lede{
  font-size:1.1rem;
  line-height:1.6;
  color:var(--ink-2);
  max-width:46rem;
  margin:0 0 1.6rem;
}

/* Quick facts: 5-cell grid (dates / venue / room / Indico /
   practical info anchor); collapses to 3 on small laptop, 2 on
   tablet, 1 on phone. The fifth cell is the in-page jump to
   #practical, styled like the rest so the strip stays balanced,
   with a small down-arrow on the value to telegraph the jump. */
.essc-quickfacts{
  display:grid;
  grid-template-columns:repeat(5,minmax(0,1fr));
  gap:14px;
  margin-top:1.4rem;
  padding:18px 22px;
  background:var(--glass-bg);
  backdrop-filter:saturate(180%) blur(20px);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  border:1px solid var(--glass-border);
  border-radius:16px;
  box-shadow:var(--glass-shadow);
}
.essc-quickfacts[data-state="loading"]{opacity:.65}
.essc-quickfacts[data-state="error"]{opacity:.5}
.essc-quickfact{display:flex;flex-direction:column;gap:.25rem;min-width:0}
.essc-quickfact .lbl{
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--muted);
}
.essc-quickfact .val{
  font-size:.95rem;
  font-weight:500;
  color:var(--ink);
  overflow-wrap:anywhere;
}
/* Anchor variant of a quick-fact tile. Reads as part of the row,
   value sits in accent colour to mark it as a link, the arrow
   nudges down on hover to telegraph the in-page jump. */
a.essc-quickfact.is-jump{
  text-decoration:none;
  color:inherit;
}
a.essc-quickfact.is-jump .val{
  color:var(--accent-2);
}
a.essc-quickfact.is-jump:hover .essc-quickfact-arrow{
  transform:translateY(2px);
}
.essc-quickfact-arrow{
  display:inline-block;
  transition:transform .2s var(--ease);
  margin-left:.15rem;
}
@media (max-width:980px){
  .essc-quickfacts{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (max-width:780px){
  .essc-quickfacts{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:480px){
  .essc-quickfacts{grid-template-columns:1fr}
}

/* Practical information. Static section sourced from the local
   organisers (not Indico). Subsection-driven so the page can grow
   from accommodation to transport / dining / need-to-know without
   restructuring. */
.essc-practical{padding:64px 0}
.essc-practical h2{
  font-size:clamp(1.8rem,1.4rem+1.8vw,2.5rem);
  margin:0 0 1.4rem;
}
.essc-practical-block{
  padding:28px;
  border-radius:18px;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  margin-bottom:24px;
}
.essc-practical-block:last-child{margin-bottom:0}
.essc-practical-block-title{
  display:flex;
  align-items:center;
  gap:10px;
  margin:0 0 .8rem;
  font-size:1.2rem;
  font-weight:600;
  color:var(--ink);
}
.essc-practical-block-title svg{
  width:20px;height:20px;flex:none;color:var(--accent-2);
}
.essc-practical-lede{
  margin:0 0 1.4rem;
  font-size:1rem;
  color:var(--ink-2);
  line-height:1.55;
  max-width:62ch;
}
.essc-practical-foot{
  margin:1.2rem 0 0;
  font-size:.9rem;
  color:var(--muted);
}
.essc-area-grid{
  list-style:none;
  padding:0;margin:0;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:14px;
}
.essc-area{
  padding:16px 18px;
  border-radius:12px;
  background:color-mix(in oklab, var(--bg-0) 60%, transparent);
  border:1px solid var(--glass-border);
  display:flex;
  flex-direction:column;
  gap:.5rem;
}
.essc-area-name{
  margin:0;
  font-size:1rem;
  font-weight:600;
  letter-spacing:-.01em;
  color:var(--ink);
}
.essc-area-note{
  margin:0;
  font-size:.85rem;
  color:var(--ink-2);
  line-height:1.4;
}
.essc-stop-chips{
  list-style:none;
  padding:0;margin:auto 0 0;
  display:flex;
  flex-wrap:wrap;
  gap:6px;
}
.essc-stop-chip{
  display:inline-flex;
  align-items:center;
  gap:6px;
  padding:3px 9px 3px 8px;
  border-radius:999px;
  font-size:.78rem;
  font-weight:500;
  color:var(--ink-2);
  background:color-mix(in oklab, var(--accent-2) 8%, transparent);
  border:1px solid color-mix(in oklab, var(--accent-2) 22%, transparent);
}
/* Leading dot follows SL convention of marking line colour. Every
   recommended neighbourhood sits on the red line (T13), so all
   chips carry the same red marker. If a future year needs other
   lines, branch on a `data-line` attribute. */
.essc-stop-chip::before{
  content:'';
  display:inline-block;
  width:7px;height:7px;border-radius:50%;
  background:#d71920; /* SL red line */
}

/* Programme section */
.essc-programme{padding-top:24px}
.essc-programme h2{
  font-size:clamp(1.8rem,1.4rem+1.8vw,2.5rem);
  margin:0 0 .8rem;
}

/* Day-chip nav. Anchor-link based, no JS scroll handler — keeps
   `prefers-reduced-motion` honoured by the browser. */
.programme-day-chips{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  margin:1.4rem 0 2rem;
  padding-top:.4rem;
}
.programme-day-chip{
  display:inline-flex;
  align-items:baseline;
  gap:.5rem;
  padding:.6rem 1rem;
  border-radius:999px;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  color:var(--ink);
  font-size:.92rem;
  font-weight:500;
  text-decoration:none;
  transition:background .2s var(--ease),transform .2s var(--ease);
}
.programme-day-chip:hover{
  background:var(--glass-bg-strong);
  transform:translateY(-1px);
  opacity:1;
}
.programme-day-chip .lbl{font-weight:600;color:var(--accent)}
.programme-day-chip .date{color:var(--muted);font-size:.85rem}

/* Day blocks */
.programme-day{
  margin:0 0 3rem;
  scroll-margin-top:100px;     /* Anchor-link landing clears the floating header */
}
.programme-day-head{
  display:flex;
  align-items:baseline;
  flex-wrap:wrap;
  gap:.6rem 1rem;
  margin-bottom:1.2rem;
  padding-bottom:.8rem;
  border-bottom:1px solid var(--line);
}
.programme-day-head h3{
  margin:0;
  font-size:1.5rem;
  font-weight:600;
}
.programme-day-date{
  color:var(--muted);
  font-size:.95rem;
}

/* Row = one time-block in the day. Two-column on desktop:
   time-gutter | items. On mobile (<700px), the gutter stacks
   above the items as a small label. */
.programme-row{
  display:grid;
  grid-template-columns:120px 1fr;
  gap:18px;
  margin:0 0 18px;
}
@media (max-width:700px){
  .programme-row{grid-template-columns:1fr;gap:8px}
}
.programme-row-time{
  font-variant-numeric:tabular-nums;
  font-size:.92rem;
  color:var(--muted);
  font-weight:500;
  padding-top:.4rem;
  white-space:nowrap;
}
.programme-row-time .start{color:var(--ink)}
.programme-row-items{
  display:grid;
  grid-template-columns:1fr;
  gap:14px;
}
.programme-row.is-parallel .programme-row-items{
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (max-width:900px){
  .programme-row.is-parallel .programme-row-items{grid-template-columns:1fr}
}

/* Slot = a single card. Three kinds: session, contribution, break. */
.programme-slot{
  padding:18px 20px;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  border-radius:14px;
  box-shadow:0 1px 2px rgba(20,35,80,.04);
  transition:box-shadow .25s var(--ease),transform .25s var(--ease);
}
.programme-slot:hover{
  box-shadow:0 10px 28px rgba(20,35,80,.10);
}
.programme-slot.is-break{
  /* Flex layout so the title and the room badge get a real gap
     between them instead of the previous inline-text collision
     (the pin icon sat right against the last word of the title).
     `flex-wrap: wrap` lets the badge drop onto its own line on
     narrow viewports without overlap. */
  display:flex;
  justify-content:center;
  align-items:center;
  flex-wrap:wrap;
  gap:14px;
  background:transparent;
  border-style:dashed;
  border-color:var(--line);
  box-shadow:none;
  padding:10px 18px;
  color:var(--muted);
  font-size:.92rem;
}
.programme-slot.is-break:hover{box-shadow:none;transform:none}
.programme-slot.is-break .programme-break-title{
  /* The title used to be small + italic + muted, which made it
     vanish next to the room badge. Drop italic, bump weight, lift
     the colour one stop toward ink so visitors can scan the day
     for "where is lunch" without squinting. */
  font-style:normal;
  font-weight:500;
  color:var(--ink-2);
}
.programme-slot.is-break .programme-slot-room::before{
  /* Visual separator between the title and the room badge when
     they sit on the same line. Drops out automatically when the
     badge wraps to its own line on narrow viewports. */
  content:'·';
  margin-right:6px;
  opacity:.5;
}
.programme-slot-head{
  display:flex;
  align-items:center;
  gap:.6rem;
  flex-wrap:wrap;
  margin-bottom:.6rem;
}
.programme-slot-kind{
  display:inline-block;
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.12em;
  text-transform:uppercase;
  padding:.25rem .65rem;
  border-radius:999px;
  background:rgba(11,18,32,.06);
  color:var(--ink-2);
}
.programme-slot-kind.is-roundtable{
  background:rgba(220,140,40,.12);
  color:#a85b00;
}
.programme-slot-kind.is-plenary{
  background:rgba(10,132,255,.12);
  color:var(--accent-2);
}
.programme-slot-room{
  display:inline-flex;
  align-items:center;
  gap:5px;
  font-size:.78rem;
  color:var(--muted);
  /* The room badge sits next to the time + kind chips on session
     cards, and at the foot of break / contribution cards (where it
     gets a little top spacing, see the selector below). The pin
     SVG inherits currentColor so it stays in sync with light + dark
     text. */
}
.programme-slot-room svg{
  width:12px;height:12px;flex:none;opacity:.85;
}
/* Contribution cards still want a small top margin so the room
   badge sits below the abstract / speaker list. Break cards use
   flex `gap` (above) so they no longer need this. */
.programme-slot.is-contribution .programme-slot-room{
  margin-top:4px;
}
.programme-slot-title{
  margin:0 0 .5rem;
  font-size:1.05rem;
  font-weight:600;
  line-height:1.35;
  color:var(--ink);
}
.programme-slot-title a{color:inherit}
.programme-slot-title a:hover{color:var(--accent-2);opacity:1}
.programme-slot-abstract{
  margin:.6rem 0 0;
  font-size:.92rem;
  color:var(--ink-2);
  line-height:1.55;
}

/* Chairs / speakers / discussants list. */
.programme-people{
  margin:.3rem 0;
  font-size:.88rem;
  color:var(--ink-2);
  line-height:1.5;
}
.programme-people-label{
  font-weight:600;
  color:var(--muted);
}
.programme-person .name{font-weight:500}
.programme-person .aff{color:var(--muted)}
/* When the speaker is one of our members, .name renders as <a> pointing
   at /people.html#<slug>. The resting state has a fully-opaque accent
   dotted underline AND a soft tint to the text colour, so touch users
   (who never see a :hover reveal) can still tell at a glance which
   names in a long Chairs / Speakers list are tappable. Desktop users
   get an additional brightness shift to full accent-2 on :hover /
   :focus-visible. The opacity:1 override cancels the site-wide
   a:hover opacity dim. */
.programme-person a.name{
  color:color-mix(in oklab, var(--accent-2) 70%, var(--ink));
  text-decoration:none;
  border-bottom:1px dotted var(--accent-2);
  transition:color .15s var(--ease), border-color .15s var(--ease);
}
.programme-person a.name:hover,
.programme-person a.name:focus-visible{
  color:var(--accent-2);
  border-bottom-color:var(--accent-2);
  opacity:1;
}

/* ESSC member preview card — opened via the Popover API when a
   reader hovers a speaker name that resolves to a NetSec member.
   One card element is built lazily, attached to <body>, and reused
   for every member. Class names are prefixed `essc-member-card-*`
   to avoid a collision with the directory's existing `.member-card`
   class on /people.html. Top-layer rendering means the card escapes
   any clipped programme-grid ancestor. */
.essc-member-card{
  position:fixed;
  margin:0;
  padding:0;
  border:1px solid var(--glass-border);
  border-radius:14px;
  /* Glassmorphism — same recipe the site uses for nav/menu surfaces.
     A solid fallback colour sits under the translucent layer so
     browsers that don't support backdrop-filter still get a readable
     surface (Firefox until 103, older Safari). */
  background:var(--bg-1);
  background:var(--glass-bg-strong);
  -webkit-backdrop-filter:saturate(160%) blur(18px);
  backdrop-filter:saturate(160%) blur(18px);
  color:var(--ink);
  width:min(360px, calc(100vw - 16px));
  box-shadow:0 12px 36px rgba(20,35,80,.18);
  font-size:.9rem;
  line-height:1.4;
  inset:auto;        /* override default popover centering */
  overflow:hidden;
}
.dark .essc-member-card{
  box-shadow:0 12px 36px rgba(0,0,0,.55);
}
/* Browsers without backdrop-filter — fall back to the opaque bg-1
   colour that came in just above the glass layer, so the surface is
   never see-through. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  .essc-member-card{background:var(--bg-1)}
}
.essc-member-card-inner{
  display:grid;
  grid-template-columns:64px 1fr;
  gap:14px;
  padding:14px 16px;
  align-items:start;
}
.essc-member-card-photo{
  width:64px;height:64px;
  border-radius:50%;
  object-fit:cover;
  background:var(--line);
  display:block;
}
.essc-member-card-photo-placeholder{
  /* Same dimensions as the photo so the grid doesn't reflow when the
     member has no photo yet. */
  background:var(--line);
}
.essc-member-card-text{min-width:0}
.essc-member-card-name{
  font-weight:600;
  font-size:1rem;
  margin:0 0 2px;
  color:var(--ink);
  /* Long names with no spaces (e.g. transliterated long surnames)
     should wrap rather than push the card wider than its max-width. */
  overflow-wrap:anywhere;
}
.essc-member-card-role{
  margin:0 0 2px;
  color:var(--muted);
  font-size:.85rem;
}
.essc-member-card-aff{
  margin:0 0 6px;
  font-size:.88rem;
  color:var(--ink-2);
}
/* Roles + WG badges. Sit between affiliation and country, kept on a
   single wrappable row so a member with three or four chips doesn't
   force the card taller than necessary. */
.essc-member-card-badges{
  display:flex;
  flex-wrap:wrap;
  gap:4px;
  margin:4px 0 8px;
}
.essc-member-card-badge{
  display:inline-block;
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.02em;
  padding:2px 7px;
  border-radius:999px;
  background:color-mix(in oklab, var(--accent-2) 14%, transparent);
  color:var(--accent-2);
  line-height:1.4;
}
.essc-member-card-badge.is-wg{
  /* WG chips read as a secondary tier — same shape, lower contrast. */
  background:var(--line);
  color:var(--muted);
}
.essc-member-card-country{
  display:flex;
  align-items:center;
  gap:6px;
  margin:0;
  color:var(--muted);
  font-size:.82rem;
}
.essc-member-card-country img{
  width:18px;height:auto;
  border-radius:2px;
  display:inline-block;
}
.essc-member-card-bio{
  margin:10px 0 0;
  font-size:.85rem;
  color:var(--ink-2);
  /* Clamp to three lines so the card never gets taller than a phone
     keyboard's worth of vertical space. */
  display:-webkit-box;
  -webkit-line-clamp:3;
  line-clamp:3;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
/* Social-link row. Compact 18px icons in a flex row, same brand
   glyphs and colour conventions as /people.html so the card reads
   visually as a smaller cousin of the directory card. */
.essc-member-card-contacts{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin:10px 0 0;
}
.essc-member-card-contact{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:28px;height:28px;
  border-radius:6px;
  color:var(--muted);
  background:transparent;
  transition:color .15s var(--ease), background .15s var(--ease);
}
.essc-member-card-contact svg{width:18px;height:18px}
.essc-member-card-contact:hover,
.essc-member-card-contact:focus-visible{
  color:var(--accent-2);
  background:color-mix(in oklab, var(--accent-2) 12%, transparent);
  opacity:1;
}
.essc-member-card-contact.is-orcid{color:#A6CE39}
.essc-member-card-contact.is-orcid:hover,
.essc-member-card-contact.is-orcid:focus-visible{
  color:#A6CE39;
  background:color-mix(in oklab, #A6CE39 14%, transparent);
}
.essc-member-card-footer{
  border-top:1px solid var(--glass-border);
  padding:10px 16px;
  text-align:right;
  /* Subtle tint so the footer separates from the card body. The
     translucent overlay sits on top of the glass layer, so the
     resulting colour reads as a slightly darker shade in light mode
     and a slightly lighter shade in dark mode without needing two
     rules. */
  background:rgba(11,18,32,.04);
}
.dark .essc-member-card-footer{
  background:rgba(255,255,255,.05);
}
.essc-member-card-footer a{
  font-size:.85rem;
  font-weight:500;
}
@media print{
  /* The card is interactive chrome; never relevant on paper. */
  .essc-member-card{display:none !important}
}

/* Contributions <details> — only on session cards that have papers. */
.programme-contribs{
  margin-top:.8rem;
  padding-top:.8rem;
  border-top:1px solid var(--line);
}
.programme-contribs > summary{
  cursor:pointer;
  font-size:.85rem;
  font-weight:500;
  color:var(--accent-2);
  user-select:none;
  list-style:none;
}
.programme-contribs > summary::-webkit-details-marker{display:none}
.programme-contribs > summary::before{
  content:"▸";
  display:inline-block;
  margin-right:.4em;
  font-size:.8em;
  transition:transform .2s var(--ease);
}
.programme-contribs[open] > summary::before{transform:rotate(90deg)}
.programme-contribs-list{
  list-style:none;
  padding:0;
  margin:.8rem 0 0;
  display:flex;
  flex-direction:column;
  gap:.9rem;
}
.programme-contrib{
  padding:.6rem .8rem;
  background:rgba(11,18,32,.03);
  border-radius:10px;
}
.dark .programme-contrib{background:rgba(255,255,255,.04)}
.programme-contrib-head{
  display:flex;
  gap:.6rem;
  align-items:baseline;
  flex-wrap:wrap;
}
.programme-contrib-time{
  font-variant-numeric:tabular-nums;
  font-size:.78rem;
  color:var(--muted);
}
.programme-contrib-title{
  margin:0;
  font-size:.95rem;
  font-weight:600;
  line-height:1.35;
  color:var(--ink);
}
.programme-contrib-title a{color:inherit}
.programme-contrib-title a:hover{color:var(--accent-2);opacity:1}
.programme-contrib-abstract{
  margin:.4rem 0 0;
  font-size:.86rem;
  color:var(--ink-2);
  line-height:1.5;
}
/* The expand-toggle is now a <button>, not an <a>: clicking swaps
   the teaser for the full abstract in place rather than sending the
   reader off to Indico. We override the native button chrome so it
   reads as part of the prose, with the same accent colour as other
   inline links. The Indico contribution URL is still reachable via
   the contribution title, which is the canonical link for the
   paper. */
.programme-contrib-more{
  display:inline;
  appearance:none;
  background:none;
  border:0;
  padding:0;
  margin-left:.25rem;
  font:inherit;
  font-size:.82rem;
  color:var(--accent-2);
  cursor:pointer;
  text-decoration:underline;
  text-underline-offset:2px;
  white-space:nowrap;
}
.programme-contrib-more:hover{
  opacity:.85;
}
.programme-contrib-more:focus-visible{
  outline:2px solid var(--accent-2);
  outline-offset:2px;
  border-radius:3px;
}
/* When expanded, the abstract grows in place. No transition: the
   text just rewrites. Animating a height auto → auto-with-more
   would either jitter or fight prefers-reduced-motion. Visitors who
   wanted the full text get it instantly. */

/* Empty / loading / error states */
.programme-loading,
.programme-error{
  padding:24px;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  border-radius:14px;
  color:var(--muted);
  text-align:center;
}
.programme-error{
  border-color:rgba(220,90,90,.35);
  background:rgba(220,90,90,.05);
  color:var(--ink-2);
}

/* Reduced-motion: kill the day-chip hover-lift. */
@media (prefers-reduced-motion: reduce){
  .programme-day-chip:hover{transform:none}
  .programme-slot:hover{transform:none}
}

/* Live-programme freshness signal. Show-don't-tell: the pulsing
   green dot next to the "Live programme" heading on
   /essc-2026.html signals that the data on the page is synced
   rather than static. Honours prefers-reduced-motion. */
.programme-live-dot{
  display:inline-block;
  width:.55em; height:.55em;
  border-radius:50%;
  background:#22c55e;
  vertical-align:.18em;
  margin-right:.85em;
  /* margin-left sized so the pulse halo (which extends .65em from
     the dot's edge at peak) doesn't reach past the natural left
     edge of the heading column. */
  margin-left:.9em;
  box-shadow:0 0 0 0 rgba(34,197,94,.7);
  animation: programmeLivePulse 2.4s ease-out infinite;
}
@keyframes programmeLivePulse{
  0%   { box-shadow:0 0 0 0 rgba(34,197,94,.55); }
  70%  { box-shadow:0 0 0 .65em rgba(34,197,94,0); }
  100% { box-shadow:0 0 0 0 rgba(34,197,94,0); }
}
.dark .programme-live-dot{
  background:#34d775;
}
@media (prefers-reduced-motion: reduce){
  .programme-live-dot{animation:none}
}

/* Livestream badge — appears on session cards whose subtype is
   "plenary" or "roundtable" (matches EISS's INTRO / KEY / RT /
   CONC livestream classification). Same green as the
   .programme-live-dot so visitors read the page-level "Live
   programme" cue and the per-session "this one is livestreamed"
   cue as the same colour family. */
/* css-collision-allow: .programme-slot-livestream */
.programme-slot-livestream{
  display:inline-flex;
  align-items:center;
  gap:.4em;
  font-size:.68rem;
  font-weight:700;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:#15803d;
  padding:.22rem .6rem;
  border-radius:999px;
  background:rgba(34,197,94,.12);
  border:1px solid rgba(34,197,94,.28);
  white-space:nowrap;
}
.programme-slot-livestream svg{
  width:.95em; height:.95em;
  flex:none;
}
.dark .programme-slot-livestream{
  color:#52d775;
  background:rgba(52,215,117,.16);
  border-color:rgba(52,215,117,.32);
}

/* ──────────────────────────────────────────────────────────────
   Print stylesheet (#123).
   ──────────────────────────────────────────────────────────────
   Some readers (academics, COST evaluators, MC reps preparing
   for plenary) actually print these pages. Default Chrome output
   wastes a sheet on the floating-header bubble and bleeds the
   dark-mode aurora blobs whenever "background graphics" is on.
   This block strips the page chrome, drops glassmorphism, and
   adds page-break hints where the content reads better grouped.
   The earlier tiny `@media print` blocks higher in the file
   (programme-grid, popover, roadmap-toggle) handle their own
   feature-specific needs; this is the cross-cutting baseline. */
@media print {
  /* Universal — flatten the colour story for paper, drop chrome. */
  html, body { background:#fff !important; color:#000 !important; }
  .ambience, .blob,
  .nav, .menu-toggle, .nav-cta,
  .footer .socials,
  .scroll-progress, .scroll-progress-bar,
  .search-trigger, .theme-toggle, .lang-switch,
  .i18n-beta-ribbon,
  .skip-link,
  .tour-trigger, .welcome-strip,
  .toast, .toast-region,
  #search-overlay,
  .rm-shipped-toggle,
  .members-toolbar,
  .essc-member-card,
  .member-bio-toggle { display:none !important; }

  /* Body padding-top compensates for the fixed header. With the
     header hidden, we don't need the cushion. */
  body, main, .container { padding-top:0 !important; }

  /* Drop glass — opaque white, no shadows, no blur. */
  .glass, .resource-card, .event-card, .mc-card, .rm-card,
  .programme-slot, .deliverable-card,
  .member-card {
    background:#fff !important;
    box-shadow:none !important;
    border:1px solid #ccc !important;
    backdrop-filter:none !important;
    -webkit-backdrop-filter:none !important;
  }

  /* Links: keep them legible. Spell out external URLs after the
     link text so a paper reader can still resolve where it points. */
  a { color:inherit !important; text-decoration:underline; }
  a[href^="http"]:not([href*="netsec-cost.eu"])::after {
    /* Reset the screen-mode external-link icon (a 0.85em×0.85em
       inline-block with a -webkit-mask) so the print URL disclosure
       isn't crammed into a 12px-wide box. Without these resets,
       `word-break: break-all` wraps the URL one character per line
       and inflates the parent (e.g. a session-card H4 wrapping an
       Indico link) to ~565px tall — which in turn made Chrome's
       print engine put every programme row on its own page. */
    display:inline !important;
    width:auto !important;
    height:auto !important;
    margin:0 !important;
    background:none !important;
    -webkit-mask:none !important;
            mask:none !important;
    content:" (" attr(href) ")";
    font-size:.78em;
    font-weight:400;
    color:#666 !important;        /* visually separate the URL from the link text */
    text-decoration:none !important;  /* the URL doesn't need its own underline */
    word-break:break-all;
  }

  /* Avoid orphan headings — keep a heading with its first content. */
  h1, h2, h3, h4 { page-break-after:avoid; }
  h2, h3 { page-break-inside:avoid; }

  /* FAQ — keep a question with its answer where possible. */
  .faq-section, .faq-item {
    page-break-inside:avoid;
  }

  /* Glossary — keep a term with its definition. */
  dl > dt { page-break-after:avoid; }
  dl > dd { page-break-before:avoid; }

  /* Press-kit colour swatches: when the background is off (the
     default in Chrome's "save as PDF"), the chip shape collapses
     to nothing visible. Print the hex code after the swatch so
     the colour name is still useful on paper. */
  .pk-colour-swatch::after {
    content:" — " attr(data-hex);
    font-family:ui-monospace, 'SF Mono', Menlo, monospace;
    font-size:.85em;
    color:#555;
  }

  /* Roadmap — landscape orientation gives the timeline room to
     breathe. Most printers accept the per-page orientation hint;
     others fall back to portrait, which still renders correctly
     just narrower. */
  @page roadmap { size: A4 landscape; margin: 12mm; }
  body.is-roadmap { page: roadmap; }

  /* Programme grid — give each day its own start so a 3-day
     programme prints as 3 pages, not as one continuous run.
     The fuller per-day breaks and tightened cards live in the
     dedicated programme print block further down. */
  .programme-day { page-break-before:always; }
  .programme-day:first-of-type { page-break-before:auto; }
  .programme-slot { page-break-inside:avoid; }

  /* Strip the directory's expand-in-place hint chrome too. */
  .members-grid.is-compact .member-card { padding:16px !important; }
}

/* ── Programme page print refinement (essc-2026.html + FR/DE) ──
   The earlier print block above handles the cross-cutting baseline.
   This block is programme-specific: cover masthead on page 1,
   tightened session cards, locale-neutral chrome stripping.
   The per-locale `@page` rule with running header text and page
   numbers lives inline in each essc-2026.*.html — the running
   header content has to be a literal string and the language
   differs per locale, so keeping it next to the locale's HTML
   document avoids three near-duplicate `@page` rules here.

   Cover masthead default state: hidden on screen, only the print
   block flips it on. Marked aria-hidden in the HTML because the
   on-screen `.essc-hero` already carries the same information for
   AT users; a duplicate landmark on screen would be noise. */
.essc-print-masthead { display:none; }
@media print {
  .essc-print-masthead {
    display:block;
    margin: 0 0 8mm;
    padding: 0 0 5mm;
    border-bottom: 1pt solid #000;
    page-break-after: avoid;
    break-after: avoid;
  }
  .essc-print-masthead .title {
    margin: 0 0 3mm;
    font-family: 'Lexend', 'Inter', sans-serif;
    font-size: 22pt;
    letter-spacing: -.02em;
    line-height: 1.15;
    font-weight: 700;
    color: #000;
  }
  .essc-print-masthead .when-where {
    margin: 0 0 2mm;
    font-size: 11pt;
    line-height: 1.4;
    color: #000;
  }
  .essc-print-masthead .organisers {
    margin: 0;
    font-size: 9.5pt;
    line-height: 1.4;
    color: #444;
  }

  /* Hide on-screen chrome that's redundant once the masthead is in
     place, or that has no meaning on paper. The "Times in Europe/Paris
     … on Indico" line is dropped because the masthead already names
     the conference and the Indico URL will appear after each link via
     the existing link-disclosure rule. */
  .essc-hero,
  .programme-day-chips,
  .programme-live-dot,
  .programme-loading,
  .programme-error,
  .essc-programme > .container > p.muted,
  .essc-programme > .container > .eyebrow,
  .essc-practical { display:none !important; }

  /* The "Live programme" h2 is screen chrome — replace with a
     tighter section opener on paper. */
  .essc-programme h2 {
    font-size: 14pt;
    margin: 0 0 5mm;
    color: #000;
  }

  /* Day — own page after the first; tighter head with stronger rule. */
  .programme-day {
    margin: 0 0 8mm;
  }
  .programme-day-head {
    margin: 0 0 4mm;
    padding: 0 0 2mm;
    border-bottom: 0.75pt solid #000;
    gap: .4rem 1rem;
    page-break-after: avoid;
    break-after: avoid;
  }
  .programme-day-head h3 {
    font-size: 13pt;
    font-weight: 700;
    color: #000;
  }
  .programme-day-date {
    font-size: 10pt;
    color: #444;
  }

  /* Row — narrower time gutter, smaller gap. Keep parallel sessions
     side-by-side; the viewport in print is ~595pt wide so the
     screen breakpoint at 900px does not fire.

     `align-items: start` + `grid-auto-rows: min-content` is the
     critical pairing for Chrome's print engine: without them, the
     `break-inside: avoid` hint on the slot child causes the parent
     grid row track to expand to the remaining page height (the
     engine reserves the next-page worth of vertical space "in
     case" the slot needs it), then the slot stretches to fill
     that track. End result was a one-row-per-page programme. The
     two declarations together pin track height to the content's
     intrinsic min-content size and stop the stretch.

     `align-content: start` on the inner grid does the same job for
     parallel rows. */
  .programme-row {
    grid-template-columns: 70pt 1fr;
    grid-auto-rows: min-content;
    align-items: start;
    align-content: start;
    gap: 8pt;
    margin: 0 0 3mm;
  }
  .programme-row-time {
    font-size: 9pt;
    padding-top: 2pt;
    align-self: start;
  }
  .programme-row-items {
    gap: 5pt;
    grid-auto-rows: min-content;
    align-items: start;
    align-content: start;
  }
  .programme-row.is-parallel .programme-row-items {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6pt;
  }

  /* Slot — sharper corners, thinner border, no shadow, paper-sized
     type. `align-self: start` is the belt-and-braces companion to
     the row's `align-items: start` above. */
  .programme-slot {
    padding: 6pt 9pt;
    border-radius: 3pt;
    border: 0.6pt solid #888 !important;
    background: #fff !important;
    box-shadow: none !important;
    font-size: 9.5pt;
    line-height: 1.35;
    align-self: start;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  .programme-slot.is-break {
    padding: 4pt 8pt;
    border-style: dashed !important;
    border-color: #aaa !important;
    color: #555 !important;
    font-size: 9pt;
  }
  .programme-slot-head {
    gap: .3rem;
    margin-bottom: .35rem;
  }
  /* Session title — high contrast on paper. Without an explicit
     near-black colour here, the global `h4 { color: var(--ink) }`
     stays in force, and `--ink` resolves to a dark navy that prints
     as light grey on cheap office printers / faint preview viewers.
     Same idea for the `<a>` inside the title — `a { color: inherit }`
     is already set above, so this colour cascades through. */
  .programme-slot-title,
  .programme-slot-title a,
  .programme-contrib-title,
  .programme-contrib-title a { color:#000 !important; }
  .programme-slot-title { font-size: 10pt; font-weight: 600; }
  .programme-slot-meta,
  .programme-slot-people { font-size: 8.5pt; color: #444; }
  .programme-slot-room { font-size: 8pt; }
  .programme-slot-livestream { display:none; }   /* dot has no meaning on paper */

  /* Force the contributions list open on print so the full paper
     line-up + abstracts make it onto paper. The toggle summary is
     suppressed; the "Show more" inline button has no use on paper. */
  .programme-contribs,
  .programme-contribs[open] { display: block; }
  .programme-contribs > summary { display: none; }
  .programme-contribs-list {
    margin-top: 3mm;
    gap: 2mm;
  }
  .programme-contrib {
    padding: 3pt 6pt;
    background: rgba(0,0,0,.03) !important;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  .programme-contrib-title { font-size: 9pt; }
  .programme-contrib-time  { font-size: 7.5pt; }
  .programme-contrib-abstract {
    font-size: 8.5pt;
    color: #333;
    margin-top: 1mm;
  }
  .programme-contrib-more { display: none; }
}
