/* ============================================================
   account_settings.css
   ============================================================
   Owns /settings/* surfaces: profile edit, theme picker,
   connected music providers, notification preferences.

   Includes:
     - pr41 settings console shell: two-column layout with the
       left rail of grouped sections, used by /settings/profile,
       /settings/music, /settings/notifications, etc.
     - pwa5 notifications-settings page chrome: subscription
       pills, permission states, and browser-support detection
       messaging under /settings/notifications.

   Reference: markdown/design/DESIGN_DECISIONS_CSS_REFACTOR.md
   ============================================================ */

/* ============================================================
   pr41 — settings console
   ============================================================
   Two-column layout for the /settings/* surface, modeled directly
   on the admin console (.admin-console) above. Distinct visual
   class names (.account-*) so future divergence between admin and
   account chrome doesn't require untangling shared rules.

   Surfaces:
     /settings/                — overview (summary cards + inline
                                 visibility editor)
     /settings/profile         — edit display name, bio, avatar
     /settings/free-space      — edit profile free-space cell
     /settings/password        — change password (non-forced flow)

   Forced-change-password flow keeps its own minimal layout — it
   does NOT extend account/base.html.

   Token discipline: every color, radius, spacing here is a var()
   reference. Dark mode inherits for free via the existing
   prefers-color-scheme block.

   Mobile: below 720px the rail stacks above content (same as admin).
   Below 920px the summary-card grid drops from 2-up to 1-up before
   the rail breaks, so the cards never get uncomfortably narrow.
   ============================================================ */

.account-console {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: var(--space-5);
    max-width: 1400px;
    margin: var(--space-5) auto;
    padding: 0 var(--space-4);
    align-items: start;
}

/* ---- Left rail ---- */

.account-rail {
    position: sticky;
    top: var(--space-5);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.account-rail-header {
    padding: var(--space-2) var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Yellow label, matching the admin rail's "internal controls" feel.
   Communicates "you're in a controls surface, not the main app." */
.account-rail-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.14em;
    color: var(--color-warning);
    text-transform: uppercase;
}

.account-rail-sub {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* Section group label — small, all-caps, muted. Mirrors .admin-rail-group. */
.account-rail-group {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: var(--space-3) var(--space-2) var(--space-1);
}

.account-rail-link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 8px 10px;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    text-decoration: none;
    border-radius: var(--radius-sm);
    border-left: 2px solid transparent;
    transition:
        background var(--transition-fast),
        color var(--transition-fast),
        border-color var(--transition-fast);
}

.account-rail-link:hover {
    background: var(--color-bg-subtle);
    color: var(--color-text);
}

.account-rail-link.is-active {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--color-text);
    border-left-color: var(--color-accent);
}

/* "soon" stubs — rendered as <span> in the template, this just adds
   the visual cue and the right-aligned pill. */
.account-rail-link.is-disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.account-rail-link.is-disabled::after {
    content: 'soon';
    margin-left: auto;
    font-size: 9px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    padding: 1px 6px;
    background: var(--color-bg-subtle);
    border-radius: var(--radius-pill);
}

.account-rail-link.is-disabled:hover {
    background: transparent;
}

/* ---- Content column ---- */

.account-content {
    min-width: 0;
    /* min-width: 0 prevents grid items from refusing to shrink when
       their content is wider than the column — same reasoning as
       .admin-content. */
}

/* Console-style page header shared across all /settings/* pages.
   h1 left, muted meta right. Sits above the section body content. */
.account-console-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.account-console-head h1 {
    font-size: 1.1rem;
    font-weight: var(--font-weight-semibold);
    margin: 0;
}

.account-console-head .crumbs {
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
}

/* Subtitle below the head, prose-style. Used on sub-pages
   (profile, free-space, password) per the section-header pattern. */
.account-console-subtitle {
    color: var(--color-text-muted);
    font-size: var(--font-size-body);
    margin-top: -10px;
    margin-bottom: var(--space-4);
}

/* ---- Summary card grid (overview page only) ---- */

.summary-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.summary-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.summary-card .label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.summary-card .value {
    font-size: 1rem;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
}

.summary-card .description {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* Edit-link row pinned to the bottom of the card so all four cards
   align their action rows regardless of body content length. */
.summary-card .actions {
    margin-top: auto;
    padding-top: var(--space-2);
}

.summary-card a.edit-link,
.summary-card button.edit-link {
    font-size: var(--font-size-base);
    color: var(--color-accent);
    text-decoration: none;
    font-weight: var(--font-weight-medium);
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.summary-card a.edit-link:hover,
.summary-card button.edit-link:hover {
    text-decoration: underline;
}

/* Disabled-style "edit-link" used by read-only cards (e.g. account
   status). Inherits the link shape but rendered muted and inert. */
.summary-card .edit-link.is-inert {
    color: var(--color-text-muted);
    cursor: default;
}

.summary-card .edit-link.is-inert:hover {
    text-decoration: none;
}

/* ---- Summary pills (inline state badges) ---- */

.summary-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    border-radius: var(--radius-pill);
    background: var(--color-bg-subtle);
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    letter-spacing: 0.05em;
    text-transform: lowercase;
}

.summary-pill.is-public {
    background: color-mix(in srgb, var(--color-success) 15%, transparent);
    color: var(--color-success);
}

.summary-pill.is-private {
    background: color-mix(in srgb, var(--color-text-muted) 18%, transparent);
    color: var(--color-text-muted);
}

.summary-pill.is-warn {
    background: color-mix(in srgb, var(--color-warning) 18%, transparent);
    color: color-mix(in srgb, var(--color-warning) 75%, var(--color-text));
}

.summary-pill.is-admin {
    background: color-mix(in srgb, var(--color-accent) 15%, transparent);
    color: var(--color-accent);
}

/* ---- Inline editor (the visibility radios on /settings/) ---- */

.inline-editor {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    /* scroll-margin-top so the #privacy anchor doesn't slide under
       the sticky navbar when jumped to from the visibility rail link. */
    scroll-margin-top: 80px;
}

.inline-editor h2 {
    font-size: 0.95rem;
    font-weight: var(--font-weight-semibold);
    margin: 0 0 4px;
}

.inline-editor .hint {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    margin-bottom: var(--space-3);
}

/* Each editor-row is a labeled group of radios separated by a thin
   border. First row's top border is suppressed so the heading hugs it. */
.editor-row {
    padding: var(--space-3) 0;
    border-top: 1px solid var(--color-border);
}

.editor-row:first-of-type {
    border-top: 0;
    padding-top: 0;
}

.editor-row .form-label {
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--space-2);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.editor-row-actions {
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
    text-align: right;
}

/* ---- Sub-page section wrapper ---- */

/* Used by /settings/profile, /settings/free-space, /settings/password
   to wrap their existing form cards in the same console-shell padding
   and surface treatment as the overview's inline-editor. Page-specific
   form internals stay untouched. */
.account-section {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
}

/* inv1-followup -- admin invite-request queue splits pending into
   two side-by-side columns (sponsored / unsponsored) so admin can
   triage both lanes at once without scrolling. Collapses to 1-up at
   the same breakpoint as the rest of the admin console so cards
   don't get cramped. */
.invite-requests-pending-grid {
    display: grid;
    /* inv3-pr-c-3 -- third column for boost requests wedged into
       the same triage surface. 1fr 1fr 1fr is denser than the
       prior 1fr 1fr but the boost-request row is narrower (no
       sponsor line + shorter note typical) so the columns balance
       reasonably even on a 1280-wide viewport. */
    grid-template-columns: 1fr 1fr 1fr;
    gap: var(--space-4);
}

/* Collapse to 2-up at the breakpoint where 3 columns would start
   getting cramped, then to 1-up at the narrow break. */
@media (max-width: 1200px) {
    .invite-requests-pending-grid {
        grid-template-columns: 1fr 1fr;
    }
}
@media (max-width: 920px) {
    .invite-requests-pending-grid {
        grid-template-columns: 1fr;
    }
}

/* ---- Mobile ---- */

/* Cards collapse to 1-up before the rail breaks, so we never get
   thin 110-px cards on a 720-810px viewport. */
@media (max-width: 920px) {
    .summary-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 720px) {
    .account-console {
        grid-template-columns: 1fr;
    }
    .account-rail {
        position: static;
    }
}

/* === === === pwa5 notifications settings page (phase 13) === === === */

/*
   Page-specific styles for /settings/notifications. Uses the
   .push-prefs-* prefix to avoid colliding with the in-app
   .notifications-page selector on /notifications/.

   Lives inside the .account-content rail layout. Most surface
   styling (cards, labels, pills) is inherited from the existing
   .inline-editor / .editor-row infrastructure (pr41).

   New widgets specific to this page:
     - hero card (zero-devices CTA)
     - device row with inline-edit nickname
     - group master toggle (cursor hint of clickability)
     - disabled-toggle visual state for has_subs=False
*/

/* ---- Hero card (zero-subs CTA) ---- */

.push-prefs-hero {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-5) var(--space-4);
    text-align: center;
    margin-bottom: var(--space-4);
}

.push-prefs-hero h2 {
    font-size: 1.1rem;
    font-weight: var(--font-weight-semibold);
    margin: 0 0 var(--space-2);
}

.push-prefs-hero p {
    margin-bottom: var(--space-3);
}

.push-prefs-hero-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    color: var(--color-accent);
    margin-bottom: var(--space-3);
}

/* ---- Banners (alert variants — flex layout for icon + text) ---- */

.push-prefs-banner {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
}

.push-prefs-banner svg {
    flex-shrink: 0;
    margin-top: 2px;
}

/* ---- Device row inline rename ---- */
/* Display span gets a dashed underline on hover to hint at
   double-click-to-edit. The input renders compactly via
   .form-control-sm (Bootstrap). */

.device-nickname {
    cursor: pointer;
    border-bottom: 1px dashed transparent;
    transition: border-color 0.15s ease;
}

.device-nickname:hover {
    border-bottom-color: var(--color-border);
}

.device-nickname-input {
    max-width: 280px;
}

/* ---- Group master + toggle list ---- */
/* Group master is the label itself (data-master-for). Cursor
   pointer signals clickability; user-select none prevents accidental
   text selection on rapid clicks. The toggle-list is indented to
   visually associate children with the master. */

.push-prefs-group-master {
    cursor: pointer;
    user-select: none;
}

.push-prefs-master-checkbox {
    margin-right: var(--space-2);
}

.push-prefs-toggle-list {
    padding-left: var(--space-4);
}

.push-prefs-toggle-row {
    padding: var(--space-1) 0;
}

.push-prefs-toggle-row.is-disabled {
    opacity: 0.55;
}

.push-prefs-toggle-row.is-disabled .form-check-label {
    cursor: not-allowed;
}


/* ============================================================
   pal1 — Palette picker mini-preview cards
   ============================================================
   Renders the 6 palette options as a grid of mini-app previews so
   the user sees what they're picking before they commit. Each card
   carries its own data-palette and data-theme="dark" attributes so
   the palette-specific selector blocks in tokens.css fire INSIDE
   the card, regardless of what palette the rest of the page is in.

   This works because tokens.css [data-palette="X"] selectors match
   ANY element with that attribute — not just <html>. So
   <div data-palette="cherry-bomb" data-theme="dark"> creates a
   scoped pink-themed context for everything inside that div.

   Mini wordmark cursor reuses the navbar-brand-blink keyframe from
   navbar.css so the animation behavior stays consistent +
   the existing prefers-reduced-motion guard applies.
   ============================================================ */

.palette-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}

.palette-picker-option {
    cursor: pointer;
    margin: 0;
    display: block;
}

.palette-picker-radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.palette-picker-card {
    background: #0a0a0a;
    border: 1px solid #1a1a1a;
    border-radius: 10px;
    overflow: hidden;
    transition: border-color var(--transition-medium),
                box-shadow var(--transition-medium),
                transform var(--transition-fast);
}

.palette-picker-option:hover .palette-picker-card {
    transform: translateY(-1px);
    border-color: var(--color-border);
}

.palette-picker-radio:checked + .palette-picker-card {
    border-color: var(--color-accent);
    box-shadow:
        0 0 0 1px rgba(var(--color-halo-rgb), 0.4),
        0 0 16px 2px rgba(var(--color-halo-rgb), 0.15);
}

.palette-picker-nav {
    background: var(--color-bg-navbar);
    padding: 8px 10px;
    border-bottom: 1px solid #0a0a0a;
}

.palette-picker-wordmark {
    font-family: var(--font-display, 'VT323'), monospace;
    font-size: 16px;
    color: #d8d2c2;
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
}

.palette-picker-prompt {
    color: #7a7a7a;
    margin-right: 4px;
}

.palette-picker-cursor {
    display: inline-block;
    width: 6px;
    height: 14px;
    background: var(--color-accent);
    margin-left: 3px;
    vertical-align: -2px;
    animation: navbar-brand-blink 1.06s steps(2, end) infinite;
}

.palette-picker-body {
    padding: 10px;
    background: #000;
}

.palette-picker-post {
    background: #141414;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 8px 10px;
    margin-bottom: 8px;
    box-shadow:
        0 0 0 1px rgba(var(--color-halo-rgb), 0.18),
        0 0 14px 2px rgba(var(--color-halo-rgb), 0.07);
}

.palette-picker-post-author {
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 500;
    color: #d8d2c2;
    margin-bottom: 3px;
}

.palette-picker-post-body {
    font-family: var(--font-sans);
    font-size: 11px;
    color: #d8d2c2;
}

.palette-picker-mention {
    color: var(--color-accent);
    font-weight: 500;
}

.palette-picker-btn-row {
    display: flex;
    justify-content: flex-end;
}

.palette-picker-btn {
    font-family: var(--font-display, 'VT323'), monospace;
    font-size: 13px;
    background: var(--color-accent);
    color: var(--color-on-accent);
    border: 2px solid var(--color-accent-outline);
    border-radius: 6px;
    padding: 3px 12px;
    letter-spacing: 0.02em;
    box-shadow:
        0 0 0 1px rgba(var(--color-halo-rgb), 0.4),
        0 0 12px 2px rgba(var(--color-halo-rgb), 0.15);
}

.palette-picker-label {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    color: var(--color-text-muted);
    text-align: center;
}

.palette-picker-radio:checked ~ .palette-picker-label {
    color: var(--color-text);
    font-weight: 500;
}

@media (prefers-reduced-motion: reduce) {
    .palette-picker-cursor {
        animation: none;
    }
    .palette-picker-option:hover .palette-picker-card {
        transform: none;
    }
}

/* ============================================================
   Coming-soon placeholder palette cards (pal1 followup).

   Two non-submittable placeholders rendered at the end of the
   picker grid — visual hooks for upcoming features (random color
   scheme, seasonal theme). Shape matches the operational cards
   so users get a real sense of what'll ship; the muted state +
   center pill signal it's not interactive yet.

   When the actual features ship, drop the --soon modifier, wire
   the real radio input, and add the value to USER_PALETTES +
   AppearanceForm.palette.choices.
   ============================================================ */
.palette-picker-option--soon {
    cursor: not-allowed;
    position: relative;
}

/* Mute the inner card — pointer-events:none blocks hover-translate
   AND prevents the children from showing as interactive. The pill
   sits OUTSIDE the muted card subtree so it stays at full opacity
   and remains legible. */
.palette-picker-option--soon .palette-picker-card {
    pointer-events: none;
    opacity: 0.45;
    filter: grayscale(0.6);
}

.palette-picker-option--soon .palette-picker-label {
    opacity: 0.6;
    font-style: italic;
}

/* Center pill — overlays the card to communicate state without
   needing to redesign the card itself. Border + bg keep it
   legible against any palette accent showing through. */
.palette-picker-soon-pill {
    position: absolute;
    top: 50%;
    left: 50%;
    /* Slight upward bias so the pill centers on the CARD visually,
       not on the option wrapper (which also includes the bottom
       label). 16px == half the label row's vertical contribution. */
    transform: translate(-50%, calc(-50% - 16px));
    background: rgba(0, 0, 0, 0.85);
    color: #f6efe2;
    font-family: var(--font-display, 'VT323'), monospace;
    font-size: 13px;
    letter-spacing: 0.04em;
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    white-space: nowrap;
    text-transform: lowercase;
    pointer-events: none;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}

/* ============================================================
   inv2-pr-a -- /settings/invite mint surface.

   The mint page rolls its own quota block + code-row layout
   because the rest of /settings/* doesn't have a "list of things
   with side actions" pattern -- everything else is a form. Once
   another /settings page needs a similar list (likely candidates:
   /settings/sessions when that ships, content-blocks if we move
   it out of audience), extract .invite-code-row into a shared
   .settings-list-row class.
   ============================================================ */

.invite-quota-block {
    /* Override default .inline-editor inner padding rhythm since
       this is a one-row callout, not a form. */
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.invite-quota-row {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.invite-quota-summary {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex: 1 1 auto;
    min-width: 0;
}

.invite-quota-chip {
    /* Read-the-room sizing: big enough to be the page's anchor,
       not so big it shouts. Mirrors the .summary-pill density
       used elsewhere on the console. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 6px 14px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-elevated, rgba(255, 255, 255, 0.04));
    font-family: var(--font-display, 'VT323'), monospace;
    font-size: 18px;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

.invite-quota-chip.has-quota {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.invite-quota-chip.is-empty {
    /* Don't make "0 / 5" scary. The empty state isn't an error;
       it's a "wait for the timer" cue. Muted is enough. */
    opacity: 0.65;
}

.invite-quota-meta {
    min-width: 0;
}

.invite-quota-headline {
    font-weight: 600;
}

.invite-quota-refill {
    margin-top: 2px;
}

.invite-mint-form {
    flex: 0 0 auto;
}

.invite-code-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.invite-code-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg-elevated, rgba(255, 255, 255, 0.03));
    flex-wrap: wrap;
}

.invite-code-main {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    min-width: 0;
    flex: 1 1 auto;
}

.invite-code-value {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 15px;
    padding: 2px 8px;
    background: var(--color-bg, rgba(0, 0, 0, 0.15));
    border-radius: 4px;
    /* Don't let a long code overflow the row -- they're URL-safe
       base64 so word-break: break-all is safe. */
    word-break: break-all;
}

.invite-code-value.is-used {
    /* Strikethrough is too aggressive; muted-italic is enough to
       signal "this one's spent." */
    opacity: 0.65;
}

.invite-code-meta {
    /* Stays on the same row as the code on wide screens; wraps
       under it at narrow widths via the parent's align-items:
       baseline + min-width: 0 trick. */
    white-space: nowrap;
}

.invite-code-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 auto;
}

/* inv3-pr-c-2 -- redemption progress pips on the active code. One
   pip per max_uses slot; filled state for each redemption. Sits
   below the code-value row as a visual reinforcement of the
   "N of M used" text. Aria-hidden in the template because the
   text counter is the screen-reader source of truth. */
.invite-progress-pips {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.invite-pip {
    display: inline-block;
    width: 18px;
    height: 6px;
    border-radius: 999px;
    background: var(--color-border);
    transition: background-color 0.2s ease;
}

.invite-pip.is-filled {
    background: var(--color-accent);
}

/* inv3-pr-c-2 -- post-refill banner. Sits between the page header
   and the quota block when the user's quota refilled past the
   active code's max_uses snapshot. Inherits the Bootstrap
   alert-warning styling so it looks like a normal page-level
   advisory; the copy itself is the personality. */
.invite-refill-banner {
    margin-bottom: var(--space-3);
}

/* inv3-pr-c-3 -- "request more invites" section + pending-state
   note quote. Quotes the user's submitted note back at them so
   they remember what they asked for while it sits in the admin
   queue. */
.invite-boost-note {
    border-left: 3px solid var(--color-border);
    padding-left: var(--space-2);
    font-style: italic;
}

@media (max-width: 600px) {
    .invite-quota-row {
        flex-direction: column;
        align-items: stretch;
    }

    .invite-mint-form .btn {
        width: 100%;
    }

    .invite-code-row {
        flex-direction: column;
        align-items: stretch;
    }

    .invite-code-actions {
        justify-content: flex-end;
    }
}

/* ============================================================
   ux-color-fu -- surprise-me palette card + action panel.

   Replaces the "random — coming soon" placeholder. The card
   itself reuses the .palette-picker-option chrome (so it sits
   visually with the 6 named cards), with a centered button
   overlaid on the card body to invite the click.
   ============================================================ */

.palette-picker-option--surprise {
    position: relative;
}

.palette-picker-option--surprise .palette-picker-card {
    /* Hint that this card is interactive without being identical
       to the radio cards -- a dashed border telegraphs "this is a
       different kind of action." */
    border-style: dashed;
    border-color: var(--color-accent);
    cursor: default;
}

.palette-picker-surprise-btn {
    /* Centered overlay button -- same visual treatment as the
       soon-pill so the card layout stays balanced. */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, calc(-50% - 16px));
    background: var(--color-accent);
    color: var(--color-on-accent);
    border: 1px solid var(--color-border);
    font-family: var(--font-display, "VT323"), monospace;
    font-size: 14px;
    letter-spacing: 0.04em;
    padding: 6px 14px;
    border-radius: 999px;
    cursor: pointer;
    transition: background-color 0.2s ease;
    white-space: nowrap;
}

.palette-picker-surprise-btn:hover:not([disabled]) {
    background: var(--color-accent-hover);
}

.palette-picker-surprise-btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

.palette-surprise-panel {
    /* Reuse the .invite-boost-block padding/border treatment via
       composition rather than re-declaring. */
}

/* ============================================================
   ux-nitpick — dashboard music radio stack
   ============================================================
   /settings/music's au2 "dashboard music" section ships its
   options as bare <label class="home-audio-option"> rows, with
   no rules anywhere. Label defaults to inline, so the options
   read as one prose blob instead of a stacked menu. These rules
   flip the container to a column flex and align each option's
   radio + label as a row.
   ============================================================ */

.home-audio-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.home-audio-option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    cursor: pointer;
}

.home-audio-option input[type="radio"] {
    margin-top: var(--space-1);
    flex-shrink: 0;
}
