/* Light/dark theme matching SMARTPocket (Inter, white/cream surfaces, blue+orange accents).
   All colour, spacing, type-size, radius and motion values come from the tokens in :root so the
   dark theme is a single override block and the spacing/type rhythm stays consistent. */
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap");

@font-face{
  font-family:"Space Grotesk";
  src:url("fonts/space-grotesk-var.woff2") format("woff2");
  font-weight:300 700;font-style:normal;font-display:swap;
}
:root{
  /* spacing scale - 4 / 8 px rhythm */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:28px; --sp-8:32px; --sp-10:44px;
  /* type scale */
  --fs-xs:11px; --fs-sm:12px; --fs-base:13px; --fs-md:14px; --fs-lg:16px; --fs-xl:18px; --fs-2xl:22px; --fs-3xl:30px;
  /* radii */
  --r-sm:6px; --r:8px; --r-lg:12px; --r-xl:14px; --r-pill:20px;
  /* motion + focus */
  --ease:cubic-bezier(.4,0,.2,1);            /* standard ease-out - smooths every hover/state change */
  --transition:.18s var(--ease); --ring:rgba(30,125,110,.5);

  /* surfaces / text / borders (light) */
  --bg:#f8f9fa; --card:#ffffff; --surface-2:#f3f5f7;
  --border:#e5e7eb; --border-strong:#d1d5db;
  --text:#111827; --text-2:#334155; --muted:#666666; --faint:#94a3b8;
  --accent:#2c6bed; --accent-hover:#1e57d6; --accent2:#e98b39;
  /* THE LOGO'S OWN COLOURS, kept separate from --accent/--accent2 on purpose. The mark is a brand
     asset and is reproduced as the designer drew it (#0759ae / #ff641c); --accent/--accent2 are
     FUNCTION colours for UI and for the apo/holo duotone. They are close but not the same, and
     conflating them would either wash out the mark or drag every button toward the logo's deeper blue. */
  --logo-blue:#0759ae; --logo-orange:#ff641c; --logo-mid:#8d7180;
  /* display heading font + the apo->holo DATA duotone (design refresh tier 1).
     Left stop = --accent (blue) = apo, right stop = --accent2 (orange) = holo: the same two colours the
     SMARTFlexDB mark uses (blue helix, orange ligand/shift). It was teal->orange, but teal is the
     INTERACTIVE colour (links, focus rings) - reserving blue/orange for DATA keeps a reader from
     mistaking a link colour for an apo label. Consumers: .card's top edge (every card on the site),
     .hero-stat::after and the home hero rule. */
  --font-display:"Space Grotesk",Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --grad-apoholo:linear-gradient(90deg,var(--accent),var(--accent2));
  --backdrop:rgba(15,23,42,.45);
  /* RDKit 2D depictions are black-on-white line art - the bonds vanish on a dark fill, so this token
     stays light in BOTH themes (used only by .lig2d / .ligcell). */
  --panel-light:#ffffff;
  /* every other scientific canvas (3Dmol scenes, fornac 2D bubbles, transparent PNG thumbnails) follows
     the theme: white in light mode, near-black in dark mode so it stops flashing white on a dark page. */
  --canvas:#ffffff;
  --shadow-sm:0 1px 2px 0 rgba(0,0,0,.05);
  --shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);
  /* design refresh tier 2: atmosphere + card depth */
  --grid-line:rgba(15,23,42,.05); --motif:rgba(15,23,42,.06);
  --shadow-card:0 1px 2px rgba(16,24,40,.05),0 10px 26px -10px rgba(16,24,40,.13);
  --glow-apo:rgba(233,139,57,.10); --glow-holo:rgba(30,125,110,.10);

  /* status text */
  --ok:#16a34a; --warn:#d2772a; --bad:#dc2626;
  /* semantic tint pairs (badges / tags): bg + foreground */
  --t-green-bg:#e3f3f0; --t-green-fg:#1e7d6e;
  --t-orange-bg:#fbeede; --t-orange-fg:#b9701f;
  --t-purple-bg:#ede9fe; --t-purple-fg:#6d28d9;
  --t-blue-bg:#e7eefe; --t-blue-fg:#2c5fd0;
  --t-indigo-bg:#eef2ff; --t-indigo-fg:#3730a3;
  --t-slate-bg:#eef2f7; --t-slate-fg:#475569;
  --t-red-bg:#fde8e8; --t-red-fg:#b91c1c;
}

:root[data-theme="dark"]{
  --bg:#0f1419; --card:#1a212b; --surface-2:#232c38;
  --border:#2c3744; --border-strong:#3c4a5a;
  --text:#e6edf3; --text-2:#c3cdda; --muted:#97a3b1; --faint:#6c7886;
  --accent:#5b8cff; --accent-hover:#7aa2ff; --accent2:#f0a868;
  /* lifted for the dark canvas - #0759ae on near-black is barely visible. Because these live in the
     theme block and the mark is INLINE svg, the logo follows the site's own data-theme toggle, which an
     <img>-embedded SVG could never do (it can only see the OS preference). */
  --logo-blue:#5b8cff; --logo-orange:#ff8a4d; --logo-mid:#a98ea0;
  --backdrop:rgba(0,0,0,.65);
  /* dark scientific canvas (3Dmol scenes / fornac 2D / thumbnails); --panel-light stays #fff for RDKit */
  --canvas:#0b0e14;
  --shadow-sm:0 1px 2px 0 rgba(0,0,0,.4);
  --shadow:0 4px 10px -2px rgba(0,0,0,.55),0 2px 4px -1px rgba(0,0,0,.4);
  --grid-line:rgba(255,255,255,.055); --motif:rgba(255,255,255,.06);
  --shadow-card:0 2px 4px rgba(0,0,0,.4),0 14px 30px -12px rgba(0,0,0,.65);
  --glow-apo:rgba(240,168,104,.16); --glow-holo:rgba(95,214,191,.15); --ring:rgba(95,214,191,.5);

  --ok:#3fb96a; --warn:#e8a368; --bad:#f08a8a;
  --t-green-bg:#11302a; --t-green-fg:#5fd6bf;
  --t-orange-bg:#3a2a16; --t-orange-fg:#f0a868;
  --t-purple-bg:#2a2140; --t-purple-fg:#bba6f2;
  --t-blue-bg:#16243f; --t-blue-fg:#83a6ff;
  --t-indigo-bg:#1e2440; --t-indigo-fg:#a7b3f2;
  --t-slate-bg:#232c38; --t-slate-fg:#97a3b1;
  --t-red-bg:#3a1c1c; --t-red-fg:#f08a8a;
}

*{box-sizing:border-box}
html{color-scheme:light dark}
body{margin:0;background:var(--bg);color:var(--text);line-height:1.6;-webkit-font-smoothing:antialiased;
  font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
a{color:var(--t-green-fg);text-decoration:none;transition:color var(--transition),filter var(--transition)}
a:hover{filter:brightness(1.12)}
h1,h2,h3,h4{font-weight:700;line-height:1.2;letter-spacing:-.02em;margin:0}
h1,h2{font-family:var(--font-display)}
:focus-visible{outline:2px solid var(--ring);outline-offset:2px;border-radius:3px}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* branded text selection (translucent holo-teal - keeps any text colour readable) */
::selection{background:color-mix(in srgb,var(--t-green-fg) 22%,transparent)}
/* slim, unobtrusive scrollbars in both engines */
html{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:8px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--muted)}
/* Persistent, easy-to-grab horizontal scrollbar for the wide side-scrolling panels:
   Sequence alignment (.align-mono), Per-residue displacement + dashboard Feature Track
   (.dispscroll), and Base-pair arcs (.bparc-body). overflow-x:auto (set per-class) keeps the
   bar hidden until the content actually overflows; a *visible* track + a taller, higher-contrast
   thumb then make it obvious and mouse-draggable (the default transparent-track bar reads as an
   invisible hairline, esp. under macOS overlay scrollbars).
   GOTCHA: this is WebKit-only ON PURPOSE - do NOT add scrollbar-width/scrollbar-color to these
   selectors. Since Chrome 121 (Jan 2024), setting either standard property makes Blink IGNORE all
   ::-webkit-scrollbar-* rules and fall back to the OS overlay scrollbar, which auto-hides on macOS
   (i.e. "no scrollbar at all"). Firefox - which has no ::-webkit-scrollbar - gets the standard
   properties in the @-moz-document (Firefox-only) block just below. */
.align-mono::-webkit-scrollbar,.dispscroll::-webkit-scrollbar,.bparc-body::-webkit-scrollbar{height:12px}
.align-mono::-webkit-scrollbar-track,.dispscroll::-webkit-scrollbar-track,.bparc-body::-webkit-scrollbar-track{background:var(--surface-2);border-radius:8px}
.align-mono::-webkit-scrollbar-thumb,.dispscroll::-webkit-scrollbar-thumb,.bparc-body::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:8px;border:2px solid var(--surface-2);background-clip:content-box}
.align-mono::-webkit-scrollbar-thumb:hover,.dispscroll::-webkit-scrollbar-thumb:hover,.bparc-body::-webkit-scrollbar-thumb:hover{background:var(--muted)}
@-moz-document url-prefix(){
  .align-mono,.dispscroll,.bparc-body{scrollbar-width:thin;scrollbar-color:var(--border-strong) var(--surface-2)}
}

.site-footer{margin-top:var(--sp-10);padding:var(--sp-6) var(--sp-4);border-top:1px solid var(--border);
  text-align:center;color:var(--muted);font-size:var(--fs-base);background:var(--card)}

header{padding:var(--sp-3) var(--sp-6);background:var(--card);border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;row-gap:var(--sp-1);position:sticky;top:0;z-index:20;
  box-shadow:0 6px 20px -16px rgba(15,23,42,.45)}   /* soft downward lift so the sticky bar reads above content */
/* logo: icon + wordmark on one row (flex keeps the inline svg + text from wrapping to two lines).
   The back link reuses the .sub slot (a clickable <span>, styled exactly like the subtitle that renders
   fine here) - NO flex tweaks, so it lays out identically to the known-good subtitle. */
header h1{font-size:var(--fs-xl);display:flex;align-items:center}
header .sub{color:var(--muted);font-size:var(--fs-base)}
header .back-link{font-weight:600;cursor:pointer}
header .back-link:hover{color:var(--accent)}
.nav{margin-left:auto;display:flex;align-items:center;gap:var(--sp-1)}
.nav a{color:var(--muted);font-size:var(--fs-md);font-weight:600;padding:5px 10px;border-radius:var(--r-pill);transition:color var(--transition),background var(--transition)}
.nav a:hover{color:var(--accent);background:var(--surface-2)}
.nav a.active{color:var(--accent);background:var(--surface-2)}
/* dark/light toggle */
.theme-toggle{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;
  border:1px solid var(--border);border-radius:var(--r);background:var(--card);color:var(--muted);cursor:pointer;
  box-shadow:var(--shadow-sm);transition:color var(--transition),border-color var(--transition),background var(--transition)}
.theme-toggle:hover{color:var(--accent);border-color:var(--accent)}
.theme-toggle:active{transform:translateY(1px)}
.theme-toggle svg{width:17px;height:17px;display:block;flex:none}
/* the pair page also loads molstar/3Dmol/fornac, whose styles can inflate the toggle icon - pin it hard */
header .theme-toggle{flex:none;width:32px;height:32px;padding:0}
header .theme-toggle svg{width:17px !important;height:17px !important}
/* inline SVG icons replacing emoji */
.ico{width:14px;height:14px;display:inline-block;vertical-align:-2px;flex:none}
.ico-l{margin-right:5px}
/* ---- the SMARTFlexDB mark -------------------------------------------------------------------
   Geometry is inlined per page (this is a static site - the nav is duplicated too); the THEMING lives
   here, once, so a colour change is one edit rather than ten. */
.lm-b{fill:none;stroke:var(--logo-blue);stroke-linecap:round;stroke-linejoin:round}
.lm-o{fill:none;stroke:var(--logo-orange);stroke-linecap:round;stroke-linejoin:miter}
.lm-of{fill:var(--logo-orange)}
.lm-x{fill:none;stroke:url(#lmG);stroke-linecap:round;stroke-linejoin:round}
.lm-x2{fill:none;stroke:url(#hmG);stroke-linecap:round;stroke-linejoin:round}
.lm-g0{stop-color:var(--logo-orange)} .lm-g1{stop-color:var(--logo-mid)} .lm-g2{stop-color:var(--logo-blue)}
/* header: the SIMPLIFIED mark at 24px — the h1 is 18px/flex, so its line box is ~24px and the mark sits
   inside it without growing the bar. app.js re-measures --header-h at runtime so nothing would BREAK if it
   did, but the sticky header changing height between releases is a visible regression on every page. */
.logo-mark{width:20px;height:24px;display:block;flex:0 0 auto;margin-right:9px}
/* hero: the FULL mark beside a live-text wordmark — selectable, searchable, translatable and immune to a
   missing font, which is why the wordmark is NOT baked into the SVG. */
/* .hero-brand / .hero-mark / .hero-word live in home.css, which owns the Home page and loads after this
   file. Defining them here too just created a silent override. The --logo-* variables above are the
   shared part, and they stay here. */
/* sticky in-page section nav (pair page) */
/* title + section nav pinned together below the site header (so you always see which pair you're on) */
.pinhead{position:sticky;top:var(--header-h,54px);z-index:16;background:var(--bg);margin:0 0 var(--sp-4);
  box-shadow:0 6px 8px -8px rgba(0,0,0,.25)}
.pinhead #title{margin:8px 0}
.subnav{display:flex;gap:2px;flex-wrap:wrap;align-items:center;
  background:var(--bg);border-bottom:1px solid var(--border);margin:0;padding:6px 0}
.subnav a{font-size:var(--fs-base);font-weight:600;color:var(--muted);padding:5px 10px;border-radius:var(--r-sm);
  transition:color var(--transition),background var(--transition)}
.subnav a:hover,.subnav a.active{color:var(--accent);background:var(--surface-2)}
[id^="sec-"],#cardpanel,#ligcard{scroll-margin-top:var(--stick,150px)}
html{scroll-behavior:smooth}
.type-badge{display:inline-block;background:var(--t-indigo-bg);color:var(--t-indigo-fg);border-radius:var(--r-sm);
  padding:2px 9px;font-size:var(--fs-xs);font-weight:700;margin:0 4px 6px 0}
.copies-badge{display:inline-block;background:var(--surface-2);color:var(--muted);border-radius:var(--r-sm);
  padding:2px 9px;font-size:var(--fs-xs);font-weight:600;margin:0 4px 6px 0}   /* "N holo copies" on collapsed cards */
.if-badge{display:inline-block;padding:1px 8px;border-radius:10px;font-size:11px;font-weight:700;white-space:nowrap}
.comp-badge{display:inline-block;border-radius:var(--r-sm);padding:2px 8px;font-size:var(--fs-xs);font-weight:700;
  margin:0 4px 6px 0;vertical-align:middle}
.cb-multi{background:var(--t-slate-bg);color:var(--t-slate-fg)}
.cb-prot{background:var(--t-green-bg);color:var(--t-green-fg)}
.cb-dna{background:var(--t-purple-bg);color:var(--t-purple-fg)}

.wrap{max-width:1200px;margin:0 auto;padding:var(--sp-7)}
.wrap.wide{width:95%;max-width:2000px}   /* pair page: fill most of the viewport (small side margins) */
.meta{color:var(--muted);font-size:var(--fs-base)}
/* About page (.wrap.about-lg): bigger, higher-contrast body copy matching the unclassed License paragraphs */
.about-lg .meta,.about-lg li{font-size:var(--fs-lg);color:var(--text-2)}
/* ...but sections wrapped in .about-wide span the full column (no 72ch reading-measure cap) */
.about-wide p,.about-wide li{max-width:none!important}
h2{font-size:var(--fs-2xl);margin:2px 0 6px;font-weight:800}
h3{font-size:var(--fs-sm);margin:var(--sp-6) 0 var(--sp-2);color:var(--muted);text-transform:uppercase;
  letter-spacing:.05em;font-weight:600}

/* gallery */
.hero{text-align:center;margin:var(--sp-2) 0 var(--sp-6);background:radial-gradient(62% 150% at 50% -34%, var(--glow-holo), transparent 70%)}
.hero h2{font-size:var(--fs-3xl)}
.hero .meta{max-width:680px;margin:var(--sp-2) auto 0}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(218px,1fr));gap:var(--sp-4)}
@media(max-width:520px){.grid{grid-template-columns:1fr}}
/* first-load gallery entrance: cards fade/rise in, lightly staggered. Only when #gallery carries .ah-enter,
   which app.js adds ONCE on the initial render - never on filter/sort/page re-renders (so no replay-flicker). */
@keyframes ah-cardin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.grid.ah-enter>.card{animation:ah-cardin .4s var(--ease) both}
.grid.ah-enter>.card:nth-child(2){animation-delay:.035s}
.grid.ah-enter>.card:nth-child(3){animation-delay:.07s}
.grid.ah-enter>.card:nth-child(4){animation-delay:.105s}
.grid.ah-enter>.card:nth-child(5){animation-delay:.14s}
.grid.ah-enter>.card:nth-child(6){animation-delay:.175s}
.grid.ah-enter>.card:nth-child(7){animation-delay:.21s}
.grid.ah-enter>.card:nth-child(8){animation-delay:.245s}
.grid.ah-enter>.card:nth-child(9){animation-delay:.28s}
.grid.ah-enter>.card:nth-child(10){animation-delay:.315s}
.grid.ah-enter>.card:nth-child(11){animation-delay:.35s}
.grid.ah-enter>.card:nth-child(12){animation-delay:.385s}
.grid.ah-enter>.card:nth-child(n+13){animation-delay:.42s}   /* everything past the first screenful arrives together */
/* generic staggered rise-in for a container's direct children - used on Statistics (chart panels) and
   Cluster (plot + list cards). Those pages render once per page load, so no replay-guard is needed. */
.ah-in>*{animation:ah-cardin .4s var(--ease) both}
.ah-in>*:nth-child(2){animation-delay:.05s}
.ah-in>*:nth-child(3){animation-delay:.1s}
.ah-in>*:nth-child(4){animation-delay:.15s}
.ah-in>*:nth-child(5){animation-delay:.2s}
.ah-in>*:nth-child(6){animation-delay:.25s}
.ah-in>*:nth-child(n+7){animation-delay:.3s}

/* homepage controls + filters */
.controls{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;margin:6px 0 var(--sp-3)}
.controls .spacer{flex:1}
.controls .count{color:var(--muted);font-size:var(--fs-base)}
.searchbox{flex:0 1 320px}
.searchbox input{width:100%;font:inherit;line-height:normal;padding:6px var(--sp-3);border:1px solid var(--border);
  border-radius:var(--r);background:var(--card);color:var(--text);transition:border-color var(--transition)}
.searchbox input:focus{border-color:var(--t-green-fg);outline:none;box-shadow:0 0 0 3px var(--ring)}
.sortlbl{display:flex;align-items:center;gap:6px}
.controls select{font:inherit;padding:6px var(--sp-2);border:1px solid var(--border);border-radius:var(--r);
  background:var(--card);color:var(--text);cursor:pointer;transition:border-color var(--transition)}
.filters{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-3) var(--sp-4);
  margin:0 0 var(--sp-4);box-shadow:var(--shadow-sm)}
.filters .frow{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;margin:6px 0}
.filters .flabel{font-size:var(--fs-sm);font-weight:600;color:var(--muted);min-width:64px}
.chips{display:flex;gap:6px;flex-wrap:wrap}
/* ---- collapsible counted facet (Database page: Type / Method / Pocket motif) ---------------------
   A <details> so the disclosure is native: keyboard- and AT-accessible, and it cannot get stuck shut if a
   script throws. Each row carries the option's card count plus a bar scaled to the largest count in that
   facet, so the list reads as a distribution of the release rather than a bare list of names. */
.facet-dd>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px}
.facet-dd>summary::-webkit-details-marker{display:none}          /* Safari's default triangle */
.facet-dd>summary::after{content:"⌄";margin-left:auto;font-size:var(--fs-base);color:var(--muted);
  transition:transform var(--dur,.15s) var(--ease,ease)}
.facet-dd[open]>summary::after{transform:rotate(180deg)}
.facet-dd>summary:hover::after{color:var(--text)}
.fg-n{font-weight:600;text-transform:none;letter-spacing:0;color:var(--accent);font-size:var(--fs-xs)}
.optlist{display:flex;flex-direction:column;gap:0;margin-top:4px}
/* tight rows: the sidebar has three of these lists stacked, so a comfortable row height pushes Pocket
   motif below the fold. --fs-sm + 2px padding keeps ~10 options visible without scrolling. */
.opt{display:grid;grid-template-columns:1fr auto 34px;align-items:center;gap:8px;width:100%;
  background:none;border:0;border-radius:var(--r-sm);padding:2px 6px;cursor:pointer;text-align:left;
  font:inherit;font-size:var(--fs-sm);line-height:1.35;color:var(--text)}
.opt:hover{background:var(--bg)}
.opt-l{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.opt-n{color:var(--muted);font-size:var(--fs-xs);font-variant-numeric:tabular-nums}
.opt-b{height:9px;background:var(--border);border-radius:2px;overflow:hidden}
.opt-b>i{display:block;height:100%;background:var(--accent);opacity:.55}
.opt.on{background:var(--accent);color:#fff}
.opt.on .opt-n{color:#fff;opacity:.85}
.opt.on .opt-b{background:rgba(255,255,255,.3)}
.opt.on .opt-b>i{background:#fff;opacity:.9}
.chip{background:var(--card);border:1px solid var(--border);border-radius:var(--r-pill);padding:4px var(--sp-3);
  font-size:var(--fs-sm);cursor:pointer;color:var(--text);transition:border-color var(--transition),background var(--transition),color var(--transition)}
.chip:hover{border-color:var(--accent)}
.chip:active{transform:translateY(1px)}
.chip.on{background:var(--accent);color:#fff;border-color:var(--accent)}
.ctitle{font-size:var(--fs-sm);color:var(--muted);margin:2px 0 6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card{background-color:var(--card);
  /* apo->holo duotone top edge, hidden at rest (height 0) and grown to 3px on hover - brand through-line */
  background-image:var(--grad-apoholo);background-repeat:no-repeat;background-position:top left;background-size:100% 0;
  border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-4);
  box-shadow:var(--shadow-card);
  transition:box-shadow var(--transition),transform var(--transition),border-color var(--transition),background-size var(--transition);
  display:block;min-width:0;overflow:hidden}
.card:hover{border-color:var(--t-green-fg);box-shadow:var(--shadow);background-size:100% 3px}
a.card:hover{transform:translateY(-2px)}
.thumb{background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r);margin-bottom:var(--sp-3);
  height:120px;display:flex;align-items:center;justify-content:center;overflow:hidden}
.thumb svg{display:block}
.thumb3d{width:100%;height:100%;object-fit:contain;display:block}
.card h3{margin:0 0 var(--sp-3);font-size:var(--fs-lg);color:var(--text);text-transform:none;letter-spacing:-.01em;font-weight:700}
.lig{color:var(--accent2);font-weight:700}
.badge{display:inline-block;background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-sm);
  padding:2px var(--sp-2);font-size:var(--fs-sm);margin:2px 4px 2px 0;color:var(--muted)}

/* ---- research-console layout (home) ---- */
.intro{margin:6px 0 var(--sp-4);background:radial-gradient(52% 170% at 14% -40%, var(--glow-apo), transparent 70%)}
.intro h2{font-size:var(--fs-2xl)}
.legend-inline{white-space:nowrap}
.sw{display:inline-block;width:10px;height:10px;border-radius:2px;vertical-align:middle;margin:0 4px 0 10px}
.sw-holo{background:#2f9e8f}.sw-apo{background:#d2772a}
.mobile-only{display:none}
.console-layout{display:grid;grid-template-columns:248px minmax(0,1fr);gap:var(--sp-5);align-items:start}
.facets{position:sticky;top:74px;max-height:calc(100vh - 90px);overflow:auto;
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:2px var(--sp-4)}
.facets #filters{background:none;border:none;border-radius:0;padding:0;margin:0;box-shadow:none}
.facet-group{padding:var(--sp-3) 0;border-bottom:1px solid var(--border)}
.facet-group:last-child{border-bottom:none}
.facet-group>.flabel{display:block;font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;color:var(--muted);margin-bottom:var(--sp-2)}
.facet-group>.flabel .hint{float:right;font-weight:600;text-transform:none;letter-spacing:0}
.facet-check{display:flex;align-items:center;gap:6px;font-size:var(--fs-base);color:var(--text);margin:6px 0;cursor:pointer}
.facet-range{display:flex;align-items:center;gap:6px}
/* the spinners had no font-size of their own, so they inherited the body size and sat noticeably larger
   than the .opt rows and the facet labels around them. Match the counted-facet scale (--fs-sm). */
.facet-range input{flex:1;min-width:0;font-family:inherit;font-size:var(--fs-sm);line-height:1.35;
  padding:5px var(--sp-2)}
.facet-range .hint{font-size:var(--fs-sm)}
.results-toolbar{margin-bottom:var(--sp-4)}   /* the two .rt-row children carry the flex, see below */
.results-toolbar .count{font-weight:600;color:var(--text)}
.results-toolbar .spacer{flex:1}
.results-toolbar .searchbox{flex:0 1 240px}
.view-toggle{display:inline-flex;border:1px solid var(--border);border-radius:var(--r);overflow:hidden}
.view-toggle .vt{border:none;border-radius:0;box-shadow:none;padding:6px 9px}
.view-toggle .vt+.vt{border-left:1px solid var(--border)}
.view-toggle .vt.on,.view-toggle .vt.on:hover{background:var(--accent);color:#fff}
/* card metric chips + Δ bar */
.cbadges{margin:2px 0 4px;display:flex;flex-wrap:wrap;align-items:center}
.cstats{display:flex;gap:var(--sp-4);margin:var(--sp-2) 0 0}
.cstats .stat{display:flex;flex-direction:column;line-height:1.1}
.cstats .stat b{font-size:var(--fs-md);color:var(--text);font-variant-numeric:tabular-nums}
.cstats .stat span{font-size:10px;color:var(--muted);margin-top:1px}
/* dense results table */
.tablewrap{overflow-x:auto;border:1px solid var(--border);border-radius:var(--r-lg);background:var(--card)}
.restable{width:100%;border-collapse:collapse;font-size:var(--fs-base)}
.restable th{position:sticky;top:0;background:var(--card);text-align:left;color:var(--muted);font-weight:600;
  padding:var(--sp-2) var(--sp-3);border-bottom:2px solid var(--border);white-space:nowrap}
.restable th.num,.restable td.num{text-align:right;font-variant-numeric:tabular-nums}
.restable td{padding:7px var(--sp-3);border-bottom:1px solid var(--border);white-space:nowrap}
.restable tbody tr:last-child td{border-bottom:none}
.restable tbody tr:nth-child(even) td{background:var(--surface-2)}
.restable tbody tr:hover td{background:var(--t-green-bg)}
.restable .lig{color:var(--accent2);font-weight:600}
/* pagination */
.pager{display:flex;justify-content:center;align-items:center;gap:4px;flex-wrap:wrap;margin:var(--sp-5) 0 var(--sp-2)}
/* the Database toolbar carries the pager inline, so it drops the centring and the vertical margin that
   only make sense for a block sitting under a grid. Empty when there is one page -> zero footprint. */
/* the toolbar is TWO FIXED ROWS, not one wrapping line: row 1 = what you are looking at (count,
   search, view, per-page, sort), row 2 = what you can take away (CSV / Full release / Full data) with
   the pager pushed right. Fixed so the controls do not move between viewport widths. */
.rt-row{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
.rt-row-2{margin-top:var(--sp-2)}
/* ONE metric for every control in the toolbar. The two <select>s were unstyled: the existing rule is
   `.controls select`, and this toolbar is .rt-row, so they fell through to the browser default — a
   different font, border and height from the buttons beside them. The search box used `font:inherit`,
   which is the body size and therefore larger than everything else on the row. Both now match .btn
   exactly (--fs-base, 6px/--sp-3, --r, --shadow-sm), so the row reads as one set of controls. */
.rt-row .searchbox input,
.rt-row select{font-family:inherit;font-size:var(--fs-base);line-height:1.35;
  padding:6px var(--sp-3);border:1px solid var(--border);border-radius:var(--r);
  background:var(--card);color:var(--text);box-shadow:var(--shadow-sm);
  transition:border-color var(--transition),color var(--transition)}
.rt-row select{cursor:pointer;padding-right:var(--sp-2)}
.rt-row select:hover{border-color:var(--t-green-fg);color:var(--t-green-fg)}
.rt-row .searchbox input:focus,
.rt-row select:focus{border-color:var(--t-green-fg);outline:none;box-shadow:0 0 0 3px var(--ring)}
/* Sort stretched to fit its widest option ("Max Δ (apo→holo)"), leaving a box far wider than its content
   for every other choice. Cap it and let the native ellipsis handle the long one. */
.rt-row #sort{max-width:148px}
.rt-row #pageSize{max-width:64px}
/* the "Per page" / "Sort" words are chrome, not controls - keep them quiet and one line */
.rt-row .sortlbl{font-size:var(--fs-sm);color:var(--muted);white-space:nowrap;gap:5px}
.pager-inline{margin:0;gap:3px;flex-wrap:nowrap}
.pager-inline:empty{display:none}
.pgbtn{min-width:34px;padding:6px 11px;font-size:var(--fs-base);border:1px solid var(--border);background:var(--card);
  color:var(--text);border-radius:var(--r-sm);cursor:pointer;
  transition:border-color var(--transition),color var(--transition),background var(--transition)}
.pgbtn:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.pgbtn.on{background:var(--accent);color:#fff;border-color:var(--accent)}
.pgbtn:disabled{opacity:.45;cursor:default}
.pgdots{padding:0 4px;color:var(--muted)}
@media(max-width:820px){
  .console-layout{grid-template-columns:1fr}
  .facets{position:static;max-height:none;display:none;margin-bottom:var(--sp-3)}
  .facets.open{display:block}
  .mobile-only{display:inline-flex}
}

/* detail */
.detail-layout{display:flex;gap:var(--sp-6);align-items:flex-start;margin-top:6px}
.detail-layout .main{flex:1;min-width:0}
.detail-layout .sidebar{width:284px;flex:none;position:sticky;top:74px}
.detail-layout .sidebar h3{margin-top:6px}
.infocard{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-4) var(--sp-4);
  box-shadow:var(--shadow-sm);margin-bottom:var(--sp-4);font-size:var(--fs-base)}
.infocard .ic-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
.infocard .ic-pdb{font-weight:800;font-size:17px;letter-spacing:-.01em;color:var(--text)}
a.ic-pdb:hover{color:var(--accent)}
.infocard .ic-tag{font-size:var(--fs-xs);font-weight:700;padding:2px 9px;border-radius:var(--r-pill)}
.infocard .ic-tag.holo{background:var(--t-green-bg);color:var(--t-green-fg)}
.infocard .ic-tag.apo{background:var(--t-orange-bg);color:var(--t-orange-fg)}
.infocard .ic-tag.lig-tag{background:var(--t-purple-bg);color:var(--t-purple-fg)}
.lig2d{background:var(--panel-light);border:1px solid var(--border);border-radius:var(--r);padding:6px;margin:var(--sp-2) 0 var(--sp-3)}
.lig2d svg{display:block;width:100%;height:auto;max-width:280px;margin:0 auto}
/* THE LIGAND CARD IS ONE OF FOUR EQUAL COLUMNS, so it must not out-grow its neighbours (2026-07-28).
   Three squeezes, all scoped to #ligcard so the hover POPOVER (.lig2d-pop, which has room) and the
   holo/apo cards' Authors block keep their original sizing:
     - the 2D drawing caps at 200px instead of 280 and loses half its vertical margin;
     - the "Properties (hover)" trigger sat inside 8px/12px margins that read as a blank band on
       either side of a single line of text - 2px/6px now;
     - SMILES is no longer printed inline at all: it moved into a hover popover beside a copy button
       (.smiles-row), which removed 5-6 wrapped lines from the card. */
#ligcard .lig2d{padding:4px;margin:6px 0 8px}
#ligcard .lig2d svg{max-width:200px}
#ligcard .ligprops-wrap{margin:2px 0 6px}
/* re-assert the hover-popover reset at id specificity: `.lig2d-pop .lig2d` (0,2,0) would otherwise lose
   to `#ligcard .lig2d` (1,1,0) above. The popover has no caller in app.js today, so this is defensive
   rather than load-bearing - but a rule that silently stops applying is the wrong thing to leave behind. */
#ligcard .lig2d-pop .lig2d{margin:0;border:none;padding:0}
#ligcard .lig2d-pop .lig2d svg{max-width:280px}
/* ligand 2D depiction shown only on hover (keeps the card compact + uniform) */
.lig2d-wrap{position:relative;display:inline-block;margin:var(--sp-2) 0 var(--sp-3)}
.lig2d-trigger{font-size:var(--fs-sm);color:var(--accent);cursor:help;border-bottom:1px dashed var(--accent)}
.lig2d-pop{display:none;position:absolute;z-index:40;top:calc(100% + 6px);left:0;width:296px;
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow);padding:var(--sp-2)}
.lig2d-pop .lig2d{margin:0;border:none;padding:0}
.lig2d-wrap:hover .lig2d-pop{display:block}
/* chemical properties revealed on hover (2D depiction shown directly above) */
.ligprops-wrap{position:relative;display:inline-block;margin:var(--sp-2) 0 var(--sp-3)}
.ligprops-trigger{font-size:var(--fs-sm);color:var(--accent);cursor:help;border-bottom:1px dashed var(--accent)}
.ligprops-pop{display:none;position:absolute;z-index:40;top:calc(100% + 6px);left:0;width:min(280px,calc(100vw - 36px));
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow);padding:var(--sp-2) var(--sp-3)}
.ligprops-pop dl{margin:0}
.ligprops-wrap:hover .ligprops-pop{display:block}
/* SMILES trigger + copy button on one line; the popover holds the raw string, which is long and
   unbroken, so it gets `break-all` and a monospace face (the characters matter individually). */
.smiles-row{display:flex;align-items:center;gap:6px;margin:2px 0 2px}
#ligcard .smiles-row .ligprops-wrap{margin:0}   /* id specificity: beats `#ligcard .ligprops-wrap` above */
.smiles-pop{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:var(--fs-xs);
  line-height:1.5;word-break:break-all;white-space:normal}
/* equal-size info/ligand/overview tiles: all on one row, sharing the width equally */
/* FOUR cards since 2026-07-28 (Overview · Holo · Apo · Ligand) - the fifth "External links" card was
   dissolved into the other four, so the row is 4-up and each card is ~25% wider than it was at 5-up.
   That width matters: at 5-up the Overview <dl> was wrapping values mid-word ("Ribos omal RNA",
   "pocke t Δ"). Breakpoints step 4 -> 2 -> 1 rather than through 3, so the row never leaves a single
   orphan card on its own line. */
.cardrow{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-3);align-items:stretch;margin:var(--sp-2) 0 6px}
.cardrow .infocard{min-width:0;margin-bottom:0}
@media(max-width:1180px){.cardrow{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.cardrow{grid-template-columns:1fr}}
/* collapsible structure-details panel (pair page) */
.cardpanel{margin:var(--sp-2) 0 6px}
.cardpanel-head{width:100%;display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
  background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-3) var(--sp-4);
  box-shadow:var(--shadow-sm);cursor:pointer;text-align:left;font:inherit;color:var(--text);
  transition:border-color var(--transition),background var(--transition)}
.cardpanel-head:hover{border-color:var(--border-strong);background:var(--surface-2)}
.cp-caret{font-size:var(--fs-xs);color:var(--muted);transition:transform var(--transition);flex:none}
.cardpanel:not(.collapsed) .cp-caret{transform:rotate(90deg)}
.cp-title{font-weight:800;font-size:var(--fs-lg);flex:none}
.cp-summary{color:var(--muted);font-size:var(--fs-base);display:flex;gap:var(--sp-2);flex-wrap:wrap;align-items:center;min-width:0}
.cp-more{margin-left:auto;font-size:var(--fs-sm);font-weight:600;color:var(--accent);flex:none}
.cp-more::after{content:"Show all"}
.cardpanel:not(.collapsed) .cp-more::after{content:"Hide"}
.cardpanel:not(.collapsed) .cp-summary{display:none}
.cardpanel.collapsed .cardrow{display:none}
.cardpanel .cardrow{margin:var(--sp-3) 0 0}
.infocard .ic-tag.sum-tag{background:var(--t-slate-bg);color:var(--t-slate-fg)}
.linkcol{display:flex;flex-direction:column;gap:6px;margin-top:var(--sp-3)}
.linkcol .btn{display:block;width:100%;text-align:left;box-sizing:border-box;font-size:var(--fs-sm);padding:6px var(--sp-3)}
.linkcol .linkgrp-h{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:8px 0 3px}
.linkcol .linkgrp-h:first-child{margin-top:0}
/* links rendered INSIDE a card (2026-07-28): the standalone External-links card is gone, so the rows sit
   under the card's own content - a top rule separates them from the <dl> above without adding a heading.
   ONE ROW of equal-width buttons: `flex:1 1 0` makes 2 buttons half-width (holo: NAKB + HARIBOSS) and
   3-4 buttons third/quarter-width (ligand: PubChem/DrugBank/ChEMBL, plus ChEBI when the CCD has one)
   without hard-coding a count. `min-width:0` lets a label ellipsise rather than force the row to wrap;
   the full target is in each button's `title`. */
.linkcol-inline{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px;
  margin-top:11px;padding-top:11px;border-top:1px solid var(--border)}
/* TWO per row, not one flex share per button. The cards are ~1/4 of the row, so four buttons sharing a
   single line left each one narrower than its own label and the trailing arrow wrapped. A 2-column grid
   gives every button a definite width: holo fills one row (NAKB + HARIBOSS), the ligand card takes two
   rows (PubChem/DrugBank first, then ChEMBL - and ChEBI when the CCD carries one). A LONE button spans
   both columns so it is not left half-width beside a gap: the apo card (NAKB only) and Overview (ZIP). */
.linkcol-inline .btn{min-width:0;text-align:center;box-sizing:border-box;font-size:var(--fs-xs);
  padding:6px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.linkcol-inline .btn:only-child{grid-column:1 / -1}
/* downloads section: bundle manifest + prominent ZIP button + direct file links */
.dl-card{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);
  padding:var(--sp-4) var(--sp-5);box-shadow:var(--shadow-sm)}
.dl-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--sp-6)}
@media (max-width:760px){.dl-grid{grid-template-columns:1fr}}
.dl-card .flabel{display:block;font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;
  letter-spacing:.03em;color:var(--muted);margin-bottom:var(--sp-2)}
/* bundle CTA: the description with a small icon-only download button sitting RIGHT AFTER the text (the
   text takes only its natural width, so the button is not floated to the far edge). The button's size is
   ALSO set inline in renderDownloads so pair-page injected lib styles can't stretch it. */
.dl-cta{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);margin:0 0 var(--sp-2)}
.dl-cta-text{margin:0}
#dl-card a.btn.dl-zip{flex:none;width:24px;height:24px;padding:0;background:var(--surface-2)}
#dl-card .dl-zip .ico{width:13px;height:13px;flex:none;margin:0}
.dl-direct{margin-top:var(--sp-5);display:flex;flex-wrap:wrap;gap:6px}
.dl-direct .flabel{width:100%}
.dl-direct .btn{font-size:var(--fs-sm)}
.dl-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.dl-list li{display:flex;align-items:baseline;gap:var(--sp-3);font-size:var(--fs-sm)}
.dl-list code{background:var(--surface-2);border-radius:4px;padding:2px 7px;font-size:var(--fs-sm);
  white-space:nowrap;color:var(--text-2)}
.dl-desc{color:var(--muted)}
/* statistics page */
.statgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-4);margin-top:var(--sp-3)}
.statblock h3{margin-top:0}
.statbar{cursor:pointer}
.statbar:hover rect{opacity:.82}
.statbar:hover text{fill:var(--text)}
@media(max-width:1300px){.statgrid{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:980px){.statgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:640px){.statgrid{grid-template-columns:1fr}}
.statgrid.statgrid3{grid-template-columns:repeat(3,minmax(0,1fr))}
@media(max-width:980px){.statgrid.statgrid3{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:640px){.statgrid.statgrid3{grid-template-columns:1fr}}
/* API docs */
.apidoc .ep{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-3) var(--sp-4);
  margin-bottom:var(--sp-3);box-shadow:var(--shadow-sm)}
.apidoc .ep code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:var(--fs-base)}
.apidoc .ep code.m{background:#1e7d6e;color:#fff;border-radius:4px;padding:1px 7px;font-size:var(--fs-xs);margin-right:var(--sp-2)}
.apidoc .ep p{margin:var(--sp-2) 0 0;color:var(--muted);font-size:var(--fs-base)}
.infocard .ic-title{font-size:var(--fs-sm);color:var(--text);line-height:1.45;margin:6px 0 var(--sp-3);font-weight:500}
.infocard dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:7px var(--sp-3);margin:0}
.infocard dt{color:var(--muted);font-size:var(--fs-sm);white-space:nowrap;align-self:start}
/* `overflow-wrap:anywhere` used to break values MID-WORD when the cards were 5-up and narrow
   ("Ribos omal RNA", "pocke t Δ", "5XZ1| A"). `break-word` only breaks a word that cannot fit on a
   line of its own, so ordinary values now wrap at spaces; the long unbroken ones that genuinely need
   it (SMILES, a 40-char classification) still break rather than overflow the card. */
.infocard dd{margin:0;font-size:var(--fs-sm);text-align:right;font-weight:600;min-width:0;overflow-wrap:break-word}
.infocard .ic-authors{margin-top:11px;padding-top:11px;border-top:1px solid var(--border);
  color:var(--muted);font-size:var(--fs-sm);line-height:1.5}
@media(max-width:980px){.detail-layout{flex-direction:column}
  .detail-layout .sidebar{width:100%;position:static}}
.metrics{display:flex;flex-wrap:wrap;gap:var(--sp-3);margin:var(--sp-4) 0 6px}
.metric{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:var(--sp-2) var(--sp-4);
  font-size:var(--fs-base);color:var(--muted);box-shadow:var(--shadow-sm)}
.metric b{color:var(--text);font-weight:700}
.panels{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4)}
.panel{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-4);box-shadow:var(--shadow-sm)}
.panel h4{margin:0 0 var(--sp-3);font-size:var(--fs-md);display:flex;justify-content:space-between;align-items:center;font-weight:600}
.viewer{width:100%;height:430px;position:relative;border-radius:var(--r);overflow:hidden;background:var(--canvas)}
.viewer.big{height:520px}
#contacts3d{background:var(--canvas);border:1px solid var(--border)}     /* 3Dmol interaction scene (theme-aware) */
/* chemical-space scatter (chem.html) */
.btngroup{display:inline-flex;gap:6px;flex-wrap:wrap}
.chem-bar{width:200px;height:12px;border-radius:3px;border:1px solid var(--border);
  background:linear-gradient(to right,rgb(37,99,237),rgb(225,29,72))}
.leg-item{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-base);color:var(--muted);margin-right:6px}
.leg-dot{width:12px;height:12px;border-radius:50%;display:inline-block}
.chemdot{cursor:pointer}
.chemdot:hover circle{stroke:var(--text);stroke-width:2.5px}
.chemdot text{pointer-events:none}
/* clicked 2D nucleotide - linked to the 3D viewer */
g.gnode.fl-sel circle{stroke:var(--text) !important;stroke-width:3.5px !important}

/* two modules split across one row (e.g. sequence alignment + displacement), equal height */
.split-row{display:flex;gap:var(--sp-5);align-items:stretch;margin-bottom:4px}
.split-row .split-col{flex:1 1 50%;min-width:0;display:flex;flex-direction:column}
.split-row .split-col h3{margin-top:6px}
/* both boxes fill their column so the (shorter) displacement card stretches to the alignment card's
   height - the JS still sizes the SVG close, this just guarantees the two boxes end level */
.split-row .split-col .chart{min-width:0;flex:1 1 auto}
@media(max-width:980px){.split-row{flex-direction:column}.split-row .split-col{width:100%}
  .split-row .split-col .chart{display:block;flex:none}}

/* 3D ligand interactions + interaction-data tables side by side, equal height */
.ix-row{display:flex;gap:var(--sp-5);align-items:stretch;margin:var(--sp-6) 0 4px}
.ix-row>section{flex:1 1 0;min-width:0;display:flex;flex-direction:column}
/* h3 flush to the row top (the row's margin-top gives the gap above the module); margin:0 also drops the
   global 8px bottom margin so the title sits close to the bar+box below, not floating far above it */
.ix-row>section h3{margin:0}
/* both bars are 40px tall with the SAME margins (6px top, 0 bottom) so the header area (h3 + bar) is identical
   height in both columns - that's what makes the two 430px boxes below start and end level. The legend sits
   flush on the 3D viewer just as the tabs sit flush on the table (the 40px bar height gives the breathing room). */
.ix-row .ixbar{height:auto;min-height:40px;display:flex;align-items:center;gap:6px;
  flex-wrap:wrap;overflow-x:auto;white-space:normal;margin:6px 0 0}
.ix-row .tabs.ixbar{flex-wrap:nowrap}
.ix-row #contacts3d{height:430px}
.ix-row #tbl-body{height:430px;max-height:none}
@media(max-width:980px){.ix-row{flex-direction:column}}

/* 3D superposition + linked 2D secondary structure, side by side.
   Grid + subgrid: each column's <section> shares the row's three tracks (title / controls / box),
   so the h3 titles line up, the control blocks line up, and the 3D viewer + 2D panels share one
   top AND bottom edge across both columns. */
.linked-row{display:grid;grid-template-columns:minmax(0,58fr) minmax(0,42fr);
  grid-template-rows:auto auto 1fr;column-gap:var(--sp-5);margin-bottom:4px}
.linked-row > section{display:grid;grid-template-rows:subgrid;grid-row:1/4;min-width:0}
.linked-row .col-3d{grid-column:1}
.linked-row .col-2d{grid-column:2}
.linked-row > section > h3{margin-top:6px}
.panels.stacked{grid-template-columns:1fr;gap:var(--sp-3)}
.linked-row .viewer.big{height:auto;min-height:560px}   /* +40px: Mol* top sequence bar sits inside #viewer */
.linked-row .col-2d .panels.stacked{display:flex;flex-direction:column;height:100%;min-height:0}
.linked-row .col-2d .panel{flex:1 1 0;display:flex;flex-direction:column;min-height:0}
.linked-row .col-2d .ss{flex:1 1 0;height:auto;min-height:120px}
@media(max-width:1100px){
  .linked-row{display:block}
  .linked-row > section{display:block}
  .linked-row .col-2d .panels.stacked{display:grid;height:auto}
  .linked-row .col-2d .panel{display:block}
  .linked-row .col-2d .ss{flex:none;height:340px}
  .linked-row .viewer.big{height:440px;min-height:0}   /* +40px for the Mol* sequence bar */
}
.ss{width:100%;height:360px;background:var(--canvas);border:1px solid var(--border);border-radius:var(--r);overflow:hidden}
/* joined multi-chain 2D - a clean strand/ladder schematic (replaces the fornac force layout for "All chains").
   Theme-aware via tokens so it flips with light/dark; the strand is drawn 5'→3', paired bases sit in columns. */
.j2d-wrap{width:100%;height:100%;overflow:auto;padding:4px}
.j2d{display:block;margin:0 auto;font-family:var(--font-display,inherit)}
.j2d-bb{fill:none;stroke:var(--border-strong);stroke-width:2;stroke-linecap:round}
.j2d-rung{stroke:var(--accent);stroke-width:2;opacity:.7}
.j2d-arc{fill:none;stroke:var(--faint);stroke-width:1.1;opacity:.55}
.j2d-nt{fill:var(--surface-2);stroke:var(--border-strong);stroke-width:1.4;transition:stroke .12s}
.j2d-node{cursor:pointer}
.j2d-node:hover .j2d-nt{stroke:var(--accent)}
.j2d-node.j2d-sel .j2d-nt{stroke:var(--accent2);stroke-width:2.6}
.j2d-lbl{fill:var(--text);font-size:10px;font-weight:600;pointer-events:none;user-select:none}
.j2d-lbl.on{fill:#fff}
.j2d-end{fill:var(--muted);font-size:10px;font-weight:700}
.j2d-chain{fill:var(--text-2);font-size:11px;font-weight:600}
.j2d-num{fill:var(--faint);font-size:9px;font-weight:500}
/* joined-2D inter-chain line legend - lives inside the Secondary-structure (2D) header ⓘ popup (#info-dssr).
   Each item is a full-width row (line sample inline via vertical-align) so the label never gets squeezed/wrapped. */
.bp-legend{margin:14px 0 2px;display:flex;flex-direction:column;gap:9px}
.bp-legend-i{font-size:var(--fs-sm);color:var(--text-2);line-height:1.5}
.ss-lg-svg{vertical-align:middle;margin-right:9px;overflow:visible}
.modal-rule{border:0;border-top:1px solid var(--border);margin:20px 0 4px}
.err{color:var(--bad);font-size:var(--fs-base);padding:var(--sp-2)}
@media(max-width:900px){.panels{grid-template-columns:1fr}}

/* controls + charts */
.toolbar{display:flex;align-items:center;gap:var(--sp-2);margin:6px 0 var(--sp-3);flex-wrap:wrap}
/* toolbar buttons are atomic: never shrink, never wrap internally (the whole button wraps to a new line instead,
   since .toolbar is flex-wrap), so a narrow column can't squeeze a label. */
.toolbar .btn{flex:none;white-space:nowrap}
/* the morph play/pause button is icon-only (no label) - drop the icon's right margin so the glyph sits centred */
#play .ico{margin:0}
.btn{background:var(--card);color:var(--text);border:1px solid var(--border);border-radius:var(--r);
  padding:6px var(--sp-3);font-size:var(--fs-base);cursor:pointer;box-shadow:var(--shadow-sm);
  transition:border-color var(--transition),color var(--transition),background var(--transition)}
.btn:hover{border-color:var(--t-green-fg);color:var(--t-green-fg)}
.btn:active{transform:translateY(1px)}
.btn.on{background:var(--accent);color:#fff;border-color:var(--accent)}
.hint{color:var(--muted);font-size:var(--fs-sm)}
input[type=number]{font:inherit;padding:4px 6px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--card);color:var(--text)}
.chart{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-4);overflow:auto;box-shadow:var(--shadow-sm)}
.chart svg{display:block;margin:0 auto}
/* horizontal-scroll wrapper for the displacement chart when the RNA is too long to fit */
.dispscroll{overflow-x:auto;overflow-y:hidden;width:100%;max-width:100%}
.dispscroll svg{min-width:100%}
/* per-residue displacement bars: hover-magnify + click-to-focus */
rect.dbar{cursor:pointer;transition:transform .12s ease, filter .12s ease}
rect.dbar:hover{transform:scale(1.18);transform-box:fill-box;transform-origin:bottom center;filter:brightness(1.08)}
rect.dbar-sel{stroke:var(--text);stroke-width:1.6px;paint-order:stroke}
/* per-nucleotide feature track: hover-highlight + click-to-focus cells */
rect.trk-cell{cursor:pointer;transition:filter .12s ease}
rect.trk-cell:hover{filter:brightness(1.1)}
rect.trk-cell-sel,rect.trk-sel{stroke:var(--text);stroke-width:1.8px;paint-order:stroke}
/* feature-track motif filter buttons */
.trk-modes{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}
.trk-mbtn{display:inline-flex;align-items:center;font-size:11px;font-weight:600;line-height:1;
  padding:3px 8px;border:1px solid var(--border);border-radius:var(--r-pill);background:var(--card);
  color:var(--muted);cursor:pointer;transition:color var(--transition),border-color var(--transition),background var(--transition)}
.trk-mbtn:hover{border-color:var(--accent);color:var(--accent)}
.trk-mbtn.on{background:var(--surface-2);border-color:var(--accent);color:var(--text)}
.trk-dot{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:5px;flex:none}
/* per-panel pocket-chain picker (2D #ss-chain, dashboard #track-chain) - only shown for multi-chain pockets */
.trk-chainsel{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;color:var(--muted)}
.trk-chainsel select,.trk-sel select,.trk-modes select{font:inherit;font-size:11px;font-weight:600;line-height:1;
  padding:3px 6px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--card);
  color:var(--text);cursor:pointer;transition:color var(--transition),border-color var(--transition),background var(--transition)}
.trk-chainsel select:hover,.trk-sel select:hover,.trk-modes select:hover{border-color:var(--accent)}

/* interaction-data tables (tabbed) */
.tabs{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin:6px 0 0}
.tab{background:var(--card);border:1px solid var(--border);border-bottom:none;border-radius:var(--r) var(--r) 0 0;
  padding:7px var(--sp-4);font-size:var(--fs-base);cursor:pointer;color:var(--muted);transition:color var(--transition),background var(--transition)}
.tab:hover{color:var(--accent)}
.tab.on{background:var(--accent);color:#fff;border-color:var(--accent)}
#tbl-body{margin-top:0;border-top-left-radius:0;max-height:440px}
table.dtbl{width:100%;border-collapse:collapse;font-size:var(--fs-base)}
table.dtbl th{text-align:left;color:var(--muted);font-weight:600;padding:var(--sp-2) var(--sp-3);
  border-bottom:2px solid var(--border);position:sticky;top:-14px;background:var(--card)}
table.dtbl td{padding:7px var(--sp-3);border-bottom:1px solid var(--border)}
table.dtbl tr:hover td{background:var(--surface-2)}
.tag-hbond{color:var(--ok);font-weight:600}
.tag-vdw{color:var(--muted)}
.tag-broken{color:var(--bad);font-weight:600}

/* apo vs holo sequence alignment */
.align-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:var(--fs-base);
  line-height:1.5;white-space:pre;overflow-x:auto}
/* Global/Local identity now ride on each chain's own .chain-sub header (2026-07-28) instead of a green
   banner above the panels; the full explanation still lives in the data-info="identity" modal. */
.al-id-metric{white-space:nowrap;font-weight:600}
.al-id-metric b{font-weight:700;color:var(--text)}
.al-id-sep{opacity:.45;margin:0 5px}
/* 3D-incompleteness annotation (modeled vs declared/SEQRES) - amber chip matching the if-badge palette */
.seqres-note{font-size:var(--fs-sm);margin:0 0 10px;padding:7px var(--sp-3);border-radius:var(--r-sm);
  background:#fdf3da;color:#7a5b00;line-height:1.55}
.seqres-note b{font-weight:700}
/* Plain wrapping text - deliberately NOT a flex row. The warning triangle that used to lead this sentence
   was removed: as a fixed-width inline-block SVG it kept getting pushed onto its own line, and flexing the
   row around it collapsed the long text into a narrow column. The amber panel already signals the warning. */
.sr-warn{display:block}
.seqres-full{margin-top:5px;display:flex;gap:8px;align-items:baseline}
.seqres-full .sr-lab{flex:none;font-weight:700;font-size:var(--fs-xs);opacity:.85}
.seqres-full code{word-break:break-all;background:#fffdf5;border:1px solid #e8dcae;border-radius:4px;
  padding:1px 5px;font-size:var(--fs-xs);color:#5a4500;font-family:monospace}
.apo-copy-sel{max-width:100%;font-size:var(--fs-sm);padding:1px 4px}
.seqres-note.plain{background:var(--surface-2);color:var(--text)}   /* copy chooser without an incompleteness warning */
.apo-copy-pick{margin-top:6px;font-weight:700}
.apo-copy-pick .apo-copy-sel{margin:0 5px;font-weight:400}
/* cross-PDB "Apo structure" selector in the pinhead (add_apo_alternatives) */
.apo-alt-bar{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;margin:4px 0 2px}
.apo-alt-bar:empty{display:none}
.apo-alt-lbl{font-size:var(--fs-sm);font-weight:700;color:var(--text-2)}
.apo-alt-sel{font-size:var(--fs-sm);padding:2px 6px;max-width:360px;border-radius:var(--r-sm)}
.apo-alt-note{font-weight:400;font-size:var(--fs-xs)}
/* "show all" escape hatch inside the note (clears the Database identity filter carried in the URL) */
.apo-alt-note a{text-decoration:underline}
/* an ?apo=/?copy= this pair record does not carry was ignored - the page must say so, not silently
   render the default apo under a URL that names another one (applyVariant -> _variant_missing) */
.apo-alt-warn{font-weight:400;font-size:var(--fs-xs);color:var(--warn);
  border:1px solid var(--warn);border-radius:var(--r-sm);padding:2px 8px;background:transparent}
/* per-chain divider label inside the alignment / displacement panels of a multi-chain pocket */
.chain-sub{font-weight:600;font-size:var(--fs-sm);color:var(--text-2);margin:14px 0 4px;
  padding:2px 8px;background:var(--bg);border-left:3px solid var(--accent,#2c6bed);border-radius:3px;
  display:flex;align-items:center;flex-wrap:wrap}
.chart > .chain-sub:first-child{margin-top:0}
/* a single-chain pocket has no "chain X ⇄ apo Y" prefix to hang the metrics on - the section title
   already names the pair - so its header carries the two identities alone, without the accent rule. */
.chain-sub-id{border-left:none;background:transparent;padding-left:0}
.chain-sub .info-i{margin-left:5px}
.al-block{margin-bottom:var(--sp-4)}
.al-lbl{display:inline-block;width:44px;color:var(--muted);font-family:Inter,sans-serif;font-size:var(--fs-xs)}
.al-num{display:inline-block;width:34px;text-align:right;padding-right:var(--sp-2);color:var(--faint);
  font-family:Inter,sans-serif;font-size:var(--fs-xs)}
.al-num-r{padding-left:var(--sp-2);color:var(--faint);font-family:Inter,sans-serif;font-size:var(--fs-xs)}
.al-ok{color:var(--text-2)}
.al-mm{color:var(--t-red-fg);font-weight:700;background:var(--t-red-bg);border-radius:2px}
.al-gap{color:var(--faint);background:var(--surface-2);border-radius:2px}
.al-pocket{border-bottom:2.5px solid var(--accent)}     /* binding-site residue */
/* declared in SEQRES but NOT modeled (disordered): we know which base it is, so we print it - but it has no
   coordinates, so it is inert (no seqid tooltip, no click target, never underlined as a binding site).
   Composes with al-ok / al-mm rather than replacing them: opacity + italic keep a faded MISMATCH still red,
   and the extra colour rule below only greys the plain (matching) case. Tuned per theme so it stays legible
   in both - dark mode needs a higher floor than light. (theme.js always sets data-theme, so the explicit
   attribute is the only dark selector this sheet uses.) */
.al-unmod{opacity:.62;font-style:italic}
.al-ok.al-unmod{color:var(--faint)}
:root[data-theme="dark"] .al-unmod{opacity:.75}
:root[data-theme="dark"] .al-ok.al-unmod{color:var(--muted)}

/* about / features page */
.legend-row{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);
  padding:var(--sp-3) var(--sp-4);font-size:var(--fs-sm);color:var(--muted);line-height:1.9;box-shadow:var(--shadow-sm)}
.info-tbl{width:100%;border-collapse:collapse;font-size:var(--fs-base);margin:6px 0 4px}
.info-tbl td,.info-tbl th{text-align:left;padding:var(--sp-2) var(--sp-3);border-bottom:1px solid var(--border);vertical-align:top}
.info-tbl th{color:var(--muted);font-weight:600}
.info-tbl td:first-child{font-weight:600;white-space:nowrap;color:var(--text)}
/* 2026-08-02: opt-in label wrapping. nowrap above is right for the short labels (<=20 chars) every
   other .info-tbl uses - dropping it globally shrank their label column to its longest WORD and wrapped
   text that used to sit on one line. Only the pair page's interactions modal has a 97-char label, which
   under nowrap pushed that table to 748px inside a 683px modal and clipped the source column off the
   right edge. Tag just that table .wrap-labels. Same modifier pattern as .info-tbl.tour below. */
.info-tbl.wrap-labels td:first-child{white-space:normal}
.info-tbl code,.trust code,.hint code,.feat code,.feat h4 code{background:var(--surface-2);border-radius:4px;padding:1px 5px;font-size:var(--fs-sm)}
.feat-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);margin:6px 0 4px}
@media(max-width:760px){.feat-grid{grid-template-columns:1fr}}
.feat{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-3) var(--sp-4);box-shadow:var(--shadow-sm)}
.feat h4{font-size:var(--fs-lg);margin:6px 0 0;letter-spacing:-.01em;font-weight:700}
.feat p{margin:7px 0 0;color:var(--muted);font-size:var(--fs-base);line-height:1.55}
.feat .src{color:var(--text)}
.feat .src b{color:var(--muted);font-weight:600}
.srctag{display:inline-block;font-size:var(--fs-xs);font-weight:700;border-radius:var(--r-pill);padding:2px 9px;margin:0 4px 0 0}
/* PROVENANCE TAGS — four SCIENTIFIC sources, renamed 2026-08-02. The old labels mixed two axes: the
   green tag ("structure-derived") covered both external-tool output and our own coordinate arithmetic,
   and "live" described how a value is FETCHED, not where it comes from. Now: st-truth = Tool-derived
   (an external tool read the coordinates: x3dna-dssr, US-align, BLAST, RDKit), st-comp = Geometry-derived
   (we measure the coordinates directly with gemmi/numpy), st-heur = Heuristic (a rule-based inference),
   st-ext = Deposited metadata (verbatim from the PDB entry). Class names are unchanged so no page needs a
   class rewrite — only the visible label moved. Freshness ("live", fetched on demand) is a separate
   statement and must never sit in this legend. */
.st-truth{background:var(--t-green-bg);color:var(--t-green-fg)}
.st-comp{background:var(--t-blue-bg);color:var(--t-blue-fg)}
.st-heur{background:var(--t-orange-bg);color:var(--t-orange-fg)}
.st-ext{background:var(--t-slate-bg);color:var(--t-slate-fg)}
.trust{margin:6px 0 0;padding-left:var(--sp-5)}
.trust li{color:var(--muted);font-size:var(--fs-base);line-height:1.6;margin-bottom:7px}
.trust b{color:var(--text)}
/* featured example card */
.example-card{display:flex;gap:var(--sp-5);align-items:center;background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-xl);padding:var(--sp-4);box-shadow:var(--shadow-sm);margin:var(--sp-2) 0 6px}
.ex-thumb{width:240px;flex:none;height:120px;background:var(--canvas);border:1px solid var(--border);border-radius:var(--r-lg);
  overflow:hidden;display:flex;align-items:center;justify-content:center}
.ex-body{min-width:0}
.ex-stats{display:flex;flex-wrap:wrap;gap:var(--sp-5);margin:var(--sp-3) 0 var(--sp-4)}
.ex-stat{display:flex;flex-direction:column;font-size:var(--fs-sm);color:var(--muted)}
.ex-stat b{font-size:var(--fs-xl);color:var(--text);font-weight:800;line-height:1.2}
.btn.primary{background:var(--accent);   /* fallback if color-mix unsupported */
  background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 86%,#fff),var(--accent));
  color:#fff;border-color:var(--accent);font-weight:700;box-shadow:var(--shadow-sm)}
.btn.primary:hover{background:var(--accent-hover);
  background:linear-gradient(180deg,var(--accent),var(--accent-hover));
  border-color:var(--accent-hover);color:#fff;transform:translateY(-1px);box-shadow:var(--shadow)}
.info-tbl.tour td:nth-child(2){white-space:normal;color:var(--muted);font-weight:400}
@media(max-width:680px){.example-card{flex-direction:column;align-items:stretch}.ex-thumb{width:100%}}
@media(max-width:600px){.info-tbl td,.info-tbl th{padding:6px var(--sp-2);font-size:var(--fs-sm)}
  .info-tbl td:first-child{white-space:normal}}
.feat-grid.cols3{grid-template-columns:repeat(3,minmax(0,1fr))}
@media(max-width:760px){.feat-grid.cols3{grid-template-columns:1fr}}
.rule{margin:var(--sp-2) 0 2px;font-size:var(--fs-base)}
.rule summary{cursor:pointer;color:var(--accent);font-weight:600}
.rule pre{background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r);padding:var(--sp-3) var(--sp-4);
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:var(--fs-sm);line-height:1.5;overflow-x:auto;margin:var(--sp-2) 0 0}
.rule p{color:var(--muted);font-size:var(--fs-base);line-height:1.6;margin:var(--sp-2) 0 0}
/* click-to-explain ⓘ trigger + modal */
.info-i{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;
  border:1px solid var(--border);background:var(--card);color:var(--muted);font:700 11px Georgia,serif;font-style:italic;
  cursor:pointer;margin-left:6px;vertical-align:middle;padding:0;line-height:1;transition:color var(--transition),border-color var(--transition)}
.info-i:hover{color:var(--accent);border-color:var(--accent)}
@keyframes ah-fade{from{opacity:0}to{opacity:1}}
@keyframes ah-pop{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}
.modal-backdrop{position:fixed;inset:0;background:var(--backdrop);z-index:100;
  display:flex;align-items:center;justify-content:center;padding:var(--sp-5);animation:ah-fade .16s var(--ease)}
.modal-backdrop[hidden]{display:none}
.modal-card{background:var(--card);border-radius:var(--r-xl);box-shadow:var(--shadow);max-width:760px;width:100%;
  max-height:85vh;overflow:auto;padding:var(--sp-6) var(--sp-7);position:relative;animation:ah-pop .22s var(--ease)}
.modal-x{position:absolute;top:var(--sp-2);right:var(--sp-4);border:none;background:none;font-size:26px;line-height:1;
  color:var(--muted);cursor:pointer;padding:4px}
.modal-x:hover{color:var(--text)}
.modal-body h3{text-transform:none;letter-spacing:-.01em;color:var(--text);font-size:var(--fs-xl)}

/* --- phones / very narrow viewports --- */
@media(max-width:980px){
  /* interaction-data tabs: wrap instead of horizontal-scroll once the row is stacked */
  .ix-row .tabs.ixbar{flex-wrap:wrap;height:auto;min-height:40px;overflow-x:visible}
  .ix-row #contacts3d,.ix-row #tbl-body{height:360px}
}
@media(max-width:600px){
  header{padding:var(--sp-2) var(--sp-4);gap:var(--sp-3)}
  header h1{font-size:17px}
  .nav{gap:var(--sp-3);flex-wrap:wrap}
  .wrap{padding:var(--sp-4) var(--sp-3)}
  .wrap.wide{width:100%}
  .hero h2{font-size:var(--fs-2xl)}
  h2{font-size:var(--fs-xl)}
  .viewer{height:360px}.viewer.big{height:440px}   /* +40px for the Mol* sequence bar */
  .lig2d-pop{width:min(296px,calc(100vw - 36px))}
}

/* --- pocket series (same pocket, multiple molecules) --- */
.pcard{cursor:pointer}
.pcard:hover{border-color:var(--accent)}
.apo-tag{display:inline-block;background:var(--t-green-bg);color:var(--t-green-fg);border-radius:var(--r-sm);
  padding:1px 7px;font-size:var(--fs-xs);font-weight:600;vertical-align:middle}
.liggrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:var(--sp-3)}
.ligcell{border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-3);text-align:center;background:var(--panel-light)}
.ligsvg{height:130px;display:flex;align-items:center;justify-content:center;overflow:hidden}
.ligsvg svg{width:100%;height:100%;object-fit:contain}
.lignm{font-weight:600;margin-top:6px;color:var(--text)}
.ligcell a{display:inline-block;margin-top:4px}
/* in-place sequence with pocket residues coloured (highlighter colours kept across themes) */
.pk-seq{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-md);line-height:1.95;
  letter-spacing:.5px;word-break:break-all;color:var(--faint);margin:0 0 1.1rem}
.pk-nt{padding:1px 0;border-radius:3px}
.pk-nt.pk-all{background:#1f7a6b;color:#fff;font-weight:700;padding:1px 2px}
.pk-nt.pk-some{background:#f0a868;color:#4a2f12;font-weight:600;padding:1px 2px}
.pk-nt.pk-low{background:#fbe8d4;color:#8a5a2b;padding:1px 2px}
.pk-brk{color:var(--border-strong);padding:0 4px}
/* residue chips (fallback for long RNAs) */
.pk-reslist{display:flex;flex-wrap:wrap;gap:5px;margin:0 0 1rem}
.pk-res{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-sm);padding:2px 7px;
  border-radius:var(--r-sm);border:1px solid var(--border);background:var(--card);color:var(--muted)}
.pk-res sub{font-size:9px;opacity:.7;margin-left:1px}
.pk-res.pk-all{background:var(--t-green-bg);border-color:var(--t-green-fg);color:var(--t-green-fg);font-weight:700}
.pk-res.pk-some{background:var(--t-orange-bg);border-color:var(--warn);color:var(--t-orange-fg);font-weight:600}
.pk-res.pk-low{background:var(--t-orange-bg);border-color:var(--border);color:var(--t-orange-fg)}
.apo-na{color:var(--faint)}
b.pk-all{color:var(--t-green-fg)}.pk-some{color:var(--warn)}
/* sibling-copy switcher on the pair page title */
.copy-switch{font-size:var(--fs-base);font-weight:400;color:var(--muted);margin-left:var(--sp-4);white-space:nowrap}
.copy-switch select{font-size:var(--fs-base);padding:2px 7px;border-radius:var(--r-sm);border:1px solid var(--border);
  background:var(--card);color:var(--text);margin-left:4px;cursor:pointer}
/* per-ligand contacted residues on each card */
.lig-res{display:flex;flex-wrap:wrap;gap:3px;justify-content:center;margin-top:4px}
.lig-res .pk-res{font-size:10px;padding:1px 4px;border-radius:5px}
/* conformational dashboard: feature track (left 50%, scrolls) + Rg & pocket-burial line plots (25% each), ONE equal-height row */
.dyn-row{display:flex;gap:var(--sp-3);align-items:stretch;flex-wrap:nowrap}
.dyn-row .dyn-cell{background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);
  padding:10px 12px;box-shadow:var(--shadow-sm);min-width:0;display:flex;flex-direction:column}
.dyn-track{flex:1 1 100%;max-width:100%}   /* the feature track is now the whole dashboard row (Rg/burial morph plots removed) */
.dyn-track .dyn-trackbody{min-width:0;flex:1 1 auto}
.dyn-plot{flex:1 1 0;min-width:0}                 /* the two plots split the remaining 50% -> ~25% each */
.dyn-phead{font-size:12px;font-weight:600;color:var(--text);display:flex;justify-content:space-between;
  align-items:baseline;gap:8px;margin-bottom:6px}
.dyn-sub{font-weight:400;color:var(--faint);font-size:11px}
.dyn-delta{font-weight:400;color:var(--faint);font-size:10px;white-space:nowrap}
.dyn-pbody{flex:1 1 auto;min-height:44px;position:relative}
/* absolute → the svg carries NO intrinsic height, so the Feature track's natural height drives the row
   and the two plots just follow it (no whitespace); preserveAspectRatio="none" fills the body exactly */
.dyn-psvg{position:absolute;top:0;left:0;width:100%;height:100%;display:block}
.dyn-pfoot{font-size:10px;color:var(--muted);margin-top:5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media(max-width:900px){.dyn-row{flex-wrap:wrap}.dyn-track{flex:1 1 100%;max-width:100%}.dyn-plot{flex:1 1 calc(50% - var(--sp-3))}}

/* base-pair rewiring: arc diagram (70%) + Changes table (30%) share one row under the Conformational dashboard */
.bparc-row{display:flex;gap:var(--sp-3);margin-top:var(--sp-3)}
.bparc-cell{flex:0 1 70%;min-width:0}                    /* shrink (not 0-shrink) so the gap fits without wrapping */
.bparc-body{overflow-x:auto;overflow-y:hidden;min-height:260px;margin-top:4px}   /* grows to fit the arc (+ optional sequence ribbon); the wide SVG scrolls sideways */
.bparc-svg{display:block;margin:0;background:var(--canvas);border:1px solid var(--border);border-radius:var(--r)}  /* left-align so scroll starts at nt 1 */
.bparc-legend{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin-top:8px;font-size:12px;color:var(--muted)}
.bparc-key{display:inline-flex;align-items:center;gap:5px}
.bparc-key b{color:var(--text);font-variant-numeric:tabular-nums}
.bparc-src{margin-left:auto}
.bparc-scrollhint{color:var(--faint);font-style:italic}
.bpk{width:20px;height:0;border-top:2.5px solid;display:inline-block;border-radius:2px}
.bpk-formed{border-top-color:var(--t-green-fg)}
.bpk-broken{border-top-color:var(--bad)}
.bpk-cons{border-top-color:var(--faint)}
.bpk-dash{border-top-color:var(--muted);border-top-style:dashed}
/* arc-header controls: chain selector + "Show unchanged (N)" toggle, right-aligned in the panel head */
.bparc-ctrls{display:inline-flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:flex-end}
.bparc-constog{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:400;color:var(--muted);white-space:nowrap;cursor:pointer}
.bparc-constog input{cursor:pointer}
/* Changes table beside the arc */
.bptable-cell{flex:0 1 30%;min-width:0;display:flex;flex-direction:column}
.bptable-head{font-size:12px;font-weight:600;color:var(--text);display:flex;align-items:baseline;gap:6px;margin-bottom:6px}
.bptable-head span{font-weight:400;color:var(--muted);font-variant-numeric:tabular-nums}
/* height is set in JS (renderBpArc) to match the arc box exactly, so the Changes table tracks the arc+ribbon
   height in every mode; 260px is just the pre-render fallback. overflow:auto scrolls the rows within it. */
#bptable-host{height:260px;overflow:auto;border:1px solid var(--border);border-radius:var(--r);background:var(--card)}
.bptable{font-size:11px}
.bptable th{padding:5px 8px;cursor:pointer;user-select:none}
.bptable td{padding:4px 8px}
.bptable-note{padding:16px 12px;text-align:center;margin:0}
.bpt-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle}
.bpt-formed{background:var(--t-green-fg)}
.bpt-broken{background:var(--bad)}
.bpt-neq{font-weight:800;color:var(--text);font-size:10px}
/* inline coloured words in the section caption + modal headings */
.bpc-formed{color:var(--t-green-fg);font-weight:600}
.bpc-broken{color:var(--bad);font-weight:600}
.bpc-cons{color:var(--muted);font-weight:600}
/* legend key for a formed/broken pair at a differing apo/holo position (the "≠" arc marker) */
.bparc-neq{color:var(--muted);font-style:italic}
.bparc-neq::first-letter{font-style:normal;font-weight:800;color:var(--text)}
/* partner-swap marker: accent dot on the arc axis + "⇄" legend key + Changes-table badge (a nucleotide that
   pairs with a different partner in apo vs holo -> a formed arc above and a broken arc below share its node) */
.bpk-swap{width:auto;height:auto;border-top:0;border-radius:0;color:var(--accent);font-weight:800;font-size:13px;line-height:1}
.bpt-swap{font-weight:800;color:var(--accent);font-size:11px}
.bpt-swaprow td{background:color-mix(in srgb,var(--accent) 7%,transparent)}
@media(max-width:900px){.bparc-row{flex-wrap:wrap}.bparc-cell,.bptable-cell{flex:1 1 100%;max-width:100%}.bparc-src{margin-left:0;flex-basis:100%}}

/* ============================================================================
   Usability polish - click-to-copy · back-to-top · prose measure · empty state
   ========================================================================== */
/* F1 · click-to-copy icon button (PDB IDs, ligand codes, sequences) */
.copybtn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;
  margin-left:6px;border:1px solid transparent;border-radius:var(--r-sm);background:none;color:var(--faint);
  cursor:pointer;vertical-align:middle;flex:none;
  transition:color var(--transition),border-color var(--transition),background var(--transition)}
.copybtn:hover{color:var(--accent);border-color:var(--border);background:var(--surface-2)}
.copybtn.copied{color:var(--ok);border-color:var(--ok)}
.copybtn svg,.copybtn .ico{width:14px;height:14px;display:block}
/* the "copy sequence" cluster in the alignment identity banner */
.al-seqcopy{margin-left:4px;white-space:nowrap}
.al-seqcopy .hint{margin:0 1px}
.seqres-full .copybtn{margin-left:4px}

/* F3 · floating back-to-top button (injected by theme.js on every page; below the modal at z-index 100) */
.to-top{position:fixed;right:20px;bottom:20px;z-index:60;width:40px;height:40px;
  display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:50%;
  background:var(--card);color:var(--muted);cursor:pointer;box-shadow:var(--shadow);
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity var(--transition),transform var(--transition),color var(--transition),border-color var(--transition)}
.to-top.show{opacity:1;visibility:visible;transform:none}
.to-top:hover{color:var(--accent);border-color:var(--accent)}
.to-top:active{transform:translateY(1px)}
.to-top svg{width:18px;height:18px;display:block}
@media(max-width:600px){.to-top{right:14px;bottom:14px}}

/* F4 · cap running-text measure on prose pages (about/help). Only classless <p> (the body prose) +
   list items - banners/hints/tables/grids (which carry a class) keep their full width.
   2026-08-04: the cap alone left every paragraph pinned to the LEFT of a 1144px column, so help.html
   read as a narrow strip with ~420px of dead space beside it. .prose-narrow makes the COLUMN the
   measure, so headings, running text, cards and the FAQ all share one edge. It is opt-in per page:
   about.html keeps the wide column because its provenance table and feature grid genuinely need it
   (a break-out rule was tried here and pushed .about-wide off-centre, so the column stays put). */
.wrap.prose-narrow{max-width:900px}
.prose p:not([class]),.prose li{max-width:72ch}

/* F5 · friendly empty state for the gallery */
.empty-state{text-align:center;padding:var(--sp-10) var(--sp-4);color:var(--muted)}
.empty-state .empty-ico{color:var(--faint);margin-bottom:var(--sp-2);line-height:0}
.empty-state .empty-ico svg{width:44px;height:44px;display:inline-block}
.empty-state .empty-title{font-size:var(--fs-lg);font-weight:700;color:var(--text);margin:0 0 2px}
.empty-state .btn{margin-top:var(--sp-4);display:inline-block}
