/* ══════════════════════════════════════════════
   东西情报 · ECLab News
   Material Design 3 (Material You) theme

   Shared M3 semantic tokens (surfaces, ink, outlines, containers, shape,
   elevation, motion) live in assets/tokens.css, loaded before this file.
   This :root holds only the journal's source color and its app-specific
   tokens — tonal helpers, extended type scale, layout width, and the
   journal's --accent / --brand / --headline-size / --w.

   Every color role is derived from --accent (set per-issue by app.js).
   The accent is treated as the M3 "primary" key color; surfaces, containers
   and on-* roles are generated from it with color-mix() so the whole UI
   re-tones per issue, the way Material You re-tones from a source color.
   ══════════════════════════════════════════════ */
:root {
  /* ── Source / primary key color ── */
  --accent: #4c566a; /* overridden per-issue by app.js */

  /* ── Tonal helpers (journal-specific) ── */
  --accent-bg: color-mix(in srgb, var(--accent) 9%, white);
  --accent-h: color-mix(in srgb, var(--accent) 80%, black);
  --accent-light: color-mix(in srgb, var(--accent) 30%, white);

  /* ── Shape ── */
  --radius: 12px; /* legacy token kept for safety */

  /* ── Typography (Material You is sans-first) ── */
  --brand:
    "PingFang SC", "Microsoft YaHei", "Noto Sans SC", Roboto, -apple-system,
    BlinkMacSystemFont, "Segoe UI", sans-serif;
  --serif: var(--brand); /* legacy alias → unified sans */
  --sans: var(--brand);
  --mono: "Roboto Mono", "SF Mono", "Consolas", monospace;

  /* ── M3 Expressive type scale ──
     Expressive leans on a formal scale with heavier "emphasized" display /
     headline roles to build hierarchy. Each token pairs size · weight ·
     line-height · tracking. Large roles use fluid clamp() sizing. */
  --display-l-size: clamp(2.4rem, 5vw, 3.4rem);
  --display-l-weight: 800;
  --display-l-lh: 1.08;
  --display-l-track: -0.02em;

  --display-m-size: clamp(2rem, 4vw, 2.75rem);
  --display-m-weight: 800;
  --display-m-lh: 1.12;
  --display-m-track: -0.015em;

  --headline-size: clamp(1.6rem, 2.5vw, 2rem);
  --headline-lh: 1.2;
  --headline-track: -0.01em;

  --title-l-size: 1.4rem;
  --title-l-weight: 700;
  --title-l-lh: 1.3;

  --title-m-size: 1.1rem;
  --title-m-weight: 700;
  --title-m-lh: 1.4;

  /* ── Layout ── */
  --w: 920px;
  --sidebar-w: 300px;
}

/* ══════════════════════════════════════════════
   Dark Mode — M3 dark color roles
   ══════════════════════════════════════════════ */
[data-theme="dark"] {
  /* ── Neutrals tinted by source (M3 dark neutral palette, subdued) ── */
  --bg: color-mix(in srgb, var(--accent) 5%, #111118);
  --surface: color-mix(in srgb, var(--accent) 4%, #1d1b20);
  --surface-1: color-mix(in srgb, var(--accent) 6%, #1d1b20);
  --surface-2: color-mix(in srgb, var(--accent) 8%, #1d1b20);
  --surface-3: color-mix(in srgb, var(--accent) 11%, #1d1b20);

  /* ── On-surface text roles ── */
  --ink: #e6e0e9;
  --ink-soft: #cac4d0;
  --muted: #938f99;
  --outline: color-mix(in srgb, var(--accent) 16%, #5a5660);
  --outline-soft: color-mix(in srgb, var(--accent) 10%, #3a3640);

  /* ── Primary roles (dark, subdued) ── */
  --on-primary: #ffffff;
  --primary-container: color-mix(in srgb, var(--accent) 28%, #1d1b20);
  --on-primary-container: color-mix(in srgb, var(--accent) 85%, white);

  /* ── Secondary roles (dark, subdued) ── */
  --secondary-container: color-mix(in srgb, var(--accent) 22%, #1d1b20);
  --on-secondary-container: color-mix(in srgb, var(--accent) 85%, white);

  /* ── Tonal helpers (dark, subdued) ── */
  --accent-bg: color-mix(in srgb, var(--accent) 12%, #1d1b20);
  --accent-h: color-mix(in srgb, var(--accent) 65%, white);
  --accent-light: color-mix(in srgb, var(--accent) 30%, #1d1b20);

  /* ── State layers (dark: 8% hover, 12% press) ── */
  --state-hover: color-mix(in srgb, var(--accent) 8%, transparent);
  --state-press: color-mix(in srgb, var(--accent) 12%, transparent);

  /* ── Elevations (M3: use lighter overlays on dark surfaces) ── */
  --elev-1: 0 1px 3px 1px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.3);
  --elev-2: 0 2px 6px 2px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.35);
  --elev-3: 0 4px 8px 3px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.35);
}

/* soften error red for dark backgrounds */
[data-theme="dark"] .state-msg.error {
  color: #f2b8b5;
}
/* calmer dark tag backgrounds */
[data-theme="dark"] .tag-rec {
  background: color-mix(in srgb, color-mix(in srgb, var(--accent) 60%, hsl(35, 70%, 50%)) 22%, #1d1b20);
  color: color-mix(in srgb, var(--accent) 35%, hsl(35, 70%, 72%));
  border-color: color-mix(in srgb, var(--accent) 22%, hsl(35, 60%, 45%));
}
[data-theme="dark"] .tag-journal {
  background: color-mix(in srgb, color-mix(in srgb, var(--accent) 60%, hsl(255, 45%, 50%)) 22%, #1d1b20);
  color: color-mix(in srgb, var(--accent) 35%, hsl(255, 50%, 75%));
  border-color: color-mix(in srgb, var(--accent) 22%, hsl(255, 40%, 50%));
}
[data-theme="dark"] .tag-keyword {
  background: color-mix(in srgb, color-mix(in srgb, var(--accent) 60%, hsl(150, 35%, 42%)) 22%, #1d1b20);
  color: color-mix(in srgb, var(--accent) 35%, hsl(150, 40%, 65%));
  border-color: color-mix(in srgb, var(--accent) 22%, hsl(150, 30%, 42%));
}
/* calmer dark featured hero + issue cards */
[data-theme="dark"] .featured-issue {
  background: var(--primary-container);
  border-color: color-mix(in srgb, var(--accent) 32%, #1d1b20);
}
/* hover: see @media (hover: hover) block at end of file */
[data-theme="dark"] .featured-issue::after {
  background: color-mix(in srgb, var(--on-primary-container) 6%, transparent);
}
/* hover: see @media (hover: hover) block at end of file */

/* ══════════════════════════════════════════════
   Reset & Base
   ══════════════════════════════════════════════ */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  scroll-behavior: smooth;
}
body {
  font-family: var(--brand);
  font-size: clamp(16px, 1vw + 11px, 18px);
  line-height: 1.7;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
[hidden] {
  display: none !important;
}

/* ══════════════════════════════════════════════
   Progress Bar — M3 linear indicator
   ══════════════════════════════════════════════ */
#progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  width: 0;
  background: var(--primary);
  border-radius: 0 var(--shape-full) var(--shape-full) 0;
  z-index: 1000;
  transition: width 0.1s linear;
}

/* ══════════════════════════════════════════════
   Header — M3 center-aligned top app bar
   ══════════════════════════════════════════════ */
#eclab-header {
  position: relative;
  background: var(--surface-2);
  border-bottom: 1px solid var(--outline-soft);
  padding: 2.75rem 2rem 2.25rem;
  text-align: center;
  overflow: hidden;
}
/* expressive soft accent glow behind the header content */
#eclab-header::before {
  content: "";
  position: absolute;
  top: -60%;
  left: 50%;
  width: 120%;
  height: 200%;
  transform: translateX(-50%);
  background: radial-gradient(
    closest-side,
    var(--state-hover),
    transparent 70%
  );
  pointer-events: none;
  z-index: 0;
}
.header-content {
  position: relative;
  z-index: 1;
}

.header-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  max-width: calc(var(--w) + var(--sidebar-w) + 3rem);
  margin: 0 auto;
}

#eclab-header .header-logo-wrap {
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  flex-shrink: 0;
  /* symmetric circle frame; logo image fills the frame (no flat colour behind) */
  border-radius: var(--shape-full);
  background: var(--surface);
  overflow: hidden;
  box-shadow:
    0 0 0 1.5px var(--outline),
    var(--elev-1);
  transition:
    transform 0.3s var(--ease-spring),
    box-shadow 0.25s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */
#eclab-header .header-logo-img {
  width: 103%;
  height: 103%;
  display: block;
  object-fit: cover;
  transform: translateY(-4%);
}

.header-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}

#eclab-header h1 {
  font-family: var(--brand);
  font-size: var(--display-m-size);
  font-weight: var(--display-m-weight);
  letter-spacing: var(--display-m-track);
  line-height: var(--display-m-lh);
  margin: 0;
}
/* clickable title → expressive pill */
#eclab-header h1 a {
  display: inline-block;
  color: var(--on-primary-container);
  background: var(--primary-container);
  text-decoration: none;
  padding: 0.35rem 1.4rem;
  border-radius: var(--shape-full);
  transition:
    transform 0.3s var(--ease-spring),
    background-color 0.25s var(--ease-standard),
    box-shadow 0.25s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */
#eclab-header h1 a:active {
  transform: scale(0.99);
}
#eclab-header .subtitle {
  font-family: var(--brand);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  margin: 0;
}
#eclab-header .subtitle-link {
  color: var(--muted);
  text-decoration: none;
  padding: 0.25rem 0.7rem;
  border-radius: var(--shape-full);
  transition:
    color 0.2s var(--ease-standard),
    background-color 0.2s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */

/* ── Theme toggle — M3 icon button in top-right of header ── */
/* header action buttons (theme toggle + lab link), positioned top-right.
   Matched to the issue appbar's button layout so icons sit at the same
   viewport position on both pages. */
.header-actions {
  position: fixed;
  top: 8px;
  right: .75rem;
  display: flex;
  gap: .4rem;
  z-index: 2;
}
#theme-toggle {
  position: relative;
  top: auto;
  right: auto;
  width: 48px;
  height: 48px;
  border: none;
}
/* hover: see @media (hover: hover) block at end of file */
#theme-toggle:active {
  transform: scale(0.92);
}

.theme-icon {
  position: absolute;
  display: grid;
  place-items: center;
  line-height: 0;
  transition: opacity .25s var(--ease-standard),
              transform .45s var(--ease-spring);
  will-change: transform, opacity;
}
.theme-icon svg { display: block; }
/* light mode: moon visible, sun hidden */
[data-theme="light"] .icon-sun,
html:not([data-theme]) .icon-sun {
  opacity: 0; transform: rotate(-120deg) scale(.45); pointer-events: none;
}
[data-theme="light"] .icon-moon,
html:not([data-theme]) .icon-moon {
  opacity: 1; transform: rotate(0deg) scale(1);
}
/* dark mode: sun visible, moon hidden */
[data-theme="dark"] .icon-moon {
  opacity: 0; transform: rotate(120deg) scale(.45); pointer-events: none;
}
[data-theme="dark"] .icon-sun {
  opacity: 1; transform: rotate(0deg) scale(1);
}
/* M3 spin — covers both toggle buttons */
.theme-toggle.spinning {
  animation: theme-spin .5s var(--ease-spring) both;
}
@keyframes theme-spin {
  0%   { transform: scale(1)    rotate(0deg); }
  30%  { transform: scale(.78)  rotate(130deg); }
  62%  { transform: scale(1.1)  rotate(295deg); }
  100% { transform: scale(1)    rotate(360deg); }
}

/* ══════════════════════════════════════════════
   Layout
   ══════════════════════════════════════════════ */
#page-wrapper {
  display: flex;
  max-width: calc(var(--w) + var(--sidebar-w) + 3rem);
  margin: 0 auto;
  padding: 2rem 1.5rem 3rem;
  gap: 1.75rem;
  align-items: flex-start;
}
/* front page (no sidebar): narrower wrapper + centered single content column */
body:not(.issue-view) #page-wrapper {
  max-width: calc(var(--w) + 3rem);
  justify-content: center;
}
body:not(.issue-view) #content {
  flex: 0 1 var(--w); /* don't grow to fill; let the wrapper center it */
  width: 100%;
  margin: 0 auto;
}

/* ══════════════════════════════════════════════
   Navigation Drawer (TOC Sidebar) — M3 nav drawer
   ══════════════════════════════════════════════ */
#toc-sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  position: sticky;
  top: 1.5rem;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
  padding: 1.25rem 0.75rem;
  background: var(--surface-1);
  border: none;
  border-radius: var(--shape-lg);
  box-shadow: var(--elev-1);
}

#toc-sidebar .toc-title {
  font-family: var(--brand);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary);
  padding: 0 0.9rem 0.7rem;
  margin-bottom: 0.5rem;
}

#sidebar-controls {
  padding: 0 0.25rem 0.85rem;
  margin-bottom: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

/* ── M3 segmented buttons (sliding pill toggles) ── */
.sidebar-pill-row {
  position: relative;
  display: flex;
  height: 42px; /* fixed so the rail icons can align to each row's center */
  background: var(--surface-3);
  border-radius: var(--shape-full);
  padding: 4px;
}

.pill-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  /* default covers the first pill (both toggles start with pill 1 active);
     JS refines the exact width/position, but this keeps the active pill's
     highlight visible even if JS measurement returns 0 (some Android WebViews) */
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  background: var(--primary);
  border-radius: var(--shape-full);
  box-shadow: var(--elev-1);
  pointer-events: none;
  transition:
    transform 0.4s var(--ease-spring),
    width 0.4s var(--ease-spring);
  z-index: 0;
}
.pill-thumb.no-spring {
  transition: none;
}

.sidebar-pill {
  position: relative;
  z-index: 1;
  flex: 1;
  font-family: var(--brand);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
  background: transparent;
  border: none;
  padding: 0.5rem 0.5rem;
  cursor: pointer;
  border-radius: var(--shape-full);
  transition: color 0.2s var(--ease-standard);
  white-space: nowrap;
}
/* hover: see @media (hover: hover) block at end of file */
.sidebar-pill.active {
  color: var(--on-primary);
}

#toc-sidebar nav {
  overflow: hidden;
  position: relative;
}

.nav-track {
  display: flex;
  width: 200%;
  transition: transform 0.4s var(--ease-emphasized);
}
.nav-track.no-spring {
  transition: none;
}

.nav-track > ul {
  width: 50%;
  list-style: none;
  padding: 0;
  margin: 0;
  position: relative;
  flex-shrink: 0;
}

/* ── M3 nav drawer active indicator: full-height pill ── */
.toc-indicator {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  width: 100%;
  height: 0;
  background: var(--secondary-container);
  border-radius: var(--shape-full);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  transition:
    transform 0.45s var(--ease-spring),
    height 0.45s var(--ease-emphasized),
    opacity 0.25s var(--ease-standard);
}
.toc-indicator.no-anim {
  transition: none;
}

.nav-track > ul > li {
  margin-bottom: 0.15rem;
}

.nav-track > ul > li > a {
  position: relative;
  z-index: 1;
  display: block;
  padding: 0.6rem 0.9rem;
  font-family: var(--brand);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  border-radius: var(--shape-full);
  transition:
    color 0.2s var(--ease-standard),
    background-color 0.2s var(--ease-standard);
  cursor: pointer;
}
/* hover: see @media (hover: hover) block at end of file */
/* keep weight constant so the indicator can't break on a line-count change */
.nav-track > ul > li > a.active {
  color: var(--on-secondary-container);
  font-weight: 500;
}
.nav-track > ul > li > a:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
  border-radius: var(--shape-full);
}

@media (prefers-reduced-motion: reduce) {
  .pill-thumb {
    transition: none;
  }
  .nav-track {
    transition: none;
  }
  .toc-indicator {
    transition: opacity 0.15s ease;
  }
  .tag {
    transition: none;
  }
  .index-section {
    transition: none !important;
    animation: none !important;
  }
  .category-section.fade-in {
    animation: none;
    opacity: 1;
  }
  .issue-card,
  .featured-issue {
    animation: none;
  }
  .article-card {
    animation: none;
  }
  .issue-title::after {
    animation: none;
  }
  #eclab-header::before {
    display: none;
  }
}

#toc-sidebar nav > ul > li > ul {
  display: none;
}

/* ── M3 FAB (mobile TOC toggle) ── */
#toc-toggle {
  display: none;
  position: fixed;
  bottom: 1.4rem;
  right: 1.4rem;
  width: 56px;
  height: 56px;
  border-radius: var(--shape-md);
  background: var(--primary-container);
  color: var(--on-primary-container);
  border: none;
  box-shadow: var(--elev-3);
  cursor: pointer;
  z-index: 900;
  place-items: center;
  transition:
    box-shadow 0.2s var(--ease-standard),
    border-radius 0.35s var(--ease-spring),
    transform 0.15s var(--ease-standard);
}
#toc-toggle svg { display: block; }
/* hover: see @media (hover: hover) block at end of file */
#toc-toggle:active {
  transform: scale(0.92);
  border-radius: var(--shape-full);
}

/* ══════════════════════════════════════════════
   Main Content
   ══════════════════════════════════════════════ */
#content {
  flex: 1;
  min-width: 0;
  max-width: var(--w);
}

.state-msg {
  font-family: var(--brand);
  font-size: 1rem;
  color: var(--muted);
  text-align: center;
  padding: 4rem 1rem;
}
.state-msg.error {
  color: #ba1a1a;
}

/* ── M3 Expressive contained loading indicator ──
   A single shape that rotates while morphing through the M3 shape set
   (circle → squircle → clover-ish → squircle). Pure CSS, accent-tinted. */
.loading-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}
.m3-loader {
  width: 52px;
  height: 52px;
  background: var(--primary);
  border-radius: 38% 62% 63% 37% / 41% 44% 56% 59%;
  animation:
    m3-loader-spin 2.4s var(--ease-emphasized) infinite,
    m3-loader-morph 2.4s var(--ease-spring) infinite;
}
@keyframes m3-loader-spin {
  to { transform: rotate(360deg); }
}
@keyframes m3-loader-morph {
  0%   { border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%; }
  25%  { border-radius: 62% 38% 46% 54% / 60% 56% 44% 40%; }
  50%  { border-radius: 30% 70% 70% 30% / 30% 52% 48% 70%; background: color-mix(in srgb, var(--accent) 55%, white); }
  75%  { border-radius: 58% 42% 38% 62% / 45% 62% 38% 55%; }
  100% { border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%; }
}
.loading-label {
  font-family: var(--brand);
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
  .m3-loader {
    animation: m3-loader-pulse 1.4s ease-in-out infinite;
    border-radius: var(--shape-full);
  }
  @keyframes m3-loader-pulse {
    0%, 100% { opacity: 0.5; }
    50% { opacity: 1; }
  }
}

/* ══════════════════════════════════════════════
   Headings — M3 type scale
   ══════════════════════════════════════════════ */
h2.section-h {
  position: relative;
  font-family: var(--brand);
  font-size: var(--title-l-size);
  font-weight: var(--title-l-weight);
  line-height: var(--title-l-lh);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  margin: 2.75rem 0 1.1rem;
  padding-bottom: 0.5rem;
  padding-left: 0.9rem;
  border-bottom: 1px solid var(--outline-soft);
}
/* expressive accent bar before each section heading */
h2.section-h::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.15em;
  bottom: 0.55rem;
  width: 5px;
  border-radius: var(--shape-full);
  background: linear-gradient(
    var(--primary),
    color-mix(in srgb, var(--accent) 45%, white)
  );
}

h3.category-h {
  display: inline-block;
  font-family: var(--brand);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--on-secondary-container);
  background: var(--secondary-container);
  margin: 1.75rem 0 0.6rem;
  padding: 0.3rem 0.85rem;
  border: none;
  border-radius: var(--shape-full);
}

/* ══════════════════════════════════════════════
   Issue title block + intro
   ══════════════════════════════════════════════ */
.issue-title {
  font-family: var(--brand);
  font-size: var(--headline-size);
  font-weight: var(--headline-weight);
  letter-spacing: var(--headline-track);
  line-height: var(--headline-lh);
  color: var(--ink);
  margin: 0.75rem 0 0.55rem;
}
/* expressive accent underline that grows in */
.issue-title::after {
  content: "";
  display: block;
  height: 4px;
  width: 64px;
  margin-top: 0.5rem;
  border-radius: var(--shape-full);
  background: linear-gradient(
    90deg,
    var(--primary),
    color-mix(in srgb, var(--accent) 45%, white)
  );
  animation: title-underline 0.5s var(--ease-emphasized) both;
}
@keyframes title-underline {
  from {
    width: 0;
    opacity: 0;
  }
  to {
    width: 64px;
    opacity: 1;
  }
}
.issue-meta {
  font-family: var(--brand);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--muted);
  margin-bottom: 1.25rem;
}
.issue-intro {
  background: var(--surface-2);
  border: none;
  border-radius: var(--shape-md);
  padding: 1rem 1.2rem;
  margin: 0.4rem 0 1.25rem;
  color: var(--ink-soft);
  font-size: 0.95rem;
  line-height: 1.75;
}

/* ══════════════════════════════════════════════
   Category Sections — filtering support
   ══════════════════════════════════════════════ */
.index-section {
  margin-bottom: 2rem;
}
.category-section {
  margin-bottom: 1.5rem;
}
.category-section.fade-in {
  animation: section-fade-in 0.35s var(--ease-emphasized) both;
}

@keyframes section-fade-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.index-section.panel-fade-in {
  animation: panel-fade-in 0.3s var(--ease-standard) both;
}
.index-section.panel-fade-out {
  animation: panel-fade-out 0.2s var(--ease-standard) both;
}
@keyframes panel-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes panel-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* ══════════════════════════════════════════════
   Index List
   ══════════════════════════════════════════════ */
.article-index-item {
  padding: 0.85rem 0.25rem;
  border-bottom: 1px solid var(--outline-soft);
}
.article-index-item:last-child {
  border-bottom: none;
}
.article-index-title {
  margin-bottom: 0.4rem;
}
.article-index-title a {
  font-family: var(--brand);
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  line-height: 1.5;
  display: block;
  transition: color 0.2s var(--ease-standard);
  cursor: pointer;
}
/* hover: see @media (hover: hover) block at end of file */
.article-index-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.4rem;
}
.article-index-summary {
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.65;
}

/* ── M3 chips/tags ── */
.tag {
  display: inline-block;
  font-family: var(--brand);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 0.28rem 0.7rem;
  border-radius: var(--shape-xs);
  white-space: nowrap;
  cursor: pointer;
  transition:
    filter 0.18s var(--ease-standard),
    transform 0.25s var(--ease-spring),
    box-shadow 0.18s var(--ease-standard);
  line-height: 1.4;
  vertical-align: middle;
}
/* hover: see @media (hover: hover) block at end of file */
.tag:active {
  transform: translateY(0) scale(1);
  box-shadow: none;
}

.tag-rec {
  background: color-mix(
    in srgb,
    color-mix(in srgb, var(--accent) 84%, hsl(35, 90%, 55%)) 20%,
    white
  );
  color: color-mix(in srgb, var(--accent) 50%, hsl(35, 75%, 36%));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, hsl(35, 70%, 55%));
}
.tag-journal {
  background: color-mix(
    in srgb,
    color-mix(in srgb, var(--accent) 84%, hsl(255, 65%, 58%)) 20%,
    white
  );
  color: color-mix(in srgb, var(--accent) 50%, hsl(255, 55%, 42%));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, hsl(255, 55%, 58%));
}
.tag-keyword {
  background: color-mix(
    in srgb,
    color-mix(in srgb, var(--accent) 84%, hsl(150, 55%, 48%)) 20%,
    white
  );
  color: color-mix(in srgb, var(--accent) 50%, hsl(150, 50%, 30%));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, hsl(150, 45%, 48%));
}

/* ══════════════════════════════════════════════
   Divider
   ══════════════════════════════════════════════ */
hr {
  border: none;
  height: 1px;
  background: var(--outline-soft);
  margin: 2.75rem 0;
}

/* ══════════════════════════════════════════════
   Article Detail Cards — M3 filled/elevated card
   ══════════════════════════════════════════════ */
.article-card {
  background: var(--surface-1);
  border: 1px solid var(--outline-soft);
  border-radius: var(--shape-lg);
  margin: 1.5rem 0;
  overflow: hidden;
  box-shadow: var(--elev-1);
  scroll-margin-top: 4.5rem; /* account for fixed appbar */
  cursor: pointer;
  transition:
    box-shadow 0.3s var(--ease-standard),
    transform 0.35s var(--ease-spring),
    border-color 0.25s var(--ease-standard);
  animation: card-enter 0.45s var(--ease-emphasized) both;
}
/* expressive staggered entrance across the detail list (delay set in JS) */
.article-card {
  animation-delay: calc(var(--enter-i, 0) * 0.045s);
}
/* hover: see @media (hover: hover) block at end of file */
.article-card:active {
  transform: translateY(-1px) scale(0.997);
}
.article-card h3 {
  font-family: var(--brand);
  font-size: var(--title-m-size);
  font-weight: var(--title-m-weight);
  color: var(--ink);
  line-height: var(--title-m-lh);
  letter-spacing: 0;
  text-transform: none;
  margin: 0;
  padding: 1rem 1.25rem 0.85rem;
  border: none;
  background: var(--surface-2);
  border-bottom: 1px solid var(--outline-soft);
}
.article-card p {
  padding: 0.5rem 1.25rem;
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.7;
  border-bottom: 1px solid var(--outline-soft);
}
.article-card p:last-child {
  border-bottom: none;
}
.article-card p strong {
  font-family: var(--brand);
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--on-secondary-container);
  margin-right: 0.5rem;
}
/* tag row inside a detail card (matches the index tag styling) */
.article-card-tags {
  padding: 0.85rem 1.25rem;
  margin: 0;
  border-bottom: 1px solid var(--outline-soft);
}
.article-card p.abstract {
  background: var(--accent-bg);
  padding: 0.8rem 1.25rem 0.9rem;
  font-size: 0.92rem;
  line-height: 1.8;
  color: var(--ink-soft);
}
.article-card .rec-flag {
  display: inline-block;
  font-family: var(--brand);
  font-size: 0.78rem;
  font-weight: 700;
  color: color-mix(in srgb, var(--accent) 50%, hsl(35, 75%, 36%));
}

/* ══════════════════════════════════════════════
   Links
   ══════════════════════════════════════════════ */
p a {
  color: var(--primary);
  text-decoration: none;
  word-break: break-word;
}
p a:hover {
  text-decoration: underline;
}

/* ══════════════════════════════════════════════
   Landing / Archive
   ══════════════════════════════════════════════ */
.landing-intro {
  background: var(--surface-2);
  border: none;
  padding: 1.1rem 1.3rem;
  margin: 1.5rem 0 2rem;
  color: var(--ink-soft);
  font-size: 0.98rem;
  line-height: 1.8;
  border-radius: var(--shape-md);
}
.landing-intro .intro-link {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}
.landing-intro .intro-link:hover {
  text-decoration: underline;
}
.landing-intro strong {
  color: var(--primary);
}

/* ── Hero / featured card — M3 expressive, flat + high contrast ── */
.featured-issue {
  position: relative;
  display: block;
  background: var(--primary-container);
  border: 2px solid var(--on-primary-container);
  border-radius: var(--shape-xl);
  padding: 1.75rem 1.75rem 1.5rem;
  margin-bottom: 2.5rem;
  text-decoration: none;
  color: inherit;
  box-shadow: none;
  overflow: hidden;
  transition:
    transform 0.35s var(--ease-spring),
    background-color 0.25s var(--ease-standard);
  animation: card-enter 0.45s var(--ease-emphasized) both;
}
/* expressive accent blob in the hero corner */
.featured-issue::after {
  content: "";
  position: absolute;
  right: -40px;
  bottom: -40px;
  width: 140px;
  height: 140px;
  border-radius: var(--shape-full);
  background: color-mix(in srgb, var(--on-primary-container) 12%, transparent);
  pointer-events: none;
  transition: transform 0.5s var(--ease-spring);
}
/* hover: see @media (hover: hover) block at end of file */
.featured-issue:active {
  transform: translateY(-1px) scale(0.995);
}
.featured-issue .featured-badge {
  position: relative;
  z-index: 1;
  font-family: var(--brand);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-primary);
  background: var(--primary);
  padding: 0.3rem 0.8rem;
  border-radius: var(--shape-full);
}
.featured-issue .featured-title {
  position: relative;
  z-index: 1;
  font-family: var(--brand);
  font-size: var(--headline-size);
  font-weight: var(--headline-weight);
  letter-spacing: var(--headline-track);
  line-height: var(--headline-lh);
  color: var(--on-primary-container);
  margin: 0.9rem 0 0.35rem;
}
.featured-issue .featured-meta {
  position: relative;
  z-index: 1;
  font-family: var(--brand);
  font-size: 0.88rem;
  font-weight: 600;
  color: color-mix(in srgb, var(--on-primary-container) 85%, transparent);
}

.year-group {
  margin-bottom: 2rem;
}
.year-heading {
  font-family: var(--brand);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ink);
  margin: 1.75rem 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--outline-soft);
}
.issue-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1rem;
}

/* ── M3 expressive outlined card — flat, high contrast ── */
.issue-card {
  display: block;
  background: var(--surface);
  border: 1.5px solid var(--outline);
  border-radius: var(--shape-md);
  padding: 1.2rem 1.25rem;
  text-decoration: none;
  color: inherit;
  box-shadow: none;
  transition:
    transform 0.3s var(--ease-spring),
    border-color 0.25s var(--ease-standard),
    background-color 0.25s var(--ease-standard);
  animation: card-enter 0.45s var(--ease-emphasized) both;
}
/* expressive staggered entrance across the grid */
.issue-card:nth-child(1) {
  animation-delay: 0.02s;
}
.issue-card:nth-child(2) {
  animation-delay: 0.06s;
}
.issue-card:nth-child(3) {
  animation-delay: 0.1s;
}
.issue-card:nth-child(4) {
  animation-delay: 0.14s;
}
.issue-card:nth-child(5) {
  animation-delay: 0.18s;
}
.issue-card:nth-child(6) {
  animation-delay: 0.22s;
}
.issue-card:nth-child(n + 7) {
  animation-delay: 0.26s;
}
@keyframes card-enter {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}
/* hover: see @media (hover: hover) block at end of file */
.issue-card:active {
  transform: translateY(-1px) scale(0.99);
}
.issue-card .ic-title {
  font-family: var(--brand);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.4rem;
  line-height: 1.4;
}
.issue-card .ic-meta {
  font-family: var(--brand);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--muted);
}

/* ── M3 text button ── */
.back-link {
  display: inline-flex;
  align-items: center;
  font-family: var(--brand);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--primary);
  text-decoration: none;
  margin: 0.5rem 0 1.25rem;
  padding: 0.5rem 0.9rem 0.5rem 0.7rem;
  border-radius: var(--shape-full);
  transition: background-color 0.2s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */

/* ══════════════════════════════════════════════
   Issue App Bar — Google Workspace style, fixed
   ══════════════════════════════════════════════ */
#issue-appbar {
  --appbar-h: 64px;
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--appbar-h);
  background: var(--bg);
  border-bottom: 1px solid var(--outline-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: 0 .75rem;
  z-index: 980;
}

/* three zones */
.appbar-left  { display: flex; align-items: center; gap: .6rem; flex: 0 0 auto; }
.appbar-center { flex: 1; display: flex; justify-content: center; align-items: center; padding: 0 .75rem; min-width: 0; }
.appbar-right { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; }

/* shared icon button style in appbar */
.appbar-icon-btn {
  width: 48px;
  height: 48px;
  border-radius: var(--shape-full);
  border: none;
  background: var(--surface-2);
  cursor: pointer;
  display: grid;
  place-items: center;
  line-height: 0;
  color: var(--muted);
  text-decoration: none;
  flex-shrink: 0;
  transition: color .2s var(--ease-standard), background-color .2s var(--ease-standard), border-radius .3s var(--ease-spring), transform .2s var(--ease-spring);
}
.appbar-icon-btn svg { display: block; }
/* hover: see @media (hover: hover) block at end of file */
/* M3 Expressive press: the round button morphs toward a squircle + squishes */
.appbar-icon-btn:active {
  border-radius: var(--shape-md);
  transform: scale(0.9);
}

/* appbar small logo */
.appbar-logo-wrap {
  width: 36px; height: 36px;
  border-radius: var(--shape-full);
  overflow: hidden;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: var(--surface);
  box-shadow: 0 0 0 1.5px var(--outline);
  transition: box-shadow .2s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */
.appbar-logo-img {
  width: 103%; height: 103%;
  object-fit: cover;
  transform: translateY(-4%);
  display: block;
}

.appbar-title {
  font-family: var(--brand);
  font-size: .95rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  letter-spacing: .01em;
}

/* search bar — taller, M3 style */
.appbar-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: 540px;
  height: 48px;
  background: var(--surface-3);
  border-radius: var(--shape-full);
  border: 1.5px solid transparent;
  transition: border-color .2s var(--ease-standard), background-color .2s var(--ease-standard), box-shadow .2s var(--ease-standard);
}
.appbar-search-wrap:focus-within {
  background: var(--surface);
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.search-icon {
  position: absolute;
  left: 1rem;
  color: var(--muted);
  pointer-events: none;
  line-height: 0;
  display: grid;
  place-items: center;
}
.search-icon svg { display: block; }
.appbar-search {
  width: 100%;
  height: 100%;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--brand);
  font-size: .92rem;
  color: var(--ink);
  padding: 0 3rem 0 3rem;
  border-radius: var(--shape-full);
}
.appbar-search::placeholder { color: var(--muted); }
.search-clear {
  position: absolute;
  right: .6rem;
  width: 32px; height: 32px;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  border-radius: var(--shape-full);
  line-height: 0;
  display: grid;
  place-items: center;
  transition: color .15s, background-color .15s;
}
.search-clear svg { display: block; }
/* hover: see @media (hover: hover) block at end of file */

/* lab link button */
.appbar-lab-link {
  width: auto;
  padding: 0 .9rem;
  gap: .4rem;
  font-size: .82rem;
  font-weight: 600;
  white-space: nowrap;
  display: flex;
  align-items: center;
}
.lab-link-text { font-family: var(--brand); }

/* body offset when issue appbar is shown.
   On mobile Chrome 100vh includes the area behind the URL bar, which makes the
   body taller than the visible viewport and introduces unwanted scroll. Pin the
   body to exactly the visible viewport so nothing shifts behind the appbar. */
body.issue-view {
  padding-top: 64px;
  overflow: hidden;
  height: 100vh;          /* fallback for browsers without dvh */
  height: 100dvh;
}
body.issue-view #eclab-header { display: none; }
body.issue-view #toc-toggle { display: none !important; } /* FAB hidden; drawer btn used instead */

/* ── Issue-view layout: Workspace-style inline drawer + rounded content card ── */
/* App bar blends into the drawer (no border) */
body.issue-view #issue-appbar { border-bottom: none; }

/* page-wrapper hosts the inline sidebar + content card */
body.issue-view #page-wrapper {
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 0 1.25rem 0 0; /* keep the content card off the right edge */
  max-width: 100%;
  margin: 0;
  height: calc(100vh - 64px);   /* fallback */
  height: calc(100dvh - 64px);
  min-height: calc(100vh - 64px);
  min-height: calc(100dvh - 64px);
  overflow: hidden; /* page itself doesn't scroll; the content card does */
}

/* Sidebar = rail (always) + panel (expanded only) */
body.issue-view #toc-sidebar {
  position: sticky;
  top: 64px;
  align-self: flex-start;
  display: flex;
  flex-direction: row;
  width: auto;
  max-height: calc(100vh - 64px);   /* fallback */
  max-height: calc(100dvh - 64px);
  height: calc(100vh - 64px);
  height: calc(100dvh - 64px);
  padding: 0;
  margin: 0;
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
  transform: none;
  z-index: 5;
}

/* the vertical icon rail */
#sidebar-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* gap + top padding match #sidebar-controls so each rail icon lines up
     vertically with its corresponding pill row */
  gap: .55rem;
  width: 72px;
  flex-shrink: 0;
  padding: 1rem .5rem;
}
.rail-btn {
  position: relative;
  width: 48px;
  /* height matches the pill-row height so centers align with the switches */
  height: 42px;
  border-radius: var(--shape-full);
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  line-height: 0;
  transition: background-color .2s var(--ease-standard), color .2s var(--ease-standard), border-radius .3s var(--ease-spring), transform .2s var(--ease-spring);
}
.rail-btn:active {
  border-radius: var(--shape-md);
  transform: scale(0.9);
}
.rail-btn svg {
  display: block;
  position: absolute;
  transition: opacity .2s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */
/* #rail-view: show keywords icon by default, journals when view=journals */
.rail-icon-journals { opacity: 0; }
body.view-journals .rail-icon-keywords { opacity: 0; }
body.view-journals .rail-icon-journals { opacity: 1; }
/* #rail-hide: show open eye by default, closed when hide-selected */
.rail-eye-closed { opacity: 0; }
body.hide-selected .rail-eye-open { opacity: 0; }
body.hide-selected .rail-eye-closed { opacity: 1; }

/* the expandable panel (switches + tag list) */
#sidebar-panel {
  display: flex;
  flex-direction: column;
  width: var(--sidebar-w);
  min-width: 0;
  overflow: hidden;
  transition: width .3s var(--ease-emphasized), opacity .2s var(--ease-standard);
}
/* sticky switches — do not scroll */
#sidebar-controls {
  padding: 1rem .8rem .85rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  flex-shrink: 0;
}
/* only the tag nav scrolls */
body.issue-view #toc-nav {
  flex: 1;
  overflow-x: hidden; /* clip the horizontally-sliding nav track */
  overflow-y: auto;   /* but let the tag list scroll vertically */
  overscroll-behavior: contain; /* don't chain scroll to the article */
  padding: 0 .5rem 1rem;
  min-height: 0; /* critical for flex child scroll */
}

/* permanent 文献详情 entry pinned to the bottom of the sidebar panel.
   Bottom padding + link height match the rail's bottom padding + button height
   so the text is vertically centered with the #rail-details icon. */
#sidebar-footer {
  flex-shrink: 0;
  padding: .5rem .5rem 1rem;
  border-top: 1px solid var(--outline-soft);
}
.details-link {
  display: flex;
  align-items: center;
  height: 42px;
  width: 100%;
  padding: 0 .9rem;
  font-family: var(--brand);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: transparent;
  border: none;
  border-radius: var(--shape-full);
  cursor: pointer;
  text-align: left;
  transition:
    color 0.2s var(--ease-standard),
    background-color 0.2s var(--ease-standard);
}
/* hover: see @media (hover: hover) block at end of file */
.details-link.active {
  color: color-mix(in srgb, var(--accent) 86%, black);
  background: color-mix(in srgb, var(--accent) 30%, white);
}
[data-theme="dark"] .details-link.active {
  color: color-mix(in srgb, var(--accent) 30%, white);
  background: color-mix(in srgb, var(--accent) 42%, #1d1b20);
}

/* rail icon for 文献详情 (visible when the panel is collapsed).
   Not highlighted in article-detail view — the footer text highlight suffices. */
#rail-details { margin-top: auto; }

/* collapsed state (wide screens): hide the panel, keep the rail */
@media (min-width: 901px) {
  body.issue-view.sidebar-collapsed #sidebar-panel {
    width: 0;
    opacity: 0;
    pointer-events: none;
  }
}

/* ── Higher-contrast UI accents (issue 4) ──────────────────────────────── */

/* Sidebar active-tag highlight: stronger fill + darker on-color text */
body.issue-view .toc-indicator {
  background: color-mix(in srgb, var(--accent) 30%, white);
}
[data-theme="dark"] body.issue-view .toc-indicator {
  background: color-mix(in srgb, var(--accent) 42%, #1d1b20);
}
body.issue-view .nav-track > ul > li > a.active,
body.issue-view .nav-track > ul > li > a:hover {
  color: color-mix(in srgb, var(--accent) 86%, black);
}
[data-theme="dark"] body.issue-view .nav-track > ul > li > a.active,
[data-theme="dark"] body.issue-view .nav-track > ul > li > a:hover {
  color: color-mix(in srgb, var(--accent) 30%, white);
}

/* Search bar: gentle resting background + clearer text/placeholder */
.appbar-search-wrap {
  background: color-mix(in srgb, var(--accent) 11%, #fdfcff);
  border-color: var(--outline);
}
[data-theme="dark"] .appbar-search-wrap {
  background: color-mix(in srgb, var(--accent) 10%, #1d1b20);
  border-color: var(--outline);
}
.appbar-search { color: var(--ink); }
.appbar-search::placeholder { color: var(--ink-soft); }
.search-icon { color: var(--ink-soft); }

/* Dark-mode switch icon: full-strength on-surface color + gentle bg */
.theme-toggle.appbar-icon-btn {
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 13%, #fdfcff);
}
/* hover: see @media (hover: hover) block at end of file */
[data-theme="dark"] .theme-toggle.appbar-icon-btn {
  background: color-mix(in srgb, var(--accent) 12%, #1d1b20);
}
/* hover: see @media (hover: hover) block at end of file */

/* Lab website link: full-strength color + gentle bg */
.appbar-lab-link {
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 13%, #fdfcff);
}
/* hover: see @media (hover: hover) block at end of file */
[data-theme="dark"] .appbar-lab-link {
  background: color-mix(in srgb, var(--accent) 12%, #1d1b20);
}
/* hover: see @media (hover: hover) block at end of file */

/* Drawer expand icon: no colored background at rest, circle only on hover */
#appbar-drawer {
  background: transparent;
  color: var(--ink);
}
/* hover: see @media (hover: hover) block at end of file */

/* content becomes a distinct rounded surface card.
   The card itself stays fixed in the viewport; only its inner content scrolls.
   flex: 1 lets it fill the wrapper height; min-height: 0 lets it shrink. */
body.issue-view #content {
  flex: 1;
  min-width: 0;
  min-height: 0;
  max-width: var(--w);
  margin: 1rem auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 2rem 2rem 2.5rem;
  background: var(--surface);
  border-radius: var(--shape-xl);
  box-shadow: var(--elev-1);
}
/* targets land just below the card's top edge (appbar is outside the scroll
   container, so the heading/title is always visible after navigation) */
body.issue-view .category-section,
body.issue-view h2.section-h,
body.issue-view .article-card {
  scroll-margin-top: 1.25rem;
}

/* ── Narrow screens: sidebar becomes an overlay drawer (no rounded corners, no rail visible) ── */
@media (max-width: 900px) {
  body.issue-view #toc-sidebar {
    position: fixed;
    top: 64px; left: 0; bottom: 0;
    background: var(--bg);
    border-radius: 0; /* no rounded corners */
    box-shadow: var(--elev-3);
    z-index: 950;
    transform: translateX(-110%);
    transition: transform .3s var(--ease-emphasized);
  }
  body.issue-view #toc-sidebar.open { transform: translateX(0); }
  /* on narrow, hide the rail, show only the panel */
  #sidebar-rail { display: none; }
  body.issue-view #sidebar-panel { width: var(--sidebar-w); opacity: 1; pointer-events: auto; }
  body.issue-view #page-wrapper { padding: 0; } /* content margin handles spacing */
  body.issue-view #content {
    margin: 1rem;
    padding: 1.25rem 1.1rem 1.75rem;
  }
  body.issue-view #toc-overlay.open {
    display: block;
    position: fixed;
    inset: 0;
    background: color-mix(in srgb, var(--ink) 40%, transparent);
    z-index: 940;
  }
  /* hide appbar title + logo + lab-link text on narrow to save space */
  .appbar-title { display: none; }
  .appbar-logo-wrap { display: none; }
  .appbar-center { padding: 0 .4rem; }
  .lab-link-text { display: none; }
}
#toc-overlay { display: none; }

/* search highlights */
mark.search-hl {
  background: color-mix(in srgb, var(--accent) 28%, #fff176);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}
[data-theme="dark"] mark.search-hl {
  background: color-mix(in srgb, var(--accent) 35%, #5f5100);
}

/* search matching-tags section */
.search-tag-section {
  margin-bottom: 1.25rem;
  padding: .85rem 1rem;
  background: var(--surface-2);
  border-radius: var(--shape-md);
  border: 1px solid var(--outline-soft);
  animation: card-enter .35s var(--ease-emphasized) both;
}
.search-tag-section-title {
  font-family: var(--brand);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: .6rem;
}
.search-tag-section .article-index-tags { margin: 0; }

/* ══════════════════════════════════════════════
   View Transitions — M3 shared-axis route change
   The old view slides/fades out to the left while the new one slides in from
   the right (forward feel). Progressive enhancement: browsers without the API
   just swap instantly (see navigate() in app.js).
   ══════════════════════════════════════════════ */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.4s;
    animation-timing-function: var(--ease-emphasized);
  }
  ::view-transition-old(root) {
    animation-name: vt-slide-out;
  }
  ::view-transition-new(root) {
    animation-name: vt-slide-in;
  }
  @keyframes vt-slide-out {
    to { opacity: 0; transform: translateX(-30px); }
  }
  @keyframes vt-slide-in {
    from { opacity: 0; transform: translateX(30px); }
  }
}

/* ══════════════════════════════════════════════
   M3 Expressive scroll-reveal system (shared with main site)
   ══════════════════════════════════════════════ */
.reveal {
  opacity: 0; transform: translateY(24px) scale(0.97);
  transition: opacity 0.6s var(--ease-emphasized, cubic-bezier(0.05, 0.7, 0.1, 1)),
              transform 0.6s cubic-bezier(0.22, 1.2, 0.36, 1);
}
.reveal.revealed { opacity: 1; transform: translateY(0) scale(1); }
.reveal-stagger > * {
  opacity: 0; transform: translateY(20px);
  transition: opacity 0.45s var(--ease-emphasized, cubic-bezier(0.05, 0.7, 0.1, 1)),
              transform 0.45s cubic-bezier(0.22, 1.2, 0.36, 1);
}
.reveal-stagger.revealed > *:nth-child(1) { transition-delay: 0.05s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(2) { transition-delay: 0.10s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(3) { transition-delay: 0.15s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(4) { transition-delay: 0.20s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(5) { transition-delay: 0.25s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(6) { transition-delay: 0.30s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(7) { transition-delay: 0.35s; opacity: 1; transform: translateY(0); }
.reveal-stagger.revealed > *:nth-child(8) { transition-delay: 0.40s; opacity: 1; transform: translateY(0); }

/* Journal header animated blobs (shared style with main site hero) */
#eclab-header .header-blob {
  position: absolute; border-radius: 50%; pointer-events: none; z-index: 0;
  filter: blur(50px);
}
#eclab-header .header-blob--red {
  width: 180px; height: 180px; top: -40px; left: -30px;
  background: #e4040f; opacity: 0.10;
  animation: journal-blob-float 16s ease-in-out infinite;
}
#eclab-header .header-blob--orange {
  width: 140px; height: 140px; bottom: -20px; right: -20px;
  background: #ff6e01; opacity: 0.09;
  animation: journal-blob-float 13s ease-in-out infinite reverse;
}
#eclab-header .header-blob--blue {
  width: 120px; height: 120px; top: 30%; right: 15%;
  background: #508bff; opacity: 0.08;
  animation: journal-blob-float 18s ease-in-out infinite;
  animation-delay: -6s;
}
@keyframes journal-blob-float {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33% { transform: translate(10px, -12px) scale(1.06); }
  66% { transform: translate(-8px, 8px) scale(0.95); }
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-stagger > * { opacity: 1; transform: none; transition: none; }
  #eclab-header .header-blob { animation: none; }
  .fab { animation: none !important; transition: none !important; }
}

/* ══════════════════════════════════════════════
   Responsive
   ══════════════════════════════════════════════ */
@media (min-width: 1400px) {
  :root {
    --w: 1000px;
    --sidebar-w: 320px;
  }
}

@media (max-width: 1200px) {
  #toc-toggle.visible {
    display: grid;
  }
  #page-wrapper {
    padding: 1.5rem 1rem 2rem;
  }
}

@media (max-width: 600px) {
  #eclab-header {
    padding: 2rem 1rem 1.75rem;
  }
  #eclab-header .header-logo-wrap {
    width: 64px;
    height: 64px;
  }
  #eclab-header h1 {
    font-size: 1.6rem;
  }
  #eclab-header .subtitle {
    font-size: 0.78rem;
  }
  .issue-title {
    font-size: 1.55rem;
  }
  .featured-issue .featured-title {
    font-size: 1.4rem;
  }
}

/* ══════════════════════════════════════════════
   M3 Expressive — Back-to-top FAB
   ══════════════════════════════════════════════ */
.fab {
  position: fixed; z-index: 970;
  display: inline-flex; align-items: center; gap: 0;
  height: 56px; min-width: 56px; padding: 0 16px;
  border: none; cursor: pointer;
  font-family: var(--brand); font-size: 0.85rem; font-weight: 650;
  color: var(--on-primary-container);
  background: var(--primary-container);
  border-radius: var(--shape-md);
  box-shadow: var(--elev-3);
  transition: transform 0.35s var(--ease-spring),
              box-shadow 0.25s var(--ease-standard),
              background-color 0.25s var(--ease-standard),
              opacity 0.3s var(--ease-standard),
              visibility 0.3s,
              gap 0.3s var(--ease-spring),
              padding 0.3s var(--ease-spring);
}
/* hover: see @media (hover: hover) block at end of file */
.fab:active { transform: scale(0.92); }

.fab-icon {
  flex-shrink: 0; display: block; line-height: 0;
  transition: transform 0.35s var(--ease-spring);
}
/* hover: see @media (hover: hover) block at end of file */

.fab-label {
  max-width: 0; overflow: hidden; white-space: nowrap; opacity: 0;
  transition: max-width 0.3s var(--ease-emphasized),
              opacity 0.25s var(--ease-standard),
              margin 0.3s var(--ease-spring);
  margin-left: 0;
}
/* hover: see @media (hover: hover) block at end of file */

.fab--back-to-top {
  bottom: 32px; right: 32px;
}
.fab--back-to-top.fab-enter {
  animation: fab-spring-in 0.5s var(--ease-spring) both;
}
@keyframes fab-spring-in {
  0%   { opacity: 0; transform: scale(0.4) translateY(40px); }
  60%  { opacity: 1; transform: scale(1.08) translateY(-4px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
.fab--back-to-top.fab-exit {
  animation: fab-spring-out 0.3s cubic-bezier(0.3, 0, 0.8, 0.15) both;
}
@keyframes fab-spring-out {
  to { opacity: 0; transform: scale(0.5) translateY(20px); }
}
.fab[hidden] { display: none; }

@media (max-width: 600px) {
  .fab--back-to-top { bottom: 24px; right: 24px; }
}

/* ══════════════════════════════════════════════
   Print
   ══════════════════════════════════════════════ */
@media print {
  #toc-sidebar,
  #toc-toggle,
  #toc-overlay,
  #progress-bar,
  #issue-appbar,
  .theme-toggle,
  #back-to-top {
    display: none !important;
  }
  #page-wrapper {
    display: block;
    max-width: 100%;
    padding: 0;
  }
  body {
    background: #fff;
  }
  #eclab-header h1 {
    font-size: 1.6rem;
  }
  .article-card {
    break-inside: avoid;
    box-shadow: none;
    border: 1px solid #ccc;
  }
  .article-card:hover { /* handled by @media (hover: hover) */ }
}

/* ══════════════════════════════════════════════
   Hover effects — only on devices with true hover
   Prevents "stuck" hover states on touchscreens.
   ══════════════════════════════════════════════ */
@media (hover: hover) and (pointer: fine) {
  /* dark mode overrides */
  [data-theme="dark"] .featured-issue:hover {
    background: color-mix(in srgb, var(--accent) 38%, #1d1b20);
  }
  [data-theme="dark"] .issue-card:hover {
    background: color-mix(in srgb, var(--accent) 15%, #1d1b20);
    border-color: var(--primary);
  }

  /* header */
  .header-logo-wrap:hover {
    transform: scale(1.05);
    box-shadow: 0 0 0 1.5px var(--primary), var(--elev-2);
  }
  #eclab-header h1 a:hover {
    background: var(--primary);
    color: var(--on-primary);
    transform: scale(1.03);
    box-shadow: var(--elev-1);
  }
  #eclab-header .subtitle-link:hover {
    color: var(--primary);
    background: var(--state-hover);
  }
  #theme-toggle:hover { transform: scale(1.08); }

  /* sidebar pills */
  .sidebar-pill:hover { color: var(--ink-soft); }

  /* nav drawer links */
  .nav-track > ul > li > a:hover {
    color: var(--on-secondary-container);
    background: transparent;
  }

  /* TOC toggle FAB */
  #toc-toggle:hover {
    box-shadow: var(--elev-3), 0 0 0 6px var(--state-hover);
  }

  /* article index */
  .article-index-title a:hover { color: var(--primary); }

  /* tags */
  .tag:hover {
    filter: brightness(1.04);
    transform: translateY(-2px) scale(1.03);
    box-shadow: var(--elev-1);
  }

  /* article cards */
  .article-card:hover {
    box-shadow: var(--elev-2);
    transform: translateY(-3px);
    border-color: transparent;
  }

  /* featured issue */
  .featured-issue:hover {
    transform: translateY(-4px) scale(1.005);
    background: color-mix(in srgb, var(--accent) 28%, white);
  }
  .featured-issue:hover::after { transform: scale(1.25); }

  /* issue cards */
  .issue-card:hover {
    transform: translateY(-4px);
    background: var(--secondary-container);
    border-color: var(--primary);
  }

  /* back link */
  .back-link:hover {
    text-decoration: none;
    background: var(--state-hover);
  }

  /* appbar icon buttons */
  .appbar-icon-btn:hover { color: var(--ink); background: var(--surface-3); }
  .appbar-logo-wrap:hover { box-shadow: 0 0 0 1.5px var(--primary); }
  .search-clear:hover { color: var(--ink); background: var(--state-hover); }
  .rail-btn:hover { background: var(--state-hover); color: var(--ink); }
  .details-link:hover {
    color: var(--on-secondary-container);
    background: var(--state-hover);
  }

  /* theme toggle + lab link in appbar */
  .theme-toggle.appbar-icon-btn:hover {
    color: var(--ink);
    background: color-mix(in srgb, var(--accent) 22%, #fdfcff);
  }
  [data-theme="dark"] .theme-toggle.appbar-icon-btn:hover {
    background: color-mix(in srgb, var(--accent) 20%, #1d1b20);
  }
  .appbar-lab-link:hover {
    color: var(--ink);
    background: color-mix(in srgb, var(--accent) 22%, #fdfcff);
  }
  [data-theme="dark"] .appbar-lab-link:hover {
    background: color-mix(in srgb, var(--accent) 20%, #1d1b20);
  }
  #appbar-drawer:hover {
    background: var(--state-hover);
    color: var(--ink);
  }

  /* FAB */
  .fab:hover {
    box-shadow: var(--elev-3), 0 6px 12px 4px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.12);
    background: color-mix(in srgb, var(--primary-container) 80%, var(--primary));
  }
  .fab:hover .fab-icon { transform: translateY(-2px); }
  .fab:hover .fab-label { max-width: 80px; opacity: 1; margin-left: 8px; }
}
