/**
 * Vintedex, web.
 *
 * Every colour, radius, size and duration comes from shared/design/tokens.css.
 * Nothing is decided here. A hex typed into this file is a decision made twice
 * and a theme that will be wrong in one of them, and tools/check_design.py
 * fails the build for it rather than trusting anybody to remember.
 *
 * The visual language is Vinted's, read off their stylesheet: 6px on controls
 * and cards, 12px on sheets, pills for chips, 44px controls, hairlines rather
 * than shadows, Inter. The seller has their tab open beside this one all day.
 *
 * Both themes, and the earlier version had neither: it was light because the
 * phone was dark, which is a preference dressed as a reason. It now follows
 * the machine and can be overridden; see the theme switch in ui.js.
 */

@import url("./tokens.css");

*,
*::before,
*::after { box-sizing: border-box; }

html {
    /* Tells the browser to draw its own furniture - scrollbars, the default
       form controls, the caret - in the running theme. Without it a dark page
       gets a light scrollbar and native checkboxes stay white. */
    color-scheme: light dark;
    accent-color: rgb(var(--vx-accent));
}

body {
    --vx-wordmark: url("../img/wordmark.png");
    margin: 0;
    background: rgb(var(--vx-page));
    color: rgb(var(--vx-ink));
    font-family: var(--vx-font);
    font-size: var(--vx-text-body);
    line-height: var(--vx-leading);
    -webkit-font-smoothing: antialiased;
}

a {
    color: rgb(var(--vx-accent-ink));
    text-underline-offset: 2px;
}

/* Focus is visible everywhere, once, and never removed for looks. The ring is
   outside the element so it does not shift anything as it appears. */
:focus-visible {
    outline: 2px solid rgb(var(--vx-accent));
    outline-offset: 2px;
    border-radius: var(--vx-radius);
}

/* ───────────────────────────────────────────────────────── Shell */

/*
 * The header, in Vinted's arrangement.
 *
 * Two rows, and it is the same two at every width: identity and actions, then
 * the sections. Their site does the same thing, and the only difference at
 * 390px is that the section row turns into pills that scroll sideways and the
 * quiet actions fold behind a menu.
 *
 * No second markup for mobile. One header, one set of rules, so nothing can
 * appear on one width and be forgotten on the other.
 */
.topbar {
    position: sticky;
    top: 0;
    /* The positioning context for the person menu. */
    isolation: isolate;
    z-index: var(--vx-z-sticky);
    background: rgb(var(--vx-surface));
    border-bottom: var(--vx-border) solid rgb(var(--vx-line));
}

.topbar-main {
    display: flex;
    align-items: center;
    gap: var(--vx-space-m);
    padding: var(--vx-space-s) var(--vx-space-m);
    min-height: 64px;
    max-width: 76rem;
    margin: 0 auto;
}

/*
 * The wordmark, painted rather than drawn.
 *
 * The PNG is one flat colour on transparency, so it is used as a MASK and the
 * colour comes from the accent token. One asset serves both themes, the mark
 * can never be the wrong teal, and there is no second file to fall out of step
 * with the first. It also fixes the artwork being the print teal on a screen
 * that is not.
 */
.brand {
    display: block;
    height: 26px;
    aspect-ratio: 274 / 66;
    flex: 0 0 auto;
    background: rgb(var(--vx-accent-ink));
    -webkit-mask: var(--vx-wordmark) no-repeat center left / contain;
    mask: var(--vx-wordmark) no-repeat center left / contain;
}

/*
 * The search box across the middle, as theirs: a sunken rounded field with
 * the glass inside it, taking the room between the wordmark and the actions.
 * The field is a form that goes to stock, so Enter searches and there is no
 * script between the person and the result.
 */
.topbar-search {
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    max-width: 30rem;
    min-width: 0;
    height: var(--vx-control-h);
    padding: 0 var(--vx-space-m);
    gap: var(--vx-space-s);
    background: rgb(var(--vx-sunken));
    border-radius: var(--vx-radius);
    border: var(--vx-border) solid transparent;
    transition: border-color var(--vx-duration-fast) var(--vx-ease);
}
.topbar-search:focus-within { border-color: rgb(var(--vx-accent)); }
.topbar-search svg {
    width: 20px; height: 20px; flex: 0 0 auto;
    fill: none; stroke: rgb(var(--vx-ink-secondary)); stroke-width: 2; stroke-linecap: round;
}
.topbar-search input {
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: rgb(var(--vx-ink));
    font: inherit;
    font-size: var(--vx-text-body);
    outline: none;
}
.topbar-search input::placeholder { color: rgb(var(--vx-ink-secondary)); }
.topbar-search input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* The right side: person, the one teal button, help. Pushed right; the search
   box in the middle is what stretches. */
.topbar-actions {
    display: flex;
    align-items: center;
    gap: var(--vx-space-m);
    margin-left: auto;
    flex: 0 0 auto;
}

/* Chrome, not the work. The full 44px is for what a person came to press. */
.topbar .btn {
    min-height: var(--vx-control-h-sm);
    padding: 0 var(--vx-space-m);
    font-size: var(--vx-text-label);
    flex: 0 0 auto;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
}

/* The person: initials in a circle, with the little chevron theirs has, and
   the sheet under it. */
.topbar-person { position: relative; }

.topbar .topbar-avatar {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    min-height: 0;
    border: 0;
    background: transparent;
    color: rgb(var(--vx-ink-secondary));
    border-radius: var(--vx-radius-pill);
    cursor: pointer;
}
.topbar .topbar-avatar:hover .avatar { box-shadow: 0 0 0 2px rgb(var(--vx-accent-wash)); }
.topbar .topbar-avatar svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.topbar .avatar {
    display: inline-grid;
    place-items: center;
    width: 32px; height: 32px;
    border-radius: 50%;
    background: rgb(var(--vx-accent-wash));
    color: rgb(var(--vx-accent-ink));
    font-size: var(--vx-text-label);
    font-weight: var(--vx-weight-bold);
    letter-spacing: 0.02em;
}

.topbar-sheet {
    position: absolute;
    top: calc(100% + var(--vx-space-xs));
    right: 0;
    min-width: 16rem;
    padding: var(--vx-space-xs);
    display: flex;
    flex-direction: column;
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    box-shadow: var(--vx-shadow-float);
    animation: vx-in var(--vx-duration) var(--vx-ease) both;
}
/* `hidden` has to win over the flex above, or the sheet is simply open. */
.topbar-sheet[hidden] { display: none; }
.topbar-sheet .who {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--vx-space-s) var(--vx-space-m);
    border-bottom: var(--vx-border) solid rgb(var(--vx-line));
    margin-bottom: var(--vx-space-xs);
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-label);
}
.topbar-sheet .who b { color: rgb(var(--vx-ink)); font-weight: var(--vx-weight-bold); }
.topbar-sheet [role="menuitem"] {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--vx-space-s) var(--vx-space-m);
    border: 0;
    border-radius: calc(var(--vx-radius) - 4px);
    background: transparent;
    color: rgb(var(--vx-ink));
    font: inherit;
    font-size: var(--vx-text-label);
    text-decoration: none;
    cursor: pointer;
    min-height: 0;
}
.topbar-sheet [role="menuitem"]:hover { background: rgb(var(--vx-sunken)); }

/* Help: the ringed question mark, quiet. */
.topbar-help {
    display: inline-grid;
    place-items: center;
    width: 32px; height: 32px;
    border-radius: 50%;
    color: rgb(var(--vx-ink-secondary));
}
.topbar-help:hover { background: rgb(var(--vx-sunken)); }
.topbar-help svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

/*
 * The section row: plain text links spaced across, exactly as theirs are. The
 * current one is simply darker; theirs marks nothing on that row at all, and
 * a pill or an underline there competes with every real link on the page.
 */
.topbar-nav {
    display: flex;
    gap: var(--vx-space-xl);
    padding: 0 var(--vx-space-m);
    max-width: 76rem;
    margin: 0 auto;
    overflow-x: auto;
    scrollbar-width: none;
}
.topbar-nav::-webkit-scrollbar { display: none; }

.topbar-nav a {
    padding: var(--vx-space-s) 0 var(--vx-space-m);
    color: rgb(var(--vx-ink-secondary));
    text-decoration: none;
    font-size: var(--vx-text-label);
    white-space: nowrap;
    transition: color var(--vx-duration-fast) var(--vx-ease);
}
.topbar-nav a:hover { color: rgb(var(--vx-ink)); }
.topbar-nav a[aria-current="page"] {
    color: rgb(var(--vx-ink));
    font-weight: var(--vx-weight-medium);
}

/*
 * Narrow.
 *
 * Wordmark, person and Vender stay on the first line; the search box gives
 * way (stock has its own), help goes into the person's sheet by being the
 * install link there already, and the section row scrolls sideways.
 */
@media (max-width: 720px) {
    .topbar-main { gap: var(--vx-space-s); min-height: 56px; }
    .topbar-search { display: none; }
    .topbar-help { display: none; }
    .topbar-actions { gap: var(--vx-space-s); }
    .topbar-nav { gap: var(--vx-space-l); }
}

main {
    max-width: 76rem;
    margin: 0 auto;
    padding: var(--vx-space-l) var(--vx-space-m) var(--vx-space-xxl);
}

h1 {
    font-size: var(--vx-text-display);
    line-height: var(--vx-leading-tight);
    letter-spacing: var(--vx-tracking-tight);
    font-weight: var(--vx-weight-bold);
    margin: 0 0 var(--vx-space-xs);
    text-wrap: balance;
}

h2 {
    font-size: var(--vx-text-title);
    line-height: var(--vx-leading-tight);
    letter-spacing: var(--vx-tracking-tight);
    font-weight: var(--vx-weight-bold);
    margin: var(--vx-space-xl) 0 var(--vx-space-m);
    text-wrap: balance;
}

.lede {
    color: rgb(var(--vx-ink-secondary));
    margin: 0 0 var(--vx-space-l);
    max-width: 60ch;
}

/* ─────────────────────────────────────────────── Cards and tiles */

.card {
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    box-shadow: var(--vx-shadow-raised);
    padding: var(--vx-space-m);
}

.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--vx-space-s);
    margin-bottom: var(--vx-space-l);
}

/*
 * Written out rather than composed.
 *
 * This rule used to be `.tile { composes: card; }`, which is a CSS Modules
 * feature and not CSS. Browsers drop it without a word, so every tile in the
 * product has been a bare div with no background, no border and no padding
 * since the day it was written, and it looked deliberate enough that nobody
 * questioned it.
 */
.tile {
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    box-shadow: var(--vx-shadow-raised);
    padding: var(--vx-space-m);
}

.tile b {
    display: block;
    font-size: var(--vx-text-display);
    font-weight: var(--vx-weight-bold);
    letter-spacing: var(--vx-tracking-tight);
    line-height: var(--vx-leading-tight);
    font-variant-numeric: tabular-nums;
}

.tile span {
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-label);
}

.tile.good b { color: rgb(var(--vx-good-ink)); }
.tile.bad b  { color: rgb(var(--vx-bad-ink)); }
.tile.warn b { color: rgb(var(--vx-warn-ink)); }

/* ──────────────────────────────────────────────────────── Tables */

.table-wrap {
    overflow-x: auto;
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--vx-text-label);
}

th {
    text-align: left;
    font-weight: var(--vx-weight-medium);
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-micro);
    text-transform: uppercase;
    letter-spacing: var(--vx-tracking-caps);
    padding: var(--vx-space-s) var(--vx-space-s);
    border-bottom: var(--vx-border) solid rgb(var(--vx-line));
    white-space: nowrap;
}

td {
    padding: var(--vx-space-s);
    border-bottom: var(--vx-border) solid rgb(var(--vx-line));
    vertical-align: middle;
}

/* Vinted's own row height, which is also the smallest comfortable target. */
tbody tr { min-height: var(--vx-control-h); }
tr:last-child td { border-bottom: 0; }

tbody tr {
    transition: background var(--vx-duration-fast) var(--vx-ease);
}
tbody tr:hover { background: rgb(var(--vx-sunken)); }

td.num, th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

td.code {
    font-family: var(--vx-font-mono);
    font-size: var(--vx-text-label);
    color: rgb(var(--vx-ink-secondary));
}

/* ──────────────────────────────────────────────────────── Status */

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--vx-space-xs);
    padding: 2px var(--vx-space-s);
    border-radius: var(--vx-radius-pill);
    font-size: var(--vx-text-label);
    font-weight: var(--vx-weight-medium);
    white-space: nowrap;
}

.chip::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

/*
 * Six statuses, five colours, and the sharing is on purpose.
 *
 * "Em stock" and "Retirado" are both the absence of a sale, so both are quiet
 * greys; what tells them apart is the word, not a hue invented to fill a gap.
 * Every colour here means the same thing it means everywhere else in the
 * product: teal is us, amber is attention, green is money in, red is wrong.
 */
.chip.in-stock  { color: rgb(var(--vx-ink-secondary)); background: rgb(var(--vx-sunken)); }
.chip.to-ship   { color: rgb(var(--vx-warn-ink));      background: rgb(var(--vx-warn-wash)); }
.chip.shipped   { color: rgb(var(--vx-accent-ink));    background: rgb(var(--vx-accent-wash)); }
.chip.delivered { color: rgb(var(--vx-good-ink));      background: rgb(var(--vx-good-wash)); }
.chip.returned  { color: rgb(var(--vx-bad-ink));       background: rgb(var(--vx-bad-wash)); }
.chip.withdrawn { color: rgb(var(--vx-ink-faint));     background: rgb(var(--vx-sunken)); }
/* Where a piece stands on Vinted, beside its status here. */
.chip.unpublished  { color: rgb(var(--vx-warn-ink));  background: rgb(var(--vx-warn-wash)); }
.chip.vinted-draft { color: rgb(var(--vx-ink-faint)); background: rgb(var(--vx-sunken)); }
.chip.vinted-published { color: rgb(var(--vx-good-ink)); background: rgb(var(--vx-good-wash)); }

/* The deadline is the one thing here that gets louder over time. */
.due { font-variant-numeric: tabular-nums; white-space: nowrap; }
.due.soon  { color: rgb(var(--vx-warn-ink)); font-weight: var(--vx-weight-medium); }
.due.today { color: rgb(var(--vx-bad-ink)); font-weight: var(--vx-weight-bold); }
.due.late {
    color: rgb(var(--vx-on-accent));
    background: rgb(var(--vx-bad));
    padding: 2px var(--vx-space-s);
    border-radius: var(--vx-radius-pill);
    font-weight: var(--vx-weight-bold);
}

/* ────────────────────────────────────────────────────── Controls */

button, .btn {
    font: inherit;
    font-weight: var(--vx-weight-medium);
    min-height: var(--vx-control-h);
    padding: 0 var(--vx-space-l);
    border-radius: var(--vx-radius);
    border: var(--vx-border) solid transparent;
    background: rgb(var(--vx-accent));
    color: rgb(var(--vx-on-accent));
    cursor: pointer;
    transition: background var(--vx-duration-fast) var(--vx-ease),
                border-color var(--vx-duration-fast) var(--vx-ease);
}

button:hover:not(:disabled),
.btn:hover { background: rgb(var(--vx-accent-strong)); }

/* Pressing moves nothing. A button that shifts under the finger reads as the
   page being knocked rather than as the press landing. */
button:active:not(:disabled) { background: rgb(var(--vx-accent-strong)); }

button:disabled {
    background: rgb(var(--vx-disabled-bg));
    color: rgb(var(--vx-disabled-ink));
    cursor: default;
}

button.quiet, .btn.quiet {
    background: rgb(var(--vx-surface));
    color: rgb(var(--vx-ink));
    border-color: rgb(var(--vx-line-strong));
}
button.quiet:hover:not(:disabled) { background: rgb(var(--vx-sunken)); }

button.danger { background: rgb(var(--vx-bad)); }
button.danger:hover:not(:disabled) { background: rgb(var(--vx-bad-ink)); }

input, select, textarea {
    font: inherit;
    min-height: var(--vx-control-h);
    padding: 0 var(--vx-control-pad);
    border: var(--vx-border) solid rgb(var(--vx-line-strong));
    border-radius: var(--vx-radius);
    background: rgb(var(--vx-surface));
    color: rgb(var(--vx-ink));
    width: 100%;
    transition: border-color var(--vx-duration-fast) var(--vx-ease);
}

textarea {
    padding: var(--vx-space-s) var(--vx-control-pad);
    line-height: var(--vx-leading);
    resize: vertical;
}

input::placeholder, textarea::placeholder { color: rgb(var(--vx-ink-faint)); }

/* Vinted thickens the border on focus rather than adding a ring. Copied,
   because the seller's eye is trained on theirs. No glow: a coloured halo on
   an input is the house style of generated pages and is banned by rule. */
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: rgb(var(--vx-accent));
    border-width: var(--vx-border-strong);
}

label {
    display: block;
    font-size: var(--vx-text-label);
    color: rgb(var(--vx-ink-secondary));
    margin-bottom: var(--vx-space-xs);
}

.row {
    display: flex;
    gap: var(--vx-space-m);
    flex-wrap: wrap;
    align-items: flex-end;
}
.row > * { flex: 1 1 12rem; }
.row > .narrow { flex: 0 0 10rem; }

.filters {
    display: flex;
    gap: var(--vx-space-s);
    flex-wrap: wrap;
    margin-bottom: var(--vx-space-m);
}

.filters button {
    min-height: var(--vx-control-h-sm);
    padding: 0 var(--vx-space-m);
    border-radius: var(--vx-radius-pill);
    background: rgb(var(--vx-surface));
    color: rgb(var(--vx-ink-secondary));
    border-color: rgb(var(--vx-line-strong));
    font-size: var(--vx-text-label);
}

.filters button[aria-pressed="true"] {
    background: rgb(var(--vx-accent-wash));
    color: rgb(var(--vx-accent-ink));
    border-color: rgb(var(--vx-accent));
}

.filters button .n {
    color: rgb(var(--vx-ink-faint));
    margin-left: var(--vx-space-xs);
    font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────────────────────────────── Notices */

.notice {
    padding: var(--vx-space-s) var(--vx-space-m);
    border-radius: var(--vx-radius);
    background: rgb(var(--vx-accent-wash));
    color: rgb(var(--vx-accent-ink));
    margin-bottom: var(--vx-space-m);
}
.notice.bad {
    background: rgb(var(--vx-bad-wash));
    color: rgb(var(--vx-bad-ink));
}

.empty {
    padding: var(--vx-space-xxl) var(--vx-space-m);
    text-align: center;
    color: rgb(var(--vx-ink-secondary));
}
.empty b {
    display: block;
    color: rgb(var(--vx-ink));
    font-size: var(--vx-text-title);
    margin-bottom: var(--vx-space-xs);
}

/* ─────────────────────────────────────────────────────── Sign in */

.gate {
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: var(--vx-space-m);
}
.gate .card { width: 100%; max-width: 24rem; padding: var(--vx-space-l); }
.gate .brand { height: 28px; margin-bottom: var(--vx-space-l); }
.gate label { margin-top: var(--vx-space-m); }
.gate button { width: 100%; margin-top: var(--vx-space-l); }

/*
 * The QR, painted in ink rather than drawn in black.
 *
 * The SVG uses currentColor, so on a dark theme the code inverts along with
 * everything else and still scans: readers look for the contrast between the
 * modules and the quiet zone, not for black on white specifically.
 */
.qr-frame {
    width: 100%;
    max-width: 15rem;
    margin: 0 auto var(--vx-space-m);
    aspect-ratio: 1;
    padding: var(--vx-space-s);
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    color: rgb(var(--vx-ink));
}
.qr-frame svg { display: block; }

.qr-number {
    text-align: center;
    margin: 0 0 var(--vx-space-s);
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-label);
}
.qr-number b {
    display: block;
    font-size: var(--vx-text-display);
    font-weight: var(--vx-weight-heavy);
    letter-spacing: 0.2em;
    font-variant-numeric: tabular-nums;
    color: rgb(var(--vx-ink));
}

/* ─────────────────────────────────────────────────── Definições */

/*
 * Grouped rows, as Vinted draws them on both web and phone: icon, label,
 * value, chevron, stacked, and the groups separated by space rather than by
 * boxes. A settings screen is scanned for one thing and left; the shape has
 * to make that scan cheap.
 */
.settings { max-width: 40rem; }
.settings h1 { margin-bottom: var(--vx-space-l); }

.settings-group { margin-bottom: var(--vx-space-l); }
.settings-group h2 {
    font-size: var(--vx-text-label);
    color: rgb(var(--vx-ink-secondary));
    margin: 0 0 var(--vx-space-s);
    letter-spacing: 0;
}

.settings-rows {
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    overflow: hidden;
}

/*
 * A row is a <button>, because it opens something. But it must not LOOK like
 * one, and the generic button rules (accent fill, accent-strong on hover and
 * active) reach it through the element selector. Rather than fight each state
 * as it turns up, every rule here is written as `.settings-rows .settings-row`
 * with the state appended, which outranks anything the element selector can
 * say in any state. Found by looking at the dark theme: "Convidar" flashed
 * accent-strong under the pointer, which on dark is a pale teal.
 */
.settings-rows .settings-row,
.settings-rows .settings-row:hover,
.settings-rows .settings-row:active,
.settings-rows .settings-row:focus {
    width: 100%;
    min-height: 52px;
    margin: 0;
    padding: 0 var(--vx-space-m);
    border: 0;
    border-radius: 0;
    background: transparent;
    color: rgb(var(--vx-ink));
    font: inherit;
    font-weight: var(--vx-weight-normal);
    text-align: left;
    display: grid;
    grid-template-columns: 20px 1fr auto 12px;
    align-items: center;
    gap: var(--vx-space-m);
    cursor: pointer;
    transition: background var(--vx-duration-fast) var(--vx-ease);
}
.settings-rows .settings-row + .settings-row { border-top: var(--vx-border) solid rgb(var(--vx-line)); }
.settings-rows .settings-row:hover,
.settings-rows .settings-row:active { background: rgb(var(--vx-sunken)); }
.settings-rows .settings-row.danger,
.settings-rows .settings-row.danger:hover,
.settings-rows .settings-row.danger:active { color: rgb(var(--vx-bad-ink)); }

.settings-row-icon { display: flex; color: rgb(var(--vx-ink-secondary)); }
.settings-row-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.settings-row.danger .settings-row-icon { color: inherit; }
.settings-row-label { font-weight: var(--vx-weight-medium); }
.settings-row-value {
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-label);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 14rem;
}
.settings-row-chevron { color: rgb(var(--vx-ink-faint)); font-size: 20px; line-height: 1; }

/* The panel a row opens. A dialog, so Escape and focus trapping come free. */
.settings-panel {
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius-large);
    padding: var(--vx-space-l);
    width: min(100% - 2rem, 26rem);
    background: rgb(var(--vx-surface));
    color: rgb(var(--vx-ink));
    box-shadow: var(--vx-shadow-float);
}
.settings-panel::backdrop { background: rgb(var(--vx-overlay) / var(--vx-overlay-alpha)); }
.settings-panel[open] { animation: vx-in var(--vx-duration) var(--vx-ease) both; }
.settings-panel h2 { font-size: var(--vx-text-title); margin: 0 0 var(--vx-space-m); }
.settings-panel label { margin-top: var(--vx-space-m); }
.settings-panel .lede { font-size: var(--vx-text-label); margin-bottom: var(--vx-space-s); }
.settings-panel .hint { color: rgb(var(--vx-ink-secondary)); font-size: var(--vx-text-micro); margin: var(--vx-space-xs) 0 0; }
.settings-panel-actions {
    display: flex;
    gap: var(--vx-space-s);
    justify-content: flex-end;
    margin-top: var(--vx-space-l);
}
.settings-panel-actions button { min-height: var(--vx-control-h-sm); }

.settings-choices { display: grid; gap: var(--vx-space-xs); }
.settings-choice {
    display: flex;
    align-items: center;
    gap: var(--vx-space-s);
    padding: var(--vx-space-s) var(--vx-space-m);
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius);
    cursor: pointer;
    font-size: var(--vx-text-body);
    color: rgb(var(--vx-ink));
    margin: 0;
}
.settings-choice:has(input:checked) {
    border-color: rgb(var(--vx-accent));
    background: rgb(var(--vx-accent-wash));
}
.settings-choice input { width: auto; min-height: 0; margin: 0; }

.settings-list { display: grid; gap: 0; border: var(--vx-border) solid rgb(var(--vx-line)); border-radius: var(--vx-radius); margin-bottom: var(--vx-space-m); }
.settings-list-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--vx-space-s);
    padding: var(--vx-space-s) var(--vx-space-m);
    font-size: var(--vx-text-label);
}
.settings-list-row + .settings-list-row { border-top: var(--vx-border) solid rgb(var(--vx-line)); }

/* ─────────────────────────────────────────────────── Onboarding */

/*
 * Owns the whole viewport until first-time setup is finished. The page under
 * it never draws, so nothing behind needs hiding; the overlay is the page.
 */
.onboarding {
    position: fixed;
    inset: 0;
    z-index: var(--vx-z-modal);
    display: grid;
    place-items: center;
    padding: var(--vx-space-m);
    background: rgb(var(--vx-page));
    overflow: auto;
}

.onboarding-card {
    width: 100%;
    max-width: 30rem;
    background: rgb(var(--vx-surface));
    border: var(--vx-border) solid rgb(var(--vx-line));
    border-radius: var(--vx-radius-large);
    padding: var(--vx-space-xl);
}

.onboarding-card .brand { height: 26px; margin-bottom: var(--vx-space-l); }
.onboarding-card h1 { font-size: var(--vx-text-title); margin-bottom: var(--vx-space-s); }
.onboarding-card h2 { font-size: var(--vx-text-label); margin: var(--vx-space-m) 0 var(--vx-space-s); }
.onboarding-card .lede { font-size: var(--vx-text-label); margin-bottom: var(--vx-space-m); }
.onboarding-card label { margin-top: var(--vx-space-m); }
.onboarding-card button { width: 100%; margin-top: var(--vx-space-m); }
.onboarding-card .hint {
    color: rgb(var(--vx-ink-secondary));
    font-size: var(--vx-text-micro);
    margin: var(--vx-space-xs) 0 0;
    min-height: 1.2em;
}
.onboarding-card .tiles { margin: var(--vx-space-m) 0 0; }
.onboarding-card .tile button { margin-top: var(--vx-space-s); }

/*
 * The three steps, as a row of labels. Numbered in the DOM (an <ol>) because
 * these ARE a sequence; drawn without visible numerals because the labels
 * already say what each one is and the current one is marked by colour.
 */
.onboarding-steps {
    display: flex;
    gap: var(--vx-space-m);
    list-style: none;
    margin: 0 0 var(--vx-space-l);
    padding: 0;
    font-size: var(--vx-text-micro);
    text-transform: uppercase;
    letter-spacing: var(--vx-tracking-caps);
    color: rgb(var(--vx-ink-faint));
}
.onboarding-steps li { position: relative; padding-bottom: var(--vx-space-xs); }
.onboarding-steps li::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
    border-radius: 1px;
    background: rgb(var(--vx-line));
}
.onboarding-steps li.done { color: rgb(var(--vx-ink-secondary)); }
.onboarding-steps li.done::after { background: rgb(var(--vx-accent-ink)); }
.onboarding-steps li.current { color: rgb(var(--vx-accent-ink)); font-weight: var(--vx-weight-bold); }
.onboarding-steps li.current::after { background: rgb(var(--vx-accent)); }

.ob-invites { display: grid; gap: var(--vx-space-s); }
.ob-invite {
    text-align: left;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-height: auto;
    padding: var(--vx-space-s) var(--vx-space-m);
    margin-top: 0 !important;
}
.ob-invite .hint { margin: 0; }

/* ──────────────────────────────────────────────── The animations */

/*
 * The whole motion vocabulary of the product, and there is deliberately not
 * much of it. Three things move: something arriving, a list arriving one row
 * after another, and something that is loading.
 *
 * Everything else is a state change on something already on screen, which is
 * a transition on the property itself and lives with the component.
 *
 * A screen that animates more than this does not feel more alive; it feels
 * slower, because every one of these costs the reader a moment of waiting for
 * the page to settle before they can act.
 */

@keyframes vx-in {
    from { opacity: 0; transform: translateY(var(--vx-lift)); }
    to   { opacity: 1; transform: none; }
}

/** Something arriving: a panel, a card, a notice. */
.vx-in {
    animation: vx-in var(--vx-duration) var(--vx-ease) both;
}

/**
 * A list arriving.
 *
 * The stagger is capped at six because it is a courtesy, not a feature: past
 * that the last row is waiting on an animation nobody is watching, and a table
 * of forty rows would take two seconds to finish appearing.
 */
.vx-stagger > * { animation: vx-in var(--vx-duration) var(--vx-ease) both; }
.vx-stagger > *:nth-child(1) { animation-delay: 0ms; }
.vx-stagger > *:nth-child(2) { animation-delay: 30ms; }
.vx-stagger > *:nth-child(3) { animation-delay: 60ms; }
.vx-stagger > *:nth-child(4) { animation-delay: 90ms; }
.vx-stagger > *:nth-child(5) { animation-delay: 120ms; }
.vx-stagger > *:nth-child(n+6) { animation-delay: 150ms; }

/** Waiting. A pulse, not a spinner: nothing here takes long enough for one. */
@keyframes vx-pulse {
    50% { opacity: .5; }
}
.vx-loading {
    animation: vx-pulse 1.2s var(--vx-ease) infinite;
    pointer-events: none;
}

/*
 * Reduced motion is handled in tokens.css by taking the durations to almost
 * nothing, which covers every rule above at once. Repeating a blanket
 * `* { animation: none }` here would also kill the fade, leaving content to
 * pop in - the jarring thing the setting exists to avoid.
 */
