/* ==========================================================================
   nolifeidk.eu — admin panel
   Loaded AFTER ../style.css and only adds what the public page doesn't have.
   Tokens, .topbar, .btn*, .card*, .section*, .tags, .footer, .status-dot and
   every breakpoint come from style.css.
   ========================================================================== */

:root {
  --up:   #4ade80;
  --down: #f87171;
  --warn: #fbbf24;
  --idle: #64748b;
}

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

/*
 * Panel pages never set the .js class that gates style.css's scroll-reveal, so
 * sections are visible already. Pinned explicitly anyway: a dashboard should
 * appear at once, and this stays correct if the reveal rules change.
 */
.panel-body .section,
.panel-body .hero {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Panel pages are chrome, not prose — cap them wider than the landing page. */
.panel-main,
.panel-body .topbar,
.panel-body .footer {
  width: 100%;
  max-width: 84rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.panel-body .topbar { max-width: none; }

/*
 * style.css caps `main > section` at --content and gives it its own
 * padding-inline. Inside .panel-main that double-pads and re-narrows every
 * section, so hand width control back to the .panel-main container alone.
 */
.panel-main > section {
  max-width: none;
  padding-inline: 0;
  /* Tighter than the landing page: this is a tool, not a scrolling narrative. */
  padding-block: clamp(1.75rem, 3.5vh, 2.75rem);
}

.brand-tag {
  padding: 0.1rem 0.42rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: rgba(94, 234, 212, 0.08);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.nav-danger:hover { color: var(--down) !important; }
.nav-danger::after { background: var(--down) !important; }

/* Persistent version of style.css's hover underline, for the current tab. */
.topnav a.is-active { color: var(--text); }
.topnav a.is-active::after { transform: scaleX(1); }

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

/* ---------- Login gate ---------- */

.gate {
  display: grid;
  place-items: center;
  min-height: 76svh;
  padding: clamp(2rem, 8vh, 5rem) var(--gutter);
}

.gate-card {
  width: 100%;
  max-width: 25rem;
  padding: clamp(1.6rem, 4vw, 2.4rem);
  border: 1px solid var(--border);
  border-radius: 16px;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.035), rgba(255,255,255,0)),
    var(--surface);
  box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.8);
  text-align: center;
}

.gate-icon {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  margin: 0 auto 1.15rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: rgba(94, 234, 212, 0.07);
  color: var(--accent);
}

.gate-title {
  margin: 0 0 0.4rem;
  font-size: var(--step-2);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.gate-note {
  margin: 0 0 1.5rem;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.gate-note code {
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.06);
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--text);
}

.gate-error {
  margin: 0 0 1.15rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid rgba(248, 113, 113, 0.35);
  border-radius: 9px;
  background: rgba(248, 113, 113, 0.09);
  font-size: var(--step--1);
  color: #fca5a5;
}

.gate-form { display: grid; gap: 0.7rem; }

.gate-input {
  width: 100%;
  min-height: 46px;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.35);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--step-0);
  letter-spacing: 0.14em;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.gate-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(94, 234, 212, 0.14);
}

.gate-submit { width: 100%; }

/* ---------- Panel hero ---------- */

.panel-hero { padding-block: clamp(2rem, 6vh, 3.5rem) clamp(1.25rem, 3vh, 2rem); }

.panel-h1 {
  margin: 0;
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 3.1rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.panel-sub {
  margin: 0.55rem 0 0;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.panel-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  margin-top: 1.4rem;
}

.btn-sm {
  min-height: 38px;
  padding: 0.45rem 1rem;
  font-size: 0.82rem;
}

.btn-sm:disabled {
  opacity: 0.55;
  cursor: progress;
  transform: none;
}

.panel-checked {
  font-size: 0.76rem;
  color: var(--text-faint);
}

/* ---------- Service tiles ---------- */

.service {
  display: flex;
  flex-direction: column;
  /* .card is styled for a static block; these tiles are links. */
  color: inherit;
  text-decoration: none;
}

.service-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}

.service-top .card-icon { margin-bottom: 1rem; }

.service h3 {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
}

.service-arrow {
  font-size: 0.85em;
  color: var(--text-faint);
  transition: transform 0.3s var(--ease), color 0.3s var(--ease);
}

.service:hover .service-arrow {
  color: var(--accent);
  transform: translate(2px, -2px);
}

.service-meta { margin-top: auto; }

/* Empty metadata cells collapse so the row doesn't show blank pills. */
.service-meta .is-empty { display: none; }

.svc-state { text-transform: lowercase; }

/* ---------- Status dots ---------- */

.svc-dot {
  width: 9px;
  height: 9px;
  margin-top: 4px;
  border-radius: 50%;
  background: var(--idle);
  flex-shrink: 0;
  transition: background 0.3s var(--ease), box-shadow 0.3s var(--ease);
}

.svc-up {
  background: var(--up);
  box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.16);
}

.svc-down {
  background: var(--down);
  box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.16);
}

.svc-error {
  background: var(--warn);
  box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.16);
}

.svc-unknown { background: var(--idle); }

.svc-pending {
  background: var(--accent);
  animation: pulse 1.1s ease-in-out infinite;
}

/* Colour the state pill to match its dot. */
.service:has(.svc-up)    .svc-state { color: var(--up); }
.service:has(.svc-down)  .svc-state { color: var(--down); }
.service:has(.svc-error) .svc-state { color: var(--warn); }

/* ---------- Host stats ---------- */

.stats-note { margin-bottom: clamp(1.2rem, 3vh, 1.8rem); }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: clamp(0.7rem, 1.6vw, 1rem);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 1.05rem 1.15rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.stat-label {
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.stat-value {
  font-family: var(--font-mono);
  font-size: 1.02rem;
  font-weight: 500;
  color: var(--text);
  overflow-wrap: anywhere;
}

.stat-of { color: var(--text-faint); font-weight: 400; }

.stat-foot {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-faint);
}

.meter {
  display: block;
  width: 100%;
  height: 5px;
  margin-top: 0.2rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  overflow: hidden;
}

.meter-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.5s var(--ease);
}

.meter-warn .meter-fill { background: var(--warn); }
.meter-crit .meter-fill { background: var(--down); }

/* ---------- Wiki ---------- */

.wiki-toolbar { justify-content: space-between; }

.wiki-search { margin-left: auto; }

.wiki-search-input {
  min-width: 14rem;
  min-height: 38px;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--text);
  font-family: inherit;
  font-size: 0.82rem;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.wiki-search-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(94, 234, 212, 0.14);
}

.wiki-card {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  color: inherit;
  text-decoration: none;
}

.wiki-card h3 { margin: 0; }
.wiki-card p { margin: 0; flex-grow: 1; }

.wiki-updated {
  display: block;
  font-size: 0.72rem;
  color: var(--text-faint);
}

.wiki-view-toolbar { justify-content: flex-start; }

.wiki-delete-form { margin: 0; }

.wiki-delete-btn:hover {
  color: var(--down);
  border-color: rgba(248, 113, 113, 0.4);
  background: rgba(248, 113, 113, 0.08);
}

/* ---------- Wiki editor ---------- */

.wiki-editor {
  display: grid;
  gap: 0.5rem;
  max-width: 52rem;
}

.wiki-label,
.field-label {
  margin-top: 0.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.field-hint { text-transform: none; letter-spacing: normal; font-weight: 400; }

.wiki-title-input,
.wiki-body-input,
.field-input,
.field-textarea {
  width: 100%;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--text);
  font-family: inherit;
  font-size: var(--step--1);
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.wiki-body-input,
.field-textarea {
  font-family: var(--font-mono);
  line-height: 1.6;
  resize: vertical;
}

.wiki-title-input:focus,
.wiki-body-input:focus,
.field-input:focus,
.field-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(94, 234, 212, 0.14);
}

.wiki-image-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.2rem;
}

.wiki-image-status {
  font-size: 0.74rem;
  color: var(--text-faint);
}

/* ---------- Wiki categories ---------- */

.wiki-cat-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 1.1rem;
}

.wiki-cat-pill {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.022);
  font-size: 0.76rem;
  color: var(--text-dim);
  text-transform: capitalize;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease), background 0.25s var(--ease);
}

.wiki-cat-pill:hover { color: var(--text); border-color: #38424f; }

.wiki-cat-pill.is-active {
  color: var(--accent);
  border-color: rgba(94, 234, 212, 0.4);
  background: rgba(94, 234, 212, 0.08);
}

.wiki-card-cat {
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ---------- Wiki sections ---------- */

/* Above the category pills and visibly heavier than them: the section is the
   first decision, the category a refinement of it. */
.wiki-sections {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 1.2rem;
  padding: 0.3rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.22);
  /* So a narrow phone scrolls the tabs rather than the whole page. */
  max-width: max-content;
}

.wiki-section-tab {
  padding: 0.38rem 0.95rem;
  border-radius: 9px;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-dim);
  white-space: nowrap;
  transition: color 0.25s var(--ease), background 0.25s var(--ease);
}

.wiki-section-tab:hover { color: var(--text); background: rgba(255, 255, 255, 0.04); }

.wiki-section-tab.is-active {
  color: var(--bg);
  background: var(--accent);
}

.wiki-section-tab.is-active .pill-count { opacity: 0.7; }

/* On the All tab a group heading says which half it belongs to. */
.wiki-group-section {
  margin-right: 0.45rem;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ---------- Wiki attachments ---------- */

.wiki-attachments,
.wiki-backlinks {
  max-width: 74ch;
  margin-top: 1.6rem;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.wiki-attach-title {
  margin: 0 0 0.7rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.wiki-file-list {
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.wiki-file {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.2);
  font-size: 0.82rem;
}

.wiki-file-kind {
  flex: none;
  min-width: 3.1rem;
  padding: 0.12rem 0.4rem;
  border-radius: 5px;
  background: rgba(94, 234, 212, 0.1);
  color: var(--accent);
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  text-align: center;
}

/* minmax(0)'s flexbox twin: a long filename truncates instead of shoving the
   size and the buttons off the row. */
.wiki-file-name {
  flex: 1 1 12rem;
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wiki-file-name:hover { color: var(--accent); }

.wiki-file-size,
.wiki-file-when {
  flex: none;
  font-size: 0.7rem;
  color: var(--text-faint);
}

.wiki-file-insert,
.wiki-file-dl {
  flex: none;
  padding: 0.16rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  cursor: pointer;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.wiki-file-insert:hover,
.wiki-file-dl:hover { color: var(--accent); border-color: rgba(94, 234, 212, 0.4); }

.wiki-backlink-list {
  display: grid;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.86rem;
}

.wiki-backlink-list a { color: var(--text); }
.wiki-backlink-list a:hover { color: var(--accent); }
.wiki-backlink-list .mono { margin-left: 0.5rem; font-size: 0.68rem; color: var(--text-faint); }

/* A note about files picked up from the drop folder, good news and bad. */
.wiki-drop-note {
  display: grid;
  gap: 0.25rem;
  max-width: 60ch;
  margin-top: 1rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid rgba(94, 234, 212, 0.28);
  border-radius: 10px;
  background: rgba(94, 234, 212, 0.06);
  font-size: 0.8rem;
  color: var(--text-dim);
}

.wiki-drop-bad { color: var(--warn); }

/* ---------- Wiki file library ---------- */

.wiki-file-library .wiki-file-row { gap: 0.55rem 0.7rem; }

.wiki-file-owner {
  flex: 1 1 10rem;
  min-width: 0;
  overflow: hidden;
  font-size: 0.76rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wiki-file-owner a { color: var(--text-dim); }
.wiki-file-owner a:hover { color: var(--accent); }
.wiki-file-owner .mono { margin-left: 0.4rem; font-size: 0.66rem; color: var(--text-faint); }

.wiki-file-orphan { color: var(--warn); }

.wiki-file-attach,
.wiki-file-del {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  min-width: 0;
}

/* A <select> is as wide as its widest <option>, and these options are page
   titles. min-width:0 plus a zero flex basis is what lets it shrink instead of
   dragging the row — and the row's parents — past the edge of the screen. */
.wiki-file-select {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
  max-width: 13rem;
  padding: 0.28rem 0.45rem;
  font-size: 0.74rem;
}

/* ---------- Wiki: a published page that disagrees with this one ---------- */

/* Warm rather than red: nothing is broken and nothing has been lost, there is
   simply a decision to make. */
.wiki-import-note {
  max-width: 74ch;
  margin-bottom: 1.4rem;
  padding: 1.1rem 1.25rem;
  border: 1px solid rgba(251, 191, 36, 0.35);
  border-radius: var(--radius);
  background: rgba(251, 191, 36, 0.07);
}

.wiki-import-note p {
  margin: 0 0 0.9rem;
  font-size: 0.86rem;
  color: var(--text-dim);
}

.wiki-import-note .wiki-attach-title { color: var(--warn); }
.wiki-import-note .panel-toolbar { margin-top: 0.9rem; }

.wiki-import-preview summary {
  cursor: pointer;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.wiki-import-preview summary:hover { color: var(--accent); }

/* The preview is a quotation of another page, so it sits inside this one rather
   than pretending to be the sheet itself. */
.wiki-import-preview .wiki-article {
  max-width: 100%;
  margin-top: 0.8rem;
  max-height: 26rem;
  overflow-y: auto;
}

/* ---------- Wiki: [[links]] between pages ---------- */

/* A page link is a link to somewhere you already wrote, so it gets the accent
   and a soft underline rather than looking like an outbound one. */
.wiki-article .wiki-link {
  border-bottom: 1px solid rgba(94, 234, 212, 0.3);
  color: var(--accent);
  text-decoration: none;
}

.wiki-article .wiki-link:hover { border-bottom-color: var(--accent); }

/* A link to a page that isn't there reads as broken rather than as prose, so a
   typo in a page name is visible the first time you look at the page. */
.wiki-link.is-missing {
  color: var(--down);
  border-bottom: 1px dashed rgba(248, 113, 113, 0.55);
  cursor: help;
}

/* ---------- Wiki: pin button ---------- */

.wiki-pin-btn.is-pinned {
  color: var(--warn);
  border-color: rgba(251, 191, 36, 0.4);
  background: rgba(251, 191, 36, 0.08);
}

/* ---------- Wiki: [[ link completion ---------- */

/* Absolutely positioned, so a list appearing mid-sentence never nudges the
   textarea or the buttons under it. .wiki-editor is the containing block. */
.wiki-editor { position: relative; }

.wiki-link-suggest {
  position: absolute;
  z-index: 40;
  left: 0;
  width: min(26rem, 100%);
  max-height: 15rem;
  margin: 0;
  padding: 0.25rem;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
  list-style: none;
}

.wiki-link-option {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.35rem 0.55rem;
  border-radius: 7px;
  font-size: 0.82rem;
  cursor: pointer;
}

.wiki-link-option.is-active { background: rgba(94, 234, 212, 0.12); }

.wiki-link-option-title {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wiki-link-option-where {
  flex: none;
  font-size: 0.66rem;
  color: var(--text-faint);
}

@media (max-width: 620px) {
  /* The tab strip is the one thing allowed to scroll sideways; the page isn't. */
  .wiki-sections {
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .wiki-sections::-webkit-scrollbar { display: none; }

  .wiki-file-select { max-width: 100%; }
  .wiki-file-attach { flex: 1 1 100%; }

  /* A file row carries seven things — badge, name, size, date, owning page,
     a page picker and two buttons. On a 320px phone no arrangement of those
     fits side by side, and flex-wrap alone still let the widest line push the
     page. Below this width the row stacks instead, and the name wraps rather
     than being cut off with an ellipsis nobody can expand. */
  .wiki-file {
    flex-direction: column;
    /* nowrap matters: in a column container "wrap" packs items into side-by-side
       *columns*, and the 100% basis below then gave each one its own — which is
       how a stacked row ended up wider than the screen rather than narrower. */
    flex-wrap: nowrap;
    align-items: stretch;
  }

  .wiki-file-attach,
  .wiki-file-del { flex: 0 0 auto; }

  .wiki-file-name {
    flex: none;
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .wiki-file-kind { align-self: flex-start; }

  .wiki-file-insert,
  .wiki-file-dl { align-self: flex-start; }
}

/* ---------- Wiki article (rendered Markdown) ---------- */

/* A page you read, rather than text the background shows through. The panel's
   other surfaces are cards of data; this one is a document, so it gets its own
   sheet, its own measure and its own rhythm. */
.wiki-article {
  /* Between --text and --text-dim: enough contrast to read a long page
     without the glare of near-white on a dark sheet. */
  --ink: #d3dae4;

  max-width: 74ch;
  margin: 0;
  padding: clamp(1.4rem, 3.5vw, 2.6rem) clamp(1.15rem, 3vw, 2.4rem);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-0);
  line-height: 1.75;
}

/* Nothing should push the sheet's own edges around. */
.wiki-article > :first-child { margin-top: 0; }
.wiki-article > :last-child { margin-bottom: 0; }

.wiki-article h1,
.wiki-article h2,
.wiki-article h3,
.wiki-article h4 {
  color: var(--text);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

/* Three visibly different sizes. They used to be 1.1rem, 1rem and 1rem, which
   meant an h2 was the same size as the sentence under it and the page had no
   structure you could see at a glance. */
.wiki-article h1 {
  margin: 2.2rem 0 0.9rem;
  font-size: var(--step-2);
}

/* A rule above every section heading: the divider that says one thing has
   ended and another has started. */
.wiki-article h2 {
  margin: 2.4rem 0 0.9rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-size: var(--step-1);
}

.wiki-article h1 + h2,
.wiki-article > h2:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.wiki-article h3 {
  margin: 1.8rem 0 0.6rem;
  font-size: calc(var(--step-0) * 1.06);
}

.wiki-article h4 {
  margin: 1.5rem 0 0.5rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.wiki-article p { margin: 0 0 1.15rem; }

.wiki-article ul,
.wiki-article ol {
  margin: 0 0 1.15rem;
  padding-left: 1.4rem;
}

.wiki-article li { margin-bottom: 0.45rem; }
.wiki-article li:last-child { margin-bottom: 0; }
.wiki-article li > ul,
.wiki-article li > ol { margin: 0.45rem 0 0; }
.wiki-article ul li::marker { color: var(--accent); }
.wiki-article ol li::marker { color: var(--text-faint); font-variant-numeric: tabular-nums; }

.wiki-article strong { color: var(--text); font-weight: 600; }
.wiki-article em { font-style: italic; }

.wiki-article code {
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.06);
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--text);
}

/* A long identifier in inline code has nowhere to wrap — no spaces, no hyphens —
   so "objednavka.getZakaznik().getAdresa()" pushed the whole page sideways on a
   phone. Inline code may break mid-token; a fenced block still scrolls instead,
   because breaking a line of code changes what it says. */
.wiki-article :not(pre) > code { overflow-wrap: anywhere; }

/* And the same for a bare long word or URL in ordinary prose. */
.wiki-article { overflow-wrap: break-word; }

.code-block {
  margin: 0 0 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.code-block-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--border-soft);
  background: var(--surface-2);
}

.code-block-lang {
  margin-right: auto;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.code-copy-btn {
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background 0.2s var(--ease);
}

.code-copy-btn:hover {
  color: var(--text);
  border-color: var(--accent);
}

.code-copy-btn.is-copied {
  color: var(--accent);
  border-color: var(--accent);
}

.code-block pre {
  margin: 0;
  padding: 0.9rem 1rem;
  overflow-x: auto;
}

.code-block pre code {
  padding: 0;
  background: none;
  font-size: 0.85em;
}

.wiki-article img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 0 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.wiki-article blockquote {
  margin: 0 0 1.15rem;
  padding: 0.6rem 0 0.6rem 1.1rem;
  border-left: 2px solid var(--accent);
  color: var(--text-dim);
  font-style: italic;
}

.wiki-article blockquote p:last-child { margin-bottom: 0; }

.wiki-article a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.wiki-article hr {
  margin: 2rem 0;
  border: 0;
  border-top: 1px solid var(--border);
}

/* Tables. The wrapper scrolls rather than the page, so a wide table on a phone
   doesn't drag the whole layout sideways. */
.wiki-table-wrap {
  margin: 0 0 1.4rem;
  overflow-x: auto;
  scrollbar-width: thin;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.wiki-article table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92em;
}

.wiki-article thead th {
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-soft);
  color: var(--text);
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}

.wiki-article tbody td {
  padding: 0.55rem 0.85rem;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: top;
}

.wiki-article tbody tr:last-child td { border-bottom: 0; }
.wiki-article tbody tr:hover td { background: rgba(255, 255, 255, 0.02); }

/* Give the code blocks the sheet's margins rather than the page's, and make it
   obvious a long command scrolls instead of just ending mid-word. */
.wiki-article .code-block {
  margin-bottom: 1.4rem;
  background: var(--bg-soft);
}

.wiki-article .code-block pre { scrollbar-width: thin; }

/* Breathing room between the actions and the page they act on — they used to
   sit directly on top of the first line and read as part of it. */
.wiki-view-toolbar { margin-bottom: 1.5rem; }

.wiki-article + .wiki-updated { margin-top: 1rem; }

/* ---------- Wiki: rewrite with AI ---------- */

.wiki-ai-panel {
  margin-top: 0.5rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(94, 234, 212, 0.03);
}

.wiki-ai-panel .field-label { margin-top: 0; }

.wiki-ai-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.wiki-ai-row .field-input { flex: 1 1 auto; }

.wiki-ai-status {
  margin: 0.5rem 0 0;
  min-height: 1.2em;
  font-size: 0.74rem;
  color: var(--text-faint);
}

/* ---------- AI settings + chat ---------- */

.ai-saved-note {
  margin: 0 0 1rem;
  font-size: var(--step--1);
  color: var(--accent);
}

.ai-chat {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  max-width: 52rem;
}

.ai-chat-log {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-height: 8rem;
  max-height: 32rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow-y: auto;
}

.ai-bubble {
  max-width: 85%;
  padding: 0.6rem 0.85rem;
  border-radius: 12px;
  font-size: var(--step--1);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.ai-bubble-user {
  align-self: flex-end;
  background: rgba(94, 234, 212, 0.12);
  color: var(--text);
}

.ai-bubble-assistant {
  align-self: flex-start;
  background: var(--surface-2);
  color: var(--text);
}

.ai-bubble-error {
  align-self: flex-start;
  border: 1px solid rgba(248, 113, 113, 0.35);
  background: rgba(248, 113, 113, 0.09);
  color: #fca5a5;
}

.ai-chat-form {
  display: flex;
  gap: 0.5rem;
  align-items: flex-end;
}

.ai-chat-input { flex: 1 1 auto; resize: vertical; }

.ai-chat-status {
  min-height: 1.2em;
  font-size: 0.74rem;
  color: var(--text-faint);
}

/* ---------- Pulse ---------- */

.pulse-grid {
  display: grid;
  /* min(20rem, 100%) rather than a bare 20rem: on a narrow phone the track
     minimum would otherwise exceed the viewport and push the page sideways. */
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
  gap: 0.9rem;
  margin-bottom: 1.2rem;
}

.pulse-empty {
  margin: 0;
  font-size: var(--step--1);
  color: var(--text-faint);
}

.pulse-card {
  padding: 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.pulse-card.is-stale { opacity: 0.6; }

.pulse-card-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.9rem;
}

.pulse-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--up);
  box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.15);
  flex: none;
}

.pulse-card.is-stale .pulse-dot {
  background: var(--idle);
  box-shadow: none;
}

.pulse-name {
  margin: 0;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pulse-kind {
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.pulse-seen {
  margin-left: auto;
  font-size: 0.68rem;
  color: var(--text-faint);
}

.pulse-metrics {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}

.pulse-metric { min-width: 0; }

.pulse-metric-label {
  display: block;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.pulse-metric-value {
  display: block;
  margin: 0.15rem 0 0.3rem;
  font-family: var(--font-mono);
  font-size: 1.05rem;
  color: var(--text);
}

.pulse-spark {
  display: block;
  width: 100%;
  height: 28px;
  overflow: visible;
}

.pulse-spark-line {
  fill: none;
  stroke: var(--up);
  stroke-width: 1.4;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.pulse-spark-fill {
  fill: rgba(74, 222, 128, 0.12);
  stroke: none;
}

.pulse-metric.is-warn .pulse-spark-line { stroke: var(--warn); }
.pulse-metric.is-warn .pulse-spark-fill { fill: rgba(251, 191, 36, 0.12); }
.pulse-metric.is-warn .pulse-metric-value { color: var(--warn); }

.pulse-metric.is-crit .pulse-spark-line { stroke: var(--down); }
.pulse-metric.is-crit .pulse-spark-fill { fill: rgba(248, 113, 113, 0.14); }
.pulse-metric.is-crit .pulse-metric-value { color: var(--down); }

.pulse-metric.is-none .pulse-spark-line { stroke: var(--idle); }
.pulse-metric.is-none .pulse-metric-value { color: var(--text-faint); }

.pulse-detail {
  margin: 0.9rem 0 0;
  font-size: 0.68rem;
  line-height: 1.5;
  color: var(--text-faint);
  overflow-wrap: anywhere;
}

.pulse-setup {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.15);
}

.pulse-setup > summary {
  padding: 0.7rem 1rem;
  font-size: var(--step--1);
  color: var(--text-dim);
  cursor: pointer;
}

.pulse-setup > summary:hover { color: var(--text); }

.pulse-setup[open] > summary {
  border-bottom: 1px solid var(--border-soft);
  color: var(--text);
}

.pulse-setup > :not(summary) { margin-inline: 1rem; }
.pulse-setup > :last-child { margin-bottom: 1rem; }
.pulse-setup .prose { margin-top: 1rem; }

/* ---------- Notifications (ntfy) ---------- */

.ntfy-status {
  font-size: 0.7rem;
  color: var(--text-faint);
}

.ntfy-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}

.ntfy-filters .wiki-search-input { flex: 1 1 16rem; min-width: 0; }

/* ---------- Notifications: chrome ---------- */

/* Any element given an explicit display needs this, or the hidden attribute
   stops working and panels that should be closed sit open. */
.panel-body [hidden] { display: none !important; }

.ntfy-unread {
  display: inline-block;
  min-width: 1.15rem;
  margin-left: 0.3rem;
  padding: 0 0.28rem;
  border-radius: 999px;
  background: var(--down);
  color: #0a0c0f;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 600;
  text-align: center;
}

.ntfy-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--idle);
  flex: none;
}

.ntfy-dot.is-live { background: var(--up); box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.15); }
.ntfy-dot.is-bad  { background: var(--down); box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.15); }

.ntfy-snooze-wrap { position: relative; }

.ntfy-snooze-menu {
  position: absolute;
  top: calc(100% + 0.3rem);
  left: 0;
  z-index: 30;
  display: grid;
  min-width: 7rem;
  padding: 0.25rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}

.ntfy-snooze-menu button {
  padding: 0.35rem 0.6rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: var(--step--1);
  text-align: left;
  cursor: pointer;
}

.ntfy-snooze-menu button:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }

.ntfy-confirmbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.8rem;
  padding: 0.5rem 0.8rem;
  border: 1px solid rgba(248, 113, 113, 0.4);
  border-radius: var(--radius);
  background: rgba(248, 113, 113, 0.08);
  font-size: var(--step--1);
  color: var(--text);
}

.ntfy-confirmbar button { margin-left: auto; }

/* ---------- Notifications: publish dialog ---------- */

.ntfy-veil {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.6);
}

.ntfy-dialog {
  position: fixed;
  z-index: 41;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(32rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.2rem 1.3rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
}

.ntfy-dialog-title {
  margin: 0 0 0.4rem;
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--text);
}

.ntfy-dialog-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 0.4rem;
}

.ntfy-dialog-row .ntfy-opt { flex: 1 1 10rem; }

.ntfy-dialog-note {
  min-height: 1.1em;
  margin: 0.5rem 0 0;
  font-size: 0.7rem;
  color: var(--down);
}

.ntfy-toast {
  position: fixed;
  z-index: 50;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.55rem 1rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  font-size: var(--step--1);
  color: var(--text);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}

.ntfy-toast.is-bad { border-color: rgba(248, 113, 113, 0.5); color: var(--down); }

/* ---------- Notifications: settings panel ---------- */

.ntfy-settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: 0.9rem;
}

.ntfy-run {
  min-width: 0;
  margin: 0;
  padding: 0.85rem 1rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

/* The settings fieldsets. This rule was lost when the packed-run card took
   the .ntfy-group name for a while; .ntfy-run below is that card, and the two
   deliberately share a look. min-width keeps a long <select> option or a row
   of sliders from widening the grid column and tipping the page sideways. */
.ntfy-group {
  min-width: 0;
  margin: 0;
  padding: 0.85rem 1rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.ntfy-group-wide { grid-column: 1 / -1; }

.ntfy-group legend {
  padding: 0 0.35rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.ntfy-opt {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.5rem;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.ntfy-opt > span { flex: none; min-width: 5.5rem; }
.ntfy-opt .field-input {
  min-width: 0;
  max-width: 100%;
  padding: 0.35rem 0.5rem;
  font-size: 0.78rem;
}
.ntfy-opt input[type="range"] { flex: 1 1 auto; min-width: 0; }

/* --- speech: the two voice engines, and piper's shaping sliders ---------- */

.ntfy-voice-pane {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--border);
}

.ntfy-shaping {
  margin-top: 0.6rem;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.ntfy-shaping > summary {
  cursor: pointer;
  padding: 0.25rem 0;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.ntfy-shaping > summary:hover { color: var(--text); }

/* Fourteen sliders is a wall unless the numbers are readable at a glance. */
.ntfy-shaping .ntfy-opt > span { min-width: 6.5rem; font-size: 0.7rem; }

.ntfy-shape-val {
  flex: none;
  min-width: 3.2rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-align: right;
  color: var(--text-faint);
}

.ntfy-shaping .btn { margin-top: 0.7rem; }

.ntfy-group .field-hint {
  display: block;
  margin: 0.35rem 0 0;
  font-size: 0.7rem;
  color: var(--text-faint);
}

.ntfy-perm {
  margin: 0.4rem 0 0;
  font-size: 0.66rem;
  color: var(--text-faint);
}

.ntfy-prios {
  display: flex;
  gap: 0.3rem;
  margin-top: 0.5rem;
}

.ntfy-prio-box {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.15rem 0.35rem;
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-faint);
}

.ntfy-topic-settings {
  display: grid;
  /* Wide enough that the topic name stays readable — a mute switch you can't
     match to a topic is worse than no mute switch. */
  grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.ntfy-topic-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
}

.ntfy-topic-row > .mono {
  flex: 1 1 auto;
  /* Never ellipsised down to "ser…": the name is the whole point of the row. */
  min-width: 6.5rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.72rem;
  color: var(--text);
}

.ntfy-topic-row .field-input { flex: none; width: 5.5rem; }

.ntfy-topic-row .ntfy-opt { margin-top: 0; font-size: 0.7rem; }
.ntfy-topic-row .field-input { padding: 0.2rem 0.35rem; font-size: 0.7rem; }

.wiki-cat-pill.is-muted { opacity: 0.45; text-decoration: line-through; }
.wiki-cat-pill.is-chatty { border-color: rgba(251, 191, 36, 0.4); }

.ntfy-rate {
  margin-left: 0.3rem;
  font-size: 0.62rem;
  color: var(--text-faint);
}

.ntfy-spark-holder {
  display: inline-flex;
  align-items: center;
  margin-left: 0.3rem;
  vertical-align: middle;
}

.ntfy-spark {
  width: 34px;
  height: 10px;
  overflow: visible;
}

.ntfy-spark path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0.8;
}

.ntfy-day {
  margin: 1rem 0 0.2rem;
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.ntfy-day:first-child { margin-top: 0; }

.ntfy-run {
  min-width: 0;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.ntfy-run.is-high   { border-left-color: var(--warn); }
.ntfy-run.is-urgent { border-left-color: var(--down); }

.ntfy-run-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.7rem 1rem;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.ntfy-run-head:hover { background: rgba(255, 255, 255, 0.03); }

.ntfy-run-chev {
  flex: none;
  width: 0.9rem;
  color: var(--text-faint);
  transition: transform 0.15s var(--ease);
}

.ntfy-run.is-open .ntfy-run-chev { transform: rotate(90deg); }

.ntfy-run-count {
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--text);
}

.ntfy-run-sum {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.ntfy-run-span {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  color: var(--text-faint);
}

.ntfy-run-body {
  display: grid;
  gap: 0.4rem;
  padding: 0 0.6rem 0.6rem;
}

.ntfy-run-body .ntfy-msg { background: rgba(0, 0, 0, 0.2); }

/* Muting silences alerts and speech — it never hides the message, or there
   would be no way to find it again and turn it back on. */
.ntfy-msg.is-mutedreport,
.ntfy-msg.is-mutedtopic {
  opacity: 0.55;
  border-left-color: var(--idle) !important;
}

.ntfy-msg.is-mutedreport:hover,
.ntfy-msg.is-mutedtopic:hover { opacity: 0.85; }

.ntfy-muted-chip {
  padding: 0.05rem 0.35rem;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.ntfy-msg.is-chattyrow .ntfy-body {
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Colour modes. Severity is the default and lives on the base rules above. */
.ntfy-feed.colour-none .ntfy-msg { border-left-color: var(--border); }

.ntfy-feed.colour-topic .ntfy-msg.topic-0 { border-left-color: #5eead4; }
.ntfy-feed.colour-topic .ntfy-msg.topic-1 { border-left-color: #a78bfa; }
.ntfy-feed.colour-topic .ntfy-msg.topic-2 { border-left-color: #60a5fa; }
.ntfy-feed.colour-topic .ntfy-msg.topic-3 { border-left-color: #fbbf24; }
.ntfy-feed.colour-topic .ntfy-msg.topic-4 { border-left-color: #f472b6; }
.ntfy-feed.colour-topic .ntfy-msg.topic-5 { border-left-color: #4ade80; }
.ntfy-feed.colour-topic .ntfy-msg.topic-6 { border-left-color: #fb923c; }
.ntfy-feed.colour-topic .ntfy-msg.topic-7 { border-left-color: #94a3b8; }

.ntfy-muted-list {
  display: grid;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.ntfy-muted-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  font-size: var(--step--1);
}

.ntfy-muted-sample {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-dim);
}

.ntfy-muted-until {
  flex: none;
  font-size: 0.64rem;
  color: var(--text-faint);
}

#ntfy-oncall.is-armed {
  color: var(--down);
  border-color: rgba(248, 113, 113, 0.45);
  background: rgba(248, 113, 113, 0.1);
}

.ntfy-msg.is-unacked {
  box-shadow: 0 0 0 1px rgba(248, 113, 113, 0.35);
}

/* Compact density: one-line-ish rows for scanning a busy feed. */
.ntfy-feed.is-compact .ntfy-msg { padding: 0.45rem 0.7rem; }
.ntfy-feed.is-compact .ntfy-msg-head { margin-bottom: 0.15rem; }
.ntfy-feed.is-compact .ntfy-title { font-size: 0.8rem; }
.ntfy-feed.is-compact .ntfy-body {
  font-size: 0.78rem;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ntfy-feed {
  display: grid;
  /* minmax(0,…) so a long unbroken line in an alert can't widen the page. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem;
  margin-top: 1.1rem;
  max-width: 60rem;
}

.ntfy-msg {
  min-width: 0;
  padding: 0.8rem 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.ntfy-msg.is-high   { border-left-color: var(--warn); }
.ntfy-msg.is-urgent { border-left-color: var(--down); }
.ntfy-msg.is-low    { opacity: 0.75; }

.ntfy-msg-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}

.ntfy-topic {
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.ntfy-pri {
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warn);
}

.ntfy-msg.is-urgent .ntfy-pri { color: var(--down); }

.ntfy-when {
  margin-left: auto;
  font-size: 0.66rem;
  color: var(--text-faint);
}

.ntfy-title {
  margin: 0 0 0.2rem;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text);
}

.ntfy-body {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text-dim);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.ntfy-ai {
  margin: 0.6rem 0 0;
  padding: 0.55rem 0.7rem;
  border-left: 2px solid var(--accent);
  border-radius: 0 6px 6px 0;
  background: rgba(94, 234, 212, 0.05);
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text);
}

.ntfy-msg-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.55rem;
}

.ntfy-msg-foot .ntfy-explain { margin-left: auto; }

/* ---------- Security ---------- */

.gate-code {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 1.3rem;
  letter-spacing: 0.4em;
  text-indent: 0.4em; /* offsets the trailing letter-space so digits look centred */
}

.security-actions {
  display: grid;
  gap: 1.2rem;
  max-width: 34rem;
}

.security-form .field-label { margin-top: 0; }

/* ---------- Snippets ---------- */

.snippet-list {
  display: grid;
  /* minmax(0, …) rather than a bare 1fr: a grid item defaults to min-width
     auto, so one long unbreakable command line would set the card's width and
     push the whole page sideways on a phone. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  max-width: 60rem;
}

.snippet {
  min-width: 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.snippet-head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}

.snippet-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text);
}

.snippet-uses {
  flex: none;
  font-size: 0.68rem;
  color: var(--text-faint);
}

.snippet .code-block { margin-bottom: 0.7rem; }

.snippet-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.snippet-tag {
  padding: 0.12rem 0.45rem;
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  font-size: 0.65rem;
  color: var(--text-faint);
  text-decoration: none;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.snippet-tag:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.snippet-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
}

.pill-count {
  opacity: 0.55;
  font-size: 0.9em;
}

/* ---------- Activity timeline ---------- */

.timeline {
  list-style: none;
  margin: 0;
  padding: 0 0 0 1rem;
  border-left: 1px solid var(--border-soft);
}

.timeline-item {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.4rem 0;
  font-size: var(--step--1);
  color: var(--text-dim);
}

.timeline-mark {
  position: absolute;
  left: calc(-1rem - 3px);
  top: 0.75rem;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--idle);
}

.timeline-item.is-auth    .timeline-mark { background: var(--accent); }
.timeline-item.is-wiki    .timeline-mark { background: var(--up); }
.timeline-item.is-ai      .timeline-mark { background: #a78bfa; }
.timeline-item.is-pulse   .timeline-mark { background: var(--warn); }
.timeline-item.is-snippet .timeline-mark { background: #60a5fa; }

.timeline-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.timeline-when {
  flex: none;
  font-size: 0.68rem;
  color: var(--text-faint);
}

/* ---------- Responsive ---------- */

@media (max-width: 620px) {
  .panel-hero { padding-block: 1.5rem 1rem; }
  .brand-tag { display: none; }
  .panel-toolbar { gap: 0.6rem 0.8rem; }
  .stat { padding: 0.9rem 1rem; }
  .wiki-search { margin-left: 0; width: 100%; }
  .wiki-search-input { width: 100%; min-width: 0; }
}

/* Keep Wiki/logout reachable where style.css hides .topnav entirely.
   Threshold matches style.css's own topnav-hide breakpoint — keep in sync. */
@media (max-width: 480px) {
  .panel-body .topnav { display: flex; gap: 0.75rem; font-size: 0.72rem; }
}

/* A phone has no room for a 6.5rem label, a slider and a readout on one line. */
@media (max-width: 480px) {
  .ntfy-opt { flex-wrap: wrap; }
  .ntfy-opt > span { min-width: 4.5rem; }
  .ntfy-shaping .ntfy-opt > span { min-width: 5.5rem; }
  .ntfy-opt .field-input { flex: 1 1 8rem; }
}

/* Seven nav items and a search button don't fit a narrow window. The nav
   scrolls within itself rather than widening the page — every panel page
   shares this bar, so an overflow here tilts the whole site sideways.
   It starts at 620px rather than 420px because style.css brings the nav back
   at 480px, and the band between the two used to show it at full width with
   no way to shrink: measured at 110px of sideways scroll at 421px wide. */
@media (max-width: 620px) {
  .panel-body .topnav {
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .panel-body .topnav::-webkit-scrollbar { display: none; }
}

/* Below a small phone, tighten it as well as letting it scroll. */
@media (max-width: 420px) {
  .panel-body .topnav {
    gap: 0.6rem;
    font-size: 0.68rem;
  }
}

@media (min-width: 1800px) {
  .panel-main,
  .panel-body .topbar,
  .panel-body .footer { max-width: 96rem; }
}

@media (min-width: 2400px) {
  .panel-main,
  .panel-body .topbar,
  .panel-body .footer { max-width: 110rem; }
}

/* :has() is broadly supported, but fall back to a neutral pill without it. */
@supports not selector(:has(*)) {
  .svc-state { color: var(--text-faint); }
}

/* ---------- Command palette (Ctrl-K) ---------- */

/* A search button rather than another nav link: the nav is already five items
   and starts scrolling on a phone, and this is a verb, not a place. */
.topbar-search {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-left: auto;
  padding: 0.35rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--text-faint);
  font: inherit;
  font-size: 0.74rem;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.topbar-search:hover { color: var(--text); border-color: #38424f; }
.topbar-search-icon { font-size: 0.9em; }

.topbar-search-key {
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.85em;
}

.cmdk {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  /* Nearer the top than the middle: the results grow downwards and the eye is
     already up there, having just pressed the key. */
  place-items: start center;
  padding: clamp(3rem, 12vh, 8rem) 1rem 1rem;
}

.cmdk[hidden] { display: none !important; }

.cmdk-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(4, 6, 9, 0.72);
  backdrop-filter: blur(3px);
}

.cmdk-panel {
  position: relative;
  width: min(44rem, 100%);
  max-height: min(70vh, 40rem);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
}

.cmdk-input {
  flex: none;
  padding: 1rem 1.1rem;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--step-0);
}

.cmdk-input:focus { outline: none; }
.cmdk-input::placeholder { color: var(--text-faint); }

/* The native clear button renders as a blue cross that belongs to no theme
   this site has; Escape and the backdrop both already close the thing. */
.cmdk-input::-webkit-search-cancel-button,
.cmdk-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

.cmdk-results {
  flex: 1 1 auto;
  margin: 0;
  padding: 0.35rem;
  overflow-y: auto;
  list-style: none;
  scrollbar-width: thin;
}

.cmdk-row {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  padding: 0.55rem 0.7rem;
  border-radius: calc(var(--radius) - 4px);
  cursor: pointer;
}

.cmdk-row.is-active { background: rgba(94, 234, 212, 0.09); }
.cmdk-row:hover { background: rgba(255, 255, 255, 0.04); }

.cmdk-kind {
  flex: none;
  min-width: 3.6rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.cmdk-kind-wiki { color: var(--accent); }
.cmdk-kind-file { color: #c4b5fd; }

/* minmax(0) so a long context line truncates instead of pushing the meta off. */
.cmdk-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.cmdk-title {
  color: var(--text);
  font-size: var(--step--1);
  font-weight: 500;
}

.cmdk-context {
  overflow: hidden;
  font-size: 0.72rem;
  color: var(--text-faint);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cmdk-row mark {
  background: rgba(94, 234, 212, 0.22);
  color: inherit;
  border-radius: 2px;
}

.cmdk-meta {
  flex: none;
  max-width: 9rem;
  overflow: hidden;
  font-size: 0.66rem;
  color: var(--text-faint);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cmdk-empty {
  padding: 1.2rem 0.9rem;
  color: var(--text-faint);
  font-size: var(--step--1);
  text-align: center;
}

.cmdk-foot {
  flex: none;
  display: flex;
  gap: 1rem;
  margin: 0;
  padding: 0.55rem 0.9rem;
  border-top: 1px solid var(--border);
  font-size: 0.66rem;
  color: var(--text-faint);
}

.cmdk-foot kbd {
  margin-right: 0.2rem;
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
}

/* The nav is seven links wide and the topbar has no room to spare: below a
   full desktop the button drops to its icon, which is the whole affordance
   anyway. Measured — at 768px the labelled button overflowed by 13px. */
@media (max-width: 900px) {
  .topbar-search-label,
  .topbar-search-key { display: none; }
  .topbar-search { padding: 0.3rem 0.5rem; }
}

@media (max-width: 620px) {
  .cmdk-meta { display: none; }
  .cmdk-kind { min-width: 3rem; }
}

/* ---------- Wiki: contents and heading anchors ---------- */

.wiki-toc {
  max-width: 74ch;
  margin: 0 0 1.1rem;
  padding: 0.85rem 1.1rem 0.95rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.015);
}

.wiki-toc-label {
  margin: 0 0 0.5rem;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.wiki-toc-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
}

.wiki-toc-item { margin: 0.2rem 0; }
.wiki-toc-l3 { padding-left: 1rem; font-size: 0.92em; }

.wiki-toc-item a {
  color: var(--text-dim);
  text-decoration: none;
}

.wiki-toc-item a:hover {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The topbar is sticky, so a heading jumped to would otherwise land under it. */
.wiki-article h1,
.wiki-article h2,
.wiki-article h3,
.wiki-article h4 { scroll-margin-top: 5rem; }

/* Present but out of the way until you want it. */
.wiki-anchor {
  margin-left: 0.4rem;
  opacity: 0;
  color: var(--text-faint);
  font-weight: 400;
  text-decoration: none;
  transition: opacity 0.12s ease, color 0.12s ease;
}

.wiki-article h2:hover .wiki-anchor,
.wiki-article h3:hover .wiki-anchor,
.wiki-article h4:hover .wiki-anchor,
.wiki-anchor:focus-visible { opacity: 1; }

.wiki-anchor:hover { color: var(--accent); }

/* A touch screen has no hover, so there is nothing to reveal — and a row of
   stray hashes down the page is worse than no anchors at all. */
@media (hover: none) {
  .wiki-anchor { display: none; }
}

/* ---------- Wiki: editor preview ---------- */

.wiki-preview { margin-top: 1rem; }

.wiki-preview-label {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin: 0 0 0.5rem;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.wiki-preview-state {
  font-size: 0.85em;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* The preview is the read view, so it uses the read view's sheet — what you
   see here is exactly what the saved page will look like. */
.wiki-preview .wiki-article { max-width: none; }

/* An anchor in the preview would link into a page that doesn't exist yet. */
.wiki-preview .wiki-anchor { display: none; }
