/* Clippet — the visual system "Kept" (clippet-clean/web/STYLE.md), the claim
   page's share of it.

   THE COLOUR LAW (binding — a rule that paints outside it is wrong):
     amber  = happening   nothing on this page: it encodes no time.
     green  = done        the wordmark's span, and the word "connected".
     red    = loss        nothing on this page: a refusal is not a deletion.
     ink    = every button. One solid ink button per screen (Connect, a held
              name's Pay when no Connect is drawn, or Sign in with
              Discord); the rest are hairline. No hue ever fills a
              control, colours a link, or tints a hover. Grey is waiting.

   Complete light palette on bare :root, the same tokens again for the dark
   system preference. No colour has its only definition inside a media block.
   There is no theme cookie and no Settings control here — no session to hang
   one on — so the page follows the system, and there is no data-theme block. */

@font-face {
  font-family: "Spline Sans";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/spline-sans.woff2") format("woff2");
}
@font-face {
  font-family: "Spline Sans Mono";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/spline-sans-mono.woff2") format("woff2");
}

/* ---------- tokens ---------- */
:root {
  color-scheme: light dark;
  /* daylight studio */
  --bg: #ECEDEF;
  --surface: #FFFFFF;
  --surface-2: #F4F5F6;
  --line: #D5D7DB;
  --line-strong: #A7ABB3;
  --text: #17181C;
  --muted: #5B5F67;
  --faint: #787C85;
  --ok: #0E7C4F;
  /* The portal encodes TIME and LOSS, which the claim page never did: a clock
     on a held name, a grace period running out, a name disabled because
     something else answered under it. Amber = happening, red = loss — the two
     remaining words of the colour law, as INK on a banner's rule and its first
     words, never a fill and never a control. Measured on --surface (#FFFFFF):
     amber 6.0 : 1, red 6.1 : 1; both clear AA at the 13 px a banner is set in. */
  --warn: #8A5A00;
  --loss: #B3261E;
  /* Discord's blurple: on THIS surface — the one page of the product that is about Discord — it
     takes the wordmark's span and the done word "connected" (Kevin, 2026-09-15: "blurple highlights
     on the discord work"). Everywhere else the span and done are --ok, and nothing else here is
     blue: not a button, not a link, not a focus ring. Two values, light | dark, exactly as --ok has
     two: the light one is 4.6 : 1 on white but only 3.6 : 1 on the screening room's surface, under
     AA for the 12 px mono state cell (design pass 2026-09-16, finding 4). */
  --discord: #5865F2;
  --primary: #17181C;
  --primary-text: #FFFFFF;
  --focus: #17181C;
  --sans: "Spline Sans", "Segoe UI", Roboto, system-ui, sans-serif;
  --mono: "Spline Sans Mono", ui-monospace, Consolas, Menlo, monospace;
}
@media (prefers-color-scheme: dark) {
  :root {
    /* screening room */
    --bg: #191816;
    --surface: #211F1C;
    --surface-2: #2A2825;
    --line: #34312D;
    --line-strong: #514D47;
    --text: #ECE9E2;
    --muted: #A9A59C;
    --faint: #837F77;
    --ok: #4CD69A;
    /* the screening room's amber and red: 8.9 : 1 and 6.4 : 1 on --surface */
    --warn: #E8B45A;
    --loss: #F2857A;
    /* the dark blurple: 5.2 : 1 on #211F1C, and still unmistakably Discord's. The span and the
       word take it together — one token, so they can never disagree. */
    --discord: #7C86F7;
    --primary: #ECE9E2;
    --primary-text: #191816;
    --focus: #ECE9E2;
  }
}

/* ---------- base ---------- */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { background: var(--bg); color: var(--text); font: 15px/1.5 var(--sans); -webkit-font-smoothing: antialiased; min-height: 100vh; }
h1, h2, p, pre, form { margin: 0; }
h1 { font-size: 22px; line-height: 1.2; font-weight: 600; overflow-wrap: anywhere; }
h2 { font-size: 17px; line-height: 1.3; font-weight: 600; overflow-wrap: anywhere; }
b { font-weight: 600; }
code, .mono { font-family: var(--mono); font-size: 0.93em; }
/* overflow-wrap, not word-break: a host with nowhere to break still breaks
   rather than overflow, but a command with spaces in it breaks at a SPACE —
   break-all split "clippet" across two lines in the refusal sentence. */
code { background: var(--surface-2); padding: 0.1em 0.35em; border-radius: 3px; overflow-wrap: anywhere; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 2px; }
button, input { font: inherit; color: inherit; }
::placeholder { color: var(--faint); opacity: 1; }
main.page { max-width: 1040px; margin: 0 auto; padding: 24px; }
main.page.claim { max-width: 720px; }
.title { margin: 0 0 16px; }

/* ---------- text roles ---------- */
.line { margin: 0; font-size: 17px; line-height: 1.4; color: var(--muted); max-width: 64ch; }
.hint { font-size: 13px; color: var(--faint); }
.ok { color: var(--discord); }
/* the truncation note: a hint that stands outside a panel, so it needs the gap
   a panel's padding would have given it */
.cap { margin: 16px 0 0; }

/* ---------- the wordmark ----------
   The two p stems are the handles and the kept span joins them at the
   descender tips; the four values are measured from the Spline Sans 600
   outlines (STYLE.md, §20 erratum 271) and must not be rounded. The mark is
   ink plus that span — never a hue on the letters. The living mark's eyes and
   faces belong to clippet-clean's app.js; this page has no script, and the
   rest state is the mark. */
.wordmark { display: inline-flex; align-items: baseline; font-weight: 600; letter-spacing: -0.025em; color: var(--text); line-height: 1; white-space: nowrap; font-size: 21px; text-decoration: none; }
.wordmark .pp { position: relative; }
.wordmark .pp::after { content: ""; position: absolute; left: 0.071em; width: 0.7105em; bottom: -0.265em; height: 0.1em; background: var(--discord); border-radius: 0.05em; }
.wordmark.display { font-size: 40px; }

/* ---------- header: the mark at one end, the session at the other ----------
   The site's own bar, with less in it: no Library, no Settings, no name, and no
   glyph. Sign out is a form button dressed as a link — the site's .linkish
   without its marker stroke, which is what its own nav links drop too (a nav
   link is not prose). */
header.top { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 24px; border-bottom: 1px solid var(--line); background: var(--surface); }
header.top nav { display: flex; align-items: center; gap: 18px; font-size: 14px; min-width: 0; }
.linkish { font: inherit; font-size: 14px; color: var(--muted); background: none; border: 0; padding: 2px 1px; cursor: pointer; }
.linkish:hover { color: var(--text); }

/* ---------- buttons: ink; the hue never fills one ----------
   font-family is spelled out because a button also lives in a state cell,
   which is mono: the Add-to-server button must read in the page's own face. */
.btn { display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 14px; border-radius: 4px; border: 1px solid var(--line-strong); background: var(--surface); color: var(--text); font-family: var(--sans); font-weight: 500; font-size: 14px; cursor: pointer; white-space: nowrap; text-decoration: none; }
.btn:hover { border-color: var(--text); }
.btn.primary { background: var(--primary); color: var(--primary-text); border-color: var(--primary); }
.btn.primary:hover { opacity: 0.92; }
.btn.small { height: 30px; padding: 0 10px; font-size: 13px; }

/* ---------- fields ---------- */
input[type="text"] { display: block; width: 100%; height: 36px; padding: 0 10px; background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: 4px; color: var(--text); margin: 0; }

/* ---------- THE ONE GRAMMAR: label | control | state ---------- */
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: 6px; }
.panel + .panel { margin-top: 16px; }
.panel-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 12px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.panel > .hint { padding: 12px 16px; border-bottom: 1px solid var(--line); }
.row { display: grid; grid-template-columns: 9rem minmax(0, 1fr) auto; gap: 10px 16px; align-items: center; padding: 12px 16px; }
.row + .row { border-top: 1px solid var(--line); }
.row.top { align-items: start; }
.row.top .rl { padding-top: 9px; }
.rl { font-size: 13px; color: var(--muted); }
.rc { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-width: 0; }
.rc > input { flex: 1 1 8rem; width: auto; min-width: 14ch; } /* never narrower than a name: the Another name row squeezed it to 5 letters (Kevin, 2026-10-14) */
.rc > pre { flex: 1 1 100%; min-width: 0; }
.rs { font: 12px/1.4 var(--mono); color: var(--muted); text-align: right; justify-self: end; max-width: 26ch; }
.rs.ok { color: var(--discord); }
.rs .on { color: var(--ok); } /* a setting's state "on" is green, "off" stays muted (Kevin, 2026-10-19: "the 'on' should be green text to follow theme") */
#token-state { display: inline-block; min-width: 17ch; text-align: right; } /* the Token row's cell keeps the width of its widest words ("click selects all", 17ch) when the copy script writes "copied" or "not copied", so the token beside it never reflows on the click (lane copytoken) */
.row-actions { display: flex; align-items: center; gap: 10px; }

/* the two LIST panels — the rows that are SERVERS, not fields. The name is the
   row's subject, so it takes the free width instead of sitting in the
   grammar's 9rem label column, and there is no control cell between it and its
   state. Two columns: the server | what is true of it. */
.panel.list .row { grid-template-columns: minmax(0, 1fr) auto; padding: 8px 16px; }
/* Kevin, 2026-09-16, eleven servers deep: "a lot of empty space … at the very least slight shadowing on every
   other row". The name is the subject, so it wears the text colour at the body size, and the rows sit tighter. */
.panel.list .rl { font-size: 14px; color: var(--text); }
/* Every list row lives in ONE grid, and by default that grid is a single column:
   the rows stack, each takes the panel's whole width, and every second one rests
   on --surface-2 (the Connected rows, whose state is a host and a word). */
.panel.list .rows { display: grid; grid-template-columns: minmax(0, 1fr); }
.panel.list .row + .row { border-top: 0; }
.panel.list .row:nth-child(n+2) { border-top: 1px solid var(--line); }
.panel.list .row:nth-child(even) { background: var(--surface-2); }

/* …and a panel that OPTS IN runs TWO ACROSS on a wide screen (design pass
   2026-09-16, finding 1B): eleven servers down one 672 px column is eleven bands
   of nothing between a name and its button, which tighter rows cannot close. The
   panel keeps its siblings' width, every button lands within about 200 px of its
   name, and an odd last row simply leaves its right cell empty. The hairline
   between the columns is the even cells' left edge; the row rules are re-drawn
   per CELL, so the single column's are cancelled first. The zebra is by VISUAL
   ROW — both cells of a pair share the stripe, so a wide row still reads as ONE
   row — and it starts on the second row, where the single column's zebra starts.
   One column below 780 px, in the responsive block.
   ONLY the Add-first panel opts in: see listPanel() for why a row carrying a
   host may not be halved. */
.panel.list.two .rows { grid-template-columns: 1fr 1fr; }
.panel.list.two .row:nth-child(n+2) { border-top: 0; }
.panel.list.two .row:nth-child(n+3) { border-top: 1px solid var(--line); }
.panel.list.two .row:nth-child(even) { border-left: 1px solid var(--line); background: none; }
.panel.list.two .row:nth-child(4n+3), .panel.list.two .row:nth-child(4n+4) { background: var(--surface-2); }
/* a striped last row with no partner (3, 7, 11 rows — Kevin's own eleven) would
   be a half-width band stopping at the column hairline. It takes the whole width
   instead: a stripe is a ROW, and a row with nothing beside it is the panel. */
.panel.list.two .row:nth-child(4n+3):last-child { grid-column: 1 / -1; }
/* a list row's state is one line — the host and the word "connected" sit side by
   side, never stacked. On a WIDE screen there is room for that whatever the
   host; the phone block below lets it wrap, because there the rule was costing
   the name its own row. */
.panel.list .rs { max-width: none; white-space: nowrap; }

/* ---------- a row that opens: the ready rows, and the Pass folds ----------
   One panel, one <details> per ready server (or per Pass name), and the
   <summary> IS the row: the subject | its state | a chevron. The chevron is
   DRAWN (two borders), never an icon file, and paints --muted or ink and
   nothing else; it is the one disclosure mark in the system and it lives on a
   row, never beside the wordmark. list-style and the webkit marker go, or the
   browser draws its own triangle beside it. */
.panel.ready details + details { border-top: 1px solid var(--line); }
.panel.ready summary, .panel.pass summary { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px 16px; align-items: center; padding: 8px 16px; cursor: pointer; list-style: none; }
.panel.ready summary::-webkit-details-marker, .panel.pass summary::-webkit-details-marker { display: none; }
.panel.ready summary .rl, .panel.pass details.name > summary .rl { font-size: 14px; color: var(--text); }
/* one line, and a verdict wider than its cell's max-width is cut with an
   ellipsis INSIDE the cell — never run under the chevron, never widen the page
   (run 13, N3: the forwarder takes any string the plane sends as a disabled name's reason) */
.panel.ready summary .rs, .panel.pass summary .rs { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.panel.ready summary::after, .panel.pass summary::after { content: ""; width: 7px; height: 7px; border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted); transform: rotate(45deg); margin: 0 4px 3px 0; transition: transform 130ms ease; }
.panel.ready details[open] > summary::after, .panel.pass details[open] > summary::after { transform: rotate(-135deg); margin-bottom: -2px; }
.panel.ready details[open] > summary { background: var(--surface-2); }
.panel.ready details[open] > summary .rs, .panel.pass details[open] > summary .rs { color: var(--text); }
.panel.ready details > form { border-top: 1px solid var(--line); }
.panel.ready details > form > .hint { padding: 12px 16px 0; }
.panel.ready details > form > .row + .row { border-top: 1px solid var(--line); }
.panel.ready summary:focus-visible, .panel.pass summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; }

/* ---------- a server's own face, beside its name ----------
   24 px, round, on --surface-2 with a hairline ring so a transparent PNG reads
   on either ground. Where Discord has no icon the circle carries the name's
   initials, in the page's own face — never a hue, never a tile beside the
   wordmark (STYLE.md: icons belong to things, not to the mark). */
.srv { display: inline-flex; align-items: center; gap: 10px; min-width: 0; overflow-wrap: anywhere; }
.avatar { flex: none; width: 24px; height: 24px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line); object-fit: cover; }
.avatar.initials { display: inline-flex; align-items: center; justify-content: center; font: 500 10px/1 var(--sans); letter-spacing: -0.02em; white-space: nowrap; color: var(--muted); }
/* the .env lines and the bind command: things a machine measured, so mono — and
   things a person COPIES, so each is shown whole and selects whole (design pass
   2026-09-16, finding 8). The public key used to run off the right edge and
   scroll, which is how a half copy happens; now the block wraps, one click
   selects all of it, and the row's state cell says so. A wrapped <pre> still
   copies with its own newlines and none of the wrap's. */
pre.mono { width: 100%; background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px; padding: 8px 10px; font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; -webkit-user-select: all; user-select: all; cursor: copy; }

/* ---------- the foot: the two legal pages, on every page ----------
   Two links, centred, in the grammar's grey. Not a panel and not a nav: they
   are the pages a person goes to once, and the page they are on is the one
   that matters. */
footer.foot { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 18px; padding: 28px 24px 32px; font-size: 13px; }
footer.foot a { color: var(--faint); text-decoration: none; }
footer.foot a:hover { color: var(--text); }
/* the bar's right end can hold a LINK as well as the sign-out form button */
a.linkish { text-decoration: none; display: inline-block; }

/* ---------- the two legal pages ----------
   Prose, so a measure and a rhythm: one column, 68ch, the headings ink and the
   body the grammar's --muted, exactly as a .hint is. Nothing else is added —
   the markup is generated from the Markdown at build time and this sheet is
   what dresses it. */
main.page.doc { max-width: 680px; }
.doc h2 { margin: 28px 0 8px; }
.doc h3 { font-size: 15px; margin: 20px 0 6px; }
.doc p, .doc li { color: var(--muted); max-width: 68ch; }
.doc p { margin: 0 0 12px; }
.doc ul, .doc ol { margin: 0 0 12px; padding-left: 20px; }
.doc li { margin: 0 0 6px; }
.doc strong { color: var(--text); }

/* ---------- the portal: banners ----------
   A banner is a FACT, not a control: a rule down its left edge and its first
   words carry the hue, and nothing in it is filled, tinted or clickable. amber
   = happening (a grace running out, a box gone quiet, a release behind),
   red = loss (a name disabled). Anything else is the plain one. */
.banner { display: block; margin: 0 0 12px; padding: 10px 14px; background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--line-strong); border-radius: 4px; font-size: 13px; color: var(--muted); }
.banner b { color: var(--text); font-weight: 600; }
.banner.warn { border-left-color: var(--warn); }
.banner.warn b { color: var(--warn); }
.banner.loss { border-left-color: var(--loss); }
.banner.loss b { color: var(--loss); }

/* ---------- the portal: the Your name panel ----------
   Its children are rows, forms that wrap one row each, state lines and hints,
   so the hairline between them is drawn by the PANEL and not by the row: every
   direct child after the head takes a rule, and the head keeps its own. */
.panel.pass > * + * { border-top: 1px solid var(--line); }
.panel.pass > .panel-head + * { border-top: 0; }
.panel.pass > p { padding: 12px 16px; margin: 0; }
/* a hint inside this panel is a row like any other: the panel draws the rule
   above it, so the claim page own .panel hint bottom rule would double it */
.panel.pass > .hint { border-bottom: 0; }
.panel.pass > form > .row { padding: 12px 16px; }
/* the price cell: "$3.99 a month or $39.99 a year" on two even lines, never a
   lone "year" under it */
.panel.pass .rs { max-width: 32ch; }
/* a name field's row (Another name, Rename): the field, the suffix and the
   button stay on ONE line and the FIELD gives up the width, never the button —
   at 720 px the price cell left the control too little for the field's 8rem
   basis and the button wrapped under it (run 13, N5). The field shrinks to
   14ch and no further: N5's min-width 0 outweighed .rc > input's 14ch here,
   so Another name showed five letters (Kevin, 2026-10-14; lane portal014,
   2026-10-19). Under 780px the row stacks to one column anyway; above it the
   720px page leaves 252px for the control beside the one-line yearly price,
   and the field, the suffix and Reserve need 322px (measured in Chromium), so
   in a name field's row the state cell is 17ch: the price on two even lines
   ("$3.99 a month or" / "$39.99 a year"), the control 343px. Every other
   control cell in these panels holds one item, so the rules change nothing
   else. */
.panel.pass .rc { flex-wrap: nowrap; }
.panel.pass .rc > input { min-width: 14ch; }
@media (min-width: 781px) {
  .panel.pass .row:has(> .rc > input) .rs { max-width: 17ch; }
}
/* a served name is a FOLD (run 12, lane names): the summary is the address
   in the state line's own weight, and inside, the panel's rules again — every
   child after the summary takes a hairline, a state line or a hint its padding */
.panel.pass details.name > summary .rl { font-weight: 600; }
/* the name reads in ink; the suffix every summary repeats steps back */
.panel.pass details.name > summary .rl .sfx { color: var(--muted); font-weight: 500; }
.panel.pass details > * + * { border-top: 1px solid var(--line); }
.panel.pass details > p { padding: 12px 16px; margin: 0; }
/* THE OPEN NAME IS ONE CARD: its summary and its whole body, down to the next
   closed summary, sit on ONE inset ground — the ready rows' open tone — so it
   reads as a card inside the panel while the closed names stay flat. No new
   colour, no shadow, no radius but the panel's own at its foot. The wells a
   person copies from or types in turn to --surface on that ground, so they
   still read as wells. */
.panel.pass details.name[open] { background: var(--surface-2); }
.panel.pass > details.name[open]:last-child { border-radius: 0 0 5px 5px; }
.panel.pass details.name[open] pre.mono, .panel.pass details.name[open] input[type="text"] { background: var(--surface); }
/* Setup, inside a name: a grammar row that opens — label | what is inside |
   the chevron. It takes no tint of its own: it is part of the card. */
.panel.pass details.setup > summary { grid-template-columns: 9rem minmax(0, 1fr) auto; padding: 12px 16px; }
.panel.pass details.setup > summary .rl { font-size: 14px; color: var(--text); font-weight: 500; }
.panel.pass details.setup > summary::after { width: 8px; height: 8px; border-right: 2px solid var(--text); border-bottom: 2px solid var(--text); }
.panel.pass details.setup > summary .rs { justify-self: start; text-align: left; max-width: none; }
/* THE SELF-HOSTING FOLD (run 18b; class docker): the compose lines under one
   closed fold, drawn last in a name's card (the Pass panel), inside Your
   Clippet and inside a ready row's form — three places with three different
   summary rules, so the fold carries
   its own: Setup's grammar row (label | what is inside | the chevron), the
   label and the state in the row's own faces, no tint of its own on any
   ground (it is part of whatever card it sits in), and a hairline between its
   children as the Pass folds draw. .panel leads every selector so these
   rules outweigh the ready panel's (a server-name label at 14 px, an inset
   open summary) and the Pass panel's own summary grid. */
.panel details.docker > summary { display: grid; grid-template-columns: 9rem minmax(0, 1fr) auto; gap: 10px 16px; align-items: center; padding: 12px 16px; cursor: pointer; list-style: none; background: none; }
.panel details.docker > summary::-webkit-details-marker { display: none; }
.panel details.docker > summary .rl { font-size: 14px; color: var(--text); font-weight: 500; }
.panel details.docker > summary .rs { font: 12px/1.4 var(--mono); color: var(--muted); justify-self: start; text-align: left; max-width: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.panel details.docker > summary::after { content: ""; width: 8px; height: 8px; border-right: 2px solid var(--text); border-bottom: 2px solid var(--text); transform: rotate(45deg); margin: 0 4px 3px 0; transition: transform 130ms ease; }
.panel details.docker[open] > summary::after { transform: rotate(-135deg); margin-bottom: -2px; }
.panel details.docker[open] > summary .rs { color: var(--text); }
.panel details.docker > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; }
.panel details.docker > * + * { border-top: 1px solid var(--line); }
.panel details.docker > p { padding: 12px 16px; margin: 0; }
/* THE TWO SUB-FOLDS READ AS FOLDS (lane portal015, the review's M1/M2): Setup
   and Self-hosting carry a label in ink and the heavier chevron above, a
   neutral hover on the whole summary row (--line, no hue), and a left bar the
   whole height of the fold, closed and open alike, so the closed row reads as
   the same fold the open one is and an open one shows where it ends. The
   summary draws the bar too, so a summary ground (the hover, a ready row's
   open tone) never paints over it. */
.panel.pass details.setup, .panel details.docker,
.panel.pass details.setup > summary, .panel details.docker > summary { box-shadow: inset 3px 0 0 var(--line-strong); }
.panel.pass details.setup > summary:hover, .panel details.docker > summary:hover { background: var(--line); }
/* a hint in the Pass panels is --muted, never --faint (3.7 : 1 on the open card) */
.panel.pass .hint:not(.done):not(.bad) { color: var(--muted); }
/* a hint is the footnote of the row above it, not a row of its own (lane
   portalnits, the review's m2): no hairline between them and no top padding,
   so "The old name works…" reads as Rename's and the notices line as its row's */
.panel.pass details > p.hint, .panel.pass > form + p.hint, .panel.pass > .row + p.hint { border-top: 0; padding-top: 0; }
/* a closed name's verdict that is happening — offline, paused, cancels — is
   amber in its summary too, as the banner above says it (the review's m3);
   waiting stays grey (the law: grey is waiting) */
.panel.pass details.name > summary .rs.warn { color: var(--warn); }
/* the row after a fold (a ready row's Address) takes the rule the row grammar
   draws between rows */
.panel details.docker + .row { border-top: 1px solid var(--line); }
/* the Connected panel's Other servers fold (lane portal017): the panel's
   foot, under the rows' last hairline, its corners the panel's own; inside, a
   striped server row draws the left bar too, so its ground never paints over it */
.panel.list > details.docker { border-top: 1px solid var(--line); border-radius: 0 0 5px 5px; }
.panel.list > details.docker:not([open]) > summary { border-radius: 0 0 5px 5px; }
.panel.list details.docker .row:nth-child(even) { box-shadow: inset 3px 0 0 var(--line-strong); }
.state { font: 12px/1.6 var(--mono); color: var(--muted); overflow-wrap: anywhere; }
.state .addr { color: var(--text); font-weight: 600; }
/* the held line's address splits as a fold's summary does: the name in ink,
   the suffix stepping back (the review's n1) */
.state .addr .sfx { color: var(--muted); font-weight: 500; }
.hint.done { color: var(--ok); }
.hint.bad { color: var(--loss); }
/* the thing that cannot be done (a name while the shelf is empty, the waiting
   list): a fact in the state cell's own face, never a button that would do
   nothing and never a link that would 404 */
.soon { font-family: var(--mono); font-size: 12px; color: var(--faint); }
/* the last 24 hours: 24 empty cells, oldest left. Up is a solid --ok bar; down
   is NO fill, a hairline --loss outline (the colour law: red is text and a
   hairline, never a fill), so solid against hollow tells them apart without
   hue; before the claim is a --line baseline. */
.hours { flex: 1 1 100%; display: grid; grid-template-columns: repeat(24, minmax(0, 1fr)); gap: 2px; align-items: end; height: 16px; max-width: 30rem; }
.hour { display: block; height: 100%; border-radius: 1px; }
.hour.up { background: var(--ok); }
.hour.down { border: 1px solid var(--loss); }
.hour.none { height: 1px; background: var(--line); }
/* recent: one change a line, in the state line's own face */
.row.lines { align-items: start; }
.recent { flex: 1 1 100%; display: grid; gap: 2px; font: 12px/1.6 var(--mono); color: var(--muted); }
/* the picker: the name, then what it will become, then the button */
.suffix { font-family: var(--mono); font-size: 13px; color: var(--faint); }
/* the pricing truths: the panel's own paragraph block, one sentence a line */
.truths { display: grid; gap: 8px; padding: 12px 16px; }
.truths p { font-size: 13px; color: var(--muted); max-width: 68ch; }

/* ---------- the front door and the message pages ---------- */
.auth { max-width: 460px; margin-inline: auto; margin-block: 40px; display: grid; gap: 22px; justify-items: center; }
.auth.front { margin-block-start: 96px; }
.front { gap: 18px; text-align: center; }
.front .enter { margin: 6px 0 0; }

/* ---------- responsive ---------- */
@media (max-width: 780px) {
  .row { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .row.top .rl { padding-top: 0; }
  .rs { text-align: left; justify-self: start; max-width: none; }
  .rs:empty { display: none; }
  /* a list row is two things and stays two things at every width: the server,
     and the button or the word that is true of it. Stacking them would put a
     narrow phone back where the 9rem column left it.
     The name keeps a FLOOR here, and the state may wrap: on a phone the
     one-line rule below (the host beside the word, never over it) was taking
     the whole row for a long host and leaving the name to go down the column a
     letter at a time. A host that cannot fit now wraps inside its own <code>,
     which already breaks anywhere, and the name keeps 6rem to be a name in. */
  .panel.list .row { grid-template-columns: minmax(6rem, 1fr) auto; gap: 10px 16px; }
  .panel.list .rs { text-align: right; justify-self: end; white-space: normal; }
  /* the panel that opted in gives the second column up here: every row is its
     own visual row again, so the hairlines and the zebra go back to counting
     rows rather than pairs (the same servers stay striped). The plain list
     panels are already this, at every width. */
  .panel.list.two .rows { grid-template-columns: minmax(0, 1fr); }
  .panel.list.two .row:nth-child(n+2) { border-top: 1px solid var(--line); }
  .panel.list.two .row:nth-child(odd) { background: none; }
  .panel.list.two .row:nth-child(even) { background: var(--surface-2); border-left: 0; }
  /* on a phone the Self-hosting summary is the label and the chevron; Setup
     keeps its contents cell (token · rotate · app fits at 400 px), so a closed
     Setup still says Rotate is inside */
  .panel details.docker > summary { grid-template-columns: minmax(0, 1fr) auto; }
  .panel details.docker > summary .rs { display: none; }
}
@media (max-width: 600px) {
  main.page { padding: 16px; }
  header.top { padding: 10px 16px; }
  .wordmark.display { font-size: 32px; }
  .auth { margin-block: 20px; }
  .auth.front { margin-block-start: 56px; }
}

/* ---------- reduced motion ----------
   The chevron's turn is the only thing that moves on this page; app.css's own
   one-line block covers the same ground on the rest of the product. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
