/* Watch dashboard. App shell aligned with the header, capped on wide screens. */

/* Author display rules (e.g. .gate { display:grid }) beat the UA [hidden]
   stylesheet. Without this, sign-in stays on screen after a successful login. */
[hidden] {
  display: none !important;
}

.pro-body {
  min-height: 100vh;
}

/* Match header and shell to one column so the page does not stretch edge to edge. */
.pro-body .wrap {
  max-width: 1400px;
  padding-left: clamp(1rem, 2.5vw, 2rem);
  padding-right: clamp(1rem, 2.5vw, 2rem);
}

.pro-page {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 clamp(1rem, 2.5vw, 2rem) 2.5rem;
}

.pro-shell:not([hidden]) {
  display: grid;
  grid-template-columns: minmax(14rem, 16.5rem) minmax(0, 1fr);
  gap: 0;
  min-height: calc(100vh - 66px);
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--panel);
  margin-top: 1rem;
}

.pro-rail {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  padding: 1.15rem 1rem 1.5rem;
  border-right: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 55%, var(--panel));
  min-width: 0;
}

.rail-head {
  display: grid;
  gap: .45rem;
}

.rail-kicker {
  margin: 0;
  font: 700 .72rem/1 var(--sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.rail-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem .6rem;
  align-items: center;
}

.rail-soft,
.rail-email {
  margin: 0;
  font-size: .82rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.rail-nav {
  display: grid;
  gap: .25rem;
}

.rail-heading {
  margin: 0 0 .35rem .1rem;
  font: 600 .68rem/1 var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: .75;
}

.rail-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  padding: .55rem .7rem;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font: 600 .9rem/1.2 var(--sans);
  text-align: left;
  cursor: pointer;
  transition: background .12s var(--ease, ease), color .12s var(--ease, ease);
}

.rail-link > span:first-of-type { flex: 1 1 auto; min-width: 0; }

.rail-ico {
  flex: none;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .75;
}

/* The old hover was --bg at 70 per cent over a panel that is nearly --bg, so
   it was invisible. It has to be obvious that these are buttons. */
.rail-link:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.rail-link:hover .rail-ico { opacity: 1; }

.rail-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.rail-link[aria-current="true"] {
  color: var(--text);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
  background: var(--bg);
}

/* A bar on the selected one, so the current place is readable at a glance
   rather than a slightly different grey. */
.rail-link[aria-current="true"]::before {
  content: "";
  position: absolute;
  left: -1px;
  top: 20%;
  bottom: 20%;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}

.rail-link[aria-current="true"] .rail-ico { opacity: 1; color: var(--accent); }

.rail-count {
  font: 600 .75rem/1 var(--sans);
  color: var(--muted);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .15rem .4rem;
  min-width: 1.4rem;
  text-align: center;
}

.rail-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .55rem;
}

.rail-section-head h2 {
  margin: 0;
  font: 650 .8rem/1.2 var(--sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.rail-form {
  display: grid;
  gap: .45rem;
  margin-bottom: .65rem;
}

.rail-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .3rem;
}

.rail-list button {
  display: grid;
  gap: .15rem;
  width: 100%;
  text-align: left;
  padding: .55rem .7rem;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.rail-list button:hover {
  background: color-mix(in srgb, var(--bg) 70%, transparent);
}

.rail-list button[aria-current="true"] {
  border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
  background: var(--bg);
}

.rail-list .name {
  font: 600 .92rem/1.25 var(--sans);
}

.rail-list .sub {
  font-size: .78rem;
  color: var(--muted);
}

/* Desktop already has the project list in the rail, so this second picker is
   for narrow screens only. It needs to out-specify label.field further down the
   file, which is why it is not just .mobile-project. */
.pro-rail label.mobile-project {
  display: none;
}

.pro-main {
  min-width: 0;
  padding: 1.35rem clamp(1rem, 2vw, 1.75rem) 2rem;
  background: var(--bg);
}

.view-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.view-kicker {
  margin: 0 0 .2rem;
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.view-lead {
  margin: .4rem 0 0;
  max-width: 40rem;
  color: var(--muted);
  font-size: .98rem;
}

.view-head h1 {
  margin: 0;
  font: 700 clamp(1.45rem, 2.4vw, 1.85rem)/1.15 var(--sans);
  letter-spacing: -.025em;
}

.view-head .lead {
  margin: .4rem 0 0;
  max-width: 40rem;
  color: var(--muted);
  font-size: .98rem;
}

.eyebrow {
  margin: 0 0 .25rem;
  font: 650 .72rem/1 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.view-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.empty-panel {
  max-width: 28rem;
  margin: 4rem 0 0;
  padding: 0;
}

.empty-panel h1 {
  margin: 0 0 .5rem;
  font: 700 1.5rem/1.2 var(--sans);
  letter-spacing: -.02em;
}

.empty-panel p {
  margin: 0;
  color: var(--muted);
}

.history-filter {
  max-width: 28rem;
  margin: 0 0 1rem;
}

.history-runs {
  margin-top: 1rem;
}

.history-runs .title {
  word-break: break-all;
}

.subnav {
  display: flex;
  flex-wrap: nowrap;
  gap: .15rem;
  margin: 0 0 1.25rem;
  padding: 0;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.subnav button {
  flex: 0 0 auto;
  padding: .7rem .95rem;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  background: transparent;
  color: var(--muted);
  font: 600 .9rem/1.2 var(--sans);
  cursor: pointer;
  white-space: nowrap;
}

.subnav button:hover {
  color: var(--text);
}

.subnav button[aria-selected="true"] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.work-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(16rem, 20rem) minmax(0, 1fr);
  align-items: start;
}

/* When the Add form is closed the list takes the whole row, rather than
   leaving a column of nothing where the form used to be. */
.work-grid:has(> .form-panel[hidden]) {
  grid-template-columns: minmax(0, 1fr);
}

/* The Add button sits at the end of the list header. */
.panel-head {
  gap: .75rem;
}

.panel-head .btn {
  margin-left: auto;
}

.guide-steps {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  display: grid;
  gap: .65rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.guide-steps li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .55rem;
  align-items: start;
  padding: .75rem .8rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}

.guide-steps .n {
  display: grid;
  place-items: center;
  width: 1.45rem;
  height: 1.45rem;
  border-radius: 50%;
  background: rgba(240, 160, 32, .15);
  color: var(--accent-ink);
  font: 700 .75rem/1 var(--sans);
}

.guide-steps strong {
  display: block;
  font-size: .88rem;
  line-height: 1.3;
}

.guide-steps p {
  margin: .25rem 0 0;
  color: var(--muted);
  font-size: .8rem;
  line-height: 1.4;
}

.guide-steps code {
  font: 500 .78rem/1.3 var(--mono);
}

.instruct-steps {
  margin: 0 0 1rem;
  padding-left: 1.15rem;
  color: var(--muted);
  font-size: .88rem;
}

.instruct-steps li {
  margin: .25rem 0;
}

.instruct-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .25rem;
}

.panel {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  padding: 1.1rem 1.15rem 1.2rem;
}

.panel-grow {
  min-width: 0;
}

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .75rem;
}

.panel h2 {
  margin: 0 0 .35rem;
  font: 650 1rem/1.3 var(--sans);
  letter-spacing: -.01em;
}

.panel-head h2 {
  margin: 0;
}

.panel .hint {
  margin: 0 0 1rem;
  color: var(--muted);
  font-size: .88rem;
}

.panel .soft {
  color: var(--muted);
  font-size: .85rem;
}

.stack {
  display: grid;
  gap: .65rem;
}

label.field {
  display: grid;
  gap: .3rem;
  font-size: .82rem;
  color: var(--muted);
}

input,
select,
textarea {
  width: 100%;
  min-width: 0;
  padding: .55rem .7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
}

input:focus,
select:focus,
textarea:focus {
  outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent);
  outline-offset: 1px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  padding: .55rem .95rem;
  border-radius: 8px;
  border: 1px solid var(--line-2);
  background: var(--panel);
  color: var(--text);
  font: 600 .88rem/1.2 var(--sans);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}

.btn:hover {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line-2));
}

.btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #180f02;
}

.btn-primary:hover {
  filter: brightness(1.05);
  border-color: var(--accent);
}

.btn-ghost {
  background: transparent;
  color: var(--muted);
  border-color: var(--line);
}

.btn-ghost:hover {
  color: var(--text);
}

.btn-danger {
  color: #e07070;
  border-color: color-mix(in srgb, #e07070 35%, var(--line));
  background: transparent;
}

:root[data-theme="light"] .btn-danger {
  color: #b03030;
}

.btn-sm {
  padding: .35rem .65rem;
  font-size: .8rem;
}

.btn-block {
  width: 100%;
}

.pill {
  display: inline-flex;
  align-items: center;
  padding: .15rem .5rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: .75rem;
  color: var(--text);
}

.pill.pro {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  color: var(--accent-ink);
}

.table-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--bg);
}

.table-list:empty::after,
.table-list .empty-row {
  display: block;
  padding: 1rem .9rem;
  color: var(--muted);
  font-size: .92rem;
}

.table-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .75rem;
  align-items: center;
  padding: .75rem .9rem;
  border-top: 1px solid var(--line);
}

.reports-row .reports-main {
  min-width: 0;
}

.reports-link {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  color: inherit;
  text-decoration: none;
}

.reports-link:hover .reports-host {
  text-decoration: underline;
}

.reports-host {
  font-weight: 600;
  font-size: .95rem;
  word-break: break-all;
}

.reports-meta {
  font-size: .82rem;
  color: var(--muted);
}

.reports-actions {
  display: flex;
  gap: .35rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.reports-toolbar {
  display: grid;
  grid-template-columns: minmax(12rem, 1.6fr) minmax(7rem, 0.7fr) minmax(8rem, 0.9fr) auto;
  gap: .65rem .75rem;
  align-items: end;
  margin: 0 0 1rem;
}

.reports-toolbar .field {
  margin: 0;
}

.reports-search input {
  width: 100%;
}

.reports-count {
  margin: 0 0 .65rem;
  font-size: .88rem;
  color: var(--muted);
}

.reports-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  margin: 1rem 0 0;
  flex-wrap: wrap;
}

.reports-page {
  font-size: .88rem;
  color: var(--muted);
}

@media (max-width: 720px) {
  .reports-toolbar {
    grid-template-columns: 1fr 1fr;
  }
  .reports-search {
    grid-column: 1 / -1;
  }
}

.table-row:first-child {
  border-top: 0;
}

.table-row .title {
  font: 600 .92rem/1.3 var(--sans);
  overflow-wrap: anywhere;
}

.table-row .sub {
  margin-top: .15rem;
  font-size: .8rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.table-row .row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  justify-content: flex-end;
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: .12rem .45rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  font: 650 .7rem/1.2 var(--sans);
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--muted);
}

.badge.ok {
  border-color: color-mix(in srgb, var(--good) 45%, var(--line));
  color: var(--good);
}

.badge.wait {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  color: var(--accent-ink);
}

/* Result colours. Brand rule: these mark an outcome, never decoration. */
.pro-body {
  --good: #3fb950;
  --bad: #f85149;
}

/* Whether the last alert on this rule actually arrived. Muted until there is
   something to report, so an untested rule does not read as a problem. */
.table-row .delivery {
  margin-top: .3rem;
  font-size: .78rem;
  line-height: 1.4;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.table-row .delivery.ok {
  color: var(--good);
}

.table-row .delivery.bad {
  color: var(--bad);
}

.instruct {
  margin-top: 1rem;
}

.instruct-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 1rem 0;
}

.instruct h3 {
  margin: 0 0 .5rem;
  font: 650 .9rem/1.2 var(--sans);
}

.kv {
  margin: 0;
  display: grid;
  gap: .35rem .75rem;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  font-size: .85rem;
}

.kv dt {
  color: var(--muted);
}

.kv dd {
  margin: 0;
}

.copy-row {
  display: flex;
  align-items: flex-start;
  gap: .45rem;
  min-width: 0;
}

.copy-row code {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-all;
}

.copy-row .btn {
  flex: 0 0 auto;
  margin-top: .05rem;
}

.kv code {
  display: block;
  padding: .45rem .55rem;
  border-radius: 6px;
  background: var(--bg);
  border: 1px solid var(--line);
  font: 500 .78rem/1.4 var(--mono);
  overflow-wrap: anywhere;
}

/* The rail head.

   Credits get the number, because that is the thing people check. Limits get
   bars, because a bar says "nearly full" before you have read anything. */
.rail-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .9rem;
}

.rail-top .rail-kicker { margin: 0; }

.credit-block {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.credit-n {
  font: 700 1.7rem/1 var(--mono);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.credit-k {
  font-size: .76rem;
  color: var(--muted);
}

.meters {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: grid;
  gap: .6rem;
}

.meter {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .2rem .5rem;
  font-size: .76rem;
  color: var(--muted);
}

.meter-k { min-width: 0; }

.meter-v {
  font: 600 .76rem/1.2 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.meter-v i { font-style: normal; color: var(--muted); font-weight: 400; }

.meter-bar {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}

.meter-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}

/* Full is the only state worth colouring. Everything else is just a number. */
.meter-full .meter-v { color: var(--bad); }
.meter-full .meter-bar i { background: var(--bad); }

/* The long explanation, out of the way until it is wanted. */
.rail-note {
  margin-bottom: 1rem;
  font-size: .76rem;
}

.rail-note summary {
  cursor: pointer;
  color: var(--muted);
  list-style: none;
}

.rail-note summary::-webkit-details-marker { display: none; }

.rail-note summary::before {
  content: "+ ";
  color: var(--accent-ink);
}

.rail-note[open] summary::before { content: "− "; }

.rail-note summary:hover { color: var(--text); }

.rail-note p { margin: .5rem 0 0; }

/* The row that reveals the rest of a list. Centred, quiet, and only there
   when there is something behind it. */
.more-row {
  display: flex;
  justify-content: center;
  padding: .75rem 0 .25rem;
}

/* One monitor, on its own screen.

   Headline numbers first, then the shape, then the history. Same order as the
   reference, because it matches the order the questions arrive in: is it up,
   when did you last look, what has the day been like, what went wrong. */
.detail-head {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: .85rem;
}

.detail-actions {
  display: flex;
  gap: .4rem;
  margin-left: auto;
  flex-wrap: wrap;
}

.up-detail h2 {
  margin: 0;
  font: 700 1.4rem/1.2 var(--sans);
  letter-spacing: -.02em;
  overflow-wrap: anywhere;
}

.up-detail > .hint {
  margin: .3rem 0 1.25rem;
}

.detail-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(0, 1.6fr);
  gap: .75rem;
  margin-bottom: .75rem;
}

.detail-windows {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-bottom: 1.25rem;
}

.dcard {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  min-width: 0;
}

.dk {
  font: 650 .68rem/1.2 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.dv {
  font: 700 1.4rem/1.2 var(--mono);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.dv.good { color: var(--good); }
.dv.bad  { color: var(--bad); }

.dn {
  font-size: .78rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.dcard-wide .daystrip { margin: .35rem 0 .2rem; }

.detail-panel { margin-bottom: 1rem; }

.daystrip-30 { height: 30px; }

.hbar.none {
  background: var(--line);
  flex: 1 1 100%;
}

.detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
}

/* Certificate and domain. A label and a value, nothing else, because that is
   all either of them is. */
.factlist {
  list-style: none;
  margin: 0;
  padding: 0;
}

.factlist li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--line);
}

.factlist li:last-child { border-bottom: 0; }

.factlist .fk { color: var(--muted); font-size: .85rem; }

.factlist .fv {
  font: 600 .88rem/1.3 var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.factlist .fv.bad { color: var(--bad); }

.table-row .title.bad { color: var(--bad); }

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

/* A day of bars on a monitor row.

   The thing that makes a monitoring dashboard readable without reading: you
   see the shape of last night before a single word. One bar an hour. */
.daystrip {
  display: flex;
  gap: 2px;
  height: 22px;
  margin: .6rem 0 .3rem;
}

.hbar {
  flex: 1 1 0;
  min-width: 2px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--good) 75%, transparent);
}

.hbar.out { background: var(--bad); }

.daystrip-legend {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
  font: .7rem/1 var(--mono);
  color: var(--muted);
}

.daystrip-legend .up24 {
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Sections inside Uptime. A pill row rather than another underlined tab bar,
   so it reads as "which one of these" and not as a second level of the same
   thing. */
.upnav {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin: 0 0 1.15rem;
  padding: .25rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: color-mix(in srgb, var(--bg) 55%, var(--panel));
}

/* Every segment carries a surface at rest, not only the selected one.
   Plain text on the container read as a label, so nobody knew the other three
   could be pressed. A faint edge is enough to say "this is a control". */
.upnav button {
  flex: 1 1 auto;
  padding: .5rem .85rem;
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  border-radius: 7px;
  background: color-mix(in srgb, var(--panel) 45%, transparent);
  color: var(--muted);
  font: 600 .85rem/1.2 var(--sans);
  cursor: pointer;
  white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  .upnav button { transition: background .12s ease, color .12s ease, border-color .12s ease; }
}

.upnav button:hover {
  color: var(--text);
  background: var(--panel);
  border-color: var(--line);
}

.upnav button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.upnav button[aria-selected="true"] {
  background: var(--panel);
  color: var(--text);
  border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
  box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}

/* Loading.

   Lists used to appear out of nothing after a request, which on a slow
   connection reads as an empty account. A shape in the right place says the
   answer is coming and stops the page jumping when it lands. */
.skeleton {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sk-row {
  display: grid;
  gap: .5rem;
  padding: .85rem 0;
  border-bottom: 1px solid var(--line);
}

.sk-row:last-child { border-bottom: 0; }

.sk-bar {
  height: .7rem;
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--line) 70%, transparent) 25%,
    color-mix(in srgb, var(--line) 140%, transparent) 50%,
    color-mix(in srgb, var(--line) 70%, transparent) 75%
  );
  background-size: 320% 100%;
}

.sk-bar.w-40 { width: 40%; }
.sk-bar.w-70 { width: 70%; }
.sk-bar.w-55 { width: 55%; height: .6rem; }

@media (prefers-reduced-motion: no-preference) {
  .sk-bar { animation: skShimmer 1.4s ease-in-out infinite; }
}

@keyframes skShimmer {
  0%   { background-position: 130% 0; }
  100% { background-position: -30% 0; }
}

/* What is watching this page. Three chips: speed, uptime, alerts.
   A chip that is off is a button, because showing what is missing next to the
   way to switch it on teaches the feature and gives the next step at once. */
.cover {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .5rem;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .22rem .5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 500 .74rem/1.3 var(--sans);
  white-space: nowrap;
}

.chip-on {
  border-color: color-mix(in srgb, var(--good) 35%, var(--line));
  color: var(--good);
}

.chip-on::before { content: "✓"; font-size: .7rem; }

.chip-bad {
  border-color: color-mix(in srgb, var(--bad) 45%, var(--line));
  color: var(--bad);
}

.chip-bad::before { content: "●"; font-size: .6rem; }

/* Off is an invitation, not a warning. Muted until hovered, then it is
   obviously a thing you can press. */
.chip-off {
  background: none;
  color: var(--muted);
  cursor: pointer;
  font-family: var(--sans);
}

.chip-off::before { content: "+"; font-size: .8rem; }

.chip-off:hover,
.chip-off:focus-visible {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  color: var(--accent-ink);
}

/* The strip at the top of a project. Three readings, biggest first, so a
   glance answers "is anything wrong" without opening a tab. */
.summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .75rem;
  margin: 0 0 1.5rem;
}

.sum-card {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  padding: .85rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  min-width: 0;
}

.sum-k {
  font: 650 .68rem/1.2 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.sum-v {
  font: 700 1.55rem/1.15 var(--mono);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.sum-note {
  font-size: .78rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Colour is the verdict, never decoration. A card with nothing to say stays
   plain rather than going green for the sake of it. */
.sum-card.tone-good .sum-v { color: var(--good); }
.sum-card.tone-warn .sum-v { color: var(--accent); }
.sum-card.tone-poor .sum-v { color: var(--bad); }
.sum-card.tone-poor {
  border-color: color-mix(in srgb, var(--bad) 38%, var(--line));
}

@media (max-width: 720px) {
  .summary { grid-template-columns: 1fr; gap: .5rem; }
  .sum-card { flex-direction: row; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
  .sum-k { flex: 0 0 100%; }
  .sum-v { font-size: 1.3rem; }
}

.chart-wrap {
  margin-top: .75rem;
}

.score-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

/* The reading, before the shape. Somebody who looks for one second should get
   the number and the direction, and nothing else. */
.chart-head {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: .35rem;
}

.chart-now {
  font: 700 2rem/1 var(--mono);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.chart-now.is-good { color: var(--good); }
.chart-now.is-mid  { color: var(--accent); }
.chart-now.is-poor { color: var(--bad); }

.chart-now-k {
  font-size: .8rem;
  color: var(--muted);
}

.chart-move {
  margin-left: auto;
  font-size: .82rem;
  color: var(--muted);
}

.chart-move.bad { color: var(--bad); }
.chart-move.ok  { color: var(--good); }

/* Lighthouse's own cut points, as two marked lines. Everybody who has opened
   Lighthouse knows 50 and 90 already, so the chart needs no legend. Lines
   rather than filled bands: a filled red block under 50 pulled the eye to
   empty space and made the area fill muddy where the two overlapped. */
.score-svg .grid {
  stroke: var(--line);
  stroke-width: 1;
}

.score-svg .grid-good {
  stroke: color-mix(in srgb, var(--good) 45%, transparent);
  stroke-dasharray: 3 4;
}

.score-svg .grid-mid {
  stroke: color-mix(in srgb, var(--accent) 45%, transparent);
  stroke-dasharray: 3 4;
}

.score-svg .axis {
  fill: var(--muted);
  font: 10px/1 var(--mono);
}

.score-svg .axis-note {
  font: 9px/1 var(--sans);
  letter-spacing: .03em;
  opacity: .75;
}

.score-svg .line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.score-svg .area {
  fill: url(#scoreFade);
  stroke: none;
}

.score-svg .fade-top {
  stop-color: var(--accent);
  stop-opacity: .22;
}

.score-svg .fade-bottom {
  stop-color: var(--accent);
  stop-opacity: 0;
}

.score-svg .pt {
  fill: var(--accent);
}

/* The moment it fell. On a plain line that bend looks like every other bend. */
.score-svg .pt-drop {
  fill: var(--bad);
}

.score-svg .pt-last {
  fill: var(--panel);
  stroke: var(--accent);
  stroke-width: 2.5;
}

.score-svg .drop-label {
  fill: var(--bad);
  font: 600 11px/1 var(--mono);
}

/* Runs. The address is already in the picker above, so each row is the day,
   the score, and whether it moved. */
.history-runs {
  margin-top: 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}

.run-row {
  display: grid;
  grid-template-columns: 1fr auto 5.5rem;
  align-items: center;
  gap: .75rem;
  padding: .6rem .85rem;
  font-size: .88rem;
}

.run-row + .run-row {
  border-top: 1px solid var(--line);
}

.run-when { color: var(--muted); }

.run-score {
  font: 600 .95rem/1 var(--mono);
  font-variant-numeric: tabular-nums;
}

a.run-score {
  text-decoration: none;
}

a.run-score:hover {
  text-decoration: underline;
}

.run-score.is-good { color: var(--good); }
.run-score.is-mid  { color: var(--text); }
.run-score.is-poor { color: var(--bad); }

.run-delta {
  text-align: right;
  font: .82rem/1 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.run-delta.bad { color: var(--bad); }
.run-delta.ok  { color: var(--good); }

/* Latest score on a saved page, so five client URLs can be read at a glance
   instead of clicking into each one. A dot, not a coloured number, because the
   number is the reading and the colour is only the verdict. */
.target-score {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-top: .35rem;
}

.score-dot {
  width: .55rem;
  height: .55rem;
  border-radius: 50%;
  flex: none;
  background: var(--muted);
}

.score-dot.is-good { background: var(--good); }
.score-dot.is-warn { background: var(--accent); }
.score-dot.is-poor { background: var(--bad); }

/* The Up list puts the dot inline with the address rather than in a flex row,
   and a bare span ignores width and height. Grey is the honest colour for a
   monitor that has not run yet: a new row must not claim to be up. */
.table-row .title .score-dot {
  display: inline-block;
  vertical-align: middle;
  margin-right: .1rem;
}

/* The heartbeat URL is the whole product for that row, so it is on the page
   rather than behind a details panel. Mono, because it is a command, and it
   scrolls inside itself so a long token cannot push the layout sideways. */
.table-row .ping-url {
  margin-top: .45rem;
  overflow-x: auto;
}

.table-row .ping-url code {
  display: inline-block;
  padding: .3rem .5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: color-mix(in srgb, var(--bg) 60%, var(--panel));
  font: .76rem/1.5 var(--mono);
  /* Wrap, never truncate. A token you cannot see is a token you cannot
     check against the one in your crontab. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text);
}

/* Which monitors go on a public page. Checkboxes, one per monitor, because
   the choice has to be deliberate: "everything in this project" would publish
   an internal admin page the moment somebody started watching it. */
.status-picks {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1rem;
  margin-top: .6rem;
}

.status-picks .pick {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .82rem;
  color: var(--muted);
  cursor: pointer;
}

.status-picks .pick input {
  margin: 0;
  accent-color: var(--accent);
}

/* The second half of the Up tab. A rule, because these answer two different
   questions and running them together reads as one long list. */
.up-beats {
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}

/* The outage list opens under the row, so it needs its own line breaks. */
.table-row .delivery.outages {
  white-space: pre-line;
  font-variant-numeric: tabular-nums;
}

/* Why a button is disabled.
   Not an error, so not red. It is the thing you are meant to read, so amber,
   and it is text on the page rather than a title tooltip, because a tooltip
   does not exist on a phone. */
.cap-note {
  margin: .1rem 0 .6rem;
  padding: .55rem .7rem;
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 0 8px 8px 0;
  font-size: .82rem;
  line-height: 1.45;
  color: var(--text);
}

/* Real visitors panel.
   Instrument, not dashboard: one number per card, mono so it reads as a
   reading rather than an opinion, and colour only on the verdict. */
.field-block {
  margin-top: 1.15rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
}

.field-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  margin-bottom: .8rem;
}

.field-head h3 {
  margin: 0;
  font: 600 1rem/1.25 var(--sans);
}

.field-note {
  font-size: .8rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.field-grid {
  display: grid;
  gap: .7rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.metric-card {
  padding: .8rem .85rem .7rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: color-mix(in srgb, var(--line) 18%, transparent);
}

.metric-name {
  font: 600 .78rem/1.3 var(--sans);
  color: var(--muted);
}

/* Mono, because it is a measurement. */
.metric-value {
  margin-top: .3rem;
  font: 600 1.5rem/1.15 var(--mono);
  letter-spacing: -.01em;
  overflow-wrap: anywhere;
}

.metric-band {
  margin-top: .3rem;
  display: inline-block;
  font: 650 .7rem/1.2 var(--sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.metric-card.is-good .metric-band { color: var(--good); }
.metric-card.is-warn .metric-band { color: var(--accent-ink); }
.metric-card.is-poor .metric-band { color: var(--bad); }

.metric-card.is-good { border-color: color-mix(in srgb, var(--good) 32%, var(--line)); }
.metric-card.is-warn { border-color: color-mix(in srgb, var(--accent) 32%, var(--line)); }
.metric-card.is-poor { border-color: color-mix(in srgb, var(--bad) 32%, var(--line)); }

.metric-spark {
  margin-top: .5rem;
  color: var(--muted);
}

.metric-card.is-good .metric-spark { color: color-mix(in srgb, var(--good) 70%, var(--muted)); }
.metric-card.is-warn .metric-spark { color: color-mix(in srgb, var(--accent) 70%, var(--muted)); }
.metric-card.is-poor .metric-spark { color: color-mix(in srgb, var(--bad) 70%, var(--muted)); }

.metric-spark .spark {
  display: block;
  width: 100%;
  height: auto;
}

.metric-plain {
  margin-top: .45rem;
  font-size: .76rem;
  line-height: 1.4;
  color: var(--muted);
}

/* One card per row on a narrow phone, so the number never wraps mid digit. */
@media (max-width: 30rem) {
  .field-grid {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .metric-card {
    transition: border-color .15s ease;
  }
}

.gap-box {
  margin-top: .85rem;
  padding: .75rem .85rem;
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 0 8px 8px 0;
}

.gap-box strong {
  display: block;
  margin-bottom: .25rem;
  font-size: .95rem;
}

.gap-box p {
  margin: 0;
  color: var(--muted);
  font-size: .9rem;
}

.msg {
  margin: .5rem 0 0;
  font-size: .88rem;
  color: var(--muted);
  min-height: 1.2em;
}

.msg.err {
  color: #e07070;
}

:root[data-theme="light"] .msg.err {
  color: #b03030;
}

/* Signed out marketing gate. One hero composition, then path + price. */
.gate:not([hidden]) {
  display: block;
  padding: 0 0 3.5rem;
}

.gate-hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
  min-height: calc(100vh - 66px);
  padding: clamp(2.5rem, 6vh, 4.5rem) 0 clamp(2rem, 4vh, 3rem);
  overflow: hidden;
}

.gate-hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto 35%;
  height: min(70vh, 560px);
  pointer-events: none;
  background:
    radial-gradient(ellipse 55% 70% at 70% 35%, color-mix(in srgb, var(--accent) 18%, transparent), transparent 70%),
    radial-gradient(ellipse 40% 50% at 20% 80%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 65%);
}

.gate-hero > * {
  position: relative;
}

.gate-brand {
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  margin: 0;
  font: 700 1.05rem/1 var(--sans);
  letter-spacing: -.02em;
  color: var(--text);
}

.gate-brand svg {
  flex: 0 0 auto;
}

.gate-hero-copy h1 {
  margin: 1.35rem 0 0;
  max-width: 11ch;
  font: 750 clamp(2.15rem, 5.2vw, 3.35rem)/1.05 var(--sans);
  letter-spacing: -.035em;
}

.gate-lead {
  margin: 1rem 0 0;
  max-width: 28rem;
  color: var(--muted);
  font-size: clamp(1.02rem, 1.6vw, 1.15rem);
  line-height: 1.55;
}

.gate-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .55rem;
  margin-top: 1.75rem;
  max-width: 28rem;
  align-items: start;
}

.gate-email {
  margin: 0;
}

.gate-form .field {
  display: grid;
  gap: .35rem;
  font: 600 .82rem/1.2 var(--sans);
  color: var(--muted);
}

.gate-form input[type="email"] {
  width: 100%;
  min-height: 2.85rem;
  padding: .7rem .9rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  color: var(--text);
  font: 500 1rem/1.2 var(--sans);
}

.gate-form input[type="email"]:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.gate-form .btn {
  min-height: 2.85rem;
  white-space: nowrap;
  padding-left: 1.15rem;
  padding-right: 1.15rem;
}

.gate-form .msg {
  grid-column: 1 / -1;
  margin: .15rem 0 0;
  min-height: 1.25rem;
}

.gate-note {
  margin: .85rem 0 0;
  max-width: 28rem;
  color: var(--muted);
  font-size: .88rem;
  line-height: 1.45;
}

.gate-hero-visual {
  min-width: 0;
}

.gate-stage {
  position: relative;
  padding: 1.4rem 1.45rem 1.25rem;
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--line));
  border-radius: 0;
  background:
    linear-gradient(165deg, color-mix(in srgb, var(--accent) 9%, var(--panel)), var(--panel) 42%),
    var(--panel);
  box-shadow:
    0 1px 0 color-mix(in srgb, var(--accent) 20%, transparent),
    0 28px 60px rgba(0, 0, 0, .22);
}

.gate-stage-top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .4rem .75rem;
}

.gate-stage-k {
  font: 700 .68rem/1 var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.gate-stage-url {
  font: 600 .9rem/1.2 var(--sans);
  color: var(--muted);
}

.gate-stage-score {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .55rem .85rem;
  margin-top: 1.1rem;
}

.gate-stage-num {
  font: 750 3.25rem/1 var(--sans);
  letter-spacing: -.04em;
  color: var(--text);
}

.gate-stage-delta {
  font: 600 .92rem/1.3 var(--sans);
  color: #e07070;
}

:root[data-theme="light"] .gate-stage-delta {
  color: #b03030;
}

.gate-chart {
  display: block;
  width: 100%;
  height: 9.5rem;
  margin-top: 1rem;
  overflow: visible;
}

.gate-chart-fill {
  fill: url(#gateFill);
  opacity: 0;
  animation: gateFillIn .9s ease .45s forwards;
}

.gate-chart-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 520;
  stroke-dashoffset: 520;
  animation: gateDraw 1.15s ease .2s forwards;
}

.gate-chart-dot {
  fill: var(--bg);
  stroke: var(--accent);
  stroke-width: 2.5;
  opacity: 0;
  transform-origin: 280px 102px;
  animation: gateDot .55s ease .95s forwards;
}

.gate-stage-alert {
  margin: .95rem 0 0;
  padding: .65rem .8rem;
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--text);
  font: 600 .9rem/1.35 var(--sans);
  opacity: 0;
  transform: translateY(8px);
  animation: gateRise .55s ease 1.1s forwards;
}

/* The other half of the product, on the same card. The preview showed only a
   score drop, which sold Watch and left Up invisible to anybody signed out. */
.gate-stage-up {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: .45rem 0 0;
  font-size: .82rem;
  color: var(--good);
  /* Arrives just after the score alert, so the two read as one sequence
     rather than one appearing on top of something already there. */
  opacity: 0;
  transform: translateY(8px);
  animation: gateRise .55s ease 1.35s forwards;
}

.gate-stage-dot {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--good);
  flex: none;
}

.gate-brand,
.gate-hero-copy h1,
.gate-lead,
.gate-form,
.gate-note {
  opacity: 0;
  transform: translateY(12px);
  animation: gateRise .7s ease forwards;
}

.gate-brand { animation-delay: .05s; }
.gate-hero-copy h1 { animation-delay: .12s; }
.gate-lead { animation-delay: .2s; }
.gate-form { animation-delay: .28s; }
.gate-note { animation-delay: .36s; }

.gate-stage {
  opacity: 0;
  transform: translateY(16px);
  animation: gateRise .8s ease .22s forwards;
}

@keyframes gateRise {
  to { opacity: 1; transform: none; }
}

@keyframes gateDraw {
  to { stroke-dashoffset: 0; }
}

@keyframes gateFillIn {
  to { opacity: 1; }
}

@keyframes gateDot {
  0% { opacity: 0; transform: scale(.4); }
  70% { opacity: 1; transform: scale(1.15); }
  100% { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .gate-brand,
  .gate-hero-copy h1,
  .gate-lead,
  .gate-form,
  .gate-note,
  .gate-stage,
  .gate-chart-fill,
  .gate-chart-line,
  .gate-chart-dot,
  .gate-stage-alert,
  .gate-stage-up {
    animation: none;
    opacity: 1;
    transform: none;
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }
}

.gate-path {
  margin-top: clamp(1.5rem, 4vw, 2.75rem);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--line);
}

.gate-path h2,
.gate-include h2 {
  margin: 0;
  font: 700 clamp(1.25rem, 2vw, 1.55rem)/1.2 var(--sans);
  letter-spacing: -.02em;
}

.gate-steps {
  list-style: none;
  margin: 1.35rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem 1.5rem;
}

.gate-steps li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .75rem;
  align-items: start;
}

.gate-step-n {
  display: grid;
  place-items: center;
  width: 1.85rem;
  height: 1.85rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-ink);
  font: 700 .8rem/1 var(--sans);
}

.gate-steps strong {
  display: block;
  font: 650 1rem/1.25 var(--sans);
}

.gate-steps p {
  margin: .35rem 0 0;
  color: var(--muted);
  font-size: .95rem;
  line-height: 1.45;
}

.gate-include {
  margin-top: clamp(2rem, 5vw, 3.25rem);
  padding: clamp(1.35rem, 3vw, 1.85rem) 0 0;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: 1rem 2rem;
  align-items: start;
}

.gate-include-copy p {
  margin: .65rem 0 0;
  max-width: 34rem;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.5;
}

.gate-include-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .55rem;
}

.gate-include-list li {
  position: relative;
  padding-left: 1.15rem;
  color: var(--text);
  font: 550 .98rem/1.4 var(--sans);
}

.gate-include-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: .45rem;
  height: .45rem;
  border-radius: 1px;
  background: var(--accent);
}

.gate-include-cta {
  margin-top: 1.1rem;
}

.gate-include-soft {
  grid-column: 1 / -1;
  margin: .35rem 0 0;
  color: var(--muted);
  font-size: .92rem;
  line-height: 1.45;
}

.gate-include-soft a {
  color: var(--text);
}

.plan-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .85rem 1rem;
  margin: 0 0 1.15rem;
  padding: .9rem 1rem;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 9%, var(--panel));
}

.plan-banner[hidden] {
  display: none !important;
}

.plan-banner strong {
  display: block;
  font-size: .95rem;
}

.plan-banner p {
  margin: .2rem 0 0;
  color: var(--muted);
  font-size: .88rem;
  max-width: 40rem;
}

.lock-panel {
  margin: 0 0 1rem;
  padding: 1.25rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.lock-panel[hidden] {
  display: none !important;
}

.lock-panel h2 {
  margin: 0 0 .4rem;
  font: 700 1.15rem/1.25 var(--sans);
}

.lock-panel > p {
  margin: 0 0 .85rem;
  color: var(--muted);
  max-width: 36rem;
}

.lock-list {
  margin: 0 0 1rem;
  padding: 0 0 0 1.1rem;
  color: var(--muted);
  font-size: .92rem;
}

.lock-list li {
  margin: .3rem 0;
}

.empty-pro-hint {
  margin-top: 1rem;
  padding: .85rem 1rem;
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.empty-pro-hint p {
  margin: 0;
  color: var(--muted);
  font-size: .92rem;
}

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 920px) {
  .gate-hero {
    grid-template-columns: 1fr;
    min-height: 0;
    padding-top: 2rem;
    gap: 2rem;
  }

  .gate-hero-copy h1 {
    max-width: 14ch;
  }

  .gate-steps {
    grid-template-columns: 1fr;
  }

  .gate-include {
    grid-template-columns: 1fr;
  }

  .work-grid {
    grid-template-columns: 1fr;
  }

  .instruct-grid {
    grid-template-columns: 1fr;
  }

  .guide-steps {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 560px) {
  .gate-form {
    grid-template-columns: 1fr;
  }

  .gate-form .btn {
    width: 100%;
  }
}

@media (max-width: 860px) {
  .pro-shell:not([hidden]) {
    grid-template-columns: 1fr;
    min-height: 0;
    margin-top: .75rem;
  }

  .pro-rail {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 1rem .9rem;
  }

  .rail-section {
    display: none;
  }

  .pro-rail label.mobile-project {
    display: grid;
  }

  .pro-main {
    padding: 1rem .9rem 1.75rem;
  }

  .view-head h1 {
    font-size: 1.35rem;
  }

  /* Wrap on a phone rather than scroll sideways.
     With five tabs and names that say what they do, the last one fell off the
     right edge and nothing showed there was more. A tab bar you have to swipe
     is a tab bar people do not find. */
  .subnav {
    margin-bottom: 1rem;
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 0;
  }

  .table-row {
    grid-template-columns: 1fr;
  }

  .table-row .row-actions {
    justify-content: flex-start;
  }

  .empty-panel {
    margin-top: 1rem;
  }

  .btn-block {
    width: auto;
  }
}

@media (max-width: 520px) {
  .pro-body .wrap,
  .pro-page {
    padding-left: .85rem;
    padding-right: .85rem;
  }

  .pro-shell:not([hidden]) {
    border-radius: 10px;
  }

  .subnav button {
    padding: .65rem .75rem;
    font-size: .85rem;
  }

  .panel {
    padding: 1rem;
  }

  .guide-steps {
    grid-template-columns: 1fr;
  }

  .confirm-card {
    padding: 1.15rem;
  }

  .confirm-actions {
    flex-direction: column-reverse;
  }

  .confirm-actions .btn {
    width: 100%;
  }
}

/* In-app confirm. Replaces window.confirm. */
.confirm:not([hidden]) {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: 1.25rem;
}

.confirm-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(6, 8, 12, .58);
  backdrop-filter: blur(2px);
}

:root[data-theme="light"] .confirm-backdrop {
  background: rgba(20, 24, 30, .35);
}

.confirm-card {
  position: relative;
  z-index: 1;
  width: min(100%, 24rem);
  padding: 1.35rem 1.4rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 18px 48px rgba(0, 0, 0, .28);
}

.confirm-card h2 {
  margin: 0;
  font: 700 1.15rem/1.25 var(--sans);
  letter-spacing: -.02em;
}

.confirm-card p {
  margin: .55rem 0 0;
  color: var(--muted);
  font-size: .95rem;
  line-height: 1.5;
}

.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem;
  margin-top: 1.25rem;
}

.confirm-actions .btn-danger {
  background: color-mix(in srgb, #e07070 18%, var(--panel));
  color: #f0a0a0;
  border-color: color-mix(in srgb, #e07070 45%, var(--line));
}

:root[data-theme="light"] .confirm-actions .btn-danger {
  background: color-mix(in srgb, #b03030 10%, var(--panel));
  color: #8f1f1f;
  border-color: color-mix(in srgb, #b03030 35%, var(--line));
}

.confirm-actions .btn-danger:hover {
  filter: brightness(1.06);
}

/* ---- Client report branding (M4-5) ---- */

.brand-preview {
  padding: 1rem;
  background: var(--sunk, var(--bg));
  border: 1px solid var(--line);
  border-radius: 10px;
}

.bp-doc {
  background: #ffffff;
  color: #14161a;
  border-radius: 8px;
  padding: 1.1rem 1.2rem 1rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
}

/* The same letterhead the downloaded report has: name or logo on the left,
   what the document is on the right, an accent rule under both. */
.bp-band {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: .75rem;
  padding-bottom: .55rem;
  margin-bottom: .9rem;
  border-bottom: 2px solid #f0a020;
}

.bp-mark {
  display: flex;
  align-items: center;
  gap: .45rem;
  min-width: 0;
  flex-wrap: wrap;
}

/* Until they type something, say so rather than showing a stray name. */
.bp-mark.bp-empty .bp-name { opacity: .45; font-style: italic; font-weight: 500; }

.bp-name {
  font-size: 1.05rem;
  letter-spacing: -.02em;
  overflow-wrap: anywhere;
}

.bp-name-small {
  font-size: .78rem;
  opacity: .7;
  overflow-wrap: anywhere;
}

.bp-mark img {
  max-height: 30px;
  max-width: 150px;
  object-fit: contain;
  display: block;
}

.bp-doc-meta {
  text-align: right;
  font-size: .64rem;
  line-height: 1.35;
  color: #5d636e;
  flex: none;
}

.bp-doc-meta b { display: block; color: #14161a; font-size: .7rem; }

.bp-note {
  margin: .6rem 0 0;
  font-size: .76rem;
  color: var(--muted);
}

.bp-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
}

.bp-hero {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 1rem 0 .85rem;
}

.bp-ring {
  flex: none;
  width: 52px;
  height: 52px;
  border: 4px solid #f0a020;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 1.15rem;
  font-weight: 600;
}

.bp-soft {
  color: #5d636e;
  font-size: .82rem;
}

.bp-line {
  height: 4px;
  border-radius: 2px;
  background: #f0a020;
  margin: .2rem 0 .7rem;
}

.bp-foot {
  margin: 0;
}

.brand-count {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}

.brand-count b {
  display: block;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 1.5rem;
  line-height: 1.1;
}

.brand-count span {
  display: block;
  margin-top: .2rem;
  font-size: .78rem;
  color: var(--muted);
}

@media (max-width: 30rem) {
  .brand-count { grid-template-columns: 1fr; }
}

/* ---- All sites (M4-2, M4-3) ---- */

.pf-head { margin: 0 0 .75rem; }

.pf-head h2 {
  margin: 0;
  font-size: 1.05rem;
  letter-spacing: -.01em;
}

.pf-head .hint {
  margin: .2rem 0 0;
  font-size: .82rem;
  color: var(--muted);
}

.pf-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .75rem;
  margin-bottom: 1.5rem;
}

.pf-stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .9rem 1rem;
}

.pf-stat b {
  display: block;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 1.65rem;
  line-height: 1.1;
}

.pf-stat b.is-good { color: var(--good); }
.pf-stat b.is-mid { color: var(--accent); }
.pf-stat b.is-poor { color: var(--bad); }
.pf-stat b.is-none { color: var(--muted); }

.pf-stat span {
  display: block;
  margin-top: .25rem;
  font-size: .78rem;
  color: var(--muted);
}

.pf-block { margin-bottom: 2rem; }

.pf-worst,
.pf-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .5rem;
}

.pf-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .85rem;
  align-items: start;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .8rem .95rem;
}

.pf-score {
  flex: none;
  width: 2.6rem;
  height: 2.6rem;
  display: grid;
  place-items: center;
  border-radius: 9px;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 1rem;
  font-weight: 600;
  border: 1px solid var(--line);
}

.pf-score.is-good { color: var(--good); border-color: color-mix(in srgb, var(--good) 45%, var(--line)); }
.pf-score.is-mid { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.pf-score.is-poor { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 45%, var(--line)); }
.pf-score.is-none { color: var(--muted); }

.pf-main { min-width: 0; }

.pf-title {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  flex-wrap: wrap;
}

.pf-title a,
.pf-title span:first-child {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.pf-project {
  font-size: .74rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .05rem .45rem;
}

.pf-meta {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin-top: .3rem;
  font-size: .78rem;
}

.pf-change { font-weight: 600; }
.pf-change.up { color: var(--good); }
.pf-change.down { color: var(--bad); }
.pf-change.noise,
.pf-change.flat,
.pf-change.none { color: var(--muted); font-weight: 400; }
.pf-change i { font-style: normal; }

.pf-when { color: var(--muted); }

.pf-worst-line {
  margin: .4rem 0 0;
  font-size: .85rem;
  color: var(--muted);
}

.pf-worst-line b { color: inherit; font-weight: 600; }

.pf-proj { margin-bottom: 1.5rem; }

.pf-proj-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin: 0 0 .6rem;
}

.pf-proj-head h3 { margin: 0; font-size: .98rem; }

.pf-proj-score {
  font-size: .78rem;
  color: var(--muted);
  font-family: var(--mono, ui-monospace, monospace);
}

.pf-empty {
  color: var(--muted);
  padding: 2rem 0;
}

@media (max-width: 40rem) {
  .pf-summary { grid-template-columns: 1fr; }
}

/* A line the report will not stand behind reads differently from one it will.
   "Where the points went" is not "do this first", and the screen must not let
   an agency mistake the two. */
.pf-worst-line .pf-tag {
  display: inline-block;
  font-size: .68rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .02rem .4rem;
  margin-right: .3rem;
  vertical-align: 1px;
}

.pf-none {
  list-style: none;
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem 1.1rem;
}

/* ---- Pages behind a login (M2.6) ---- */

/* The safety promise reads before the form, not after it. Somebody deciding
   whether to hand over a session decides here. */
.safety {
  background: color-mix(in srgb, var(--accent) 6%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--line));
  border-radius: 14px;
  padding: 1.1rem 1.25rem;
  margin-bottom: 1.5rem;
}

.safety h2 {
  margin: 0 0 .6rem;
  font-size: .95rem;
}

.safety-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .5rem;
}

.safety-list li {
  font-size: .88rem;
  line-height: 1.5;
  color: var(--muted);
  padding-left: 1.1rem;
  position: relative;
}

.safety-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

.safety-list b { color: var(--fg, inherit); font-weight: 600; }

.notice-off {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
}

.notice-off h2 { margin: 0 0 .4rem; font-size: 1rem; }
.notice-off p { margin: 0; color: var(--muted); }

/* Cookie or header. Two choices, so a pair of buttons beats a dropdown. */
.seg {
  display: flex;
  gap: .5rem;
  border: 0;
  padding: 0;
  margin: 0 0 .25rem;
}

.seg label {
  flex: 1 1 0;
  position: relative;
}

.seg input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: auto;
}

.seg span {
  display: block;
  text-align: center;
  padding: .5rem .75rem;
  border: 1px solid var(--line);
  border-radius: 9px;
  font-size: .88rem;
  cursor: pointer;
}

.seg input:checked + span {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* A focus ring has to survive the hidden radio, or this is unusable by keyboard. */
.seg input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.check {
  display: flex;
  gap: .6rem;
  align-items: flex-start;
  font-size: .86rem;
  line-height: 1.45;
  color: var(--muted);
}

/* Inputs are width:100% everywhere on this page, which stretches a checkbox
   into a 260px wide box that renders a small tick and shoves its own label out
   of the panel. It needs its own width back. */
.check input[type="checkbox"] {
  width: auto;
  min-width: 0;
  margin: .2rem 0 0;
  flex: none;
}

.check span { min-width: 0; }

.auth-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .6rem;
}

.auth-row {
  display: flex;
  gap: .9rem;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .8rem .95rem;
}

.auth-main { min-width: 0; flex: 1 1 14rem; }

.auth-main b { overflow-wrap: anywhere; }

.auth-kind {
  display: inline-block;
  margin-left: .45rem;
  font-size: .72rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .05rem .45rem;
  vertical-align: 1px;
}

.auth-meta {
  margin: .3rem 0 0;
  font-size: .78rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.auth-none {
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem 1.1rem;
}

.auth-log { margin-top: 1rem; }
.auth-log summary { cursor: pointer; font-size: .82rem; color: var(--muted); }
.auth-log ul { margin: .6rem 0 0; padding-left: 1.1rem; }
.auth-log li { font-size: .78rem; color: var(--muted); margin-bottom: .25rem; }

/* A button that reads as a link, for "prove one first" inside a sentence. */
.linky {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 34rem) {
  .auth-row { flex-direction: column; align-items: stretch; }
  /* flex-basis is a height once the row stacks, so 14rem turns into 14rem of
     empty space above the button. It only means anything side by side. */
  .auth-row .auth-main { flex: 0 1 auto; }
  .auth-row .btn { width: 100%; }
}

/* Numbered walkthrough. The old version was one sentence telling somebody to
   go and find a header in developer tools, which is four places to get lost. */
.howto {
  list-style: none;
  margin: .25rem 0 1rem;
  padding: 0;
  display: grid;
  gap: .7rem;
  counter-reset: h;
}

.howto li {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr);
  gap: .7rem;
  align-items: start;
  font-size: .86rem;
  line-height: 1.5;
  color: var(--muted);
}

.howto .n {
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: .78rem;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}

.howto b { color: inherit; font-weight: 600; }

kbd {
  font-family: var(--mono);
  font-size: .76rem;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: .05rem .3rem;
  white-space: nowrap;
}

.by-hand { margin: -.25rem 0 .25rem; }

.by-hand summary {
  cursor: pointer;
  font-size: .82rem;
  color: var(--muted);
  margin-bottom: .6rem;
}

/* The answer to "did that work", in the three shapes it can take. */
.verdict {
  margin-top: .9rem;
  padding: .85rem 1rem;
  border-radius: 11px;
  border: 1px solid var(--line);
  font-size: .87rem;
  line-height: 1.5;
}

.verdict.good {
  border-color: color-mix(in srgb, var(--good) 45%, var(--line));
  background: color-mix(in srgb, var(--good) 9%, transparent);
}

.verdict.bad {
  border-color: color-mix(in srgb, var(--bad) 45%, var(--line));
  background: color-mix(in srgb, var(--bad) 9%, transparent);
}

.verdict.unsure {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}

.verdict-next {
  display: inline-block;
  margin-top: .35rem;
  color: var(--muted);
}

/* Coming back from the payment page (M1/M4-8). */
.billing-return {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .9rem 1.1rem;
  margin-bottom: 1.25rem;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--muted);
}

.billing-return.good {
  border-color: color-mix(in srgb, var(--good) 45%, var(--line));
  background: color-mix(in srgb, var(--good) 9%, transparent);
}

.billing-return b { color: inherit; }

/* What you are paying for, and how to change it (M4-8). */
.plan-now {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .85rem 1.05rem;
  margin-bottom: 1.25rem;
  font-size: .88rem;
  line-height: 1.55;
  color: var(--muted);
  background: var(--panel);
}

.plan-now b { color: inherit; }

.plan-now-why {
  margin: .35rem 0 0;
  font-size: .8rem;
  opacity: .8;
}

/* An outage that explains itself (M2.7 polish). */
.outage-why {
  margin-top: .45rem;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--muted);
  border-left: 2px solid color-mix(in srgb, var(--bad) 40%, var(--line));
  padding-left: .7rem;
}

.outage-why b { color: var(--text); font-weight: 600; }

.outage-do {
  display: block;
  margin-top: .3rem;
  color: var(--text);
  opacity: .85;
}
