/* LungMAP components — the only layer allowed to consume the design tokens.
 *
 * Every rule here reads a custom property from tokens.css. No component
 * carries a raw colour, a raw radius or a raw duration, so changing a token
 * changes every page that uses these classes.
 *
 * Every class is prefixed `lm-`. The site still loads page.css, 283 KB of the
 * SilverStripe theme, and Bootstrap 5. A new prefix means a component can be
 * added beside existing markup without colliding with either, and a template
 * can be moved across one element at a time.
 *
 * Density is the point. The old theme spends 22 to 40px of vertical padding on
 * a table cell, a panel and a page title. These components spend 6 to 14px,
 * and pull the first row of real content above the fold.
 */

/* ====================================================================
   1. Page shell
   ==================================================================== */

.lm-shell {
  width: 100%;
  max-width: var(--lm-shell-max);
  margin-inline: auto;
  padding-inline: var(--lm-gutter);
}
.lm-shell--wide { max-width: var(--lm-shell-wide); }
.lm-shell--flush { padding-inline: 0; }

/* The main column of a page. `--tight` is the dense default the redesign
   uses; `--airy` keeps the old spacing where a page still wants it. */
.lm-main { padding-block: var(--lm-space-7) var(--lm-space-10); }
.lm-main--tight { padding-block: var(--lm-space-5) var(--lm-space-8); }

/* A page with a sidebar. The aside is a fixed 208px rail, the content takes
   the rest, and the two stack under 900px. CSS grid replaces the old
   `col-md-2` + `col-md-10` pair, which forced a 12-column arithmetic onto
   every page and wasted the gutter. */
.lm-with-aside {
  display: grid;
  grid-template-columns: 208px minmax(0, 1fr);
  gap: var(--lm-space-9);
  align-items: start;
}
@media (max-width: 900px) {
  .lm-with-aside { grid-template-columns: minmax(0, 1fr); gap: var(--lm-space-6); }
}

/* ====================================================================
   2. Header — one definition, every page
   ==================================================================== */

/* The font is set HERE, on the header, because page.css:193 sets the body to
   Bootstrap's `--bs-body-font-family`, so anything inheriting from body gets
   Bootstrap's stack rather than the design's. The mockup's body rule is
   `font:16px/1.6 -apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,
   sans-serif` with `-webkit-font-smoothing:antialiased` (01-home.html:30-31);
   the smoothing is part of how the type looks at 15px and is carried too. */
.lm-header {
  background: var(--lm-paper);
  border-bottom: 1px solid var(--lm-line);
  position: relative;
  z-index: var(--lm-z-header);
  font-family: var(--lm-font-sans);
  -webkit-font-smoothing: antialiased;
}
.lm-header a, .lm-header button, .lm-header input { font-family: inherit; }
/* Height and rhythm are the approved home design's, to the pixel:
   docs/mockups/direction-c-one-screen/01-home.html:45
     .hrow{max-width:1420px;margin:0 auto;padding:13px 34px;
           display:flex;align-items:center;gap:28px}
   The 13px and the 28px are written literally rather than as the nearest
   spacing token, because the token scale has no 13 or 28 and rounding to 12
   and 24 made the header 2px shorter and its groups 4px tighter than the
   design the user approved. */
.lm-header__row {
  max-width: var(--lm-shell-max);
  margin-inline: auto;
  padding: 13px var(--lm-gutter);
  display: flex;
  align-items: center;
  gap: 28px;
}
.lm-header__logo { height: 34px; width: auto; display: block; }
.lm-header__logo-link { display: flex; align-items: center; flex: 0 0 auto; }

/* `.lm-nav` is a <ul>, so without the reset the browser draws a bullet before
   every item. That is where the dots came from. The mockup's nav is
   `nav{margin-left:auto;display:flex;gap:26px;align-items:center}`
   (01-home.html:47), and 26px is literal for the same reason as the header
   row above: the token scale has no 26. */
.lm-nav {
  list-style: none;
  margin: 0 0 0 auto;
  padding: 0;
  display: flex;
  gap: 26px;
  align-items: center;
}
.lm-nav__item { position: relative; display: flex; align-items: center; }
/* The mockup's link is `nav a{font-size:15px;font-weight:500;color:var(--ink)}`
   (01-home.html:48) and carries NO vertical padding and NO line-height of its
   own. The padding-block that used to be here added 6px above and below every
   link, which is the white space that made the bar taller than the design.
   Values are literal, not tokens, so nothing in page.css or Bootstrap can
   round them away. */
.lm-nav__link {
  font-size: 15px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--lm-ink);
  text-decoration: none;
  white-space: nowrap;
  padding: 0;
  display: inline-block;
  transition: color var(--lm-dur-fast) var(--lm-ease);
}
.lm-nav__link:hover,
.lm-nav__item:hover > .lm-nav__link { color: var(--lm-blue); }
.lm-nav__link.is-active { color: var(--lm-blue); }

/* The dropdown. It opens on hover and on keyboard focus, so a section's
   children are reachable without a mouse. */
/* The panel is anchored to the RIGHT edge of its section, not the left.
   A closed panel is `visibility:hidden`, which still takes part in layout, so
   a left-anchored 232px panel on the last section reached 78px past the
   viewport and put a horizontal scrollbar on every page. Measured on
   /home-classic/ at 1440px: header scrollWidth 1518 against clientWidth 1440.
   Anchoring right also matches a navigation bar that is itself right-aligned. */
.lm-nav__panel {
  position: absolute;
  top: 100%;
  right: 0;
  left: auto;
  /* Size to the longest child, not to a fixed floor. The 232px this
     replaces left 38-64px of empty white beside every label, because no
     section's links are that wide. max-width stops a long child from
     running off the screen. Same rule as the home page uses. */
  width: max-content;
  min-width: 0;
  max-width: 320px;
  background: var(--lm-white);
  border: 1px solid var(--lm-line);
  border-radius: var(--lm-radius-md);
  box-shadow: var(--lm-shadow-lg);
  padding: var(--lm-space-3);
  margin: 0;
  list-style: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--lm-dur-fast) var(--lm-ease),
              transform var(--lm-dur-fast) var(--lm-ease),
              visibility var(--lm-dur-fast);
}
.lm-nav__item:hover > .lm-nav__panel,
.lm-nav__item:focus-within > .lm-nav__panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.lm-nav__panel a {
  display: block;
  padding: var(--lm-space-3) var(--lm-space-5);
  font-size: var(--lm-text-base);
  color: var(--lm-ink-2);
  text-decoration: none;
  border-radius: var(--lm-radius-xs);
  white-space: nowrap;
}
.lm-nav__panel a:hover { background: var(--lm-blue-wash); color: var(--lm-blue); }

/* Mockup: `.signin{border:1px solid rgba(20,82,127,.3);border-radius:999px;
   padding:7px 17px;font-size:14px;color:var(--blue)}` (01-home.html:50).
   Literal for the same reason as the nav link above. */
.lm-signin {
  border: 1px solid var(--lm-blue-edge);
  border-radius: 999px;
  padding: 7px 17px;
  font-size: 14px;
  line-height: 1.2;
  color: var(--lm-blue);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--lm-dur-fast) var(--lm-ease);
}
.lm-signin:hover { background: var(--lm-blue-wash); color: var(--lm-blue); }

/* The burger, shown only where the inline nav cannot fit. */
.lm-burger {
  display: none;
  margin-left: auto;
  background: none;
  border: 0;
  padding: var(--lm-space-3);
  cursor: pointer;
  color: var(--lm-ink);
}
.lm-burger svg { display: block; }

/* The header search field, carried on every page but the home page. */
.lm-header__search { flex: 1 1 320px; max-width: 460px; min-width: 0; }

/* Below 1080px the search field is narrowed so the row still fits. The nav
   TYPE and the row spacing are NOT changed: the approved design fixes them at
   15px, 28px and 26px, and shrinking the type to 14px here is what made the
   header text read smaller than the mockup on a laptop window. The mockup
   itself sets `min-width:1120px` on <body> rather than restyling. */
@media (max-width: 1080px) {
  .lm-header__search { flex-basis: 220px; }
}
@media (max-width: 900px) {
  .lm-nav { display: none; }
  .lm-burger { display: block; }
  .lm-header__search { order: 3; flex: 1 1 100%; max-width: none; }
  .lm-header__row { flex-wrap: wrap; row-gap: var(--lm-space-5); }
}

/* The panel the burger opens. It lists the same sections and children as the
   inline nav, so nothing reachable on a desktop is lost on a phone.
 *
 * Visibility is NOT set here. `main.js` toggles this element with jQuery
 * `.toggle()`, which writes an inline `display`, and page.css starts it at
 * `display:none`. A `display` rule in this file would either fight the inline
 * style or strand the panel open. Only the box is restyled.
 *
 * page.css pins the panel at `top:96px`, the height of the old three-row
 * header. The new header is one row, so the offset is replaced by `top:100%`
 * against the header itself, which is correct at any header height. These
 * selectors carry the same specificity as page.css's and win by load order.
 */
.lm-mobile-nav.responsive__nav {
  background: var(--lm-white);
  border-bottom: 1px solid var(--lm-line);
  box-shadow: var(--lm-shadow-lg);
  padding: var(--lm-space-4) var(--lm-gutter-sm);
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  width: auto;
  z-index: var(--lm-z-overlay);
}
.lm-mobile-nav ul { list-style: none; margin: 0; padding: 0; }
.lm-mobile-nav > li,
.lm-mobile-nav.responsive__nav > li {
  border-bottom: 1px solid var(--lm-line);
  padding: 0;
  text-transform: none;
}
.lm-mobile-nav > li:last-child { border-bottom: 0; }
.lm-mobile-nav a,
.lm-mobile-nav.responsive__nav a {
  display: block;
  padding: var(--lm-space-4) 0;
  color: var(--lm-ink);
  text-decoration: none;
  font-size: var(--lm-text-md);
}
.lm-mobile-nav ul,
.lm-mobile-nav.responsive__nav ul {
  margin: 0;
  padding: 0 0 var(--lm-space-3) var(--lm-space-6);
}
.lm-mobile-nav ul a,
.lm-mobile-nav.responsive__nav ul a {
  color: var(--lm-ink-2);
  font-size: var(--lm-text-base);
  padding: var(--lm-space-3) 0;
}
.lm-mobile-nav a:hover { color: var(--lm-blue); }

/* The member tier: the reader's name and sign-out, or nothing. */
.lm-member {
  display: flex;
  align-items: center;
  gap: var(--lm-space-3);
  font-size: var(--lm-text-xs);
  color: var(--lm-ink-3);
  white-space: nowrap;
}
.lm-member a { color: var(--lm-ink-2); text-decoration: none; }
.lm-member a:hover { color: var(--lm-blue); }

/* ====================================================================
   3. Footer
   ==================================================================== */

.lm-footer {
  background: var(--lm-paper-sunk);
  border-top: 1px solid var(--lm-line);
  margin-top: var(--lm-space-10);
}
.lm-footer__row {
  max-width: var(--lm-shell-max);
  margin-inline: auto;
  padding: var(--lm-space-7) var(--lm-gutter);
  display: flex;
  gap: var(--lm-space-8);
  align-items: flex-start;
  flex-wrap: wrap;
}
.lm-footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lm-space-2) var(--lm-space-5);
  align-items: center;
  font-size: var(--lm-text-base);
}
.lm-footer__nav a { color: var(--lm-ink-2); text-decoration: none; }
.lm-footer__nav a:hover { color: var(--lm-blue); }
.lm-footer__sep { color: var(--lm-ink-3); }
.lm-footer__support {
  margin: var(--lm-space-5) 0 0;
  font-size: var(--lm-text-xs);
  line-height: var(--lm-leading-snug);
  color: var(--lm-ink-3);
}
.lm-footer__social { margin-left: auto; display: flex; gap: var(--lm-space-4); }
.lm-footer__social a {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--lm-radius-pill);
  background: var(--lm-white);
  border: 1px solid var(--lm-line);
  color: var(--lm-ink-2);
  text-decoration: none;
  transition: color var(--lm-dur-fast) var(--lm-ease),
              border-color var(--lm-dur-fast) var(--lm-ease);
}
.lm-footer__social a:hover { color: var(--lm-blue); border-color: var(--lm-blue-edge); }
@media (max-width: 900px) {
  .lm-footer__row { padding-inline: var(--lm-gutter-sm); }
  .lm-footer__social { margin-left: 0; }
}

/* ====================================================================
   4. Page header — the title block every inner page opens with
   ==================================================================== */

.lm-page-head {
  padding-block: var(--lm-space-6) var(--lm-space-5);
  border-bottom: 1px solid var(--lm-line);
  margin-bottom: var(--lm-space-7);
}
.lm-page-head--flush { border-bottom: 0; margin-bottom: var(--lm-space-5); }
.lm-page-head__eyebrow {
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  font-size: var(--lm-text-2xs);
  font-weight: var(--lm-weight-bold);
  color: var(--lm-pine);
  margin-bottom: var(--lm-space-3);
}
.lm-page-head__title {
  font-family: var(--lm-font-serif);
  font-weight: var(--lm-weight-semi);
  letter-spacing: var(--lm-track-display);
  line-height: var(--lm-leading-tight);
  font-size: var(--lm-display-sm);
  color: var(--lm-ink);
  margin: 0;
}
.lm-page-head__sub {
  margin: var(--lm-space-4) 0 0;
  font-size: var(--lm-text-md);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-2);
  max-width: 78ch;
}
/* A row of small facts under the title: assay, organism, donor count. */
.lm-page-head__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lm-space-3) var(--lm-space-6);
  margin-top: var(--lm-space-5);
  font-size: var(--lm-text-sm);
  color: var(--lm-ink-2);
}
.lm-page-head__meta b {
  font-weight: var(--lm-weight-semi);
  color: var(--lm-ink);
}
.lm-page-head__actions {
  display: flex;
  gap: var(--lm-space-4);
  flex-wrap: wrap;
  margin-top: var(--lm-space-5);
}

/* ====================================================================
   5. Aside / section rail
   ==================================================================== */

.lm-aside { position: sticky; top: var(--lm-space-6); }
.lm-aside__nav { list-style: none; margin: 0; padding: 0; }
.lm-aside__nav li { margin: 0; }
.lm-aside__nav a {
  display: block;
  padding: var(--lm-space-4) var(--lm-space-5);
  font-size: var(--lm-text-base);
  line-height: var(--lm-leading-snug);
  color: var(--lm-ink-2);
  text-decoration: none;
  border-left: 2px solid transparent;
  border-radius: 0 var(--lm-radius-xs) var(--lm-radius-xs) 0;
  transition: background var(--lm-dur-fast) var(--lm-ease),
              color var(--lm-dur-fast) var(--lm-ease);
}
.lm-aside__nav a:hover { background: var(--lm-blue-wash); color: var(--lm-blue); }
.lm-aside__nav a.is-active,
.lm-aside__nav a.active {
  border-left-color: var(--lm-blue);
  background: var(--lm-blue-wash);
  color: var(--lm-blue);
  font-weight: var(--lm-weight-semi);
}
@media (max-width: 900px) {
  .lm-aside { position: static; }
  .lm-aside__nav {
    display: flex;
    gap: var(--lm-space-2);
    overflow-x: auto;
    padding-bottom: var(--lm-space-3);
  }
  .lm-aside__nav a {
    border-left: 0;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    border-radius: var(--lm-radius-xs);
  }
  .lm-aside__nav a.is-active,
  .lm-aside__nav a.active { border-bottom-color: var(--lm-blue); border-left: 0; }
}

/* ====================================================================
   6. Buttons
   ==================================================================== */

.lm-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--lm-space-3);
  border: 1px solid transparent;
  border-radius: var(--lm-radius-pill);
  padding: var(--lm-space-4) var(--lm-space-7);
  font-family: inherit;
  font-size: var(--lm-text-base);
  font-weight: var(--lm-weight-semi);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--lm-dur) var(--lm-ease),
              border-color var(--lm-dur) var(--lm-ease),
              transform var(--lm-dur) var(--lm-ease);
}
.lm-btn--primary { background: var(--lm-blue); color: var(--lm-on-dark); }
.lm-btn--primary:hover {
  background: var(--lm-blue-lift);
  color: var(--lm-on-dark);
  transform: translateY(var(--lm-lift-sm));
}
.lm-btn--ghost {
  background: transparent;
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
}
.lm-btn--ghost:hover { background: var(--lm-blue-wash); color: var(--lm-blue); }
.lm-btn--quiet {
  background: var(--lm-white);
  border-color: var(--lm-line);
  color: var(--lm-ink-2);
  font-weight: var(--lm-weight-medium);
}
.lm-btn--quiet:hover { border-color: var(--lm-line-strong); color: var(--lm-ink); }
.lm-btn--sm {
  padding: var(--lm-space-3) var(--lm-space-5);
  font-size: var(--lm-text-sm);
}
.lm-btn[disabled], .lm-btn.is-disabled { opacity: .5; pointer-events: none; }

/* ====================================================================
   7. Cards
   ==================================================================== */

.lm-card {
  background: var(--lm-white);
  border: 1px solid var(--lm-line);
  border-radius: var(--lm-radius-md);
  padding: var(--lm-space-6);
  display: block;
  text-decoration: none;
  color: inherit;
}
.lm-card--tight { padding: var(--lm-space-5); }
.lm-card__title {
  margin: 0 0 var(--lm-space-3);
  font-size: var(--lm-text-xl);
  font-weight: var(--lm-weight-semi);
  color: var(--lm-ink);
  line-height: var(--lm-leading-snug);
}
.lm-card__text {
  margin: 0;
  font-size: var(--lm-text-base);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-2);
}
/* The hover the approved home design uses, reused for any card that links. */
.lm-lift {
  transition: transform var(--lm-dur) var(--lm-ease),
              box-shadow var(--lm-dur) var(--lm-ease),
              border-color var(--lm-dur) var(--lm-ease);
}
.lm-lift:hover {
  transform: translateY(var(--lm-lift));
  box-shadow: var(--lm-shadow-card);
  border-color: var(--lm-line-strong);
}

/* A responsive grid of cards that needs no column arithmetic. */
.lm-grid {
  display: grid;
  gap: var(--lm-space-6);
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.lm-grid--tight { gap: var(--lm-space-5); }
.lm-grid--wide { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

/* ====================================================================
   8. Tables — dense, and scrollable rather than overflowing
   ==================================================================== */

/* Wide tables scroll inside this box. Without it a 12-column sample table
   pushes a horizontal scrollbar onto the whole document on a phone. */
.lm-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--lm-line);
  border-radius: var(--lm-radius-sm);
  background: var(--lm-white);
}
.lm-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--lm-text-base);
  line-height: var(--lm-leading-snug);
}
.lm-table th,
.lm-table td {
  padding: var(--lm-pad-tight) var(--lm-space-5);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--lm-line);
}
.lm-table thead th {
  position: sticky;
  top: 0;
  background: var(--lm-paper-sunk);
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--lm-ink-2);
  white-space: nowrap;
  z-index: var(--lm-z-base);
}
.lm-table tbody tr:last-child td { border-bottom: 0; }
.lm-table tbody tr:hover { background: var(--lm-blue-wash); }
.lm-table--zebra tbody tr:nth-child(even) { background: var(--lm-paper); }
.lm-table--zebra tbody tr:nth-child(even):hover { background: var(--lm-blue-wash); }
.lm-table a { color: var(--lm-blue); text-decoration: none; }
.lm-table a:hover { text-decoration: underline; }
.lm-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.lm-table--compact th,
.lm-table--compact td {
  padding: var(--lm-space-3) var(--lm-space-4);
  font-size: var(--lm-text-sm);
}

/* ====================================================================
   9. Tabs
   ==================================================================== */

.lm-tabs {
  display: flex;
  gap: var(--lm-space-2);
  border-bottom: 1px solid var(--lm-line);
  margin-bottom: var(--lm-space-6);
  overflow-x: auto;
  list-style: none;
  padding: 0;
}
.lm-tab {
  padding: var(--lm-space-4) var(--lm-space-6);
  font-size: var(--lm-text-base);
  font-weight: var(--lm-weight-medium);
  color: var(--lm-ink-2);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--lm-dur-fast) var(--lm-ease),
              border-color var(--lm-dur-fast) var(--lm-ease);
}
.lm-tab:hover { color: var(--lm-blue); }
.lm-tab.is-active {
  color: var(--lm-blue);
  border-bottom-color: var(--lm-blue);
  font-weight: var(--lm-weight-semi);
}
.lm-tab__count {
  font-size: var(--lm-text-xs);
  color: var(--lm-ink-3);
  font-variant-numeric: tabular-nums;
}

/* ====================================================================
   10. Field lists — a label and its value, the dataset page's core unit
   ==================================================================== */

/* Two columns on a wide screen, one on a phone. The label column is sized to
   the longest label rather than to a 12-column grid fraction, which is what
   wasted a third of the dataset page's width. */
.lm-fields {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--lm-space-3) var(--lm-space-6);
  margin: 0;
  font-size: var(--lm-text-base);
}
.lm-fields dt,
.lm-field__label {
  font-weight: var(--lm-weight-semi);
  color: var(--lm-ink-2);
  line-height: var(--lm-leading-snug);
}
.lm-fields dd,
.lm-field__value {
  margin: 0;
  color: var(--lm-ink);
  line-height: var(--lm-leading-snug);
  min-width: 0;
  overflow-wrap: anywhere;
}
.lm-fields a { color: var(--lm-blue); }
@media (max-width: 640px) {
  .lm-fields { grid-template-columns: minmax(0, 1fr); gap: var(--lm-space-1); }
  .lm-fields dt { margin-top: var(--lm-space-4); }
}

/* Two field lists side by side on a wide page, so the dataset record does not
   run as one tall column. */
.lm-fields-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--lm-space-5) var(--lm-space-10);
  align-items: start;
}

/* ====================================================================
   11. Chips, badges and pills
   ==================================================================== */

.lm-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--lm-space-2);
  border: 1px solid var(--lm-line);
  border-radius: var(--lm-radius-pill);
  padding: var(--lm-space-2) var(--lm-space-5);
  font-size: var(--lm-text-sm);
  color: var(--lm-ink-2);
  background: var(--lm-white);
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--lm-dur-fast) var(--lm-ease),
              background var(--lm-dur-fast) var(--lm-ease);
}
.lm-chip:hover { border-color: var(--lm-blue-edge); background: var(--lm-blue-wash); }
.lm-chip.is-active {
  background: var(--lm-blue);
  border-color: var(--lm-blue);
  color: var(--lm-on-dark);
}
.lm-badge {
  display: inline-block;
  padding: var(--lm-space-1) var(--lm-space-4);
  border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-semi);
  background: var(--lm-mint-wash);
  color: var(--lm-pine);
}
.lm-badge--warn { background: var(--lm-clay-wash); color: var(--lm-warn); }
.lm-badge--info { background: var(--lm-blue-wash); color: var(--lm-blue); }

/* ====================================================================
   12. Stat strip — the counts the home page carries
   ==================================================================== */

.lm-stats {
  display: flex;
  align-items: center;
  gap: var(--lm-space-10);
  flex-wrap: wrap;
}
.lm-stat {
  display: flex;
  align-items: baseline;
  gap: var(--lm-space-3);
  font-size: var(--lm-text-sm);
  text-decoration: none;
  transition: color var(--lm-dur-fast) var(--lm-ease);
}
.lm-stat b {
  font-family: var(--lm-font-serif);
  font-size: var(--lm-text-2xl);
  font-variant-numeric: tabular-nums;
}

/* ====================================================================
   13. Glass — the panels the home hero floats over the imagery
   ==================================================================== */

.lm-glass {
  background: var(--lm-glass-bg);
  border: 1.5px solid var(--lm-glass-border);
  backdrop-filter: var(--lm-glass-blur);
  -webkit-backdrop-filter: var(--lm-glass-blur);
  border-radius: var(--lm-radius-xl);
  color: var(--lm-on-dark);
}
.lm-glass.lm-lift:hover {
  background: var(--lm-glass-bg-hover);
  border-color: var(--lm-glass-border-hi);
  box-shadow: none;
}

/* ====================================================================
   14. Utilities
   ==================================================================== */

.lm-stack > * + * { margin-top: var(--lm-space-5); }
.lm-stack--tight > * + * { margin-top: var(--lm-space-3); }
.lm-stack--loose > * + * { margin-top: var(--lm-space-8); }
.lm-cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lm-space-4);
  align-items: center;
}
.lm-muted { color: var(--lm-ink-2); }
.lm-quiet { color: var(--lm-ink-3); font-size: var(--lm-text-sm); }
.lm-nowrap { white-space: nowrap; }
.lm-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lm-hr { border: 0; border-top: 1px solid var(--lm-line); margin: var(--lm-space-7) 0; }
.lm-section { margin-bottom: var(--lm-space-9); }
.lm-section__title {
  font-size: var(--lm-text-3xl);
  font-weight: var(--lm-weight-semi);
  color: var(--lm-ink);
  margin: 0 0 var(--lm-space-5);
  line-height: var(--lm-leading-snug);
}
.lm-section__title--rule {
  border-bottom: 1px solid var(--lm-line);
  padding-bottom: var(--lm-space-4);
}
/* Reachable by a screen reader, invisible on screen. Used for a heading that
   labels a region the design shows without a visible title. */
.lm-sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* A note, a warning or an error, in the site's own colours. */
.lm-note {
  border-left: 3px solid var(--lm-info);
  background: var(--lm-blue-wash);
  padding: var(--lm-space-5) var(--lm-space-6);
  border-radius: 0 var(--lm-radius-xs) var(--lm-radius-xs) 0;
  font-size: var(--lm-text-base);
  color: var(--lm-ink-2);
}
.lm-note--warn { border-left-color: var(--lm-warn); background: var(--lm-clay-wash); }
/* Separates a note or a trailing remark from the block above it. These exist
   so a template never needs `style="margin-top:16px"`. */
.lm-note--spaced { margin-top: var(--lm-space-6); }
.lm-quiet--spaced { margin-top: var(--lm-space-7); }

/* An empty result, stated rather than left blank. */
.lm-empty {
  padding: var(--lm-space-9) var(--lm-space-6);
  text-align: center;
  color: var(--lm-ink-3);
  font-size: var(--lm-text-md);
}

/* ====================================================================
   15. Numbered steps — an ordered procedure
   ==================================================================== */

.lm-steps {
  counter-reset: lm-step;
  list-style: none;
  margin: 0;
  padding: 0;
}
.lm-steps li {
  counter-increment: lm-step;
  position: relative;
  padding: var(--lm-space-4) 0 var(--lm-space-4) var(--lm-space-10);
  font-size: var(--lm-text-base);
  color: var(--lm-ink-2);
  border-bottom: 1px solid var(--lm-line);
  line-height: var(--lm-leading-snug);
}
.lm-steps li:last-child { border-bottom: 0; }
.lm-steps li::before {
  content: counter(lm-step);
  position: absolute;
  left: 0;
  top: var(--lm-space-4);
  width: 24px;
  height: 24px;
  border-radius: var(--lm-radius-pill);
  background: var(--lm-blue);
  color: var(--lm-on-dark);
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-semi);
  display: grid;
  place-items: center;
}
.lm-steps b { color: var(--lm-ink); font-weight: var(--lm-weight-semi); }

/* ====================================================================
   16. Screenshot gallery — thumbnails that drive one large stage
   ==================================================================== */

.lm-shots {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--lm-space-4);
}
.lm-shot {
  border: 1px solid var(--lm-line);
  background: var(--lm-white);
  border-radius: var(--lm-radius-sm);
  padding: 0;
  cursor: pointer;
  overflow: hidden;
  text-align: left;
  font: inherit;
  display: block;
  width: 100%;
  transition: border-color var(--lm-dur-fast) var(--lm-ease),
              transform var(--lm-dur-fast) var(--lm-ease),
              box-shadow var(--lm-dur-fast) var(--lm-ease);
}
.lm-shot img { display: block; width: 100%; height: auto; }
.lm-shot span {
  display: block;
  font-size: var(--lm-text-2xs);
  line-height: 1.3;
  color: var(--lm-ink-2);
  padding: var(--lm-space-3) var(--lm-space-3) var(--lm-space-4);
}
.lm-shot:hover {
  border-color: var(--lm-blue);
  transform: translateY(-2px);
  box-shadow: var(--lm-shadow-card);
}
.lm-shot[aria-current="true"] {
  border-color: var(--lm-blue);
  border-width: 2px;
  box-shadow: 0 0 0 3px var(--lm-blue-wash-2);
}
.lm-shot-stage {
  background: var(--lm-white);
  border: 1px solid var(--lm-line);
  border-radius: var(--lm-radius-sm);
  overflow: hidden;
  margin: 0;
}
.lm-shot-stage img { display: block; width: 100%; height: auto; }
.lm-shot-stage a { display: block; cursor: zoom-in; }
.lm-shot-cap {
  font-size: var(--lm-text-base);
  color: var(--lm-ink-2);
  margin: var(--lm-space-5) var(--lm-space-1) 0;
  line-height: var(--lm-leading-sub);
}
.lm-shot-cap b { color: var(--lm-ink); }
.lm-shot-cap a { color: var(--lm-blue); white-space: nowrap; font-weight: var(--lm-weight-semi); }
@media (max-width: 620px) {
  .lm-shots { grid-template-columns: repeat(2, 1fr); }
}

/* A two-column documentation split that collapses on a narrow screen. */
.lm-split-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--lm-space-9);
  align-items: start;
}
.lm-split-3 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--lm-space-8);
  align-items: start;
}
/* An asymmetric split: the narrative wider than the reference beside it. */
.lm-split-lead {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: var(--lm-space-10);
  align-items: start;
}
@media (max-width: 980px) {
  .lm-split-lead { grid-template-columns: minmax(0, 1fr); gap: var(--lm-space-8); }
}

/* A plain bulleted list, sized and coloured with the rest of the page. */
.lm-list {
  margin: 0;
  padding-left: var(--lm-space-7);
  font-size: var(--lm-text-base);
  line-height: 1.75;
  color: var(--lm-ink-2);
}
.lm-list li { margin-bottom: var(--lm-space-1); }
.lm-list code, .lm-code {
  font-family: var(--lm-font-mono);
  font-size: var(--lm-text-sm);
  background: var(--lm-paper-sunk);
  padding: 0 var(--lm-space-2);
  border-radius: var(--lm-radius-xs);
}

@media (prefers-reduced-motion: reduce) {
  .lm-lift, .lm-btn, .lm-nav__panel, .lm-chip, .lm-stat, .lm-footer__social a,
  .lm-shot {
    transition: none;
  }
  .lm-lift:hover { transform: none; }
  .lm-btn--primary:hover { transform: none; }
  .lm-shot:hover { transform: none; }
}

/* ====================================================================
   HEADER — the mockup's own code, copied verbatim
   docs/mockups/direction-c-one-screen/01-home.html lines 22-23, 44-51.

   Written last in the file and scoped under `.lm-header` so it beats
   page.css (283 KB of SilverStripe theme) and Bootstrap, which were
   adding `padding:12px` to `.header` and `margin:12px 0` to `.logo`
   and inheriting Bootstrap's font onto the nav. Values are the
   mockup's literal values, not tokens: this bar is a fixed design.
   ==================================================================== */
.lm-header {
  --paper: #fbf9f6;
  --ink:   #1c2530;
  --line:  #e6e0d8;
  --blue:  #14527f;

  flex: 0 0 auto;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  font: 16px/1.6 -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
.lm-header .lm-header__row {          /* .hrow */
  max-width: 1420px;
  margin: 0 auto;
  padding: 13px 34px;
  display: flex;
  align-items: center;
  gap: 28px;
}
.lm-header .lm-header__logo {          /* .logo — page.css adds margin:12px 0 */
  height: 34px;
  width: auto;
  margin: 0;
}
/* The header ships TWO logo images: the screen one and its print twin. My
   earlier `display:block` forced both visible on screen, so the bar showed the
   logo twice. Bootstrap's `.d-print-block` only sets display inside @media
   print, so the twin has to be hidden on screen explicitly. */
.lm-header .lm-header__logo.d-print-none  { display: block; }
.lm-header .lm-header__logo.d-print-block { display: none; }
@media print {
  .lm-header .lm-header__logo.d-print-none  { display: none; }
  .lm-header .lm-header__logo.d-print-block { display: block; }
}
.lm-header .lm-nav {                   /* nav */
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
  display: flex;
  gap: 26px;
  align-items: center;
}
.lm-header .lm-nav__item { display: flex; align-items: center; position: relative; }
.lm-header .lm-nav__link {             /* nav a */
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  padding: 0;
  margin: 0;
  line-height: 1.6;
  white-space: nowrap;
}
.lm-header .lm-nav__link:hover { color: var(--blue); }
.lm-header .lm-signin {                /* .signin */
  border: 1px solid rgba(20, 82, 127, .3);
  border-radius: 999px;
  padding: 7px 17px;
  font-size: 14px;
  color: var(--blue);
  transition: .15s;
  line-height: 1.6;
}
.lm-header .lm-signin:hover { background: rgba(20, 82, 127, .07); }

/* The block above pins the header to the mockup with `.lm-header .lm-nav`,
   which is specificity (0,2,0). That outranks the responsive rule earlier in
   this file, `@media (max-width:900px){ .lm-nav{display:none} }`, at (0,1,0),
   so the desktop navigation stayed on at every width. Measured at 390px: the
   nav rendered 406px wide inside a 390px viewport and put 50px of horizontal
   overflow on every page that carries the header.
   The responsive rules are therefore restated here at the same specificity as
   the block they have to beat. They must stay AFTER it. */
@media (max-width: 900px) {
  .lm-header .lm-nav { display: none; }
  .lm-header .lm-burger { display: block; }
  .lm-header .lm-header__search { order: 3; flex: 1 1 100%; max-width: none; }
  .lm-header .lm-header__row { flex-wrap: wrap; row-gap: var(--lm-space-5); }
}
@media (max-width: 1080px) {
  .lm-header .lm-header__row { gap: var(--lm-space-6); padding-inline: var(--lm-gutter-sm); }
  .lm-header .lm-nav { gap: var(--lm-space-6); }
}

/* ====================================================================
   HEADER SEARCH — the home page's compact treatment
   Taken from docs/mockups/direction-c-one-screen/01-home.html:90-95:
     .seek{display:flex;align-items:center;gap:12px;background:#fff;
           border-radius:999px;padding:7px 7px 7px 22px;box-shadow:var(--sh)}
     .seek input{flex:1;border:0;outline:0;font:inherit;font-size:16px}
     .go{border:0;border-radius:999px;background:var(--blue);color:#fff;
         font-weight:600;font-size:15px;padding:11px 24px}
   The header field was Bootstrap's `.input-group`: a square-cornered box with
   a 1px grey border, a bright #0d6efd button and 16px of Bootstrap padding.
   These rules restyle that markup in place — the partial, its spinner and its
   "Search" label are untouched — so the bar reads as one pill with a pale
   ground and the LungMAP blue action, and stands 45px rather than 54px.
   ==================================================================== */
.lm-header .input-group {
  background: #fff;
  border-radius: 999px;
  box-shadow: 0 2px 10px rgba(13, 27, 36, .10);
  /* 10px, not 16: the placeholder starts closer to the left edge of the
     pill. Bootstrap's `ps-4` on the field added another 24px on top of
     this and has been removed from the partial. */
  padding: 3px 3px 3px 10px;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  /* Bootstrap gives .form-control a min-height near 38px and its own padding,
     which held the bar at 56px. Fixing the pill's height and zeroing that
     min-height brings it to 40px, close to the home page's own field. */
  height: 40px;
}
.lm-header .input-group .form-control.search-bar {
  border: 0 !important;
  outline: 0;
  background: transparent;
  box-shadow: none !important;
  padding: 0;
  height: auto;
  min-height: 0;
  font-size: 15px;
  line-height: 1.4;
  color: var(--lm-ink);
}
.lm-header .input-group .form-control.search-bar::placeholder {
  color: #8a949e;
  opacity: 1;
}
.lm-header .input-group .btn {
  border: 0;
  border-radius: 999px !important;
  background: #14527f;
  color: #fff;
  font-weight: 600;
  font-size: 14px;
  line-height: 1;
  padding: 0 18px;
  height: 34px;
  white-space: nowrap;
  transition: background .18s;
}
.lm-header .input-group .btn:hover { background: #2a7fbf; }

/* The header search keeps its waiting state after the pill restyle.
   Two things broke it: the button now has a fixed 34px height, so the spinner
   needed the button to be a flex row; and the sweep animation paints on
   .search-bar, whose background this file set to `transparent`. */
.lm-header .input-group .btn { display: inline-flex; align-items: center; justify-content: center; }
.lm-header form.is-thinking .search-bar {
  background-image: linear-gradient(90deg, transparent 0%,
                    rgba(20,82,127,.55) 50%, transparent 100%);
  background-size: 40% 2px; background-repeat: no-repeat;
  background-position: -40% 100%;
}

/* ------------------------------------------------------------------ article
 *
 * The prose layer. 36 content pages render through `pages/article.html`. The
 * page's HTML comes from its markdown and is never rewritten, so everything
 * here is presentation over markup the author already wrote.
 *
 * The layer is a grid rather than a stack. Prose spans the full column, but a
 * paragraph that is a LABEL followed by a LINK -- the shape the tutorial and
 * video lists use -- takes a single column and is drawn as a card. That turns
 * twelve identical text lines into a scannable two-column list and puts the
 * empty right-hand side of the page to work, without a wrapper element the
 * markdown does not have.
 */
.lm-article {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--lm-space-4);
  row-gap: var(--lm-space-4);
  /* Items stretch to their row height, so two cards beside each other end at
     the same line however long their titles run. `start` left them ragged. A
     full-width row holds one item, so stretching costs nothing there. */
  align-items: stretch;
  color: var(--lm-ink);
  font-size: var(--lm-text-base);
  line-height: var(--lm-leading-body);
}

/* Everything is full width until proven otherwise. */
.lm-article > * { grid-column: 1 / -1; margin: 0; }

.lm-article > p,
.lm-article > ul,
.lm-article > ol,
.lm-article > blockquote { max-width: 74ch; }

/* The opening paragraph carries the page. Setting it a step larger gives the
   article somewhere to start instead of opening at body size. */
.lm-article > p:first-of-type {
  font-size: var(--lm-text-lg);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-2);
  max-width: 70ch;
}

/* ---- headings ---- */
.lm-article h2,
.lm-article h3,
.lm-article h4,
.lm-article h5,
.lm-article h6 {
  color: var(--lm-ink);
  font-weight: var(--lm-weight-semi);
  line-height: var(--lm-leading-tight);
  margin-top: var(--lm-space-6);
  max-width: 74ch;
}
.lm-article > :first-child { margin-top: 0; }

.lm-article h2 {
  font-family: var(--lm-font-serif);
  font-size: var(--lm-display-sm);
  letter-spacing: var(--lm-track-display);
}
.lm-article h3 { font-size: var(--lm-text-2xl); }
.lm-article h4 { font-size: var(--lm-text-xl); }

/* A section label. The rule beside it does the work a bold grey line of
   capitals was doing alone, and gives the page its one accent. */
.lm-article h5 {
  display: flex;
  align-items: center;
  gap: var(--lm-space-3);
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-pine);
  margin-top: var(--lm-space-8);
}
.lm-article h5::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--lm-mint), transparent);
}
.lm-article h6 { font-size: var(--lm-text-md); color: var(--lm-ink-2); }

/* ---- prose links ---- */
.lm-article a {
  color: var(--lm-blue);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--lm-blue-edge);
}
.lm-article a:hover {
  color: var(--lm-blue-sunk);
  text-decoration-color: currentColor;
}

.lm-article ul,
.lm-article ol { padding-left: var(--lm-space-6); }
.lm-article li + li { margin-top: var(--lm-space-2); }
.lm-article img { max-width: 100%; height: auto; }
.lm-article table { width: 100%; }

/* ---- the card row -------------------------------------------------------
 * A paragraph holding a label and THEN a link, as `tutorials.md` writes it:
 *
 *     <p><span><strong>Tutorial 1:</strong> <a ...>Supervised annotation</a></span></p>
 *
 * The selector used to be `p:has(strong):has(a)`, which asks only whether the
 * paragraph contains both tags anywhere. Measured over the content tree on
 * 2026-08-22 that matched 16 paragraphs: the 12 real cards on tutorials.md,
 * and 4 paragraphs of ordinary prose that merely happen to hold a bold phrase
 * and a link, on citing-lungmap.md, human-tissue-core.md and
 * consortium-centers.md.
 *
 * Those four were wrecked by it. The card is a flex COLUMN, and the companion
 * rule below sets `display: contents` on the wrapper span, which lifts every
 * inline node inside it -- each text run, each `<span>LungMAP</span>`, each
 * `<a>` -- into a direct flex item. Each one then took its own line, so the
 * Citing LungMAP page broke mid-sentence: "NHLBI" / "LungMAP" / "Consortium."
 *
 * The selector now asks for the card's SHAPE. `strong ~ a` requires the bold
 * label to come before the link, which excludes prose that ends on a bold
 * grant number. `:not(:has(br))` excludes a paragraph carrying its own line
 * breaks, which no card does. Measured against the same 16 paragraphs, this
 * keeps all 12 cards and releases all 4 prose paragraphs. The longest card
 * kept runs 84 characters; the shortest prose released runs 213.
 */
.lm-article > p:has(strong ~ a):not(:has(br)) {
  grid-column: auto;
  max-width: none;
  display: flex;
  flex-direction: column;
  gap: var(--lm-space-2);
  padding: var(--lm-space-5);
  background: var(--lm-surface);
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-md);
  justify-content: flex-start;
  transition: border-color var(--lm-dur-fast) var(--lm-ease),
              box-shadow var(--lm-dur-fast) var(--lm-ease),
              transform var(--lm-dur-fast) var(--lm-ease);
}

.lm-article > p:has(strong ~ a):not(:has(br)):hover {
  background: var(--lm-surface-lift);
  border-color: var(--lm-blue-edge);
  box-shadow: var(--lm-shadow-card);
  transform: translateY(-1px);
}

/* The label becomes an eyebrow over the title rather than a prefix beside
   it, so twelve rows stop starting with the same eight characters. */
.lm-article > p:has(strong ~ a):not(:has(br)) strong {
  display: block;
  font-size: var(--lm-text-2xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3);
}

.lm-article > p:has(strong ~ a):not(:has(br)) a {
  font-size: var(--lm-text-md);
  font-weight: var(--lm-weight-medium);
  line-height: var(--lm-leading-snug);
  color: var(--lm-ink);
  text-decoration: none;
}
.lm-article > p:has(strong ~ a):not(:has(br)):hover a { color: var(--lm-blue); }

/* No external-link glyph. An arrow was appended to every card title here and
   removed on request: the whole card is the target, the hover state already
   says it is interactive, and a mark after the last word broke the line
   ending. Do not reintroduce it in this template or the others. */

/* The span the source wraps its text in must not fight the flex column. */
.lm-article > p:has(strong ~ a):not(:has(br)) > span { display: contents; }

@media (max-width: 860px) {
  .lm-article { grid-template-columns: minmax(0, 1fr); }
}

/* No motion for a reader who has asked for none. */
@media (prefers-reduced-motion: reduce) {
  .lm-article > p:has(strong ~ a):not(:has(br)) { transition: none; }
  .lm-article > p:has(strong ~ a):not(:has(br)):hover { transform: none; }
}

/* The standfirst under a page title. `lm-page-head__title` and `__meta` were
   already defined; `__lead` was not. */
.lm-page-head__lead {
  margin: var(--lm-space-3) 0 0;
  max-width: 68ch;
  font-size: var(--lm-text-lg);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-2);
}

/* The rule under a page title picks up the accent, so the head reads as a
   masthead rather than a grey divider. */
.lm-page-head {
  border-bottom: 0;
  position: relative;
}
.lm-page-head::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--lm-mint) 0 64px, var(--lm-line) 64px);
}

/* ------------------------------------------------------------------- browse
 *
 * Explore Data. The page had five saturated blue pill dropdowns competing with
 * the table for attention, and a nine-item modality strip that wrapped onto a
 * second line. Order was filters first, modality second, which asks a reader to
 * narrow before choosing what to narrow.
 *
 * Order is now modality, then filters, then results. Every load-bearing class
 * is kept: Bootstrap drives the tabs and dropdowns, `browsedatapage.js` reads
 * `data-dataset-type-id`, and DataTables binds `experiment-table`. This layer
 * only changes how they look.
 */

/* ---- modality strip ---- */
.lm-modality {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lm-space-2);
  border-bottom: 1px solid var(--lm-surface-line);
  padding-bottom: var(--lm-space-4);
  margin-bottom: var(--lm-space-5);
}
.lm-modality .nav-item { margin: 0; }
.lm-modality .nav-link {
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-pill);
  background: var(--lm-surface);
  color: var(--lm-ink-2);
  font-size: var(--lm-text-sm);
  font-weight: var(--lm-weight-medium);
  line-height: 1.2;
  padding: var(--lm-space-3) var(--lm-space-5);
  white-space: nowrap;
  transition: background var(--lm-dur-fast) var(--lm-ease),
              border-color var(--lm-dur-fast) var(--lm-ease),
              color var(--lm-dur-fast) var(--lm-ease);
}
.lm-modality .nav-link:hover {
  background: var(--lm-surface-lift);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
}
/* `.nav-tabs .nav-link.active` in Bootstrap is three classes deep and sets its
   own colour, which outranked a two-class rule here and left the selected pill
   drawing dark text on the blue fill -- unreadable. Matching its specificity
   fixes it without !important. */
.nav-tabs.lm-modality .nav-link.active,
.nav-tabs.lm-modality .nav-item .nav-link.active {
  background: var(--lm-blue);
  border-color: var(--lm-blue);
  /* `!important` here answers an `!important` already in the cascade, not a
     specificity problem. page.css:10329 sets `.nav-tabs .nav-link { color:
     #005295 !important }`, which no selector weight can outrank; measured in
     the browser, the selected pill computed to #005295 on a #14527f fill --
     blue text on blue. The legacy rule is left alone because every other
     nav-tabs strip on the site still depends on it. */
  color: var(--lm-white) !important;
  font-weight: var(--lm-weight-semi);
}
.nav-tabs.lm-modality .nav-link {
  border: 1px solid var(--lm-surface-line);
  background: var(--lm-surface);
  color: var(--lm-ink-2) !important;   /* same legacy !important */
}
.nav-tabs.lm-modality .nav-link:hover { color: var(--lm-blue) !important; }
.nav-tabs.lm-modality .nav-link:hover {
  background: var(--lm-surface-lift);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
}
.nav-tabs.lm-modality--sub .nav-link.active {
  background: var(--lm-blue-wash);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue) !important;
}
.nav-tabs.lm-modality--sub .nav-link { background: transparent; border-color: transparent; }

/* The second level, inside Spatial Imaging. Quieter than the first so the two
   rows are not read as peers. */
.lm-modality--sub {
  border-bottom: 0;
  padding-bottom: 0;
  margin: var(--lm-space-4) 0 var(--lm-space-5);
}
.lm-modality--sub .nav-link {
  border-radius: var(--lm-radius-sm);
  background: transparent;
  border-color: transparent;
  padding: var(--lm-space-2) var(--lm-space-4);
  font-size: var(--lm-text-xs);
}
.lm-modality--sub .nav-link.active {
  background: var(--lm-blue-wash);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
}

/* ---- filter bar ---- */
.lm-filterbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--lm-space-3);
  margin-bottom: var(--lm-space-4);
}
.lm-filterbar__label {
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3);
  margin-right: var(--lm-space-1);
}

/* A filter is an outlined control until it holds a value. Five filled blue
   pills read as five primary actions; the data is the primary thing here. */
.lm-filterbar .dropdown-toggle.btn {
  background: var(--lm-white);
  border: 1px solid var(--lm-surface-line);
  color: var(--lm-ink-2);
  border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-sm);
  font-weight: var(--lm-weight-medium);
  padding: var(--lm-space-2) var(--lm-space-4);
  box-shadow: none;
}
.lm-filterbar .dropdown-toggle.btn:hover,
.lm-filterbar .dropdown-toggle.btn[aria-expanded="true"] {
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
  background: var(--lm-blue-wash);
}
.lm-filterbar .dropdown-toggle.btn.is-set {
  background: var(--lm-blue);
  border-color: var(--lm-blue);
  color: var(--lm-white);
}

.lm-filterbar .dropdown-menu {
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-md);
  box-shadow: var(--lm-shadow-card);
  padding: var(--lm-space-2);
  max-height: 340px;
  overflow-y: auto;
  width: max-content;
  min-width: 0;
  max-width: 320px;
}
.lm-filterbar .dropdown-item {
  border-radius: var(--lm-radius-xs);
  font-size: var(--lm-text-sm);
  padding: var(--lm-space-2) var(--lm-space-3);
  color: var(--lm-ink-2);
  white-space: normal;
}
.lm-filterbar .dropdown-item:hover { background: var(--lm-blue-wash); color: var(--lm-blue); }
.lm-filterbar .dropdown-item.active { background: var(--lm-blue); color: var(--lm-white); }

/* ---- the values in force ---- */
.lm-chips { display: flex; flex-wrap: wrap; gap: var(--lm-space-2); align-items: center; }
.lm-chips .selected-filter { text-decoration: none; }
.lm-chips .selected-filter .btn {
  background: var(--lm-blue-wash);
  border: 1px solid var(--lm-blue-edge);
  color: var(--lm-blue);
  border-radius: var(--lm-radius-pill);
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-medium);
  padding: var(--lm-space-1) var(--lm-space-3);
  margin: 0;
}
.lm-chips .selected-filter .btn:hover {
  background: var(--lm-blue);
  border-color: var(--lm-blue);
  color: var(--lm-white);
}
.lm-chips .selected-filter i { margin-left: var(--lm-space-2); font-size: .8em; opacity: .8; }

/* ---- the results table ---- */
.lm-results .experiment-table { border-collapse: separate; border-spacing: 0; }
.lm-results .experiment-table thead th {
  font-size: var(--lm-text-2xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3);
  border-bottom: 1px solid var(--lm-surface-line);
  padding: var(--lm-space-3) var(--lm-space-3);
  vertical-align: bottom;
}
.lm-results .experiment-table tbody td {
  font-size: var(--lm-text-sm);
  color: var(--lm-ink-2);
  border-bottom: 1px solid var(--lm-line);
  padding: var(--lm-space-4) var(--lm-space-3);
  vertical-align: top;
}
.lm-results .experiment-table tbody tr:hover td { background: var(--lm-surface); }
.lm-results .experiment-table tbody td:first-child a {
  color: var(--lm-ink);
  font-weight: var(--lm-weight-medium);
  text-decoration: none;
}
.lm-results .experiment-table tbody tr:hover td:first-child a { color: var(--lm-blue); }
.lm-results .external__nav { display: flex; gap: var(--lm-space-3); list-style: none; margin: 0; padding: 0; }

/* Time-sensitive catalogue markers sit with the dataset title without
   competing with it.  Separate colours make "new" and "updated" scannable,
   while the text keeps the meaning accessible without relying on colour. */
.lm-results .dataset-status {
  display: inline-block;
  margin-left: var(--lm-space-2);
  padding: 2px 7px;
  border-radius: var(--lm-radius-pill);
  font-size: 10px;
  font-weight: var(--lm-weight-semi);
  line-height: 1.25;
  letter-spacing: .04em;
  text-transform: uppercase;
  vertical-align: 1px;
  white-space: nowrap;
}
.lm-results .dataset-status--new {
  color: #8a1414;
  background: #fbe2e2;
  border: 1px solid #edb0b0;
}
.lm-results .dataset-status--updated {
  color: #694200;
  background: #fff1cf;
  border: 1px solid #efd08a;
}

/* DataTables chrome: the length menu and the search field it injects. */
.lm-results .dataTables_length,
.lm-results .dataTables_filter { font-size: var(--lm-text-xs); color: var(--lm-ink-3); }
.lm-results .dataTables_length select,
.lm-results .dataTables_filter input {
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-sm);
  padding: var(--lm-space-2) var(--lm-space-3);
  font-size: var(--lm-text-sm);
  color: var(--lm-ink);
}
.lm-results .dataTables_filter input:focus,
.lm-results .dataTables_length select:focus {
  outline: none;
  border-color: var(--lm-blue-edge);
  box-shadow: 0 0 0 3px var(--lm-blue-wash);
}

/* The pill must not change size on hover. page.css:10320 gives
   `.nav-tabs .nav-link:hover` a bold weight, a 16px size and a 6px top border,
   all of which reflow the control: hovering a category visibly grew it. The
   geometry is pinned here so hover changes colour only. */
.nav-tabs.lm-modality .nav-link,
.nav-tabs.lm-modality .nav-link:hover,
.nav-tabs.lm-modality .nav-link:focus,
.nav-tabs.lm-modality .nav-item.show .nav-link {
  font-size: var(--lm-text-sm);
  font-weight: var(--lm-weight-medium);
  border-top-width: 1px;
  border-top-style: solid;
  border-radius: var(--lm-radius-pill);
}
.nav-tabs.lm-modality .nav-link.active,
.nav-tabs.lm-modality .nav-link.active:hover {
  font-weight: var(--lm-weight-semi);
  border-top-color: var(--lm-blue);
}
.nav-tabs.lm-modality .nav-link:hover { border-top-color: var(--lm-blue-edge); }
.nav-tabs.lm-modality .nav-link { border-top-color: var(--lm-surface-line); }

.nav-tabs.lm-modality--sub .nav-link,
.nav-tabs.lm-modality--sub .nav-link:hover,
.nav-tabs.lm-modality--sub .nav-link:focus {
  font-size: var(--lm-text-xs);
  border-top-color: transparent;
  border-radius: var(--lm-radius-sm);
}
.nav-tabs.lm-modality--sub .nav-link.active { border-top-color: var(--lm-blue-edge); }

/* ---- data page masthead -------------------------------------------------
 * A serif display line is right for an article and wrong for a data index: it
 * reads as decoration above a table. This variant follows the pattern the HCA
 * data browser uses -- a small muted eyebrow, a compact sans title, and the
 * count of what is on screen as the largest number in the block, so the
 * heading carries information rather than only a name.
 */
/* Tight to the header. The base `lm-page-head` reserves space above the
   title for an article; a data index does not need it, and with the browse
   page's own `mt-3`/`mt-4` row margins stacked on top the masthead was
   opening a large empty band under the site header. */
.lm-page-head--data {
  padding-block: 0 var(--lm-space-3);
  margin-bottom: var(--lm-space-4);
}
.lm-page-head--data::after { display: none; }
.lm-page-head--data .lm-page-head__count { margin-top: var(--lm-space-1); }

.lm-page-head--data .lm-page-head__eyebrow {
  font-size: var(--lm-text-2xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3);
  margin-bottom: var(--lm-space-2);
}
.lm-page-head--data .lm-page-head__title {
  font-family: var(--lm-font-sans);
  font-size: var(--lm-text-3xl);
  font-weight: var(--lm-weight-bold);
  letter-spacing: -0.015em;
  color: var(--lm-ink);
  margin: 0;
}
.lm-page-head--data .lm-page-head__count {
  margin: var(--lm-space-2) 0 0;
  font-size: var(--lm-text-sm);
  color: var(--lm-ink-2);
}
.lm-page-head--data .lm-page-head__count b {
  color: var(--lm-ink);
  font-weight: var(--lm-weight-semi);
}

/* ---- DataTables 2 chrome ------------------------------------------------
 * The earlier rules in this file named `.dataTables_length` and
 * `.dataTables_filter`, which are DataTables 1.x classes. This build is 2.3.7
 * and emits `dt-length`, `dt-search`, `dt-info` and `dt-paging` inside
 * `dt-layout-row`, so none of those rules ever matched and the controls kept
 * their default styling. Confirmed by reading the live DOM.
 */
.lm-results .dt-layout-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lm-space-4);
  flex-wrap: wrap;
  margin: 0 0 var(--lm-space-4);
}
.lm-results .dt-layout-row.dt-layout-table { display: block; margin: 0; }

.lm-results .dt-length,
.lm-results .dt-search,
.lm-results .dt-info {
  font-size: var(--lm-text-xs);
  color: var(--lm-ink-3);
  margin: 0;
}
.lm-results .dt-length label,
.lm-results .dt-search label { display: flex; align-items: center; gap: var(--lm-space-2); margin: 0; }

.lm-results .dt-length select,
.lm-results .dt-search input {
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-sm);
  background: var(--lm-white);
  padding: var(--lm-space-2) var(--lm-space-3);
  font-size: var(--lm-text-sm);
  color: var(--lm-ink);
  height: auto;
}
.lm-results .dt-search input { min-width: 220px; }
.lm-results .dt-search input::placeholder { color: var(--lm-ink-3); }
.lm-results .dt-length select:focus,
.lm-results .dt-search input:focus {
  outline: none;
  border-color: var(--lm-blue-edge);
  box-shadow: 0 0 0 3px var(--lm-blue-wash);
}

/* Paging: quiet square buttons, the current page filled. */
.lm-results .dt-paging { margin-left: auto; }
.lm-results .dt-paging .dt-paging-button {
  border: 1px solid transparent;
  border-radius: var(--lm-radius-sm);
  background: transparent;
  color: var(--lm-ink-2);
  font-size: var(--lm-text-sm);
  padding: var(--lm-space-2) var(--lm-space-3);
  margin: 0 1px;
  min-width: 34px;
}
.lm-results .dt-paging .dt-paging-button:hover:not(.disabled) {
  background: var(--lm-blue-wash);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue);
}
.lm-results .dt-paging .dt-paging-button.current,
.lm-results .dt-paging .dt-paging-button.current:hover {
  background: var(--lm-blue);
  border-color: var(--lm-blue);
  color: var(--lm-white);
}
.lm-results .dt-paging .dt-paging-button.disabled { color: var(--lm-ink-3); opacity: .5; }

/* The sub-tab row must stay quieter than the modality row above it. Both
   carry `lm-modality`, so the `--sub` rules are restated here, after the
   general ones, to win on order rather than on weight. */
.nav-tabs.lm-modality--sub .nav-link,
.nav-tabs.lm-modality--sub .nav-link:hover,
.nav-tabs.lm-modality--sub .nav-link:focus {
  background: transparent;
  border-color: transparent;
  color: var(--lm-ink-2) !important;
  font-size: var(--lm-text-xs);
  padding: var(--lm-space-2) var(--lm-space-4);
}
.nav-tabs.lm-modality--sub .nav-link:hover { color: var(--lm-blue) !important; background: var(--lm-blue-wash); }
.nav-tabs.lm-modality--sub .nav-link.active,
.nav-tabs.lm-modality--sub .nav-link.active:hover {
  background: var(--lm-blue-wash);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue) !important;
  font-weight: var(--lm-weight-semi);
}

/* Two corrections, both measured in the browser rather than assumed.
 *
 * 1. The sub-tab kept the primary blue fill. The general rule above lists
 *    `.nav-tabs.lm-modality .nav-item .nav-link.active`, four classes, which
 *    outranks a three-class `--sub` rule however late it appears. Matching the
 *    depth fixes it.
 *
 * 2. DataTables 2 renders the length control as a bare <select> followed by a
 *    text node -- there is no <label> to style, so the earlier rule did
 *    nothing and "entries per page" wrapped under the select. The container
 *    itself becomes the flex row.
 */
.nav-tabs.lm-modality--sub .nav-item .nav-link.active,
.nav-tabs.lm-modality--sub .nav-item .nav-link.active:hover {
  background: var(--lm-blue-wash);
  border-color: var(--lm-blue-edge);
  color: var(--lm-blue) !important;
}

/* THE TABLE CONTROLS BELONG TO THE TABLE, SO THEY TAKE ITS TYPE.
 *
 * Measured in the browser on 2026-09-20: the length select, the words "entries
 * per page", the "Search studies:" label and its box all rendered at 16px while
 * the table body sits at 14px and its headers at 11px, so the controls read as
 * the largest type in the results block. The select and its label also touched,
 * because DataTables 2 emits `<select>` then `<label>` with nothing between and
 * the container is a plain block.
 *
 * `.lm-results` was the old scope. The compendia table is not inside it: its
 * controls sit under `#compendia-table_wrapper.dt-container` in
 * `#compendia-results`, so the rule never reached the page in the screenshot.
 * `.dt-container` is what every DataTables 2 instance emits, which covers both
 * tables and any later one.
 */
.dt-container .dt-length,
.dt-container .dt-search {
  display: flex;
  align-items: center;
  gap: var(--lm-space-4);
  white-space: nowrap;
  font-size: var(--lm-text-base);
  color: var(--lm-ink-2);
}
.dt-container .dt-length label,
.dt-container .dt-search label {
  margin: 0;
  font-size: inherit;
  color: inherit;
}
.dt-container .dt-length select,
.dt-container .dt-search input {
  margin: 0;
  font-family: inherit;
  font-size: inherit;
  color: var(--lm-ink);
  padding: var(--lm-space-2) var(--lm-space-3);
  border: 1px solid var(--lm-line-strong);
  border-radius: var(--lm-radius-xs);
  background: #ffffff;
}
.dt-container .dt-length select:focus-visible,
.dt-container .dt-search input:focus-visible {
  outline: 2px solid var(--lm-blue);
  outline-offset: 1px;
}

/* ------------------------------------------------------------------ search
 * Results page. The heading sat on a 180deg grey gradient
 * (searchpage.css:81) and the category rail used 72px rows with large filled
 * count circles, so the navigation outweighed the results beside it. The rail
 * follows `lm-aside__nav`: a left rule and a wash for the current category,
 * and the count as a plain numeral.
 */
.lm-search-rail .search-result-category,
.lm-search-rail .btn.search-result-category {
  height: auto;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  border-radius: 0;
  box-shadow: none;
  padding: var(--lm-space-3) var(--lm-space-4);
  color: var(--lm-ink-2);
  font-weight: var(--lm-weight-medium);
  transition: background var(--lm-dur-fast) var(--lm-ease),
              color var(--lm-dur-fast) var(--lm-ease);
}
.lm-search-rail .search-result-category:hover {
  background: var(--lm-blue-wash);
  color: var(--lm-blue);
}
.lm-search-rail .search-result-selected-category,
.lm-search-rail .btn.search-result-selected-category {
  background: var(--lm-blue-wash);
  border-left-color: var(--lm-blue);
  border-radius: 0 var(--lm-radius-xs) var(--lm-radius-xs) 0;
  box-shadow: none;
  color: var(--lm-blue) !important;
  font-weight: var(--lm-weight-semi);
}
.lm-search-rail .search-result-category-label {
  font-size: var(--lm-text-md);
  line-height: var(--lm-leading-snug);
}

/* The count keeps its circle. Dropping it for a bare numeral made the rail
   duller and harder to scan, so the disc stays and only its colour changes:
   a wash for a category you are not in, the solid brand blue for the one you
   are. */
.lm-search-rail .search-result-count-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  /* searchpage.css:107 gives this element `padding-top: 12px`, which the
     original used to fake vertical centring in an inline-block. Inside a flex
     box that padding just pushes the number below centre, so it is cleared
     and `align-items` does the centring properly. */
  padding: 0;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--lm-blue-wash) !important;
  color: var(--lm-blue) !important;
  font-size: var(--lm-text-sm);
  font-weight: var(--lm-weight-bold);
  line-height: 1;
}
.lm-search-rail .search-result-selected-category .search-result-count-circle,
.lm-search-rail .search-result-count-circle-selected {
  background: var(--lm-blue) !important;
  color: var(--lm-white) !important;
}
.lm-search-rail .search-result-category { padding-block: var(--lm-space-4); }

/* ---- one result ---- */
.lm-search-results .search-result {
  border-bottom: 1px solid var(--lm-line);
  padding: var(--lm-space-5) 0;
}
.lm-search-results .search-result:last-child { border-bottom: 0; }
.lm-search-results .entity-label a,
.lm-search-results .search-result-title a {
  color: var(--lm-ink);
  font-size: var(--lm-text-lg);
  font-weight: var(--lm-weight-semi);
  line-height: var(--lm-leading-snug);
  text-decoration: none;
}
.lm-search-results .entity-label a:hover,
.lm-search-results .search-result-title a:hover { color: var(--lm-blue); }

.lm-search-results .search-result-metadata-row {
  display: flex;
  gap: var(--lm-space-2);
  font-size: var(--lm-text-sm);
  line-height: var(--lm-leading-snug);
  margin-top: var(--lm-space-1);
}
.lm-search-results .search-result-metadata-label {
  color: var(--lm-ink-3);
  font-weight: var(--lm-weight-medium);
  min-width: 84px;
}
.lm-search-results .search-result-metadata-value { color: var(--lm-ink-2); }

/* The tool icons under a result. */
.lm-search-results .search-tool-icon { display: inline-block; margin-right: var(--lm-space-3); }
.lm-search-results .search-tool-img {
  height: 34px;
  width: auto;
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-xs);
  background: var(--lm-white);
  transition: border-color var(--lm-dur-fast) var(--lm-ease);
}
.lm-search-results .search-tool-icon a:hover .search-tool-img { border-color: var(--lm-blue-edge); }

/* ------------------------------------------------- one masthead, everywhere
 *
 * Three different treatments had grown up: a serif title with a mint rule on
 * article pages, an eyebrow-plus-black-title on the data pages, and the
 * Analytics page's blue title over a grey line. The third is the one to keep,
 * so it is defined here once and the other two are folded into it.
 *
 * Analytics wrote it with legacy utilities -- `text-blue fw-bold text-size-30`
 * over `text-size-14 text-dark-gray`, page.css:10398 for the blue. The same
 * result is expressed in tokens so it can be changed in one place.
 */
.lm-page-head,
.lm-page-head--data {
  padding-block: var(--lm-space-4) 0;
  margin-bottom: var(--lm-space-4);
  border-bottom: 0;
  position: static;
}
.lm-page-head::after,
.lm-page-head--data::after { display: none; }

/* Also matches a bare `lm-page-head__title` with no wrapper: several page
   templates carry the title alone, and scoping the rule to the wrapper left
   them on the earlier serif definition. */
.lm-page-head__title,
.lm-page-head .lm-page-head__title,
.lm-page-head--data .lm-page-head__title {
  font-family: var(--lm-font-sans);
  font-size: 30px;
  font-weight: var(--lm-weight-bold);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--lm-blue);
  margin: 0;
}

/* The one grey line under the title. `__sub`, `__lead` and `__count` are the
   three names the templates already use for it. */
.lm-page-head__sub,
.lm-page-head__lead,
.lm-page-head .lm-page-head__sub,
.lm-page-head .lm-page-head__lead,
.lm-page-head .lm-page-head__count,
.lm-page-head--data .lm-page-head__count {
  margin: var(--lm-space-2) 0 0;
  max-width: 92ch;
  font-family: var(--lm-font-sans);
  font-size: var(--lm-text-base);
  font-weight: var(--lm-weight-regular);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-2);
}
.lm-page-head .lm-page-head__count b { font-weight: var(--lm-weight-semi); color: var(--lm-ink); }

/* Style 3 carries no eyebrow. */
.lm-page-head .lm-page-head__eyebrow,
.lm-page-head--data .lm-page-head__eyebrow { display: none; }

/* Reserve the scrollbar's width whether or not a scrollbar is showing.
 *
 * Tabs on the browse page differ a lot in height -- measured, the proteomics
 * pane renders a 3,702px document and the microRNA pane 2,760px. With classic
 * scrollbars one of those shows a vertical bar and the other does not, so the
 * viewport width changes between them and every centred element, including the
 * header, jumps sideways by the scrollbar width when you switch tabs.
 *
 * `stable` reserves the gutter permanently. On systems with overlay scrollbars
 * (macOS trackpad default) scrollbars take no space and this has no effect, so
 * it costs nothing there.
 */
html { scrollbar-gutter: stable; }

/* ----------------------------------------------------------------- dataset
 * One dataset. The page drew its title at 24px, its author list bold blue and
 * every label and value inside a `shadow-lg` panel in the same blue, so the
 * description read as a wall of link-coloured text. The masthead is the shared
 * one; below it, labels are muted and values are ink.
 */
.lm-dataset__authors {
  margin-top: var(--lm-space-2);
  font-size: var(--lm-text-base);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink);
}
.lm-dataset__authors sup { color: var(--lm-ink-3); font-size: .72em; }

.lm-dataset__affil {
  margin-top: var(--lm-space-1);
  font-size: var(--lm-text-sm);
  line-height: var(--lm-leading-sub);
  color: var(--lm-ink-3);
}
.lm-dataset__affil sup { font-size: .78em; }

.lm-dataset__link {
  font-size: var(--lm-text-sm);
  font-weight: var(--lm-weight-medium);
  color: var(--lm-blue);
  text-decoration: none;
}
.lm-dataset__link:hover { text-decoration: underline; text-underline-offset: 2px; }
.lm-dataset__sep { color: var(--lm-line-strong); margin: 0 var(--lm-space-3); }

/* The metadata card. */
.lm-dataset__card {
  background: var(--lm-surface);
  border: 1px solid var(--lm-surface-line);
  border-radius: var(--lm-radius-md);
  box-shadow: none;
  padding: var(--lm-space-5) var(--lm-space-4);
}
.lm-dataset__card .panel-content { padding: 0; }

/* Description and every other metadata value: ink, with the label muted so a
   reader can scan the labels without reading the values. */
.lm-dataset__card .lm-fact__label {
  display: inline;
  font-size: var(--lm-text-xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3);
  margin-right: var(--lm-space-2);
}
.lm-dataset__card .lm-fact__value {
  font-size: var(--lm-text-sm);
  line-height: var(--lm-leading-body);
  color: var(--lm-ink-2);
}
.lm-dataset__card .lm-fact__value a { color: var(--lm-blue); }

/* The description is the one long value; give it room to breathe and a
   readable measure while the short facts stay inline. */
.lm-dataset__card .row > div > .lm-fact__label + .lm-fact__value { max-width: 108ch; }
.lm-dataset__card .row { margin-bottom: var(--lm-space-3); }
.lm-dataset__card .dataset-db-xref-img { height: 22px; width: auto; margin-right: var(--lm-space-3); }

/* The dataset page's table carries `dataset-table`, not `experiment-table`, so
   the results styling above skipped it and its headers and cells kept the
   legacy blue. Same treatment, same tokens. */
.lm-results .dataset-table { border-collapse: separate; border-spacing: 0; width: 100%; }
.lm-results .dataset-table thead th {
  font-size: var(--lm-text-2xs);
  font-weight: var(--lm-weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--lm-track-eyebrow);
  color: var(--lm-ink-3) !important;
  border-bottom: 1px solid var(--lm-surface-line);
  padding: var(--lm-space-3);
  vertical-align: bottom;
}
.lm-results .dataset-table tbody td {
  font-size: var(--lm-text-sm);
  color: var(--lm-ink-2);
  border-bottom: 1px solid var(--lm-line);
  padding: var(--lm-space-3);
  vertical-align: top;
}
.lm-results .dataset-table tbody tr:hover td { background: var(--lm-surface); }
.lm-results .dataset-table tbody td a { color: var(--lm-blue); text-decoration: none; }
.lm-results .dataset-table tbody td a:hover { text-decoration: underline; text-underline-offset: 2px; }
.lm-results .dataset-table tbody td:first-child a { color: var(--lm-ink); font-weight: var(--lm-weight-medium); }
.lm-results .dataset-table tbody tr:hover td:first-child a { color: var(--lm-blue); }

/* The sample name in the network panel is a link to that sample's filtered
   view of the catalogue. */
.net-title-link { color: var(--lm-blue); text-decoration: none; }
.net-title-link:hover { text-decoration: underline; text-underline-offset: 2px; }

/* --- LungChat, the one highlighted item in the header --------------------
 * A top-level link rather than a section, so it needs to look different from
 * the four menus beside it.
 *
 * Dark grey, NOT the LungChat purple, on every page that uses this header.
 * The purple (#6c4fb5) drew the eye away from page content, so on 2026-09-07
 * the site owner asked for grey everywhere except the home page. The home
 * page keeps the purple: `.HomeC .lm-nav__link--chat` in home-c.css owns the
 * pill there, and that file is untouched by this change.
 *
 * #56636f is `--lm-ink-2` from tokens.css, not a new colour. It was chosen on
 * measured contrast, not by eye: white text on it is 6.16:1, against the
 * purple's 6.13:1, so the pill recedes because it is desaturated and not
 * because it got harder to read. `--lm-ink-3` (#8a949e) was rejected at
 * 3.08:1, below the 4.5:1 floor, and `--lm-ink` (#1c2530) at 15.48:1 would
 * have been MORE prominent than the purple, which is the opposite of the ask.
 * Hover uses #4a5866, already in the project, a step down of the same size
 * the purple's #59409a hover made.
 *
 * Written twice on purpose. `.lm-nav__link` is styled in two places in this
 * file: the base rule near the top and the `.lm-header .lm-nav__link`
 * override further down, which is more specific and would otherwise repaint
 * the colour back to `--ink`. Each selector below out-specifies its pair.
 */
.lm-nav__link--chat,
.lm-header .lm-nav__link--chat {
  color: #ffffff;
  background: #56636f;
  border-radius: 999px;
  padding: 7px 15px;
  font-weight: 600;
  transition: background var(--lm-dur-fast) var(--lm-ease);
}
.lm-nav__link--chat:hover,
.lm-nav__item:hover > .lm-nav__link--chat,
.lm-header .lm-nav__link--chat:hover {
  color: #ffffff;
  background: #4a5866;
}
/* The pill carries its own padding, so the item must not add the panel's
   hover affordance around it. There is no panel to open. */
.lm-nav__item:has(> .lm-nav__link--chat) { padding: 0; }

/* The mobile menu draws plain rows, so the accent is the text colour there
   rather than a pill: a full-width block would read as a header. It follows
   the grey for the same reason, and it is inner-pages-only -- the home page
   includes navigation.html but not responsive_nav.html. */
.lm-mobile-nav__link--chat { color: #56636f !important; font-weight: 700; }
