/* Mint on a near-black base with a green cast, rather than pastel-on-white: a dashboard gets
   stared at, and light mint over a full page turns muddy fast. The mint carries the accents,
   the surfaces stay quiet. */

:root {
  --bg: #0c1311;
  --bg-2: #101a16;
  --surface: #151f1b;
  --surface-2: #1b2823;
  --surface-3: #223229;
  --line: #26282c;             /* every hairline on the site, the user's pick (7 Sep 2026) */
  --line-bright: #2f463b;

  --text: #e9f4ef;
  --dim: #8ba79b;
  --faint: #61796f;

  --mint: #3ddc97;
  --mint-bright: #5eead4;
  --mint-deep: #10b981;
  --mint-glow: rgba(61, 220, 151, .22);

  --warn: #f0b45f;
  --danger: #f27272;

  --r: 14px;
  --r-sm: 9px;
  --ease: cubic-bezier(.34, .8, .3, 1);
}

/* ── scrollbars ──────────────────────────────────────────────────── */
/* Left alone, Windows draws a wide light grey bar with arrow buttons at each end, which on a
   near-black page is the brightest thing on screen. It showed up worst inside the role list,
   where a 10px column of Windows chrome sat against the dark rows.

   Applied to everything rather than to that one list: the page itself, the docs tables, the
   insights charts and the settings sidebar all scroll too, and one styled scrollbar beside
   four default ones is worse than none. Firefox takes the two standard properties, Chromium
   and Edge take the pseudo elements, and both are given the same thing. The box-sizing
   rides in the same rule: one pass over every element instead of two. */
* {
  box-sizing: border-box;
  scrollbar-width: thin;
  scrollbar-color: var(--line-bright) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line-bright);
  border-radius: 6px;
  /* Transparent border plus padding-box keeps the thumb clear of the track edges, which is
     what stops a 10px bar reading as a 10px slab. */
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: #3d5a4c; background-clip: padding-box; }
/* The little arrows at each end, which nothing else on this site has. */
::-webkit-scrollbar-button { display: none; }
::-webkit-scrollbar-corner { background: transparent; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  color: var(--text);
  background: var(--bg);
  /* Century Gothic where it's installed (Windows and Office machines); Jost, loaded in
     base.html, is the geometric lookalike for every device without it. Bold as the base
     weight for the whole site, at the user's request. */
  font: 700 15px/1.6 "Century Gothic", CenturyGothic, "Jost", ui-sans-serif, -apple-system,
        BlinkMacSystemFont, "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* The backdrop: two soft mint glows in the top corners over a slow fade from --bg-2 to --bg.
   It sits on its own fixed layer behind everything rather than as a fixed background on the
   body, because a fixed body background makes the browser repaint the whole viewport on
   every scroll, and this layer just stays put while the page slides over it. Same layers,
   same size (the viewport), same look, including through the blurred sticky bar. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(1100px 520px at 12% -12%, rgba(61, 220, 151, .09), transparent 62%),
    radial-gradient(900px 460px at 92% 4%, rgba(94, 234, 212, .07), transparent 58%),
    linear-gradient(178deg, var(--bg-2), var(--bg) 42%);
}

a { color: inherit; }

::selection { background: var(--mint-glow); color: #fff; }

/* ── top bar ─────────────────────────────────────────────────────── */
.bar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 26px;
  background: rgba(12, 19, 17, .82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 700;
  font-size: 16.5px;
  letter-spacing: -.2px;
  text-decoration: none;
  background: linear-gradient(100deg, var(--mint-bright), var(--mint));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* The Newt face beside the name, in the header and the footer. An <img>, so the
   gradient-text trick on .brand leaves it alone. */
.brand-mark { display: block; width: 26px; height: auto; flex: none; }
.foot-brand .brand-mark { width: 22px; }

.who { display: flex; align-items: center; gap: 11px; font-size: 14px; }
.who img { border-radius: 50%; border: 1.5px solid var(--line-bright); }
.who form { margin: 0; }

/* ── layout ──────────────────────────────────────────────────────── */
main { max-width: 800px; margin: 0 auto; padding: 40px 22px 88px; }

h1 {
  font-size: 30px;
  line-height: 1.2;
  letter-spacing: -.7px;
  margin: 0 0 26px;
}

h2 {
  font-size: 16.5px;
  letter-spacing: -.2px;
  margin: 0;
}

/* Page-level headings need room; the ones inside cards are handled by .head. */
main > h2 { margin: 40px 0 6px; }
main > h2 + .fine { margin-bottom: 14px; }

p { margin: 0 0 14px; }

.fine { color: var(--dim); font-size: 13.2px; margin: 5px 0 0; }
/* Chips of placeholder text wrap onto several lines, so they need room not to collide. */
.fine code { line-height: 2.1; }
a.fine { text-decoration: none; border-bottom: 1px solid transparent; transition: .18s var(--ease); }
a.fine:hover { color: var(--mint); border-bottom-color: var(--mint-glow); }

/* ── hero ────────────────────────────────────────────────────────── */
.hero { text-align: center; padding: 84px 0 60px; }

.hero h1 {
  font-size: clamp(30px, 6vw, 42px);
  margin-bottom: 16px;
  background: linear-gradient(120deg, #fff 18%, var(--mint-bright) 62%, var(--mint));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero p { color: var(--dim); max-width: 47ch; margin: 0 auto 26px; font-size: 15.5px; }
.hero .fine { max-width: 44ch; margin: 22px auto 0; color: var(--faint); }

.bar-left { display: flex; align-items: center; gap: 22px; }

.nav-link {
  color: var(--dim);
  text-decoration: none;
  font-size: 14px;
  font-weight: 550;
  transition: color .18s var(--ease);
}
.nav-link:hover { color: var(--mint); }

/* ── documentation ───────────────────────────────────────────────── */
body.docs-page main { max-width: 1060px; }

.docs {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 44px;
  align-items: start;
}

/* Sticky, because the command tables are long and losing your place in a reference page is
   the whole reason people give up on one. */
.toc {
  position: sticky;
  top: 84px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-right: 8px;
  border-right: 1px solid var(--line);
}

.toc-title {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 10px;
}

.toc a {
  color: var(--dim);
  text-decoration: none;
  font-size: 13.6px;
  padding: 6px 10px;
  border-radius: 7px;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.toc a:hover { background: rgba(61, 220, 151, .08); color: var(--mint-bright); }

/* Highlights the section you're actually in, so a long reference page keeps its place. */
.toc a.here {
  color: var(--mint-bright);
  background: rgba(61, 220, 151, .1);
  font-weight: 600;
}

/* ── docs search ─────────────────────────────────────────────────── */
.docs-search {
  position: sticky;
  top: 74px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 30px;
  padding: 10px 0;
  /* Opaque, since the page scrolls underneath it. */
  background: linear-gradient(var(--bg) 76%, transparent);
}

/* Shared with the settings search below: it is the same control doing the same job. */
.docs-search input, .settings-search input {
  flex: 1;
  min-width: 0;
  margin: 0;
  padding: 11px 15px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  font: inherit;
  font-size: 14.5px;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.docs-search input:hover, .settings-search input:hover { border-color: #3a5548; }
.docs-search input:focus, .settings-search input:focus {
  outline: none;
  border-color: var(--mint);
  box-shadow: 0 0 0 3px var(--mint-glow);
}
.docs-search input::-webkit-search-cancel-button,
.settings-search input::-webkit-search-cancel-button { filter: grayscale(1) opacity(.6); }

.hits {
  flex: none;
  font-size: 12.6px;
  font-weight: 600;
  color: var(--mint-bright);
  padding: 4px 11px;
  border-radius: 999px;
  background: rgba(61, 220, 151, .1);
  border: 1px solid rgba(61, 220, 151, .28);
}

.no-hits { color: var(--dim); font-size: 14.3px; margin-bottom: 30px; }

/* While filtering, a section is a list of matching commands and nothing else. */
.docs-body.filtering > section > .lead-text,
.docs-body.filtering > section > ol,
.docs-body.filtering > section > ul,
.docs-body.filtering > section > h3,
.docs-body.filtering > section > p,
.docs-body.filtering > section > dl,
.docs-body.filtering .docs-cta { display: none; }
.docs-body.filtering > section { margin-bottom: 30px; }
.docs-body.filtering > section > .table-wrap { display: block; }

/* ── settings search ───────────────────────────────────── */
/* The same box as the docs page, deliberately: it does the same job and there is no reason
   for it to look like a different control. Not sticky, because the settings page already has
   a sidebar pinned down the left and two sticky things fighting for the top is one too many. */
.settings-search {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
}
/* The box itself is styled with the docs search, above. */

/* Which tab a card came from. Only worth saying while the tabs are not deciding what is on
   screen, so it is hidden until a search is running. */
.from-tab { display: none; }
.settings.filtering .from-tab {
  display: block;
  margin-bottom: 10px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Every pane at once, stacked, rather than one tab's worth. The sidebar stays where it is:
   it is still how you leave the search. */
.settings.filtering .panes { display: flex; flex-direction: column; gap: 0; }
.settings.filtering .pane { display: block; }
/* A card matched on its own title keeps its rows, so the ones left standing are the answer
   and want a little more room than they get in a full list. */
.settings.filtering .logrow[hidden],
.settings.filtering .rolerow[hidden],
.settings.filtering .counterrow[hidden] { display: none; }

/* ── heading permalinks ──────────────────────────────────────────── */
.anchor {
  margin-left: 9px;
  color: var(--faint);
  text-decoration: none;
  font-weight: 600;
  font-size: .78em;
  opacity: 0;
  transition: opacity .16s var(--ease), color .16s var(--ease);
}
h2:hover .anchor, h3:hover .anchor, .anchor:focus-visible { opacity: 1; }
.anchor:hover { color: var(--mint); }

/* Says the link is on the clipboard, which is why anybody clicked it. */
.anchor.copied { opacity: 1; color: var(--mint-bright); }
.anchor.copied::after {
  content: "copied";
  margin-left: 7px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .3px;
}

.docs-body > section { margin-bottom: 56px; scroll-margin-top: 88px; }
/* Clears the sticky search box as well as the header when jumping to a heading, with enough
   margin that the heading doesn't sit tucked against the underside of the bar. */
.docs-body h3[id] { scroll-margin-top: 156px; }

.docs-body h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 21px;
  letter-spacing: -.4px;
  margin: 0 0 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.sec-icon {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 9px;
  background: rgba(61, 220, 151, .1);
  border: 1px solid rgba(61, 220, 151, .22);
  font-size: 15px;
}

.docs-body h3 {
  font-size: 13.4px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: var(--faint);
  margin: 28px 0 12px;
}

.lead-text { color: var(--dim); font-size: 15px; margin-bottom: 18px; }

ol.numbered { counter-reset: n; list-style: none; padding: 0; margin: 0; }
ol.numbered > li {
  counter-increment: n;
  position: relative;
  padding: 0 0 0 38px;
  margin-bottom: 20px;
}
ol.numbered > li::before {
  content: counter(n);
  position: absolute;
  left: 0; top: 0;
  display: grid; place-items: center;
  width: 25px; height: 25px;
  border-radius: 50%;
  background: rgba(61, 220, 151, .12);
  border: 1px solid rgba(61, 220, 151, .3);
  color: var(--mint-bright);
  font-size: 12.5px;
  font-weight: 700;
}
ol.numbered strong { display: block; margin-bottom: 4px; letter-spacing: -.1px; }
ol.numbered p { margin: 0; color: var(--dim); font-size: 14.3px; }
ol.numbered.tight > li { margin-bottom: 14px; }

ul.notes { list-style: none; padding: 0; margin: 0; }
ul.notes li {
  position: relative;
  padding-left: 20px;
  margin-bottom: 11px;
  color: var(--dim);
  font-size: 14.3px;
  line-height: 1.62;
}
ul.notes li::before {
  content: "";
  position: absolute;
  left: 3px; top: 9px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--mint);
  opacity: .75;
}
ul.notes strong { color: var(--text); }

/* Tables scroll rather than squash: a command signature that wraps mid-argument is unreadable. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  /* On a phone the "who can use it" column sits off the right edge with nothing to say so.
     Same fade as the role lists, turned on its side, and taken off by app.js once there is
     nothing further right to reach. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
/* Nothing to hint at when the table fits, and a mask on a table that fits would fade a column
   for no reason. app.js adds at-end immediately in that case. */
@media (min-width: 861px) {
  .table-wrap { -webkit-mask-image: none; mask-image: none; }
}

table.commands { width: 100%; border-collapse: collapse; font-size: 14px; }

table.commands th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--faint);
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

table.commands td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  color: var(--dim);
  vertical-align: top;
}
table.commands tr:last-child td { border-bottom: 0; }
table.commands tr:hover td { background: rgba(61, 220, 151, .035); }

td.cmd { white-space: nowrap; }
td.cmd code { color: var(--mint-bright); font-weight: 600; }
.args {
  display: block;
  margin-top: 3px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.8px;
  color: var(--faint);
}

.who-tag {
  display: inline-block;
  white-space: nowrap;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--line-bright);
  background: var(--surface-2);
  font-size: 11.8px;
  color: var(--dim);
}
.who-tag.open {
  border-color: rgba(61, 220, 151, .3);
  background: rgba(61, 220, 151, .08);
  color: var(--mint-bright);
}

dl.faq { margin: 0; }
dl.faq dt { font-weight: 620; margin-top: 20px; letter-spacing: -.1px; }
dl.faq dt:first-child { margin-top: 0; }
dl.faq dd {
  margin: 5px 0 0;
  color: var(--dim);
  font-size: 14.3px;
  line-height: 1.62;
}

.docs-cta { text-align: center; padding-top: 8px; }
.docs-cta h2 { display: block; border: 0; padding: 0; margin-bottom: 18px; }

@media (max-width: 820px) {
  /* minmax(0, 1fr) rather than 1fr: a bare 1fr means minmax(auto, 1fr), which lets the wide
     command tables push the column past the viewport instead of scrolling inside it. */
  .docs { grid-template-columns: minmax(0, 1fr); gap: 26px; }
  .toc {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 0 0 16px;
  }
  .toc-title { width: 100%; margin-bottom: 4px; }
  .toc a { background: var(--surface-2); border: 1px solid var(--line); }
}

/* ── landing page ────────────────────────────────────────────────── */
/* Wider than the settings pages: marketing copy in a 800px column looks like a memo. */
body.landing-page main { max-width: 1060px; }

.bar.scrolled { border-bottom-color: var(--line-bright); box-shadow: 0 8px 24px -20px #000; }

/* Elements arrive as you reach them. Only hidden when the .js flag is set, so with scripting
   off nothing is ever invisible.

   Both rules are scoped to .js and the shown one comes second: `.js [data-reveal]` and
   `[data-reveal].shown` have identical specificity, so whichever is written last wins. Getting
   that backwards leaves the whole page blank. */
@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .55s var(--ease), transform .55s var(--ease);
  }
  .js [data-reveal].shown { opacity: 1; transform: none; }
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 52px;
  align-items: center;
  padding: 64px 0 76px;
}

.hero-copy h1 {
  font-size: clamp(30px, 4.4vw, 43px);
  line-height: 1.12;
  margin: 0 0 16px;
  color: #fff;
}
/* One word in colour, the rest white: the <em> the wording file puts round it. */
.hero-copy h1 em { font-style: normal; color: var(--mint-bright); }
.hero-copy p { color: var(--dim); font-size: 15.4px; margin-bottom: 26px; }
.hero-copy .cta { justify-content: flex-start; }
.hero-copy .fine { margin-top: 18px; }

/* ── the survey demo ─────────────────────────────────────────────── */
.mock {
  border: 1px solid var(--line-bright);
  border-radius: 15px;
  overflow: hidden;
  background: #16211d;
  box-shadow: 0 30px 60px -34px #000, 0 0 0 1px rgba(61, 220, 151, .07);
}

.mock-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  background: #101a16;
  border-bottom: 1px solid var(--line);
}
.dot { width: 9px; height: 9px; border-radius: 50%; }
.dot.r { background: #f27272; } .dot.y { background: #f0b45f; } .dot.g { background: var(--mint); }
.mock-channel { margin-left: 6px; color: var(--faint); font-size: 12.6px; }

.mock-body { padding: 18px 16px 14px; }
.mock-msg { display: flex; gap: 12px; }

.mock-avatar {
  width: 38px; height: 38px; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--mint), var(--mint-deep));
  color: #06251c;
  font-weight: 700;
}

.mock-content { min-width: 0; flex: 1; }
.mock-name { font-weight: 650; font-size: 14.4px; margin-bottom: 7px; }
.tag {
  margin-left: 5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--mint);
  color: #06251c;
  font-size: 9.6px;
  font-weight: 700;
  letter-spacing: .4px;
  vertical-align: 1.5px;
}

.mock-embed {
  border-left: 3px solid var(--mint);
  border-radius: 0 6px 6px 0;
  background: #101a16;
  padding: 12px 14px;
  margin-bottom: 11px;
}
.mock-embed strong { display: block; font-size: 14.4px; margin-bottom: 5px; }
.mock-embed p { margin: 0; color: var(--dim); font-size: 13.2px; line-height: 1.5; }

/* Five to a row, because that is Discord's limit on one action row: a 1 to 10 survey really
   does arrive as two rows of five. minmax(0, 1fr) so the columns stay even at any width. */
.mock-buttons {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 5px;
}

.mock-btn {
  padding: 7px 0;
  background: #2b3b34;
  color: var(--text);
  border: 0;
  border-radius: 6px;
  font-size: 13.2px;
  font-weight: 600;
  box-shadow: none;
  transition: background .14s var(--ease), transform .14s var(--ease);
}
.mock-btn:hover { background: #354a41; transform: translateY(-1px); filter: none; box-shadow: none; }
.mock-btn.picked {
  background: linear-gradient(135deg, var(--mint), var(--mint-deep));
  color: #06251c;
}

.mock-reply {
  margin-top: 11px;
  padding: 9px 12px;
  border-radius: 7px;
  background: rgba(61, 220, 151, .09);
  border: 1px solid rgba(61, 220, 151, .26);
  color: #bdf4dd;
  font-size: 13.2px;
  opacity: 0;
  transform: translateY(-4px);
}
.mock-reply.show { animation: replyIn .3s var(--ease) forwards; }
.mock-reply b { color: var(--mint-bright); }

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

.mock-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-size: 12.4px;
}
.mock-foot b { color: var(--mint-bright); }
.try { color: var(--mint); font-weight: 600; }

/* ── retention chart ─────────────────────────────────────────────── */
.chart {
  background: rgba(12, 19, 17, .5);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 20px 22px 16px;
  margin: 0 0 30px;
}
.chart-head {
  font-size: 11.6px;
  font-weight: 700;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 15px;
}
.meter-row {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 12px;
  margin-bottom: 9px;
}
.meter-label { font-size: 13px; color: var(--dim); }
.meter { display: block; height: 9px; border-radius: 999px;
  background: var(--surface-3); overflow: hidden; }
.meter-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--mint-deep), var(--mint-bright));
}
/* The landing page's bars grow in as they arrive: full width, squashed to nothing from the
   left edge, and app.js scales them out to their percentage. A transform animates without
   the browser laying the page out again on every frame, which animating the width did. The
   insights page sets its bars' width inline and never animates them, so it is left out. */
.meter-fill[data-pct] {
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1.1s var(--ease);
}
.meter-val { font-size: 13px; font-weight: 650; color: var(--mint-bright); text-align: right; }
.chart .fine { margin-top: 13px; }

@media (max-width: 880px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: 38px; padding: 44px 0 56px; }
  .hero-copy .cta { justify-content: center; }
  .hero-copy { text-align: center; }
  .hero-copy p { margin-left: auto; margin-right: auto; max-width: 50ch; }
  .meter-row { grid-template-columns: 92px minmax(0, 1fr) 38px; gap: 9px; }
  .meter-label { font-size: 12.2px; }
}

.hero.landing { padding: 76px 0 64px; }

.pill {
  display: inline-block;
  margin-bottom: 22px;
  padding: 6px 15px;
  border-radius: 999px;
  border: 1px solid var(--line-bright);
  background: rgba(61, 220, 151, .07);
  color: var(--mint-bright);
  font-size: 12.4px;
  font-weight: 600;
  letter-spacing: .3px;
}

.cta {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 6px;
}

.button.ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--line-bright);
  box-shadow: none;
}
.button.ghost:hover {
  background: rgba(61, 220, 151, .07);
  border-color: var(--mint);
  color: var(--mint-bright);
  filter: none;
}

.button.small { padding: 8px 15px; font-size: 13.6px; }
/* The header's Dashboard button: a dark chip with the Newt face in front of the word,
   mint text and a hairline, rather than another solid mint pill next to the brand. */
.button.chip {
  background: var(--surface-2);
  color: var(--mint);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: none;
}
.button.chip:hover {
  filter: none;
  background: var(--surface-3);
  border-color: var(--line);
  box-shadow: 0 0 0 3px var(--mint-glow);
}
.button.chip img { display: block; width: 20px; height: auto; }

.link-plain {
  color: var(--dim);
  text-decoration: none;
  font-size: 14px;
  transition: color .18s var(--ease);
}
.link-plain:hover { color: var(--mint); }

h2.section {
  font-size: 22px;
  letter-spacing: -.4px;
  text-align: center;
  margin: 0 0 30px;
}

section { margin-bottom: 72px; }

.features {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
}

.feature {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--mint);
  border-radius: 12px;
  padding: 20px 22px 16px;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.feature:hover { transform: translateY(-4px);
                 box-shadow: 0 18px 40px -26px rgba(61, 220, 151, .6); }


.feature > * { position: relative; z-index: 1; }

.feature h3 {
  margin: 0 0 8px;
  font-size: 15.8px;
  letter-spacing: -.2px;
}
.feature p { margin: 0; color: var(--dim); font-size: 13.8px; line-height: 1.6;
             font-weight: 400; }

/* The command chips under the sentence, and the card's own icon ghosted big in the
   corner from the bot's mint emoji set. */
.feature .feature-chips { margin: 12px 0 0; }
.spec-chip {
  display: inline-block;
  background: rgba(61, 220, 151, .10);
  border: 1px solid rgba(61, 220, 151, .28);
  color: var(--mint-bright);
  border-radius: 7px;
  padding: 1px 8px;
  margin: 2px 4px 2px 0;
  font: 600 11px/1.6 ui-monospace, SFMono-Regular, Consolas, monospace;
  white-space: nowrap;
}
.feature .feature-wm {
  position: absolute;
  right: -12px; bottom: -14px;
  width: 84px; height: 84px;
  opacity: .08;
  pointer-events: none;
  z-index: 0;
}

.grid-foot { margin: 18px 0 0; text-align: center; }
.grid-foot a { color: var(--mint); }

/* The differentiator gets its own treatment so it doesn't read as another feature card. */
.spotlight {
  background:
    radial-gradient(620px 300px at 50% 0%, rgba(61, 220, 151, .1), transparent 70%),
    linear-gradient(180deg, var(--surface), var(--surface-2));
  border: 1px solid var(--line-bright);
  border-radius: 20px;
  padding: 44px 38px 38px;
}
.spotlight .lead {
  text-align: center;
  color: var(--dim);
  max-width: 56ch;
  margin: 0 auto 30px;
  font-size: 15.4px;
}
.spotlight > .fine { text-align: center; max-width: 62ch; margin: 26px auto 0; }

.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 15px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.steps li {
  counter-increment: step;
  position: relative;
  padding: 18px 18px 18px 20px;
  border-left: 2px solid var(--line-bright);
  color: var(--dim);
  font-size: 14.2px;
  line-height: 1.6;
}
.steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 23px; height: 23px;
  margin-bottom: 10px;
  border-radius: 50%;
  background: rgba(61, 220, 151, .13);
  border: 1px solid rgba(61, 220, 151, .3);
  color: var(--mint-bright);
  font-size: 12px;
  font-weight: 700;
}
.steps strong { display: block; color: var(--text); margin-bottom: 3px; font-weight: 620; }

/* ── what it costs, on the landing page ──────────────────────────── */
/* Deliberately two panels rather than the full pricing table from /premium. The job here is
   to say the number out loud before somebody has invested any more reading, not to sell. */
.cost-row {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
}

.cost {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 24px 22px;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
}
/* The paid card wears the premium page's own look: mint tint, glow, and the yearly
   ribbon riding its top edge (the .plan-ribbon styles from the premium section). */
.cost.paid {
  position: relative;
  border-color: rgba(61, 220, 151, .5);
  background:
    linear-gradient(180deg, rgba(61, 220, 151, .09), rgba(61, 220, 151, .02) 45%),
    linear-gradient(180deg, var(--surface), var(--surface-2));
  box-shadow: 0 0 34px -14px rgba(61, 220, 151, .55);
}
.cost .button { margin-top: 14px; }

.cost-label {
  display: block;
  color: var(--faint);
  font-size: 12.4px;
  letter-spacing: .3px;
  text-transform: uppercase;
  margin-bottom: 9px;
}
.cost.paid .cost-label { color: var(--mint-bright); }

.cost strong { font-size: 30px; letter-spacing: -1px; line-height: 1; }
.cost strong span { font-size: 13.5px; letter-spacing: 0; color: var(--dim); font-weight: 500; }
.cost p { color: var(--dim); font-size: 14px; margin: 12px 0 0; line-height: 1.6; }
.cost a.fine { display: inline-block; color: var(--mint); margin-top: 12px; }

.closing { text-align: center; margin-bottom: 40px; }
.closing h2 { font-size: 24px; letter-spacing: -.4px; margin-bottom: 10px; }
.closing p { color: var(--dim); margin-bottom: 22px; }

/* ── buttons ─────────────────────────────────────────────────────── */
.button, button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: linear-gradient(135deg, var(--mint), var(--mint-deep));
  color: #05221a;
  border: 0;
  border-radius: var(--r-sm);
  padding: 11px 21px;
  font: inherit;
  font-weight: 650;
  letter-spacing: -.1px;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .18) inset, 0 6px 18px -8px var(--mint);
  transition: transform .16s var(--ease), box-shadow .2s var(--ease), filter .2s var(--ease);
}

.button:hover, button:hover {
  filter: brightness(1.07);
  transform: translateY(-1px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .22) inset, 0 12px 26px -10px var(--mint);
}
.button:active, button:active { transform: translateY(0); }
.button:focus-visible, button:focus-visible,
select:focus-visible, textarea:focus-visible, a:focus-visible {
  outline: 2px solid var(--mint-bright);
  outline-offset: 2px;
}

.hero .button { padding: 13px 28px; font-size: 15.5px; }

button.link {
  background: none;
  color: var(--dim);
  padding: 0;
  font-weight: 500;
  box-shadow: none;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
button.link:hover {
  background: none;
  color: var(--mint);
  filter: none;
  transform: none;
  box-shadow: none;
  border-bottom-color: var(--mint-glow);
}

/* ── cards ───────────────────────────────────────────────────────── */
.grid { display: grid; gap: 13px; grid-template-columns: repeat(auto-fill, minmax(238px, 1fr)); }

.card {
  position: relative;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 22px;
  margin: 0 0 16px;
  transition: border-color .2s var(--ease), transform .2s var(--ease),
              box-shadow .25s var(--ease);
}

/* A mint hairline along the top edge, so a wall of cards still reads as a list. */
.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  border-radius: var(--r) var(--r) 0 0;
  background: linear-gradient(90deg, transparent, var(--mint-glow) 22%, var(--mint-glow) 78%, transparent);
  opacity: .8;
}

.card.server {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0;
  padding: 16px;
  text-decoration: none;
}
.card.server:hover {
  border-color: var(--line-bright);
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -18px rgba(0, 0, 0, .9), 0 0 0 1px var(--mint-glow);
}
.card.server img { border-radius: 12px; }

/* The whole card opens settings; insights is one item on the actions row below the name and
   opts out of that by sitting above the stretched cover link. The cover is stretched over the
   card rather than wrapping it, because wrapping would put the insights link inside another
   link. The name and actions stack, because at three cards across there is no room for a name
   and a pill side by side: the name got about forty pixels and ellipsed to nothing. */
.card.server .server-body {
  flex: 1;
  min-width: 0;          /* so a long name ellipses instead of forcing the card wider */
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.card.server a.cover { text-decoration: none; color: inherit; }
.card.server a.cover strong {
  display: block;
  letter-spacing: -.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card.server a.cover::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.card.server a.cover:focus-visible::after {
  outline: 2px solid var(--mint);
  outline-offset: 2px;
}

.server-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.6px;
}
.server-actions .fine { margin: 0; }
.server-actions .dot-sep { color: var(--faint); }

.server-insights {
  /* Above the stretched cover, which is the only reason this needs a stacking context. */
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--dim);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: color .16s var(--ease);
}
.server-insights:hover { color: var(--mint-bright); }

.card.muted { opacity: .66; }
.card.muted:hover { border-color: var(--line); transform: none; box-shadow: none; }
.card.muted::before { opacity: .3; }

.blank {
  width: 48px; height: 48px; flex: none;
  border-radius: 12px;
  background: linear-gradient(140deg, var(--surface-3), var(--surface-2));
  border: 1px solid var(--line-bright);
  display: grid; place-items: center;
  font-weight: 700;
  color: var(--mint);
}

.head { margin-bottom: 18px; }
.head h2 { display: flex; align-items: center; gap: 9px; }
.head h2::before {
  content: "";
  width: 3px;
  height: 15px;
  border-radius: 2px;
  background: linear-gradient(var(--mint-bright), var(--mint-deep));
}

h2 + .fine, .head .fine { margin-top: 7px; }

/* ── forms ───────────────────────────────────────────────────────── */
label {
  display: block;
  margin: 0 0 15px;
  font-size: 13.2px;
  font-weight: 550;
  color: var(--dim);
  letter-spacing: .1px;
}

/* One rule for every box you type or pick in: dropdowns, text areas, text and number
   fields, and the search box on the cases page, which is a flex item that keeps its own
   width and spacing and so only shares the dressing. Number fields were once left out of
   this, and every threshold in the automod pane rendered as a small white browser default. */
select, textarea, input[type="text"], input[type="number"],
.case-filters input[type="search"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  padding: 10px 12px;
  font: inherit;
  font-size: 14.5px;
}
select, textarea, input[type="text"], input[type="number"] {
  display: block;
  width: 100%;
  margin-top: 7px;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
select:hover, textarea:hover,
input[type="text"]:hover, input[type="number"]:hover { border-color: #3a5548; }
select:focus, textarea:focus,
input[type="text"]:focus, input[type="number"]:focus,
.case-filters input[type="search"]:focus {
  outline: none;
  border-color: var(--mint);
  box-shadow: 0 0 0 3px var(--mint-glow);
}
textarea { resize: vertical; min-height: 78px; line-height: 1.55; }

select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--dim) 50%),
    linear-gradient(135deg, var(--dim) 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
  cursor: pointer;
}

/* Checkboxes become switches: this is a settings page, and a switch reads as on or off at a
   glance where a tick reads as a task. */
label.check {
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--text);
  font-size: 14.5px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
}

label.check input {
  appearance: none;
  position: relative;
  flex: none;
  width: 40px;
  height: 23px;
  margin: 0;
  border-radius: 999px;
  background: var(--surface-3);
  border: 1px solid var(--line-bright);
  cursor: pointer;
  transition: background .22s var(--ease), border-color .22s var(--ease);
}

label.check input::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 3px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--dim);
  transform: translateY(-50%);
  transition: left .22s var(--ease), background .22s var(--ease);
}

label.check input:checked {
  background: linear-gradient(135deg, var(--mint), var(--mint-deep));
  border-color: transparent;
}
label.check input:checked::after { left: 20px; background: #06251c; }
label.check input:focus-visible { outline: 2px solid var(--mint-bright); outline-offset: 2px; }

form.card button[type="submit"] { margin-top: 4px; }

/* ── settings, as tabs down the side ─────────────────────────────── */
body.settings-page main { max-width: 1060px; }

.settings {
  display: grid;
  grid-template-columns: 208px minmax(0, 1fr);
  gap: 30px;
  align-items: start;
}

/* Sticky so the section list stays put while a long pane scrolls. 84px clears the header. */
.sidenav {
  position: sticky;
  top: 84px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sidenav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--dim);
  text-decoration: none;
  font-size: 14.2px;
  font-weight: 500;
  transition: background .16s var(--ease), color .16s var(--ease),
              border-color .16s var(--ease);
}
.sidenav a:hover { background: var(--surface); color: var(--text); }
.sidenav a.on {
  background: linear-gradient(100deg, rgba(61, 220, 151, .14), rgba(61, 220, 151, .04));
  border-color: rgba(61, 220, 151, .32);
  color: var(--text);
}

.sidenav .ti { flex: none; width: 18px; text-align: center; font-size: 14px; }
.sidenav .tl {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The one item in this list that leaves the page. Separated by a rule and given an arrow, so
   it does not read as a sixth tab that simply refuses to look selected. */
.sidenav a.leaves {
  margin-top: 10px;
  padding-top: 15px;
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
/* The second one and any after it belong to the same group, so only the first draws the rule
   that separates the group from the tabs. */
.sidenav a.leaves.nudge { margin-top: 0; padding-top: 9px; border-top: 0; }
.sidenav a.leaves:hover { background: var(--surface); color: var(--mint-bright); }
.sidenav a.leaves:hover .arrow { transform: translateX(2px); }
.sidenav .arrow {
  flex: none;
  color: var(--faint);
  font-size: 13px;
  transition: transform .16s var(--ease);
}
.sidenav a.leaves:hover .arrow { color: var(--mint); }

/* Says which features are actually doing something without opening every tab. */
.sidenav .dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 0 3px var(--mint-glow);
}

.pane { animation: fade .22s var(--ease); }
/* Only the last one, since a tab can hold more than one card. */
.pane > .card:last-child { margin-bottom: 0; }

@keyframes fade {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* The panes are only ever hidden by script, so this has to beat anything that sets display. */
[hidden] { display: none !important; }

@media (max-width: 860px) {
  /* The sidebar becomes a scrolling strip above the pane. */
  .settings { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .sidenav {
    position: static;
    flex-direction: row;
    gap: 6px;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: thin;
  }
  .sidenav a { flex: none; border: 1px solid var(--line); }
  .sidenav .tl { max-width: 130px; }
}

/* ── roles ───────────────────────────────────────────────────────── */
/* A compact tick rather than the switch above. A server can easily have fifty roles, and a
   column of fifty switches is a wall; a tick reads as "one of many" and scans quickly. */
.rolelist {
  margin: 12px 0 4px;
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  background: var(--bg);
  max-height: 320px;
  overflow-y: auto;
  /* The list cuts off mid row, which is the right affordance and looked like a clipping bug.
     Fading the last few pixels turns it into "there is more below". The mask is on the scroll
     box, not the content, so it stays at the bottom edge rather than scrolling away. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
}
/* Once you are at the bottom there is nothing more to hint at, and fading the final row would
   be a lie. Added by app.js; without script the shallow fade simply stays. */
.rolelist.at-end,
.table-wrap.at-end {
  -webkit-mask-image: none;
  mask-image: none;
}

.rolerow {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--line);
}
.rolerow:last-child { border-bottom: 0; }
.rolerow:hover { background: var(--surface); }
.rolerow.blocked { opacity: .5; }
.rolerow.blocked:hover { background: none; }

label.pick {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 1;
  min-width: 0;                 /* so a long role name truncates instead of pushing the row */
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.rolerow.blocked label.pick { cursor: not-allowed; }

label.pick input {
  appearance: none;
  flex: none;
  width: 17px;
  height: 17px;
  margin: 0;
  border-radius: 5px;
  background: var(--surface-3);
  border: 1px solid var(--line-bright);
  cursor: inherit;
  display: grid;
  place-items: center;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
label.pick input:checked {
  background: linear-gradient(135deg, var(--mint), var(--mint-deep));
  border-color: transparent;
}
label.pick input:checked::after {
  content: "";
  width: 9px;
  height: 5px;
  border: 2px solid #06251c;
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}
label.pick input:focus-visible { outline: 2px solid var(--mint-bright); outline-offset: 2px; }

.swatch {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--dim);       /* Discord's own default for a role with no colour set */
}

.rolename { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Allowed to shrink and wrap. With flex: none the reason text set the row's width, which put a
   horizontal scrollbar inside the list on any narrow screen. */
.why {
  color: var(--warn);
  font-size: 12.4px;
  text-align: right;
  flex: 0 1 auto;
  min-width: 0;
}

/* ── the server log ──────────────────────────────────────────────── */
.logtools { display: flex; align-items: center; gap: 10px; }
.logtools .spacer { flex: 1; }

button.tiny {
  padding: 5px 11px;
  font-size: 12.4px;
  font-weight: 500;
  background: var(--surface-3);
  color: var(--dim);
  border: 1px solid var(--line-bright);
  box-shadow: none;
}
button.tiny:hover {
  background: var(--surface);
  color: var(--text);
  filter: none;
  transform: none;
  box-shadow: none;
}

.logrows {
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  background: var(--bg);
  overflow: hidden;
}

.logrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--line);
}
.logrow:last-child { border-bottom: 0; }
.logrow:hover { background: var(--surface); }

/* The dropdown is the exception, not the point, so it stays narrow and quiet next to the
   name. Somebody who never wants to split their log should be able to ignore this column. */
.logrow select {
  flex: none;
  width: 168px;
  margin-top: 0;
  padding: 6px 30px 6px 10px;
  font-size: 13px;
  background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
}

.lg-icon { flex: none; width: 20px; text-align: center; }
.lg-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.lg-label { font-size: 14px; font-weight: 500; }
.lg-blurb { font-size: 12.4px; color: var(--faint); font-weight: 400; line-height: 1.4; }

@media (max-width: 620px) {
  .logrow { flex-wrap: wrap; }
  .logrow label.pick { flex-basis: 100%; }
  .logrow select { width: 100%; flex: 1; }
}

/* ── just added ──────────────────────────────────────────────────── */
body.added-page main { max-width: 720px; }

.landed { text-align: center; margin-bottom: 34px; }
.landed h1 { margin-bottom: 12px; }
.landed .lead { color: var(--dim); max-width: 46ch; margin: 0 auto; }

.tick {
  width: 62px;
  height: 62px;
  margin: 0 auto 20px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 30px;
  color: #06251c;
  background: linear-gradient(135deg, var(--mint-bright), var(--mint-deep));
  box-shadow: 0 0 0 8px var(--mint-glow);
}

ol.numbered.big > li { margin-bottom: 26px; }
ol.numbered.big > li::before { width: 29px; height: 29px; font-size: 13.5px; }
ol.numbered.big strong { font-size: 16px; margin-bottom: 6px; }
ol.numbered.big p { font-size: 14.6px; }

.landed-cta { justify-content: center; margin: 34px 0 22px; }
.centred { text-align: center; }

/* ── first run ───────────────────────────────────────────────────── */
.card.firstrun {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  border-color: rgba(61, 220, 151, .34);
  background: linear-gradient(140deg, rgba(61, 220, 151, .09), var(--surface-2) 58%);
}
.fr-icon { font-size: 28px; flex: none; line-height: 1.2; }
.card.firstrun h2 { margin-bottom: 8px; }
.card.firstrun h2::before { display: none; }

ol.fr-steps { counter-reset: fr; list-style: none; padding: 0; margin: 14px 0; }
ol.fr-steps li {
  counter-increment: fr;
  position: relative;
  padding-left: 30px;
  margin-bottom: 10px;
  font-size: 14.4px;
  color: var(--dim);
}
ol.fr-steps li::before {
  content: counter(fr);
  position: absolute;
  left: 0; top: 1px;
  display: grid; place-items: center;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: rgba(61, 220, 151, .14);
  border: 1px solid rgba(61, 220, 151, .32);
  color: var(--mint-bright);
  font-size: 11.5px;
  font-weight: 700;
}

/* ── changelog ───────────────────────────────────────────────────── */
body.changelog-page main { max-width: 860px; }

.entry {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr);
  gap: 26px;
  padding: 26px 0;
  border-top: 1px solid var(--line);
}
.entry:first-child { border-top: 0; padding-top: 6px; }

/* Sticky so the date stays beside its entry while a long one scrolls past. */
.when { position: sticky; top: 88px; align-self: start; }
.when time {
  font-size: 12.6px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--faint);
}

.what h2 { font-size: 18px; letter-spacing: -.3px; margin-bottom: 14px; }

ul.changes { list-style: none; padding: 0; margin: 0; }
ul.changes li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  margin-bottom: 11px;
  font-size: 14.4px;
  line-height: 1.6;
  color: var(--dim);
}
ul.changes .text { flex: 1; min-width: 0; }

.kind {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  width: 84px;
  padding: 2.5px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
}
.kind.new { color: var(--mint-bright); background: rgba(61, 220, 151, .12);
            border: 1px solid rgba(61, 220, 151, .3); }
.kind.better { color: #a9c7ff; background: rgba(88, 101, 242, .14);
               border: 1px solid rgba(88, 101, 242, .34); }
.kind.fixed { color: var(--warn); background: rgba(240, 180, 95, .12);
              border: 1px solid rgba(240, 180, 95, .3); }

@media (max-width: 620px) {
  .entry { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .when { position: static; }
  ul.changes li { flex-wrap: wrap; gap: 6px; }
  .card.firstrun { flex-direction: column; gap: 10px; }
}

/* ── support ─────────────────────────────────────────────────────── */
body.support-page main { max-width: 860px; }

.grid.two { grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); margin-bottom: 8px; }
.grid.two .card { margin-bottom: 0; }

.card.join { text-align: center; }
.join-icon { font-size: 30px; margin-bottom: 8px; }
.card.join h2 { justify-content: center; }
.card.join .head, .card.join h2::before { display: none; }
.card.join .fine { margin-bottom: 16px; }

.button.disabled {
  background: var(--surface-3);
  color: var(--faint);
  border: 1px solid var(--line-bright);
  box-shadow: none;
  cursor: not-allowed;
}

ul.quick { list-style: none; padding: 0; margin: 12px 0 0; }
ul.quick li { margin-bottom: 11px; }
ul.quick a { color: var(--mint); text-decoration: none; font-size: 14.2px; font-weight: 500; }
ul.quick a:hover { text-decoration: underline; }
ul.quick span { display: block; color: var(--faint); font-size: 12.8px; }

/* ── tickets ─────────────────────────────────────────────────────── */
.tickets { margin-top: 18px; }

.ticket { scroll-margin-top: 90px; }
.ticket-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.ticket-head strong { display: block; font-size: 15.5px; letter-spacing: -.2px; }
.ticket-head .fine { margin-top: 3px; }

.tnum {
  display: inline-block;
  margin-bottom: 4px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .6px;
  color: var(--faint);
}

.tstatus {
  flex: none;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
  padding: 4px 11px;
  border-radius: 999px;
}
.tstatus.open { color: var(--warn); background: rgba(240, 180, 95, .12);
                border: 1px solid rgba(240, 180, 95, .32); }
.tstatus.answered { color: var(--mint-bright); background: rgba(61, 220, 151, .12);
                    border: 1px solid rgba(61, 220, 151, .32); }
.tstatus.closed { color: var(--faint); background: var(--surface-3);
                  border: 1px solid var(--line-bright); }
/* A ticket whose channel is gone: the same pill, tinted red so it reads as something that
   ended badly rather than something that was finished. */
.tstatus.deleted { color: var(--danger); background: rgba(242, 114, 114, .12);
                   border: 1px solid rgba(242, 114, 114, .32); }

.thread { margin: 16px 0; display: flex; flex-direction: column; gap: 10px; }

/* Staff replies lean the other way, so a thread reads as a conversation at a glance. */
.msg {
  padding: 11px 14px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  border: 1px solid var(--line);
  max-width: 88%;
}
.msg.staff {
  align-self: flex-end;
  background: rgba(61, 220, 151, .08);
  border-color: rgba(61, 220, 151, .24);
}
.msg .who {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .4px;
  color: var(--faint);
  margin-bottom: 3px;
}
.msg p { margin: 0; font-size: 14.2px; white-space: pre-wrap; word-break: break-word; }

.ticket form textarea { min-height: 60px; }

/* ── status page ─────────────────────────────────────────────────── */
body.status-page main { max-width: 760px; }

/* The panel, statuspage style: a heading with a hide button, the verdict in a line, then
   one row per part with an icon, the name, the state word and, for the bot, the day of
   its last incident on the right and the 90-day bars underneath. */
.status-card {
  padding: 22px 24px 8px;
  border-radius: var(--r);
  border: 1px solid var(--line-bright);
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  margin-bottom: 16px;
}
.status-card.up { border-color: rgba(61, 220, 151, .34); }
.status-card.wobbly { border-color: rgba(240, 180, 95, .34); }
.status-card.down { border-color: rgba(242, 114, 114, .34); }
.panel-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.panel-head h2 { margin: 0; font-size: 19px; letter-spacing: -.3px; }
.verdict { margin: 4px 0 6px; }
.verdict strong { font-size: 14.5px; margin-right: 6px; }
.verdict .fine { display: inline; }

.srow { padding: 16px 0 14px; border-top: 1px solid var(--line); }
.srow-head { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; }
.srow-head strong { font-size: 15.5px; letter-spacing: -.2px; }
.sword { font-size: 13px; color: var(--dim); }
.sword.up { color: var(--mint); }
.sword.wobbly { color: var(--warn); }
.sword.down { color: var(--danger); }
.slast { margin-left: auto; font-size: 12.5px; color: var(--faint); white-space: nowrap; }
.srow > .fine { margin: 8px 0 0; }
.srow .history-ends { margin: 6px 0 0; }

/* The state icon: four glyphs in the span, the class shows one. Coloured like the word. */
.sicon { flex: none; width: 19px; height: 19px; color: var(--dim); }
.sicon svg { display: none; width: 19px; height: 19px; }
.sicon.up { color: var(--mint); }
.sicon.wobbly { color: var(--warn); }
.sicon.down { color: var(--danger); }
.sicon.up .i-up, .sicon.wobbly .i-wobbly, .sicon.down .i-down, .sicon.unknown .i-unknown { display: block; }

.status-card [data-status-body][hidden] { display: none; }

@media (prefers-reduced-motion: no-preference) {
  /* The halo swells from 5px out to 9px and all but fades away, then comes back. */
  @keyframes pulse {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.3); opacity: .2; }
  }
}

.grid.stats { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); margin-bottom: 22px; }

/* ── the 90-day uptime bars ──────────────────────────────────────── */
/* One <i> per day, statuspage style. Days from before the counter existed are hollow
   rather than red, because "we weren't counting yet" is not an outage. */
.card.history { margin-bottom: 16px; }
.history-head { display: flex; justify-content: space-between; align-items: baseline;
                margin-bottom: 12px; }
.history-head h2 { margin: 0; }
.history-pct { color: var(--mint); font-size: 14px; }
.upbars { display: flex; gap: 2px; }
.upbars i {
  flex: 1; height: 28px; border-radius: 2px; background: var(--mint); opacity: .85;
  min-width: 0;
}
.upbars i:hover { opacity: 1; }
.upbars i.miss { background: var(--warn); }
.upbars i.dead { background: var(--danger); }
.upbars i.nodata { background: none; border: 1px solid var(--line); opacity: .6; }
.history-ends { display: flex; justify-content: space-between; margin: 6px 0 10px; }
.history-ends span { font-size: 11.5px; }

.stat {
  padding: 16px 18px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
}
.stat-label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 6px;
}
.stat-value { font-size: 17px; font-weight: 600; letter-spacing: -.2px; }

/* ── the incident list ───────────────────────────────────────────── */
.card.incidents { margin-bottom: 16px; }
.incidents h2 { margin-bottom: 8px; font-size: 17px; }
.incident { padding: 11px 0; }
.incident + .incident { border-top: 1px solid var(--line); }
.incident strong { display: block; font-size: 14px; }
.incident .fine { margin-top: 2px; }
.incidents > .fine { margin: 6px 0 0; }

/* ── premium ─────────────────────────────────────────────────────── */
/* Wider than the settings pages, like the landing page and for the same reason: this one is
   read once by somebody deciding something, not stared at while they work. */
body.premium-page main { max-width: 1060px; }

.premium-hero { text-align: center; padding: 58px 0 46px; margin-bottom: 0; }
.premium-hero h1 {
  font-size: clamp(28px, 4.2vw, 40px);
  line-height: 1.14;
  margin: 0 0 16px;
  background: linear-gradient(118deg, #fff 20%, var(--mint-bright) 66%, var(--mint));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.premium-hero .lead {
  color: var(--dim);
  font-size: 15.4px;
  max-width: 54ch;
  margin: 0 auto;
}

.premium-page .warn { max-width: 62ch; margin-inline: auto; }

.pricing { text-align: center; margin-bottom: 64px; }
.section-lead {
  color: var(--dim);
  text-align: center;
  max-width: 58ch;
  margin: -18px auto 26px;
  font-size: 14.6px;
}

/* All three plans side by side, the yearly one starred and raised. Each card is a flex
   column with its button pinned to the bottom edge, so the buttons sit on one line
   however long the lists above them run. */
.plan-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  text-align: left;
  align-items: stretch;
}

.plan {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 26px 24px;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  transition: transform .15s var(--ease), border-color .15s var(--ease);
}
.plan:hover { transform: translateY(-4px); border-color: var(--line-bright); }

/* The starred (yearly) card: mint tint, glow, raised above its neighbours, and a ribbon
   riding its top edge. */
.plan.star {
  position: relative;
  border-color: rgba(61, 220, 151, .55);
  background:
    linear-gradient(180deg, rgba(61, 220, 151, .10), rgba(61, 220, 151, .02) 40%),
    linear-gradient(180deg, var(--surface), var(--surface-2));
  box-shadow: 0 0 44px -14px rgba(61, 220, 151, .55);
  margin-top: -14px;
  padding-top: 34px;
}
.plan.star:hover { transform: translateY(-6px); }
.plan-ribbon {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: linear-gradient(90deg, var(--mint), var(--mint-bright));
  color: #05221a;
  font-size: 11.5px;
  font-weight: 700;
  padding: 4px 14px;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: 0 6px 18px -6px rgba(61, 220, 151, .8);
}
.plan-ribbon img { display: block; }

.plan-kicker {
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--dim);
}
.plan-kicker.mint { color: var(--mint); }

.price { display: flex; align-items: baseline; gap: 8px; margin: 10px 0 0; flex-wrap: wrap; }
.price strong { font-size: 34px; letter-spacing: -1.4px; line-height: 1; }
.price span { color: var(--dim); font-size: 13.5px; }
.price .was { color: var(--faint); font-weight: 400; font-size: 14.5px; }

.plan-blurb {
  color: var(--dim);
  font-size: 12.8px;
  line-height: 1.6;
  margin: 6px 0 0;
}

/* The short lists, each line led by one of the bot's mint emoji. flex: 1 is what pushes
   every card's button down to the shared bottom line. */
ul.plan-points { list-style: none; padding: 0; margin: 16px 0 18px; flex: 1; }
ul.plan-points li {
  display: flex;
  gap: 9px;
  padding: 6px 0;
  font-size: 13.4px;
  line-height: 1.5;
  color: var(--dim);
}
ul.plan-points li img { flex: none; margin-top: 1px; }
ul.plan-points li b { color: var(--text); }

/* Full width, so the columns' buttons line up whatever their labels say. */
.plan .button { width: 100%; }

.pricing-foot { max-width: 58ch; margin: 22px auto 0; }

/* ── the feature rows, each with its little picture ──────────────── */
/* Text one side, a small HTML drawing of the feature the other, alternating so the
   scroll has a rhythm. The two Discord embeds reuse the global .dmock classes. */
.feat-duo {
  display: flex; gap: 22px; align-items: center;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 20px 22px; margin-bottom: 12px; text-align: left;
  transition: transform .15s var(--ease), border-color .15s var(--ease);
}
.feat-duo:hover { transform: translateY(-3px); border-color: rgba(61, 220, 151, .4); }
.feat-duo.flip { flex-direction: row-reverse; }
.feat-words { flex: 1; min-width: 0; }
.feat-words h3 { font-size: 15.5px; margin: 0 0 6px; }
.feat-words .fine { font-size: 13px; }
.feat-pic { flex: 0 0 235px; }
@media (max-width: 620px) {
  .feat-duo, .feat-duo.flip { flex-direction: column; }
  .feat-pic { flex: none; width: 100%; }
}

/* A digest line inside a .dmock embed, for the weekly summary picture. */
.dmock-line { color: #dbdee1; font-size: 11.5px; font-weight: 400; padding: 1.5px 0; }

/* The year: six bars free would forget, six it keeps. */
.feat-bars {
  display: flex; gap: 4px; align-items: flex-end; height: 78px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 12px 8px;
}
.feat-bars i { flex: 1; border-radius: 3px 3px 0 0; background: var(--mint); opacity: .9; }
.feat-bars i.old { background: var(--line-bright); }
.feat-bars-cap { text-align: center; font-size: 10.5px; color: var(--faint);
                 font-weight: 400; margin-top: 5px; }

/* The export: a few rows of pretend CSV. */
.feat-csv {
  background: #0a0f0d; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; font: 500 10.5px/1.75 ui-monospace, Consolas, monospace;
  color: var(--dim); overflow: hidden;
}
.feat-csv b { color: var(--mint); font-weight: 700; display: block; }

/* The limits: three meters filling up. */
.feat-meters { background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
               padding: 12px 14px; }
.feat-meter { margin-bottom: 8px; }
.feat-meter:last-child { margin-bottom: 0; }
.feat-meter .lab { display: flex; justify-content: space-between; font-size: 10.5px;
                   color: var(--dim); font-weight: 400; margin-bottom: 3px; }
.feat-meter .lab b { color: var(--mint); }
.feat-meter .track { height: 7px; border-radius: 999px; background: var(--line);
                     overflow: hidden; }
.feat-meter .fillbar { height: 100%; border-radius: 999px;
                       background: linear-gradient(90deg, var(--mint), var(--mint-bright)); }

/* The queue: your ticket glowing at the front of it. */
.feat-queue { background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
              padding: 10px 12px; }
.feat-queue .qrow { display: flex; align-items: center; gap: 8px; padding: 6px 8px;
                    border-radius: 8px; font-size: 11.5px; font-weight: 400;
                    color: var(--dim); }
.feat-queue .qrow.you { background: rgba(61, 220, 151, .10);
                        border: 1px solid rgba(61, 220, 151, .35);
                        color: var(--text); font-weight: 700; }
.feat-queue .dotq { width: 7px; height: 7px; border-radius: 50%;
                    background: var(--line-bright); flex: none; }
.feat-queue .qrow.you .dotq { background: var(--mint);
                              box-shadow: 0 0 8px rgba(61, 220, 151, .8); }

/* ── the message builder ─────────────────────────────────────────── */
body.embed-page main { max-width: 1160px; }

.build-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
.build-fields .card:last-of-type { margin-bottom: 12px; }

/* The preview follows you down a long form. There is no point in a live preview you have to
   scroll back up to look at. */
.build-preview { position: sticky; top: 84px; align-self: start; }
.build-preview .fine { margin-top: 12px; }

.sticky-send {
  position: sticky;
  bottom: 0;
  gap: 10px;
  padding: 14px 0;
  background: linear-gradient(transparent, var(--bg) 28%);
}

.colour-row { display: flex; align-items: center; gap: 12px; margin-top: 6px; }
.colour-row input[type="color"] {
  width: 46px; height: 34px; padding: 2px;
  background: var(--surface-3);
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  cursor: pointer;
}

/* Only appears once you are near the limit, so it reads as a warning rather than furniture. */
.count { display: block; margin-top: 4px; font-size: 11.6px; color: var(--faint); }
.count.over { color: var(--danger); font-weight: 600; }

.field-row {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 14px 14px 2px;
  margin-bottom: 11px;
  background: rgba(12, 19, 17, .4);
}
.field-head { display: flex; justify-content: space-between; align-items: center;
              margin-bottom: 10px; font-size: 13px; }

/* ── the preview itself ──────────────────────────────── */
/* Discord's own dark theme, not this site's. Everything below is deliberately hardcoded
   rather than using the variables the rest of the page runs on: the whole job of this panel
   is to look like somewhere else, and inheriting a mint accent from the surrounding page
   would make it a worse preview every time the site's palette changed.

   The values are Discord's current dark theme. Chat #313338, embeds a shade darker at
   #2b2d31, body text #dbdee1, headings #f2f3f5, muted #949ba4, links #00a8fc, blurple
   #5865f2 for the APP badge.

   Prefixed dc- because one of them, --text, is also the name of a variable this site
   defines at the root. Redefining it here would quietly shadow it for anything nested
   inside the preview. */
.dc {
  --dc-chat: #313338;
  --dc-embed: #2b2d31;
  --dc-sunk: #1e1f22;
  --dc-text: #dbdee1;
  --dc-bright: #f2f3f5;
  --dc-muted: #949ba4;
  --dc-link: #00a8fc;
  --dc-blurple: #5865f2;

  border-radius: 8px;
  overflow: hidden;
  background: var(--dc-chat);
  border: 1px solid #26282c;
  /* gg sans is Discord's own and isn't licensed for use here, so this names it first for
     anyone who happens to have it and falls back to the same stack Discord itself falls back
     to. It is the one thing that cannot be exact. */
  font-family: "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.dc-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--dc-chat);
  box-shadow: 0 1px 0 rgba(4, 4, 5, .2), 0 1.5px 0 rgba(6, 6, 7, .05);
  color: var(--dc-bright);
  font-size: 16px;
  font-weight: 600;
}
.dc-hash { width: 20px; height: 20px; flex: none; color: var(--dc-muted); }

.dc-chat { padding: 16px 16px 18px; }
.dc-msg { display: flex; gap: 16px; }

.dc-avatar {
  width: 40px; height: 40px; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--dc-blurple);
  color: #fff;
  font-size: 17px;
  font-weight: 500;
}

.dc-body { min-width: 0; flex: 1; }
.dc-meta { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.dc-name { color: var(--dc-bright); font-size: 16px; font-weight: 500; line-height: 1.375; }
.dc-app {
  background: var(--dc-blurple);
  color: #fff;
  border-radius: 3px;
  padding: 0 4px;
  height: 15px;
  display: inline-flex;
  align-items: center;
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
}
.dc-when { color: var(--dc-muted); font-size: 12px; }

.dc-text {
  color: var(--dc-text);
  font-size: 16px;
  line-height: 1.375;
  white-space: pre-wrap;
  word-wrap: break-word;
  margin-bottom: 4px;
}

/* The left bar is set from the colour picker, so only the fallback lives here. */
.dc-embed {
  max-width: 520px;
  margin-top: 8px;
  border-left: 4px solid var(--dc-sunk);
  border-radius: 4px;
  background: var(--dc-embed);
  padding: 8px 16px 16px 12px;
}

/* Discord lays an embed out as a grid: everything in the first column, the thumbnail beside
   it in the second, and the image and footer across both. */
.dc-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0 16px;
}
.dc-col { grid-column: 1; min-width: 0; }
.dc-thumb {
  grid-column: 2; grid-row: 1;
  width: 80px; height: 80px;
  margin-top: 8px;
  border-radius: 4px;
  object-fit: cover;
}
.dc-image, .dc-foot { grid-column: 1 / -1; }

.dc-author {
  display: flex; align-items: center; gap: 8px;
  margin-top: 8px;
  color: var(--dc-bright);
  font-size: 14px;
  font-weight: 600;
}
.dc-author img { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; }

.dc-title {
  margin-top: 8px;
  color: var(--dc-bright);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.375;
}
.dc-desc {
  margin-top: 8px;
  color: var(--dc-text);
  font-size: 14px;
  line-height: 1.125rem;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.dc-title.linked { color: var(--dc-link); cursor: pointer; }
.dc-title.linked:hover { text-decoration: underline; }
.dc-desc a, .dc-text a { color: var(--dc-link); text-decoration: none; }
.dc-desc a:hover, .dc-text a:hover { text-decoration: underline; }
.dc-desc code, .dc-text code {
  background: var(--dc-sunk);
  border-radius: 3px;
  padding: 0 2px;
  font-family: Consolas, "Andale Mono WT", "Andale Mono", monospace;
  font-size: 85%;
}
.dc-desc code.block, .dc-text code.block {
  display: block;
  padding: 8px;
  margin-top: 6px;
  border: 1px solid var(--dc-sunk);
  font-size: 12px;
  line-height: 1.125rem;
}
.dc-desc .h1 { font-size: 24px; } .dc-desc .h2 { font-size: 20px; }
.dc-desc .h3 { font-size: 16px; }
.dc-desc small, .dc-text small { color: var(--dc-muted); font-size: 12px; }

/* Discord splits an embed into twelve columns and gives each inline field four of them, so
   three sit in a row and a full-width one takes the lot. */
/* minmax(0, 1fr) rather than 1fr: a bare 1fr track still refuses to shrink below its
   content's minimum width, so a field name long enough to matter widened its column and
   pushed the next field onto a row of its own. */
.dc-fields {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 8px;
  margin-top: 8px;
}
.dc-field { grid-column: span 12; min-width: 0; }
.dc-field.inline { grid-column: span 4; }
.dc-field b {
  display: block;
  color: var(--dc-bright);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.125rem;
  margin-bottom: 2px;
}
.dc-field span {
  color: var(--dc-text);
  font-size: 14px;
  line-height: 1.125rem;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.dc-image {
  display: block;
  max-width: 100%;
  margin-top: 16px;
  border-radius: 4px;
}

.dc-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  color: var(--dc-muted);
  font-size: 12px;
  font-weight: 500;
  line-height: 1rem;
}
.dc-foot img { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; }

.dc-nothing { margin: 8px 0 0; color: var(--dc-muted); font-size: 14px; }

@media (max-width: 900px) {
  .build-cols { grid-template-columns: minmax(0, 1fr); }
  /* Three inline fields in an embed this narrow is about twenty pixels of text each. Two
     across stays readable and is what Discord's own app does at this width. */
  .dc-field.inline { grid-column: span 6; }
  /* Stuck to the top of a phone it would cover the field being typed into. */
  .build-preview { position: static; }
}

/* ── insights ────────────────────────────────────────────────────── */
/* Wider than the settings pages: a twelve point line squeezed into 800px is a scribble. */
body.insights-page main { max-width: 1000px; }

/* A modifier rather than a rule on .page-head itself, which the changelog, status and support
   pages also use with a single child. Making that flex would change how their text wraps for
   no reason. */
.page-head.split { display: flex; align-items: flex-start;
  justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.page-head.split h1 { margin-bottom: 0; }

.stat-big {
  display: block;
  font-size: 30px;
  font-weight: 650;
  letter-spacing: -1px;
  line-height: 1.1;
  margin: 3px 0 2px;
}

/* Which way it moved, in a colour you can read before the number. Up is not automatically
   good on every metric, but on retention it is. */
.delta { font-size: 12.8px; font-weight: 600; }
.delta.up { color: var(--mint); }
.delta.down { color: var(--warn); }

.chart-card { padding-bottom: 18px; }
.chart-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.chart-top h2 { margin-bottom: 4px; }
.chart-top .fine { max-width: 52ch; }

/* Links rather than buttons: each period is its own url, so a chart can be linked to and the
   back button does what it should. .seg is shared with the pricing toggle. */
.periods { display: inline-flex; gap: 4px; padding: 4px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px; }
.periods .seg { text-decoration: none; display: inline-flex; align-items: center; }

/* The chart keeps its shape and scrolls rather than squashing. A line chart compressed onto a
   phone stops being readable long before it stops fitting. */
/* The inner layer scrolls sideways; the outer one holds the tooltip and does not clip, so a
   tooltip above a tall point is not cut off at the top. */
.chart-scroll { overflow-x: auto; margin: 0 -4px; padding: 0 4px; }
svg.trend { display: block; width: 100%; min-width: 460px; height: auto; overflow: visible; }

/* Faint, and lighter still away from the axis, so the grid guides the eye without competing
   with the line. The zero line is drawn a touch stronger to anchor the floor. */
svg.trend .gridline { stroke: var(--line); stroke-width: 1; opacity: .5; }
svg.trend .gridline.baseline { opacity: .9; }
svg.trend .axis { fill: var(--faint); font-size: 11px;
  font-family: ui-sans-serif, -apple-system, "Segoe UI", sans-serif; }
svg.trend .line {
  fill: none;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* The curve is smooth now, so ask the browser to draw it smoothly rather than snapping to
     the pixel grid, which is what left it looking faceted up close. */
  shape-rendering: geometricPrecision;
}

/* Green for arriving, red for leaving, everywhere the two appear: the lines, the dots, the
   legend and the toggle. Nobody should have to consult a key to know which is which. */
svg.trend .line.joins { stroke: var(--mint); }
svg.trend .line.leaves { stroke: var(--danger); }

/* The fill is a vertical fade painted by the gradients in <defs>: colour at the line, gone by
   the axis. The stop colours live here so the same rule serves the server render and the one
   the script rebuilds. */
#fill-joins stop { stop-color: var(--mint); }
#fill-leaves stop { stop-color: var(--danger); }
#fill-joins .g0, #fill-leaves .g0 { stop-opacity: .26; }
#fill-joins .g1, #fill-leaves .g1 { stop-opacity: 0; }
/* Both lines at once means two fills overlapping, which muddies where they cross. They ease
   back a little and let the lines carry it. */
svg.trend.both .area { opacity: .72; }

/* An empty chart is still a chart. The axes stay put and fade back a little, so it reads as
   waiting for numbers rather than as something that failed to load. */
svg.trend.bare .gridline { stroke-dasharray: 3 4; opacity: .45; }
svg.trend.bare .axis { opacity: .55; }
svg.trend .nothing {
  fill: var(--faint);
  font-size: 13px;
  font-family: ui-sans-serif, -apple-system, "Segoe UI", sans-serif;
}

/* Two kinds of dot. The static ones are the no-script fallback: small and quiet, just enough
   to carry the native tooltip. The focus dot is what the script shows instead, a single ring
   that follows the pointer along the line. */
svg.trend .dot { stroke: var(--bg); stroke-width: 2; }
svg.trend .dot.joins { fill: var(--mint); }
svg.trend .dot.leaves { fill: var(--danger); }
svg.trend .dot.static { opacity: .5; }
svg.trend .dot.focus {
  stroke-width: 3;
  filter: drop-shadow(0 0 5px rgba(0, 0, 0, .55));
}
svg.trend .dot.focus.joins { fill: var(--mint-bright); }

/* Transparent columns, one per bucket, spanning the full height of the plot. The dots are
   3.5px across and nobody should have to aim at one. */
svg.trend .hit { fill: transparent; }
svg.trend .guide { stroke: var(--line-bright); stroke-width: 1; stroke-dasharray: 3 3; }

/* Positioned against the wrapper rather than the svg, because the svg scales and the wrapper
   is what scrolls. */
.chart-wrap { position: relative; overflow: visible; }

.tip {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  /* Above the point, clearing it by 12px. On a tall point near the top of the chart there is
     no room above, so .below drops it under the point instead (set by the script). */
  transform: translate(-50%, calc(-100% - 12px));
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 12px;
  border-radius: 10px;
  background: rgba(12, 19, 17, .95);
  border: 1px solid var(--line-bright);
  box-shadow: 0 16px 34px -18px #000;
  font-size: 13px;
  line-height: 1.45;
  white-space: nowrap;
  backdrop-filter: blur(6px);
}
.tip.below { transform: translate(-50%, 14px); }
.tip-when { color: var(--faint); font-size: 12px; letter-spacing: .2px; }
.tip-row { display: flex; align-items: center; gap: 7px; color: var(--dim); }
.tip-row i { width: 9px; height: 9px; border-radius: 50%; background: var(--mint); }
.tip-row i.leaves { background: var(--danger); }
.tip-row b { color: var(--text); font-weight: 650; }

.chart-controls { display: flex; flex-wrap: wrap; gap: 8px; }

/* The selected series is coloured like the line it switches on, so the toggle says which is
   which before the chart has been read. */
.periods.series .seg.leaves.on,
.periods.series .seg.leaves.on:hover {
  background: linear-gradient(135deg, #f8a0a0, var(--danger));
  box-shadow: 0 6px 18px -10px var(--danger);
  color: #2a0d0d;
}

.legend { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 15px; }
.key { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--dim); }
.key i { width: 15px; height: 3px; border-radius: 2px; background: var(--mint); }
.key.leaves i { background: var(--danger); }
.key b { color: var(--text); font-weight: 650; }
/* The one number on the page that is a subtraction, so it says which way it went. */
.key.net b { color: var(--mint); }
.key.net.down b { color: var(--danger); }

.meter-note { margin: -4px 0 12px 120px; font-size: 12.4px; }
.meter.small { height: 7px; width: 74px; }

.rate-cell { display: flex; align-items: center; gap: 9px; }
.rate-cell b { font-size: 14px; color: var(--mint-bright); }

table.invites td { vertical-align: middle; }
.invites-more { margin-top: 14px; }

/* ── command permissions ─────────────────────────────────────────── */
label.check.big { font-size: 15.5px; font-weight: 600; }
.perm-sync { color: var(--mint-bright); }

/* Dimmed, not hidden, while the whole thing is off, so it can be set up first. */
[data-perms-body].perms-off { opacity: .5; }
[data-perms-body].perms-off .perm-save { display: none; }

.radio { display: flex; align-items: center; gap: 9px; margin: 6px 0; font-size: 14px;
  color: var(--dim); cursor: pointer; }
.radio input { accent-color: var(--mint); width: 16px; height: 16px; }

/* A category is a details card: the summary is its name and the commands it covers, and it
   opens to the role lists. */
.perm-cat { padding: 0; }
.perm-cat > summary { padding: 16px 18px; cursor: pointer; list-style: none; }
.perm-cat > summary::-webkit-details-marker { display: none; }
.perm-cat > summary::before { content: "▸"; color: var(--faint); margin-right: 9px;
  display: inline-block; transition: transform .15s var(--ease); }
.perm-cat[open] > summary::before { transform: rotate(90deg); }
.perm-cat-name { font-weight: 650; font-size: 15px; margin-right: 10px; }
.perm-cat > summary code, .perm-add code, .perm-override code { font-size: 11.8px; }
.perm-cat > p, .perm-cat > .perm-roles, .perm-cat > .perm-adv { margin: 0 18px; }
.perm-cat > .perm-adv { margin-bottom: 16px; }

/* One list of roles, each with a leave / allow / block control on the right. min-width:0 on the
   row lets a long role name ellipse rather than shove the control off the card. */
.perm-roles { margin: 8px 0; }
.perm-roles-head { display: flex; align-items: center; gap: 12px; }
.perm-search {
  flex: 1; min-width: 0; max-width: 260px; margin: 0 0 0 auto;
  padding: 6px 11px; background: var(--surface); color: var(--text);
  border: 1px solid var(--line-bright); border-radius: var(--r-sm);
  font: inherit; font-size: 13px;
}
.perm-search:focus { outline: none; border-color: var(--mint); box-shadow: 0 0 0 3px var(--mint-glow); }
.perm-rolelist { max-height: 300px; }
.perm-role-row {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px; border-bottom: 1px solid var(--line);
}
.perm-role-row:last-child { border-bottom: 0; }
.perm-role-row .swatch { flex: none; }
.perm-role-row .rolename {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13.5px;
}

/* The three-way control, from three radios. The label is the button; the radio is hidden and
   drives which one reads as on via :has. */
.tri { flex: none; display: inline-flex; border: 1px solid var(--line-bright);
  border-radius: 999px; overflow: hidden; background: var(--bg); }
.tri-opt { display: inline-flex; align-items: center; cursor: pointer; margin: 0; }
.tri-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.tri-opt span {
  display: inline-block; padding: 4px 11px; font-size: 12px; font-weight: 600;
  color: var(--faint); transition: background-color .12s var(--ease), color .12s var(--ease);
}
.tri-opt + .tri-opt span { border-left: 1px solid var(--line-bright); }
.tri-opt:hover span { color: var(--dim); }
.tri-opt.allow:has(input:checked) span { background: var(--mint); color: #05221a; }
.tri-opt.deny:has(input:checked) span { background: var(--danger); color: #2a0d0d; }
.tri-opt.neutral:has(input:checked) span { background: var(--surface-3); color: var(--text); }
/* Focus ring for keyboard users, since the real radio is hidden. */
.tri-opt:has(input:focus-visible) span { box-shadow: inset 0 0 0 2px var(--mint); }

.perm-empty { margin: 8px 0 0; }

/* The two user-id boxes, side by side then stacking. */
.perm-users { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px;
  margin: 4px 0; }
@media (max-width: 620px) { .perm-users { grid-template-columns: 1fr; } }

.perm-adv { margin-top: 8px; }
.perm-adv > summary { cursor: pointer; color: var(--mint-bright); font-size: 12.8px;
  font-weight: 600; padding: 4px 0; }
.perm-adv input[type="text"] { width: 100%; }
.perm-override .perm-roles, .perm-override .perm-adv { margin: 8px 0 0; }

.perm-override { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 14px 16px;
  margin-bottom: 12px; background: var(--surface); }
.perm-override-head { display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px; }
.link.danger { color: var(--danger); background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 12.8px; }

.perm-add { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 4px 0 10px; }
.perm-add select { min-width: 200px; }
.perm-save { margin-top: 18px; }
table.invites .fine { margin-top: 3px; }

@media (max-width: 560px) {
  .meter-note { margin-left: 0; }
  .chart-top { flex-direction: column; }
}

/* ── unsaved changes ─────────────────────────────────────────────── */
/* Built by the script, so it never appears on a page that can't clear it. */
.unsaved {
  display: none;
  align-items: center;
  gap: 11px;
  margin: 18px 0 0;
  padding: 9px 9px 9px 13px;
  border-radius: var(--r-sm);
  background: rgba(240, 180, 95, .1);
  border: 1px solid rgba(240, 180, 95, .32);
  color: #f6dcaf;
  font-size: 13.2px;
  animation: rise .25s var(--ease);
}
.unsaved span { flex: 1; }
form.dirty .unsaved { display: flex; }

/* The pane may be hidden behind another tab, so the tab itself has to say so. */
.sidenav .udot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--warn);
  box-shadow: 0 0 0 3px rgba(240, 180, 95, .18);
}

/* ── rows that reveal their own settings ─────────────────────────── */
/* Only ever hidden by script, so with JavaScript off the whole form is there. */
.js [data-reveals]:not(.on) .when-on { display: none; }

/* ── automod ─────────────────────────────────────────────────────── */
.amrow { align-items: flex-start; flex-wrap: wrap; }
.amrow label.pick { align-items: flex-start; padding-top: 2px; }

/* A word list or an allow list belongs to its rule, so it sits inside the row and comes and
   goes with it. */
.amsub {
  flex-basis: 100%;
  margin: 10px 0 2px 44px;
  font-size: 12.5px;
  color: var(--dim);
}
.amsub textarea { min-height: 52px; font-size: 13.5px; }
.amsub .lg-blurb { display: block; margin-top: 5px; }

.mini-head {
  display: block;
  margin-bottom: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
}

/* Short, because these lists sit side by side and neither should push the card long. */
/* The exemption lists sit side by side, and a server with thirty roles and three channels
   gave one box 200px and the other 76, which read as a mistake rather than as two lists.
   Grid rows stretch by default, so making each column a column and letting the list fill it
   squares them off against whichever is taller. */
.row > div { display: flex; flex-direction: column; min-width: 0; }
.rolelist.short { max-height: 200px; margin-top: 0; flex: 1; }

/* The thresholds and the action sit together on the right, so the left column stays a
   readable list of rule names rather than a row of scattered controls. */
.amset {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.amset select { width: 176px; margin-top: 0; padding: 6px 30px 6px 10px; font-size: 13px;
                background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%; }

label.num {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  text-transform: uppercase;
  color: var(--faint);
}
label.num input {
  width: 76px;
  margin-top: 3px;
  padding: 5px 8px;
  font-size: 13px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  font-family: inherit;
}
label.num input:focus {
  outline: none;
  border-color: var(--mint);
  box-shadow: 0 0 0 3px var(--mint-glow);
}

/* ── sub-sections inside one card ────────────────────────────────── */
/* The automod pane is four of these stacked: the rules, the exemptions, the age gate and the
   punishments. They used to run together with nothing but a slightly bolder line of text
   between, so the pane read as one long unbroken form and it was never obvious which controls
   belonged to which idea. A rule and a small capitalised label separate them, which is what
   the logging pane's own headers wanted too, so both share this. */
.sub-head,
.logtools {
  margin: 30px 0 14px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--faint);
}
.logtools .fine {
  margin: 0;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
}

/* The sentence under a heading is the explanation for the whole sub-section, so it sits with
   the heading rather than floating above the first control. */
.sub-head + .fine { margin: -6px 0 14px; max-width: 68ch; }

/* Two numbers, not two full width boxes. They were stretching to half the card each, which
   made a 10 and a 5 look like the most important things on the page. */
.amlimits { display: flex; flex-wrap: wrap; gap: 10px 22px; }
.amlimits label { flex: 0 1 210px; margin: 0; }

@media (max-width: 620px) {
  .amrow { flex-wrap: wrap; }
  .amrow label.pick { flex-basis: 100%; }
  .amset { width: 100%; justify-content: flex-start; }
  .amset select { flex: 1; width: auto; min-width: 0; }
  .amsub { margin-left: 0; }
}

/* ── text inputs and panels ──────────────────────────────────────── */
/* Text and number fields are dressed by the select/textarea rule near the top of the
   file; what is left here is what only they need. */

/* A box for "7" does not need to be as wide as one for a welcome message. Capped rather than
   fixed so it still shrinks on a narrow screen. */
input[type="number"] { max-width: 150px; }
/* Firefox and Chrome both put spinners on these. They are tiny, they are ugly against this
   background, and nobody has ever nudged a timeout up one minute at a time. */
input[type="number"] { -moz-appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Inside a role row these sit beside the name, so they shed the block layout above. */
input.mini {
  width: 132px;
  flex: none;
  margin-top: 0;
  padding: 5px 9px;
  font-size: 13px;
}
input.mini.emoji { width: 78px; }

.panel {
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  padding: 17px;
  margin-top: 15px;
  background: var(--bg);
}
.panel.new { border-style: dashed; }
.panel h3 { margin: 0 0 12px; font-size: 15.5px; }
.panel .warn, .panel .note { margin-bottom: 14px; }

/* minmax(0, 1fr) rather than 1fr, so a long channel name can't widen the column past the card */
.row { display: grid; gap: 13px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.row.end { display: flex; gap: 10px; margin-top: 15px; }

.note {
  border-radius: var(--r-sm);
  padding: 9px 13px;
  font-size: 13.4px;
  background: var(--surface-3);
  border: 1px solid var(--line-bright);
  color: var(--dim);
}
.note.ok { color: #b9f4da; border-color: rgba(61, 220, 151, .3); }

button.danger {
  background: none;
  color: var(--warn);
  border: 1px solid rgba(240, 180, 95, .4);
  box-shadow: none;
}
button.danger:hover {
  background: rgba(240, 180, 95, .12);
  filter: none;
  transform: none;
  box-shadow: none;
}

@media (max-width: 620px) {
  .row { grid-template-columns: minmax(0, 1fr); }
  /* The label and emoji boxes stop fitting beside the role name, so give them their own line.
     min-width: 0 as well, or an input's default intrinsic width keeps them from sharing it. */
  .rolerow { flex-wrap: wrap; }
  label.pick { flex-basis: 100%; }
  input.mini { flex: 1; width: auto; min-width: 0; }
  input.mini.emoji { flex: 0 1 88px; }
  .why { flex-basis: 100%; text-align: left; }
}

code {
  background: var(--surface-3);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1.5px 6px;
  font-size: 12.4px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color: var(--mint-bright);
}

/* ── notices ─────────────────────────────────────────────────────── */
.flash, .warn {
  display: flex;
  gap: 10px;
  border-radius: var(--r-sm);
  padding: 12px 15px;
  margin: 0 0 20px;
  font-size: 14.2px;
  animation: rise .35s var(--ease);
}

.flash {
  background: linear-gradient(100deg, rgba(61, 220, 151, .13), rgba(61, 220, 151, .05));
  border: 1px solid rgba(61, 220, 151, .35);
  color: #b9f4da;
}
.flash::before { content: "✓"; color: var(--mint); font-weight: 700; }

.warn {
  background: linear-gradient(100deg, rgba(240, 180, 95, .12), rgba(240, 180, 95, .04));
  border: 1px solid rgba(240, 180, 95, .35);
  color: #f6dcaf;
}
.warn::before { content: "!"; color: var(--warn); font-weight: 700; }

@keyframes rise {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

ul.plain { list-style: none; padding: 0; }
ul.plain li { margin-bottom: 7px; }

/* The columned footer, design B from the mockups: brand blurb left, three link columns,
   the copyright on its own rule. Left-aligned, unlike the centred row it replaced. */
footer {
  color: var(--faint);
  font-size: 12.6px;
  padding: 0 22px 40px;
  max-width: 1060px;
  margin: 0 auto;
}
footer p { margin: 0; }
.foot-live { text-align: center; margin-bottom: 18px !important; }

.foot-grid {
  display: flex;
  gap: 28px 46px;
  flex-wrap: wrap;
  padding-top: 26px;
  border-top: 1px solid var(--line);
  text-align: left;
}
.foot-about { max-width: 240px; }
.foot-brand {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--text); font-weight: 800; font-size: 15px;
}
.foot-about p { margin-top: 8px; color: var(--faint); font-weight: 400; line-height: 1.6; }
.foot-col h4 {
  font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--faint); margin: 0 0 10px;
}
.foot-col a { display: block; padding: 3px 0; font-size: 13px; color: var(--dim);
              font-weight: 400; text-decoration: none; }
.foot-col a:hover { color: var(--mint); }
.foot-bottom {
  border-top: 1px solid var(--line);
  margin-top: 22px !important;
  padding-top: 14px;
  text-align: left;
}

/* ── small screens ───────────────────────────────────────────────── */
@media (max-width: 560px) {
  .bar { padding: 12px 16px; gap: 10px; }
  main { padding: 28px 16px 64px; }
  h1 { font-size: 25px; }
  .hero { padding: 52px 0 40px; }
  .who span { display: none; }
  .grid { grid-template-columns: 1fr; }
  /* The plan columns stack, so they line up with the rest of the page rather than sitting
     inset by a few pixels, which is all a centred column buys you at this width. */
  .js .plan-grid, .plan-grid { grid-template-columns: 1fr; }
  .premium-hero { padding: 38px 0 32px; }

  /* The nav scrolls rather than pushing the account block off the page. min-width: 0 is the
     part that matters: without it a flex child refuses to shrink below its content, so every
     link added to the header widens the whole document. */
  .bar-left { gap: 15px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  .bar-left::-webkit-scrollbar { display: none; }
  .bar-left .nav-link { flex: none; }
  .who { flex: none; gap: 9px; }

  /* The account block has to earn its width at this size. The avatar goes first: "Log out"
     being on the page already says somebody is signed in, and the picture was the only part
     that said nothing the rest didn't. That plus a tighter button buys the nav back about
     sixty pixels, which is the difference between it scrolling and it looking clipped. */
  .who img { display: none; }
  .who .button.small { padding: 7px 11px; font-size: 13.2px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
/* ── the soundboard page ─────────────────────────────────────────── */
/* The rows are a list you edit in place, not a stack of forms. That distinction is the whole
   look: the global input rule here is `display:block; width:100%; margin-top:7px`, which is
   right for a settings pane and turns a row of five controls into five stacked boxes, so
   everything inside .sound opts out of it deliberately. */

/* The warning is the first thing on the page and was competing with the page. Quieter: a rule
   down the mint side, no card chrome, and the detail at reading size rather than heading size. */
.note-card {
  border: 0;
  border-left: 2px solid var(--mint);
  border-radius: 0;
  background: rgba(61, 220, 151, .045);
  padding: 14px 18px;
}
.note-card p { margin: 0 0 6px; font-size: 14px; }
.note-card p:last-child { margin: 0; }

/* ── adding one ──────────────────────────────────────────────────── */
/* Four controls of wildly different natural widths. A grid gives them honest ones: a name is
   long, an emoji is one character, and a slider needs no more than a thumb's travel. */
.sound-add {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px 150px;
  gap: 14px 16px;
  align-items: end;
}
.sound-add label { margin: 0; }
.sound-add .drop { grid-column: 1 / -1; }
.sound-add .go { grid-column: 1 / -1; justify-self: start; }

/* A file input renders as unstyleable browser furniture, so the real one is hidden and its
   label is the control. Clicking a label for a file input opens the picker for free. */
.drop {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px dashed var(--line-bright);
  border-radius: var(--r-sm);
  background: var(--bg);
  cursor: pointer;
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.drop:hover, .drop:focus-within { border-color: var(--mint); background: rgba(61, 220, 151, .05); }
.drop input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.drop-icon {
  width: 38px; height: 38px;
  flex: none;
  display: grid; place-items: center;
  border-radius: 10px;
  background: rgba(61, 220, 151, .1);
  border: 1px solid rgba(61, 220, 151, .22);
  font-size: 16px;
}
.drop-text { min-width: 0; }
.drop-text b { display: block; font-size: 14px; font-weight: 600; }
.drop-text span { display: block; margin-top: 2px; color: var(--faint); font-size: 12.4px; }
.drop-text span.bad { color: var(--warn); }
.drop-text span.good { color: var(--mint-bright); }

/* ── the list ────────────────────────────────────────────────────── */
/* Laid out the way Discord's own soundboard panel is: column headers, the emoji in its own
   column at a size you can actually read, and hairlines between rows rather than a bordered
   box around each one. The columns live in one custom property so the header and the rows
   cannot drift apart. */
.sounds-wrap {
  --sound-cols: 16px 34px 54px minmax(0, 1fr) 108px minmax(0, 150px) 62px 68px;
  margin-bottom: 16px;
}

.sounds-head,
.sound {
  display: grid;
  grid-template-columns: var(--sound-cols);
  align-items: center;
  gap: 14px;
}

.sounds-head {
  padding: 0 6px 11px;
  border-bottom: 1px solid var(--line);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  /* Brighter than the usual small print. On Discord's panel these read as column headings
     rather than as a footnote, and at --faint they disappeared into the background. */
  color: var(--dim);
}

.sounds {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sound {
  padding: 12px 6px;
  border-bottom: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.sound:hover { background: var(--surface); }
.sound.held { opacity: .4; }
.sound-edit, .sound-delete { display: contents; }

/* Only where the grip is, so the row still selects and the inputs still take a caret. */
.grip {
  cursor: grab;
  color: transparent;
  font-size: 13px;
  line-height: 1;
  text-align: center;
  user-select: none;
  transition: color .15s var(--ease);
}
.grip:active { cursor: grabbing; }
.sound:hover .grip { color: var(--faint); }

.play {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 1px solid var(--line-bright);
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text);
  font-size: 10px;
  cursor: pointer;
  /* `.button, button` further up gives every button a mint glow. Right for a call to action,
     wrong for thirty of them stacked down a list. */
  box-shadow: none;
  transition: border-color .15s var(--ease), color .15s var(--ease),
              background .15s var(--ease);
}
.play:hover { border-color: var(--mint); color: var(--mint); }
.play.on { border-color: var(--mint); background: var(--mint); color: #06251c; }

/* Borderless until you go near them. A field that looks like a field on every row makes forty
   sounds look like forty forms; a field that looks like text until hovered looks like a list
   you can edit, which is what it is. */
.sound input[type="text"],
.sound input[type="range"] {
  display: block;
  width: 100%;
  margin: 0;
}
.sound input[type="text"] {
  padding: 5px 8px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  font-size: 15px;
}
.sound:hover input[type="text"] { border-color: var(--line); background: var(--bg); }
.sound input[type="text"]:hover { border-color: var(--line-bright); }
.sound input[type="text"]:focus {
  border-color: var(--mint);
  background: var(--bg);
  box-shadow: 0 0 0 3px var(--mint-glow);
}
.s-name { font-weight: 500; color: var(--text); }

/* Its own column, the size Discord draws it. A single character in a 14px box next to a name
   was the thing that made this look like a form and not a soundboard. */
/* `input.s-emoji` rather than `.s-emoji`: the borderless rule above is
   `.sound input[type="text"]`, which outranks a bare class and was holding this at 14px. */
.sound input.s-emoji {
  text-align: center;
  font-size: 22px;
  line-height: 1.1;
  padding: 2px 0;
}
/* Repeated down every row that has no emoji yet, so it whispers rather than reads as content. */
.sound input::placeholder { color: var(--faint); opacity: .45; }

/* Who uploaded it, avatar first, the way Discord shows it. */
.s-by {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 14px;
  color: var(--dim);
}
.s-by > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.s-avatar { border-radius: 50%; flex: none; background: var(--surface-3); }
.s-by .unknown { color: var(--faint); }

/* The browser's own slider is grey with a white thumb and looks like nothing else here.

   Two heights, one look. In a row the input is the track, 4px tall, because that is all the
   vertical space there is. In the add form it has to occupy the same box as a text input or
   `align-items: end` lines the label up against nothing, so there the element is 40px and the
   track is drawn by the pseudo element inside it. */
.sound input[type="range"], .sound-add input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  box-shadow: none;
}
.sound input[type="range"] {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
}
.sound-add input[type="range"] {
  height: 42px;
  margin-top: 7px;
  background: none;
}
.sound-add input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
}
.sound-add input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
}
.sound-add input[type="range"]::-webkit-slider-thumb { margin-top: -4.5px; }
.sound input[type="range"]::-webkit-slider-thumb,
.sound-add input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px; height: 13px;
  border: 0;
  border-radius: 50%;
  background: var(--mint);
  cursor: grab;
}
.sound input[type="range"]::-moz-range-thumb,
.sound-add input[type="range"]::-moz-range-thumb {
  width: 13px; height: 13px;
  border: 0;
  border-radius: 50%;
  background: var(--mint);
  cursor: grab;
}
.sound input[type="range"]:focus, .sound-add input[type="range"]:focus {
  outline: none;
  box-shadow: 0 0 0 3px var(--mint-glow);
}

/* Both row buttons stay out of the way until the row is hovered. Delete only turns red when
   you reach for it, so a list of forty does not read as forty warnings. */
.sound .button.tiny {
  padding: 6px 11px;
  font-size: 12.5px;
  border-radius: var(--r-sm);
  background: none;
  border: 1px solid var(--line);
  color: var(--dim);
  box-shadow: none;
  opacity: 0;
  transition: opacity .15s var(--ease), border-color .15s var(--ease), color .15s var(--ease);
}
.sound:hover .button.tiny,
.sound:focus-within .button.tiny { opacity: 1; }
.sound .sound-edit .button:hover { border-color: var(--mint); color: var(--mint); }
.sound .button.danger:hover { border-color: var(--danger); color: var(--danger); }

@media (max-width: 780px) {
  /* The volume and the uploader go first: one is a fiddly target on a touch screen and the
     other is context rather than something you act on. Even without them six columns left the
     name 45px wide, so the buttons drop to a second line and the name gets the whole first
     one. */
  .sounds-wrap { --sound-cols: 16px 34px 36px minmax(0, 1fr); }
  .sound { row-gap: 8px; padding: 10px 6px; }
  .sounds-head span:nth-child(5),
  .sounds-head span:nth-child(6),
  .sound input.s-vol,
  .sound .s-by { display: none; }
  /* Columns 3 and 4 are taken on the first row by the emoji and the name, so both buttons
     land on the second one under them. */
  .sound .sound-edit .button { grid-column: 3; }
  .sound .button.danger { grid-column: 4; }
  /* No hover on a touch screen, so nothing can be hidden behind one. */
  .sound .button.tiny { opacity: 1; }
  .sound .grip { color: var(--faint); }
  .sound input[type="text"] { border-color: var(--line); background: var(--bg); }
  .sound-add { grid-template-columns: minmax(0, 1fr) 84px; }
  .sound-add .vol-cell { grid-column: 1 / -1; }
}

/* ── the reorder bar ─────────────────────────────────────────────── */
/* Follows you down: the list can be long, and a save at the bottom of forty rows is a save
   nobody finds. */
.reorder-bar {
  position: sticky;
  bottom: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--mint);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  box-shadow: 0 18px 40px -24px #000;
}
.reorder-bar span { flex: 1; font-size: 13.5px; }

/* ── the confirmation ────────────────────────────────────────────── */
.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(4, 8, 7, .74);
}
.modal[hidden] { display: none; }

.modal-card {
  width: min(520px, 100%);
  padding: 26px;
  border: 1px solid var(--line-bright);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: 0 40px 80px -40px #000;
}
.modal-card h2 { margin: 0 0 10px; font-size: 19px; letter-spacing: -.3px; }
.modal-card p { margin: 0 0 14px; color: var(--dim); font-size: 14px; }
.modal-card .notes { margin: 0 0 20px; }
.modal-card .notes li { font-size: 13.6px; }

.modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.modal-actions .button.danger {
  background: none;
  border: 1px solid rgba(242, 114, 114, .45);
  color: var(--danger);
  box-shadow: none;
}
.modal-actions .button.danger:hover {
  border-color: var(--danger);
  background: rgba(242, 114, 114, .1);
}


/* ── the tickets page ─────────────────────────────────────────────── */
/* Option rows follow the editable-list rule: quiet until you're in one. The hairline between
   options keeps five stacked rows readable without making each look like its own form. */
.ticket-opt { padding: 12px 0 0; }
.ticket-opt + .ticket-opt { margin-top: 12px; border-top: 1px solid rgba(255, 255, 255, .06); }
.ticket-opt .check { margin-top: 8px; }
.ticket-opt.new .mini-head { display: block; margin-bottom: 8px; }

/* The record table. Wide content scrolls inside its own box rather than the page. */
.ticket-table-wrap { overflow-x: auto; }
.ticket-table { width: 100%; border-collapse: collapse; font-size: 13.6px; }
.ticket-table th {
  text-align: left; font-weight: 600; color: var(--dim);
  font-size: 12px; text-transform: uppercase; letter-spacing: .4px;
  padding: 6px 12px 6px 0; border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.ticket-table td {
  padding: 8px 12px 8px 0; border-bottom: 1px solid rgba(255, 255, 255, .05);
  white-space: nowrap;
}
.ticket-table tr:last-child td { border-bottom: 0; }

/* ── the welcome card preview ─────────────────────────────────────── */
.card-preview {
  display: block; width: 100%; max-width: 640px; border-radius: 14px;
  margin-top: 12px; background: rgba(255, 255, 255, .04); min-height: 120px;
}

/* ── placeholder chips with tooltips ──────────────────────────────── */
/* The greeting placeholders, each explaining itself on hover or keyboard focus. Pure CSS:
   the tip rides in data-tip and nothing here needs a script. */
.ph {
  position: relative; cursor: help; margin-right: 2px;
  border-bottom: 1px dotted var(--faint);
}
.ph:focus-visible { outline: 1px solid var(--mint); outline-offset: 2px; }
.ph::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 9px); left: 50%;
  transform: translateX(-50%) translateY(2px);
  background: #171d21; color: #dfe6e3;
  border: 1px solid rgba(255, 255, 255, .14); border-radius: 8px;
  padding: 7px 11px; font-size: 12.5px; line-height: 1.45;
  font-family: system-ui, sans-serif; font-weight: 400;
  white-space: nowrap; box-shadow: 0 8px 24px -8px rgba(0, 0, 0, .7);
  opacity: 0; pointer-events: none; transition: opacity .12s, transform .12s;
  z-index: 30;
}
.ph::before {
  content: ""; position: absolute; bottom: calc(100% + 4px); left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: #171d21;
  opacity: 0; transition: opacity .12s; z-index: 31; pointer-events: none;
}
.ph:hover::after, .ph:focus-visible::after {
  opacity: 1; transform: translateX(-50%) translateY(0);
}
.ph:hover::before, .ph:focus-visible::before { opacity: 1; }
/* The first chips sit near the card's left edge, where a centred tip would clip. */
.ph-row .ph:first-of-type::after, .ph-row .ph:nth-of-type(2)::after {
  left: 0; transform: translateX(0) translateY(2px);
}
.ph-row .ph:first-of-type:hover::after, .ph-row .ph:nth-of-type(2):hover::after,
.ph-row .ph:first-of-type:focus-visible::after, .ph-row .ph:nth-of-type(2):focus-visible::after {
  transform: translateX(0) translateY(0);
}

/* ── the premium badge ────────────────────────────────────────────── */
.premium-chip {
  display: inline-flex; align-items: center; gap: 5px; vertical-align: middle;
  margin-left: 10px; padding: 4px 12px; border-radius: 999px;
  font-size: 13px; font-weight: 600; letter-spacing: .2px;
  color: #bff4dc; background: rgba(61, 220, 151, .12);
  border: 1px solid rgba(61, 220, 151, .4);
}
.premium-line { margin-top: 2px; }
/* Premium picker cards wear it structurally instead of spending text space on a chip: a
   mint top edge with a small tab hanging off it, ribbon-style. The name loses nothing. */
.card.server.premium { border-top: 2px solid var(--mint); }
.card.server .premium-tab {
  position: absolute; top: -1px; right: 12px; z-index: 2;
  background: var(--mint); color: #06231a;
  font-size: 10px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  padding: 1.5px 8px; border-radius: 0 0 7px 7px;
}

/* The red line on a locked Premium feature. Red on purpose: everything else on the page is
   mint, so this is the one thing that reads as "not yet", and the link right beside it is
   where "yet" starts. */
.premium-need {
  margin: 4px 0 14px; padding: 9px 12px; border-radius: 9px;
  color: #ffb4b4; font-size: 13.5px;
  background: rgba(242, 114, 114, .09);
  border: 1px solid rgba(242, 114, 114, .35);
}
.premium-need a { color: #ffd2d2; font-weight: 600; }

/* The locked card's controls: present, visibly out of reach. The fieldset is only there to
   disable everything at once, so it must not look like anything. */
fieldset.premium-fields { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.premium-fields:disabled { opacity: .45; }

/* The CSV downloads on the insights page. */
.export-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }

/* ── the inline wording editor (editors only) ────────────────────── */
/* Nothing is injected into the content: with edit mode off the page is untouched.
   In edit mode, editable spots outline on hover and a click edits instead of acting. */
.copyediting .copyedit-spot:hover {
  outline: 1.5px dashed var(--mint); outline-offset: 2px;
  cursor: pointer; border-radius: 3px;
}
.copy-pencil.on {
  opacity: 1;
  filter: drop-shadow(0 0 6px rgba(61, 220, 151, .55));
}
.copyedit-bar {
  position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%);
  z-index: 95; display: flex; align-items: center; gap: 14px;
  background: var(--surface-2); border: 1px solid var(--mint);
  border-radius: 999px; padding: 8px 10px 8px 18px; font-size: 13px;
  box-shadow: 0 14px 34px -14px rgba(0, 0, 0, .9);
  max-width: calc(100vw - 24px);
}
.copyedit-bar span { color: var(--text); white-space: nowrap; overflow: hidden;
                     text-overflow: ellipsis; }
.copyedit-bar a { color: var(--mint); font-weight: 600; white-space: nowrap; }
.copyedit-bar button {
  margin: 0; padding: 5px 14px; font-size: 12.5px; border-radius: 999px;
}
.copyedit-pick {
  display: block; width: 100%; text-align: left; margin: 6px 0 0;
  padding: 7px 10px; font-size: 12.5px; font-weight: 400; border-radius: 8px;
  background: #101816; border: 1px solid var(--line); color: var(--text);
}
.copyedit-pick:hover { border-color: var(--mint); }
.copyedit-pop {
  position: absolute; z-index: 90; width: 360px; max-width: calc(100vw - 24px);
  background: var(--surface-2); border: 1px solid var(--line-bright);
  border-radius: 12px; padding: 12px 14px;
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .9);
}
.copyedit-pop textarea {
  width: 100%; margin: 6px 0 0; font-size: 13.5px;
}
.copyedit-note {
  font-family: ui-monospace, monospace; font-size: 11px; color: var(--faint);
  margin: 0; word-break: break-all;
}
.copyedit-status { color: #ffb4b4; font-size: 12.5px; margin: 6px 0 0; min-height: 1em; }
.copyedit-actions { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.copyedit-actions button {
  margin: 0; padding: 6px 14px; font-size: 13px; border-radius: 8px;
}

/* Two real pencil images from the icon set's duotone pipeline: the red one shows while
   editing is off, the mint one while it is on. */
.copy-pencil {
  text-decoration: none; opacity: .85; display: inline-flex; align-items: center;
  transition: opacity .15s;
}
.copy-pencil:hover { opacity: 1; }
.copy-pencil img { display: block; }
.copy-pencil .pencil-on { display: none; }
.copy-pencil.on .pencil-on { display: block; }
.copy-pencil.on .pencil-off { display: none; }

/* ── the ratings survey tab ──────────────────────────────────────── */
/* Preview on the left, numbers and the form on the right. The preview is drawn in
   Discord's own dark colours regardless of anything, because it is a picture of Discord. */
.survey-split { display: flex; gap: 22px; align-items: flex-start; }
.survey-split > div { flex: 1; min-width: 0; }
.dmock {
  background: #313338; border-radius: 10px; padding: 13px 15px; margin-top: 6px;
}
.dmock-who { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.dmock-ava {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  background: radial-gradient(circle at 35% 30%, #6ff0bb, #17976b);
}
.dmock-who b { color: #fff; font-size: 13.5px; }
.dmock-tag {
  background: #5865f2; color: #fff; font-size: 9px; font-weight: 700;
  padding: 1px 4px; border-radius: 3px; letter-spacing: .2px;
}
.dmock-embed {
  background: #2b2d31; border-left: 3px solid var(--mint);
  border-radius: 4px; padding: 9px 11px;
}
.dmock-title { color: #f2f3f5; font-weight: 700; font-size: 13.5px; margin-bottom: 3px; }
.dmock-desc { color: #dbdee1; font-size: 12.5px; line-height: 1.45; }
.dmock-row { display: flex; gap: 6px; margin-top: 8px; }
.dmock-btn {
  background: #5865f2; color: #fff; font-size: 12px; font-weight: 600;
  min-width: 34px; height: 27px; border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center;
}
.survey-stats { display: flex; gap: 12px; margin-bottom: 4px; }
.survey-stat {
  flex: 1; background: var(--bg); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 13px;
}
.survey-stat b {
  display: block; font-size: 20px; color: var(--mint); letter-spacing: -.5px;
}
.survey-stat b i { font-style: normal; font-size: 12px; color: var(--dim); }
.survey-stat span { color: var(--dim); font-size: 11.5px; }
@media (max-width: 760px) {
  .survey-split { flex-direction: column; }
  .survey-split > div { width: 100%; }
}

/* ── server counters ─────────────────────────────────────────────── */
/* The same shape as the log event rows: tick a kind, and its one setting (the channel
   name template) appears beside it. */
.counterrows {
  border: 1px solid var(--line-bright);
  border-radius: var(--r-sm);
  background: var(--bg);
  overflow: hidden;
  margin-top: 8px;
}
.counterrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--line);
}
.counterrow:last-child { border-bottom: 0; }
.counterrow:hover { background: var(--surface); }
.counterrow .counter-tpl {
  flex: none;
  width: 220px;
  margin-top: 0;
  padding: 6px 10px;
  font-size: 13px;
}
.counter-live, .counter-err {
  font-size: 11px; font-weight: 600; margin-left: 8px; padding: 1px 8px;
  border-radius: 999px; vertical-align: 1px; white-space: nowrap;
}
.counter-live {
  color: #bff4dc; background: rgba(61, 220, 151, .12);
  border: 1px solid rgba(61, 220, 151, .4);
}
.counter-err {
  color: #ffb4b4; background: rgba(242, 114, 114, .09);
  border: 1px solid rgba(242, 114, 114, .35);
}
@media (max-width: 620px) {
  .counterrow { flex-wrap: wrap; }
  .counterrow label.pick { flex-basis: 100%; }
  .counterrow .counter-tpl { width: 100%; flex: 1; }
}

/* ── 🏝️ frutiger aero, the landing page's easter egg ─────────────── */
/* Styled after frutigeraeroarchive.org: a grass-and-sky scene painted in CSS, dark
   smoked-glass panels floating on it, white text, and that unmistakable lime green.
   The switch is the footer's brand mark on the landing page: the logo IS the button,
   no chrome of its own, a glow on hover and a green one while aero is on. */
button.foot-brand {
  padding: 0; margin: 0; background: none; border: 0; box-shadow: none; border-radius: 0;
  height: auto; min-height: 0; line-height: inherit; text-align: left; justify-content: flex-start;
  font-family: inherit; font-weight: 800; font-size: 15px; letter-spacing: 0; color: var(--text);
  cursor: pointer; transition: none;
}
button.foot-brand .brand-mark { transition: transform .15s var(--ease), filter .15s; }
button.foot-brand:hover, button.foot-brand:active {
  background: none; box-shadow: none; color: var(--text); filter: none; transform: none;
}
button.foot-brand:hover .brand-mark { transform: scale(1.2); filter: drop-shadow(0 0 10px rgba(64, 200, 220, .8)); }
button.foot-brand.on .brand-mark { filter: drop-shadow(0 0 12px rgba(120, 220, 40, .9)); }

body.aero {
  --bg: #2a7fd4; --bg-2: #1e6fd0;
  --surface: rgba(28, 30, 28, .86); --surface-2: rgba(20, 22, 20, .88);
  --surface-3: rgba(40, 44, 40, .9);
  --line: rgba(255, 255, 255, .14); --line-bright: rgba(255, 255, 255, .26);
  --text: #f2f5f0; --dim: #c4ccc0; --faint: #98a294;
  --mint: #52d813; --mint-bright: #8ee62e; --mint-deep: #2fa30a;
  --mint-glow: rgba(82, 216, 19, .3);
  background: #2a7fd4;
}
/* The user's wallpaper (compressed from their 4K original to 1920px / ~280KB), with the
   sky blue behind it while it loads, on the same fixed layer the normal backdrop uses.
   Relative url, so it resolves next to this stylesheet in /static/. */
body.aero::before {
  background: #2a7fd4 url("aero-bg.jpg") center bottom / cover no-repeat;
}
/* The smoked-glass panels the archive floats on its wallpaper. */
body.aero .bar,
body.aero footer,
body.aero .feature,
body.aero .cost,
body.aero .chart,
body.aero .card {
  background: rgba(26, 28, 26, .84);
  border-color: rgba(255, 255, 255, .16);
  backdrop-filter: blur(7px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 12px 30px -16px rgba(0, 0, 0, .8);
}
body.aero .bar { background: rgba(18, 20, 18, .82); }
/* The glossy green button, XP-download-page green: shine on top, depth below. */
body.aero .button:not(.ghost) {
  background: linear-gradient(180deg, #b6f05a, #6cd41f 45%, #3ba50e);
  color: #0c2c04;
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, .75), 0 8px 20px -8px rgba(59, 165, 14, .9);
}
body.aero .spec-chip {
  background: rgba(82, 216, 19, .12); border-color: rgba(142, 230, 46, .4);
  color: #a5ef5c;
}
body.aero .feature { border-left-color: #52d813; }
body.aero .plan-ribbon {
  background: linear-gradient(180deg, #b6f05a, #52c414); color: #0c2c04;
}
body.aero .cost.paid {
  border-color: rgba(142, 230, 46, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12), 0 0 34px -12px rgba(82, 216, 19, .7);
}
/* The hero gradient text, relit in the archive's lime against the sky. */
body.aero .hero-copy h1,
body.aero .hero h1 {
  background: linear-gradient(120deg, #ffffff 15%, #d3f77e 55%, #8ee62e);
  -webkit-background-clip: text;
  background-clip: text;
  text-shadow: none;
}
/* Text that sits straight on the wallpaper gets the archive treatment: either its own
   smoked-glass panel, or a shadow strong enough to read on grass. */
body.aero .hero-copy {
  background: rgba(26, 28, 26, .78);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 16px;
  padding: 26px 28px;
  backdrop-filter: blur(7px);
  box-shadow: 0 14px 34px -18px rgba(0, 0, 0, .8);
}
body.aero .steps {
  background: rgba(26, 28, 26, .78);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 16px;
  padding: 18px 24px;
  backdrop-filter: blur(7px);
}
body.aero .section,
body.aero .section-lead,
body.aero .lead,
body.aero .grid-foot,
body.aero .closing h2,
body.aero .closing p,
body.aero .fine {
  text-shadow: 0 1px 5px rgba(0, 0, 0, .6);
}
/* ── the permissions audit (/servers/<id>/audit) ──────────────────── */
/* Design picked 31 August 2026: the score ring. One number out of 100, a verdict in words,
   and every finding priced in the points fixing it gains. Three severity colours only:
   danger red, the shared amber warn, and dim for minor. */
.audit-hero {
  position: relative;
  display: flex;
  gap: 34px;
  align-items: center;
  background: linear-gradient(160deg, var(--surface-2), var(--surface) 60%);
  border: 1px solid var(--line-bright);
  border-radius: 20px;
  padding: 30px 34px;
  margin: 4px 0 10px;
  overflow: hidden;
}
/* The soft glow behind the ring takes the band's colour. */
.audit-hero::before {
  content: "";
  position: absolute;
  width: 340px;
  height: 340px;
  left: -80px;
  top: -110px;
  border-radius: 50%;
  filter: blur(70px);
  opacity: .5;
  background: radial-gradient(circle, rgba(242, 114, 114, .3), transparent 65%);
}
.audit-hero.band-needs::before { background: radial-gradient(circle, rgba(240, 180, 95, .32), transparent 65%); }
.audit-hero.band-solid::before { background: radial-gradient(circle, rgba(240, 180, 95, .25), transparent 65%); }
.audit-hero.band-locked::before { background: radial-gradient(circle, var(--mint-glow), transparent 65%); }

.scanned {
  position: absolute;
  right: 22px;
  top: 16px;
  font-size: 12px;
  color: var(--faint);
  display: flex;
  align-items: center;
  gap: 7px;
}
.scanned i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 8px var(--mint);
  animation: audit-blink 2s infinite;
}
@keyframes audit-blink { 50% { opacity: .35; } }

.ring { position: relative; width: 172px; height: 172px; flex: none; }
.ring svg { transform: rotate(-90deg); display: block; }
.ring .track { stroke: rgba(255, 255, 255, .06); }
.ring .arc {
  stroke-linecap: round;
  stroke-dasharray: 452.4;
  stroke-dashoffset: 452.4;
  animation: audit-fill 1.4s cubic-bezier(.3, .8, .3, 1) .3s forwards;
  filter: drop-shadow(0 0 10px rgba(240, 180, 95, .4));
}
.band-locked .arc { filter: drop-shadow(0 0 10px var(--mint-glow)); }
@keyframes audit-fill { to { stroke-dashoffset: var(--target); } }
.ring .num {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.ring .num b { font-size: 52px; line-height: 1; color: var(--danger); }
.band-needs .num b, .band-solid .num b { color: var(--warn); }
.band-locked .num b { color: var(--mint); text-shadow: 0 0 30px var(--mint-glow); }
.ring .num span {
  font-size: 11px;
  color: var(--faint);
  letter-spacing: .14em;
  text-transform: uppercase;
  margin-top: 4px;
}

.verdict { position: relative; }
.verdict .word { font-size: 22px; margin: 0 0 2px; }
.verdict .word em { font-style: normal; color: var(--danger); }
.band-needs .word em, .band-solid .word em { color: var(--warn); }
.band-locked .word em { color: var(--mint); }
.verdict .carrot { color: var(--dim); font-size: 13.5px; margin: 2px 0 0; max-width: 420px; }
.verdict .carrot b { color: var(--mint-bright); }

.chips { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
.achip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  border: 1px solid var(--line-bright);
  background: var(--bg-2);
  color: var(--dim);
}
.achip b { font-size: 15px; color: var(--text); }
.achip.hi { color: var(--danger); border-color: rgba(242, 114, 114, .45); background: rgba(242, 114, 114, .08); }
.achip.hi b { color: var(--danger); }
.achip.med { color: var(--warn); border-color: rgba(240, 180, 95, .4); background: rgba(240, 180, 95, .07); }
.achip.med b { color: var(--warn); }

.checked { margin: 0 0 26px; }

/* ── the group headers ── */
.ghead { display: flex; align-items: baseline; gap: 12px; margin: 28px 0 12px; }
.ghead h2 { font-size: 16px; margin: 0; }
.ghead .n { font-size: 12px; padding: 1px 9px; border-radius: 999px; }
.ghead.high .n { background: rgba(242, 114, 114, .13); color: var(--danger); }
.ghead.medium .n { background: rgba(240, 180, 95, .12); color: var(--warn); }
.ghead.low .n { background: var(--surface-3); color: var(--dim); }
.ghead .fine { font-size: 12.5px; }
.ghead .gain { margin-left: auto; font-size: 12px; color: var(--mint-bright); white-space: nowrap; }

/* ── the findings ── */
details.finding {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: var(--surface);
  margin-bottom: 10px;
  overflow: hidden;
  transition: border-color .15s;
}
details.finding:hover { border-color: var(--line-bright); }
details.finding::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; }
details.finding.high::before { background: var(--danger); }
details.finding.medium::before { background: var(--warn); }
details.finding.low::before { background: var(--faint); }
details.finding summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 14px 18px 14px 20px;
}
details.finding summary::-webkit-details-marker { display: none; }
.ft { flex: 1; font-size: 14.5px; min-width: 180px; }
.fpts { flex: none; font-size: 12px; color: var(--mint-bright); white-space: nowrap; }
.f-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 12px;
  color: var(--dim);
  white-space: nowrap;
}
.farr { flex: none; color: var(--faint); transition: transform .18s; font-size: 15px; }
details.finding[open] .farr { transform: rotate(90deg); }

.f-body {
  border-top: 1px solid var(--line);
  padding: 14px 20px 18px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.f-body h4 {
  margin: 0 0 6px;
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--faint);
}
.f-body ul,
.f-body ol { margin: 0; padding-left: 17px; color: var(--dim); font-size: 13px; }
.f-body li { margin: 4px 0; }
.f-body ol li::marker { color: var(--mint); }

.allclear { border-left: 3px solid var(--mint); }
.allclear h2 { margin: 0 0 6px; font-size: 17px; }
.audit-foot { margin-top: 30px; max-width: 680px; }

@media (max-width: 680px) {
  .audit-hero { flex-direction: column; text-align: center; }
  .verdict .carrot { max-width: none; }
  .chips { justify-content: center; }
  .f-body { grid-template-columns: 1fr; }
  .ghead { flex-wrap: wrap; }
  details.finding summary { flex-wrap: wrap; }
}

/* The ignore action inside an open finding, and the accepted list at the bottom. */
.f-act {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 4px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.f-act .fine { font-size: 12px; }
.ignored-note { margin: -4px 0 12px; max-width: 640px; }
.irow {
  display: flex;
  align-items: center;
  gap: 13px;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: var(--surface);
  padding: 10px 18px;
  margin-bottom: 8px;
  opacity: .65;
  transition: opacity .15s;
}
.irow:hover { opacity: 1; }
.irow .ft { font-size: 13.5px; }
.irow form { margin-left: auto; flex: none; }

/* ── the mod cases browser (/servers/<id>/cases) ──────────────────── */
.case-filters { display: flex; gap: 10px; margin: 4px 0 18px; flex-wrap: wrap; }
/* Dressed with the other text fields near the top of the file; this is only its width. */
.case-filters input[type="search"] { flex: 1 1 240px; }
.case-filters select { flex: 0 1 200px; }
.case-count { margin: 0 0 10px; }
/* The table scrolls inside its own box on narrow screens; the page never scrolls sideways. */
.case-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: var(--surface);
}
.case-table { width: 100%; border-collapse: collapse; font-size: 13.5px; min-width: 640px; }
.case-table th {
  text-align: left;
  padding: 10px 14px;
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
  border-bottom: 1px solid var(--line);
}
.case-table td { padding: 9px 14px; border-bottom: 1px solid var(--line); }
.case-table tbody tr:last-child td { border-bottom: 0; }
.case-table tbody tr:hover { background: var(--surface-2); }
.c-num { color: var(--faint); }
.c-reason, .c-mod, .c-when { color: var(--dim); }
.c-act {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  background: var(--surface-3);
  color: var(--dim);
  white-space: nowrap;
}
.c-act.a-ban, .c-act.a-kick { background: rgba(242, 114, 114, .13); color: var(--danger); }
.c-act.a-warn, .c-act.a-timeout { background: rgba(240, 180, 95, .12); color: var(--warn); }
.c-act.a-unban, .c-act.a-untimeout { background: rgba(61, 220, 151, .12); color: var(--mint); }
tr.struck .c-reason, tr.struck .c-target { text-decoration: line-through; opacity: .6; }
.case-pages { display: flex; align-items: center; gap: 14px; margin-top: 16px; }

/* ── the custom commands pane ─────────────────────────────────────── */
.ccrow {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 10px;
}
.cc-top {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.cc-bang { color: var(--mint); font-size: 16px; }
/* input[type=text] is display:block width:100% globally; these live in a flex row. */
.cc-top input.cc-name {
  display: inline-block;
  width: 140px;
  margin-top: 0;
}
.cc-top select { width: auto; flex: 0 1 auto; }
.cc-del { margin-left: auto; color: var(--faint); }
input.cc-response { margin-top: 0; }
@media (max-width: 680px) {
  .cc-top select { flex: 1 1 140px; }
}

/* The advanced fold inside a custom command row. */
.cc-adv { margin-top: 8px; }
.cc-adv summary {
  cursor: pointer;
  color: var(--faint);
  font-size: 12.5px;
  list-style: none;
}
.cc-adv summary::before { content: "› "; color: var(--mint); }
.cc-adv[open] summary::before { content: "⌄ "; }
.cc-adv summary::-webkit-details-marker { display: none; }
.cc-adv-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 10px;
}
.cc-adv-grid h4 {
  margin: 0 0 4px;
  font-size: 11.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}
.cc-adv-grid .rolelist.short { max-height: 160px; overflow-y: auto; }
.cc-adv-row {
  display: flex;
  align-items: end;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.cc-adv-row label { font-size: 13px; }
.cc-adv-row select { width: auto; }
.cc-adv-row .check { align-self: center; }
textarea.cc-response { margin-top: 0; }
@media (max-width: 680px) {
  .cc-adv-grid { grid-template-columns: 1fr; }
}

/* The pick-an-action cards and the blocks they open (the MEE6 shape). */
.cc-pickgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 8px;
}
button.cc-pick {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  border: 1px solid var(--line-bright);
  border-radius: 11px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
  text-align: left;
  transition: border-color .15s;
}
button.cc-pick:hover { border-color: var(--mint); }
.cc-plus { margin-left: auto; color: var(--mint); font-size: 16px; }
.cc-block {
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 12px 14px;
  margin-bottom: 8px;
  background: var(--bg-2);
}
.cc-bh {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--mint-bright);
  margin-bottom: 8px;
}
button.cc-x {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--danger);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.cc-sendrow {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.cc-lbl { color: var(--dim); font-size: 13px; }
.cc-sendrow select { width: auto; }
@media (max-width: 560px) { .cc-pickgrid { grid-template-columns: 1fr; } }

/* ── the commands on/off board ─────────────────────────────────────── */
/* Switch toggles rather than ticks, a count on every card, and a floating save bar.
   Everything is cb- prefixed on purpose: the site's global input rules have
   out-specified bare classes before, and these switches restyle a checkbox. */
.cb-status { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 4px 0 18px; }
.cb-chip {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 13px; font-size: 12.5px; color: var(--dim);
}
.cb-chip b { color: var(--text); }
.cb-led { width: 7px; height: 7px; border-radius: 50%; background: var(--mint);
          box-shadow: 0 0 8px var(--mint-glow); }
.cb-led.isoff { background: var(--danger); box-shadow: none; }
.cb-search { margin-left: auto; }
.cb-search input {
  background: var(--surface); border: 1px solid var(--line); color: var(--text);
  border-radius: 999px; padding: 7px 15px; font: inherit; font-size: 13px; width: 220px;
}
.cb-search input:focus { outline: none; border-color: var(--mint-deep); }
.cb-search input::placeholder { color: var(--faint); }

.cb-cat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); margin-bottom: 14px; overflow: hidden;
}
.cb-head { display: flex; align-items: center; gap: 13px; padding: 15px 18px; }
.cb-ico {
  width: 38px; height: 38px; flex: none; display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 11px; font-size: 18px;
}
.cb-titles { min-width: 0; }
.cb-name { display: block; font-size: 16.5px; }
.cb-sub { display: block; color: var(--faint); font-size: 12px; letter-spacing: .4px;
          text-transform: uppercase; }
.cb-sub .offcount { color: var(--danger); }
.cb-head .cb-sw { margin-left: auto; }
.cb-body { padding: 4px 14px 14px; border-top: 1px solid var(--line);
           transition: opacity .25s var(--ease); }
.cb-cat.catoff .cb-body { opacity: .35; }
.cb-cat.catoff .cb-ico { filter: grayscale(1); opacity: .6; }

.cb-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(205px, 1fr));
  gap: 8px; padding-top: 12px;
}
.cb-cmd {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 8px 11px 8px 13px;
  cursor: pointer; user-select: none;
  transition: border-color .15s var(--ease), opacity .2s var(--ease);
}
.cb-cmd:hover { border-color: var(--line-bright); }
.cb-cmd code { font-size: 13px; overflow: hidden; text-overflow: ellipsis;
               white-space: nowrap; }
.cb-cmd.off { opacity: .5; }
.cb-cmd.off code { color: var(--dim); text-decoration: line-through;
                   text-decoration-color: var(--faint); }

/* The switch: a restyled checkbox, so the form posts with no script at all. */
.cb-sw { position: relative; width: 36px; height: 21px; flex: none; }
.cb-sw input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.cb-sw i {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--surface-3); border: 1px solid var(--line-bright);
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.cb-sw i::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 15px; height: 15px;
  border-radius: 50%; background: var(--faint);
  transition: translate .18s var(--ease), background .18s var(--ease);
}
.cb-sw input:checked + i { background: var(--mint-deep); border-color: var(--mint-deep); }
.cb-sw input:checked + i::after { translate: 15px 0; background: var(--bg); }
.cb-sw input:focus-visible + i { outline: 2px solid var(--mint-bright); outline-offset: 2px; }
.cb-sw.big { width: 44px; height: 25px; }
.cb-sw.big i::after { width: 19px; height: 19px; }
.cb-sw.big input:checked + i::after { translate: 19px 0; }

.cb-savebar {
  position: fixed; left: 50%; bottom: 22px; translate: -50% 0; z-index: 40;
  display: flex; align-items: center; gap: 16px;
  background: var(--bg-2); border: 1px solid var(--line-bright);
  border-radius: 999px; padding: 9px 10px 9px 22px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .55);
  transition: border-color .2s var(--ease);
}
.cb-savenote { font-size: 13px; color: var(--faint); }
.cb-savebar.dirty { border-color: var(--mint-deep); }
.cb-savebar.dirty .cb-savenote { color: var(--text); }
button.cb-discard { background: none; border: none; color: var(--faint); font: inherit;
                    font-size: 13px; cursor: pointer; padding: 0; }
button.cb-discard:hover { color: var(--danger); }
button.cb-save { border-radius: 999px; padding: 8px 22px; }
.cb-savebar.dirty button.cb-save { box-shadow: 0 0 22px var(--mint-glow); }
/* Room under the last card so the fixed bar never sits on the hint text. */
body.commands-page main { padding-bottom: 96px; }

@media (max-width: 560px) {
  .cb-grid { grid-template-columns: 1fr; }
  .cb-search { margin-left: 0; width: 100%; }
  .cb-search input { width: 100%; }
  .cb-savebar { left: 12px; right: 12px; translate: none; justify-content: space-between; }
}

/* ── the landing page's MEE6-style blocks (5 Sep 2026) ───────────── */
/* One pitch, then big alternating blocks: copy on one side, a made-up Discord window or
   the chart on the other. The pictures reuse the survey demo's .mock styling so the whole
   page looks like one product. */
.hero-copy .used { margin-top: 14px; color: var(--faint); font-size: 13.4px; font-weight: 600; }

.pitches { margin-bottom: 26px; }
.pitch {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 56px;
  align-items: center;
  margin: 0;
  padding: 44px 0;
  border-top: 1px solid var(--line);
}
.pitch:nth-child(even) .pitch-pic { order: -1; }
.pitch-copy h2 {
  font-size: clamp(23px, 2.9vw, 30px);
  line-height: 1.15;
  letter-spacing: -.4px;
  margin: 0 0 14px;
}
.pitch-copy p { color: var(--dim); font-size: 15px; line-height: 1.65; margin: 0; }
.pitch-copy .feature-chips { margin: 14px 0 0; }
.pitch-copy .more { display: inline-block; margin-top: 16px; color: var(--mint); font-weight: 600; }
.pitch-copy .more:hover { color: var(--mint-bright); }

.pitch-pic .chart { margin: 0; }
.pitch-pic .steps { grid-template-columns: minmax(0, 1fr); gap: 4px; }
.pitch-pic .steps li {
  display: grid;
  grid-template-columns: 23px minmax(0, 1fr);
  column-gap: 12px;
  padding: 9px 0;
  border-left: 0;
  font-size: 13.2px;
}
.pitch-pic .steps li::before { grid-row: 1 / span 2; margin: 1px 0 0; }
.pitch-pic .steps li strong, .pitch-pic .steps li span { grid-column: 2; }
.pitch-pic .steps li strong { margin-bottom: 1px; }
.pitch-pic > .fine { margin: 14px 0 0; }

.mock.pic .mock-msg + .mock-msg { margin-top: 14px; }
.mock-avatar.user { background: linear-gradient(140deg, #f0b45f, #d88d2a); color: #2a1a05; }
.mock-plain { margin: 0; color: var(--text); font-size: 13.6px; font-weight: 400; line-height: 1.5; }
.mock-buttons.wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mock-buttons.wide .mock-btn { padding: 8px 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mock-embed.tone-warn { border-left-color: var(--warn); }
.mock-embed.tone-danger { border-left-color: var(--danger); }
.mock-rows {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 4px 14px;
  margin: 8px 0 0;
  font-size: 13px;
}
.mock-rows dt { color: var(--faint); font-weight: 600; }
.mock-rows dd { margin: 0; color: var(--text); font-weight: 400; }
.mock-file {
  display: inline-block;
  margin-top: 10px;
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--surface-3);
  color: var(--dim);
  font: 500 12px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace;
}
.mock-cardimg {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 8px;
  border-radius: 8px;
  border: 1px solid var(--line);
}

/* The three columns and the guides row. */
.three { margin-top: 64px; }
.three h2.section, .guides h2.section { text-align: center; }
.three-row {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.three-row .feature { padding: 22px 22px 20px; border-left: 1px solid var(--line); }
.three-icon { display: block; width: 40px; height: 40px; margin-bottom: 12px; }
.three-row .feature h3 { font-size: 17px; }

.guides .lead { text-align: center; color: var(--dim); max-width: 56ch; margin: 0 auto 22px; font-size: 15px; }
.guide-row { display: grid; gap: 14px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.guide {
  display: block;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px 20px 16px;
  color: var(--text);
  text-decoration: none;
  transition: transform .2s var(--ease), border-color .2s var(--ease);
}
.guide:hover { transform: translateY(-3px); border-color: var(--line); }
.guide strong { display: block; font-size: 15.4px; margin-bottom: 6px; }
.guide p { margin: 0 0 10px; color: var(--dim); font-size: 13.6px; line-height: 1.55; font-weight: 400; }
.guide .more { color: var(--mint); font-weight: 600; font-size: 13.4px; }

@media (max-width: 880px) {
  .pitch { grid-template-columns: minmax(0, 1fr); gap: 26px; padding: 34px 0; }
  .pitch:nth-child(even) .pitch-pic { order: 0; }
  .three-row, .guide-row { grid-template-columns: minmax(0, 1fr); }
}

.pitch, .guide, .mock.pic { position: relative; }
.mock.pic { transition: transform .2s var(--ease), box-shadow .2s var(--ease); }
.mock.pic:hover { transform: translateY(-4px);
                  box-shadow: 0 30px 60px -34px #000, 0 18px 40px -26px rgba(61, 220, 151, .6); }
.pitch-pic .chart, .pitch-pic .steps { transition: transform .2s var(--ease); }
.pitch-pic .chart:hover, .pitch-pic .steps:hover { transform: translateY(-4px); }

/* The bot's avatar in the mock windows is the Newt face (static/newt.png) on a dark disc,
   the way Discord shows the real bot, rather than an initial. */
.mock-avatar.logo { background: #0c1311; border: 1px solid var(--line-bright); }
.mock-avatar.logo img { display: block; width: 34px; height: auto; }

/* ── the mock windows look like Discord ──────────────────────────── */
/* The same colours, type and spacing as the embed builder's .dc preview: Discord's dark
   theme, gg sans where the reader has it, a channel header with the hash, a timestamp
   after the name, embeds as 4px-striped panels with inline fields, grey buttons. The
   pointer glow and the hover lift from further up still apply. */
.mock {
  /* Sampled from a real message the bot sent (6 Sep 2026 screenshot): the chat is the
     mid grey, the embed the near-black panel, the buttons blurple. */
  --dc-chat: #2b2d31;
  --dc-embed: #111214;
  --dc-sunk: #1e1f22;
  --dc-text: #dbdee1;
  --dc-bright: #f2f3f5;
  --dc-muted: #949ba4;
  --dc-link: #00a8fc;
  --dc-blurple: #5865f2;
  --dc-role: #7b9cf6;
  background: var(--dc-chat);
  border: 1px solid #26282c;
  border-radius: 8px;
  font-family: "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  box-shadow: 0 30px 60px -34px #000;
}
.mock-bar {
  gap: 8px;
  padding: 12px 16px;
  background: var(--dc-chat);
  border-bottom: 0;
  box-shadow: 0 1px 0 rgba(4, 4, 5, .2), 0 1.5px 0 rgba(6, 6, 7, .05);
}
.mock-hash { width: 20px; height: 20px; flex: none; color: var(--dc-muted); }
.mock-channel { margin: 0; color: var(--dc-bright); font-size: 15px; font-weight: 600; }
.mock-body { padding: 16px; }
.mock-msg { gap: 16px; }
.mock-avatar {
  width: 40px; height: 40px;
  background: var(--dc-blurple);
  color: #fff;
  font-size: 17px;
  font-weight: 500;
}
.mock-avatar.logo { background: var(--dc-sunk); border: 0; }
.mock-avatar.user { background: #e67e22; color: #fff; }
.mock-avatar.user + .mock-content .mock-name { color: var(--dc-bright); }
.mock-name {
  display: flex; align-items: center; gap: 8px;
  color: var(--dc-role);
  font-size: 15px; font-weight: 500; line-height: 1.375;
  margin-bottom: 2px;
}
.mock .tag {
  margin: 0;
  background: var(--dc-blurple);
  color: #fff;
  border-radius: 3px;
  padding: 0 4px;
  height: 15px;
  display: inline-flex; align-items: center;
  font-size: 10px; font-weight: 500; letter-spacing: 0;
  vertical-align: 0;
}
.mock-when { color: var(--dc-muted); font-size: 12px; font-weight: 400; }
.mock-plain { color: var(--dc-text); font-size: 15px; font-weight: 400; line-height: 1.375; }

.mock-embed {
  max-width: 520px;
  margin: 8px 0 0;
  border-left-width: 4px;
  border-radius: 4px;
  background: var(--dc-embed);
  padding: 8px 16px 16px 12px;
}
.mock-embed strong { color: var(--dc-bright); font-size: 15px; font-weight: 700; margin-bottom: 8px; }
.mock-embed p { color: var(--dc-text); font-size: 14px; line-height: 1.125rem; }
.mock-rows {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto auto;
  grid-auto-flow: column;
  gap: 2px 8px;
  margin-top: 8px;
  font-size: 14px;
}
.mock-rows dt { color: var(--dc-bright); font-weight: 600; line-height: 1.125rem; }
.mock-rows dd { color: var(--dc-text); font-weight: 400; line-height: 1.125rem; }

/* Five to a row like Discord's action rows, each up to 62px wide and shrinking together
   when the window is narrow rather than wrapping four and one. */
.mock-buttons {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 62px));
  justify-content: start;
  margin-top: 8px; gap: 8px;
}
.mock-btn {
  width: auto; height: 32px; padding: 0;
  background: var(--dc-blurple); color: #fff;
  border-radius: 3px;
  font-size: 14px; font-weight: 500;
  transition: background .17s ease;
}
.mock-btn:hover { background: #4752c4; transform: none; }
.mock-btn.picked { background: #248046; color: #fff; }
.mock-btn.picked:hover { background: #1a6334; }
.mock-buttons.wide { display: flex; flex-wrap: wrap; }
.mock-buttons.wide .mock-btn { flex: none; min-width: 60px; padding: 0 16px; background: #4e5058; }
.mock-buttons.wide .mock-btn:hover { background: #6d6f78; }

.mock-file {
  margin-top: 8px;
  padding: 6px 10px;
  border-radius: 4px;
  background: var(--dc-embed);
  border: 1px solid var(--dc-sunk);
  color: var(--dc-link);
  font: 400 14px/1.3 "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.mock-cardimg { max-width: 400px; margin-top: 4px; border: 0; border-radius: 4px; }

.mock-reply {
  margin-top: 8px;
  padding: 8px 12px;
  border: 0;
  border-left: 4px solid var(--mint);
  border-radius: 4px;
  background: var(--dc-embed);
  color: var(--dc-text);
  font-size: 14px;
}
.mock-reply b { color: var(--mint-bright); }
.mock-foot {
  border-top: 1px solid rgba(255, 255, 255, .06);
  color: var(--dc-muted);
  font-size: 12px;
}
.mock-foot b { color: var(--dc-bright); }
.try { color: var(--dc-link); }

/* ── screenshots of the real thing ───────────────────────────────── */
/* The feature pictures are captures of the bot's own messages, posted with /admin
   showcase. One frame in Discord's ground, the capture at its true pixel size so every
   picture shares one scale; the column only ever shrinks one, never enlarges it. */
.shot {
  position: relative;
  display: grid;
  gap: 14px;
  justify-items: start;
  padding: 16px;
  border-radius: 8px;
  background: #000;
  border: 1px solid #26282c;
  box-shadow: 0 30px 60px -34px #000;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.shot:hover { transform: translateY(-4px);
              box-shadow: 0 30px 60px -34px #000, 0 18px 40px -26px rgba(61, 220, 151, .6); }
.shot-img { display: block; max-width: 100%; height: auto; border-radius: 4px; }

/* ── the hero's survey demo, in the screenshots' frame ───────────── */
/* The one picture that stays live. Same black frame as the captures, no channel bar,
   and the sizes of the survey as the user's Discord draws it (6 Sep 2026 capture):
   42px avatar, 17px name, 76x40 buttons twelve apart, 6px corners. */
.mock[data-demo] { background: #000; border: 1px solid #26282c; border-radius: 8px; padding: 16px 16px 12px; }
.mock[data-demo] .mock-bar { display: none; }
.mock[data-demo] .mock-body { padding: 0; }
.mock[data-demo] .mock-msg { gap: 16px; }
.mock[data-demo] .mock-avatar { width: 42px; height: 42px; }
.mock[data-demo] .mock-avatar.logo img { width: 36px; }
.mock[data-demo] .mock-name { font-size: 17px; }
.mock[data-demo] .mock-name .tag { height: 18px; font-size: 11px; padding: 0 5px; border-radius: 4px; }
.mock[data-demo] .mock-when { font-size: 13px; }
.mock[data-demo] .mock-embed { max-width: none; margin-top: 6px; padding: 12px 20px 16px 16px; border-radius: 6px; }
.mock[data-demo] .mock-embed strong { font-size: 17px; font-weight: 700; margin-bottom: 8px; }
.mock[data-demo] .mock-embed p { font-size: 16px; line-height: 1.375; }
.mock[data-demo] .mock-buttons { grid-template-columns: repeat(5, minmax(0, 76px)); gap: 12px; margin-top: 12px; }
.mock[data-demo] .mock-btn { height: 40px; border-radius: 6px; font-size: 16px; font-weight: 600; }
.mock[data-demo] .mock-reply { font-size: 15px; }
.mock[data-demo] .mock-foot { margin-top: 14px; padding-top: 10px; }

/* The JSON format shown on the question-of-the-day card, as a small code block. */
.qotd-format {
  margin: 6px 0 10px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--mint-bright);
  font: 500 12.5px/1.6 ui-monospace, SFMono-Regular, Consolas, monospace;
  white-space: pre-wrap;
  overflow-x: auto;
}

/* ── the pond behind the hero ────────────────────────────────────── */
/* The painted scene runs the full width of the window behind the hero, at just over
   half strength, with the left side (under the headline) darkened further and the
   bottom edge fading into the page. The survey demo has its own solid frame, so it
   sits on the scene untouched. */
/* The band is 100vw wide, which counts the scrollbar; clip rather than scroll. */
body.landing-page { overflow-x: clip; }
html:has(body.landing-page) { overflow-x: clip; }
.hero-grid { position: relative; isolation: isolate; padding: 84px 0 96px; }
.hero-scene {
  position: absolute;
  top: -48px; bottom: 0;
  left: calc(50% - 50vw); width: 100vw;
  z-index: -1;
  background: center / cover no-repeat;
  opacity: 1;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 0, #000 72%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0, #000 72%, transparent 100%);
}
.hero-scene::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(12, 19, 17, .45) 0%, rgba(12, 19, 17, .6) 28%,
                    rgba(12, 19, 17, .35) 48%, rgba(12, 19, 17, 0) 66%,
                    rgba(12, 19, 17, 0) 100%);
}
@media (max-width: 880px) {
  .hero-grid { padding: 44px 0 56px; }
  .hero-scene { opacity: .8; }
  .hero-scene::after { background: rgba(12, 19, 17, .45); }
}

/* ── the margins on wide screens ─────────────────────────────────── */
/* Two things the user picked from a mockup (6 Sep 2026). Every other block gets a
   slightly lighter band that runs the full width of the window, so the margin belongs to
   the section rather than sitting empty. And on windows wide enough, each block's
   picture reaches 150px past the text column on its own side and its capture scales up
   to fill the frame, while the words stay at their readable width. */
.pitch { isolation: isolate; }
.pitch:nth-child(even) { border-top-color: transparent; }
.pitch:nth-child(even)::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: calc(50% - 50vw); width: 100vw;
  z-index: -1;
  background: #101a16;
  border-top: 1px solid #26282c;
  border-bottom: 1px solid #26282c;
  pointer-events: none;
}
.pitch:nth-child(even) + .pitch { border-top-color: transparent; }

@media (min-width: 1360px) {
  .pitch { grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); }
  .pitch:nth-child(even) { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
  .pitch:nth-child(odd) .pitch-pic { margin-right: -150px; }
  .pitch:nth-child(even) .pitch-pic { margin-left: -150px; }
  .pitch .shot-img { width: 100%; max-width: 660px; }
}

/* ── the floating Add button ─────────────────────────────────────── */
/* Sits in the bottom right once the hero is gone, and leaves when the closing section
   with the same button arrives. Off until the script says so. */
.float-add {
  position: fixed;
  right: 26px; bottom: 26px;
  z-index: 40;
  border-radius: 999px;
  padding: 12px 20px 12px 16px;
  font-size: 14.5px;
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
  transition: opacity .25s var(--ease), transform .25s var(--ease), filter .2s var(--ease),
              box-shadow .2s var(--ease);
}
/* Deeper than the other buttons: the mascot's face is the button's own mint, and on the
   bright gradient it vanished. On this teal it reads, and the words go pale to match. */
.float-add {
  background: linear-gradient(135deg, #14a877, #0d6b52);
  color: #eafff5;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 8px 22px -8px rgba(13, 107, 82, .9);
}
.float-add:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .16) inset, 0 12px 26px -10px var(--mint); }
.float-add.on { opacity: 1; transform: none; pointer-events: auto; }
.float-add img { display: block; width: 22px; height: auto; }
@media (max-width: 880px) {
  .float-add { right: 14px; bottom: 14px; padding: 10px 16px 10px 12px; font-size: 13.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .float-add { transition: none; transform: none; }
}

/* ── the welcome block's picture ─────────────────────────────────── */
/* Transparent artwork, so no frame: just a shadow beneath so it sits on the page. */
.art {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 28px 36px rgba(0, 0, 0, .55));
}

/* ── the custom command demo ─────────────────────────────────────── */
/* The same black frame as the survey demo, for any mock that carries .bare. */
.mock.bare { background: #000; border: 1px solid #26282c; border-radius: 8px; padding: 16px 16px 12px; }
.mock.bare .mock-bar { display: none; }
.mock.bare .mock-body { padding: 0; }
.mock.bare .mock-msg { gap: 16px; }
.mock.bare .mock-msg + .mock-msg { margin-top: 18px; }
.mock.bare .mock-avatar { width: 42px; height: 42px; }
.mock.bare .mock-avatar.logo img { width: 36px; }
.mock.bare .mock-name { font-size: 17px; }
.mock.bare .mock-name .tag { height: 18px; font-size: 11px; padding: 0 5px; border-radius: 4px; }
.mock.bare .mock-when { font-size: 13px; }
.mock.bare .mock-plain { font-size: 16px; }
/* A server tag like Discord draws them: grey chip, the badge and the word. */
.mock .tag.cat { background: #3f4147; color: var(--dc-bright); text-transform: none; font-weight: 600; gap: 4px; }

/* Reactions, Discord's shape: a grey pill with the emoji and a count. Yours is outlined
   in blurple on a blurple tint, which is also how Discord marks a reaction you added. */
.reacts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.react {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 8px 0 6px;
  background: #2b2d31;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--dc-text);
  font: 500 14px/1 "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  cursor: pointer;
  box-shadow: none;
  transition: background .12s ease, border-color .12s ease, transform .12s ease;
}
.react:hover { background: #2b2d31; border-color: #4e5058; transform: none; filter: none; box-shadow: none; }
.react.mine { background: rgba(88, 101, 242, .15); border-color: var(--dc-blurple); color: var(--dc-bright); }
.react .react-emoji { font-size: 16px; line-height: 1; }
.react .react-count { font-weight: 500; min-width: 8px; }
.react.add { padding: 0 6px; color: var(--dc-muted); }
.react.add .react-emoji { filter: grayscale(1); opacity: .8; }
.react.add .react-plus { font-size: 13px; font-weight: 700; margin-left: -2px; }
.react.bump { animation: reactBump .28s var(--ease); }
@keyframes reactBump { 40% { transform: scale(1.18); } }

.react-picker {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 6px; padding: 6px;
  width: max-content; max-width: 100%;
  background: #111214; border: 1px solid #26282c; border-radius: 8px;
}
.react-picker[hidden] { display: none; }
.react-picker button {
  width: 34px; height: 34px; padding: 0;
  background: transparent; border: 0; border-radius: 6px;
  font-size: 20px; line-height: 1; box-shadow: none;
}
.react-picker button:hover { background: #2b2d31; transform: none; filter: none; box-shadow: none; }

/* ── the role button demo ────────────────────────────────────────── */
.mock-foot-line { margin-top: 8px !important; font-size: 12px !important; color: var(--dc-muted) !important; }
.mock.bare .mock-buttons.wide { margin-top: 8px; }
.mock.bare .mock-buttons.wide .mock-btn { height: 40px; padding: 0 20px; font-size: 15px; border-radius: 6px; }
.mock.bare .mock-reply { margin-top: 10px; }
/* A held role reads green, Discord's success style; the row rule above would otherwise
   keep it grey, since it is the more specific selector. */
.mock-buttons.wide .mock-btn.picked { background: #248046; color: #fff; }
.mock-buttons.wide .mock-btn.picked:hover { background: #1a6334; }

/* ── the page lit from the cursor ─────────────────────────────────── */
/* A fixed layer over the public pages: a soft mint light centred on the pointer, which
   app.js writes into --gx and --gy. Nothing can click it, and it fades out when the
   pointer leaves the window. */
.spot {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s var(--ease);
  background: radial-gradient(260px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(61, 220, 151, .07), rgba(61, 220, 151, .02) 40%, transparent 68%);
}
.spot.on { opacity: 1; }

/* ── the three columns hop in ────────────────────────────────────── */
/* When the row scrolls into view each column springs up and settles, one after another
   (the stagger is the data-delay app.js honours), so it reads as a wave from left to
   right. Inside the reduced-motion guard like the rest of the reveal. */
@media (prefers-reduced-motion: no-preference) {
  .js .three-row .feature { transform: translateY(80px); }
  .js .three-row .feature.shown {
    transition: none;
    animation: hop .9s cubic-bezier(.2, 1.3, .35, 1) both;
  }
  @keyframes hop {
    0% { opacity: 0; transform: translateY(80px) scale(.96); }
    50% { opacity: 1; transform: translateY(-28px) scale(1.03); }
    72% { transform: translateY(10px) scale(.995); }
    88% { transform: translateY(-4px) scale(1); }
    100% { opacity: 1; transform: none; }
  }
}

/* ── 🏝️ frutiger aero, second pass: Windows 7 glass ───────────────── */
/* The first pass floated dark smoked-glass panels on the wallpaper. This is the other
   half of the look the user asked for: Vista and Windows 7 Aero Glass. Panels are light,
   frosted and translucent with a gloss across their top half, text inside them is navy,
   buttons are green gel with a hard highlight, chips are glass, and glossy bubbles drift
   up the page. Text that sits straight on the wallpaper stays white with a shadow. The
   pond scene behind the hero goes, since the wallpaper is the scene. */
body.aero {
  --surface: rgba(235, 245, 255, .62); --surface-2: rgba(215, 235, 252, .5);
  --surface-3: rgba(255, 255, 255, .5);
  --line: rgba(255, 255, 255, .7); --line-bright: rgba(255, 255, 255, .95);
  --mint: #4fc21a; --mint-bright: #8ee63a; --mint-deep: #2f9f0d;
  --mint-glow: rgba(142, 230, 58, .35);
}
body.aero .hero-scene { display: none; }
body.aero .spot {
  background: radial-gradient(260px circle at var(--gx, 50%) var(--gy, 50%),
              rgba(255, 255, 255, .22), rgba(255, 255, 255, .06) 40%, transparent 68%);
}

/* The glass. One recipe for every panel: frosted light blue, a white hairline, a gloss
   across the top half drawn by ::after, navy text inside. */
body.aero .bar,
body.aero footer,
body.aero .feature,
body.aero .guide,
body.aero .cost,
body.aero .chart,
body.aero .card,
body.aero .steps,
body.aero .hero-copy {
  position: relative;
  color: #0e2a4a;
  --text: #0e2a4a; --dim: #2f4a66; --faint: #4b6580;
  background: linear-gradient(180deg, rgba(255, 255, 255, .66), rgba(205, 230, 250, .46));
  border: 1px solid rgba(255, 255, 255, .8);
  border-radius: 14px;
  backdrop-filter: blur(16px) saturate(1.35);
  -webkit-backdrop-filter: blur(16px) saturate(1.35);
  box-shadow: inset 0 1px 0 #fff, inset 0 -1px 0 rgba(255, 255, 255, .35),
              0 12px 34px -14px rgba(0, 45, 100, .55);
  text-shadow: none;
}
body.aero .bar::after,
body.aero footer::after,
body.aero .feature::after,
body.aero .guide::after,
body.aero .cost::after,
body.aero .chart::after,
body.aero .card::after,
body.aero .steps::after,
body.aero .hero-copy::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 48%;
  border-radius: inherit;
  border-bottom-left-radius: 40% 60%;
  border-bottom-right-radius: 40% 60%;
  background: linear-gradient(180deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, .05));
  pointer-events: none;
  z-index: 0;
}
body.aero .bar { border-radius: 0 0 14px 14px; z-index: 10; }
body.aero .bar > *, body.aero .feature > *, body.aero .guide > *, body.aero .cost > *,
body.aero .chart > *, body.aero .card > *, body.aero .steps > *, body.aero .hero-copy > * {
  position: relative; z-index: 1;
}
body.aero .bar a, body.aero .bar .nav-link, body.aero .bar .link-plain, body.aero .bar .who,
body.aero .bar button.link { color: #0e2a4a; }
body.aero .brand { background: none; -webkit-background-clip: initial; background-clip: initial;
                   color: #0e2a4a; -webkit-text-fill-color: #0e2a4a; }
body.aero .button.chip { background: rgba(255, 255, 255, .55); color: #0e2a4a;
                         border-color: rgba(255, 255, 255, .9); }
body.aero .feature { border-left: 1px solid rgba(255, 255, 255, .8); }
body.aero .feature h3, body.aero .guide strong, body.aero .cost strong,
body.aero .steps strong, body.aero .cost-label { color: #0e2a4a; }
body.aero .feature p, body.aero .guide p, body.aero .cost p, body.aero .steps li,
body.aero .chart .fine, body.aero .hero-copy .fine, body.aero .hero-copy p,
body.aero footer p, body.aero footer a, body.aero .foot-col h4, body.aero .foot-bottom,
body.aero .meter-label { color: #2f4a66; text-shadow: none; }
body.aero .guide .more, body.aero .cost a, body.aero footer a:hover,
body.aero .meter-val, body.aero .history-pct { color: #1f7a08; }
body.aero .foot-brand { color: #0e2a4a; }

/* The hero panel: navy headline with the one lime word, on light glass. */
body.aero .hero-copy h1 {
  background: none; -webkit-background-clip: initial; background-clip: initial;
  color: #0e2a4a; -webkit-text-fill-color: #0e2a4a; text-shadow: none;
}
body.aero .hero-copy h1 em { color: #2f9f0d; -webkit-text-fill-color: #2f9f0d; }
body.aero .hero-copy .pill {
  background: rgba(255, 255, 255, .6); border-color: rgba(255, 255, 255, .9); color: #1f7a08;
}
body.aero .hero-copy .used { color: #4b6580; }

/* Gel buttons: the hard highlight across the top, the deeper green below the seam. */
body.aero .button:not(.ghost):not(.chip) {
  background: linear-gradient(180deg, #e2ffa8 0%, #9cef44 47%, #55c91c 53%, #7ee030 100%);
  color: #103a08;
  border: 1px solid rgba(38, 120, 14, .65);
  border-radius: 12px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, .7);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), inset 0 -8px 14px rgba(0, 90, 0, .16),
              0 8px 18px -8px rgba(0, 70, 0, .7);
}
body.aero .button:not(.ghost):not(.chip):hover {
  filter: brightness(1.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), inset 0 -8px 14px rgba(0, 90, 0, .16),
              0 12px 24px -8px rgba(0, 70, 0, .7);
}
body.aero .button.ghost {
  background: linear-gradient(180deg, rgba(255, 255, 255, .8), rgba(215, 235, 252, .55));
  color: #0e2a4a;
  border: 1px solid rgba(255, 255, 255, .95);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 #fff, 0 8px 18px -10px rgba(0, 45, 100, .5);
}
body.aero .spec-chip {
  background: rgba(255, 255, 255, .6); border-color: rgba(255, 255, 255, .95); color: #114a2a;
}
body.aero .plan-ribbon, body.aero .cost-ribbon {
  background: linear-gradient(180deg, #e2ffa8, #7ee030); color: #103a08;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9);
}
body.aero .cost.paid { border-color: rgba(255, 255, 255, .95);
                       box-shadow: inset 0 1px 0 #fff, 0 0 34px -10px rgba(142, 230, 58, .9); }

/* Text straight on the wallpaper: white with a shadow, and the bands turn to light glass. */
body.aero .pitch-copy h2, body.aero .pitch-copy p, body.aero .section, body.aero .lead,
body.aero .grid-foot, body.aero .closing h2, body.aero .closing p, body.aero .closing .fine,
body.aero .guides .lead, body.aero .pitch-pic > .fine {
  color: #fff; text-shadow: 0 1px 2px rgba(0, 40, 90, .8), 0 2px 12px rgba(0, 40, 90, .5);
}
body.aero .pitch { border-top-color: rgba(255, 255, 255, .35); }
body.aero .pitch:nth-child(even)::before {
  background: linear-gradient(180deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, .1));
  border-top: 1px solid rgba(255, 255, 255, .55);
  border-bottom: 1px solid rgba(255, 255, 255, .35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
body.aero .more { color: #fff; text-shadow: 0 1px 2px rgba(0, 40, 90, .8); }
body.aero .grid-foot a { color: #e2ffa8; }
body.aero .float-add { color: #103a08; }

/* Bubbles, the Y2K half: glossy spheres drifting up the page on a fixed layer, drawn by
   app.js when aero is switched on and removed when it is switched off. */
.aero-bubbles { position: fixed; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.aero-bubbles i {
  position: absolute;
  bottom: -160px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgba(255, 255, 255, .95) 0 6%, rgba(255, 255, 255, .3) 12%, rgba(255, 255, 255, 0) 22%),
    radial-gradient(circle at 50% 50%, rgba(190, 235, 255, .08) 0 58%, rgba(255, 255, 255, .5) 74%, rgba(255, 255, 255, .85) 80%, rgba(255, 255, 255, 0) 83%);
  box-shadow: inset -6px -8px 16px rgba(0, 70, 140, .16), 0 0 18px rgba(255, 255, 255, .28);
  animation: bubble-rise linear infinite;
}
.aero-bubbles b {
  position: absolute; left: -12vw; top: -14vw; width: 46vw; height: 46vw; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 230, .55), rgba(255, 255, 210, .18) 35%, rgba(255, 255, 200, 0) 68%);
}
@keyframes bubble-rise {
  0% { transform: translateY(0) translateX(0); opacity: 0; }
  8% { opacity: 1; }
  50% { transform: translateY(-60vh) translateX(18px); }
  100% { transform: translateY(-125vh) translateX(-10px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .aero-bubbles i { animation: none; display: none; } }

/* The wet-glass texture under the gloss: water drops on a surface, a CC0 photograph
   ("Dews" by Nithya Ramanujam, Wikimedia Commons), lifted and cooled, shown through a
   white wash so the text on top stays easy to read. */
body.aero .feature,
body.aero .guide,
body.aero .cost,
body.aero .card,
body.aero .steps,
body.aero .hero-copy,
body.aero footer {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .78), rgba(215, 235, 252, .62)),
    url("aero-dew.webp") center / cover no-repeat;
}

/* The glossy icons: KDE's Oxygen set (LGPL, from Wikimedia Commons), only in aero mode,
   where the mint line icons would look out of place. */
.aero-ico, .aero-credit { display: none; }
body.aero .aero-ico { display: block; height: auto; filter: drop-shadow(0 4px 8px rgba(0, 40, 90, .45)); }
body.aero .pitch-copy .aero-ico { width: 56px; margin-bottom: 12px; }
body.aero .three-row .three-icon { display: none; }
body.aero .three-row .aero-ico { width: 56px; margin-bottom: 12px; }
body.aero .guide .aero-ico { width: 44px; margin-bottom: 8px; }
body.aero .aero-credit { display: block; }

/* ── the aero slideshow ──────────────────────────────────────────── */
/* Two fixed layers under the page; app.js paints the next picture on the hidden one and
   swaps which is showing. The swap is a cross-fade where the incoming picture arrives
   from a blur and the outgoing one dissolves into one, so it reads as a soft focus pull
   rather than a cut. The wallpaper on body::before stays underneath as the first slide. */
.aero-slides { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.aero-slides > div {
  position: absolute; inset: -24px;
  background: #2a7fd4 center / cover no-repeat;
  opacity: 0;
  filter: blur(22px);
  transform: scale(1.04);
  transition: opacity 1.8s ease, filter 1.8s ease, transform 8s ease-out;
}
.aero-slides > div.showing { opacity: 1; filter: blur(0); transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .aero-slides > div { transition: none; filter: none; transform: none; }
}
