/* Lumen ops dashboard (/admin/) — the brand banner, the status band and the health cards.
   ------------------------------------------------------------------------------------------
   Lives in a linked sheet, not an inline <style> in index.html, for two reasons: the 8s poll
   re-renders admin/health/_cards.html standalone (so the fragment must be styleable on its own),
   and the tests render that fragment directly.

   Colour rules, inherited from the consoles and kept verbatim here:
     · A hue used as TEXT needs the darker `-d` shade; the plain hue is for FILLS only. Violet,
       pink, azure and amber all fail WCAG AA as text on the card otherwise.
     · Identity ≠ status. Each card owns a hue (--lh-c / --lh-cd) drawn from the four NON-ALARM
       brand hues — teal, azure, violet, pink — so the 3px rail can never read as green/amber/red.
       The CTA takes the same hue, which is what stops teal meaning three things at once on a
       queue card. Status speaks through a corner pill, the offending row, and (red only) a
       surface wash — never the rail, and never the border, which sits right beside the rail.
     · The headline number is always ink. A card's status can be set by a row its headline
       doesn't mention, and colouring the verdict by it printed "3/3 healthy" in alarm red.
     · Silence means healthy. A card that is fine wears no pill and no tint; the two that aren't
       are the two you see.
   Every (foreground, background) pair declared below is AA-checked in both themes by
   ops/tests/test_ops.py::test_status_text_colours_meet_aa. */

#lh-health {
  /* Fills (never text) */
  --lh-teal: var(--lm-teal, #00bfae); --lh-azure: var(--lm-azure, #2d9cff);
  --lh-violet: var(--lm-violet, #7a5bff); --lh-pink: var(--lm-pink, #ff2d8e);
  --lh-green-f: #22c55e; --lh-amber-f: #eab308; --lh-red-f: #ef4444;
  /* Text shades (the -d ramp) */
  /* azure-d is a shade darker here than in the consoles' ramp (#1f74c8). Now that the CTA takes
     the CARD's hue, azure-d has to clear AA on an azure-tinted button as well as on plain white,
     and #1f74c8 was 4.20:1 on that tint — the exact failure the `-d` rule exists to catch. */
  --lh-teal-d: #0b6e64; --lh-azure-d: #1b68b3; --lh-violet-d: #5a3ecc;
  --lh-pink-d: #c71e70; --lh-amber-d: #8a5410; --lh-red-d: #b91c1c; --lh-green-d: #15803d;
  /* The "needs a look" ATTENTION state wears the BRAND GRADIENT (--lm-grad / --lm-grad-v: the
     teal→azure→violet→pink ramp), not a solid hue — a worklist to act on reads as brand identity,
     not a caution colour. Red stays a solid alarm. See .lh-status-attention below. */
  /* Ink + surfaces */
  --lh-ink: var(--lm-ink, #10211f); --lh-ink2: #54625f; --lh-ink3: #67736f;
  /* `--lh-card` is what "on the card" means and a red card re-points it at its own wash, so the
     unwashed surface needs its own name — mixing the wash out of a value that already contains it
     compounds on every re-render of the polled fragment. */
  --lh-card-base: #fff; --lh-card: var(--lh-card-base); --lh-wash: #f3f1ec;
  --lh-line: rgba(16, 33, 31, .10); --lh-line2: rgba(16, 33, 31, .07);
  --lh-border: color-mix(in srgb, var(--color-base-700) 24%, transparent);
  --lh-sans: "Manrope", system-ui, sans-serif;
  --lh-mono: "Space Mono", ui-monospace, monospace;
  --lh-r-card: var(--lm-r-card, 22px);
  --lh-pad: 18px;               /* the card's horizontal gutter, owned by each block */
  --lh-sh: 0 2px 8px rgba(16, 33, 31, .04), 0 16px 34px rgba(16, 33, 31, .05);
  font-family: var(--lh-sans);
}
.dark #lh-health {
  --lh-teal-d: #38e0d0; --lh-azure-d: #7cc2ff; --lh-violet-d: #b6a2ff;
  --lh-pink-d: #ff86bd; --lh-amber-d: #facc15; --lh-red-d: #f87171; --lh-green-d: #4ade80;
  --lh-ink: #eef2f0; --lh-ink2: #a6bbb7; --lh-ink3: #8b9d99;
  --lh-card-base: #0f1c1a; --lh-card: var(--lh-card-base); --lh-wash: #14201e;
  --lh-line: rgba(255, 255, 255, .11); --lh-line2: rgba(255, 255, 255, .07);
  --lh-border: rgba(255, 255, 255, .12);
  /* Shadows off in dark — as a transparent shadow rather than `none`, because the token is
     composed into multi-shadow lists (`:target`) where `none` would be invalid CSS. */
  --lh-sh: 0 0 0 rgba(0, 0, 0, 0);
}

/* ============================================================================================
   Brand banner — a compressed port of the pitch deck's title slide (docs/Pitch deck). Its job is
   tone, not data: every live number lives in the status band inside the polled fragment, so
   nothing here can go stale. Replaces both the old gradient hero and Unfold's stock header bar.

   The sidebar drops its own brand lockup on this page (see unfold/helpers/navigation_header.html),
   so the mark here is the only one — two identical ring-and-dot marks ~180px apart on the same
   line read as a duplicate rather than as branding.
   ============================================================================================ */
.lumen-banner {
  position: relative;
  overflow: hidden;             /* clips the wash layers; no popovers live in here */
  background: #fff;
  margin-bottom: 1.25rem;
}
.dark .lumen-banner { background: #0d1917; }

/* The deck's atmosphere as two independently drifting wash layers. Four soft colour fields
   between them — teal and violet from the left, pink and azure from the right — so the banner
   carries the whole brand ramp rather than the two hues the earlier version had. Animation is
   transform-only, which the compositor handles without repainting the gradients. */
.lumen-banner-glow {
  position: absolute; inset: -60% -10%;
  filter: blur(30px); pointer-events: none; z-index: 0;
}
.lumen-banner-glow-a {
  background:
    radial-gradient(26% 54% at 8% 58%, color-mix(in srgb, var(--lm-teal, #00bfae) 30%, transparent), transparent 70%),
    radial-gradient(24% 50% at 33% 22%, color-mix(in srgb, var(--lm-violet, #7a5bff) 20%, transparent), transparent 70%);
}
.lumen-banner-glow-b {
  background:
    radial-gradient(26% 56% at 64% 76%, color-mix(in srgb, var(--lm-pink, #ff2d8e) 20%, transparent), transparent 70%),
    radial-gradient(22% 48% at 92% 24%, color-mix(in srgb, var(--lm-azure, #2d9cff) 22%, transparent), transparent 70%);
}
.dark .lumen-banner-glow { opacity: .45; }

/* A dot grid fading out across the band — texture at almost no cost, and it stops the wash from
   reading as a flat wash. Masked diagonally so it never reaches the right-hand meta text. */
.lumen-banner::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(rgba(16, 33, 31, .13) 1px, transparent 1.2px);
  background-size: 15px 15px;
  -webkit-mask-image: linear-gradient(102deg, #000, transparent 60%);
  mask-image: linear-gradient(102deg, #000, transparent 60%);
  opacity: .5;
}
.dark .lumen-banner::after { background-image: radial-gradient(rgba(255, 255, 255, .10) 1px, transparent 1.2px); }

@keyframes lumen-drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(5%, 9%, 0) scale(1.16); }
}
@keyframes lumen-drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.12); }
  to   { transform: translate3d(-6%, -7%, 0) scale(.95); }
}
/* Alternate rather than loop: a linear-gradient pan has no seamless wrap point, and easing back
   and forth over 9–18s reads as ambient rather than as something demanding attention. */
@keyframes lumen-pan { to { background-position: 100% 0; } }

@media (prefers-reduced-motion: no-preference) {
  .lumen-banner-glow-a { animation: lumen-drift-a 19s ease-in-out infinite alternate; }
  .lumen-banner-glow-b { animation: lumen-drift-b 26s ease-in-out infinite alternate; }
  .lumen-banner-wordmark { animation: lumen-pan 11s ease-in-out infinite alternate; }
  .lumen-banner-edge { animation: lumen-pan 18s ease-in-out infinite alternate; }
  .lumen-rise { animation: lumen-rise .34s cubic-bezier(.2, .7, .3, 1) both; }
  .lumen-rise-d1 { animation-delay: .11s; }
}
@keyframes lumen-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Aligned to the card grid, not to the viewport: `px-4` + `.container mx-auto` are the same two
   Unfold classes the content column uses, so the wordmark's left edge tracks the cards' left edge
   automatically if that container ever changes. */
.lumen-banner-pad { position: relative; z-index: 1; padding-inline: 1rem; }
/* One scale for the whole lockup. Height, mark and type are all multiples of `--lb-s`, so the
   banner can be made taller or shorter in one place without the mark drifting out of proportion
   with the wordmark — which is what happened the last two times these were tuned separately. */
.lumen-banner-inner {
  --lb-s: 1.35;
  display: flex; align-items: flex-end; gap: 1.5rem; flex-wrap: wrap;
  padding: calc(1.6rem * var(--lb-s)) 0 calc(1.5rem * var(--lb-s));
}
.lumen-banner-brand { display: flex; align-items: flex-end; gap: calc(.95rem * var(--lb-s)); min-width: 0; }
.lumen-banner-mark {
  flex: none; display: grid; place-items: center;
  width: calc(42px * var(--lb-s)); height: calc(42px * var(--lb-s));
  border-radius: 50%; background: #fff;
  box-shadow: 0 0 0 calc(7px * var(--lb-s)) color-mix(in srgb, var(--lm-teal, #00bfae) 10%, transparent);
  margin-bottom: calc(5px * var(--lb-s));
}
.dark .lumen-banner-mark { background: #0d1917; }
/* Overrides the img's own width/height attributes, which stay at the SVG's natural 42px so the
   markup keeps an intrinsic aspect ratio and the banner doesn't reflow while the file loads. */
.lumen-banner-mark img { display: block; width: 100%; height: 100%; }
.lumen-banner-wordmark {
  font-family: "Manrope", system-ui, sans-serif;
  font-weight: 800;
  font-size: calc(2.5rem * var(--lb-s));
  letter-spacing: -.035em;
  line-height: 1;
  margin: 0;
  /* Gradient-clipped. This is a logotype, which WCAG 1.4.3 exempts from contrast — and the
     sidebar wordmark already ships exactly this treatment, so a solid-ink hero was the odd one
     out. Prose in the banner stays solid: the same fill at 11px would be a real AA failure.
     The ramp is written twice so the 100%-wide window always spans a full teal→azure→pink
     sweep as it pans; a single ramp at 200% shows only two of the three hues at a time. */
  background: linear-gradient(96deg,
    var(--lm-teal, #00bfae), var(--lm-azure, #2d9cff) 26%, var(--lm-pink, #ff2d8e) 50%,
    var(--lm-teal, #00bfae) 76%, var(--lm-azure, #2d9cff));
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lumen-banner-tagline {
  font-size: calc(.8125rem * var(--lb-s));
  margin: calc(.45rem * var(--lb-s)) 0 0;
  color: #54625f;
}
.dark .lumen-banner-tagline { color: #a6bbb7; }

/* Right side: the date and the brand line, so the bar is a composition rather than a left-aligned
   word with 60% dead space. Mono + wide tracking is the deck's eyebrow spec. */
/* Scaled at the square root of the lockup's factor, not the full one: this is an eyebrow at wide
   tracking, and taking it up 35% turns a quiet date stamp into a second headline. */
/* The meta stacks: clock on top, then the date line. The date row keeps the original horizontal
   spec, and wraps rather than clipping — the banner is overflow:hidden. */
.lumen-banner-meta {
  margin-left: auto; display: flex; flex-direction: column; align-items: flex-end;
  gap: calc(.5rem * var(--lb-s));
  font-family: "Space Mono", ui-monospace, monospace;
  font-size: .78rem; letter-spacing: 1.8px; text-transform: uppercase;
  padding-bottom: calc(.45rem * var(--lb-s));
}
.lumen-banner-metarow {
  display: flex; align-items: center; gap: calc(.9rem * var(--lb-s));
  flex-wrap: wrap; justify-content: flex-end; row-gap: .35rem;
}

/* Banner variant of the admin clock (base styles in lumen-admin.css). Sized off the eyebrow rather
   than inheriting it: the meta's .78rem/1.8px tracking is a spec for short uppercase words, and a
   time set to it reads as a third headline. The UK time is the one dark element up here; its label,
   the local row and the offset sit at the date's ink so the block reads under the date, not over it. */
.lumen-clock-banner { font-size: .72rem; align-items: flex-end; }
/* The brand hot pink, matching the sidebar clock and the mark's dot. Brightness over the -d ramp:
   3.5:1 on this wash, under the 4.5:1 AA bar for text this size (see the sidebar rule). */
.lumen-clock-banner .lumen-clock-uk .lumen-clock-time { color: #ff2d8e; }
.lumen-clock-banner .lumen-clock-uk .lumen-clock-label,
.lumen-clock-banner .lumen-clock-local { color: #67736f; }
.lumen-clock-banner .lumen-clock-drift { color: #8a5410; }
.dark .lumen-clock-banner .lumen-clock-uk .lumen-clock-label,
.dark .lumen-clock-banner .lumen-clock-local { color: #8b9d99; }
.dark .lumen-clock-banner .lumen-clock-drift { color: #facc15; }
.lumen-banner-date { color: #54625f; }
.dark .lumen-banner-date { color: #a6bbb7; }
.lumen-banner-rule { width: calc(46px * var(--lb-s)); height: 1px; background: var(--lm-grad); flex: none; }
/* The brand line is static teal-d, not gradient-clipped like the wordmark: at 11px uppercase it
   is prose, and the teal end of that ramp is 2.33:1 on white. */
.lumen-banner-sub { color: #0b6e64; }
.dark .lumen-banner-sub { color: #38e0d0; }

/* Closes the band with the full brand ramp instead of a hairline border. */
.lumen-banner-edge {
  height: 3px; position: relative; z-index: 1;
  /* Ramp written twice, same reason as the wordmark: the visible window always spans the whole
     teal → azure → violet → pink sweep rather than half of it. */
  background: linear-gradient(90deg,
    var(--lm-teal, #00bfae), var(--lm-azure, #2d9cff) 17%, var(--lm-violet, #7a5bff) 31%,
    var(--lm-pink, #ff2d8e) 50%, var(--lm-teal, #00bfae) 67%, var(--lm-azure, #2d9cff) 81%,
    var(--lm-violet, #7a5bff) 94%, var(--lm-pink, #ff2d8e));
  background-size: 200% 100%;
}

/* Narrow: turn the scale down rather than re-specifying every size. The proportions are the same
   composition, just smaller — which is the point of driving them all off one number.
   The mid step exists because the meta wraps onto its own line below ~1100px; at full scale that
   put the banner at 210px, taller than the status band it introduces. */
@media (max-width: 1100px) { .lumen-banner-inner { --lb-s: 1.1; } }
@media (max-width: 720px) {
  .lumen-banner-inner { --lb-s: .8; gap: .6rem; }
  .lumen-banner-meta { margin-left: 0; align-items: flex-start; padding-bottom: 0; font-size: .68rem; }
  .lumen-clock-banner { justify-content: start; }
}

/* ============================================================================================
   Status band — the page's single answer to "is anything broken?"
   ============================================================================================ */
#lh-health .lh-status {
  border: 1px solid var(--lh-border); border-left: 3px solid var(--lh-teal);
  border-radius: var(--lh-r-card);
  background: var(--lh-card); box-shadow: var(--lh-sh);
  padding: 16px 20px; margin-bottom: 1.75rem;
}
/* A status rail is legal here where it isn't on a card: there is exactly one band and it has no
   identity to carry, so the left edge is free to mean state. */
/* Both worklist states — "needs a look" and "needs you" — wear the brand ramp as the left border,
   exactly like the review cards' solid `border-left` (line 366) but gradient. A gradient can't be a
   border-color and a thin background strip won't hug the rounded corners, so this uses the standard
   gradient-border technique: the ramp fills the whole border-box and a card-coloured layer clipped
   to the padding-box covers the interior, leaving the ramp showing only in the border ring — which
   IS the rounded corner, so it curves cleanly. Left 3px (the accent), a hairline elsewhere.
   Severity still shows: the headline wording changes and any broken TILE stays red. */
#lh-health .lh-status-attention,
#lh-health .lh-status-alarm {
  border: 1px solid transparent;
  border-left-width: 3px;
  background:
    linear-gradient(var(--lh-card), var(--lh-card)) padding-box,
    var(--lm-grad-v) border-box;
}
#lh-health .lh-status-partial { border-left-color: var(--lh-ink3); }
#lh-health .lh-status-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
#lh-health .lh-status-pill {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 20px; font-weight: 800; letter-spacing: -.4px; color: var(--lh-ink);
}
#lh-health .lh-status-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--lh-teal); flex: none; }
#lh-health .lh-status-attention .lh-status-dot,
#lh-health .lh-status-alarm .lh-status-dot { background: var(--lm-grad); }
#lh-health .lh-status-partial .lh-status-dot { background: var(--lh-ink3); }
#lh-health .lh-status-meta {
  margin-left: auto; font-family: var(--lh-mono); font-size: 11px;
  letter-spacing: .3px; color: var(--lh-ink2); font-variant-numeric: tabular-nums;
}

/* Two lines per alert, not one pill carrying the whole sentence: the card name gets its own line
   so a column of them can be scanned down, and the reason sits under it. The tile is the link. */
#lh-health .lh-alerts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  /* `1fr` equalises rows against each other; the reason line below is what makes every tile the
     same height whichever row it lands in. Both are needed — `1fr` alone left a one-line tile on
     row 2 at 60px beside a two-line tile on row 1 at 78px. */
  grid-auto-rows: 1fr;
  gap: 9px; margin: 13px 0 0; padding: 0; list-style: none;
}
/* The whole tile is a link to its card, so it has to READ as one: a crisp white chip with a
   resting shadow (raised = clickable), not a flat wash box. Hover lifts it further and deepens the
   shadow — a clear "this does something" rather than the old 1px nudge. */
#lh-health .lh-alert {
  display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: start;
  padding: 10px 12px 11px; border-radius: 12px;
  border: 1px solid var(--lh-line); background: var(--lh-card);
  box-shadow: 0 1px 2px rgba(16, 33, 31, .05), 0 3px 9px rgba(16, 33, 31, .05);
  text-decoration: none; color: inherit;
  transition: border-color .14s, transform .14s, box-shadow .14s;
}
#lh-health a.lh-alert:hover, #lh-health label.lh-alert:hover {
  transform: translateY(-2px); border-color: var(--lh-border);
  box-shadow: 0 6px 18px rgba(16, 33, 31, .11);
}
@media (prefers-reduced-motion: reduce) {
  #lh-health a.lh-alert:hover, #lh-health label.lh-alert:hover { transform: none; }
}
#lh-health .lh-alert-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; background: var(--lh-ink3); }
#lh-health .lh-alert-body { min-width: 0; }
/* Direct child only: the reason line's emphasised numbers are <b> too, and a blanket rule here
   turned every one of them into its own line. */
#lh-health .lh-alert-body > b { display: block; font-size: 13px; font-weight: 700; color: var(--lh-ink); }
/* Exactly two lines, always: `min-height` pads a one-line reason out and the clamp caps a long
   one, so every tile is the same height no matter which row it lands in. Sized in `lh` rather
   than a px guess, so it tracks this rule's own font-size and line-height. A clamped reason is
   never the last word on it — the tile links to the card, where the row says it in full. */
#lh-health .lh-alert-body > span {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  font-size: 12.5px; line-height: 1.35; min-height: 2lh; color: var(--lh-ink2); margin-top: 1px;
}
/* The numbers are the whole point of the line; in a uniform sentence they are the hardest part
   to find. Mono here is already in the page's inventory (eyebrows, meta, pills). */
#lh-health .lh-num { display: inline; font-family: var(--lh-mono); font-size: 12px; font-weight: 700; }
/* `amber` is the SEVERITY key from Python (card status "amber"), not the paint. In the brand-ramp
   section the attention tiles inherit the crisp white chip and carry a small gradient dot — the
   ramp on the band's rail + headline dot is the section's identity; the tiles don't compete with it.
   Numbers pick out on weight + solid ink (a gradient at 12px would be muddy and fail AA). */
/* The dot is the referred card's identity hue (via lh-hue-* on the tile → --lh-c), so the chip
   colour-matches the card it points to in the grid below. */
#lh-health .lh-alert-amber .lh-alert-dot { background: var(--lh-c); }
#lh-health .lh-alert-amber .lh-num { color: var(--lh-ink); }
#lh-health .lh-alert-red {
  border-color: color-mix(in srgb, var(--lh-red-f) 28%, transparent);
  background: color-mix(in srgb, var(--lh-red-f) 5.5%, var(--lh-card));
}
#lh-health .lh-alert-red .lh-alert-dot { background: var(--lh-red-f); }
#lh-health .lh-alert-red .lh-num { color: var(--lh-red-d); }
#lh-health .lh-alert-more {
  grid-template-columns: 1fr; align-items: center; justify-items: center;
  font-size: 12.5px; font-weight: 700; color: var(--lh-ink2); cursor: pointer;
}
/* The overflow tiles ride in the same grid; hidden until the toggle is checked, so the band stays
   compact by default but every flagged card is one click away — no leaving the page. */
#lh-health .lh-alert-extra { display: none; }
#lh-health .lh-more-toggle:checked ~ .lh-alerts .lh-alert-extra { display: block; }
/* One-way: once expanded the toggle has done its job, so it removes itself and the grid shows only
   real alerts. Re-collapsing is a page refresh (the band re-renders on the poll anyway). */
#lh-health .lh-more-toggle:checked ~ .lh-alerts .lh-more-cell { display: none; }

/* ============================================================================================
   Sections + grid
   ============================================================================================ */
#lh-health .lh-section { margin-bottom: 2rem; }
/* Quieter than the card titles beneath them — a section head is furniture, not content. */
#lh-health .lh-sech {
  font-family: var(--lh-mono); font-size: 10.5px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--lh-ink2); font-weight: 700; margin: 0 0 12px;
  display: flex; align-items: center; gap: 14px;
}
#lh-health .lh-sech::after { content: ""; flex: 1; height: 1px; background: var(--lh-line2); }
/* auto-fit rather than fixed breakpoints: there is no Tailwind build to extend here, and it
   degrades 3 → 2 → 1 without leaving an orphan column. 360px so three-up only happens when
   there is genuinely room for three. */
#lh-health .lh-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 16px; }
/* Every card in a row matches the tallest one — a ragged bottom edge reads as breakage rather
   than as content of different lengths. Cards push their footer down with `margin-top:auto`, so
   the CTAs land on a common baseline; the short card in a row (Automated jobs) earns its height
   back by carrying a tail of recent runs. */
#lh-health .lh-grid { align-items: stretch; }

/* ============================================================================================
   Cards
   ============================================================================================ */
/* The rail is the card's identity, and it is the ONLY thing painted on the left edge. An earlier
   pass also tinted the border by status; on an amber card that put a 1px amber line immediately
   outside a 3px teal rail, which reads as one muddy two-tone stripe — and with a 22px radius the
   two colours blend diagonally through the corner as well. Status therefore never touches the
   border: it speaks through the corner pill, the offending row, and (red only) a faint surface
   wash. Three channels, none of them the rail. */
#lh-health .lh-card {
  --lh-c: var(--lh-teal); --lh-cd: var(--lh-teal-d);
  display: flex; flex-direction: column;
  border: 1px solid var(--lh-border); border-left: 3px solid var(--lh-c);
  border-radius: var(--lh-r-card); background: var(--lh-card); box-shadow: var(--lh-sh);
  padding: 0 0 4px;
  /* deliberately NO overflow:hidden — a card must never clip its own ? popover */
}
#lh-health .lh-hue-teal { --lh-c: var(--lh-teal); --lh-cd: var(--lh-teal-d); }
#lh-health .lh-hue-azure { --lh-c: var(--lh-azure); --lh-cd: var(--lh-azure-d); }
#lh-health .lh-hue-violet { --lh-c: var(--lh-violet); --lh-cd: var(--lh-violet-d); }
#lh-health .lh-hue-pink { --lh-c: var(--lh-pink); --lh-cd: var(--lh-pink-d); }

/* The card owns no horizontal padding; each band does. That is what lets a divider run edge to
   edge instead of stopping 18px short at both ends, which is the difference between a long card
   reading as zones and reading as one 900px column. */
#lh-health .lh-card > .lh-card-head,
#lh-health .lh-card > .lh-headline,
#lh-health .lh-card > .lh-verdict-sub,
#lh-health .lh-card > .lh-stackwrap,
#lh-health .lh-card > .lh-why,
#lh-health .lh-card > .lh-caption,
#lh-health .lh-card > .lh-block,
#lh-health .lh-card > .lh-empty,
#lh-health .lh-card > .lh-foot { padding-inline: var(--lh-pad); }

#lh-health .lh-card:focus-visible { outline: 2px solid var(--lh-pink); outline-offset: 2px; }
/* Border only, no lift. The card is not a link — the CTA inside it is — and a whole-card lift on
   hover promises a click target that isn't there. */
#lh-health .lh-card-queue { transition: border-color .14s; }
#lh-health .lh-card-queue:hover { border-color: color-mix(in srgb, var(--lh-c) 45%, var(--lh-border)); }
#lh-health .lh-card:target, #lh-health .lh-card:focus {
  outline: none;
  box-shadow: 0 0 0 2px var(--lh-pink),
              0 0 0 6px color-mix(in srgb, var(--lh-pink) 20%, transparent), var(--lh-sh);
}
/* Amber is pill-only: at any moment several cards are legitimately amber (an optional lane
   degraded, a queue ageing), and washing them all turns the board into a warning field where the
   one red card stops standing out. */
/* `--lh-card` is re-pointed at the washed surface, not just painted: half a dozen rules build a
   colour "on the card" from it — the timeline dot's halo, the run strip's desaturated green, the
   CTA fill. Left at the plain card colour they drew a white ring on a pink card. */
#lh-health .lh-card-red {
  --lh-card: color-mix(in srgb, var(--lh-red-f) 6%, var(--lh-card-base));
  background: var(--lh-card);
}
.dark #lh-health .lh-card-red { --lh-card: color-mix(in srgb, var(--lh-red-f) 14%, var(--lh-card-base)); }
#lh-health .lh-card-unavailable { background: var(--lh-wash); }
/* A card that is only interesting when it's bad (the worker queue): same anatomy, quieter number. */
#lh-health .lh-card-compact .lh-verdict { font-size: 20px; letter-spacing: -.4px; }

#lh-health .lh-card-head { display: flex; align-items: center; gap: 9px; padding-top: 15px; }
#lh-health .lh-card-ic {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px;
  background: color-mix(in oklab, var(--lh-c) 16%, transparent); color: var(--lh-cd);
}
#lh-health .lh-card-ic .material-symbols-outlined { font-size: 13px; }
#lh-health .lh-card-title {
  font-size: 13.5px; font-weight: 700; letter-spacing: -.1px; color: var(--lh-ink); margin: 0;
}
#lh-health .lh-pill {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--lh-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .9px;
  text-transform: uppercase; border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
#lh-health .lh-pill-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
#lh-health .lh-pill-red {
  color: var(--lh-red-d); background: color-mix(in srgb, var(--lh-red-f) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--lh-red-f) 28%, transparent);
}
#lh-health .lh-pill-unknown { color: var(--lh-ink2); background: color-mix(in srgb, var(--lh-ink3) 16%, transparent); }

/* The headline, split so the number reads first and its denominator and unit recede. */
#lh-health .lh-headline { display: flex; align-items: center; gap: 14px; margin-top: 8px; }
#lh-health .lh-verdict {
  font-size: 28px; font-weight: 800; letter-spacing: -1.1px; line-height: 1.05;
  color: var(--lh-ink); font-variant-numeric: tabular-nums;
}
#lh-health .lh-card-queue .lh-verdict { font-size: 32px; letter-spacing: -1.3px; }
#lh-health .lh-verdict-qual {
  font-size: 15px; font-weight: 700; letter-spacing: -.2px; color: var(--lh-ink3); margin-left: 5px;
}
#lh-health .lh-headline .lh-dots, #lh-health .lh-headline .lh-ring { margin-left: auto; }
/* The headline ratio in a second channel, top-right of the card. conic-gradient over a masked
   disc: one element, no SVG, and the sweep IS the datum. The number sits inside it, so the ring
   never has to be read by colour alone. */
#lh-health .lh-ring { flex: none; position: relative; width: 52px; height: 52px; display: grid; place-items: center; }
/* The sweep goes on ::before, not on the box: the mask that punches the hole would take the
   number out with it. */
#lh-health .lh-ring::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  /* The `-d` shade, not the fill. SC 1.4.11 wants 3:1 for a graphical object that carries
     information, and the plain hue was 2.32:1 on a 1.21:1 track — a badge, not a gauge. Using
     `-d` also means the existing AA test over the `-d` tokens (4.5:1, stricter than 3:1) already
     guards this, rather than the ring needing a contrast test of its own. */
  background: conic-gradient(var(--lh-cd) var(--lh-p), color-mix(in srgb, var(--lh-ink3) 30%, transparent) 0);
  -webkit-mask: radial-gradient(circle, transparent 18px, #000 18.5px);
  mask: radial-gradient(circle, transparent 18px, #000 18.5px);
}
#lh-health .lh-ring-v {
  font-size: 11px; font-weight: 800; letter-spacing: -.4px;
  color: var(--lh-cd); font-variant-numeric: tabular-nums;
}
#lh-health .lh-verdict-sub {
  font-family: var(--lh-mono); font-size: 11px; letter-spacing: .3px;
  color: var(--lh-cd); margin-top: 6px;
}
#lh-health .lh-why { font-size: 12.5px; font-weight: 700; line-height: 1.4; margin: 7px 0 0; }
#lh-health .lh-caption { font-size: 12.5px; line-height: 1.45; color: var(--lh-ink2); margin: 7px 0 0; }

/* ============================================================================================
   Blocks + rows
   ============================================================================================ */
#lh-health .lh-block { padding-top: 4px; padding-bottom: 4px; }
#lh-health .lh-block-titled { border-top: 1px solid var(--lh-line2); padding-top: 12px; }
#lh-health .lh-card-head + .lh-block,
#lh-health .lh-headline + .lh-block,
#lh-health .lh-caption + .lh-block,
#lh-health .lh-why + .lh-block,
#lh-health .lh-stackwrap + .lh-block { border-top: 1px solid var(--lh-line2); margin-top: 13px; }
/* The last band takes the slack, so cards in a row can match heights without their footers
   floating away from the content. */
#lh-health .lh-card > .lh-block:last-of-type { flex: 1; }
#lh-health .lh-blockhead {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 2px;
}
#lh-health .lh-blockhead-label {
  font-family: var(--lh-mono); font-size: 9.5px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--lh-ink3);
}
#lh-health .lh-blockhead-val { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }

#lh-health .lh-rows { list-style: none; margin: 0; padding: 0; }
/* A hairline per row. Seven rows floating on gaps alone read as one undifferentiated block. */
#lh-health .lh-rows > li {
  display: flex; align-items: center; gap: 12px; font-size: 12.5px;
  padding: 7px 0; border-bottom: 1px solid var(--lh-line2);
}
#lh-health .lh-rows > li:last-child { border-bottom: none; }
/* `> li` is (1,1,1); this has to match it, or `align-items: center` and `gap: 12px` survive and
   the strip floats 12px below its own label line. Same trap as `.lh-statrow` and `.lh-tick`. */
#lh-health .lh-rows > li.lh-wide { flex-direction: column; align-items: stretch; gap: 0; }
#lh-health .lh-wide .lh-row { display: flex; align-items: center; gap: 12px; width: 100%; }
/* `> li` above is (1,1,1); these need to match it or the tiles stay flex items and collapse to
   their content width, stacking one per line. */
#lh-health .lh-rows > li.lh-statrow, #lh-health .lh-rows > li.lh-legendrow { display: block; }
/* Labels in ink. They were grey on the theory that the value is the news — true for the ONE row
   you are chasing, and wrong for the other eleven, which you read as a list of what this card
   measures. Grey labels made that list a haze you had to lean into. Hierarchy is carried by
   weight and by the tabular figures instead: label 600, value 700. */
#lh-health .lh-label {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 7px;
  color: var(--lh-ink); font-weight: 600;
}
/* `muted` is a statement about the VALUE (nothing to chase here), not about what the row is. */
#lh-health .lh-label.lh-muted { color: var(--lh-ink); }
#lh-health .lh-label .material-symbols-outlined { font-size: 15px; flex: none; }
#lh-health .lh-label .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#lh-health .lh-meter { flex: none; }
#lh-health .lh-meter:empty { display: none; }
#lh-health .lh-val {
  flex: none; min-width: 4.5rem; text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.2px;
  color: var(--lh-ink); white-space: nowrap;
}
/* `muted` means "nothing to chase in this row", which is a statement about severity, not about
   legibility — the number still has to be readable. Overrides the generic `.lh-muted` grey. */
#lh-health .lh-val.lh-muted { color: var(--lh-ink); font-weight: 700; }
/* A tinted chip behind an off-nominal number, on inline rows only.
   Two problems, one fix. (a) With every label now in ink, an amber value at #8a5410 was LIGHTER
   than the neutral rows around it — the alarm read as the quietest thing on the card. (b) The
   status glyphs came off the left of the labels, which left ~11 rows carrying severity in hue
   alone. The chip restores the weight and puts the shape channel back, without an icon column.
   Block rows are excluded: their value is a sentence that already says "failed" / "partial", and
   the run strip beneath it is a second channel again. */
#lh-health .lh-rows > li:not(.lh-wide) .lh-val.lh-amber,
#lh-health .lh-rows > li:not(.lh-wide) .lh-val.lh-red {
  padding: 2px 7px; margin-right: -7px; border-radius: 7px;
}
#lh-health .lh-rows > li:not(.lh-wide) .lh-val.lh-amber { background: color-mix(in srgb, var(--lh-amber-f) 13%, transparent); }
#lh-health .lh-rows > li:not(.lh-wide) .lh-val.lh-red { background: color-mix(in srgb, var(--lh-red-f) 11%, transparent); }
/* A bar that IS the row's answer, hard against the right edge — the meter gutter sits mid-row and
   would read as decoration hung off the label rather than the shape of the number beside it. */
#lh-health .lh-trail { flex: none; width: 76px; }
#lh-health .lh-trail .lh-stackwrap { margin-top: 0; }
/* A lane's value is a status sentence, not a measurement — "success · 10m ago · 0 new" twelve
   times in bold ink is the heaviest thing on the page and none of it is news. Only the block
   rows (run lanes, the intake trend) carry sentences; every inline row's value is a number, and
   those keep the emphasis. */
#lh-health .lh-wide .lh-val { font-weight: 600; color: var(--lh-ink2); }
/* These MUST restate `color`. The rule above is (1,2,0) and beats the generic `.lh-amber`/`.lh-red`
   at (1,1,0) — so for a while every degraded lane on News ingestion and Public records, the page's
   primary alarm text, computed a severity class and then rendered in neutral grey. */
#lh-health .lh-wide .lh-val.lh-amber { font-weight: 700; color: var(--lh-amber-d); }
#lh-health .lh-wide .lh-val.lh-red { font-weight: 700; color: var(--lh-red-d); }
#lh-health .lh-wide .lh-val.lh-info { font-weight: 700; color: var(--lh-azure-d); }
#lh-health .lh-val-sub { color: var(--lh-ink3); font-weight: 600; margin-left: 4px; }
#lh-health .lh-new { color: var(--lh-pink-d); font-weight: 700; }
#lh-health .lh-ctrl { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: 12px; min-width: 5.5rem; }
#lh-health .lh-ctrl .lh-alink { min-height: 28px; display: inline-flex; align-items: center; padding: 0 6px; margin: 0 -6px; }
#lh-health .lh-ctrl form { display: inline; }
#lh-health .lh-vlink { color: inherit; text-decoration: underline; text-decoration-color: var(--lh-line); text-underline-offset: 2px; }
#lh-health .lh-vlink:hover { color: var(--lh-cd); text-decoration-color: currentColor; }
#lh-health .lh-bang {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; flex: none; border-radius: 50%;
  border: 1.5px solid currentColor; font-weight: 800; font-size: 10px; line-height: 1;
}

/* The job-log tail. A rail with a dot per run says "this is a log" at a glance, so the entries
   aren't read as measurements; older ones fade, and a failure keeps its red. */
#lh-health .lh-rows:has(> .lh-tick) { position: relative; padding-left: 15px; margin-top: 4px; }
#lh-health .lh-rows:has(> .lh-tick)::before {
  content: ""; position: absolute; left: 3px; top: 10px; bottom: 10px; width: 1.5px;
  background: linear-gradient(180deg, var(--lh-c), color-mix(in srgb, var(--lh-c) 12%, transparent));
}
/* `> li` is (1,1,1) — this has to match it or the tail keeps the per-row hairlines that make a
   log look like a table of measurements. */
#lh-health .lh-rows > li.lh-tick { position: relative; border-bottom: none; padding: 9px 0; }
#lh-health .lh-tick::before {
  content: ""; position: absolute; left: -15px; top: 16px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--lh-c); box-shadow: 0 0 0 3px var(--lh-card);
}
#lh-health .lh-tick-faded::before { background: color-mix(in srgb, var(--lh-c) 40%, transparent); }
/* A failure reads as a RING, not just a red fill: at 7px a hue swap alone is the whole signal, and
   this is the one row on the card you must not miss on a screen that renders colour badly. The ring
   is a second, non-colour channel — bigger, hollow, sitting proud of the rail. */
#lh-health .lh-tick-bad::before {
  left: -17px; top: 14px; width: 11px; height: 11px;
  background: var(--lh-card); border: 2.5px solid var(--lh-red-f);
}

/* The tail FILLS the height the grid gives this card (it is stretched to two much longer
   neighbours — 718px of it sat empty) and scrolls inside that space, so the number of rows follows
   the layout instead of a constant that is wrong at every other viewport. */
#lh-health .lh-block-titled:has(.lh-tick) {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 170px;
}
/* `flex-basis: 0` + `min-height: 0` is the whole trick: the list then contributes NOTHING to the
   card's intrinsic height, so the grid row is still sized by this card's two long neighbours and
   the tail takes the leftover. With `basis: auto` the 40 rows sized the row themselves and the
   short card became the tallest one on the page — the opposite of the fix. */
/* `overflow: hidden`, never `auto`. A scrollbar here would be the wrong answer twice: the tail is a
   glance, not something to page through, and setting overflow on ONE axis computes the other to
   `auto` — which is where the horizontal scrollbar came from. The row COUNT is trimmed to what fits
   (see fitLogTails in admin/index.html); hidden is only the backstop for the moment before it runs. */
#lh-health .lh-rows:has(> .lh-tick) { flex: 1 1 0; min-height: 0; overflow: hidden; }

/* Whole-line hit area. Stretched over the row rather than wrapping the label, so the timestamp on
   the right is clickable too and the row keeps its grid. */
#lh-health .lh-tick-link { border-radius: 7px; }
/* inset: 0, not a negative horizontal bleed — the bleed made every row wider than its container. */
#lh-health .lh-tick-hit { position: absolute; inset: 0; z-index: 1; border-radius: 7px; }
#lh-health .lh-tick-link:hover { background: color-mix(in srgb, var(--lh-c) 7%, transparent); }
#lh-health .lh-tick-hit:focus-visible { outline: 2px solid var(--lh-azure-d); outline-offset: 1px; }

/* ============================================================================================
   Text + fill colours
   ============================================================================================ */
#lh-health .lh-ok { color: var(--lh-green-d); }
#lh-health .lh-info { color: var(--lh-azure-d); }
#lh-health .lh-amber { color: var(--lh-amber-d); }
#lh-health .lh-red { color: var(--lh-red-d); }
#lh-health .lh-muted { color: var(--lh-ink2); }
#lh-health .lh-bg-ok { background: var(--lh-green-f); }
#lh-health .lh-bg-info { background: var(--lh-azure); }
#lh-health .lh-bg-amber { background: var(--lh-amber-f); }
#lh-health .lh-bg-red { background: var(--lh-red-f); }
#lh-health .lh-bg-c { background: var(--lh-c); }
#lh-health .lh-bg-c-soft { background: color-mix(in srgb, var(--lh-c) 22%, transparent); }
#lh-health .lh-bg-neutral { background: color-mix(in srgb, var(--lh-ink3) 40%, transparent); }
#lh-health .lh-bg-empty { background: color-mix(in srgb, var(--lh-ink3) 13%, transparent); }

/* ============================================================================================
   Meters, dots, stacks, strips, sparks
   ============================================================================================ */
#lh-health .lh-track {
  position: relative; display: inline-block; width: 4.75rem; height: .375rem;
  border-radius: 999px; background: color-mix(in srgb, var(--lh-ink3) 18%, transparent);
  overflow: hidden; vertical-align: middle;
}
#lh-health .lh-fill { display: block; height: 100%; border-radius: 999px; }

#lh-health .lh-dots { display: flex; gap: 3px; align-items: center; flex: none; }
#lh-health .lh-dots i { width: 7px; height: 7px; border-radius: 50%; background: color-mix(in srgb, var(--lh-ink3) 20%, transparent); }
#lh-health .lh-dot-c i.lh-dot-on { background: var(--lh-c); }
#lh-health .lh-dot-ok i.lh-dot-on { background: var(--lh-green-f); }
#lh-health .lh-dot-amber i.lh-dot-on { background: var(--lh-amber-f); }

/* A composition as one bar plus its key — the parts of a total, where the row form made you
   subtract to see the split. */
#lh-health .lh-stackwrap { margin-top: 10px; }
#lh-health .lh-stack {
  display: flex; height: 8px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--lh-ink3) 15%, transparent);
}
#lh-health .lh-stack i { display: block; }
#lh-health .lh-legend {
  display: flex; flex-wrap: wrap; gap: 6px 14px; list-style: none;
  margin: 7px 0 0; padding: 0; font-size: 10.5px; color: var(--lh-ink2);
}
#lh-health .lh-legend li { display: inline-flex; align-items: center; gap: 5px; }
#lh-health .lh-legend i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
/* The swatch has to be the colour the strip actually draws, or the key is a lie — a healthy run
   is desaturated to 45% down there, and a full-strength green chip taught the wrong green. */
#lh-health .lh-legend i.lh-bg-ok { background: color-mix(in srgb, var(--lh-green-f) 45%, var(--lh-card)); }
#lh-health .lh-legendrow .lh-legend { margin-top: 2px; }

/* Fixed-width segments, always _RECENT_RUNS slots. Shape as well as hue: a wall of saturated
   green rectangles was the loudest thing on a page whose job is to surface the two things that
   aren't fine, and red/green alone fails for the ~8% of men with deuteranopia. Failures stand
   full height; healthy runs sit low and desaturated. */
#lh-health .lh-runs { display: flex; align-items: flex-end; gap: 2.5px; height: 8px; margin-top: 7px; width: 100%; }
#lh-health .lh-seg { flex: 1 1 0%; min-width: 3px; border-radius: 2px; height: 50%; }
#lh-health .lh-seg.lh-bg-ok { background: color-mix(in srgb, var(--lh-green-f) 45%, var(--lh-card)); }
#lh-health .lh-seg.lh-bg-red, #lh-health .lh-seg.lh-bg-amber, #lh-health .lh-seg.lh-bg-info { height: 100%; }

/* Taller than the run strips on purpose. This is the one chart on the board whose SHAPE is the
   reading — 44px flattened a fortnight of volume into a texture, and a dip you should notice
   looked like a rounding error. */
#lh-health .lh-spark {
  position: relative; display: flex; align-items: flex-end; gap: 3px;
  height: 5.25rem; width: 100%; margin: 10px 0 6px;
}
#lh-health .lh-sparkbar { flex: 1 1 0%; border-radius: 2px 2px 0 0; min-height: 2px; }
/* Today's bar is a partial day by definition; solid teal on a half-day reads as a crash. */
#lh-health .lh-today { background: var(--lh-teal); opacity: .45; }
#lh-health .lh-peak { background: var(--lh-teal); }
#lh-health .lh-weekend { background: color-mix(in srgb, var(--lh-ink3) 22%, transparent); }
#lh-health .lh-ref {
  position: absolute; left: 0; right: 0; height: 1px; z-index: 1;
  background: color-mix(in srgb, var(--lh-teal) 55%, transparent);
}

/* Reference magnitudes as tiles: glanced at, never worked. */
#lh-health .lh-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 10px;
  margin: 6px 0 4px;
}
/* Right-aligned like every other number on the card. Left-aligned tiles were the one place a
   value didn't sit on the card's right edge, and in a section where the eye runs down that edge
   they read as a different kind of thing that had come loose. */
#lh-health .lh-stat {
  display: block; text-decoration: none; color: inherit; text-align: right;
  background: var(--lh-wash); border: 1px solid var(--lh-line2); border-radius: 10px;
  padding: 8px 10px;
}
#lh-health a.lh-stat:hover { border-color: color-mix(in srgb, var(--lh-c) 45%, var(--lh-border)); }
#lh-health .lh-stat-v {
  font-size: 16px; font-weight: 800; letter-spacing: -.5px; white-space: nowrap;
  font-variant-numeric: tabular-nums; color: var(--lh-ink);
}
#lh-health .lh-stat-l { font-size: 10.5px; color: var(--lh-ink2); margin-top: 1px; line-height: 1.25; }

/* ============================================================================================
   Buttons — the prominence ladder. One tonal CTA per card; Run/Logs recede.
   ============================================================================================ */
#lh-health .lh-foot {
  margin-top: auto; padding-top: 13px; padding-bottom: 9px; border-top: 1px solid var(--lh-line2);
  display: flex; align-items: center; gap: 12px;
}
#lh-health .lh-cta {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px; min-height: 38px; padding: 0 15px;
  border-radius: 12px; font-size: 13px; font-weight: 700; text-decoration: none;
  /* Tonal, never filled: filled teal is reserved for a consequential commit (the consoles' Save).
     A navigation CTA in solid teal would out-shout those. Takes the CARD's hue, so teal stops
     meaning identity and action at the same time on a queue card. */
  color: var(--lh-cd);
  background: color-mix(in srgb, var(--lh-c) 13%, var(--lh-card));
  border: 1px solid color-mix(in srgb, var(--lh-c) 40%, transparent);
  transition: transform .1s, box-shadow .15s, background .15s;
}
#lh-health .lh-cta:hover {
  background: color-mix(in srgb, var(--lh-c) 20%, var(--lh-card));
  transform: translateY(-1px);
  box-shadow: 0 3px 12px color-mix(in srgb, var(--lh-c) 22%, transparent);
}
@media (prefers-reduced-motion: reduce) { #lh-health .lh-cta:hover { transform: none; } }
#lh-health .lh-arrow { font-size: 14px; line-height: 1; }
/* A second destination is a button, not a footnote. Outlined rather than tonal so the ladder is
   still legible at a glance: one filled-ish CTA per card, and this one beside it. */
#lh-health .lh-foot-two { gap: 10px; }
#lh-health .lh-foot-two .lh-cta { flex: 1 1 0%; justify-content: center; padding: 0 12px; margin-left: 0; }
#lh-health .lh-cta-2 {
  color: var(--lh-ink2); background: transparent;
  border-color: color-mix(in srgb, var(--color-base-700) 45%, transparent);
}
#lh-health .lh-cta-2:hover {
  color: var(--lh-cd); background: transparent;
  border-color: color-mix(in srgb, var(--lh-c) 55%, transparent);
  box-shadow: none;
}
#lh-health .lh-alink {
  font-size: 12.5px; font-weight: 600; color: var(--lh-azure-d);
  background: none; border: none; padding: 0; text-decoration: none;
}
#lh-health .lh-alink:hover { color: var(--lh-violet-d); text-decoration: underline; }
#lh-health .lh-btn-run {
  display: inline-flex; align-items: center; min-height: 28px; padding: 0 11px;
  border-radius: 9px; font-size: 12px; font-weight: 700; cursor: pointer;
  color: var(--lh-ink2); background: transparent;
  /* 24% of base-700 is ~1.5:1 — under SC 1.4.11 for a control boundary. */
  border: 1px solid color-mix(in srgb, var(--color-base-700) 45%, transparent);
}
#lh-health .lh-btn-run:hover { color: var(--lh-cd); border-color: var(--lh-cd); }
#lh-health .lh-pill-run {
  display: inline-flex; align-items: center; min-height: 26px; padding: 0 10px;
  border-radius: 9px; font-size: 12px; font-weight: 700;
  color: var(--lh-azure-d); background: color-mix(in srgb, var(--lh-azure) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--lh-azure) 35%, transparent);
}

/* ============================================================================================
   Empty state + tooltip
   ============================================================================================ */
#lh-health .lh-empty { text-align: center; padding-top: 26px; padding-bottom: 20px; }
#lh-health .lh-empty-big { font-size: 15px; font-weight: 700; color: var(--lh-ink2); margin-bottom: 6px; }

#lh-health .lh-tip {
  position: relative; text-decoration: underline dotted; text-decoration-thickness: 1px;
  text-underline-offset: 2px; cursor: help; outline: none;
}
#lh-health .lh-pop {
  position: absolute; top: calc(100% + 8px); right: 0; width: 240px; z-index: 65;
  background: var(--lh-card); color: var(--lh-ink2); border: 1px solid var(--lh-border);
  border-radius: 12px; box-shadow: 0 2px 6px rgba(16, 33, 31, .08), 0 12px 28px rgba(16, 33, 31, .16);
  padding: 10px 12px; font-size: 12.5px; font-weight: 400; font-variant-numeric: normal;
  line-height: 1.55; white-space: normal; text-align: left;
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .12s, transform .12s; pointer-events: none;
}
#lh-health .lh-tip:hover .lh-pop, #lh-health .lh-tip:focus-within .lh-pop {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.dark #lh-health .lh-pop { box-shadow: 0 2px 6px rgba(0, 0, 0, .4), 0 14px 30px rgba(0, 0, 0, .5); }

@media (max-width: 520px) {
  /* Let the run strip take its own line rather than crushing 12 segments into a few pixels. */
  #lh-health .lh-wide .lh-row { flex-wrap: wrap; }
  #lh-health .lh-ctrl { min-width: 0; }
}
