/* ============================================================
 *  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 ───────────────────────────────────────────────────────
 * WHY THE HERO SITS WHERE IT SITS, and why this took several passes.
 *
 * `.home-top` is `100dvh - nav`, a flex column, CENTRED. Centring splits the
 * leftover space, so the hero is lifted by exactly HALF THE HEIGHT OF WHATEVER
 * SITS UNDER IT inside that block. donutstats puts its leaderboard carousel
 * there. The hero rules are identical on both sites — same clamps, same fonts,
 * same weights, all verified — so the only thing that could ever have differed
 * is the height of that second child.
 *
 * Every earlier attempt got that height wrong: first there was nothing under
 * the hero at all (a 50px tag row, so the hero barely rose and sat far too
 * low), then a 390px band eyeballed off a screenshot (too tall, so the hero
 * rose too far and left a canyon underneath).
 *
 * This time it is DERIVED FROM DONUTSTATS' OWN CSS rather than measured off a
 * picture:
 *
 *   .home-carousel  padding: clamp(16px,3.5vh,34px) 0 clamp(18px,4vh,40px)
 *   .lcard-compact  14px padding, 1px border, and inside it
 *                     title  12.5px + 12 padding + 1 border + 10 margin
 *                     rows   min-height 150px  (5 reserved rows x 30px)
 *                     more   11px + 14 padding + 2 border + 10 margin
 *
 * so the band is the two clamps plus a FIXED card height. Both clamps are
 * copied verbatim, which matters as much as the total: they are vh-based, so
 * donutstats' hero moves as the window height changes and ours has to move with
 * it. A single fixed number would match on one screen and drift on every other.
 *
 * --home-card-h is the one value that is arithmetic rather than a quotation.
 * If the wordmarks still do not line up, that is the number to change, and
 * nothing else needs touching.
 */
.home-top {
  min-height: 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; }

/* donutstats' @media (max-height: 620px) rule, copied — below that the block
   stops trying to fill the screen rather than squeezing the hero. */
@media (max-height: 620px) {
  .home-top { min-height: 0; }
}

/* The slot the carousel occupies there, at the same height, with the same
   vh-based padding. The tag row is CENTRED in it rather than pinned to the top:
   the cards it stands in for are centred in that space, and a row of buttons
   hugging the ceiling of an otherwise empty band is what read as "too much
   space underneath". */
.home-under {
  /* MEASURED, not computed. donutstats' carousel band came back at 313.3px on
     a real window, against the 264px I had derived from its CSS — so my
     arithmetic was ~19px heavy, which centred means the hero was sitting ~10px
     too high with that much extra beneath it.
     
     Stored as the CARD height rather than the band total, deliberately: the
     band's two paddings are vh-based on donutstats, so quoting the total would
     match on the window it was measured on and drift on every other. The card
     itself is fixed px, so this is the part that travels.
     
     313.3 measured - the two clamps at that window height (~68px) = 245px. */
  --home-card-h: 245px;
  min-height: var(--home-under-h,
    calc(clamp(16px, 3.5vh, 34px) + var(--home-card-h) + clamp(18px, 4vh, 40px)));
  display: flex;
  align-items: center;
  justify-content: center;
}

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;   /* .home-under centres it; padding here would decentre it */
}
.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; }
}
