/* Shulkerboxes site v2: tokens and components. One stylesheet for every v2 page.
   Identity kept: Bricolage Grotesque (display), Geist (body), Geist Mono (labels), the lilac.
   New: a light ground by default (cool off-white, violet-cast greys), the lilac darkened for AA on it,
   one type scale, one 4 px spacing scale, radii and shadows by role. Lab: three grounds to compare
   (cloud, mist, slate), switched by v2.mjs and stored in localStorage. Contrast ratios are in README.md. */

/* ================================================================ fonts (self-hosted, cut from the live site's files) */
/* Cut for v2 from the site's fonts (fontTools instancer + subsetter): latin + Portuguese accents, and only the weight
   range v2 renders (Bricolage 600-700, Geist 400-600; Geist Mono is static 500). 116 KB -> 86 KB on a first view. */
@font-face { font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 600 700; font-stretch: 100%; font-display: swap;
  src: url(/assets/fonts/bricolage-grotesque-v9-latin-pt-wght600-700.woff2) format("woff2"); }
@font-face { font-family: "Geist"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url(/assets/fonts/geist-v5-latin-pt-wght400-600.woff2) format("woff2"); }
@font-face { font-family: "Geist Mono"; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/assets/fonts/geist-mono-v6-latin-pt.woff2) format("woff2"); }

/* ================================================================ tokens: ground "cloud" (default, light) */
:root {
  color-scheme: light;
  /* ground and surfaces */
  --bg: #f5f5f9;            /* page */
  --bg-2: #eeedf4;          /* alternate band, footer */
  --surface: #ffffff;       /* cards, inputs, nav */
  --surface-2: #f6f5fa;     /* inset rows inside a card (address rows) */
  --surface-3: #e9e7f0;     /* tracks, skeletons */
  --wash: rgb(60 40 120 / .06);   /* hover wash on quiet controls */
  --wash-2: rgb(60 40 120 / .10); /* pressed wash */
  /* lines */
  --line: #e3e1ea;          /* hairlines, card borders */
  --line-2: #d2cfdc;        /* secondary button border, dividers that must read */
  --control: #938ea4;       /* input and select borders: 3:1 on white */
  /* text: four greys, nothing else */
  --fg-1: #16131f;          /* 16.8:1 on --bg */
  --fg-2: #3d3850;          /* 10.3:1 */
  --fg-3: #5d5770;          /* 6.3:1 on --bg, 5.8:1 on --bg-2 */
  --fg-4: #8f8aa0;          /* decoration, disabled, placeholder; never body text */
  /* accent: the lilac, darkened for AA on light */
  --accent: #6a46c2;        /* button fill (white text 6.4:1), links (5.9:1 on --bg) */
  --accent-hover: #5c39b3;
  --accent-press: #4f2f9e;
  --accent-edge: #4a2c93;
  --accent-text: #6a46c2;
  --on-accent: #ffffff;
  --accent-soft: #efe8fd;   /* chips, selected tiles */
  --accent-soft-ink: #5b39b0; /* 6.6:1 on --accent-soft */
  --accent-ring: rgb(106 70 194 / .22);
  --brand-1: #b98bcc; --brand-2: #8f62a6; --brand-3: #6f4885; --brand-4: #3b2449; /* the shulker mark */
  --focus: #6a46c2;
  /* status tones */
  --ok: #1d7a46;   --ok-soft: #e3f4ea;   --ok-dot: #22a35a;
  --wait: #9a5b00; --wait-soft: #fbf0dc; --wait-dot: #e19a1f;
  --bad: #b42f2f;  --bad-soft: #fbe7e6;  --bad-dot: #e0483f;
  --off: #5d5770;  --off-soft: #ecebf2;  --off-dot: #a5a0b5;
  /* shadows by role */
  --sh-1: 0 1px 2px rgb(30 20 70 / .05), 0 1px 1px rgb(30 20 70 / .03);                    /* resting card */
  --sh-2: 0 2px 4px rgb(30 20 70 / .05), 0 12px 28px -10px rgb(30 20 70 / .16);           /* hovered card, hero card */
  --sh-3: 0 4px 10px rgb(20 10 50 / .08), 0 28px 64px -16px rgb(20 10 50 / .30);          /* dialog, toast, popover */
  --sh-btn: inset 0 1px 0 rgb(255 255 255 / .18), 0 1px 2px rgb(40 20 90 / .28);
  --scrim: rgb(18 12 36 / .45);
  --nav-bg: rgb(245 245 249 / .82);
  --head-1: #6f9a4c; --head-2: #c58ad6; --head-3: #c99a5b; --head-4: #5f8fc9;               /* player heads */

  /* type (modern/notes.md section 2) */
  --font-display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --fs-hero: clamp(42px, 4.5vw + 22px, 80px);
  --fs-h2: clamp(30px, 2.2vw + 18px, 48px);
  --fs-h3: 20px; --lh-h3: 26px;
  --fs-lede: 18px; --lh-lede: 28px;

  /* spacing: 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96, 128 */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px; --s-8: 32px;
  --s-10: 40px; --s-12: 48px; --s-16: 64px; --s-20: 80px; --s-24: 96px; --s-32: 128px;
  --gutter: 16px;
  --wrap: 1200px;
  --column: 640px;    /* the single-column pages: claim flow, server sub-pages (704 px with gutters at 1280) */
  --prose: 560px;     /* reading measure: .prose text and the reading pages' column, about 65 characters at 17 px */
  --section: 64px;
  --head-gap: 32px;
  --nav-h: 64px;

  /* radii by role */
  --r-control: 12px;  /* buttons, inputs, selects, address rows */
  --r-card: 20px;     /* cards, panels */
  --r-inner: 14px;    /* rows and tiles inside a card, toast */
  --r-dialog: 24px;   /* dialog, sheet */
  --r-pill: 999px;    /* chips, status pills, segmented */

  /* motion */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --t-fast: .15s;
  --t-med: .24s;
}
@media (min-width: 768px) { :root { --gutter: 24px; --fs-h3: 24px; --lh-h3: 30px; --fs-lede: 20px; --lh-lede: 30px; } }
@media (min-width: 1280px) { :root { --gutter: 32px; } }
@media (min-width: 900px) { :root { --section: 96px; --head-gap: 48px; } }


/* ================================================================ base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--nav-h) + 16px); }
body { margin: 0; background: var(--bg); color: var(--fg-1); font: 400 16px/26px var(--font-body);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: hidden; }
img, svg, picture { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, h4, p, ul, ol, dl, dd, figure { margin: 0; }
ul[class], ol[class] { list-style: none; padding: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: inherit; }
code, kbd, .mono { font-family: var(--font-mono); font-weight: 500; }
::selection { background: var(--accent-soft); color: var(--fg-1); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
[hidden] { display: none !important; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip { position: absolute; left: 12px; top: -80px; z-index: 100; padding: 12px 16px; border-radius: var(--r-control);
  background: var(--fg-1); color: var(--bg); font-weight: 550; text-decoration: none; }
.skip:focus { top: 12px; }

/* ================================================================ type */
.t-hero { font: 700 var(--fs-hero)/.98 var(--font-display); letter-spacing: -.035em; text-wrap: balance; }
.t-h2 { font: 650 var(--fs-h2)/1.05 var(--font-display); letter-spacing: -.025em; text-wrap: balance; }
.t-h3 { font: 600 var(--fs-h3)/var(--lh-h3) var(--font-display); letter-spacing: -.01em; }
.t-h4 { font: 600 18px/26px var(--font-body); letter-spacing: -.005em; }
/* No heading ends on one word; running text avoids a lone last word where the browser can. */
.t-h3, .t-h4, .card-title, .prose h2, .prose h3, .server-name { text-wrap: balance; }
p, li, .faq-a { text-wrap: pretty; }
/* A question in a FAQ balances its lines (no one-word orphan under a long first line). */
summary { text-wrap: balance; }
.t-lede { font: 400 var(--fs-lede)/var(--lh-lede) var(--font-body); color: var(--fg-2); }
.t-body { font: 400 16px/26px var(--font-body); }
.t-small { font: 400 14px/20px var(--font-body); color: var(--fg-3); }
.t-eyebrow { font: 500 12px/16px var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); }
.t-mono { font: 500 14px/20px var(--font-mono); }
.t-muted { color: var(--fg-3); }
.t-accent { color: var(--accent-text); }
.t-hero .t-accent { display: block; }   /* the accent half of a hero headline always starts its own line (P-01, P-40) */
@media (max-width: 359px) { :root { --fs-hero: 36px; } .t-hero .nowrap { white-space: normal; } }   /* 320 px: "para todo mundo." fits */
.nowrap { white-space: nowrap; }
.prose { max-width: var(--prose); font: 400 17px/28px var(--font-body); }
.prose > * + * { margin-top: 16px; }
.prose h2 { margin-top: 48px; font: 650 28px/34px var(--font-display); letter-spacing: -.02em; }
.prose h3 { margin-top: 32px; font: 600 20px/26px var(--font-display); }
.prose ul, .prose ol { padding-left: 22px; }
.prose li + li { margin-top: 6px; }
.prose a, .link { color: var(--accent-text); text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  transition: text-decoration-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); border-radius: 2px; }
.prose a:hover, .link:hover { text-decoration-color: currentColor; }
.link-quiet { color: inherit; text-decoration: underline; text-decoration-color: var(--line-2); text-underline-offset: 3px; }
.link-quiet:hover { text-decoration-color: currentColor; }
button.link { border: 0; background: none; padding-inline: 0; font: inherit; }   /* a copy action set as a link (P-20 Next steps) */
/* A text link that stands on its own line or beside a short sentence ("Already have a server? Sign in", a breadcrumb,
   "Get Minecraft") gets a 44 px tall target without moving the line: padding out, the same margin back in. Links inside
   running prose (legal text, guides, FAQ answers) keep the plain inline box. */
:is(.link, .link-quiet, .footer-fine-row a):not(.prose *, .faq-a *) { display: inline-block; padding-block: 13px; margin-block: -13px; }
.arrow { font-family: var(--font-body); }

/* ================================================================ layout */
.wrap { width: 100%; max-width: calc(var(--wrap) + 2 * var(--gutter)); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-prose { max-width: calc(var(--column) + 2 * var(--gutter)); }
/* Reading pages (guides, the explainer, legal: an <article> of wrap-prose blocks) narrow to the reading measure. */
article .wrap-prose { max-width: calc(var(--prose) + 2 * var(--gutter)); }
.section { padding-block: var(--section); }
.section-alt { background: var(--bg-2); }
.section-head { max-width: 720px; margin-bottom: var(--head-gap); display: grid; gap: 12px; }
.section-head .t-lede { margin-top: 4px; }
/* Page head: the H1 of a page's first section sits at one distance below the nav (section padding + 40 px) whether an
   eyebrow, a breadcrumb or a back chip precedes it. The element before the H1 sits at the foot of one 28 px slot (a
   taller back chip grows upward into the section padding and keeps its 44 px target); with nothing before it the H1
   keeps the slot empty. A rule on
   the existing structure (first section's .section-head or .stack holding the H1), so no page markup changes; a new page
   can also say it outright with class="page-head" on the element that holds the H1. */
:is(.page-head, :is(main > section:first-child, main > article:first-child) :is(.section-head, .stack):not(.server-head *):has(> h1)) {
  --slot: 28px; --slot-gap: 12px; row-gap: var(--slot-gap); }
:is(.page-head, :is(main > section:first-child, main > article:first-child) :is(.section-head, .stack):not(.server-head *):has(> h1)) > :first-child:has(+ h1) {
  height: var(--slot); margin: 0; align-content: unsafe end; }
:is(.page-head, :is(main > section:first-child, main > article:first-child) :is(.section-head, .stack):not(.server-head *):has(> h1)) > h1:first-child {
  margin-top: calc(var(--slot) + var(--slot-gap)); }
/* A form-first page (Claim): the H1 drops the empty page-head slot and the section starts 24 px under the nav, so the
   primary button stays in the first screen at 375 x 812. */
.section-form { padding-top: 24px; }
.section-form .section-head > #page-title { margin-top: 0; }
.stack { display: grid; gap: var(--stack, 16px); align-content: start; }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cluster, 12px); }
.grid-2, .grid-3, .grid-4 { display: grid; gap: 16px; }
/* A card in a two-column grid is as tall as its own content, never stretched to its neighbour's height (P-20's join card
   was 575 px of blank white beside the steps column at 1280). */
.grid-2 { align-items: start; }
@media (min-width: 768px) { .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; } }
/* grid-4 from 900 px: up to four cells a row, never narrower than 160 px ("Active servers (3 h+)" on one line), so a narrow
   column holds three or two a row instead of four 130 px cells. */
@media (min-width: 900px) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
  .grid-4 { grid-template-columns: repeat(auto-fit, minmax(max(160px, calc((100% - 3 * 24px) / 4)), 1fr)); gap: 24px; } }
@media (min-width: 600px) and (max-width: 899px) { .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* A divider between two parts merged into one card: a 1 px hairline with 16 px either side. */
.divider { height: 0; margin-block: var(--s-4); border: 0; border-top: 1px solid var(--line); }
/* Captions inside reading text: 14 px lines held to about 62 characters (a 560 px prose column ran them to about 80). */
:is(.prose, .card-text) .t-small { max-width: 62ch; }
/* Field hints and callouts are held to the same 62-character line in a wide card or column. */
.field-hint, .callout { max-width: 62ch; }
/* Opt-in (class on a .grid-2 inside an <article>): from 1024 px the grid leaves the 560 px reading column for the full wrap
   width, centred on the page (P-32 B's "What we record" / "What we never record" cards). Below 1024 it stays in the column. */
@media (min-width: 1024px) {
  article .grid-2.grid-wide { --wide: min(var(--wrap), calc(100vw - 2 * var(--gutter)));
    width: var(--wide); margin-inline: calc((100% - var(--wide)) / 2); }
}

/* ================================================================ button
   Heights: 36 small (44 hit area), 44 default, 52 large, 56 hero. One radius for every control (12). */
.btn { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; padding: 0 18px; border: 1px solid transparent; border-radius: var(--r-control);
  font: 550 15px/1.1 var(--font-body); letter-spacing: -.005em; text-align: center; text-decoration: none; white-space: nowrap;
  -webkit-tap-highlight-color: transparent; user-select: none;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform .08s var(--ease); }
.btn:active:not(:disabled):not([aria-disabled="true"]) { transform: translateY(1px); }
.btn svg { width: 18px; height: 18px; flex: none; }
.btn-primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent-edge); box-shadow: var(--sh-btn); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-press); }
.btn-secondary { background: var(--surface); color: var(--fg-1); border-color: var(--line-2); box-shadow: var(--sh-1); }
.btn-secondary:hover { border-color: var(--control); background: var(--surface); }
.btn-secondary:active { background: var(--surface-2); }
.btn-ghost { background: transparent; color: var(--fg-1); }
.btn-ghost:hover { background: var(--wash); }
.btn-ghost:active { background: var(--wash-2); }
.btn-danger { background: var(--bad); color: #fff; border-color: transparent; box-shadow: var(--sh-btn); }
.btn-danger:hover { filter: brightness(.94); }
.btn-sm { min-height: 36px; padding: 0 14px; font-size: 14px; border-radius: 10px; }
.btn-sm::after { content: ""; position: absolute; inset: -4px; } /* 44 px hit area around a 36 px button */
.btn-lg { min-height: 52px; padding: 0 22px; font-size: 16px; }
.btn-xl { min-height: 56px; padding: 0 28px; font-size: 17px; border-radius: 14px; }
.btn-block { display: flex; width: 100%; white-space: normal; } /* a full-width label wraps instead of widening the page */
.btn-icon { min-width: 44px; padding: 0; }
.btn-icon.btn-sm { min-width: 36px; }
.btn:disabled, .btn[aria-disabled="true"] { cursor: not-allowed; background: var(--surface-3); color: var(--fg-4);
  border-color: transparent; box-shadow: none; }
.btn[aria-busy="true"] { cursor: progress; }
.btn[aria-busy="true"]::before { content: ""; width: 16px; height: 16px; border-radius: 50%; border: 2px solid currentColor;
  border-right-color: transparent; animation: spin .7s linear infinite; }
.btn.is-done { background: var(--ok-soft); color: var(--ok); border-color: transparent; box-shadow: none; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ================================================================ form fields */
.field { display: grid; gap: 6px; }
.field-label { font: 550 14px/20px var(--font-body); color: var(--fg-1); }
.field-label .opt { font-weight: 400; color: var(--fg-3); margin-left: 6px; }
.field-hint { font: 400 14px/20px var(--font-body); color: var(--fg-3); }
.field-error { display: flex; gap: 6px; align-items: flex-start; font: 500 14px/20px var(--font-body); color: var(--bad); }
.field-error::before { content: "!"; flex: none; display: grid; place-items: center; width: 18px; height: 18px; margin-top: 1px;
  border-radius: 50%; background: var(--bad); color: var(--surface); font: 700 12px/1 var(--font-body); }
.field-ok { font: 500 14px/20px var(--font-body); color: var(--ok); }
.input { width: 100%; min-height: 48px; padding: 0 14px; border: 1px solid var(--control); border-radius: var(--r-control);
  background: var(--surface); color: var(--fg-1); font: 400 16px/24px var(--font-body); /* 16 px: no zoom on iPhone */
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); appearance: none; }
textarea.input { min-height: 112px; padding: 12px 14px; resize: vertical; }
.input::placeholder { color: var(--fg-4); }
.input:hover { border-color: var(--fg-3); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
.input[aria-invalid="true"] { border-color: var(--bad); }
.input[aria-invalid="true"]:focus { box-shadow: 0 0 0 4px color-mix(in srgb, var(--bad) 22%, transparent); }
.input:disabled { background: var(--surface-3); color: var(--fg-3); border-color: var(--line-2); cursor: not-allowed; }
.input[readonly] { background: var(--surface-2); }
/* A native file field in the 48 px box: the browser's own "Choose file" button sits centred as a 32 px pill, not top-left. */
.input[type="file"] { padding: 7px; font: 400 15px/32px var(--font-body); color: var(--fg-2); cursor: pointer; }
.input[type="file"]::file-selector-button { min-height: 32px; margin: 0 12px 0 0; padding: 0 12px; border: 1px solid var(--control);
  border-radius: 8px; background: var(--surface-2); color: var(--fg-1); font: 550 14px/1 var(--font-body); cursor: pointer; }
.input-mono { font-family: var(--font-mono); font-weight: 500; font-size: 15px; }
/* An input with a fixed part after it: label + ".play.shulkerboxes.com". */
.affix { display: flex; align-items: stretch; border: 1px solid var(--control); border-radius: var(--r-control); background: var(--surface);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); overflow: hidden; }
.affix:hover { border-color: var(--fg-3); }
.affix:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
.affix .input { border: 0; box-shadow: none; min-width: 0; }
.affix-text { display: flex; align-items: center; padding: 0 14px; background: var(--surface-2); color: var(--fg-3);
  border-left: 1px solid var(--line); font: 500 14px/20px var(--font-mono); white-space: nowrap; }
/* 320 to 479 px: the 22-character ".play.shulkerboxes.com" left the input 25 to 77 px in a 238 to 311 px card ("anas-w" at
   375, phone read 10). On a phone a suffix goes under the input as its own line, breaking at the dots if it must, and the
   input takes the full width. A prefix (the console's "/") stays beside its input. */
@media (max-width: 479px) {
  .affix:has(> .input + .affix-text) { flex-wrap: wrap; }
  .affix:has(> .input + .affix-text) > .input { flex: 1 1 100%; }
  .affix > .input + .affix-text { flex: 1 1 100%; min-height: 36px; border-left: 0; border-top: 1px solid var(--line); white-space: normal; overflow-wrap: anywhere; }
}
.select { position: relative; }
.select select { width: 100%; min-height: 48px; padding: 0 40px 0 14px; border: 1px solid var(--control); border-radius: var(--r-control);
  background: var(--surface); color: var(--fg-1); font: 400 16px/24px var(--font-body); appearance: none; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.select select:hover { border-color: var(--fg-3); }
.select select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
.select select:disabled { background: var(--surface-3); color: var(--fg-3); cursor: not-allowed; }
.select::after { content: ""; position: absolute; right: 18px; top: 50%; width: 8px; height: 8px; margin-top: -6px; pointer-events: none;
  border-right: 2px solid var(--fg-3); border-bottom: 2px solid var(--fg-3); transform: rotate(45deg); }
/* Checkbox and radio rows: the whole row is the 44 px target. */
.check { display: flex; align-items: flex-start; gap: 12px; min-height: 44px; padding: 10px 0; cursor: pointer; font: 400 16px/24px var(--font-body); }
.check input { flex: none; width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--accent); cursor: pointer; }
/* Choice tiles: a radio as a card (region, world). */
.choices { display: grid; gap: 12px; border: 0; margin: 0; padding: 0; min-width: 0; }
@media (min-width: 600px) { .choices-2 { grid-template-columns: 1fr 1fr; } }
.choice { position: relative; display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; align-items: start; padding: 16px;
  border: 1px solid var(--line-2); border-radius: var(--r-inner); background: var(--surface); cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.choice:hover { border-color: var(--control); }
.choice input { grid-row: span 2; width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--accent); }
.choice-title { font: 550 16px/24px var(--font-body); }
.choice-text { grid-column: 2; font: 400 14px/20px var(--font-body); color: var(--fg-3); }
.choice:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.choice:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.choice:has(input:disabled) { opacity: .55; cursor: not-allowed; }
.form { display: grid; gap: 20px; }
.form-actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* ================================================================ card */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); box-shadow: var(--sh-1); padding: 24px; }
.card-lg { padding: 32px; }
@media (max-width: 599px) { .card-lg { padding: 24px; } }
/* A long form keeps its submit on screen at every width (P-13's Create server sat two screens down on a laptop; P-22's
   unsaved-changes bar three): the button bar sticks to the bottom of the screen while the form is in view, edge to edge
   inside the card (the negative margin is the card's padding). A bar with a sentence and actions reads as one row from
   900 px: the sentence left, the buttons right. */
.form-submit { position: sticky; bottom: 0; z-index: 2; display: grid; gap: 8px; margin: 0 -32px; padding: 12px 32px calc(12px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); background: var(--surface); }
@media (max-width: 599px) { .form-submit { margin: 0 -24px; padding-inline: 24px; } }
@media (min-width: 900px) { .form-submit:has(> .form-actions) { grid-template-columns: minmax(0, 1fr) auto; align-items: center; } }
/* The bar never covers the field it is about: while a bar shows, the page's scroll padding at the bottom is the bar's
   height plus 16 px, so Tab, focus, a hint link or an anchor stops a field above the bar, not under it. --submit-h is the
   tallest bar at that width (measured: 77 px for a one-button bar, 103 px for a phone's sentence over two buttons below
   900 px, 69 px as one row from 900). A sticky bar keeps its own room in the flow, so the form after it (P-13's "How did
   you find us?") needs no extra padding; a bar that is position: fixed (the settings block from 1024 px) does, below. */
:root { --submit-h: 104px; }
@media (min-width: 900px) { :root { --submit-h: 80px; } }
html:has(.form-submit:not([hidden])) { scroll-padding-bottom: calc(var(--submit-h) + var(--s-4)); }
.card-raised { box-shadow: var(--sh-2); }
.card-flat { box-shadow: none; background: var(--surface-2); }
a.card { display: block; color: inherit; text-decoration: none;
  transition: box-shadow var(--t-med) var(--ease), border-color var(--t-med) var(--ease), transform var(--t-med) var(--ease); }
a.card:hover { box-shadow: var(--sh-2); border-color: var(--line-2); transform: translateY(-2px); }
.card-title { font: 600 var(--fs-h3)/var(--lh-h3) var(--font-display); letter-spacing: -.01em; }
.card-text { margin-top: 8px; color: var(--fg-2); }
.card-foot { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }

/* ================================================================ chip and status light */
.chip { display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 10px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: var(--surface-2); color: var(--fg-2); font: 500 13px/1 var(--font-body); white-space: nowrap; }
.chip svg { width: 14px; height: 14px; }
.chip-accent { background: var(--accent-soft); border-color: transparent; color: var(--accent-soft-ink); }
.chip-ok { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
.chip-wait { background: var(--wait-soft); border-color: transparent; color: var(--wait); }
.chip-bad { background: var(--bad-soft); border-color: transparent; color: var(--bad); }
.chip-mono { font-family: var(--font-mono); font-size: 12px; letter-spacing: .02em; }
button.chip { position: relative; min-height: 36px; padding: 0 14px; cursor: pointer; transition: background-color var(--t-fast) var(--ease); }
button.chip::after { content: ""; position: absolute; inset: -4px 0; }
button.chip:hover { background: var(--wash-2); }
button.chip[aria-pressed="true"] { background: var(--fg-1); color: var(--bg); border-color: transparent; }
.status { display: inline-flex; align-items: center; gap: 8px; font: 550 14px/20px var(--font-body); color: var(--fg-1); white-space: nowrap; }
.status::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--off-dot); }
.status[data-tone="ok"]::before { background: var(--ok-dot); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok-dot) 22%, transparent); }
.status[data-tone="wait"]::before { background: var(--wait-dot); animation: pulse 1.4s ease-in-out infinite; }
.status[data-tone="bad"]::before { background: var(--bad-dot); }
.status[data-tone="info"]::before { background: var(--accent); }
.status-pill { min-height: 28px; padding: 0 12px 0 10px; border-radius: var(--r-pill); background: var(--off-soft); color: var(--off); font-size: 13px; }
.status-pill[data-tone="ok"] { background: var(--ok-soft); color: var(--ok); }
.status-pill[data-tone="wait"] { background: var(--wait-soft); color: var(--wait); }
.status-pill[data-tone="bad"] { background: var(--bad-soft); color: var(--bad); }
.status-pill[data-tone="info"] { background: var(--accent-soft); color: var(--accent-soft-ink); }
.status-float { background: rgb(255 255 255 / .92); color: #16131f; box-shadow: 0 1px 3px rgb(0 0 0 / .18); backdrop-filter: blur(6px); }
@keyframes pulse { 50% { opacity: .35; } }

/* ================================================================ callout, empty state, stat, meter, skeleton */
/* Block flow with the dot positioned, so a sentence with a link or bold word inside stays one paragraph (a grid made each
   inline element its own column). */
.callout { position: relative; display: block; padding: 14px 16px 14px 36px; border-radius: var(--r-inner);
  background: var(--accent-soft); color: var(--fg-1); font: 400 15px/22px var(--font-body); }
.callout::before { content: ""; position: absolute; left: 16px; top: 21px; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.callout[data-tone="ok"] { background: var(--ok-soft); } .callout[data-tone="ok"]::before { background: var(--ok-dot); }
.callout[data-tone="wait"] { background: var(--wait-soft); } .callout[data-tone="wait"]::before { background: var(--wait-dot); }
.callout[data-tone="bad"] { background: var(--bad-soft); } .callout[data-tone="bad"]::before { background: var(--bad-dot); }
.callout strong { font-weight: 600; }
.empty { display: grid; justify-items: center; gap: 8px; padding: 48px 24px; text-align: center; border: 1px dashed var(--line-2);
  border-radius: var(--r-card); background: var(--surface-2); }
.empty-icon { width: 48px; height: 48px; margin-bottom: 8px; color: var(--fg-4); }
.empty .btn { margin-top: 12px; }
.stat { display: grid; gap: 4px; }
.stat-value { font: 650 36px/40px var(--font-display); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat-note { font: 400 14px/20px var(--font-body); color: var(--fg-3); }
.meter { height: 8px; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; }
.meter > span { display: block; height: 100%; width: var(--value, 40%); border-radius: inherit; background: var(--accent);
  transition: width .6s var(--ease); }
/* The waiting bar: a 35% bar slides from off the left edge to off the right. The span stays the size of the box and a
   clip-path cuts the bar out of it, so nothing leaves the box (no scroll width at 375; a translated bar added ~100 px). */
@property --meter-x { syntax: "<number>"; inherits: false; initial-value: 0; }   /* at rest (reduced motion): the bar at the left, as before */
.meter-indeterminate > span { width: 100%; animation: slide 1.4s var(--ease) infinite;
  clip-path: inset(0 calc(max(0, 0.65 - var(--meter-x)) * 100%) 0 calc(max(0, var(--meter-x)) * 100%) round var(--r-pill)); }
@keyframes slide { from { --meter-x: -0.35; } to { --meter-x: 1.015; } }
.meter-0 { --value: 0%; } .meter-2 { --value: 2%; } .meter-5 { --value: 5%; } .meter-6 { --value: 6%; } .meter-24 { --value: 24%; }
.meter-40 { --value: 40%; } .meter-60 { --value: 60%; }
/* A meter over "12 of 50 points" fills from zero (24%; 64 of 1,000 is 6%): the label states a share of the whole, and the
   5% fill from the tier floor read as wrong under it (phone read 10). The points bar under a server's name still fills
   from the tier floor beside "12 points · 38 to Pro". */

/* ================================================================ points bar (P-20) */
/* One slim row under a server's name: tier and points, the meter (filled from the tier floor) and "Read more". The whole
   bar is one button that opens the points dialog. Below 600 px the meter takes its own line under the words. */
.points-bar { display: grid; grid-template-columns: auto minmax(64px, 1fr) auto; align-items: center; gap: 6px 12px;
  width: min(100%, 480px); min-height: 44px; padding: 6px 6px 6px 14px; border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--surface); color: var(--fg-1); font: 500 14px/20px var(--font-body); text-align: left; cursor: pointer; }
.points-bar:hover { border-color: var(--line-2); background: var(--surface-2); }
.points-bar .meter { height: 6px; }
.points-bar-more { padding: 6px 8px; color: var(--accent-text); text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px; white-space: nowrap; }
@media (max-width: 599px) {
  .points-bar { grid-template-columns: 1fr auto; border-radius: var(--r-inner); padding: 6px 6px 10px 14px; }
  .points-bar .meter { grid-column: 1 / -1; grid-row: 2; margin-right: 8px; }
}
/* P-24 Invites and upgrade: the three paid tier cards (the home's .tier-card, variants/P-06-A/variant.css) in one row
   from 1024 px. The single column opens to the wrap width there; the head and the invites card keep the column. */
@media (min-width: 1024px) {
  .wrap-prose:has(> .tier-band) { max-width: calc(var(--wrap) + 2 * var(--gutter)); }
  .wrap-prose:has(> .tier-band) > :not(.tier-band) { max-width: var(--column); }
  .tier-cards.tier-cards-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.skeleton { display: block; height: 14px; border-radius: 6px;
  background: linear-gradient(90deg, var(--surface-3) 0%, var(--surface-2) 50%, var(--surface-3) 100%) 0 0 / 200% 100%;
  animation: shimmer 1.6s linear infinite; }
.skeleton-title { height: 22px; width: 60%; }
.skeleton-line { width: 100%; }
.skeleton-short { width: 40%; }
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.spinner { display: inline-block; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--line-2);
  border-top-color: var(--accent); animation: spin .8s linear infinite; vertical-align: middle; }

/* ================================================================ steps (how it works) and progress steps (building) */
.steps { display: grid; gap: 16px; counter-reset: step; }
@media (min-width: 900px) { .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; } }
.step { position: relative; display: grid; gap: 16px; align-content: start; padding: 24px; border: 1px solid var(--line);
  border-radius: var(--r-card); background: var(--surface); box-shadow: var(--sh-1); counter-increment: step;
  font: 500 18px/28px var(--font-body); color: var(--fg-1); }
.step::before { content: "0" counter(step); display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px;
  background: var(--accent-soft); color: var(--accent-soft-ink); font: 500 14px/1 var(--font-mono); }
.progress-steps { display: grid; gap: 4px; }
.progress-steps li { display: grid; grid-template-columns: 28px 1fr; gap: 12px; align-items: center; min-height: 44px; color: var(--fg-3); }
.progress-steps li::before { content: ""; justify-self: center; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--line-2); }
.progress-steps li[data-state="done"] { color: var(--fg-2); }
.progress-steps li[data-state="done"]::before { width: 22px; height: 22px; border: 0; background: var(--ok-soft); color: var(--ok);
  content: "✓"; display: grid; place-items: center; font: 700 13px/1 var(--font-body); }
.progress-steps li[data-state="current"] { color: var(--fg-1); font-weight: 550; }
.progress-steps li[data-state="current"]::before { width: 18px; height: 18px; border-color: var(--line-2); border-top-color: var(--accent);
  animation: spin .8s linear infinite; }
/* A rung with a line under its name (P-24's tier ladder: the tier, then its perks): the dot sits on the name's 44 px line. */
.progress-steps li:has(> .stack) { align-items: start; }
.progress-steps li > .stack { gap: 0; padding-bottom: 8px; }
.progress-steps li > .stack > .cluster:first-child { min-height: 44px; }
.progress-steps li:has(> .stack)::before { margin-top: 11px; }
.progress-steps li[data-state="current"]:has(> .stack)::before { margin-top: 13px; }
.progress-steps li[data-state="todo"]:has(> .stack)::before { margin-top: 17px; }

/* ================================================================ FAQ */
.faq { border-top: 1px solid var(--line); max-width: 860px; }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary { display: flex; align-items: center; justify-content: space-between; gap: 24px; min-height: 64px; padding: 16px 0;
  list-style: none; cursor: pointer; font: 600 19px/26px var(--font-display); letter-spacing: -.01em; border-radius: 4px; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ""; flex: none; width: 28px; height: 28px; border-radius: 50%; background:
  linear-gradient(var(--fg-2), var(--fg-2)) center / 12px 2px no-repeat,
  linear-gradient(var(--fg-2), var(--fg-2)) center / 2px 12px no-repeat, var(--surface-3);
  transition: transform var(--t-med) var(--ease), background-color var(--t-fast); }
.faq summary:hover::after { background-color: var(--line-2); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-a { padding: 0 52px 24px 0; color: var(--fg-2); max-width: calc(520px + 52px); }   /* 520 px of text: at most about 75 characters a line at 16 px */

/* ================================================================ address row, Add to Minecraft, QR */
.addr-label { margin-bottom: 8px; }
/* One address: edition over the host on the left, Copy on the right. Hosts carry <wbr> after each dot so a phone breaks them there. */
.addr { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; min-height: 60px;
  padding: 8px 8px 8px 14px; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); }
.addr + .addr { margin-top: 8px; }
.addr-main { display: grid; gap: 2px; min-width: 0; }
.addr-ed { font: 500 12px/16px var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); }
.addr-host { font: 500 15px/22px var(--font-mono); color: var(--fg-1); min-width: 0; }
/* The Bedrock port sits on its own line under the host with its label ("Port: 19132"), so at 375 it never wraps into
   the host and reads as part of the address (stranger run 7). */
.addr-port { font: 500 13px/18px var(--font-mono); color: var(--fg-3); white-space: nowrap; }
.addr-actions { display: flex; gap: 6px; }
/* Two actions beside a long link (Copy link + QR) leave the link a few characters a line on a phone: stack them under it. */
@media (max-width: 479px) {
  .addr:has(.addr-actions > :nth-child(2)) { grid-template-columns: minmax(0, 1fr); padding: 12px; }
}
.addr-add { margin-top: 12px; }
.addr-note { margin-top: 8px; font: 400 13px/18px var(--font-body); color: var(--fg-3); }
.qr { display: grid; place-items: center; gap: 8px; width: 148px; padding: 14px; border: 1px dashed var(--line-2); border-radius: var(--r-inner);
  background: var(--surface); color: var(--fg-1); text-align: center; }
.qr svg { width: 100%; height: auto; }
.qr-caption { font: 500 12px/16px var(--font-mono); letter-spacing: .06em; text-transform: uppercase; color: var(--fg-3); }

/* ================================================================ player heads */
.heads { display: inline-flex; align-items: center; }
.heads i { width: 26px; height: 26px; border-radius: 7px; border: 2px solid var(--surface); background: var(--head-1);
  box-shadow: inset 0 -6px 0 rgb(0 0 0 / .14); }
.heads i + i { margin-left: -7px; }
.heads i:nth-child(2) { background: var(--head-2); } .heads i:nth-child(3) { background: var(--head-3); } .heads i:nth-child(4) { background: var(--head-4); }
.heads-off i { filter: grayscale(1); opacity: .55; }
.heads-lg i { width: 34px; height: 34px; border-radius: 9px; }

/* ================================================================ server card */
.server { overflow: hidden; padding: 0; }
.server-media { position: relative; aspect-ratio: 2 / 1; background: var(--surface-3); }
.server-media img { width: 100%; height: 100%; object-fit: cover; }
.server-media .status-pill { position: absolute; left: 14px; top: 14px; }
.server-body { padding: 20px; display: grid; gap: 16px; }
@media (min-width: 600px) { .server-body { padding: 24px; } }
.server-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.server-name { font: 650 22px/28px var(--font-display); letter-spacing: -.015em; }
.server-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.server-players { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 16px; border-top: 1px solid var(--line); }
.server-caption { padding: 12px 20px; border-top: 1px solid var(--line); background: var(--surface-2); font: 500 12px/16px var(--font-mono);
  letter-spacing: .04em; color: var(--fg-3); }

/* ================================================================ tabs */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab { position: relative; min-height: 44px; padding: 0 14px; border: 0; background: none; color: var(--fg-3);
  font: 550 15px/1 var(--font-body); white-space: nowrap; border-radius: 8px 8px 0 0; transition: color var(--t-fast) var(--ease); }
.tab:hover { color: var(--fg-1); }
.tab[aria-selected="true"] { color: var(--fg-1); }
.tab[aria-selected="true"]::after { content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px; border-radius: 2px; background: var(--accent); }
.tab-panel { padding-top: 24px; }
/* Below 400 px the tabs wrap into two rows, like a .cluster, instead of scrolling under a fade: P-41's four tabs
   (Overview · Links · Players · Money; pt-BR Visão geral · Links · Jogadores · Dinheiro) need 376 px and a 375 phone has 343
   ("Dinhe…" ended under the fade, read at round 6). Every tab is on screen, so no fade. */
@media (max-width: 399px) {
  .tabs { flex-wrap: wrap; overflow: visible; }
  .tab { padding: 0 9px; } /* round 18: four tabs fit 343 px on one row (pt-BR "Dinheiro" fell to a second row) */
  .tabs[data-more] { -webkit-mask-image: none; mask-image: none; }
}
.tab-panel:focus-visible { outline-offset: 4px; }
/* A field label with a Skip button beside it: the label text wraps, the button stays on the first row (pt-BR P-13 at 375). */
.field > .cluster:has(> .field-label + .btn) { flex-wrap: nowrap; justify-content: space-between; }
.field > .cluster:has(> .field-label + .btn) > .field-label { flex: 1 1 auto; min-width: 0; }
/* A row of section buttons that never wraps (server links, settings sections): it scrolls sideways on a phone.
   v2.mjs sets data-more="end|start|both" on .tabs and .scroll-row while part of the row is out of view, and the hidden
   side fades out, so the cut last button reads as "more this way". */
.scroll-row { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; }
.scroll-row::-webkit-scrollbar { display: none; }
.scroll-row > * { flex: none; scroll-snap-align: start; }
/* From 1024 px the row wraps into lines instead of scrolling: every section button is on screen (P-22's eight buttons were
   clipped at "Dat…" in a 640 px strip). No fade, since nothing is out of view. */
@media (min-width: 1024px) {
  .scroll-row { flex-wrap: wrap; overflow: visible; scroll-snap-type: none; }
  .scroll-row[data-more] { -webkit-mask-image: none; mask-image: none; }
}
[data-more="end"] { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent); }
[data-more="start"] { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent); }
[data-more="both"] { -webkit-mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent); mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent); }
/* Segmented: two to four options in a pill (Java / Bedrock). */
.segmented { display: inline-flex; padding: 4px; gap: 2px; border-radius: var(--r-pill); background: var(--surface-3); }
.segmented button { min-height: 36px; padding: 0 16px; border: 0; border-radius: var(--r-pill); background: transparent; color: var(--fg-2);
  font: 550 14px/1 var(--font-body); position: relative; transition: background-color var(--t-fast), color var(--t-fast); }
.segmented button::after { content: ""; position: absolute; inset: -4px 0; }
.segmented button[aria-pressed="true"], .segmented button[aria-selected="true"] { background: var(--surface); color: var(--fg-1); box-shadow: var(--sh-1); }

/* ================================================================ table, cards on phones */
.table-wrap { border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface); box-shadow: var(--sh-1); overflow: hidden; }
.table { width: 100%; border-collapse: collapse; font: 400 15px/22px var(--font-body); }
.table th { padding: 12px 16px; text-align: left; font: 500 12px/16px var(--font-mono); letter-spacing: .06em; text-transform: uppercase;
  color: var(--fg-3); background: var(--surface-2); border-bottom: 1px solid var(--line); }
.table td { padding: 14px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--surface-2); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 719px) {
  .table-wrap { border: 0; background: none; box-shadow: none; overflow: visible; border-radius: 0; }
  .table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table, .table tbody, .table tr, .table td { display: block; }
  .table tr { margin-bottom: 12px; padding: 8px 16px; border: 1px solid var(--line); border-radius: var(--r-inner);
    background: var(--surface); box-shadow: var(--sh-1); }
  /* minmax(0, 1fr) and a chip that may wrap: a long added name ("Waiting for Sample_Friend16 to join") widened the card
     past the page's gutter at 375 (phone read 10). */
  .table td { display: grid; grid-template-columns: minmax(96px, 38%) minmax(0, 1fr); gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
  .table td .chip { white-space: normal; max-width: 100%; padding-block: 5px; line-height: 18px; }
  .table td > * { justify-self: start; }
  .table td::before { content: attr(data-label); font: 500 12px/22px var(--font-mono); letter-spacing: .04em; text-transform: uppercase; color: var(--fg-3); }
  .table tbody tr:hover td { background: none; }
  .table .num { text-align: left; }
  .table td:last-child { border-bottom: 0; }
  .table thead tr, .table thead th { display: block; padding: 0; } /* the hidden header takes no width */
}

/* ================================================================ toast */
.toasts { position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom)); z-index: 120; display: grid; gap: 8px;
  justify-items: center; width: max-content; max-width: calc(100vw - 32px); transform: translateX(-50%); pointer-events: none; }
.toast { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 12px 18px 12px 14px; border-radius: var(--r-inner);
  background: var(--fg-1); color: var(--bg); box-shadow: var(--sh-3); font: 500 15px/20px var(--font-body);
  animation: toast-in .2s var(--ease); pointer-events: auto; }
.toast::before { content: "✓"; display: grid; place-items: center; width: 22px; height: 22px; flex: none; border-radius: 50%;
  background: var(--ok-dot); color: #fff; font: 700 12px/1 var(--font-body); }
.toast[data-tone="bad"]::before { content: "!"; background: var(--bad-dot); }
.toast[data-tone="info"]::before { content: "i"; background: var(--accent); color: var(--on-accent); }
.toast.is-leaving { animation: toast-out .16s var(--ease) forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px) scale(.96); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(4px) scale(.98); } }

/* ================================================================ dialog and sheet (native <dialog>) */
.dialog { width: min(520px, calc(100vw - 32px)); max-height: calc(100dvh - 48px); padding: 0; border: 0; border-radius: var(--r-dialog);
  background: var(--surface); color: var(--fg-1); box-shadow: var(--sh-3); overflow: auto; }
.dialog::backdrop { background: var(--scrim); backdrop-filter: blur(2px); }
.dialog[open] { animation: dialog-in .22s var(--ease); }
.dialog[open]::backdrop { animation: fade-in .22s var(--ease); }
@keyframes dialog-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }
@keyframes fade-in { from { opacity: 0; } }
.dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 24px 24px 0; }
.dialog-title { font: 650 24px/30px var(--font-display); letter-spacing: -.015em; }
.dialog-body { padding: 12px 24px 24px; color: var(--fg-2); display: grid; gap: 16px; }
.dialog-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 12px; padding: 16px 24px 24px; border-top: 1px solid var(--line); }
.dialog-close { margin: -6px -10px 0 0; }
.dialog-close svg { width: 18px; height: 18px; }
/* On phones a dialog marked .sheet rises from the bottom, full width, thumb-reachable. */
@media (max-width: 599px) {
  .dialog.sheet { width: 100%; max-width: 100%; margin: auto 0 0; border-radius: var(--r-dialog) var(--r-dialog) 0 0;
    padding-bottom: env(safe-area-inset-bottom); max-height: 92dvh; }
  .dialog.sheet[open] { animation: sheet-in .28s var(--ease); }
  .dialog.sheet::before { content: ""; display: block; width: 40px; height: 4px; margin: 10px auto 0; border-radius: 4px; background: var(--line-2); }
  .dialog-foot { flex-direction: column-reverse; }
  .dialog-foot .btn { width: 100%; }
}
@keyframes sheet-in { from { transform: translateY(40px); opacity: .4; } }
/* A sheet holding a wide table (P-24 tiers): up to 880 px from 900 px, so no column breaks one word per line. */
@media (min-width: 900px) { .dialog.sheet-wide { width: min(880px, calc(100vw - 64px)); } }

/* ================================================================ nav */
.brand { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; color: var(--fg-1); text-decoration: none;
  font: 700 19px/1 var(--font-display); letter-spacing: -.02em; border-radius: 8px; }
.brand-mark { width: 28px; height: 28px; flex: none; }
.nav { position: sticky; top: 0; z-index: 50; background: var(--nav-bg); backdrop-filter: saturate(1.4) blur(16px);
  -webkit-backdrop-filter: saturate(1.4) blur(16px); border-bottom: 1px solid var(--line); }
.nav-row { display: flex; align-items: center; gap: 8px; height: var(--nav-h); }
.nav-links { display: none; align-items: center; gap: 2px; margin-left: 24px; }
.nav-link { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 10px; color: var(--fg-2);
  text-decoration: none; font: 500 15px/1 var(--font-body); transition: background-color var(--t-fast), color var(--t-fast); }
.nav-link:hover { background: var(--wash); color: var(--fg-1); }
.nav-link[aria-current="page"] { color: var(--fg-1); }
.nav-end { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav-lang, .nav-signout { display: none; }
@media (max-width: 359px) { .nav-account { display: none; } }   /* 320 px: the signed-in row overflowed; the menu carries "Your servers" */
@media (min-width: 360px) and (max-width: 374px) { .nav-account { padding-inline: 8px; } }   /* 360 px: pt-BR "Seus servidores" + Menu ran 7 px past the edge */
.nav-menu-btn svg { width: 22px; height: 22px; }
@media (min-width: 900px) {
  .nav-links { display: flex; }
  .nav-lang, .nav-signout { display: inline-flex; }
  .nav-menu-btn { display: none; }
}
.menu-list { display: grid; gap: 2px; margin: 0 -8px; }
.menu-list a { display: flex; align-items: center; min-height: 52px; padding: 0 12px; border-radius: 12px; color: var(--fg-1);
  text-decoration: none; font: 550 18px/1 var(--font-body); }
.menu-list a:hover { background: var(--wash); }
.menu-list hr { border: 0; border-top: 1px solid var(--line); margin: 8px 12px; }

/* ================================================================ footer */
.footer { background: var(--bg-2); border-top: 1px solid var(--line); padding: 64px 0 calc(32px + env(safe-area-inset-bottom)); color: var(--fg-2); }
.footer-grid { display: grid; gap: 40px; }
@media (min-width: 768px) { .footer-grid { grid-template-columns: 1.4fr repeat(3, 1fr); gap: 32px; } }
.footer-tag { margin-top: 12px; max-width: 280px; font: 400 15px/22px var(--font-body); color: var(--fg-3); }
.footer-col h2 { margin-bottom: 8px; font: 500 12px/16px var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3); }
.footer-col ul { display: grid; list-style: none; margin: 0; padding: 0; }
.footer-col a { display: inline-flex; align-items: center; min-height: 40px; overflow-wrap: anywhere; color: var(--fg-1); text-decoration: none; font: 400 15px/20px var(--font-body); }
.footer-col a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 767px) {
  .footer-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 32px 12px; /* the Help column holds the support address on one line at 390 */ }
  .footer-col a { min-height: 44px; }
  .footer-col a[href^="mailto"] { font-size: 13px; letter-spacing: -.01em; } /* support@shulkerboxes.com on one line in a 187 px column */
}
@media (min-width: 768px) { .footer-cols { display: contents; } }
.footer-fine { display: grid; gap: 8px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line);
  font: 400 13px/20px var(--font-body); color: var(--fg-3); }
.footer-fine a { color: inherit; }
.footer-fine-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 24px; }

/* ================================================================ home page */
.hero { padding: 40px 0 64px; }
@media (min-width: 900px) { .hero { padding: 72px 0 96px; } }
.hero-grid { display: grid; gap: 48px; align-items: center; }
@media (min-width: 1000px) { .hero-grid { grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr); gap: 64px; } }
.hero-copy { display: grid; gap: 24px; justify-items: start; }
.hero-lede { display: grid; gap: 4px; }
.hero-facts { display: grid; gap: 10px; margin-top: 4px; }
.hero-facts li { display: flex; align-items: flex-start; gap: 10px; font: 500 16px/24px var(--font-body); color: var(--fg-2); }
.hero-facts-lede li { font: 400 var(--fs-lede)/var(--lh-lede) var(--font-body); }   /* answers that stand in for the lede (P-02) */
.fact-icon { flex: none; width: 20px; height: 20px; margin-top: 2px; }
.fact-bg { fill: var(--accent-soft); }
.fact-check { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hero-act { display: grid; gap: 14px; justify-items: start; margin-top: 8px; }
.hero-act .t-small a, .hero-act .t-small button { color: var(--fg-1); }
.hero-card { width: 100%; max-width: 520px; justify-self: center; }
@media (min-width: 1000px) { .hero-card { justify-self: end; } }
.rise { animation: rise .7s var(--ease) both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
.idea { display: grid; gap: 32px; align-items: center; }
.idea + .idea { margin-top: 64px; }
@media (min-width: 900px) {
  .idea { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 80px; }
  .idea + .idea { margin-top: 96px; }
  .idea:nth-child(even) .idea-visual { order: -1; }
}
.idea-copy { display: grid; gap: 12px; max-width: 520px; }
.idea-copy .t-lede { color: var(--fg-2); }
.idea-visual { display: grid; place-items: center; min-height: 300px; padding: 40px 24px; border-radius: 28px; background: var(--bg-2);
  border: 1px solid var(--line); }
.section-alt .idea-visual { background: var(--bg); }
.vignette { width: 100%; max-width: 400px; display: grid; gap: 12px; }
.vrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; border-radius: var(--r-inner);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--sh-1); }
.vrow-who { display: flex; align-items: center; gap: 10px; font: 550 15px/20px var(--font-body); }
.vrow-dim { opacity: .62; }
.mc { width: 100%; max-width: 400px; padding: 18px; border-radius: 6px; background: #2b2b2f; color: #f2f2f2;
  box-shadow: inset 0 0 0 2px #0e0e10, inset 0 0 0 4px #4a4a50, var(--sh-2); font: 500 13px/18px var(--font-mono); }
.mc-title { text-align: center; margin-bottom: 14px; }
.mc-label { color: #a8a8ad; margin: 10px 0 6px; }
.mc-field { padding: 9px 10px; background: #000; border: 2px solid #a0a0a0; color: #fff; overflow-wrap: anywhere; }
.mc-btn { margin-top: 16px; padding: 9px; text-align: center; background: #6b6b70; box-shadow: inset 0 0 0 2px #1a1a1d, inset 2px 2px 0 2px #9a9a9f; }
.file-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px; }
.file-icon { width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent-soft-ink); }
.file-icon svg { width: 20px; height: 20px; }
.file-name { font: 500 14px/20px var(--font-mono); overflow-wrap: anywhere; }
.grow { display: grid; gap: 10px; }
.grow-scale { display: flex; justify-content: space-between; font: 500 12px/16px var(--font-mono); color: var(--fg-3); }
.grow .meter { height: 14px; }
.grow .meter > span { background: linear-gradient(90deg, var(--accent-soft) 0%, var(--accent) 100%); }
.grow-bars { display: flex; align-items: flex-end; gap: 8px; height: 96px; }
.grow-bars i { flex: 1; border-radius: 6px 6px 3px 3px; background: var(--accent); opacity: .25; }
.grow-bars i:nth-child(1) { height: 22%; } .grow-bars i:nth-child(2) { height: 34%; opacity: .35; } .grow-bars i:nth-child(3) { height: 48%; opacity: .5; }
.grow-bars i:nth-child(4) { height: 66%; opacity: .7; } .grow-bars i:nth-child(5) { height: 100%; opacity: 1; }
.cta-band { display: grid; gap: 24px; justify-items: start; padding: 40px 24px; border-radius: 28px; background: var(--accent-soft); }
@media (min-width: 900px) { .cta-band { grid-template-columns: 1fr auto; align-items: center; padding: 56px 64px; } }
.cta-band .t-h2 { max-width: 16ch; }

/* ================================================================ desktop layouts (1024 px and up; phones unchanged)
   Settings variants P-22 A and B (since 2026-10-14 P-22 itself uses the settings block below; any page whose groups block
   is [data-fb="groups"] after a .wrap-prose head): the
   head and the groups open to the wrap width and the cards flow down two balanced CSS columns (multicol, not a row grid:
   in a row grid a short card beside a tall one leaves up to 700 px blank). A card never splits; whatever is not a card
   (the sample line) spans both columns, so the last card (Delete server) stands alone after it, as on a phone.
   The unsaved-changes bar is position: fixed here, not sticky: sticky on a column-span box inside multicol is fine in
   Chrome but not something to rely on in Safari and Firefox (variants P-22 A/B RATIONALE), and fixed is the same in all
   three. It sits on the screen's bottom edge over the wrap width; the footer's 88 px foot room keeps its last line clear. */
@media (min-width: 1024px) {
  .wrap-prose:has(+ [data-fb="groups"]), [data-fb="groups"] { max-width: calc(var(--wrap) + 2 * var(--gutter)); }
  [data-fb="groups"] { display: block; columns: 2; column-gap: var(--s-6); padding-inline: var(--gutter); }
  [data-fb="groups"] > * { break-inside: avoid; }
  [data-fb="groups"] > * + * { margin-top: var(--s-6); }
  [data-fb="groups"] > :not(section) { column-span: all; }
  [data-fb="groups"] > .form-submit { position: fixed; z-index: 40; bottom: 0; inset-inline: max(0px, calc(50% - var(--wrap) / 2 - var(--gutter)));
    margin: 0; padding-inline: var(--gutter); border: 1px solid var(--line); border-bottom: 0;
    border-radius: var(--r-inner) var(--r-inner) 0 0; box-shadow: var(--sh-2); }
  [data-fb="groups"]:has(> .form-submit:not([hidden])) { padding-bottom: calc(var(--submit-h) + var(--s-4)); }
}
/* Contents rail (opt-in): class="toc-rail" on a Contents <nav> that is a child of the <article> itself, or of the one block
   that holds the whole article (P-31's .stack), never inside a <details> or the header block: sticky only travels inside
   its parent. From 1180 px it floats into the left gutter beside
   the 560 px reading column and stays under the nav while the article scrolls, ending with the article; below 1180 it is
   hidden, so the page keeps its "Contents" disclosure for phones and marks that wrapper class="toc-disclosure" (hidden
   from 1180); only one of the two navs renders at any width, so readers and screen readers meet one Contents. A full-width
   table in the article slides over the rail on its opaque card while it scrolls by (P-31). */
@media (max-width: 1179px) { .toc-rail { display: none; } }
@media (min-width: 1180px) {
  .toc-disclosure { display: none; }
  .toc-rail { float: left; position: sticky; top: calc(var(--nav-h) + var(--s-6)); z-index: 1; display: grid; gap: 2px;
    width: min(240px, calc((100% - var(--prose)) / 2 - 2 * var(--gutter)));
    margin-left: max(var(--gutter), calc(50% - var(--prose) / 2 - var(--gutter) - min(240px, calc((100% - var(--prose)) / 2 - 2 * var(--gutter)))));
    max-height: calc(100vh - var(--nav-h) - var(--s-12)); overflow-y: auto; }
  .toc-rail a { display: block; padding: 6px 12px; border-radius: 8px; color: var(--fg-2); text-decoration: none; font: 500 14px/20px var(--font-body); }
  .toc-rail a:hover { background: var(--wash); color: var(--fg-1); }
  .toc-rail ~ * .table-wrap { position: relative; z-index: 2; }   /* the table's card passes over the rail, not under its words */
}

/* Phone-only and desktop-only parts (opt-in classes): .phone-only shows below 600 px and is gone from 600; .desktop-only is
   the reverse. For a part that only makes sense on one kind of screen, such as Add to Minecraft on P-14 and P-20 (the
   minecraft:// link adds the server in Bedrock on the phone in your hand; on a computer it does nothing and the address
   with Copy is the path), so it never sits there as a dead button. */
@media (min-width: 600px) { .phone-only { display: none !important; } }
@media (max-width: 599px) { .desktop-only { display: none !important; } }


/* ================================================================ phone tap targets (last, so they win over each component's own height) */
/* Phones and tablets: every small control is a real 44 px box (a 36 px box with an invisible margin still reads as small and
   lets a thumb land between two rows). 36 stays for the desktop pointer. */
@media (max-width: 899px) {
  .btn-sm, button.chip, a.chip, .segmented button { min-height: 44px; }
  .btn-icon.btn-sm { min-width: 44px; }
}

/* ================================================================ reduced motion: no movement anywhere */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
  .status[data-tone="wait"]::before { animation: none; opacity: 1; }
  .skeleton { animation: none; }
}
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* A log inside a .scroll-row keeps its own horizontal scroll at every width (P-27 Console, P-34 Files): long lines must not widen the page. */
.scroll-row > pre { overflow-x: auto; max-width: 100%; }
@media (min-width: 1024px) { .scroll-row:has(> pre) { overflow-x: auto; } }

/* Panel cards (2026-10-14, Scaling's polish notes): lists inside cards drop the browser indent; a card head keeps its right group
   on one row under 480 px; a foot or divider inside a .stack does not stack its margin on the gap. */
.card ul.kv, .card ul.list-tight { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.card > .hint-row, .card > .cluster.card-head { flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: 8px; }
.card > .cluster.card-head > .cluster { flex-wrap: nowrap; }
.stack > .card-foot, .stack > hr.divider { margin-top: 0; margin-bottom: 0; }
