.page-header {
  margin-bottom: 2rem;
}

.page-eyebrow {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.5rem;
}

.page-header h1 {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 0.35rem;
  background: linear-gradient(135deg, var(--text) 0%, var(--text) 55%, var(--accent) 130%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.page-header p {
  color: var(--text-muted);
  margin: 0;
  font-size: 0.95rem;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1.1rem;
  margin-bottom: 2rem;
}

.stat-grid--compact {
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

.card {
  /* No backdrop-filter here: with several .card regions on one page each
     loading independently over htmx, every fragment swap forced the browser
     to recomposite the blur/saturate sampling for every other .card and the
     blurred sidebar/topbar behind them, which is what showed up as the whole
     page glitching on each swap rather than just the swapped region. isolation
     keeps the stacking context the tooltip z-index rule below depends on,
     without the repaint cost. */
  isolation: isolate;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
  border-radius: 16px;
  padding: 1.35rem;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 16%, transparent),
    0 0 18px color-mix(in srgb, var(--accent) 14%, transparent),
    inset 0 1px 0 color-mix(in srgb, #fff 20%, transparent),
    var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.card--section {
  margin-bottom: 2rem;
}

.stat-tile {
  position: relative;
}

/* .card's backdrop-filter creates a stacking context per card, so a tooltip's
   z-index only wins against siblings inside its own card — a later card in
   the grid still paints its own backdrop over it. Raising the whole card
   above its siblings while the tooltip is open fixes that for every
   .info-icon on a .card, not just stat tiles. */
.card:has(.info-icon:hover),
.card:has(.info-icon:focus-visible) {
  z-index: 30;
}

.stat-tile--compact {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.75rem 0.9rem;
  /* The dashboard's headline tiles have fixed, known contents: a 26px icon
     chip, one line of label, one line of value. Locking the height here means
     the row above the fold reserves its exact final size on first paint, so
     the htmx swap that fills in the counts cannot reflow anything below it.
     Derived from the parts: 1.5rem padding (0.75 x2) + label line (0.72 x 1.25
     = 0.9) + 0.15 label-row margin + value line (1.3 x 1.2 = 1.56) = 4.11rem.
     The 26px icon chip is shorter than that text column, so the text sets the
     height. Keep this in step with the three values above if any of them
     change. */
  min-height: 4.11rem;
  box-sizing: border-box;
}

.stat-tile--compact .stat-tile__icon {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  margin-bottom: 0;
  /* Fixed both ways: `align-items: center` on the tile would otherwise let the
     chip stretch to the text column, changing the tile's height with it. */
  flex: 0 0 26px;
}

.stat-tile--compact .stat-tile__text {
  min-width: 0;
}

.stat-tile--compact .stat-tile__label {
  font-size: 0.72rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stat-tile__label-row {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  min-width: 0;
}

/* One spacing rule for both label shapes. Tile 1 wraps its label in a
   .stat-tile__label-row (label + info icon) while tiles 2-4 use a bare
   .stat-tile__label; these previously carried different bottom margins, which
   made tile 1 shorter than its siblings and left the row height decided by
   whichever tile was tallest. */
.stat-tile--compact .stat-tile__label-row,
.stat-tile--compact .stat-tile__label {
  margin-bottom: 0.15rem;
}

.stat-tile--compact .stat-tile__label-row .stat-tile__label {
  margin-bottom: 0;
}

.stat-tile__label-row .info-icon {
  flex-shrink: 0;
}

.stat-tile--compact .stat-tile__value {
  font-size: 1.3rem;
  /* Pinned, not left to `line-height: normal`. These tiles render twice — once
     with an em-dash placeholder, then with the real count swapped over it —
     and `normal` resolves from the glyphs actually present, so a dash and a
     digit produce line boxes of slightly different heights. That difference
     was enough to grow the tile row and push the whole page down at swap time.
     A fixed line-height makes the box depend on the font size alone, so the
     row is the same height whatever is inside it. */
  line-height: 1.2;
  min-height: 1.56rem; /* 1.3rem x 1.2 — holds the row even if the value is empty. */
}

.stat-tile--compact .stat-tile__label {
  /* Same reasoning as the value above: the label is one line by construction
     (nowrap + ellipsis), so pin its box rather than letting descenders in one
     state and not another change it. */
  line-height: 1.25;
}

.stat-tile:hover {
  transform: translateY(-2px);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 28%, transparent),
    0 0 28px color-mix(in srgb, var(--accent) 22%, transparent),
    inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent),
    var(--shadow-md);
}

.stat-tile--accent { --tile-color: var(--accent); }
.stat-tile--good { --tile-color: var(--good); }
.stat-tile--warn { --tile-color: var(--warn); }
.stat-tile--bad { --tile-color: var(--bad); }

@keyframes stat-tile-flash {
  0%, 100% {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--tile-color) 20%, transparent), var(--shadow-sm);
  }
  50% {
    box-shadow: 0 0 0 1px var(--tile-color), 0 0 18px color-mix(in srgb, var(--tile-color) 45%, transparent), var(--shadow-sm);
  }
}

.stat-tile--flash {
  animation: stat-tile-flash 1.6s ease-in-out infinite;
}

.stat-tile--flash-strong {
  animation-duration: 1s;
}

.stat-tile--flash-urgent {
  animation-duration: 0.5s;
}

.stat-tile--loading:not(.stat-tile--flash) {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent),
    0 0 20px color-mix(in srgb, var(--accent) 18%, transparent),
    var(--shadow-sm);
}

.stat-tile--loading:not(.stat-tile--flash)::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent),
    0 0 44px color-mix(in srgb, var(--accent) 42%, transparent);
  animation: stat-tile-breathe 4.2s ease-in-out infinite;
}

.stat-tile--loading.stat-tile--loading-tinted:not(.stat-tile--flash) {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--tile-color, var(--accent)) 22%, transparent),
    0 0 20px color-mix(in srgb, var(--tile-color, var(--accent)) 18%, transparent),
    var(--shadow-sm);
}

.stat-tile--loading.stat-tile--loading-tinted:not(.stat-tile--flash)::before {
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--tile-color, var(--accent)) 55%, transparent),
    0 0 44px color-mix(in srgb, var(--tile-color, var(--accent)) 42%, transparent);
}

.stat-tile--loading.stat-tile--flash-strong:not(.stat-tile--flash)::before {
  animation-duration: 2.6s;
}

.stat-tile--loading.stat-tile--flash-urgent:not(.stat-tile--flash)::before {
  animation-duration: 1.6s;
}

@keyframes stat-tile-breathe {
  0%, 100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

.stat-tile__icon {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--tile-color, var(--accent));
  background: color-mix(in srgb, var(--tile-color, var(--accent)) 14%, transparent);
  margin-bottom: 0.9rem;
}

.stat-tile__label {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 0.35rem;
}

.stat-tile__value {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* A tile whose value is a pill rather than a numeral: drop the display font
   size so the pill isn't sitting in an oversized line box, but keep the tile
   the same height as its numeric siblings so the stat row stays aligned. */
.stat-tile__value--pill {
  display: flex;
  align-items: center;
  min-height: 2.4rem;
  font-size: 1rem;
}

.status-list {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.status-row {
  padding: 0.9rem 0.25rem;
  border-bottom: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
}

.status-row:last-child {
  border-bottom: none;
}

.status-row__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.status-row__info {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.status-dot {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.status-dot--good {
  background: var(--good);
  box-shadow: 0 0 8px color-mix(in srgb, var(--good) 60%, transparent);
}

.status-dot--bad {
  background: var(--bad);
  box-shadow: 0 0 8px color-mix(in srgb, var(--bad) 60%, transparent);
}

.status-dot--off {
  background: var(--text-muted);
}

.status-row__name {
  font-weight: 600;
  font-size: 0.92rem;
}

.status-row__meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.status-row__result {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.status-row__state {
  font-size: 0.8rem;
  font-weight: 700;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
}

.status-row__state--good {
  color: var(--good);
  background: var(--good-soft);
}

.status-row__state--bad {
  color: var(--bad);
  background: var(--bad-soft);
}

.status-row__state--off {
  color: var(--text-muted);
  background: color-mix(in srgb, var(--text) 8%, transparent);
}

.status-row__latency {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.status-row__error {
  margin-top: 0.5rem;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: var(--bad-soft);
  color: var(--bad);
  font-size: 0.8rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  overflow-wrap: break-word;
}

.notice-card {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  background: var(--accent-soft);
  border-color: transparent;
  box-shadow: none;
}

.notice-card__icon {
  color: var(--accent);
  flex-shrink: 0;
  margin-top: 0.1rem;
}

.notice-card p {
  color: var(--text);
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
}
