/* ============================================================
 *  discords.css — donutdiscords' own pages.
 *
 *  Loaded AFTER tokens.css and shell.css. Everything here uses the shell's
 *  tokens and its control shape (surface, hairline border, inset highlight) —
 *  no new colours, no second radius scale, no second font. A card here should
 *  look like it came off the same site as a donutstats leaderboard row,
 *  because it did.
 * ============================================================ */

/* Same gutter and bottom room as every other page in the family: donutstats'
   .ah-wrap is `padding: 0 24px 60px`, and .container is `0 24px`. Ours used 20
   and 90, which is why the content sat at a different inset from the edge than
   the same shelves do on donutstats.
   Wider than .ah-wrap's 980 on purpose — this page is a grid of cards, not a
   column of text, so it earns the extra width the auction house does not. */
.dd-wrap { max-width: 1180px; margin: 0 auto; padding: 0 24px 60px; }

/* The listing page carries its own vertical rhythm (see below), so it must not
   also inherit the shelf page's 60px tail — that is what pushed the footer out
   of view. */
body:has(main .dd-detail) .dd-wrap { padding-bottom: 0; }

/* ── the first screen ───────────────────────────────────────────────────────
 * THE HERO SITS WHERE THE THING BELOW IT PUTS IT.
 *
 * Everything about the hero itself was already identical — same rules (shared
 * from shell.css), same fonts, same weights, every variable resolving. The
 * remaining ~150px was pure geometry, and it took measuring both screenshots to
 * see it:
 *
 *   .home-top is `100dvh - nav`, flex column, CENTRED. Centring splits the
 *   leftover space, so the hero is lifted by half the height of whatever sits
 *   under it inside that block. donutstats puts a leaderboard carousel there —
 *   `padding: 34px 0 40px` around a ~315px card, about 390px — so its hero
 *   rises ~195px. Ours had a 50px tag row, so it rose ~25px. Same hero, same
 *   wrapper, 170px apart, and no amount of adjusting padding on the hero could
 *   have fixed it because the hero was never the thing that was wrong.
 *
 * So the band below the hero is RESERVED at the same height. The tag row sits
 * at the top of it, exactly where the carousel starts, and the hero lands in
 * the same place by construction rather than by a number I tuned.
 *
 * The reserve is not a hack — it is the slot the "trending this week" strip
 * belongs in, which is the content that will eventually make this page as full
 * as donutstats'. --home-under is the one knob if the carousel ever changes
 * height there.
 */
.home-top {
  min-height: var(--hero-fill, calc(100dvh - var(--nav-h, 51px)));
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.home-top > .home-hero,
.home-top > .home-under { flex: 0 0 auto; }

/* The band donutstats fills with its carousel. 34px of top padding mirrors the
   carousel's own, so the tag row begins on the same line the cards do. */
.home-under {
  min-height: var(--home-under, 390px);
  padding-top: 34px;
}

body:has(.home-hero) main { display: block; padding-bottom: 0; }

/* ── tags ───────────────────────────────────────────────────────────────────
 * These went missing entirely: the hero re-copy replaced everything between the
 * hero and shelves headings, and this block lived in that range, so the buttons
 * rendered as raw browser default controls. Restored, and rebuilt as a
 * SEGMENTED GROUP — the same treatment as the chart range picker and the
 * settings switches, which is this estate's one existing "pick one of these"
 * control. Three pills floating on the page background read as three separate
 * decisions; inside one track they read as one.
 */
/* OUT of the hero block. While it lived in .home-top its height was part of the
   first screen's arithmetic, so adding or removing a category shifted the
   wordmark — the hero's position has to depend on the hero and nothing else.
   It sits above the shelves now, with its own fixed rhythm. */
.dd-tags {
  display: flex;
  justify-content: center;
  padding: 0 0 6px;   /* the band above supplies the top rhythm */
}
.dd-tags-inner {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}
.dd-tagbtn {
  font: 600 12.5px var(--font); color: var(--text-mid);
  background: transparent; border: none;
  border-radius: var(--radius-pill); padding: 7px 16px; cursor: pointer;
  white-space: nowrap;
  transition: background .16s ease, color .16s ease;
}
.dd-tagbtn:hover { background: var(--surface-3); color: var(--text); }
/* Solid, not a tint: the selected one has to win against the group's own
   surface, and a translucent fill over that surface barely moves. */
.dd-tagbtn.on { color: #fff; background: var(--blue); }
.dd-tagbtn.on:hover { background: var(--blue); }

/* The magnifier had no size and filled its flex box. Kept as a backstop even
   though the search hero is gone, so a future icon cannot do it again. */
.search-box svg { width: 18px; height: 18px; flex: 0 0 auto; }

/* ── shelves ────────────────────────────────────────────────────────────── */
.dd-shelf { margin-top: 34px; }
.dd-grid {
  display: grid; gap: 14px; margin-top: 14px;
  /* auto-fill with a min, so a shelf of two does not stretch two cards across
     the page — the row simply is not full, which is honest. */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

/* ── the card ───────────────────────────────────────────────────────────── */
.dd-card {
  background: var(--card-bg); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 15px 16px 13px;
  display: flex; flex-direction: column; gap: 10px; cursor: pointer;
  transition: background .16s ease, border-color .16s ease, transform .16s ease;
}
.dd-card:hover {
  background: var(--card-bg-hover); border-color: var(--border-bright);
  transform: translateY(-2px);
}
.dd-card:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

.dd-card-top { display: flex; align-items: flex-start; gap: 12px; }
.dd-card-head { min-width: 0; flex: 1; }
.dd-card-name {
  margin: 0; font: 700 15px var(--font); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dd-card-tag {
  margin: 3px 0 0; font: 400 12.5px var(--font); color: var(--text-mid);
  /* The tagline is capped at 70 characters server-side, but a long word can
     still overflow, so it is clamped here too. Belt and braces on the one
     thing that decides whether a row of cards is the same height. */
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden;
}
.dd-card-about {
  margin: 0; font: 400 12.5px/1.5 var(--font); color: var(--text-mid);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2lh;     /* two lines reserved, so cards line up whether or not
                          a listing wrote an About */
}

.dd-ico {
  width: 48px; height: 48px; border-radius: 14px; flex-shrink: 0;
  background: var(--surface-3); object-fit: cover;
}
.dd-ico-fb {
  display: grid; place-items: center;
  font: 700 20px var(--font); color: var(--text);
  background: hsl(var(--h, 210) 42% 24%);
}

.dd-badges { display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }
.dd-badge {
  font: 700 9.5px var(--font); letter-spacing: .08em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 6px; white-space: nowrap;
}
.dd-badge-ours { color: var(--blue-bright); background: var(--blue-fill); border: 1px solid var(--blue-border-dim); }
/* Paid placement says so. A directory that hides which slots were bought is a
   directory nobody believes for long — and saying it is also what makes the
   slot worth buying. */
.dd-badge-paid { color: var(--gold); background: rgba(245,158,11,.10); border: 1px solid rgba(245,158,11,.28); }
.dd-badge-up   { color: var(--green); background: rgba(34,197,94,.10); border: 1px solid rgba(34,197,94,.28); }
.dd-badge-ok   { color: var(--green); background: rgba(34,197,94,.10); border: 1px solid rgba(34,197,94,.28); }
.dd-badge-dead { color: var(--red); background: rgba(239,68,68,.10); border: 1px solid rgba(239,68,68,.28); }

.dd-card-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  padding-top: 10px; border-top: 1px solid var(--border-soft);
  font: 600 11.5px var(--font); color: var(--text-mid);
}
.dd-chip-tag {
  font: 700 10px var(--font); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-mid); background: var(--surface-3);
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 8px;
}
.dd-stat { display: inline-flex; align-items: center; gap: 5px; }
.dd-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-dim); }
.dd-dot-on { background: var(--green); box-shadow: 0 0 0 3px rgba(34,197,94,.16); }
.dd-votes { margin-left: auto; color: var(--blue-bright); font-weight: 700; }

/* ── rating ─────────────────────────────────────────────────────────────── */
/* One bar filled to a fraction, not five glyphs. At card size five separate
   shapes turn to mush, and a partial star is unreadable at 12px. */
.dd-rate { display: inline-flex; align-items: center; gap: 5px; }
.dd-rate b { color: var(--text); font-weight: 700; }
.dd-rate i { color: var(--text-dim); font-style: normal; font-size: 10.5px; }
.dd-rate-none { color: var(--text-dim); font-weight: 400; }
.dd-stars {
  position: relative; width: 46px; height: 8px; border-radius: 4px;
  background: var(--surface-3); overflow: hidden;
}
.dd-stars-on { position: absolute; inset: 0 auto 0 0; background: var(--gold); }

.dd-card-sk {
  min-height: 158px; background: var(--card-bg);
  border: 1px solid var(--border-soft); border-radius: var(--radius-card);
  animation: dd-pulse 1.4s ease-in-out infinite;
}
@keyframes dd-pulse { 0%,100% { opacity: .55 } 50% { opacity: .85 } }

/* ── detail page ────────────────────────────────────────────────────────── */
/*
 * One server's page is a single card and usually shorter than the window, so it
 * used to sit at the top with a long empty gap under it and the footer pushed
 * off the bottom — a page that scrolls to reveal nothing.
 *
 * main becomes a column and the card centres in whatever room is left after the
 * header and footer, with equal air above and below. min-height, NOT height:
 * a tall window centres the card, a short one lets the page grow and scroll
 * normally. Forcing overflow:hidden here would cut the activity chart off on a
 * laptop, which is a worse bug than a scrollbar.
 */
/* `main .dd-detail`, not `.dd-detail`. The card now also exists inside the
   server modal, which is a child of <body> — so the unscoped selector matched
   whenever a listing was open and centred the HOMEPAGE's main behind it. */
body:has(main .dd-detail) main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Both published by shell-nav.js from the real elements. The fallbacks only
     ever apply for the frame before the first measurement lands. */
  min-height: calc(100vh - var(--nav-h, 66px) - var(--foot-h, 130px));
  padding: clamp(14px, 2.5vh, 30px) 0;
}

.dd-detail {
  background: var(--card-bg); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 22px; margin-top: 14px;
}
.dd-detail-sk { min-height: 340px; animation: dd-pulse 1.4s ease-in-out infinite; }
.dd-detail-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.dd-detail-head .dd-ico { width: 76px; height: 76px; border-radius: 20px; }
.dd-detail-id { flex: 1; min-width: 200px; }
.dd-detail-name { margin: 0; font: 700 24px var(--font); color: var(--text); }
.dd-detail-tag { margin: 5px 0 0; font: 400 14px var(--font); color: var(--text-mid); }
.dd-detail-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
.dd-detail-about {
  margin: 18px 0 0; font: 400 14px/1.65 var(--font); color: var(--text-mid);
  max-width: 68ch;
}

.dd-join {
  font: 700 13px var(--font); color: #fff; background: #5865F2;
  border: none; border-radius: 8px; padding: 11px 20px; text-decoration: none;
  white-space: nowrap; transition: filter .16s ease;
}
.dd-join:hover { filter: brightness(1.12); }

.dd-nums {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px; margin-top: 20px;
}
.dd-num {
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 12px; padding: 12px 14px;
}
.dd-num-v { font: 700 20px var(--mono); color: var(--text); }
.dd-num-l { font: 600 11px var(--font); color: var(--text-mid); margin-top: 3px; }
.dd-num-s { font: 400 10.5px var(--font); color: var(--text-dim); margin-top: 2px; }

.dd-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--border-soft);
}
.dd-vote {
  font: 700 13px var(--font); color: var(--text);
  background: var(--blue-fill); border: 1px solid var(--blue-border);
  border-radius: 10px; padding: 10px 18px; cursor: pointer;
  transition: background .16s ease;
}
.dd-vote:hover:not(:disabled) { background: rgba(3,111,255,.18); }
.dd-vote:disabled { cursor: default; color: var(--text-dim); background: var(--surface-3); border-color: var(--border); }
.dd-vote.is-done { color: var(--green); border-color: rgba(34,197,94,.3); background: rgba(34,197,94,.08); }

.dd-rateblock {
  display: inline-flex; align-items: center; gap: 10px; margin-left: auto;
  font: 600 12px var(--font); color: var(--text-mid);
}
.dd-rateblock-guest { color: var(--text-dim); }
.dd-rateblock-l { white-space: nowrap; }
/* "Voted elsewhere today" — the limit is one A DAY, not one ever, so this
   reads differently from the disabled state on the server you did vote for. */
.dd-vote.is-spent { color: var(--text-dim); }
.dd-starrow { display: inline-flex; gap: 2px; }
.dd-star {
  background: none; border: none; cursor: pointer; padding: 2px;
  font-size: 20px; line-height: 1; color: var(--surface-4);
  transition: color .12s ease, transform .12s ease;
}
.dd-star:hover { transform: scale(1.12); }
.dd-star.on { color: var(--gold); }
/* Hovering a star lights every star to its LEFT as well, so the control shows
   the score it would set rather than only the one under the cursor. */
.dd-starrow:hover .dd-star { color: var(--gold); }
.dd-starrow .dd-star:hover ~ .dd-star { color: var(--surface-4); }
.dd-unrate { background: none; border: none; cursor: pointer; color: var(--text-dim); font: 600 11.5px var(--font); }
.dd-unrate:hover { color: var(--red); }

/* ── activity ───────────────────────────────────────────────────────────── */
.dd-activity { margin-top: 26px; }
.dd-abars {
  display: grid; grid-template-columns: repeat(24, 1fr); gap: 3px;
  align-items: end; height: 118px; margin-top: 12px;
  padding: 10px 10px 0; background: var(--surface-3);
  border: 1px solid var(--border); border-radius: 12px;
}
.dd-abar { background: var(--green); border-radius: 3px 3px 0 0; min-height: 2px; }
/* A SECOND SOLID TONE, not opacity. A translucent bar picks up whatever sits
   behind it and reads as washed out rather than as a quieter hour. */
.dd-abar.is-quiet { background: rgba(34,197,94,.28); }
.dd-axis {
  display: flex; justify-content: space-between; margin-top: 7px; padding: 0 4px;
  font: 500 10.5px var(--mono); color: var(--text-dim);
}

/* ── submit ─────────────────────────────────────────────────────────────── */
.dd-panel {
  background: var(--card-bg); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 20px; margin-top: 16px;
}
.dd-panel-cta { text-align: center; padding: 34px 22px; }
.dd-panel-t { margin: 0; font: 700 19px var(--font); color: var(--text); }
.dd-panel-b { margin: 9px auto 18px; max-width: 58ch; font: 400 13.5px/1.6 var(--font); color: var(--text-mid); }

/* Three across in the modal, and auto-fill outside it. minmax(0,1fr) rather
   than a min width: a fixed minimum silently drops to two columns the moment a
   name is long, which is the sort of layout that looks like it broke. */
.dd-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; margin-top: 14px; }
.dd-add-body .dd-picker { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 0; }
@media (max-width: 720px) { .dd-add-body .dd-picker { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Three across means each tile is narrow, so it stacks: face on top, name
   under it, role last. Side by side at this width the name had about six
   characters before the ellipsis. */
/* Compact. The tile was 44px of icon plus 28px of padding, which set the
   modal's width more than any of its content did — three of them and the panel
   had to be 780px wide to avoid squeezing the names. */
.dd-pick {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 11px; padding: 10px 8px; cursor: pointer;
  transition: background .16s ease, border-color .16s ease, transform .16s ease;
}
.dd-pick:hover { background: var(--surface-4); border-color: var(--border-bright); transform: translateY(-1px); }
.dd-pick.on { border-color: var(--blue-border); background: var(--blue-fill); }
.dd-pick .dd-ico { width: 34px; height: 34px; border-radius: 11px; font-size: 14px; }
.dd-pick-n {
  width: 100%; min-width: 0; font: 600 11.5px var(--font); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dd-pick-r { font: 700 8.5px var(--font); letter-spacing: .07em; text-transform: uppercase; color: var(--text-dim); }

.dd-field { margin-top: 16px; }

/* Invite and category on one row. They are the two things the person has to
   supply about a server they have already chosen, and both are short — stacked,
   they made a three-screen form out of two decisions. The invite takes the
   remaining width because a URL is the only thing here that can be long. */
.dd-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px; align-items: start;
}
.dd-row > .dd-field { margin-top: 0; }
.dd-row .dd-tags { justify-content: flex-start; padding: 0; }
@media (max-width: 620px) {
  .dd-row { grid-template-columns: minmax(0, 1fr); }
}
.dd-label {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 600 12px var(--font); color: var(--text-mid); margin-bottom: 6px;
}
/* --font, not --mono: JetBrains Mono draws a DOTTED ZERO, which in a counter
   that spends most of its life reading "0/120" looks like a rendering fault.
   Tabular numerals keep the digits from shifting as the count climbs, which is
   the only thing the monospace face was really buying here. */
.dd-count {
  font: 500 10.5px var(--font); color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.dd-input {
  width: 100%; box-sizing: border-box;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 10px; padding: 11px 13px;
  font: 400 13.5px var(--font); color: var(--text);
  transition: border-color .16s ease, background .16s ease;
}
.dd-input:focus { outline: none; border-color: var(--blue-border); background: var(--surface-4); }
.dd-input::placeholder { color: var(--text-dim); }
/* No resize handle. The field is sized for the 120 characters it accepts, and a
   grabber in the corner of a box that cannot usefully grow is furniture. */
.dd-area { resize: none; line-height: 1.55; font-family: var(--font); }
.dd-hint { display: block; margin-top: 6px; font: 400 11.5px var(--font); color: var(--text-dim); }

.dd-form-foot { display: flex; align-items: center; gap: 14px; margin-top: 22px; }
.dd-form-msg { font: 500 12.5px var(--font); color: var(--text-mid); }
.dd-form-msg.is-bad { color: var(--red); }

.dd-mine { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.dd-mine-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 12px;
}
.dd-mine-row .dd-ico { width: 38px; height: 38px; border-radius: 11px; font-size: 15px; }
.dd-mine-id { flex: 1; min-width: 0; }
.dd-mine-n { display: block; font: 600 13.5px var(--font); color: var(--text); cursor: pointer; }
.dd-mine-n:hover { color: var(--blue-bright); }
.dd-mine-s { font: 500 11.5px var(--font); color: var(--text-mid); }
.dd-dead { color: var(--red); font-weight: 700; }
.dd-bump {
  font: 700 12px var(--font); color: var(--text);
  background: var(--blue-fill); border: 1px solid var(--blue-border);
  border-radius: 9px; padding: 8px 14px; cursor: pointer; white-space: nowrap;
}
.dd-bump.is-off { color: var(--text-dim); background: var(--surface-4); border-color: var(--border); cursor: default; }
.dd-edit { padding: 8px 14px; font-size: 12px; }

/* ── the server modal ───────────────────────────────────────────────────────
 * A listing opens over the shelves rather than replacing them. Same backdrop
 * and surface as the settings modal; the detail card inside keeps the styles it
 * already had, minus the page chrome it no longer needs.
 */
.dd-srv-modal {
  width: min(760px, 100%); height: auto;
  max-height: min(88vh, 860px);
  position: relative; overflow: hidden;
  display: block;
}
.dd-srv-x { position: absolute; right: 12px; top: 12px; z-index: 4; }
.dd-srv-body {
  overflow: auto;
  max-height: min(88vh, 860px);
}
.dd-srv-body::-webkit-scrollbar { width: 6px; }
.dd-srv-body::-webkit-scrollbar-thumb { background: var(--border-bright); border-radius: 3px; }
.dd-srv-body::-webkit-scrollbar-track { background: transparent; }
.dd-srv-body::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
@supports (-moz-appearance: none) {
  .dd-srv-body { scrollbar-width: thin; scrollbar-color: var(--border-bright) transparent; }
}
/* Inside the modal the card IS the modal: no second border, no second radius,
   no shadow of its own. */
.dd-srv-body .dd-detail {
  background: none; border: none; border-radius: 0; margin: 0; padding: 24px;
}
/* The page-centring rule must not apply to the modal copy. */
.dd-srv-backdrop .dd-detail { min-height: 0; }

/* ── the add-a-server modal ─────────────────────────────────────────────────
 * Only the pieces the settings modal does not already provide. The backdrop,
 * blur, surface, radius, header and footer all come from .set-* — reusing them
 * is what makes this feel like the same product rather than a lookalike.
 */
/* Wide enough for three picker tiles. .set-modal's own width is min(880px,100%)
   and its height min(600px, …); this only narrows it, so the surface, radius,
   border and the blue hairline in its shadow are all still the settings
   modal's. */
/* Narrower: the tiles were doing the widening, not the content. See .dd-pick. */
.dd-add-modal {
  width: min(660px, 100%); height: auto;
  max-height: min(660px, calc(100vh - 48px));
  /* head / body / foot, so the footer is a row of the modal rather than
     something floating inside the scroll area. */
  display: grid; grid-template-rows: auto 1fr auto;
}

/* The title is centred, with the close button floating over the right end
   rather than sitting in the row — otherwise the title centres against the
   space LEFT OVER beside the button, which is a few pixels off centre and
   reads as a mistake rather than a choice.
   
   Taller, and left on the modal's OWN surface — only the footer is darker.
   Darkening both ends framed the content like a letterbox; the settings modal
   darkens just its foot, so the panel reads as a card with a base rather than a
   band sandwiched between two bars. */
.dd-add-modal .set-head {
  position: relative; justify-content: center;
  padding: 22px 52px;
  border-bottom: 1px solid var(--border-soft);
}
.dd-add-modal .set-head h2 { text-align: center; font-size: 14px; letter-spacing: .06em; }
.dd-add-modal .set-x { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); }

/* Search over the picker. Same shape as the site's other inputs; it appears
   only when the list is long enough to be worth filtering. */
.dd-add-search {
  display: flex; align-items: center; gap: 9px;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 10px; padding: 9px 12px; margin-bottom: 14px;
  color: var(--text-dim);
}
.dd-add-search:focus-within { border-color: var(--blue-border); background: var(--surface-4); }
/* `.set-backdrop :focus-visible` draws a 2px blue outline on ANY focused thing
   inside a modal — correct nearly everywhere, wrong here, because the input
   fills a field that already has its own border and the ring landed as a
   rectangle floating inside it. The wrapper shows focus instead (above), which
   is the same signal on the element people actually see. */
.set-backdrop .dd-add-search input:focus-visible,
.set-backdrop .dd-add-search input:focus { outline: none; box-shadow: none; }
.dd-add-search input {
  flex: 1; min-width: 0; background: none; border: none; outline: none;
  font: 400 13px var(--font); color: var(--text);
}
.dd-add-search input::placeholder { color: var(--text-dim); }

.dd-add-body {
  display: block; padding: 20px 22px;
  max-height: min(62vh, 560px); overflow: auto;
  /* The spawner calculator's worth panel, exactly: rgba(0,0,0,0.28), chosen
     there because --page-bg made it identical to both the chips on it and the
     page behind the card. The same reasoning holds here — the picker tiles sit
     on --surface-3, so the surface under them has to be darker than the modal
     without dropping all the way to the page. */
  background: rgba(0, 0, 0, 0.28);
  /* The house inner-scrollbar, lifted from .set-menu-body — the page's overlay
     scrollbar is a page-level thing and cannot serve a scrolling panel. */
  /* NO scrollbar-width here. Chromium 121+ treats the standard property as
     opt-in to the standard scrollbar and then IGNORES every
     ::-webkit-scrollbar rule below — which is why the end-cap arrows kept
     coming back however many sub-parts were set to display:none. The
     webkit rules do the work in Chromium and Safari; Firefox, which has no
     arrows to remove, gets the thin treatment in the @supports block after
     this rule. */
}
.dd-add-body::-webkit-scrollbar { width: 6px; }
.dd-add-body::-webkit-scrollbar-thumb { background: var(--border-bright); border-radius: 3px; }
.dd-add-body::-webkit-scrollbar-track { background: transparent; }
/* No end caps. The page's overlay scrollbar is a bare thumb on a bare track,
   and a panel inside it sprouting little arrow boxes is the one place the
   native control shows through. */
/* The end caps. `display: none` alone is not reliably honoured — the buttons
   are a shadow-DOM part and some builds keep reserving their box — so the size
   is zeroed as well, and every sub-part is named rather than relying on one. */
.dd-add-body::-webkit-scrollbar-button,
.dd-add-body::-webkit-scrollbar-button:start,
.dd-add-body::-webkit-scrollbar-button:end,
.dd-add-body::-webkit-scrollbar-button:vertical:start,
.dd-add-body::-webkit-scrollbar-button:vertical:end,
.dd-add-body::-webkit-scrollbar-button:vertical:increment,
.dd-add-body::-webkit-scrollbar-button:vertical:decrement {
  display: none; width: 0; height: 0; background: transparent;
}
.dd-add-body::-webkit-scrollbar-corner { background: transparent; }

/* Firefox only: it ignores the webkit pseudo-elements and draws no arrows, so
   the standard property is safe to use where it is the ONLY thing available.
   -moz-appearance matches in Firefox and nowhere else. */
@supports (-moz-appearance: none) {
  .dd-add-body { scrollbar-width: thin; scrollbar-color: var(--border-bright) transparent; }
}
/* ── the modal's action bar ──────────────────────────────────────────────────
 * Three zones on one row: a way back on the left, what the site is telling you
 * in the middle, the commit on the right. That is the order the settings modal
 * already uses (Reset / … / Done), so this is the same bar with the middle slot
 * filled rather than a new one.
 *
 * DARKER than the modal body, and darker than .set-foot's own 35% wash: the
 * footer should read as the page showing through beneath the panel, which is
 * what makes a modal look like it is sitting on the site rather than floating
 * in front of a grey rectangle. --page-bg is that colour exactly.
 */
.dd-add-foot {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: 14px;
  padding: 16px 20px;
  /* The SAME wash as the body, so the bar blends into the panel instead of
     ending it with a second colour. The hairline is all the separation it
     needs. */
  background: rgba(0, 0, 0, 0.28);
  border-top: 1px solid var(--border-soft);
}
.dd-add-foot[hidden] { display: none; }
/* "Pick another" is a step BACK, not a destructive action — .set-reset turns red
   on hover because it undoes your settings, which would be the wrong promise
   here. Same shape, neutral intent. */
.dd-add-foot .set-reset { color: var(--text-mid); background: transparent; border-color: var(--border); }
.dd-add-foot .set-reset:hover {
  color: var(--text); background: var(--surface-3); border-color: var(--border-bright);
}

/* The commit keeps .set-done's gradient — it is the site's one "this is the
   button" treatment and the modal should not invent a second. */
.dd-add-foot .set-done { padding: 10px 22px; }
.dd-add-foot .set-done[disabled] { filter: grayscale(.6) brightness(.8); cursor: default; }

.dd-add-foot .dd-form-msg {
  text-align: center; font: 500 12.5px var(--font); color: var(--text-mid);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dd-add-foot .dd-form-msg.is-bad { color: #fca5a5; }

.dd-add-wait {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 44px 20px; color: var(--text-mid); font: 500 13.5px var(--font);
}
.dd-add-wait.is-bad { color: var(--red); }
.dd-spin {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--surface-4); border-top-color: var(--blue);
  animation: dd-spin .7s linear infinite;
}
@keyframes dd-spin { to { transform: rotate(360deg); } }

.dd-add-empty {
  padding: 34px 22px; text-align: center; color: var(--text-mid);
  font: 400 13.5px/1.6 var(--font);
  display: flex; flex-direction: column; align-items: center; gap: 16px;
}

/* A server already listed stays in the picker rather than vanishing — a gap
   where your server used to be reads as "we lost it". Marked instead, and it
   opens the edit form. */
.dd-pick.is-listed { opacity: .72; }
.dd-pick.is-listed .dd-pick-r { color: var(--blue-bright); }
/* A listing whose invite stopped resolving. Marked rather than hidden — this is
   the one screen where you can fix it, so removing it would hide the problem
   from the only person who can do anything about it. */
.dd-pick.is-dead { border-color: rgba(239,68,68,.35); }
.dd-pick.is-dead .dd-pick-r { color: var(--red); }

/* Inside the modal the tag group sits left with the other fields, not centred
   like the one under the hero. */
.dd-add-body .dd-tags { justify-content: flex-start; padding: 0; }

/* ── narrow ─────────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .dd-wrap { padding: 18px 14px 70px; }
  .dd-add-body { max-height: 70vh; }
  .dd-add-foot { flex-wrap: wrap; }
  .dd-grid { grid-template-columns: 1fr; }
  .dd-detail { padding: 16px; }
  .dd-detail-name { font-size: 20px; }
  .dd-join { width: 100%; text-align: center; }
  .dd-rateblock { margin-left: 0; width: 100%; }
  /* 24 bars in a phone's width is 4px each — still readable as a shape, which
     is all this chart is for. Kept rather than dropped: "when is it busy" is
     exactly the question someone on a phone is asking. */
  .dd-abars { height: 92px; gap: 2px; }
}
