/*
 * One dark theme, deliberately: this is an operations console read at 3 a.m.
 * on whatever device is closest, so contrast and touch-target size outrank
 * matching anybody's OS theme.
 */

:root {
  --bg: #0d1117;
  --panel: #161b22;
  --panel-2: #1c2330;
  --border: #2d333b;
  --text: #e6edf3;
  --muted: #8b949e;
  --accent: #4493f8;
  --ok: #3fb950;
  --bad: #f85149;
  --warn: #d29922;
  --radius: 10px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }
.muted { color: var(--muted); }
.error { color: var(--bad); min-height: 1.2em; margin: 0.5rem 0 0; }
.ok-text { color: var(--ok); }
.warn-text { color: var(--warn); }

/* --- login ---------------------------------------------------------------- */

.login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.login-card {
  width: min(24rem, 100%);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2rem;
}

.login-card h1 { margin: 0 0 0.25rem; font-size: 1.4rem; }
.login-card p { margin-top: 0; }

label { display: block; margin: 1rem 0 0; font-size: 0.9rem; color: var(--muted); }

input, select {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.6rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-size: 1rem;
}

input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

button {
  margin-top: 1.25rem;
  padding: 0.6rem 1.1rem;
  background: var(--accent);
  border: none;
  border-radius: 6px;
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}

button:hover { filter: brightness(1.1); }
button:disabled { opacity: 0.5; cursor: default; }

/* The sign-in door is an anchor, not a button: it is a plain navigation to
   /session/start, and making it a real link means it works before any script
   has run and can be opened the way any link can. It borrows the button's
   look because it is the one action on that card. */
a.button {
  display: block;
  margin-top: 1.25rem;
  padding: 0.6rem 1.1rem;
  background: var(--accent);
  border-radius: 6px;
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  text-align: center;
  text-decoration: none;
}

a.button:hover { filter: brightness(1.1); }

button.ghost {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  margin: 0;
}

button.danger { background: var(--bad); }
button.small { padding: 0.3rem 0.7rem; font-size: 0.85rem; margin: 0; }

/* --- shell ---------------------------------------------------------------- */

:root { --topbar: 3rem; }

.topbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: var(--topbar);
  padding: 0.4rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  position: sticky;
  top: 0;
  z-index: 30;
}

.brand { font-size: 1.05rem; letter-spacing: 0.02em; }
.brand b { color: var(--accent); }

/* The account menu: the address is the summary, the pop-over holds the two
   things that are about the operator rather than the estate. */
.account { margin-left: auto; position: relative; min-width: 0; }
.account > summary {
  list-style: none;
  cursor: pointer;
  font-size: 0.85rem;
  padding: 0.3rem 0.6rem;
  border: 1px solid transparent;
  border-radius: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 18rem;
}
.account > summary::-webkit-details-marker { display: none; }
.account > summary::after { content: " ▾"; opacity: 0.6; }
.account[open] > summary { border-color: var(--border); background: var(--bg); }
.account-pop {
  position: absolute;
  right: 0;
  top: calc(100% + 0.35rem);
  min-width: 11rem;
  display: grid;
  gap: 0.25rem;
  padding: 0.5rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 28px rgb(0 0 0 / 0.45);
}
.account-pop a {
  display: block;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
}
.account-pop a:hover { background: var(--panel-2); }
.account-pop button { width: 100%; }

/* The sidebar. A grid of two columns on a desk; on a phone the same element
   slides in as a drawer, so there is one menu and not two. */
.body {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  min-height: calc(100dvh - var(--topbar));
}

.menu {
  position: sticky;
  top: var(--topbar);
  align-self: start;
  max-height: calc(100dvh - var(--topbar));
  overflow-y: auto;
  padding: 0.6rem 0.5rem 1.5rem;
  border-right: 1px solid var(--border);
  background: var(--panel);
  font-size: 0.92rem;
}

.menu details { margin: 0.15rem 0; }
.menu summary {
  list-style: none;
  cursor: pointer;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
}
.menu summary::-webkit-details-marker { display: none; }
.menu summary::after { content: "▾"; font-size: 0.7rem; opacity: 0.7; }
.menu details:not([open]) summary::after { content: "▸"; }
.menu summary:hover { color: var(--text); }

.menu a, .menu .soon {
  display: block;
  padding: 0.35rem 0.6rem 0.35rem 1.1rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.menu .lone a { padding-left: 0.6rem; font-weight: 500; }
.menu a:hover { background: var(--panel-2); }
.menu a.active { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); font-weight: 500; }
.menu a.ext::after { content: " ↗"; color: var(--muted); font-size: 0.85em; }
.menu .soon { color: var(--muted); opacity: 0.6; cursor: default; white-space: normal; }
.menu .soon::after { content: " soon"; font-size: 0.7em; letter-spacing: 0.05em; text-transform: uppercase; }
.menu a:focus-visible, .menu summary:focus-visible, .account > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.menu-toggle { display: none; font-size: 1.1rem; line-height: 1; padding: 0.3rem 0.6rem; }
.backdrop { display: none; }

@media (max-width: 899px) {
  .body { grid-template-columns: minmax(0, 1fr); }
  .menu-toggle { display: inline-block; }
  .menu {
    position: fixed;
    top: var(--topbar);
    left: 0;
    bottom: 0;
    width: min(18rem, 85vw);
    max-height: none;
    z-index: 25;
    transform: translateX(-100%);
    transition: transform 160ms ease;
    box-shadow: none;
  }
  body.menu-open .menu { transform: none; box-shadow: 0 0 40px rgb(0 0 0 / 0.5); }
  .backdrop {
    display: block;
    position: fixed;
    inset: var(--topbar) 0 0 0;
    background: rgb(0 0 0 / 0.5);
    z-index: 20;
  }
  .backdrop[hidden] { display: none; }
  @media (prefers-reduced-motion: reduce) { .menu { transition: none; } }
}

/* `.tabs` is kept for the AI Studio page's own sub-tabs (`.tabs.sub`); the
   shell's tab strip it used to style is gone. */
.tabs {
  display: flex;
  gap: 0.25rem;
  padding: 0.5rem 1rem 0;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  overflow-x: auto;
}

.tabs a {
  padding: 0.5rem 0.9rem;
  color: var(--muted);
  text-decoration: none;
  border-radius: 8px 8px 0 0;
  white-space: nowrap;
}

.tabs a.active { color: var(--text); background: var(--bg); border: 1px solid var(--border); border-bottom-color: var(--bg); margin-bottom: -1px; }

.view { padding: 1rem 1.25rem; max-width: 72rem; width: 100%; margin: 0 auto; min-width: 0; }

/* Overview's wall, one band per project. The band label is the same voice as
   the sidebar's folds, so the two read as the same map. */
.wall-group { margin-bottom: 0.9rem; }
.wall-group h3 {
  margin: 0 0 0.4rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.wall-group h3 .bad-count { color: var(--bad); margin-left: 0.4rem; }

/* Coverage bars on the Languages page: a share of strings served, so the
   fill is the fact and the colour is only a hint about how far from done. */
.bar { display: inline-block; vertical-align: middle; width: 9rem; height: 0.55rem; margin-right: 0.5rem; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.bar span { display: block; height: 100%; background: var(--warn); }
.bar span.full { background: var(--ok); }
.bar span.half { background: var(--accent); }
.bar span.low { background: var(--warn); }

h2 { font-size: 1.1rem; margin: 1.5rem 0 0.75rem; }
h2:first-child { margin-top: 0.25rem; }

/* --- panels, stats, tables ------------------------------------------------ */

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: 0.6rem; }

.stat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.75rem 0.9rem;
}

.stat .n { font-size: 1.5rem; font-weight: 700; }
.stat .l { color: var(--muted); font-size: 0.8rem; }

.wall { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.6rem; }

.tile {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
}

.tile .dot { width: 0.7rem; height: 0.7rem; border-radius: 50%; flex: none; }
.tile.up .dot { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.tile.down .dot { background: var(--bad); box-shadow: 0 0 8px var(--bad); }
.tile.down { border-color: var(--bad); }
.tile .name { font-weight: 600; font-size: 0.9rem; white-space: nowrap; }
/* A latency or an error code, never a sentence: the full error rides the
   tile's title, so a long one truncates here instead of stretching the row. */
.tile .lat { margin-left: auto; color: var(--muted); font-size: 0.8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 9rem; }

/* Funding deadlines borrow the health tile so the front page has one visual
   grammar, with two differences: grant names are sentences rather than service
   handles, so they wrap instead of truncating, and the countdown is the point
   of the tile, so it is never dimmed to muted grey. */
.deadlines { grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); margin: 0.75rem 0; }
.tile.deadline { align-items: flex-start; }
.tile.deadline .dot { background: var(--warn); margin-top: 0.25rem; }
.tile.deadline .name { white-space: normal; line-height: 1.35; }
/* The countdown never truncates — "in 2..." is the one thing on the tile that
   has to be read exactly — so it keeps its width and the name gives way. */
.tile.deadline .lat { color: var(--text); max-width: none; flex: none; overflow: visible; text-overflow: clip; }
/* Inside three days: the tile itself has to read as late, not just its text. */
.tile.deadline.urgent { border-color: var(--bad); }
.tile.deadline.urgent .dot { background: var(--bad); box-shadow: 0 0 8px var(--bad); }
.tile.deadline.urgent .lat { color: var(--bad); font-weight: 700; }

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
  margin-bottom: 1rem;
}

.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); }

table { border-collapse: collapse; width: 100%; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.55rem 0.8rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
th { color: var(--muted); font-weight: 600; font-size: 0.8rem; background: var(--panel); position: sticky; top: 0; }
tbody tr:hover { background: var(--panel-2); }
tbody tr.clickable { cursor: pointer; }
tr:last-child td { border-bottom: none; }

.badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  border: 1px solid var(--border);
}

.badge.active, .badge.up, .badge.ACTIVE { color: var(--ok); border-color: var(--ok); }
.badge.suspended, .badge.down, .badge.BANNED, .badge.blocked { color: var(--bad); border-color: var(--bad); }
.badge.PENDING, .badge.paused, .badge.unknown { color: var(--warn); border-color: var(--warn); }

.row { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: end; }
.row label { margin: 0; flex: 1 1 10rem; }
.row button { margin-top: 0; align-self: end; }

/* The Contact page's chips. A chip reads as a state rather than as an action:
   the selected one is solid, the rest are ghosts, and the number beside each is
   how many of that kind are in the STORE — not how many are on this page. It is
   the count that tells an operator there is something waiting, so it has to be
   the true one. */
button.chip { padding: 0.3rem 0.75rem; border-radius: 999px; font-size: 0.85rem; margin: 0; }
button.chip b { margin-left: 0.2rem; font-weight: 700; opacity: 0.75; }

/* Its own row above the free-text filter, and allowed to wrap: the chips are
   built from whatever kinds came back, so how many there are is not something
   this stylesheet gets to assume. */
#bug-kinds { margin-bottom: 0.75rem; align-items: center; }

.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.75rem; }

.crumbs { margin-bottom: 0.75rem; font-size: 0.9rem; }
.crumbs a { color: var(--accent); text-decoration: none; cursor: pointer; }

.small { font-size: 0.85rem; }

/* Reasons are sentences, not identifiers, so this column wraps while the
   rest of the table stays on one line. */
td.wrap { white-space: normal; min-width: 18rem; }

a.evidence { color: var(--accent); cursor: pointer; text-decoration: underline; }

.evidence-dump {
  margin: 0;
  padding: 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--muted);
  max-height: 22rem;
  overflow: auto;
}

/* Secrets and recovery codes: monospace and selectable, since the whole point
   is copying them accurately. */
.secret {
  display: inline-block;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  user-select: all;
  word-break: break-all;
  line-height: 1.8;
}

details summary { cursor: pointer; }

.note {
  border-inline-start: 3px solid var(--warn);
  background: var(--panel);
  padding: 0.6rem 0.9rem;
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 0.9rem;
  margin: 0.75rem 0;
}

.toast {
  position: fixed;
  inset-block-end: 1rem;
  inset-inline-start: 50%;
  transform: translateX(-50%);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
  z-index: 100;
  box-shadow: 0 4px 24px rgb(0 0 0 / 0.5);
}
.toast.bad { border-color: var(--bad); }

@media (max-width: 640px) {
  .view { padding: 0.75rem; }
  th, td { padding: 0.5rem 0.6rem; }
}

/* --- schema designer ------------------------------------------------------ */

.field-row {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.5rem;
  background: var(--bg);
}

.field-row > summary {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  flex-wrap: wrap;
  cursor: pointer;
  list-style: none;
}

/* The marker is replaced by the row's own layout; leaving both makes the
   summary jump horizontally when it opens. */
.field-row > summary::-webkit-details-marker { display: none; }
.field-row[open] > summary { margin-bottom: 0.75rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; }

.field-row textarea {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.5rem 0.65rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85rem;
}

.field-row label input[type="checkbox"] { width: auto; margin-top: 0.5rem; }

a.schema-link { color: var(--accent); text-decoration: none; }
a.schema-link:hover { text-decoration: underline; }

/*
 * Bug reports. A report is prose somebody typed, not a data dump, so the body
 * wraps and keeps the normal text colour — `.evidence-dump` above is muted
 * monospace, which is right for a machine's output and wrong for a person's.
 */
.report-body {
  margin: 0 0 1rem;
  padding: 0.9rem 1rem;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font: inherit;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 24rem;
  overflow: auto;
}

/* Table cells are nowrap globally, which a 280-character preview would drag
   the whole table sideways with — pushing the "design" badge past the scroll
   edge, so telling whether a report has one meant scrolling to find out.
   `width:100%` with `max-width:0` is the table idiom for "take whatever the
   other columns leave and truncate to it": the fixed columns size naturally,
   this one absorbs the rest, and the row fits at any window width. */
.bug-preview {
  width: 100%;
  max-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The environment facts: a label column and a value column, not a data grid. */
.facts { width: auto; }
.facts th { position: static; background: none; padding-left: 0; width: 9rem; }
.facts td { white-space: normal; }
/* User agents are one long unbroken token and will not wrap on their own. */
.facts .ua { font-size: 0.8rem; color: var(--muted); overflow-wrap: anywhere; }
/* --- AI Studio ------------------------------------------------------------ */

/*
 * The only page here with long-form text input, so it is also the only one
 * that needed a textarea style. Monospace on purpose: what goes in these boxes
 * is instructions to a model, where a stray line break or a doubled space is
 * a thing somebody has to be able to see.
 */
textarea {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.6rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font: 13px/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  resize: vertical;
}

textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
textarea:disabled, input:disabled { opacity: 0.55; }

/* A second tab strip inside the view, distinguished from the shell's by
   sitting on the page background rather than on the top bar. */
.tabs.sub {
  background: transparent;
  padding: 0 0 0.5rem;
  margin-bottom: 1rem;
}

.ai-status {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  align-items: center;
}

.ai-warn { border-color: var(--warn); }

.ai-block { border-left: 3px solid var(--accent); }
/* A block that is switched off still shows its text, faded — hiding it would
   make "what will actually be sent" a thing you have to reconstruct. */
.ai-block.off { border-left-color: var(--border); opacity: 0.6; }

.ai-block-head { display: flex; gap: 0.75rem; align-items: start; }
.ai-block-title { flex: 1; min-width: 0; }
.ai-block-title .badge { margin-left: 0.4rem; vertical-align: 1px; }

.ai-order { display: flex; flex-direction: column; gap: 0.2rem; }
.ai-order button { padding: 0.1rem 0.45rem; line-height: 1.3; }

.ai-switch { display: flex; gap: 0.5rem; align-items: start; margin: 0; }
.ai-switch input { width: auto; margin: 0.2rem 0 0; flex: none; }
.ai-switch.block { margin-top: 1rem; }
.ai-switch.block span { color: var(--text); }

.ai-choice { display: flex; gap: 0.6rem; align-items: start; margin: 0 0 0.9rem; color: var(--text); font-size: 0.9rem; }
.ai-choice input { width: auto; margin: 0.25rem 0 0; flex: none; }

.ai-keys { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: 0.35rem; }
.ai-key { display: flex; gap: 0.4rem; align-items: center; margin: 0; }
.ai-key input { width: auto; margin: 0; flex: none; }

/* The bar that does things. Sticky, because the block list is long and the
   distance between "I have finished editing" and "Publish" should not be a
   scroll to the bottom of a page whose length depends on what you typed. */
.ai-bar {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0;
  background: var(--panel-2);
}

.ai-bar .grow { flex: 1; }
.ai-bar button { margin-top: 0; }

code { background: var(--panel-2); padding: 0.05rem 0.3rem; border-radius: 4px; font-size: 0.85em; }

/* The Contact page's filter bar: two rows of chips over a row of inputs. The
   label sits beside its chips rather than above them, so the two rows read as
   two questions ("which source?", "which type?") rather than as a stack of
   unrelated buttons. */
.filters { display: grid; gap: 0.7rem; }
.filter-line { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 0.6rem; align-items: start; }
.filter-label { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.7; padding-top: 0.35rem; }
.filters .chips { gap: 0.4rem; }
.filters form.row label { flex: 0 1 12rem; }
.filters form.row label:last-of-type { flex: 1 1 16rem; }
#c-count .warn { color: var(--warn); }
