/* Versyi Status — shares versyi.com's design tokens exactly (palette, fonts,
   glass-card pattern) rather than approximating them, so this reads as the
   same product, not a lookalike. */

:root {
  --grey1: #252525;
  --grey2: #515b6f;
  --grey3: #858c9a;
  --grey4: #afbecc;
  --grey5: #dadada;
  --bg: #141414;
  --accent1: oklch(78% 0.15 85);   /* warm — reused for "degraded" */
  --accent2: oklch(75% 0.13 205);  /* cool */
  --up: oklch(75% 0.14 150);
  --degraded: var(--accent1);
  --down: oklch(65% 0.18 25);
  --unknown: rgba(133, 140, 154, 0.14);
  --maintenance: var(--accent2);
}

* { box-sizing: border-box; }

/* No scrollbar-gutter here: it was reserving 15px on the right even though
   the page fits without scrolling, which pulled the dashed divider short of
   the edge and shifted the centered column off true center. versyi.com has
   no such gutter, so leaving it in made the two pages fail to line up. */
html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--grey5);
  font-family: 'Space Grotesk', sans-serif;
  -webkit-font-smoothing: antialiased;
}

.v-glass {
  background: rgba(20, 20, 20, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(133, 140, 154, 0.25);
}

/* ---------- fixed top-left cluster: logo (links back to versyi.com),
   "STATUS" label beside it, overall-status pill underneath. Logo markup and
   styling matches versyi.com's topbar exactly, including its 8x8 pixel
   pattern from buildLogoGrid() (hardcoded here since this page carries none
   of that runtime) — only the click behavior differs, since a scroll-to-top
   button doesn't make sense on a page that isn't the main site. ---------- */
.v-topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  /* Opaque, so content passes underneath rather than showing through the bar
     and crossing the dashed rule on the way past. */
  background: var(--bg);
  padding: 8px 24px 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
/* The same dashed rule versyi.com hangs under its nav, in the same place as
   well as the same style: there the nav is 56px tall with the rule at its
   bottom edge, so the line occupies y 54-56 with the logo pill sitting at
   y 8-48 above it. This topbar reproduces that box (8 + 40 + 8 = 56) rather
   than approximating the gap, so the two pages line up when you switch
   between them. The phone override at the bottom of this file keeps that
   relationship on touch devices, where versyi.com drops the whole cluster
   below the safe-area inset. */
.v-topbar::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: repeating-linear-gradient(
    to right,
    rgba(133, 140, 154, 0.4) 0px,
    rgba(133, 140, 154, 0.4) 20px,
    transparent 20px,
    transparent 32px
  );
}
.v-topbar-row { display: flex; align-items: center; gap: 8px; }

.v-topbar-logo {
  height: 40px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 0 12px;
  border-radius: 9px;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.v-topbar-logo:hover { background: rgba(133, 140, 154, 0.28); border-color: rgba(133, 140, 154, 0.6); transform: translateY(-2px); }
.v-topbar-logo:active { background: rgba(133, 140, 154, 0.35); transform: translateY(0) scale(0.96); }

.v-logo-grid { display: flex; flex-direction: column; }
.v-logo-row { display: flex; }
.v-logo-row span { width: 3px; height: 3px; flex: none; background: transparent; }
.v-logo-row span.v-logo-on { background: var(--grey5); }
.v-logo-row span.v-logo-accent { background: var(--accent1); }
.v-logo-word {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.5px;
  color: var(--grey5);
}

.v-topbar-status-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1.5px;
  color: var(--grey3);
  margin: 0;
}
/* On /history this is a breadcrumb: STATUS links home, HISTORY is where you
   are. The current page is not a link, so it does not invite a click that
   would reload the page you are already on. */
.v-crumb-link {
  color: var(--grey3);
  text-decoration: none;
  transition: color 0.15s ease;
}
.v-crumb-link:hover { color: var(--grey5); }
.v-crumb-sep { color: var(--grey2); }
.v-crumb-here { color: var(--grey5); }

/* ---------- layout ---------- */
.v-wrap {
  max-width: 760px;
  margin: 0 auto;
  padding: 74px 20px 24px;
  display: flex;
  flex-direction: column;
}

.v-overall {
  /* Sits below the dashed divider as the page's opening line rather than
     inside the fixed nav cluster, so the topbar stays purely identity and
     the answer to "is everything okay" belongs to the content. */
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0 auto 16px;
  padding: 6px 12px;
  border-radius: 7px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.2px;
}
/* inline-flex centers via the wrap being a flow container */
.v-overall { align-self: center; }
/* Full width, so the monitor cards line up with the Daily Report above them. */
.v-categories { align-self: stretch; }
.v-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--grey3);
  flex: none;
  position: relative;
}
.v-dot::after {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: inherit;
  opacity: 0.35;
  animation: v-pulse 2.2s ease-out infinite;
}
[data-state="up"] .v-dot { background: var(--up); }
[data-state="degraded"] .v-dot { background: var(--degraded); }
[data-state="down"] .v-dot { background: var(--down); }
[data-state="maintenance"] .v-dot { background: var(--maintenance); }
[data-state="loading"] .v-dot { background: var(--grey3); }
[data-state="loading"] .v-dot::after { animation-duration: 1s; }

@keyframes v-pulse {
  0% { transform: scale(0.6); opacity: 0.35; }
  100% { transform: scale(2.2); opacity: 0; }
}

/* ---------- categories & cards ---------- */
.v-category { margin-bottom: 12px; }
.v-category-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--grey3);
  margin: 0 0 6px 2px;
  text-transform: uppercase;
}

.v-card {
  border-radius: 10px;
  padding: 8px 12px;
  margin-bottom: 5px;
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.v-card:hover { transform: translateY(-2px); border-color: rgba(133, 140, 154, 0.4); }

.v-card-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 6px;
  flex-wrap: wrap;
}
.v-card-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--grey5);
}
.v-card-label .v-dot { width: 6px; height: 6px; }
.v-card-pct {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  font-weight: 600;
  color: var(--grey4);
  font-variant-numeric: tabular-nums;
}
.v-card-pct .unit { color: var(--grey3); font-weight: 400; font-size: 10px; margin-left: 2px; }

.v-bars {
  display: flex;
  align-items: flex-end;
  /* centred so the leftover pixels from whole-pixel bar widths sit evenly on
     both sides instead of trailing off one edge */
  justify-content: center;
  gap: 1px;
  height: 22px;
  overflow: hidden;
}
/* Width comes from --bar-w, which app.js computes from the measured
   container as an integer number of pixels. flex: 1 would be responsive but
   lands on fractional widths that the browser rounds per-bar, so gaps
   visibly alternate between 1px and 2px; an integer width keeps every gap
   identical while still scaling with the page. */
.v-bar {
  width: var(--bar-w, 3px);
  flex: none;
  height: 100%;
  border-radius: 1px;
  background: var(--unknown);
  opacity: 0;
  transform: scaleY(0.4);
  transform-origin: bottom;
  transition: opacity 0.4s ease, transform 0.4s cubic-bezier(.2,.8,.3,1), background 0.15s ease;
  transition-delay: calc(var(--i) * 1ms);
}
.v-bars.in .v-bar { opacity: 1; transform: scaleY(1); }
/* Days trimmed to keep the remaining bars legible on narrow screens. */
.v-bar.is-trimmed { display: none; }
.v-bar[data-status="up"] { background: var(--up); }
.v-bar[data-status="degraded"] { background: var(--degraded); }
.v-bar[data-status="down"] { background: var(--down); }
.v-bar[data-status="maintenance"] { background: var(--maintenance); }
.v-bar:hover { filter: brightness(1.35); }

/* Custom tooltip — deliberately not the native title attribute, which has a
   ~1s OS-level hover delay before it appears. This shows on the same frame
   as the hover (an 80ms fade is felt as instant, not a delay) and never
   interferes with the bars' own entrance transition, which is untouched. */
.v-tooltip {
  position: fixed;
  pointer-events: none;
  background: rgba(20, 20, 20, 0.95);
  border: 1px solid rgba(133, 140, 154, 0.3);
  border-radius: 6px;
  padding: 6px 10px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey5);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.08s ease, transform 0.08s ease;
  z-index: 1000;
}
.v-tooltip.show { opacity: 1; transform: translateY(0); }

.v-card-range {
  display: flex;
  justify-content: space-between;
  margin-top: 3px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  color: var(--grey2);
  letter-spacing: 0.3px;
}

/* Today's report on the front page. Uses the same badge/title/body pieces as
   the history page's report cards so a note reads identically wherever it
   appears. */
.v-today { align-self: stretch; }
.v-today-card { margin-bottom: 12px; }
.v-today-card .v-report-body { font-size: 12px; margin-top: 6px; }
.v-today-none {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey3);
}
/* bars are clickable now, so say so */
.v-bar { cursor: pointer; }

/* ---------- history link + history page ---------- */
.v-historylink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 7px;
  border: 1px solid rgba(133, 140, 154, 0.22);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.4px;
  color: var(--grey3);
  text-decoration: none;
  transition: color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.v-historylink:hover {
  color: var(--grey5);
  border-color: rgba(133, 140, 154, 0.5);
  transform: translateY(-1px);
}
.v-cal { flex: none; }

.v-backlink {
  align-self: flex-start;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey3);
  text-decoration: none;
  margin-bottom: 14px;
}
.v-backlink:hover { color: var(--grey5); }

.v-history-block { margin-bottom: 22px; }
.v-empty {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey2);
  padding: 8px 2px;
}

.v-report { margin-bottom: 8px; }
.v-report-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.v-report-title { font-size: 13px; font-weight: 600; color: var(--grey5); }
.v-badge {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  color: var(--bg);
  background: var(--grey3);
  flex: none;
}
.v-badge-maintenance { background: var(--accent2); }
.v-badge-incident { background: var(--down); }
.v-report-meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--grey2);
  margin-top: 4px;
}
.v-report-body {
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--grey4);
}
.v-report-affected { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 9px; }
.v-report-affected-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--grey2);
}
.v-chip {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--grey4);
  border: 1px solid rgba(133, 140, 154, 0.25);
  border-radius: 4px;
  padding: 1px 6px;
}

.v-table { width: 100%; border-collapse: collapse; margin-top: 8px; }
.v-table th {
  text-align: left;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--grey2);
  font-weight: 500;
  padding: 0 8px 6px 0;
  border-bottom: 1px solid rgba(133, 140, 154, 0.18);
}
.v-table td {
  padding: 6px 8px 6px 0;
  font-size: 12px;
  color: var(--grey4);
  border-bottom: 1px solid rgba(133, 140, 154, 0.08);
}
.v-table tr:last-child td { border-bottom: none; }
.v-td-date { color: var(--grey5); white-space: nowrap; }
.v-td-status { margin-left: 6px; }
.v-td-num { font-family: 'IBM Plex Mono', monospace; font-variant-numeric: tabular-nums; white-space: nowrap; }
.v-dot-sm { width: 6px; height: 6px; display: inline-block; vertical-align: middle; }
/* the pulse halo is right for one live indicator, not for a column of rows */
.v-dot-sm::after { display: none; }

/* ---------- history: controls, calendar, list ---------- */
.v-wrap-history { max-width: 720px; }

.v-histbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.v-monthnav { display: flex; align-items: center; gap: 6px; }
.v-monthlabel {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.6px;
  color: var(--grey5);
  min-width: 128px;
  text-align: center;
}
.v-navbtn {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  border: 1px solid rgba(133, 140, 154, 0.25);
  background: rgba(20, 20, 20, 0.75);
  color: var(--grey4);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease, opacity 0.15s ease;
}
.v-navbtn:hover:not(:disabled) {
  background: rgba(133, 140, 154, 0.28);
  border-color: rgba(133, 140, 154, 0.6);
  transform: translateY(-1px);
}
.v-navbtn:active:not(:disabled) { transform: translateY(0) scale(0.94); }
.v-navbtn:disabled { opacity: 0.28; cursor: default; }

.v-histtools { display: flex; align-items: center; gap: 8px; }
.v-search {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey4);
  background: rgba(20, 20, 20, 0.75);
  border: 1px solid rgba(133, 140, 154, 0.25);
  border-radius: 7px;
  padding: 5px 8px;
  color-scheme: dark;
  transition: border-color 0.15s ease;
}
.v-search:focus { outline: none; border-color: rgba(133, 140, 154, 0.6); }
/* A date with no record shakes rather than silently doing nothing. */
.v-search.is-miss { animation: v-shake 0.4s ease; border-color: var(--down); }
@keyframes v-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  50% { transform: translateX(4px); }
  80% { transform: translateX(-2px); }
}

.v-viewtoggle {
  display: flex;
  border: 1px solid rgba(133, 140, 154, 0.25);
  border-radius: 7px;
  overflow: hidden;
}
.v-viewbtn {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  letter-spacing: 0.4px;
  padding: 5px 10px;
  border: none;
  background: transparent;
  color: var(--grey3);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.v-viewbtn:hover { color: var(--grey5); }
.v-viewbtn.is-on { background: rgba(133, 140, 154, 0.22); color: var(--grey5); }

.v-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
  margin-bottom: 5px;
}
.v-dow span {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--grey2);
  text-align: center;
}

/* perspective lives on the wrapper so the grid itself can rotate in 3D */
.v-gridwrap { perspective: 1400px; }
.v-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
  transform-origin: center left;
  backface-visibility: hidden;
}
.v-grid.flip-out-fwd { animation: v-page-out-fwd 0.19s ease-in forwards; }
.v-grid.flip-out-back { animation: v-page-out-back 0.19s ease-in forwards; }
.v-grid.flip-in-fwd { animation: v-page-in-fwd 0.32s cubic-bezier(.2,.8,.3,1); }
.v-grid.flip-in-back { animation: v-page-in-back 0.32s cubic-bezier(.2,.8,.3,1); }

@keyframes v-page-out-fwd {
  to { transform: rotateY(-32deg) translateX(-14px); opacity: 0; }
}
@keyframes v-page-in-fwd {
  from { transform: rotateY(32deg) translateX(14px); opacity: 0; }
  to { transform: none; opacity: 1; }
}
@keyframes v-page-out-back {
  to { transform: rotateY(32deg) translateX(14px); opacity: 0; }
}
@keyframes v-page-in-back {
  from { transform: rotateY(-32deg) translateX(-14px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.v-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border-radius: 8px;
  border: 1px solid rgba(133, 140, 154, 0.18);
  background: rgba(20, 20, 20, 0.6);
  color: var(--grey4);
  cursor: pointer;
  font-family: 'Space Grotesk', sans-serif;
  opacity: 0;
  transform: translateY(5px) scale(0.96);
  transition: opacity 0.32s ease, transform 0.32s cubic-bezier(.2,.8,.3,1),
    border-color 0.15s ease, background 0.15s ease;
  /* capped so a long month still assembles quickly */
  transition-delay: calc(min(var(--i) * 9, 220) * 1ms);
}
.v-grid.in .v-cell { opacity: 1; transform: none; }
.v-cell.is-blank { border: none; background: none; cursor: default; }
/* Dimming belongs only to the settled state — setting it here too made
   empty days the one thing on the grid that skipped the entrance, so they
   popped in first while every real day was still fading up. */
.v-cell.is-empty { cursor: default; }
.v-grid.in .v-cell.is-empty { opacity: 0.45; }
.v-cell:not(.is-empty):not(.is-blank):hover {
  border-color: rgba(133, 140, 154, 0.55);
  background: rgba(133, 140, 154, 0.14);
}
.v-cell.is-selected {
  border-color: var(--grey4);
  background: rgba(133, 140, 154, 0.2);
}
.v-cell-num { font-size: 12px; font-weight: 600; color: var(--grey5); }
.v-cell-pct {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 8.5px;
  color: var(--grey3);
}
/* status reads as a bar under the number, same colour language as the strip */
.v-cell[data-status]::after {
  content: '';
  position: absolute;
  left: 22%;
  right: 22%;
  bottom: 5px;
  height: 2px;
  border-radius: 2px;
  background: var(--unknown);
}
.v-cell[data-status="up"]::after { background: var(--up); }
.v-cell[data-status="degraded"]::after { background: var(--degraded); }
.v-cell[data-status="down"]::after { background: var(--down); }
.v-cell[data-status="maintenance"]::after { background: var(--maintenance); }
.v-cell.is-blank::after { display: none; }

/* Day tooltip: wider than the bar tooltip because it carries a row per
   service, so it opts out of the shared nowrap. */
.v-tooltip-day {
  white-space: normal;
  min-width: 190px;
  padding: 8px 10px;
  text-align: left;
}
.v-tip-date {
  font-size: 10.5px;
  color: var(--grey3);
  margin-bottom: 5px;
}
.v-tip-none { font-size: 11px; color: var(--grey2); }
.v-tip-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 1.5px 0;
  font-size: 11px;
}
.v-tip-key {
  width: 6px;
  height: 6px;
  border-radius: 2px;
  flex: none;
  background: var(--unknown);
}
[data-state="up"] .v-tip-key { background: var(--up); }
[data-state="degraded"] .v-tip-key { background: var(--degraded); }
[data-state="down"] .v-tip-key { background: var(--down); }
[data-state="maintenance"] .v-tip-key { background: var(--maintenance); }
.v-tip-name { color: var(--grey4); }
.v-tip-val { margin-left: auto; color: var(--grey5); font-variant-numeric: tabular-nums; }
.v-tip-note {
  margin-top: 6px;
  padding-top: 5px;
  border-top: 1px solid rgba(133, 140, 154, 0.2);
  font-size: 10px;
  color: var(--grey3);
}

/* Click/tap detail: a centred view that grows out of the day that was clicked.
   Previously this floated beside the day and dodged the cursor, which meant you
   could still end up hovering the thing you were trying to read. Centring it
   and putting a backdrop behind removes the problem rather than steering
   around it. */
.v-dayscrim {
  position: fixed;
  inset: 0;
  z-index: 1150;
  background: rgba(10, 10, 10, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
}
.v-dayscrim.open { opacity: 1; pointer-events: auto; }

.v-dayview {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  transform-origin: center;
  z-index: 1200;
  width: min(420px, calc(100vw - 24px));
  max-height: min(76vh, 560px);
  overflow-y: auto;
  border-radius: 12px;
  border: 1px solid rgba(133, 140, 154, 0.32);
  background: rgba(18, 18, 18, 0.98);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.6);
  padding: 14px 16px;
  opacity: 0;
  pointer-events: none;
  /* The curve overshoots a little so the day feels like it springs open. */
  transition: opacity 0.2s ease, transform 0.34s cubic-bezier(.22, 1.2, .36, 1);
}
.v-dayview.open { opacity: 1; pointer-events: auto; }

.v-day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.v-day-title { font-size: 13px; font-weight: 600; color: var(--grey5); }
.v-day-state {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.6px;
  color: var(--grey3);
}
.v-day-state-up { color: var(--up); }
.v-day-state-degraded { color: var(--degraded); }
.v-day-state-down { color: var(--down); }
.v-day-state-maintenance { color: var(--maintenance); }

.v-day-reports-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--grey2);
  margin: 12px 0 6px;
}
.v-day-noreport {
  margin-top: 11px;
  padding-top: 9px;
  border-top: 1px solid rgba(133, 140, 154, 0.15);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey2);
}
.v-day-report {
  padding-top: 9px;
  border-top: 1px solid rgba(133, 140, 154, 0.12);
  margin-top: 8px;
}
.v-day-report:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }
.v-day-report .v-report-body { font-size: 12px; margin-top: 6px; }

.v-legend {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 10px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9.5px;
  color: var(--grey2);
}
.v-legend span { display: inline-flex; align-items: center; gap: 5px; }
.v-key { width: 8px; height: 3px; border-radius: 2px; background: var(--unknown); display: inline-block; }
.v-key[data-k="up"] { background: var(--up); }
.v-key[data-k="degraded"] { background: var(--degraded); }
.v-key[data-k="down"] { background: var(--down); }
.v-key[data-k="maintenance"] { background: var(--maintenance); }

.v-listday { margin-bottom: 6px; }

/* ---------- footer ---------- */
.v-footer {
  margin-top: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  text-align: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--grey3);
}
.v-footer a { color: var(--grey3); text-decoration: none; }
.v-footer a:hover { color: var(--grey5); }
.v-footer-sep { margin: 0 8px; color: var(--grey2); }

/* Below the strip's natural width the bars cannot stay 3px without
   overflowing, so they go back to flexing and fill whatever is there. The
   uneven-gap rounding described above returns, which is the right trade at
   this size — an overflowing or clipped strip is the worse outcome. */
@media (max-width: 585px) {
  /* min-width on the month label leaves a dead gap beside the next arrow
     once the bar wraps, so drop it and let the label size to its text. */
  .v-monthlabel { min-width: 0; }
  .v-histtools { width: 100%; justify-content: space-between; }
  .v-search { flex: 1 1 auto; min-width: 0; }
  .v-cell-pct { font-size: 8px; }
  .v-cell-num { font-size: 11px; }
  /* a tapped tooltip must never be wider than the screen it sits on */
  .v-tooltip-day { min-width: 0; max-width: calc(100vw - 24px); }
  .v-table th, .v-table td { font-size: 11px; }
  /* No .v-bar width override here — sizeBars() already floors the bar width
     to whole pixels against the measured container, so it adapts down to
     narrow screens on its own; overriding to flex: 1 would put the uneven
     fractional gaps back exactly where they are hardest to see. */
  .v-wrap { padding: 68px 14px 20px; }
  .v-bars { height: 16px; }
}

/* Matches versyi.com's own phone rule exactly (same query, same insets):
   there the logo moves to env(safe-area-inset-top) + 46px and the nav grows
   to env(safe-area-inset-top) + 94px, which keeps the divider 8px under the
   logo just as it is on desktop. */
@media (max-width: 640px) and (hover: none) and (pointer: coarse) {
  .v-topbar { padding-top: calc(env(safe-area-inset-top, 0px) + 46px); padding-bottom: 8px; }
  .v-wrap { padding-top: calc(env(safe-area-inset-top, 0px) + 110px); }
}

@media (prefers-reduced-motion: reduce) {
  .v-dot::after { animation: none; }
  .v-cell { opacity: 1; transform: none; transition: none; transition-delay: 0ms; }
  .v-dayview, .v-dayscrim { transition: none; }
  .v-grid { animation: none !important; }
  .v-bar { transition: none; opacity: 1; transform: none; }
  .v-card { transition: none; }
}
