/* ── Vitrine publique ───────────────────────────────────────────────────────
   Reprend les variables de style.css / branding.css : la vitrine suit donc le
   thème et la palette configurés pour l'instance, sans duplication de couleurs.
   Mise en page volontairement plus aérée que le portail : lecture longue par
   des visiteurs, pas consultation rapide par des membres. */

.pub-body {
  display: block;
  min-height: 100vh;
  background: var(--bg);
  line-height: 1.65;
}

/* ── Barre de navigation ── */
.pub-nav {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.7rem clamp(1rem, 5vw, 3.5rem);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}

.pub-brand { display: flex; align-items: center; flex-shrink: 0; }
.pub-brand img { height: 34px; width: auto; display: block; }

.pub-nav-links {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  flex: 1;
  overflow-x: auto;
  scrollbar-width: none;
}
.pub-nav-links::-webkit-scrollbar { display: none; }

.pub-nav-links a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.84rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
  padding: 0.25rem 0;
  border-bottom: 1.5px solid transparent;
}
.pub-nav-links a:hover,
.pub-nav-links a.active { color: var(--text); border-bottom-color: var(--accent); }

.pub-nav-actions { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; }

.pub-login-btn {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius, 6px);
  color: var(--accent);
  text-decoration: none;
  font-size: 0.82rem;
  white-space: nowrap;
}
.pub-login-btn:hover { background: var(--accent); color: #fff; }

/* ── Bandeau d'accueil ── */
.pub-hero {
  padding: clamp(3.5rem, 11vw, 7rem) clamp(1rem, 5vw, 3.5rem) clamp(3rem, 8vw, 5rem);
  border-bottom: 1px solid var(--border);
  background:
    radial-gradient(ellipse 80% 60% at 50% -10%,
      color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
    var(--bg);
}

.pub-hero-inner { max-width: 780px; margin: 0 auto; text-align: center; }

.pub-hero-title {
  font-size: clamp(2.1rem, 6vw, 3.6rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text);
  margin-bottom: 1rem;
}

.pub-hero-subtitle {
  font-size: clamp(1rem, 2.2vw, 1.22rem);
  color: var(--text-muted);
  max-width: 620px;
  margin: 0 auto;
}

.pub-hero-body { margin-top: 1.4rem; }
.pub-hero-actions { display: flex; gap: 0.7rem; justify-content: center; flex-wrap: wrap; margin-top: 2rem; }

/* Bandeau avec visuel : texte à gauche, image à droite. La classe n'est posée
   que si la section « hero » porte une image — sans elle, le bandeau garde sa
   présentation centrée. */
.pub-hero-visual:empty { display: none; }
.pub-hero-visual img { display: block; width: 100%; height: auto; }

.pub-hero.has-visual .pub-hero-inner {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  max-width: 1180px;
  text-align: left;
}
.pub-hero.has-visual .pub-hero-text { flex: 1 1 54%; min-width: 0; }
.pub-hero.has-visual .pub-hero-visual { flex: 1 1 46%; min-width: 0; }
.pub-hero.has-visual .pub-hero-subtitle { margin-left: 0; }
.pub-hero.has-visual .pub-hero-actions { justify-content: flex-start; }

/* En dessous de deux colonnes lisibles, on repasse au bandeau centré d'origine
   avec le visuel en dessous du texte. */
@media (max-width: 860px) {
  .pub-hero.has-visual .pub-hero-inner {
    flex-direction: column;
    text-align: center;
    max-width: 780px;
  }
  .pub-hero.has-visual .pub-hero-subtitle { margin-inline: auto; }
  .pub-hero.has-visual .pub-hero-actions { justify-content: center; }
  .pub-hero.has-visual .pub-hero-visual { max-width: 460px; }
}

.pub-btn-primary, .pub-btn-ghost {
  display: inline-block;
  padding: 0.6rem 1.3rem;
  border-radius: var(--radius, 6px);
  font-size: 0.88rem;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  font-family: inherit;
}
.pub-btn-primary { background: var(--accent); color: #fff; }
.pub-btn-primary:hover { background: var(--accent-hover); }
.pub-btn-ghost { border-color: var(--border); color: var(--text); background: transparent; }
.pub-btn-ghost:hover { border-color: var(--accent); color: var(--accent); }

/* ── Sections ── */
.pub-section { padding: clamp(3rem, 7vw, 5rem) clamp(1rem, 5vw, 3.5rem); }
.pub-section-alt { background: var(--surface); border-block: 1px solid var(--border); }
.pub-section-inner { max-width: 940px; margin: 0 auto; }

.pub-section-head { margin-bottom: 2rem; }
.pub-section-title {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  color: var(--text);
  letter-spacing: -0.01em;
  margin-bottom: 0.4rem;
}
.pub-section-lead { color: var(--text-muted); font-size: 0.95rem; }
.pub-muted { color: var(--text-muted); font-size: 0.9rem; }

.pub-section-image {
  display: block;
  width: 100%;
  max-height: 480px;
  object-fit: contain;
  border-radius: 10px;
  margin-bottom: 2rem;
}

/* Section texte + image : la figure flotte à droite et le texte l'habille.
   Le clearfix garde la figure dans le bloc de texte quand elle est plus haute
   que lui, sinon elle déborderait sur la section suivante. */
.pub-prose-floated::after { content: ''; display: block; clear: both; }
.pub-prose-floated .pub-section-image {
  float: right;
  width: 45%;
  max-width: 430px;
  max-height: none;
  height: auto;
  margin: 0.3rem 0 1.2rem clamp(1.5rem, 3vw, 2.5rem);
}
/* Trop étroit pour un habillage : la figure reprend toute la largeur. */
@media (max-width: 760px) {
  .pub-prose-floated .pub-section-image {
    float: none;
    width: 100%;
    max-width: none;
    margin: 1.5rem 0;
  }
}

/* Les titres de style.css sont en capitales : acceptable pour un intitulé de
   section, illisible pour un titre d'article scientifique ou une sous-partie
   de texte suivi. Ces niveaux-là reviennent donc à une casse normale. */
.pub-prose h3,
.pub-highlight h3,
.pub-paper-title,
.pub-modal-title {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 600;
}

/* ── Prose (corps des sections et des news) ── */
.pub-prose { color: var(--text); font-size: 1rem; }
.pub-prose p { margin-bottom: 1rem; }
.pub-prose p:last-child { margin-bottom: 0; }
/* Respiration demandée par « --- » dans le texte d'une section : l'écart entre
   paragraphes est uniforme par ailleurs, ceci le double ponctuellement. */
.pub-prose-gap { height: 1.6rem; }
.pub-prose h3 {
  font-size: 1.12rem;
  margin: 1.8rem 0 0.7rem;
  color: var(--text);
}
.pub-prose ul { margin: 0 0 1rem 1.2rem; }
.pub-prose li { margin-bottom: 0.35rem; }
.pub-prose a { color: var(--accent); }
.pub-prose strong { color: var(--text); font-weight: 600; }
.pub-prose code {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.88em;
  background: var(--surface-2);
  padding: 0.1em 0.35em;
  border-radius: 3px;
}

/* ── Cartes « highlights » ── */
.pub-highlights {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}
.pub-highlight {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius, 6px);
  padding: 1.2rem 1.3rem;
}
.pub-section-alt .pub-highlight { background: var(--bg); }
.pub-highlight h3 { margin: 0 0 0.4rem; font-size: 1rem; color: var(--text); }
.pub-highlight p { color: var(--text-muted); font-size: 0.9rem; margin: 0; }

/* ── News ── */
.pub-news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

.pub-news-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius, 6px);
  padding: 1.25rem;
  cursor: pointer;
  font-family: inherit;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.pub-news-card:hover { border-color: var(--accent); transform: translateY(-2px); }

.pub-card-date {
  font-size: 0.75rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.pub-card-title { font-size: 1.02rem; color: var(--text); line-height: 1.35; }
.pub-card-excerpt {
  font-size: 0.9rem;
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pub-card-more { font-size: 0.82rem; color: var(--accent); margin-top: auto; }

.pub-more { display: block; margin: 1.6rem auto 0; }

/* ── Publications ── */
.pub-filters { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1.6rem; }
.pub-input {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius, 6px);
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: 0.88rem;
}
.pub-section-alt .pub-input { background: var(--surface); }
.pub-input:focus { outline: none; border-color: var(--accent); }
#paperSearch { flex: 1; min-width: 220px; }
.pub-select { min-width: 130px; }

.pub-year-group { margin-bottom: 2rem; }
.pub-year-label {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.4rem;
  margin-bottom: 0.9rem;
}

.pub-paper {
  padding: 0.9rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.pub-paper:last-child { border-bottom: none; }
.pub-paper-title { font-size: 0.98rem; color: var(--text); line-height: 1.4; margin-bottom: 0.25rem; }
.pub-paper-authors { font-size: 0.86rem; color: var(--text-muted); }
.pub-paper-meta { font-size: 0.84rem; color: var(--text-muted); font-style: italic; margin-top: 0.15rem; }
.pub-paper-links { display: flex; gap: 0.9rem; margin-top: 0.4rem; flex-wrap: wrap; }
.pub-paper-links a { font-size: 0.8rem; color: var(--accent); text-decoration: none; }
.pub-paper-links a:hover { text-decoration: underline; }
.pub-paper-abstract {
  font-size: 0.88rem;
  color: var(--text-muted);
  margin-top: 0.5rem;
  padding-left: 0.8rem;
  border-left: 2px solid var(--border);
}
.pub-abstract-toggle {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.8rem;
  cursor: pointer;
  padding: 0;
  font-family: inherit;
}

/* ── Pied de page ── */
.pub-footer {
  border-top: 1px solid var(--border);
  padding: 2.5rem clamp(1rem, 5vw, 3.5rem);
  background: var(--bg);
}
.pub-footer-inner {
  max-width: 940px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
}
.pub-footer-logo { height: 30px; width: auto; opacity: 0.8; margin-bottom: 0.7rem; display: block; }
.pub-footer-links { display: flex; flex-direction: column; gap: 0.4rem; }
.pub-footer-links a { color: var(--text-muted); font-size: 0.85rem; text-decoration: none; }
.pub-footer-links a:hover { color: var(--accent); }

/* ── Lecture d'une news ── */
.pub-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.pub-modal[hidden] { display: none; }

.pub-modal-box {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius, 6px);
  padding: 2rem;
  max-width: 660px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
}
.pub-modal-title { font-size: 1.35rem; color: var(--text); margin: 0.3rem 0 1.2rem; line-height: 1.3; }
.pub-modal-close {
  position: absolute;
  top: 0.8rem;
  right: 1rem;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
.pub-modal-close:hover { color: var(--text); }

@media (max-width: 700px) {
  /* Les liens restent affichés et défilent horizontalement : les masquer
     laissait un visiteur sur téléphone sans aucun moyen de passer de News à
     Publications, qui sont des pages à part entière. */
  .pub-nav { gap: 0.7rem; flex-wrap: wrap; }
  .pub-nav-links { flex: 0 0 100%; gap: 0.9rem; order: 3; padding-bottom: 0.15rem; }
  .pub-nav-links a { font-size: 0.8rem; }
  .pub-nav-actions { margin-left: auto; }
  .pub-footer-inner { flex-direction: column; }
}

/* ── Pages dédiées (News, Publications) ─────────────────────────────────── */
.pub-page-head {
  padding: clamp(2.5rem, 6vw, 4rem) clamp(1rem, 5vw, 3.5rem) 0;
}

.pub-page-title {
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--text);
  margin-bottom: 0.5rem;
}

/* En-tête de section avec son lien « tout voir » à droite */
.pub-section-head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.pub-section-head-row .pub-btn-ghost { flex-shrink: 0; }

/* Sur l'accueil, les cartes d'actualité sont des liens vers /news */
a.pub-news-card { text-decoration: none; color: inherit; }

/* ── Carte du consortium ─────────────────────────────────────────────────── */
.pub-map { margin-top: 1.8rem; }

.pub-map-stats {
  display: flex;
  gap: 2.2rem;
  flex-wrap: wrap;
  margin-bottom: 1.2rem;
}
.pub-map-stat { display: flex; flex-direction: column; }
.pub-map-stat strong {
  font-size: 1.7rem;
  line-height: 1.1;
  color: var(--accent);
  font-weight: 700;
}
.pub-map-stat span { font-size: 0.8rem; color: var(--text-muted); letter-spacing: 0.03em; }

.pub-map-frame {
  border: 1px solid var(--border);
  border-radius: var(--radius, 6px);
  overflow: hidden;
  background: var(--surface);
}
.pub-section-alt .pub-map-frame { background: var(--bg); }
.pub-map-svg { display: block; width: 100%; height: auto; }

.pub-map-legend {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
  font-size: 0.75rem;
}
.pub-map-scale {
  flex: 1;
  max-width: 180px;
  height: 8px;
  border-radius: 4px;
  border: 1px solid var(--border);
}

/* Repli textuel du même décompte : lisible sans la carte, et seule forme
   utilisable au lecteur d'écran ou si le CDN est injoignable. */
.pub-map-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  margin: 1rem 0 0;
  padding: 0;
}
.pub-map-list li {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 0.15rem 0.7rem;
  font-size: 0.82rem;
}
.pub-map-country { color: var(--text); }
.pub-map-count { color: var(--accent); font-weight: 600; }

.pub-map-tooltip {
  position: fixed;
  z-index: 80;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
  color: var(--text);
  box-shadow: 0 4px 14px var(--shadow);
}

/* ── Figure animée : distorsions spectrales du CMB ───────────────────────────
   Le SVG est chargé par site.js depuis /figures/ puis injecté dans la page,
   ce qui permet de le styler ici (donc de suivre le thème) et de ne lancer
   l'animation qu'au moment où le lecteur arrive dessus. */
:root { --fig-firas:#b57bd8; --fig-y:#58a6e0; --fig-mu:#e0687a; }
[data-theme="light"] { --fig-firas:#8e44ad; --fig-y:#2472a4; --fig-mu:#c0392b; }

.pub-figure { clear: both; margin: 2.5rem 0 0; }

/* Figure posée sur un côté, le texte de la section l'habillant. Le marqueur
   doit alors être placé assez haut dans le texte pour qu'il reste des
   paragraphes à faire remonter à côté d'elle. */
.pub-figure-right, .pub-figure-left {
  clear: none;
  width: 46%;
  margin-top: 0.2rem;
  margin-bottom: 1.2rem;
}
.pub-figure-right { float: right; margin-left: clamp(1.5rem, 3vw, 2.5rem); }
.pub-figure-left  { float: left;  margin-right: clamp(1.5rem, 3vw, 2.5rem); }
/* Trop étroit pour un habillage : la figure reprend toute la largeur. */
@media (max-width: 760px) {
  .pub-figure-right, .pub-figure-left {
    float: none; width: 100%; margin: 1.8rem 0 0;
  }
}
/* Le bloc de texte doit englober la figure flottante, sinon elle déborderait
   sur la section suivante quand elle est plus haute que le texte. */
.pub-prose::after { content: ''; display: block; clear: both; }
.pub-figure svg { display: block; width: 100%; height: auto; }
.pub-figure figcaption {
  color: var(--text-muted); font-size: 0.82rem; line-height: 1.5; margin-top: 0.6rem;
}

.fig-frame { fill: none; stroke: var(--border); stroke-width: 1.2; }
.fig-tick  { stroke: var(--border); stroke-width: 1.2; }
.fig-num   { fill: var(--text-muted); font-size: 15px; }
.fig-exp, .fig-sub { font-size: 11px; }
.fig-axis  { fill: var(--text-muted); font-size: 17px; }

.fig-curve  { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.fig-cmb    { stroke: var(--text);       stroke-width: 4; }
.fig-dt     { stroke: var(--text);       stroke-width: 1.4; }
.fig-fg     { stroke: var(--text-muted); stroke-width: 2.6; }
.fig-firas  { stroke: var(--fig-firas);  stroke-width: 3.4; stroke-dasharray: 1 7; }
.fig-ydist  { stroke: var(--fig-y);      stroke-width: 2.4; }
.fig-mudist { stroke: var(--fig-mu);     stroke-width: 2.4; }
.fig-fossil { stroke: var(--text);       stroke-width: 2.6; }
.fig-dashed { stroke-dasharray: 9 7; }
.fig-band   { fill: var(--text-muted); opacity: 0.18; }

.fig-lab { font-size: 17px; font-weight: 600; opacity: 0; }
.fig-cmb-l, .fig-dt-l { fill: var(--text); }
.fig-dt-l    { font-weight: 400; }
.fig-fg-l    { fill: var(--text-muted); }
.fig-firas-l { fill: var(--fig-firas); }
.fig-y-l     { fill: var(--fig-y); }
.fig-mu-l    { fill: var(--fig-mu); }
.fig-fossil-l{ fill: var(--text); font-size: 20px; font-weight: 700; }

/* Chaque courbe est révélée par un rectangle de découpe que l'on étire :
   contrairement à stroke-dashoffset, ça marche aussi sur les traits
   pointillés (branches négatives de µ et y) et sur la bande d'avant-plans. */
.fig-wipe { transform: scaleX(0); transform-origin: 105px 0; transform-box: view-box; }
@keyframes fig-wipe { to { transform: scaleX(1); } }
@keyframes fig-fade { to { opacity: 1; } }
.pub-figure.is-playing .fig-lab { animation: fig-fade 0.5s forwards; }
.pub-figure.is-playing .fw-cmb{animation:fig-wipe 1.4s 0.0s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-dt{animation:fig-wipe 1.2s 0.5s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-band{animation:fig-wipe 1.0s 1.0s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-fgline{animation:fig-wipe 1.2s 1.0s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-firas{animation:fig-wipe 1.0s 1.7s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-yneg{animation:fig-wipe 1.2s 2.3s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-ypos{animation:fig-wipe 1.2s 2.3s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-muneg{animation:fig-wipe 1.2s 2.9s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-mupos{animation:fig-wipe 1.2s 2.9s cubic-bezier(.4,0,.2,1) forwards}
.pub-figure.is-playing .fw-fossil{animation:fig-wipe 1.6s 3.6s cubic-bezier(.4,0,.2,1) forwards}

/* Sans animation : on montre directement la figure terminée. */
@media (prefers-reduced-motion: reduce) {
  .pub-figure .fig-wipe { transform: scaleX(1); animation: none; }
  .pub-figure .fig-lab  { opacity: 1; animation: none; }
}

/* ── Schéma optique animé ────────────────────────────────────────────────────
   Le schéma est large et détaillé : il prend toute la largeur, l'interférogramme
   se plaçant juste en dessous sur la même échelle horizontale. */
.op-wrap { position: relative; display: flex; flex-direction: column; gap: 0.4rem; }
.op-wrap svg { display: block; width: 100%; height: auto; }

:root { --op-sky:#e0687a; --op-bbir:#58a6e0; --op-mix:#9b7fd4; }
[data-theme="light"] { --op-sky:#c0392b; --op-bbir:#2472a4; --op-mix:#6b4fa8; }

/* Chaque faisceau est un chemin unique : ses tronçons peuvent se recouvrir
   (faisceau incident et réfléchi près d'un miroir) sans que le remplissage
   s'assombrisse, puisqu'il n'est peint qu'une fois. */
.op-beam { stroke-width: 1; fill-opacity: 0.32; transition: fill-opacity 0.4s, stroke-opacity 0.4s; }
.op-beam-sky  { fill: var(--op-sky);  stroke: var(--op-sky); }
.op-beam-bbir { fill: var(--op-bbir); stroke: var(--op-bbir); }
.op-beam-mix  { fill: var(--op-mix);  stroke: var(--op-mix); }
/* Voie non retenue : elle s'arrête sur le BSM, on la laisse visible en sourdine. */
.op-beam.is-blocked { fill-opacity: 0.07; stroke-opacity: 0.25; }

.op-mirror-arc { fill: none; stroke: var(--text); stroke-width: 6; stroke-linecap: round; }
.op-mirror-moving { stroke: var(--text); }
.op-mirror-small { stroke-width: 4.5; }
.op-mirror-big { stroke-width: 7; }
.op-pol { fill: var(--surface-2); stroke: var(--text-muted); stroke-width: 1.6; }
.op-dichroic { stroke: var(--text); stroke-width: 4; stroke-linecap: round; }
.op-horn { fill: var(--surface-2); stroke: var(--text-muted); stroke-width: 1.6; }
.op-arrow { fill: var(--accent); }
.op-arrow-line { stroke: var(--accent); stroke-width: 2.4; fill: none; }
.op-block { fill: none; stroke: var(--border); stroke-width: 1.4; stroke-dasharray: 6 5; }

.op-bbir-box { fill: var(--surface-2); stroke: var(--op-bbir); stroke-width: 2; }
.op-bbir-teeth { fill: none; stroke: var(--op-bbir); stroke-width: 2.2; }

/* BSM : rangé hors du faisceau quand il laisse passer le télescope, basculé à
   45° dans le faisceau quand il y renvoie le BBIR. */
.op-bsm-blade {
  fill: var(--text);
  transform-box: view-box;
  transform: translate(390px, calc(var(--bsm-y) + var(--bsm-park)));
  transition: transform 0.5s cubic-bezier(.4,0,.2,1);
}
.op-bsm.is-reflecting .op-bsm-blade { transform: translate(390px, var(--bsm-y)) rotate(var(--bsm-rot)); }

.op-lab   { fill: var(--text); font-size: 20px; font-weight: 600; }
.op-lab-m { fill: var(--text); font-size: 19px; font-weight: 500; }
.op-lab-moving { fill: var(--accent); font-weight: 600; }
.op-lab-p { fill: var(--accent); font-size: 21px; font-weight: 700; }
.op-sub   { fill: var(--text-muted); font-size: 17px; }
.op-mode  { fill: var(--accent); font-size: 30px; font-weight: 700; }

/* Survol : l'élément se souligne, son nom complet s'affiche en infobulle. */
.op-part { cursor: help; }
.op-part:hover .op-mirror-arc,
.op-part:hover .op-pol,
.op-part:hover .op-horn,
.op-part:hover .op-bbir-box,
.op-part:hover .op-dichroic-box,
.op-part:hover .op-bsm rect { stroke: var(--accent); fill: var(--accent); fill-opacity: 0.18; }
.op-part:hover .op-mirror-arc { fill: none; }

.op-tip {
  position: absolute; z-index: 5; pointer-events: none;
  max-width: 300px; padding: 0.4rem 0.6rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  font-size: 0.8rem; line-height: 1.35; box-shadow: 0 4px 14px var(--shadow);
}

.op-axis { stroke: var(--border); stroke-width: 1.4; }
.op-axis-zpd { stroke-dasharray: 4 5; }
.op-axis-title { fill: var(--text-muted); font-size: 19px; }
.op-ifg-line  { fill: none; stroke: var(--accent); stroke-width: 2.4; }
.op-ifg-guide { stroke: var(--text-muted); stroke-width: 1.2; opacity: 0.5; }
.op-ifg-dot   { fill: var(--accent); }
.op-readout {
  fill: var(--text); font-size: 21px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.op-bsm-rail { stroke: var(--text-muted); stroke-width: 1.2; stroke-dasharray: 3 4; opacity: 0.5; }

/* Sélecteur de mode d'observation, sous le schéma. « Auto » fait défiler les
   quatre modes ; choisir un mode le maintient. */
.op-modes { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.op-mode-btn {
  flex: 1 1 8rem; display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.45rem 0.7rem; text-align: left; cursor: pointer;
  background: transparent; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--radius, 6px);
  font-family: inherit; font-size: 0.78rem; line-height: 1.3;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.op-mode-btn b { color: var(--text); font-size: 0.92rem; font-weight: 600; }
.op-mode-btn:hover { border-color: var(--text-muted); color: var(--text); }
/* Le mode affiché à l'instant : discret, il suit le défilement automatique. */
.op-mode-btn.is-current { border-color: var(--accent); }
/* Le mode retenu par le lecteur. */
.op-mode-btn.is-pinned {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border-color: var(--accent); color: var(--text);
}
.op-mode-btn.is-pinned b { color: var(--accent); }
