/**
 * EONA-X Design System — component styles for the eona-ds Yew crate.
 *
 * Ported verbatim from the design-system repo's charte-graphique-design-system
 * branch (brand/index.html's inline <style>), so that any consumer linking
 * this file alongside tokens.css (from the same repo/branch) renders
 * pixel-identically to the original static page. Rules are grouped by the
 * component that owns them; keep that mapping when adding new components so
 * drift against the source page stays easy to spot.
 */

/* ---------- base reset (shared by every page using this crate) ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--eona-font-family);
  color: var(--eona-navy);
  background: var(--eona-gray-bg);
  font-size: var(--eona-size-body);
  line-height: var(--eona-line-body);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: var(--eona-blue-action); text-decoration: none; }
a:hover { text-decoration: underline; }
.wrap { max-width: 1180px; margin: 0 auto; padding: 0 24px; }
h1, h2, h3, h4 { font-weight: var(--eona-weight-semibold); margin: 0 0 .5em; letter-spacing: -0.01em; }
p { margin: 0 0 1em; }
code, .mono { font-family: 'SF Mono', 'Consolas', monospace; }

/* ---------- section shell ---------- */
section.block { padding: 84px 0; border-bottom: 1px solid rgba(4,5,83,.08); }
section.block:last-of-type { border-bottom: none; }

/* ---------- Button atom ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px; font-size: var(--eona-size-button); font-weight: var(--eona-weight-medium);
  padding: 12px 22px; border-radius: var(--eona-radius-pill); border: none; cursor: pointer;
}
.btn-primary { background: var(--eona-blue-action); color: #fff; }
.btn-primary:hover { background: #0060d6; text-decoration: none; }
.btn-ghost { background: rgba(255,255,255,.08); color: #fff; border: 1px solid rgba(255,255,255,.3); }
.btn-ghost:hover { background: rgba(255,255,255,.16); text-decoration: none; }

/* ---------- Pill atom (.name-pill) ---------- */
.naming-grid { display: flex; gap: 14px; flex-wrap: wrap; margin: 20px 0; }
.name-pill { display: flex; align-items: center; gap: 8px; font-family: 'SF Mono', Consolas, monospace; font-size: 15px; background: #fff; padding: 10px 16px; border-radius: 999px; box-shadow: var(--eona-shadow-card); }
.name-pill.ok { color: var(--eona-navy); }
.name-pill.bad { color: #9a3a3a; text-decoration: line-through; }

/* ---------- SectionHead molecule (BadgeNum + kicker + h2) ---------- */
.section-head { display: flex; align-items: flex-start; gap: 18px; margin-bottom: 40px; }
.badge-num {
  flex: none; width: var(--eona-badge-diameter); height: var(--eona-badge-diameter);
  border-radius: 50%; background: var(--eona-navy); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--eona-weight-bold); font-size: 18px;
}
.section-head h2 { font-size: var(--eona-size-h1); color: var(--eona-navy); }
.section-head .kicker { display: block; font-size: 12.5px; font-weight: var(--eona-weight-semibold); letter-spacing: .1em; text-transform: uppercase; color: var(--eona-blue-action); margin-bottom: 4px; }

/* ---------- section intro / callout ---------- */
.section-intro { max-width: 74ch; color: #33355f; font-size: 15.5px; }
.callout {
  background: #fff; border-left: 4px solid var(--eona-gold); border-radius: 10px;
  padding: 18px 22px; font-size: 14.5px; color: var(--eona-navy); box-shadow: var(--eona-shadow-card);
  margin: 20px 0;
}
.callout b { font-weight: var(--eona-weight-semibold); }
.fr { color: #6a6c94; font-style: italic; }

/* ---------- RefCard molecule ---------- */
.ref-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px,1fr)); gap: 22px; margin-top: 8px; }
.ref-card { background: #fff; border-radius: var(--eona-radius-card); overflow: hidden; box-shadow: var(--eona-shadow-card); }
.ref-card img { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
.ref-card figcaption { padding: 14px 18px 18px; }
.ref-card .rc-title { font-size: 14.5px; font-weight: var(--eona-weight-semibold); margin-bottom: 4px; }
.ref-card .rc-desc { font-size: 12.5px; color: #55578a; }

/* ---------- PaletteGroup + Swatch molecules ---------- */
.palette-group { margin-bottom: 44px; }
.palette-group h3 { font-size: 17px; margin-bottom: 4px; }
.palette-group .group-desc { font-size: 14px; color: #55578a; max-width: 70ch; margin-bottom: 18px; }
.ref-note { display: inline-block; font-size: 11px; background: rgba(237,160,28,.15); color: #8a5a08; padding: 3px 9px; border-radius: 999px; font-weight: 600; margin-bottom: 10px; }

.swatch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px,1fr)); gap: 16px; }
.swatch {
  border: none; padding: 0; text-align: left; cursor: pointer; background: #fff;
  border-radius: var(--eona-radius-card); overflow: hidden; box-shadow: var(--eona-shadow-card);
  font-family: inherit; display: block; width: 100%;
}
.swatch-color { height: 96px; display: flex; align-items: flex-end; padding: 10px 14px; position: relative; }
.swatch-hex { font-family: 'SF Mono', Consolas, monospace; font-size: 13px; font-weight: 600; padding: 4px 9px; border-radius: 6px; background: rgba(255,255,255,.85); color: #111; }
.swatch-copy-flag { position: absolute; top: 8px; right: 10px; font-size: 10.5px; background: rgba(255,255,255,.9); color: var(--eona-navy); padding: 2px 8px; border-radius: 999px; font-weight: 600; opacity: 0; transition: opacity .15s; }
.swatch.copied .swatch-copy-flag { opacity: 1; }
.swatch-meta { padding: 12px 14px 16px; }
.swatch-name { font-size: 14px; font-weight: var(--eona-weight-semibold); margin-bottom: 3px; }
.swatch-usage { font-size: 12.5px; color: #55578a; line-height: 1.4; }
.swatch-variants { font-size: 11px; color: #8385ab; margin-top: 6px; }

/* ---------- DeckTop ---------- */
.decktop {
  background: var(--eona-navy);
  color: rgba(255,255,255,.75);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  font-weight: var(--eona-weight-medium);
}
.decktop .wrap { display: flex; justify-content: space-between; align-items: center; padding-top: 8px; padding-bottom: 8px; }
.decktop b { color: #fff; }

/* ---------- MainNav ---------- */
nav.mainnav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(247,249,254,.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid rgba(4,5,83,.08);
}
nav.mainnav .wrap { display: flex; align-items: center; gap: 28px; height: 60px; }
.brandmark { display: flex; align-items: center; gap: 8px; font-weight: var(--eona-weight-bold); font-size: 17px; color: var(--eona-navy); white-space: nowrap; }
.brandmark .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--eona-gold); box-shadow: 8px 0 0 -1px var(--eona-blue-action); }
.navlinks { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; }
.navlinks::-webkit-scrollbar { display: none; }
.navlinks a {
  color: var(--eona-navy); font-size: 13.5px; font-weight: var(--eona-weight-medium);
  padding: 8px 12px; border-radius: var(--eona-radius-pill); white-space: nowrap;
}
.navlinks a:hover { background: rgba(0,110,240,.1); text-decoration: none; }
.navlinks a.back { color: var(--eona-blue-action); }
.navspacer { flex: 1; }
.navutil { display: flex; gap: 8px; }
.navutil a { font-size: 12.5px; font-weight: var(--eona-weight-medium); color: var(--eona-blue-action); border: 1px solid rgba(0,110,240,.35); padding: 6px 12px; border-radius: var(--eona-radius-pill); }
.navutil a:hover { background: rgba(0,110,240,.08); text-decoration: none; }

/* ---------- Hero (index's big .hero and icons' smaller .libhero share these) ---------- */
.hero, .libhero {
  position: relative; overflow: hidden;
  color: #fff;
}
.hero {
  background: linear-gradient(160deg, var(--eona-navy) 0%, var(--eona-navy-deep) 100%);
  padding: 88px 0 96px;
}
.libhero {
  background: linear-gradient(160deg, var(--eona-navy) 0%, var(--eona-navy-deep) 100%);
  padding: 64px 0 56px;
}
.hero .wrap, .libhero .wrap { position: relative; z-index: 2; }
.hero-eyebrow { display: inline-flex; align-items: center; gap: 8px; background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.18); color: #fff; font-size: 12.5px; font-weight: var(--eona-weight-medium); padding: 6px 14px; border-radius: var(--eona-radius-pill); margin-bottom: 22px; }
.libhero .hero-eyebrow { margin-bottom: 20px; }
.hero-eyebrow .sw { width: 8px; height: 8px; border-radius: 50%; background: var(--eona-gold); }
.hero h1, .libhero h1 { font-size: var(--eona-size-display); line-height: var(--eona-line-display); margin-bottom: .3em; }
.hero h1 { max-width: 15ch; }
.libhero h1 { max-width: 18ch; }
.hero h1 em, .libhero h1 em { font-style: normal; color: var(--eona-lavender); }
.hero p.lede { font-size: 18px; max-width: 56ch; color: rgba(255,255,255,.8); }
.libhero p.lede { font-size: 17px; max-width: 62ch; color: rgba(255,255,255,.8); }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 28px; align-items: center; }
.libhero .hero-actions { margin-top: 26px; }
.hero-count { font-size: 13px; color: rgba(255,255,255,.65); }

.mesh-bg { position: absolute; inset: 0; z-index: 1; opacity: .9; }
.stripe { position: absolute; z-index: 1; }

/* diagonal gold stripe — the deck's signature graphic anchor */
.gold-stripe {
  position: absolute; width: 46%; height: 260%; top: -80%; right: -6%;
  background: var(--eona-gold);
  transform: rotate(var(--eona-stripe-angle));
  opacity: .95;
}
.hero .gold-stripe { opacity: .12; }
.libhero .gold-stripe { opacity: .12; }

/* ---------- Positioning: mvo cards, pillars, personality ---------- */
.pillars { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 20px; margin: 28px 0 40px; }
.pillar-card { background: var(--eona-navy); color: #fff; border-radius: var(--eona-radius-card); padding: 26px; }
.pillar-num { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; background: var(--eona-blue-action); font-size: 13px; font-weight: var(--eona-weight-bold); margin-bottom: 14px; }
.pillar-card h3 { font-size: 16px; text-transform: uppercase; letter-spacing: .02em; margin-bottom: 14px; }
.pillar-card ul { margin: 0; padding-left: 18px; font-size: 14px; color: rgba(255,255,255,.85); }
.pillar-card li { margin-bottom: 10px; }
.pillar-card li b { color: #fff; }

.mvo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap: 16px; margin: 24px 0; }
.mvo-card { background: #fff; border-radius: 14px; padding: 20px; box-shadow: var(--eona-shadow-card); }
.mvo-tag { display: inline-flex; align-items: center; gap: 6px; background: var(--eona-blue-action); color: #fff; font-size: 12.5px; font-weight: var(--eona-weight-medium); padding: 5px 12px; border-radius: var(--eona-radius-pill); margin-bottom: 10px; }
.mvo-tag .dot { width: 6px; height: 6px; border-radius: 50%; background: #fff; }
.mvo-card p { font-size: 14px; margin: 0; }

.personality { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 20px; margin-top: 12px; }
.personality-card { background: #fff; border-radius: 14px; padding: 20px; box-shadow: var(--eona-shadow-card); }
.personality-card .tag { display: inline-block; background: var(--eona-blue-action); color: #fff; font-size: 12.5px; font-weight: var(--eona-weight-medium); padding: 5px 12px; border-radius: var(--eona-radius-pill); margin-bottom: 10px; }
.personality-card p { font-size: 14px; color: #33355f; margin: 0; }

/* ---------- Typography ---------- */
.type-hero { background: var(--eona-navy); color: #fff; border-radius: var(--eona-radius-card); padding: 40px 36px; margin-bottom: 32px; }
.type-hero .glyphs { font-size: 68px; font-weight: var(--eona-weight-semibold); margin-bottom: 6px; }
.type-hero .fam { font-size: 20px; color: var(--eona-lavender); margin-bottom: 18px; }
.type-hero .chars { font-size: 22px; color: rgba(255,255,255,.85); letter-spacing: .02em; }
.type-tagline { font-size: 26px; font-weight: var(--eona-weight-regular); margin: 30px 0 40px; max-width: 46ch; }
.type-tagline .accent { color: var(--eona-blue-action); font-weight: var(--eona-weight-medium); }
.type-scale-row { display: grid; grid-template-columns: 140px 1fr 140px; gap: 18px; align-items: baseline; padding: 18px 0; border-top: 1px solid rgba(4,5,83,.08); }
.type-scale-row:first-of-type { border-top: none; }
.type-scale-row .role { font-size: 12px; font-weight: var(--eona-weight-semibold); text-transform: uppercase; letter-spacing: .05em; color: var(--eona-blue-action); }
.type-scale-row .spec { font-size: 12px; color: #6a6c94; text-align: right; font-family: 'SF Mono', Consolas, monospace; }
.weight-strip { display: flex; flex-wrap: wrap; gap: 24px; margin-top: 16px; }
.weight-strip div span.w { display: block; font-size: 30px; }
.weight-strip div span.lbl { display: block; font-size: 11.5px; color: #6a6c94; margin-top: 4px; }

/* ---------- Logo ---------- */
.logo-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: 36px; align-items: center; margin-bottom: 40px; }
@media (max-width: 820px) { .logo-grid { grid-template-columns: 1fr; } }
.logo-visual { background: #fff; border-radius: var(--eona-radius-card); box-shadow: var(--eona-shadow-card); overflow: hidden; }
.logo-visual img { width: 100%; }
.logo-visual figcaption { font-size: 12px; color: #6a6c94; padding: 10px 16px 16px; }
.rules-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.rules-list li { display: flex; gap: 10px; font-size: 14.5px; background: #fff; border-radius: 10px; padding: 12px 14px; box-shadow: var(--eona-shadow-card); }
.rules-list li.do::before { content: "\2713"; color: var(--eona-success); font-weight: 700; }
.rules-list li.dont::before { content: "\2715"; color: var(--eona-error); font-weight: 700; }
.rules-list li.caution::before { content: "!"; color: var(--eona-warning); font-weight: 700; }

.bg-check-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px,1fr)); gap: 14px; margin-top: 18px; }
.bg-check { border-radius: 12px; padding: 22px 14px; text-align: center; font-size: 12.5px; font-weight: 600; }
.bg-check .ic { font-size: 20px; display: block; margin-bottom: 8px; }

/* ---------- LogoDownloadCard grid ---------- */
.logo-downloads { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px,1fr)); gap: 14px; margin-top: 16px; }
.logo-download {
  display: flex; flex-direction: column; background: #fff; border-radius: 14px;
  overflow: hidden; box-shadow: var(--eona-shadow-card); color: inherit;
}
.logo-download:hover { text-decoration: none; box-shadow: 0 14px 32px rgba(4,5,83,.2); }
.logo-download__preview {
  display: flex; align-items: center; justify-content: center;
  height: 96px; padding: 16px; border-bottom: 1px solid rgba(4,5,83,.06);
}
.logo-download__preview img { width: 100%; height: 100%; object-fit: contain; }
.logo-download__preview.is-transparent {
  background-image:
    linear-gradient(45deg, #e2e4ef 25%, transparent 25%),
    linear-gradient(-45deg, #e2e4ef 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #e2e4ef 75%),
    linear-gradient(-45deg, transparent 75%, #e2e4ef 75%);
  background-size: 14px 14px;
  background-position: 0 0, 0 7px, 7px -7px, -7px 0;
}
.logo-download__label { font-size: 13.5px; font-weight: var(--eona-weight-semibold); padding: 12px 14px 2px; }
.logo-download__action { font-size: 12px; color: var(--eona-blue-action); font-weight: 600; padding: 2px 14px 14px; }

/* icon chips */
.icon-chip-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 28px; }
.icon-chip { background: #fff; border-radius: 999px; padding: 8px 16px; font-size: 13px; font-weight: 600; box-shadow: var(--eona-shadow-card); color: var(--eona-navy); }

/* imagery tag row */
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 26px; }
.tag-row span { background: var(--eona-lavender-pale, #e9ecfc); color: var(--eona-navy); font-size: 12.5px; font-weight: 600; padding: 6px 14px; border-radius: 999px; }

/* ---------- declinations gallery ---------- */
.filter-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 26px; }
.filter-btn {
  font-size: 13px; font-weight: 600; padding: 8px 16px; border-radius: 999px; border: 1px solid rgba(4,5,83,.15);
  background: #fff; color: var(--eona-navy); cursor: pointer;
}
.filter-btn.active { background: var(--eona-navy); color: #fff; border-color: var(--eona-navy); }
.decl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px,1fr)); gap: 22px; }
.decl-card { background: #fff; border-radius: var(--eona-radius-card); overflow: hidden; box-shadow: var(--eona-shadow-card); }
.decl-card img { width: 100%; aspect-ratio: 16/9; object-fit: cover; border-bottom: 1px solid rgba(4,5,83,.06); }
.decl-body { padding: 16px 18px 20px; }
.decl-type { display: inline-block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--eona-blue-action); margin-bottom: 6px; }
.decl-title { font-size: 14.5px; font-weight: var(--eona-weight-semibold); margin-bottom: 6px; }
.decl-desc { font-size: 12.5px; color: #55578a; }

/* ---------- shape convention strip ---------- */
.shape-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap: 18px; margin-top: 10px; }
.shape-card { background: #fff; border-radius: 14px; padding: 20px; box-shadow: var(--eona-shadow-card); }
.shape-demo { height: 64px; display: flex; align-items: center; justify-content: center; margin-bottom: 14px; }
.demo-pill { background: var(--eona-blue-action); color: #fff; padding: 12px 26px; border-radius: 999px; font-size: 13px; font-weight: 600; }
.demo-badge { width: 48px; height: 48px; border-radius: 50%; background: var(--eona-navy); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; }
.demo-card { width: 80px; height: 52px; border-radius: 14px; background: var(--eona-navy); position: relative; overflow: hidden; }
.demo-card::after { content: ""; position: absolute; width: 40px; height: 140%; top: -20%; right: -12px; background: var(--eona-gold); transform: rotate(28deg); }
.demo-x { position: relative; width: 60px; height: 60px; }
.demo-x span { position: absolute; width: 60px; height: 10px; background: var(--eona-lavender-deep, #b5c8f3); border-radius: 6px; top: 25px; }
.demo-x span:first-child { transform: rotate(45deg); }
.demo-x span:last-child { transform: rotate(-45deg); }
.shape-card h4 { font-size: 13.5px; margin-bottom: 4px; }
.shape-card p { font-size: 12px; color: #55578a; margin: 0; }

/* ---------- footer / resources (index page) ---------- */
footer#resources { background: var(--eona-navy); color: rgba(255,255,255,.75); padding: 60px 0 40px; }
footer#resources h2 { color: #fff; font-size: 22px; }
footer#resources .res-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 40px; margin-top: 24px; }
@media (max-width: 720px) { footer#resources .res-grid { grid-template-columns: 1fr; } }
footer#resources a { color: var(--eona-lavender); }
footer#resources .file-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; font-size: 13.5px; }
footer#resources .file-list code { background: rgba(255,255,255,.08); padding: 2px 8px; border-radius: 6px; }
footer#resources .bottom-line { border-top: 1px solid rgba(255,255,255,.12); margin-top: 40px; padding-top: 20px; font-size: 12px; color: rgba(255,255,255,.5); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; }

/* ---------- footer (icons page) ---------- */
footer.icons-footer { background: var(--eona-navy); color: rgba(255,255,255,.75); padding: 44px 0; margin-top: 40px; }
footer.icons-footer a { color: var(--eona-lavender); }
footer.icons-footer .bottom-line { font-size: 12.5px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; }

@media (max-width: 600px) {
  .hero, .libhero { padding: 64px 0 72px; }
  section.block { padding: 56px 0; }
  .type-scale-row { grid-template-columns: 1fr; gap: 4px; }
  .type-scale-row .spec { text-align: left; }
}

/* ==================================================================== */
/* Components extracted from eona-x.eu (the live corporate site, WordPress
   "solanum" theme) — not the brand-guide slides above. Colors reuse this
   crate's existing --eona-* tokens rather than introducing a parallel set,
   since the live site's own palette already matches them almost exactly
   (its --c-blue-dark-secondary #040553 is our --eona-navy, its
   --c-blue-third #006ef0 is our --eona-blue-action, etc.). See
   crates/site's README for the deliberate simplifications: the real header
   floats each piece as its own frosted-glass chip over a photo/hero
   backdrop; SiteHeader below keeps the same colors/shape/button but as a
   solid navy strip (no photo backdrop on every page for glass-over-nothing
   to make sense). The fixed-position + scroll-collapse *mechanics* ARE
   faithfully reproduced (reverse-engineered from the real site's own
   header.js) — see SiteHeader's doc comment and
   crates/site/assets/site-header.js. */
/* ==================================================================== */

/* ---------- SiteHeader (unified portal nav, all pages) ---------- */
/* Vertical spacing lives on .site-header itself (a unique element, not
   sharing the .wrap class) rather than on a bare .site-header__wrap rule —
   an earlier version put `padding` on .site-header__wrap and it collided
   with icons.html's own copy of the base .wrap rule at equal specificity,
   silently losing that padding on that page only (see the "Fix site-header
   padding lost on icons.html" commit). Keeping .site-header__wrap free of
   its own padding/margin sidesteps that whole class of bug rather than just
   patching this one instance of it -- same reasoning applies again below to
   the body top-offset compensation. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 999;
  /* Genuinely transparent -- matches eona-x.eu's own #en-tete, verified with
     getComputedStyle() directly on the live site: `background-color:
     rgba(0, 0, 0, 0)` both at rest AND once its `.is-scrolled`-equivalent
     class is on (scrolled 1000px down, still transparent). The real header
     never paints itself at all; its dark-bar *look* at rest is its hero's
     own full-bleed background showing through from y:0, and once scrolled
     past the hero it stays see-through over whatever page content follows
     -- legible there only because each piece (`.header-menu`'s glass pill,
     `.header-lang`) carries its own frosted chip, not because the bar
     behind them is opaque. This was a real, previously-undetected
     difference: this rule used to paint a solid `var(--eona-navy-deep)`
     bar across the full width in both scroll states, which is why scrolling
     over light page content used to still show a solid navy strip instead
     of the content underneath.
     Our own resting-state "continuous dark surface" look (needed because,
     unlike the real site, none of this portal's pages have a hero that
     starts at the true viewport top -- see the padding-top comment above)
     is now reproduced by `.site-header::before` below instead of by
     painting this element, so `.site-header` itself stays honestly
     transparent like the real one; once `.is-scrolled` that backdrop drops
     out too (see its own rule) and this header becomes just as see-through
     as the real site's. */
  padding: 20px 0;
  transition: padding .2s ease, top .2s ease;
}
@media (min-width: 1024px) {
  .site-header { top: 2rem; }
  /* Real site's own class name (`.header.is-scrolled`), kept as-is here. */
  .site-header.is-scrolled { top: 0; }
}
.site-header.is-scrolled { padding: 10px 0; }
/* Fixed positioning takes .site-header out of flow -- compensate with
   padding-top on `body` itself (not on whatever follows .site-header in the
   DOM) so the reserved gap shows body's own light --eona-gray-bg, not one
   of DeckTop's/HeroFilter's own darker backgrounds stretching upward into
   it, and so neither of those elements' own shape gets distorted. Targets
   `html > body`, not a bare `body` selector -- icons-page.css has its own
   copy of `body {...}` (same specificity as a bare `body` rule here would
   be) that loads after this file on that one page and would silently win
   the tie, the exact bug class already fixed once for .site-header__wrap
   (see that comment above and the "Fix site-header padding lost on
   icons.html" commit) -- `html > body` (0,0,2) reliably outranks a bare
   `body` (0,0,1) regardless of load order. Sized for the resting
   (unscrolled, desktop) header height; when scrolled the real header
   shrinks and this becomes a bit more space than strictly needed rather
   than too little -- erring toward "never clips" over pixel-perfect
   tracking of the header's animated height. 156px = the header's own
   measured 116px content height (governed by the standalone logo at 76px
   tall, its tallest child -- see the logo-sizing comment below) plus its
   32px top offset, rounded up a little for the same "never clips" margin
   as everywhere else in this file; re-check this measurement again if the
   logo's own height changes. */
html > body { padding-top: 156px; }
@media (max-width: 720px) {
  /* The pill can wrap to two rows at this width (see .site-header__wrap
     media query below), so the reserved space is larger here too -- 224px,
     re-measured for the fourth nav link: a real worst-case two-row header
     (four links, "Design System"+"Icons" over "Components"+"Data Space")
     renders 207.4px tall, and this follows the same "erring toward never
     clips" margin as the desktop value above rather than tracking that
     number exactly. (An earlier version of this value, 194px, predated the
     fourth link and the two-row pill it can now produce -- see the
     .site-header__pill width-glitch fix below for why a two-row pill only
     became reachable once a fourth link was added.) */
  html > body { padding-top: 224px; }
}
/* Stands in for the real site's own hero -- now that .site-header itself is
   honestly transparent (see its own comment above), SOMETHING has to fill
   the area behind it at rest or every page's header would float over plain
   body background, not a "continuous dark surface." The real site gets
   this for free (its hero starts at the true viewport top, y:0, so the
   transparent header always has the hero's own dark background directly
   behind it); none of this portal's pages do that (each one's first
   section is pushed below .site-header by the padding-top reserve above),
   so a dedicated backdrop reproduces the same *look* without moving
   Hero/DeckTop/HeroFilter's own box -- one fixed rectangle, independent of
   whatever each page's first section happens to be, sized to the header's
   own resting footprint (32px top offset + 116px header height -- 156px,
   the same number as the desktop padding-top reserve above, and for the
   same reason: err toward covering slightly more than the measured header
   height rather than clipping it if content nudges it taller. Keep this
   in sync with that value -- both move together whenever the header's own
   resting height does, e.g. the logo-sizing change below).
   This is scoped to exactly the situation the real site doesn't have to
   solve: it disappears below 1024px and once `.is-scrolled` (both cases
   the header sits flush at `top: 0`, so there is no gap above it left to
   fill), at which point .site-header is just as see-through as the real
   one, over whatever the page happens to be showing at that scroll
   position -- matching the real header's own tolerance for that (confirmed
   on the live site: scrolled past its hero, the transparent bar shows
   arbitrary page content behind it too, legible only via each piece's own
   glass chip, not the bar itself). */
.site-header::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 156px;
  background: var(--eona-navy-deep);
  /* Without this, the standalone logo silently disappears behind this
     backdrop (confirmed empirically -- getBoundingClientRect() and
     computed opacity/visibility all said it should be showing, only
     elementFromPoint() at its own center gave it away, returning
     .site-header instead of the logo's <img>). Cause: this pseudo-element
     is `position: fixed`, a *positioned* box, so CSS painting order puts
     it in the same layer as -- and, being earlier in the generated-content
     order, *underneath* -- any other positioned-or-equivalent sibling; but
     `.site-header__pill` and `.site-header__lang` each carry their own
     `backdrop-filter`, which (per spec) promotes an element into that same
     positioned paint layer even without `position` of its own, so they
     ended up above this backdrop by DOM-order coincidence while the
     standalone logo -- a plain, unpromoted, non-positioned <a> -- painted
     in the *earlier*, non-positioned layer, underneath it. `z-index: -1`
     sidesteps the coincidence entirely: it forces this backdrop into the
     negative-z-index layer, which paints before (behind) every other kind
     of child of `.site-header` regardless of which of them happen to have
     their own stacking context. Only became visible once this rule grew
     from a 2rem sliver (which never overlapped the header's own content
     box) to its current full-header-height -- see this rule's own comment
     above for why. */
  z-index: -1;
}
@media (max-width: 1023px) {
  .site-header::before { content: none; }
}
.site-header.is-scrolled::before { content: none; }
.site-header .site-header__wrap {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
/* Three independent pieces, mirroring eona-x.eu's real #en-tete layout
   (standalone logo | centered glass pill nav | standalone action pill —
   its lang switcher's slot on the real site) rather than one flat bar, plus
   a second hidden copy of the logo/actions inside the pill (--pill variants
   below) that swap places with the standalone ones on scroll. */
.site-header__logo { display: flex; align-items: center; flex: none; }
/* Re-measured directly on eona-x.eu (getBoundingClientRect on its
   `.header-logo-link svg` and its nav pill, `nav.menu`/`.menu-hover`):
   logo height 98px against a ~67-69px pill -- a ratio of about 1.43-1.47,
   the real site's logo running notably taller than its pill, not just as
   tall. An earlier pass here landed on 60px against this pill's own
   (unrelated, independently-sized) ~54px resting height -- a ratio of
   only ~1.12 -- which is closer to "a bit taller" than the real site's
   "clearly taller." 76px against that same ~54px brings the ratio to
   ~1.41, matching what was actually measured rather than the earlier
   pass's apparent estimate. (rather than the original 36px, which read as
   an afterthought next to the pill, undersized on both counts.) Changing
   this changes the header's own resting content height, which both the
   desktop `html > body` padding-top reserve and `.site-header::before`'s
   height below have to keep matching -- see their own comments. */
.site-header__logo--top img { display: block; height: 76px; width: auto; }
.site-header__pill {
  display: flex; align-items: center; justify-content: center; gap: 2px;
  flex: 1; max-width: 460px; margin: 0 auto;
  background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.14);
  backdrop-filter: blur(var(--eona-blur, 16px));
  border-radius: var(--eona-radius-pill); padding: 6px;
}
.site-header__link {
  color: rgba(255,255,255,.75); font-size: 14px; font-weight: var(--eona-weight-medium);
  padding: 8px 16px; border-radius: var(--eona-radius-pill); white-space: nowrap;
}
.site-header__link:hover { background: rgba(255,255,255,.1); color: #fff; text-decoration: none; }
.site-header__link[aria-current=page] { background: #fff; color: var(--eona-navy); }
.site-header__actions {
  display: flex; align-items: center; gap: 8px; flex: none;
}
/* No chip background of its own -- eona-x.eu doesn't wrap its lang switcher
   and its (absent, here) CTA in one shared box either, each floats as its
   own independent glass piece directly on the header. `.site-header__lang`
   below carries that look now instead, so a future `show_login` button
   (already self-styled, `.pill-btn-glass-light`) sits next to it as its own
   chip rather than nesting inside this wrapper's. */
.site-header__lang {
  color: rgba(255,255,255,.75); font-size: 14px; font-weight: var(--eona-weight-medium);
  padding: 8px 16px; border-radius: var(--eona-radius-pill); white-space: nowrap;
  background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.14);
  backdrop-filter: blur(var(--eona-blur, 16px));
}

/* ---------- scroll-collapse: standalone <-> pill-internal swap ---------- */
.site-header__logo--top,
.site-header__actions--top {
  transition: opacity .3s ease, transform .3s ease;
}
.site-header.is-scrolled .site-header__logo--top,
.site-header.is-scrolled .site-header__actions--top {
  opacity: 0; transform: scale(0); pointer-events: none;
}
.site-header__logo--pill,
.site-header__actions--pill {
  width: 0; opacity: 0; visibility: hidden; transform: scale(0); overflow: hidden;
  transition: width .3s ease, opacity .3s ease, transform .3s ease, visibility 0s .3s;
}
.site-header__logo--pill img { display: block; height: 27px; width: auto; }
.site-header.is-scrolled .site-header__logo--pill,
.site-header.is-scrolled .site-header__actions--pill {
  width: auto; opacity: 1; visibility: visible; transform: scale(1);
  transition: width .3s ease, opacity .3s ease, transform .3s ease;
}
/* A regression in the fix directly above this comment: `.site-header__pill`
   keeps `flex: 1; max-width: 460px` (its own resting-state rule, above) in
   BOTH scroll states, but that cap was only ever measured against the
   resting content -- the four nav links alone, ~444.5px, the internal
   logo/actions copies contributing 0px width (`width: 0` two rules up).
   Once `.is-scrolled`, those two copies stop being 0-width and join the
   four links as real content the pill has to fit -- and the 460px cap,
   already at its own near-zero slack for the links alone (see the 720px
   fix's own comment below: "4.8px of slack at 1024px"), falls far short of
   the larger total. Measured directly (getBoundingClientRect from the
   internal logo's left edge to the internal actions chip's right edge,
   both visible post-`.is-scrolled`, transitions settled): logo 28.5px +
   four links 444.5px + EN actions chip 51.4px + the pill's five 2px
   inter-child gaps 10px = 534.3px of content -- constant across every
   desktop width tested (1024/1200/1536px, the only widths `.is-scrolled`
   can ever apply at, gated by site-header.js's own 1024px `matchMedia`)
   since none of these pieces scale with viewport. Add the pill's own 6px+
   6px padding and 1px+1px border (both included in `max-width`, since this
   project's global box-sizing is border-box) and it needs 548.3px overall,
   ~88px past the inherited 460px cap -- confirmed the bug this produces:
   the logo and EN chip visibly spill out past the pill's own rounded glass
   edges on both sides (content is centered, via the pill's own `margin: 0
   auto`, so it overflows symmetrically), exactly the look eona-x.eu's own
   scrolled/consolidated pill does NOT have (screenshot-verified there: logo
   + links + lang switcher all sit inside one glass bar with zero overflow).
   560px covers the measured 548.3px with a bit of real slack this time,
   rather than repeating the ~4.8px margin that let this regress the moment
   new content joined the pill in the first place. Re-measure this again if
   `show_login` is ever flipped on (its PillButton would join this same
   internal actions chip) or if the nav gains a fifth link. */
.site-header.is-scrolled .site-header__pill { max-width: 560px; }

@media (max-width: 720px) {
  .site-header .site-header__wrap { flex-wrap: wrap; justify-content: center; }
  /* The width glitch: `.site-header__pill` was sized (`max-width: 460px`,
     above) back when the nav held three links; with the fourth ("Data
     Space") its own natural content width -- four `white-space: nowrap`
     labels plus their gaps and the pill's own padding, a fixed ~462px that
     does NOT shrink with the viewport since flex items can't shrink a
     no-wrap label below its own text width -- is already *right at* that
     460px cap on desktop (confirmed empirically: 4.8px of slack at 1024px
     and up) and comfortably exceeds it on any narrower one. Below this
     720px breakpoint `max-width: 100%` replaces the 460px cap so the pill
     can span the full stacked-below-the-logo row, but "100%" is still
     nowhere near enough once that row itself is narrower than ~462px --
     confirmed on a real render at 480px and 375px, where the links visibly
     spilled out past the pill's own rounded edges on both sides (content
     centered, so it overflows left and right symmetrically) rather than
     staying inside its glass background. `flex-wrap: wrap` here lets the
     four links fold onto a second internal row *inside* the pill's own
     rounded box instead of spilling past its edges -- costs nothing at
     widths where they already fit in one row (wrapping only ever engages
     once content actually doesn't fit) and keeps working arbitrarily
     narrow, unlike a fixed-width/padding tweak that would just move the
     breakpoint where it starts failing again. The real site sidesteps this
     entirely with a hamburger/off-canvas menu below its own ~1024px
     breakpoint (confirmed on eona-x.eu) -- a bigger feature than this
     fix's scope, so this keeps the existing inline-pill mobile pattern and
     makes it survive a fourth link instead of replacing it.
     `flex: 0 0 100%` replacing the pill's own base `flex: 1` here -- not
     just adding `flex-wrap` alone -- because of a second, narrower glitch
     that surfaced only once links could wrap: `.site-header__pill`'s base
     rule (above) is `flex: 1`, i.e. `flex-basis: 0%` plus `flex-grow: 1`,
     which asks the browser to size the pill by *growing it from zero*
     using its wrapped content as the yardstick -- a flex-basis:0%
     auto-sizing negotiation that is a known Chromium fixed-point edge
     case for a *wrapping* flex item, and it really did misfire here:
     confirmed empirically at exactly 375px wide, where the pill measured
     only 203px (every link forced onto its own row, 4 total) while both
     480px and 320px -- narrower *and* wider -- correctly measured
     308px/257px (2 rows). That is the signature of an intrinsic-sizing
     quirk, not a real too-little-room case (there was room; the pill just
     didn't claim it) -- and it didn't even respond to an explicit
     `width: 100%` added alongside the inherited `flex: 1`, because
     `flex-basis` (the inherited `0%`) takes precedence over `width` for a
     flex item's main size regardless of what `width` says. `flex: 0 0
     100%` sidesteps the negotiation entirely: basis is a definite 100% of
     the line (correct anyway, since the pill is alone on its wrapped row)
     and grow/shrink are both zeroed so nothing renegotiates it afterward.
     Scoped to this media query only, since the bug is specific to a
     *wrapping* flex item computing its own size and doesn't reproduce in
     desktop's single-row `flex: 1` layout above. */
  .site-header__pill { order: 3; flex: 0 0 100%; max-width: 100%; flex-wrap: wrap; }
}

/* ---------- HeroFilter (.hero__filter — listing-page hero) ---------- */
.hero-filter {
  position: relative;
  background: var(--eona-navy);
  padding: 56px 0 40px;
  overflow: hidden;
}
.hero-filter__container {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: end;
}
@media (max-width: 720px) {
  .hero-filter__container { grid-template-columns: 1fr; align-items: start; }
}
.hero-filter__title { color: #fff; margin-bottom: 12px; }
.hero-filter__description { color: rgba(255,255,255,.8); max-width: 34ch; margin: 0; }
.hero-filter__actions { display: flex; gap: 12px; align-items: flex-end; justify-content: flex-end; flex-wrap: wrap; }
@media (max-width: 720px) { .hero-filter__actions { justify-content: flex-start; } }
.hero-filter--backdrop .hero-filter__image {
  position: absolute; inset: 0; z-index: 0;
  background: radial-gradient(120% 100% at 80% 0%, var(--eona-blue-royal) 0%, var(--eona-navy) 60%);
}
.hero-filter--backdrop .hero-filter__overlay {
  position: absolute; inset: 0;
  background: linear-gradient(0deg, var(--eona-navy) 0%, rgba(4,5,83,0) 65%);
}

/* ---------- PillButton (.css__button on eona-x.eu) ---------- */
.pill-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border-radius: 100px; font-weight: 500; font-size: 15px;
  padding: 10px 20px; border: none; cursor: pointer; transition: all .3s ease;
  text-decoration: none;
}
.pill-btn:disabled { cursor: not-allowed; }
.pill-btn-solid { background: var(--eona-blue-royal); color: #fff; }
.pill-btn-solid:hover { background: var(--eona-navy); color: #fff; text-decoration: none; }
.pill-btn-glass-light {
  backdrop-filter: blur(var(--eona-blur, 12px));
  background: rgba(255,255,255,.17); border: 1px solid rgba(255,255,255,.3); color: #fff;
}
.pill-btn-glass-light:hover { background: rgba(255,255,255,.25); color: #fff; text-decoration: none; }
.pill-btn-glass-dark {
  backdrop-filter: blur(var(--eona-blur, 12px));
  background: rgba(255,255,255,.17); border: 1px solid var(--eona-navy); color: var(--eona-navy);
}
.pill-btn-glass-dark:hover { background: var(--eona-navy); color: #fff; text-decoration: none; }

/* ---------- TagLabel (.label-tags) ---------- */
.tag-label {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: var(--eona-radius-pill); padding: 4px 10px;
  font-size: 12px; font-weight: 600;
  background: rgba(0,0,0,.06); color: var(--eona-navy);
}
.tag-label::before { content: ""; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--eona-navy); }
.tag-label-blue { background: var(--eona-blue-action); color: #fff; }
.tag-label-blue::before { background: var(--eona-lavender); }

/* ---------- TextField (.form__css floating label) ---------- */
.text-field { position: relative; }
.text-field label {
  position: absolute; top: 8px; left: 16px;
  font-size: 11.5px; font-weight: 500; color: var(--eona-navy);
}
.text-field input, .text-field textarea {
  display: block; width: 100%; box-sizing: border-box; border: 0; border-radius: 8px;
  background: #fff; color: var(--eona-navy); font-family: inherit; font-size: 15px;
  padding: 30px 16px 8px; box-shadow: 0 7px 29px 0 rgba(100,100,111,.09);
}
.text-field textarea { min-height: 9em; resize: vertical; }
.text-field input:focus, .text-field textarea:focus { outline: 2px solid var(--eona-blue-action); outline-offset: 1px; }

/* ---------- Cards (.card-news / .card-member / .card-case) ---------- */
.news-card, .case-card { border-radius: var(--eona-radius-card); overflow: hidden; box-shadow: var(--eona-shadow-card); }
.news-card__link, .case-card__link { display: flex; flex-direction: column; height: 100%; color: inherit; }
.news-card__link:hover, .case-card__link:hover { text-decoration: none; }
.news-card__image, .case-card__image {
  aspect-ratio: 16/9; position: relative; overflow: hidden;
  background: var(--eona-lavender-pale);
  display: flex; align-items: center; justify-content: center;
  color: var(--eona-navy); font-size: 13px; font-weight: 600;
}
.case-card__image { background: var(--eona-lavender); }
.news-card__image .tag-label, .case-card__image .tag-label { position: absolute; top: 14px; left: 14px; }
.news-card__content {
  display: flex; flex-direction: column; gap: 12px; padding: 24px; background: #fff; flex: auto;
}
.case-card__content {
  display: flex; flex-direction: column; align-items: flex-start; gap: 16px; padding: 24px;
  background: var(--eona-navy-deep); color: #fff; flex: auto;
}
.news-card__title { color: var(--eona-navy); font-weight: 500; margin: 0; }
.case-card__title { color: #fff; font-weight: 500; margin: 0; }

.member-card {
  width: 150px; aspect-ratio: 2/1; border-radius: 8px;
  background: rgba(255,255,255,.8); backdrop-filter: blur(var(--eona-blur, 12px));
  display: flex; align-items: center; justify-content: center;
}
.member-card__logo {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
  padding: 14px; font-size: 12px; font-weight: 600; color: var(--eona-navy); text-align: center;
}

/* ---------- BeeNest showcase page (.beenest-grid) ---------- */
/* Not a port from eona-x.eu — bee-nest.html is a new page for this crate's own
   BeeNest hex-flower organisms (organisms/beenest.rs), which have no
   upstream page to mirror. Each diagram is a raw embedded <svg> with a fixed
   viewBox, so it needs its own max-width/height rule: the base `img {
   max-width: 100% }` reset above only ever applied to <img>, never bare
   <svg>, in the original page too. */
.beenest-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px,1fr)); gap: 32px; margin: 20px 0 48px; }
.beenest-card { background: #fff; border-radius: var(--eona-radius-card); box-shadow: var(--eona-shadow-card); padding: 24px; display: flex; justify-content: center; }
.beenest-card svg { max-width: 100%; height: auto; }

/* ---------- Architecture diagrams showcase (diagrams.html, .diagram-grid) ---------- */
/* Each diagram is a plain <img> (fetched from the eona-architecture-decision-records
   repo's docs/diagrams/ at build time — see site's gitlab.rs), not an inline <svg>,
   so it needs no viewBox override beyond the page-wide `img { max-width: 100% }` reset. */
.diagram-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px,1fr)); gap: 28px; margin: 20px 0 48px; }
.diagram-card { background: #fff; border-radius: var(--eona-radius-card); box-shadow: var(--eona-shadow-card); padding: 22px; display: flex; flex-direction: column; gap: 14px; }
.diagram-card img { width: 100%; height: auto; }
.diagram-card h3 { margin: 0; font-size: 16px; color: var(--eona-navy); font-weight: 600; }
.diagram-card p { margin: 0; font-size: 13.5px; color: var(--eona-text-muted); line-height: 1.5; }
.diagram-card a.diagram-source { align-self: flex-start; font-size: 12.5px; font-weight: 600; color: var(--eona-blue-action); text-decoration: none; }
.diagram-card a.diagram-source:hover { text-decoration: underline; }

/* ---------- Components gallery page layout ---------- */
.gallery-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin: 20px 0 36px; }
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 22px; margin: 20px 0 36px; }
.gallery-members-row { display: flex; flex-wrap: wrap; gap: 14px; margin: 20px 0 36px; }
.gallery-field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 20px; margin: 20px 0 36px; max-width: 640px; }

/* ==================================================================== */
/* More eona-x.eu extractions: nav dropdowns, an accordion, a modal, and
   the members-directory card. Same rules as the first eona-x.eu batch
   above: real classes/values from the live app.css, --eona-* tokens
   instead of a parallel set. Source pages: eona-x.eu/ (dropdowns, member
   marquee) and eona-x.eu/about/ (accordion, real markup sample) and
   eona-x.eu/members-and-users/ (member-filter card, real markup sample).
   No live modal instance was found on any page fetched while building
   this — see Modal's own doc comment. */
/* ==================================================================== */

/* ---------- NavDropdown (.menu-link[aria-expanded] + .submenu) ---------- */
.menu-link {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; cursor: pointer; font: inherit;
  color: var(--eona-navy); font-size: 14px; font-weight: 500;
  padding: 8px 14px; border-radius: var(--eona-radius-pill);
}
.menu-link[aria-expanded=true] { background: var(--eona-navy); color: #fff; }
.menu-arrow { font-size: 10px; transition: transform .2s; }
.menu-link[aria-expanded=true] .menu-arrow { transform: rotate(180deg); }
.submenu {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 20;
  width: max-content; min-width: 200px;
  background: #fff; border-radius: var(--eona-radius-card); box-shadow: var(--eona-shadow-card);
  transition: opacity .2s ease;
}
.submenu[inert] { opacity: 0; pointer-events: none; }
.submenu-content { padding: 18px; }
.submenu-list { display: flex; flex-direction: column; gap: 10px; list-style: none; margin: 0; padding: 0; }
.submenu-link { color: var(--eona-navy); font-size: 14px; font-weight: 500; }
.submenu-close {
  position: absolute; top: 8px; right: 8px; width: 24px; height: 24px;
  display: grid; place-items: center; background: none; border: none; cursor: pointer;
  color: var(--eona-navy); font-size: 13px;
}

/* ---------- AccordionItem (.card-accordeon, native <details>/<summary>) ---------- */
.card-accordeon { background: #fff; border-radius: var(--eona-radius-card); padding: 28px; box-shadow: var(--eona-shadow-card); }
.card-accordeon summary { list-style: none; cursor: pointer; }
.card-accordeon summary::-webkit-details-marker { display: none; }
.card-accordeon-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.card-accordeon-title { color: var(--eona-navy); font-size: 18px; font-weight: 500; margin: 0; }
.card-accordeon-arrow {
  flex: none; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--eona-lavender);
  display: flex; align-items: center; justify-content: center; transition: transform .2s ease;
}
[open] .card-accordeon-arrow { transform: rotate(180deg); }
.card-accordeon-content { margin-top: 16px; color: #55578a; }
.card-accordeon-content p { margin: 0 0 .8em; }

/* ---------- Modal (.modal / .modal-inner) ---------- */
.modal {
  position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.7); padding: 24px; transition: background-color .2s ease;
}
.modal[inert] { background: rgba(0,0,0,0); pointer-events: none; }
.modal[inert] .modal-inner { opacity: 0; transform: translateY(12px); }
.modal-inner {
  position: relative; background: #fff; color: var(--eona-navy); border-radius: var(--eona-radius-card);
  padding: 32px; max-width: 32rem; width: 100%; transition: opacity .2s ease, transform .2s ease;
}

/* ---------- MemberFilterCard (.card-member__filter) ---------- */
.card-member__filter {
  display: grid; grid-template-columns: 1.1fr 1fr 1.3fr; gap: 20px;
  background: var(--eona-gray-bg); border-radius: var(--eona-radius-card); padding: 20px 24px;
}
@media (max-width: 720px) { .card-member__filter { grid-template-columns: 1fr; } }
.card-member__filter-header { display: flex; align-items: center; gap: 14px; }
.card-member__filter-logo {
  flex: none; width: 72px; aspect-ratio: 2/1; background: #fff; border-radius: 6px;
  display: flex; align-items: center; justify-content: center; font-size: 11px; color: #8385ab;
}
.card-member__filter-title { display: flex; flex-direction: column; gap: 2px; }
.card-member__filter-title-name { font-size: 15px; font-weight: 500; color: var(--eona-navy); margin: 0; }
.card-member__filter-title-type p { font-size: 12px; color: var(--eona-navy); margin: 0; }
.card-member__filter-localisation, .card-member__filter-sectors { display: flex; flex-direction: column; gap: 8px; justify-content: center; }
.term-name-label { font-size: 13px; font-weight: 500; color: var(--eona-navy); }

/* ---------- Member marquee (static fallback — see components_gallery.rs) ---------- */
.marquee-row { display: flex; flex-wrap: wrap; gap: 14px; }

/* ---------- Slide-style content sections (DataspaceIntro / DataspaceLayers) ----------
   A distinct section pattern for content pages meant to read like eona-x.eu's own
   landing page (full-bleed alternating dark/light blocks) rather than the
   design-system reference page's uniform-background `section.block`. Additive only —
   `section.block` above is untouched, so index/icons/components.html don't shift. */
section.slide-section { padding: var(--eona-space-7) 0; }
@media (max-width: 720px) { section.slide-section { padding: var(--eona-space-6) 0; } }
section.slide-section--light { background: var(--eona-gray-bg); }
section.slide-section--dark {
  background: var(--eona-navy); color: rgba(255,255,255,.85);
}
section.slide-section--dark h2 { color: #fff; }
section.slide-section--dark .section-head .kicker { color: var(--eona-lavender); }
section.slide-section--dark .badge-num { background: #fff; color: var(--eona-navy); }
section.slide-section--dark .section-intro { color: rgba(255,255,255,.75); }

/* Still used by SemanticLayerStack (`semantic_layer_stack.rs`) and, for
   `.layers-diagram` alone, SemanticLayerPattern (`semantic_layer_pattern.rs`)
   -- DataspaceLayers, IdsRamLayers, and InteroperabilityLayers all moved off
   this hand-authored-SVG + separate-legend pattern onto the native-accordion
   rules below (see `.layers-accordion`'s own comment), but
   `data-space-semantic-layer.html`'s two organisms deliberately still use
   it, so it stays. */
.layers-diagram { display: block; width: 100%; height: auto; margin: 40px 0 32px; }
.layers-diagram text { font-family: var(--eona-font-family); }

.layer-legend { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 18px; }
.layer-legend-item { display: flex; gap: 14px; align-items: flex-start; }
.layer-legend-chip { flex: none; width: 14px; height: 14px; border-radius: 4px; margin-top: 4px; }
.layer-legend-title { font-weight: var(--eona-weight-semibold); color: #fff; margin-bottom: 4px; }
.layer-legend-desc { font-size: 14px; color: rgba(255,255,255,.7); margin: 0; }

/* ---------- Accordion-slide layers (`.layers-accordion` / `.layer-band`) ----------
   Shared by DataspaceLayers, IdsRamLayers, and InteroperabilityLayers --
   these class names were already slide-agnostic (unlike
   `.dataspace-layers-layout`/`.dataspace-layers-intro` just below, renamed
   to match once a second and third slide needed them), so they didn't need
   renaming when the other two slides adopted this same pattern. Native
   <details name="...">, one group per slide (each slide uses its own
   `name` -- "dataspace-layer", "ids-ram-layer", "interoperability-layer" --
   so the three groups can't cross-interfere), all layers within one slide
   sharing that slide's `name` so the browser enforces single-open with zero
   JS (same `<details>`/`<summary>` precedent as `.card-accordeon` above).
   Each `.layer-band` carries its own `background`/`color` inline (the
   layer's old SVG-band fill/text colors) so the whole card -- summary AND,
   once opened, its content -- reads as one coherent colored panel rather
   than the description falling back to the section's plain dark background.
   Collapsed height is deliberately minimal (tight summary padding, no
   min-height) so every band plus the intro paragraph fits inside one
   deck-mode slide viewport in the default all-collapsed state; only the one
   band a reader actually opens is allowed to grow past that. */
.layers-accordion { display: flex; flex-direction: column; gap: 8px; margin: 28px 0 4px; }
.layer-band { border-radius: 12px; overflow: hidden; }
.layer-band summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 12px;
  padding: 13px 20px;
}
.layer-band summary::-webkit-details-marker { display: none; }
.layer-band summary:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
.layer-band-icon { flex: none; display: flex; width: 26px; height: 26px; }
.layer-band-icon svg { width: 100%; height: 100%; display: block; }
.layer-band-label { font-weight: 600; font-size: 16px; flex: 1; }
.layer-band-caret { flex: none; font-size: 13px; opacity: .8; transition: transform .15s ease; }
.layer-band[open] .layer-band-caret { transform: rotate(180deg); }
.layer-band-content { padding: 0 20px 18px 58px; }
.layer-band-content p { margin: 0; font-size: 14.5px; opacity: .88; }
.layer-band-content a { font-weight: 500; }

/* ---------- Accordion-slide wide two-column layout (DataspaceLayers / IdsRamLayers / InteroperabilityLayers) ----------
   Named `.layers-slide-*`, not after any one of the three slides that use
   it — originally `DataspaceLayers` alone had this layout under
   `.dataspace-layers-layout`/`.dataspace-layers-intro`, but nothing in
   these rules is actually specific to that slide, so both were renamed
   once `IdsRamLayers`/`InteroperabilityLayers` converted to the same
   accordion pattern and needed the identical grid rather than a duplicated
   copy. Every non-accordion slide in the deck keeps content inside `.wrap`
   (max-width ~1180px, centered); these three alone break out of that fixed
   cap to size themselves off the slide's own width instead (90%, centered,
   well past 1180px on any normal viewport), with their own page-edge
   padding standing in for `.wrap`'s, then split into a 1/3 intro column +
   2/3 accordion column grid.

   The right column's width must never change when a band opens — that's a
   CSS *grid track* here, not a flex-basis percentage or an intrinsic-content
   width: `grid-template-columns` fixes each track's size from the grid
   itself, independent of how tall any one item inside a track grows, so
   `.layers-accordion` (which fills its track at `width: 100%`, implicitly,
   as any grid item does by default) cannot widen just because one
   `<details>` inside it expands taller. Verified live, not just reasoned
   about: on `DataspaceLayers`, `getBoundingClientRect().width` on
   `.layers-accordion` read identical with Network collapsed-by-default vs.
   with Application (the longest description) open instead — re-verified on
   `IdsRamLayers`/`InteroperabilityLayers` after the rename, same result.

   860px breakpoint (not this file's usual 720px) chosen by actually resizing
   the viewport: at 720px the 1fr/2fr split still left the intro column too
   narrow for its own heading + paragraph before the accordion column had
   any real room problem, so the stack-to-one-column point was pushed out
   further than the codebase's typical breakpoint. */
.layers-slide-layout {
  width: 90%;
  box-sizing: border-box;
  margin: 0 auto;
  padding: 0 56px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 48px;
  align-items: start;
}
.layers-slide-intro { min-width: 0; }
.layers-slide-layout .layers-accordion { margin: 0; min-width: 0; }
@media (max-width: 860px) {
  .layers-slide-layout {
    grid-template-columns: 1fr;
    /* 64px, not this file's usual 24px: below this breakpoint the intro
       column (first in source order) stacks on top of the accordion, which
       puts its own text at roughly the same vertical position the deck's
       fixed-position .deck-arrow prev/next buttons occupy (`top: 50%`,
       `left`/`right: 14px` — see the "Slide-deck presentation mode" rules
       below). Confirmed live in a genuinely narrow (594px) browsing
       context with the old 24px padding: the '←' button visibly sat on top
       of the intro paragraph's own text. 64px clears the arrow's largest
       on-screen reach (14px inset + 44px width = 58px, the size it stays
       above the deck's own 720px arrow-shrink breakpoint) with a small
       gutter to spare, and still covers its reach once shrunk to 36px wide
       (14+36=50px) below 720px, so one value suffices for this entire
       block without a second nested query. Scoped to these three slides'
       own layout only, not `.deck-arrow` or `.wrap` (both shared by every
       other slide) — the identical overlap reproduces deck-wide (e.g. on
       slide 2, #what-is-a-dataspace) at the same narrow widths, but fixing
       that is out of scope here: it predates this slide's own layout
       change and isn't caused by it. */
    padding: 0 64px;
    gap: 24px;
  }
}

/* footer.icons-footer's own margin-top:40px is breathing room meant for
   following a light section (its only other uses, on icons.html/
   components.html, both end in light content); left alone here it exposes
   body's light-gray background as a seam between two dark blocks. `main` is
   footer's actual previous sibling (not the section itself), hence :has()
   rather than a plain adjacent-sibling selector; scoped to this case only. */
main:has(> .slide-section--dark:last-child) + footer.icons-footer { margin-top: 0; }

/* ---------- TechnicalPlanes (.plane-grid / .plane-card) ----------
   Three parallel/cooperating cards, not another stacked-band diagram — see
   technical_planes.rs's own doc comment for why. Adapts .pillars/.pillar-card
   below (repeat(auto-fit) grid, numbered-card-with-bulleted-points), but
   background/text come from each card's own inline style (a per-plane
   color) rather than .pillar-card's fixed navy, since these three are peers
   rather than a numbered sequence sharing one card style. */
.plane-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap: 20px; margin: 28px 0 8px; }
.plane-card { border-radius: var(--eona-radius-card); padding: 26px; box-shadow: var(--eona-shadow-card); }
.plane-card h3 { font-size: 17px; text-transform: uppercase; letter-spacing: .02em; margin-bottom: 12px; }
.plane-card .plane-responsibility { font-size: 14px; opacity: .92; margin-bottom: 14px; }
.plane-card ul { margin: 0; padding-left: 18px; font-size: 13.5px; opacity: .92; }
.plane-card li { margin-bottom: 8px; }

/* ---------- Slide-deck presentation mode (data-space.html only) ----------
   Progressive enhancement: by default every #dataspace-deck > section (and
   the Hero <header>) renders in normal document flow, identical to a plain
   scrolling page -- nothing here is required to read the content. See
   dataspace-deck.js: it adds .deck-mode to #dataspace-deck once it has
   actually run, and only then do these rules turn each direct child into a
   full-height, one-at-a-time "slide" the script shows/hides and navigates
   between. Slide height subtracts the fixed header's own reserved
   `html > body { padding-top }` (above) so one slide plus the header
   together fill exactly one viewport, not one-viewport-plus-the-header. */
#dataspace-deck.deck-mode > section,
#dataspace-deck.deck-mode > header {
  display: none;
  height: calc(100vh - 112px);
  overflow-y: auto;
  /* Reserve space for the fixed .deck-nav (dots + counter) pinned at
     bottom:18px -- verified live: without this, a tall slide's own last
     content (e.g. the linked "Semantic layer" band's legend text/link on
     the interoperability slide) scrolled to end up partially hidden behind
     that fixed overlay, with no further scroll room to reveal it. */
  padding-bottom: 90px;
}
@media (max-width: 720px) {
  #dataspace-deck.deck-mode > section,
  #dataspace-deck.deck-mode > header {
    height: calc(100vh - 170px);
  }
}
#dataspace-deck.deck-mode > .deck-active {
  display: flex;
  flex-direction: column;
  /* flex-start, not center: a slide taller than the viewport (the stacked-
     band diagrams, in particular) would have justify-content:center clip
     its top under scrollTop:0 with no way to scroll into that space --
     verified live, "Application layer" and the section head were
     permanently invisible on data-space.html#dataspace-layers before this
     fix. flex-start costs a little vertical centering on short slides
     (Hero, the closing slide) in exchange for never losing content on tall
     ones. */
  justify-content: flex-start;
}

/* Nav chrome is created by dataspace-deck.js, not present in the static
   markup, so it adds nothing to the no-JS reading experience. Each piece
   carries its own light/translucent background so it stays legible
   regardless of which slide (light or dark themed) is behind it. */
.deck-dots {
  display: flex; gap: 8px; background: rgba(255,255,255,.85);
  padding: 8px 14px; border-radius: 999px; box-shadow: var(--eona-shadow-card);
}
.deck-dot { width: 9px; height: 9px; border-radius: 50%; border: none; padding: 0; background: rgba(4,5,83,.25); cursor: pointer; }
.deck-dot.is-active { background: var(--eona-blue-action); width: 22px; border-radius: 999px; }
.deck-counter {
  font-size: 11.5px; font-weight: var(--eona-weight-medium); color: var(--eona-navy);
  background: rgba(255,255,255,.85); padding: 4px 12px; border-radius: 999px;
  box-shadow: var(--eona-shadow-card);
}
.deck-nav {
  position: fixed; left: 0; right: 0; bottom: 18px; z-index: 1000;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.deck-arrow {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 1000;
  width: 44px; height: 44px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.85); color: var(--eona-navy); font-size: 18px;
  box-shadow: var(--eona-shadow-card);
}
.deck-arrow.prev { left: 14px; }
.deck-arrow.next { right: 14px; }
.deck-arrow:disabled { opacity: .3; cursor: default; }
.deck-hint {
  position: fixed; top: 128px; left: 50%; transform: translateX(-50%); z-index: 1000;
  font-size: 11.5px; color: var(--eona-navy); background: rgba(255,255,255,.9);
  padding: 5px 14px; border-radius: 999px; box-shadow: var(--eona-shadow-card);
}
@media (max-width: 720px) {
  .deck-arrow { width: 36px; height: 36px; font-size: 15px; }
  .deck-hint { top: 186px; }
}

/* ==================================================================
   Toolkit demo page — documentation chrome
   ------------------------------------------------------------------
   Unlike everything above, these classes are NOT ported from eona-x.eu
   or the brand charter: nothing on the live site documents a component
   library. They are the toolkit's own, built from the same tokens so
   they sit next to the ported components without reading as a foreign
   stylesheet. Used only by CodeBlock / UsageExample / PropsTable and
   the IntegrationSection, i.e. only on the demo page.
   ================================================================== */

/* A tinted section, to separate the integration half of the demo page
   from the gallery half without a heading-level change. */
section.block-alt { background: var(--eona-gray-bg); }

.code-block {
  border: 1px solid rgba(4,5,83,.12);
  border-radius: var(--eona-radius-sm);
  overflow: hidden;
  background: var(--eona-navy-deep);
  margin: 16px 0 0;
}
.code-block-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px 6px 14px;
  background: rgba(255,255,255,.06);
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.code-block-lang {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  font-weight: var(--eona-weight-medium); color: var(--eona-lavender);
}
.code-block-copy {
  font-family: inherit; font-size: 11.5px; font-weight: var(--eona-weight-medium);
  color: var(--eona-white); background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.18); border-radius: var(--eona-radius-pill);
  padding: 3px 12px; cursor: pointer;
}
.code-block-copy:hover { background: rgba(255,255,255,.2); }
.code-block-copy.copied { background: var(--eona-success); border-color: transparent; }
/* Long lines scroll inside the block rather than widening the page. */
.code-block-pre {
  margin: 0; padding: 14px 16px; overflow-x: auto;
  font-size: 12.5px; line-height: 1.6; color: #e6ecff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.code-block-pre code { font: inherit; color: inherit; background: none; padding: 0; }

/* Rendered component above, the html! that produced it below. */
.usage-example { margin: 20px 0 36px; }
.usage-preview {
  border: 1px solid rgba(4,5,83,.1);
  border-radius: var(--eona-radius-sm) var(--eona-radius-sm) 0 0;
  border-bottom: none;
  padding: 22px;
  background: var(--eona-white);
}
.usage-preview-dark { background: var(--eona-navy-deep); }
/* The preview's own children keep the margins they had before UsageExample
   wrapped them; collapse those against the frame instead of doubling up. */
.usage-preview > :first-child { margin-top: 0; }
.usage-preview > :last-child { margin-bottom: 0; }
.usage-example .code-block { margin: 0; border-radius: 0 0 var(--eona-radius-sm) var(--eona-radius-sm); }

.props-table-wrap { overflow-x: auto; margin: 8px 0 36px; }
.props-table { border-collapse: collapse; width: 100%; min-width: 560px; font-size: 13.5px; }
.props-table caption {
  text-align: left; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  font-weight: var(--eona-weight-semibold); color: var(--eona-blue-royal);
  padding-bottom: 8px;
}
.props-table th {
  text-align: left; font-weight: var(--eona-weight-semibold); color: var(--eona-navy);
  border-bottom: 2px solid rgba(4,5,83,.14); padding: 8px 12px 8px 0;
}
.props-table td {
  vertical-align: top; color: #33355f;
  border-bottom: 1px solid rgba(4,5,83,.08); padding: 10px 12px 10px 0;
}
.props-table code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; color: var(--eona-navy);
  background: var(--eona-lavender-pale); border-radius: 4px; padding: 1px 6px;
}
.props-table .props-type { background: none; padding: 0; color: #5a5d86; }
.props-table .props-required {
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  font-weight: var(--eona-weight-semibold); color: var(--eona-blue-action);
}

.integration-case {
  font-size: var(--eona-size-h3); font-weight: var(--eona-weight-semibold);
  color: var(--eona-navy); margin: 40px 0 0;
}
.integration-case + .section-intro { margin-top: 8px; }

.integration-note {
  border-left: 3px solid var(--eona-gold);
  background: var(--eona-white);
  border-radius: 0 var(--eona-radius-sm) var(--eona-radius-sm) 0;
  padding: 14px 18px; margin: 20px 0 0; max-width: 74ch;
  font-size: 14.5px; color: #33355f;
}
.integration-note b { color: var(--eona-navy); }
.integration-note p { margin: 6px 0 0; line-height: var(--eona-line-body); }

/* Side-by-side light/dark proof for the semantic layer. The dark pane carries
   its own data-theme, so the same markup resolves different tokens a few
   centimetres apart — which is the only honest way to show a theme on a page
   that is itself one theme. */
.theme-demo { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); gap: 18px; margin: 20px 0 24px; }
.theme-demo__pane { background: var(--eona-surface-page); border: 1px solid var(--eona-border-subtle); border-radius: var(--eona-radius-sm); padding: 16px; }
.theme-demo__caption {
  display: block; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  font-weight: var(--eona-weight-semibold); color: var(--eona-text-muted); margin-bottom: 10px;
}
.theme-demo__card {
  background: var(--eona-surface-raised); border: 1px solid var(--eona-border-subtle);
  border-radius: var(--eona-radius-sm); padding: 14px 16px; color: var(--eona-text-primary);
  box-shadow: var(--eona-shadow-surface);
}
.theme-demo__card p { margin: 6px 0; font-size: 14px; line-height: var(--eona-line-body); }
.theme-demo__card a { color: var(--eona-accent); }
.theme-demo__muted { font-size: 12.5px; color: var(--eona-text-muted); }

/* ---------- Section 09: the same component in two stacks ---------------
   One row per component: the Yew call and the React call side by side, or
   the Yew call and a note saying why there is no React one. Both panes are
   .code-block, so the only thing this adds is the two-up frame and the
   pane label; the snippets themselves are generated (bridge/examples.rs).
   Auto-fit rather than a fixed 1fr 1fr: at one column the panes stack in
   source order, Yew first, which is the order the prose reads them in. */
/* 42 rows is too many to scroll past looking for one name; this is the only
   way into a single component's snippet, since the page has no search. */
.snippet-jump { display: flex; flex-wrap: wrap; gap: 6px; margin: 20px 0 8px; }
.snippet-jump a {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; text-decoration: none;
  color: var(--eona-blue-royal); background: var(--eona-lavender-pale);
  border-radius: var(--eona-radius-pill); padding: 3px 10px;
}
.snippet-jump a:hover { background: var(--eona-lavender); color: var(--eona-navy); }

.snippet-index { margin-top: 8px; }
.snippet-entry { padding: 26px 0; border-bottom: 1px solid rgba(4,5,83,.08); }
.snippet-entry:last-child { border-bottom: none; }
.snippet-name {
  font-size: var(--eona-size-h3); font-weight: var(--eona-weight-semibold);
  color: var(--eona-navy); margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.snippet-source { margin: 4px 0 0; font-size: 12.5px; color: #5a5d86; }
.snippet-source code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.snippet-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px,1fr)); gap: 18px; align-items: start; }
.snippet-pane-label {
  display: block; margin-top: 14px;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  font-weight: var(--eona-weight-semibold); color: var(--eona-blue-royal);
}
/* The label supplies the gap above each pane, so the block below it does not
   add a second one. */
.snippet-pane .code-block { margin-top: 6px; }
.snippet-pane-absent .snippet-pane-label { color: #5a5d86; }
/* Not a .code-block: an absent component has no code, and dressing prose as a
   snippet would invite someone to copy it. Tinted rather than white, because
   this section is a plain .block and a white panel on white would read as a
   gap where the second snippet should be. */
.snippet-absent {
  margin-top: 6px; padding: 14px 16px;
  border: 1px dashed rgba(4,5,83,.2); border-radius: var(--eona-radius-sm);
  background: var(--eona-gray-bg);
  font-size: 14px; color: #33355f;
}
.snippet-absent p { margin: 0 0 8px; line-height: var(--eona-line-body); }
.snippet-absent p:last-child { margin-bottom: 0; }
.snippet-absent b { color: var(--eona-navy); }
.snippet-absent-track { font-size: 12.5px; color: #5a5d86; }

@media (max-width: 720px) {
  .code-block-pre { font-size: 11.5px; }
  .usage-preview { padding: 16px; }
}

/* ---------- DatasetCard ----------------------------------------------
   A catalog entry. Replaces edc-web-components' PatternFly DatasetCard,
   which brought a second design system along with it. Whole card is one
   <a>, so the action needs no separate control. */
.dataset-card {
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--eona-white); border-radius: var(--eona-radius-card);
  box-shadow: var(--eona-shadow-card); text-decoration: none; color: inherit;
  transition: transform .18s ease, box-shadow .18s ease;
}
.dataset-card:hover { transform: translateY(-3px); box-shadow: 0 18px 40px rgba(4,5,83,.22); }
.dataset-card__media {
  position: relative; aspect-ratio: 16 / 9; background: var(--eona-lavender-pale);
  display: flex; align-items: center; justify-content: center;
}
.dataset-card__thumb { width: 100%; height: 100%; object-fit: cover; display: block; }
.dataset-card__thumb--empty {
  font-size: 40px; font-weight: var(--eona-weight-bold); color: var(--eona-lavender);
  display: flex; align-items: center; justify-content: center;
}
.dataset-card__badge {
  position: absolute; top: 12px; left: 12px;
  background: var(--eona-navy); color: var(--eona-white);
  font-size: 10.5px; font-weight: var(--eona-weight-semibold); letter-spacing: .08em;
  padding: 4px 10px; border-radius: var(--eona-radius-pill);
}
.dataset-card__body { padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.dataset-card__title {
  margin: 0; font-size: 16.5px; font-weight: var(--eona-weight-semibold);
  color: var(--eona-navy); line-height: 1.3;
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.dataset-card__version {
  font-size: 11px; font-weight: var(--eona-weight-medium); color: var(--eona-blue-action);
  background: var(--eona-lavender-pale); border-radius: var(--eona-radius-pill); padding: 2px 8px;
}
.dataset-card__publisher { margin: 0; font-size: 12.5px; color: #5a5d86; }
.dataset-card__description {
  margin: 0; font-size: 14px; line-height: var(--eona-line-body); color: #33355f; flex: 1;
}
.dataset-card__action {
  margin-top: 4px; font-size: 13.5px; font-weight: var(--eona-weight-semibold);
  color: var(--eona-blue-action);
}
.dataset-card:hover .dataset-card__action { color: var(--eona-blue-royal); }

/* Screen-reader-only text. The crate's first use is `EvolutionBadge`, whose
   direction glyph is aria-hidden so it is never read as punctuation; this
   carries the word instead. Not `display:none`, which removes it from the
   accessibility tree too. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- charts (eona-x/backlog#822) ---------- */
/* Pure SVG and no script: these render server-side and print. */

.chart-donut { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.chart-donut__svg { width: 120px; height: 120px; display: block; }
/* `fill: none` matters: a dashed circle is a ring only if it is unfilled. */
.chart-donut__track,
.chart-donut__value { fill: none; stroke-width: 22.5; }
.chart-donut__track { stroke: var(--eona-chart-track); }
.chart-donut__value--good { stroke: var(--eona-chart-good); }
.chart-donut__value--warning { stroke: var(--eona-chart-warning); }
.chart-donut__value--danger { stroke: var(--eona-chart-danger); }
.chart-donut__label {
  font-family: var(--eona-font-family);
  font-size: 22px; font-weight: var(--eona-weight-semibold);
  fill: var(--eona-text-primary);
}
.chart-donut__caption {
  font-size: 13px; color: var(--eona-text-muted); text-align: center;
}

.metric-tile {
  display: flex; flex-direction: column; gap: 2px;
  padding: 16px 18px; background: var(--eona-surface-raised);
  border: 1px solid var(--eona-border-subtle); border-radius: var(--eona-radius-card);
}
.metric-tile__label { font-size: 13px; color: var(--eona-text-muted); }
.metric-tile__value {
  font-size: 28px; font-weight: var(--eona-weight-semibold);
  color: var(--eona-text-primary); line-height: 1.15;
}
.metric-tile__help { font-size: 12px; color: var(--eona-text-muted); }
.metric-tile__delta { margin-top: 6px; }

.evolution-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: var(--eona-weight-medium);
}
.evolution-badge__glyph { font-size: 11px; line-height: 1; }
/* The value carries the text weight; the glyph beside it stays small so the
   pair reads as one unit rather than as an icon and a number. */
.evolution-badge__value { font-variant-numeric: tabular-nums; }
.evolution-badge--up { color: var(--eona-chart-good); }
.evolution-badge--down { color: var(--eona-chart-danger); }
.evolution-badge--flat { color: var(--eona-text-muted); }

/* Direction and band must survive a black-and-white print, where every
   stroke above collapses to a similar grey. The glyph carries direction;
   the ring is distinguished by a dash pattern per band. */
@media print {
  .chart-donut__value--warning { stroke-dasharray: none; stroke: #000; opacity: .55; }
  .chart-donut__value--danger { stroke: #000; opacity: .85; }
  .chart-donut__value--good { stroke: #000; opacity: .3; }
  .chart-donut__track { stroke: #d8d8d8; }
}
