/* =============================================================================
   AeroRemote — application shell & design system
   -----------------------------------------------------------------------------
   Written mobile-first: every base rule describes the phone, and the handful of
   min-width blocks only widen the measure. The `ar-` namespace is deliberate —
   it replaces the old dashboard chrome rather than fighting it, so the legacy
   rules in styles.css simply stop matching.
   ========================================================================== */

/* ---------- Tokens ------------------------------------------------------- */

:root {
    /* Surfaces: flat and quiet. Depth comes from borders, not from glass. */
    /* --ar-bg is the sheet: the centred column the app is actually written on.
       --ar-page is everything beside it. In dark the relationship inverts — the
       page lifts and the column stays the darkest thing on screen. */
    --ar-bg: #0b0c0e;
    --ar-page: #1b1e23;
    --ar-surface: #131518;
    --ar-surface-2: #1b1e22;
    --ar-surface-hi: #23272c;

    --ar-line: rgba(255, 255, 255, 0.10);
    --ar-line-strong: rgba(255, 255, 255, 0.20);

    --ar-ink: #f2f4f6;
    --ar-ink-2: #9ba3ab;
    /* ink-3 carries 11-13px type (the step counter, cross labels, byte count),
       so it has to clear 4.5:1 on --ar-surface, not merely look quiet. */
    --ar-ink-3: #8b949c;

    --ar-accent: #22c9e6;
    --ar-accent-hi: #4fd8f0;
    --ar-accent-ink: #05191f;
    --ar-accent-wash: rgba(34, 201, 230, 0.12);
    --ar-accent-line: rgba(34, 201, 230, 0.45);

    --ar-ok: #34d399;
    --ar-warn: #fbbf24;
    --ar-danger: #f87171;
    --ar-warn-wash: rgba(251, 191, 36, 0.10);
    --ar-danger-wash: rgba(248, 113, 113, 0.10);

    /* Spacing — 4px base. The gap says how strong the break is:
       1-2 inside a control · 3-4 between controls in a group ·
       6 between groups · 10 between sections · 12 before the page ends. */
    --ar-1: 0.25rem;
    --ar-2: 0.5rem;
    --ar-3: 0.75rem;
    --ar-4: 1rem;
    --ar-5: 1.25rem;
    --ar-6: 1.5rem;
    --ar-8: 2rem;
    --ar-10: 2.5rem;
    --ar-12: 3rem;

    /* Type — six steps, each with one job. No loose font-size values anywhere:
       if something needs a size, it needs one of these. */
    --ar-t-display: 1.625rem;  /* step titles, the done screen (2rem >= 40rem) */
    --ar-t-title:   1.25rem;   /* section headings, manual h2                 */
    --ar-t-body:    1rem;      /* paragraphs, row titles, inputs              */
    --ar-t-label:   0.875rem;  /* field labels, buttons, tabs, selects        */
    --ar-t-meta:    0.8125rem; /* help text, row subtitles, captions          */
    --ar-t-micro:   0.6875rem; /* eyebrow, cross labels, badges — always caps */

    --ar-w-regular: 400;
    --ar-w-medium:  550;
    --ar-w-semi:    600;
    --ar-w-bold:    700;

    /* Control heights — three, matched to role. */
    --ar-h-sm: 2.25rem;  /* 36px — chips, small buttons, selects, row actions  */
    --ar-h-md: 2.75rem;  /* 44px — primary controls, icon buttons, tap minimum */
    --ar-h-lg: 3.5rem;   /* 56px — list rows                                   */

    /* Radii — three, plus the pill. */
    --ar-r-sm: 0.5rem;   /*  8px — small controls, checkboxes, keys            */
    --ar-r: 0.75rem;     /* 12px — cards, lists, panels                        */
    --ar-r-pill: 999px;  /*        chips, mode switch, status                  */

    /* One measure for the whole app. The top bar, the content and the action bar
       all use it, so their left and right edges line up at every width and in
       both views — the bar never changes width when you switch view. Prose is
       capped separately in ch, so a wide column does not mean long lines. */
    --ar-measure: 34rem;
    --ar-gutter: var(--ar-4);

    /* Two relationships repeat in all three views, so they get a token each and
       cannot drift: the gap under the mode switch, and heading -> its content. */
    --ar-gap-mode: var(--ar-6);
    --ar-gap-head: var(--ar-5);

    --ar-topbar-h: 3.5rem;
    --ar-tap: var(--ar-h-md);

    --ar-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    --ar-shadow-up: 0 -1px 0 var(--ar-line), 0 -8px 24px rgba(0, 0, 0, 0.35);
    --ar-ease: 150ms cubic-bezier(0.2, 0, 0, 1);
}

:root[data-theme="light"] {
    --ar-bg: #ffffff;
    --ar-page: #e8ecf1;
    --ar-surface: #f7f9fb;
    --ar-surface-2: #eef2f6;
    --ar-surface-hi: #e4eaf0;

    --ar-line: rgba(10, 22, 32, 0.12);
    --ar-line-strong: rgba(10, 22, 32, 0.24);

    --ar-ink: #0e1519;
    --ar-ink-2: #566370;
    --ar-ink-3: #6b7681;

    --ar-accent: #0284a4;
    --ar-accent-hi: #026b86;
    --ar-accent-ink: #ffffff;
    --ar-accent-wash: rgba(2, 132, 164, 0.09);
    --ar-accent-line: rgba(2, 132, 164, 0.38);

    --ar-ok: #059669;
    --ar-warn: #b45309;
    --ar-danger: #dc2626;
    --ar-warn-wash: rgba(180, 83, 9, 0.09);
    --ar-danger-wash: rgba(220, 38, 38, 0.08);

    --ar-shadow: 0 1px 2px rgba(10, 22, 32, 0.08);
    --ar-shadow-up: 0 -1px 0 var(--ar-line), 0 -8px 24px rgba(10, 22, 32, 0.06);
}

/* ---------- Base --------------------------------------------------------- */

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--ar-page);
    color: var(--ar-ink);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-size: var(--ar-t-body);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
}

/* The old sheet paints a decorative gradient wash over the whole page. */
body::before {
    display: none !important;
}

body,
.ar-app {
    height: 100dvh;
}

@supports not (height: 100dvh) {
    body,
    .ar-app {
        height: 100vh;
    }
}

/* Phone: a fixed-height shell. Only the middle row scrolls, so the top bar and
   the action bar stay put without any fixed positioning, and the primary action
   is always in thumb reach. Desktop switches to a normal document (see below). */
.ar-app {
    display: grid;
    grid-template-rows: auto auto 1fr auto;
    overflow: hidden;
}

/* The top bar and the action bar sit outside the scroller, so they do not lose
   width to its reserved scrollbar gutter. Above the measure that is invisible —
   every column centres to the same place — but below it each fills its own box
   and the bars end up 15px wider on each side than the content. `--ar-sbw` is
   measured from the live scroller (0 with overlay scrollbars) and pads it back. */
.ar-topbar,
.ar-actions {
    padding-inline: var(--ar-sbw, 0px);
}

.ar-scroll {
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Reserve the scrollbar on both sides: the top bar sits outside this scroller,
       so a one-sided gutter would shift the content column a few pixels out of
       line with it. */
    scrollbar-gutter: stable both-edges;
}

/* Every region full-bleeds the page colour and paints the sheet as one centred
   band exactly as wide as the measure, so the column reads as a single unbroken
   sheet running from the top bar through the content into the action bar.
   The band is a background, not a box on .ar-col: that way it ignores each
   region's own padding and fills a scroller whose content is shorter than it is.
   Below the measure the band covers everything and the page colour never shows. */
.ar-topbar,
.ar-navbar,
.ar-main,
.ar-actions {
    background-color: var(--ar-page);
    background-image: linear-gradient(var(--ar-bg), var(--ar-bg));
    background-repeat: no-repeat;
    background-position: center top;
    background-size: min(100%, var(--ar-measure)) 100%;
}

/* Every region shares one column so the bar, the content and the actions line
   up on the same two edges at any width. */
.ar-col {
    width: 100%;
    max-width: var(--ar-measure);
    margin-inline: auto;
    padding-inline: var(--ar-gutter);
}

/* ---------- Typography --------------------------------------------------- */

.ar-eyebrow {
    margin: 0 0 var(--ar-2);
    font-size: var(--ar-t-meta);
    font-weight: var(--ar-w-semi);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ar-ink-3);
}

.ar-title {
    margin: 0;
    font-size: var(--ar-t-display);
    line-height: 1.2;
    font-weight: var(--ar-w-bold);
    letter-spacing: -0.02em;
    color: var(--ar-ink);
    text-wrap: balance;
}

.ar-lede {
    margin: var(--ar-3) 0 0;
    color: var(--ar-ink-2);
    font-size: var(--ar-t-body);
}

.ar-h2 {
    margin: 0;
    font-size: var(--ar-t-title);
    font-weight: var(--ar-w-semi);
    letter-spacing: -0.01em;
}

.ar-muted {
    color: var(--ar-ink-2);
}

.ar-small {
    font-size: var(--ar-t-meta);
}

/* ---------- Top bar ------------------------------------------------------ */

.ar-topbar {
    border-bottom: 1px solid var(--ar-line);
}

.ar-topbar__col {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ar-2);
    row-gap: var(--ar-2);
    min-height: var(--ar-topbar-h);
    padding-block: var(--ar-2);
}

/* The tabs take their own row on a phone, which leaves room for the name beside
   the status. Only the byline drops. */
.ar-topbar__brand {
    display: flex;
    align-items: baseline;
    gap: var(--ar-2);
    min-width: 0;
}

.ar-topbar__name {
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-bold);
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.ar-topbar__by {
    display: none;
    font-size: var(--ar-t-meta);
    color: var(--ar-ink-3);
}

.ar-topbar__by a {
    color: inherit;
}

.ar-topbar__tools {
    display: flex;
    align-items: center;
    gap: var(--ar-1);
    margin-left: auto;
}


/* Connection and battery read as one status object, not two chips. */
/* A readout, not a control: no fill and no border, because in the top bar those
   are what say "you can press this" — and this is the one thing you cannot. */
.ar-status {
    display: inline-flex;
    align-items: center;
    gap: var(--ar-2);
    height: var(--ar-tap);
    padding-inline: var(--ar-2);
    border: 0;
    background: none;
    color: var(--ar-ink-2);
    font: inherit;
    font-size: var(--ar-t-meta);
    font-weight: var(--ar-w-medium);
    white-space: nowrap;
    border-radius: var(--ar-r-pill);
    cursor: default;
    order: -1;
}

/* Disconnected, the chip is the way out of the app's most common dead end, so it
   has to look pressable — a bare label nobody would think to tap is the reason
   the connect button had to live somewhere else. Connected (or mid-connect) it
   goes back to being a plain label.

   aria-disabled rather than :disabled: a status must stay legible, and the shared
   disabled recipe would grey it out. */
.ar-status[aria-disabled="false"] {
    border: 1px solid var(--ar-line);
    color: var(--ar-ink);
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
}

.ar-status[aria-disabled="false"]:hover,
.ar-status[aria-disabled="false"]:focus-visible {
    background: var(--ar-surface-hi);
    border-color: var(--ar-line-strong);
}

.ar-status[data-state="connecting"] .ar-status__dot {
    background: var(--ar-accent);
    animation: ar-status-pulse 1s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .ar-status[data-state="connecting"] .ar-status__dot {
        animation: none;
    }
}

.ar-status__dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--ar-ink-3);
    flex: none;
}

.ar-status[data-state="connected"] {
    color: var(--ar-ink);
}

.ar-status[data-state="connected"] .ar-status__dot {
    background: var(--ar-ok);
    box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.18);
}

/* Auto-save reports into the same slot as the connection state: it is device
   state, it is always on screen, and reusing the slot means the confirmation
   cannot shift the layout under the control you just touched. */
.ar-status[data-state="saving"],
.ar-status[data-state="saved"] {
    color: var(--ar-ink);
}

.ar-status[data-state="saving"] .ar-status__dot {
    background: var(--ar-accent);
    animation: ar-status-pulse 1s ease-in-out infinite;
}

.ar-status[data-state="saved"] .ar-status__dot {
    background: var(--ar-ok);
    box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.18);
}

.ar-status[data-state="savefail"] {
    color: var(--ar-danger);
}

.ar-status[data-state="savefail"] .ar-status__dot {
    background: var(--ar-danger);
}

@keyframes ar-status-pulse {
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .ar-status[data-state="saving"] .ar-status__dot {
        animation: none;
    }
}

.ar-status__battery {
    font-variant-numeric: tabular-nums;
}

.ar-status__battery[hidden] {
    display: none;
}

.ar-status__battery.is-low {
    color: var(--ar-danger);
}

.ar-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--ar-tap);
    height: var(--ar-tap);
    padding: 0;
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface);
    color: var(--ar-ink-2);
    cursor: pointer;
    transition: background var(--ar-ease), color var(--ar-ease), border-color var(--ar-ease);
}

.ar-icon-btn:hover {
    background: var(--ar-surface-2);
    color: var(--ar-ink);
}

.ar-icon-btn svg {
    width: 1.25rem;
    height: 1.25rem;
}

.ar-icon-btn__label {
    display: none;
}

/* ---------- Progress ----------------------------------------------------- */

/* A rail, not dots: eleven dots on a 360px screen is unreadable. */
/* ---------- Main / step -------------------------------------------------- */

.ar-main {
    min-height: 0;
}

/* One column, at every width. A heading beside its own controls only works when
   the controls are tall enough to sit next to; when they are not it leaves an
   orphan column, so the flow never splits. */
.ar-step {
    padding-block: 0 var(--ar-8);
    display: flex;
    flex-direction: column;
    gap: var(--ar-5);
}

.ar-step__head .ar-lede {
    max-width: 52ch;
}

.ar-step__body {
    display: flex;
    flex-direction: column;
    gap: var(--ar-4);
    min-width: 0;
}

/* ---------- Buttons ------------------------------------------------------ */

.ar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ar-2);
    min-height: var(--ar-tap);
    padding-inline: var(--ar-5);
    border: 1px solid transparent;
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface-2);
    color: var(--ar-ink);
    font: inherit;
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
    text-align: center;
    cursor: pointer;
    transition: background var(--ar-ease), border-color var(--ar-ease), opacity var(--ar-ease);
}

/* ONE disabled recipe for the whole app: the surface stays, the ink drops, the
   border stays. Never blanket opacity — it fades the very affordance (a radio
   ring, an arrow) that tells you what the control was. */
.ar-btn:disabled,
.ar-choice:disabled,
.qs-nav-btn:disabled,
.ar-select select:disabled {
    background: var(--ar-surface-2);
    border-color: var(--ar-line);
    color: var(--ar-ink-3);
    opacity: 1;
    cursor: not-allowed;
}

.ar-choice:disabled {
    background: transparent;
}

.ar-btn--primary {
    background: var(--ar-accent);
    color: var(--ar-accent-ink);
}

.ar-btn--primary:hover:not(:disabled) {
    background: var(--ar-accent-hi);
}

.ar-btn--ghost {
    background: transparent;
    border-color: var(--ar-line);
    color: var(--ar-ink);
}

.ar-btn--ghost:hover:not(:disabled) {
    background: var(--ar-surface-2);
}

.ar-btn--quiet {
    background: transparent;
    color: var(--ar-ink-2);
    padding-inline: var(--ar-3);
    font-weight: var(--ar-w-medium);
}

.ar-btn--quiet:hover:not(:disabled) {
    color: var(--ar-ink);
}

.ar-btn--danger,
.ar-link--danger {
    color: var(--ar-danger);
}

.ar-btn--danger {
    background: var(--ar-danger-wash);
    border-color: var(--ar-danger);
}

.ar-btn--sm {
    min-height: var(--ar-h-sm);
    padding-inline: var(--ar-3);
    font-size: var(--ar-t-meta);
}

.ar-btn--block {
    width: 100%;
}

/* Inline in a sentence it stays inline; standing on its own it needs a real
   touch target, hence .ar-link--block. */
.ar-link {
    border: 0;
    background: none;
    padding: 0;
    color: var(--ar-accent);
    font: inherit;
    font-weight: var(--ar-w-semi);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

/* ---------- Action bar --------------------------------------------------- */

/* Always in thumb reach on a phone; on a desktop it reads as an app footer.
   No fixed positioning — the shell grid pins it. */
.ar-actions {
    box-shadow: var(--ar-shadow-up);
    padding-block: var(--ar-3);
    padding-bottom: calc(var(--ar-3) + env(safe-area-inset-bottom, 0px));
}

.ar-actions[hidden] {
    display: none;
}

.ar-actions-sentinel {
    height: 1px;
}

.ar-actions__inner {
    display: flex;
    align-items: center;
    gap: var(--ar-3);
}

/* The primary action takes the remaining width so it is the obvious target. */
.ar-actions .ar-btn--primary {
    flex: 1;
}

.ar-actions__spacer {
    flex: 1;
}

/* ---------- Selection ----------------------------------------------------- */

/* Three treatments, mapped to what the control changes:
     solid accent fill — the page's one primary action  .ar-btn--primary
     raised surface    — a mode is current              .ar-mode
     tint + accent line— a value is set on this thing   everything below,
                         including the section chips.
   One declaration, so a selected chip, a selected row, a selected card and a
   pressed toggle cannot drift apart. */
.ar-select-row[aria-checked="true"],
.ar-choice[aria-pressed="true"],
.ar-pick2__opt[aria-pressed="true"],
.ar-icon-btn[aria-pressed="true"],
.ar-key.is-special,
.qs-chapter.active,
.ar-chip[aria-selected="true"],
.ar-chip.active {
    background: var(--ar-accent-wash);
    border-color: var(--ar-accent-line);
    color: var(--ar-accent);
}

/* The naming line inside a selected object goes accent with it. */
.ar-select-row[aria-checked="true"] .ar-item__title,
.ar-choice[aria-pressed="true"] .ar-item__title,
.ar-pick2__opt[aria-pressed="true"] span,
.ar-keyrow.is-special .ar-keyrow__glyph {
    color: var(--ar-accent);
}

/* ---------- Lists -------------------------------------------------------- */

/* One grouped container with dividers. Eight separately floating pills is what
   made the media step look like debris. */
.ar-list {
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r);
    background: var(--ar-surface);
    overflow: hidden;
}

.ar-item {
    display: flex;
    align-items: center;
    gap: var(--ar-3);
    min-height: var(--ar-h-lg);
    padding: var(--ar-3) var(--ar-4);
    width: 100%;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
}

.ar-item + .ar-item {
    border-top: 1px solid var(--ar-line);
}

.ar-item--tappable {
    cursor: pointer;
    transition: background var(--ar-ease);
}

.ar-item--tappable:hover {
    background: var(--ar-surface-2);
}

.ar-item__icon {
    flex: none;
    width: 1.5rem;
    font-size: var(--ar-t-body);
    line-height: 1;
    text-align: center;
}

.ar-item__body {
    flex: 1;
    min-width: 0;
}

.ar-item__title {
    display: block;
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
}

.ar-item__sub {
    display: block;
    font-size: var(--ar-t-meta);
    color: var(--ar-ink-2);
}

.ar-item__value {
    flex: none;
    font-size: var(--ar-t-meta);
    color: var(--ar-ink-2);
    font-variant-numeric: tabular-nums;
}

.ar-item__value--unset {
    color: var(--ar-ink-3);
}

/* Fixed width so the list's right edge does not jitter as labels change
   between Assign / Clear / Change. */
.ar-item__action {
    flex: none;
    min-width: 4.5rem;
}

/* Checkbox affordance for a selectable list row. */
.ar-check {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border: 1.5px solid var(--ar-line-strong);
    border-radius: var(--ar-r-sm);
    background: transparent;
    color: transparent;
    transition: background var(--ar-ease), border-color var(--ar-ease), color var(--ar-ease);
}

.ar-check svg {
    width: 0.875rem;
    height: 0.875rem;
}

.ar-select-row[aria-checked="true"] .ar-check {
    background: var(--ar-accent);
    border-color: var(--ar-accent);
    color: var(--ar-accent-ink);
}

.ar-item.is-armed {
    background: var(--ar-accent-wash);
}

.ar-item.is-armed .ar-item__value {
    color: var(--ar-accent);
    font-weight: var(--ar-w-semi);
}

/* Selectable list rows (flight computer choice). */
.ar-choice {
    cursor: pointer;
    transition: background var(--ar-ease);
}

.ar-choice:hover:not(:disabled) {
    background: var(--ar-surface-2);
}

/* An empty ring when unselected, so the list reads as a choice rather than as
   static information — and matches the checkbox on the step before it. */
.ar-choice__mark {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border: 1.5px solid var(--ar-line-strong);
    border-radius: 50%;
    color: transparent;
    transition: background var(--ar-ease), border-color var(--ar-ease), color var(--ar-ease);
}

.ar-choice__mark svg {
    width: 0.8125rem;
    height: 0.8125rem;
}

.ar-choice[aria-pressed="true"] .ar-choice__mark {
    background: var(--ar-accent);
    border-color: var(--ar-accent);
    color: var(--ar-accent-ink);
}

.ar-badge,
.section-flag {
    display: inline-block;
    padding: 0.0625rem var(--ar-2);
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface-hi);
    color: var(--ar-ink-3);
    font-size: var(--ar-t-micro);
    font-weight: var(--ar-w-semi);
}

/* ---------- Notes / callouts --------------------------------------------- */

/* A note is prose, not data. Beside an .ar-list it used the same surface,
   border and radius, so the two read as one card split by accident — it keeps
   the accent rule but drops the card. */
.ar-note {
    display: flex;
    align-items: center;
    gap: var(--ar-3);
    padding: var(--ar-2) 0 var(--ar-2) var(--ar-4);
    border-left: 2px solid var(--ar-line-strong);
    font-size: var(--ar-t-label);
    color: var(--ar-ink-2);
}

.ar-note--accent { border-left-color: var(--ar-accent); }
.ar-note--warn   { border-left-color: var(--ar-warn); }
.ar-note--danger { border-left-color: var(--ar-danger); }
.ar-note--ok     { border-left-color: var(--ar-ok); }

.ar-note__body {
    flex: 1;
    min-width: 0;
}

.ar-note strong {
    color: var(--ar-ink);
}

/* ---------- Steps list (numbered instructions) --------------------------- */

.ar-steps {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: ar-step;
    display: flex;
    flex-direction: column;
    gap: var(--ar-3);
}

/* Block + absolutely positioned marker, not grid: a grid item is created per
   child element, so an inline <strong> in the middle of a sentence would be
   thrown onto its own row. */
.ar-steps li {
    counter-increment: ar-step;
    position: relative;
    padding-left: 2.25rem;
    min-height: 1.5rem;
    font-size: var(--ar-t-body);
    color: var(--ar-ink-2);
}

.ar-steps li::before {
    content: counter(ar-step);
    position: absolute;
    left: 0;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--ar-surface-2);
    color: var(--ar-ink);
    font-size: var(--ar-t-meta);
    font-weight: var(--ar-w-bold);
}

.ar-steps strong {
    color: var(--ar-ink);
}

/* ---------- Waiting-for-press indicator ---------------------------------- */

/* Same left-rule geometry as a note, but this one is the live thing you are
   doing — a wash behind it so the eye lands here before the footnote at the
   bottom of the same screen. */
.ar-listen {
    display: flex;
    align-items: center;
    gap: var(--ar-4);
    padding: var(--ar-3) var(--ar-4);
    border-left: 2px solid var(--ar-accent);
    border-radius: 0 var(--ar-r-sm) var(--ar-r-sm) 0;
    background: var(--ar-accent-wash);
}

.ar-listen__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.ar-listen__pulse {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: var(--ar-accent-wash);
    color: var(--ar-accent);
    animation: ar-pulse 1.8s ease-in-out infinite;
}

.ar-listen__pulse svg {
    width: 1.25rem;
    height: 1.25rem;
}

.ar-listen__text {
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
}

.ar-listen.is-done {
    border-left-color: var(--ar-ok);
    background: rgba(52, 211, 153, 0.10);
}

.ar-listen.is-done .ar-listen__pulse {
    background: rgba(52, 211, 153, 0.14);
    color: var(--ar-ok);
    animation: none;
}

@keyframes ar-pulse {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.08); opacity: 0.75; }
}

@media (prefers-reduced-motion: reduce) {
    .ar-listen__pulse { animation: none; }
}

/* ---------- The device map ------------------------------------------------ */

/* One body with the two joysticks stacked, upper above lower — the same
   arrangement as the hardware on the riser. Never side by side: the spatial
   layout is the entire reason for drawing a cross instead of listing keys.
   This is a reference, not the editor, so its keys carry glyphs only. */
/* Reads as a physical object by its fill, not by a 4px radius nobody can name.
   Every card in the app is --ar-r; this one is too. */
.ar-device {
    width: 11.5rem;
    margin-inline: auto;
    padding: var(--ar-3);
    display: flex;
    flex-direction: column;
    gap: var(--ar-4);
    border: 1px solid var(--ar-line-strong);
    border-radius: var(--ar-r);
    background: var(--ar-surface-2);
}

.ar-device__cross {
    display: flex;
    flex-direction: column;
    gap: var(--ar-2);
}

/* These two words are the only thing telling the joysticks apart, so they are
   not the quietest type on the screen. */
.ar-cross__label {
    margin: 0;
    font-size: var(--ar-t-micro);
    font-weight: var(--ar-w-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ar-ink-2);
    text-align: center;
}

.ar-cross__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: var(--ar-1);
    width: 100%;
    aspect-ratio: 1;
}

.ar-key {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface-2);
    color: var(--ar-ink-2);
    font: inherit;
    font-size: var(--ar-t-body);
    cursor: pointer;
    transition: background var(--ar-ease), border-color var(--ar-ease),
                color var(--ar-ease), transform var(--ar-ease);
}

.ar-key:hover,
.ar-key.is-linked {
    border-color: var(--ar-accent);
    color: var(--ar-accent);
}

/* A real press on the device, and the demo picker's tap. */
.ar-key:active,
.ar-key.is-pressed {
    background: var(--ar-accent);
    border-color: var(--ar-accent);
    color: var(--ar-accent-ink);
    transform: scale(0.92);
}

/* ---------- Key editor ---------------------------------------------------- */

.ar-keys {
    display: grid;
    gap: var(--ar-6);
}

.ar-keys__lists {
    display: flex;
    flex-direction: column;
    gap: var(--ar-6);
    min-width: 0;
}

/* In the flow the device is something you tap, not just read, so its buttons are
   full-size targets — and it shares the column's left edge like everything else,
   rather than floating in the middle of a left-aligned step. */
.ar-device--interactive {
    width: 14rem;
    margin-inline: 0;
    padding: var(--ar-4);
}

.ar-device--interactive .ar-key {
    font-size: var(--ar-t-body);
}

.ar-keys__map {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ar-3);
}

.ar-keyrow {
    gap: var(--ar-3);
}

.ar-keyrow__glyph {
    flex: none;
    width: 1.25rem;
    text-align: center;
    color: var(--ar-ink-3);
}

.ar-keyrow__name {
    flex: none;
    width: 4.5rem;
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
}

.ar-keyrow.is-special .ar-keyrow__glyph {
    color: var(--ar-accent);
}

.ar-keyrow.is-linked {
    background: var(--ar-surface-2);
}

/* A real press on the device lights up its row as well as its key on the map —
   that is how you work out which key is which. */
/* The wash is enough inside a card; the 2px left bar is reserved for note and
   status blocks, so it keeps one meaning. */
.ar-keyrow.is-pressed {
    background: var(--ar-accent-wash);
}

.ar-keyrow.is-pressed .ar-keyrow__glyph,
.ar-keyrow.is-pressed .ar-keyrow__name {
    color: var(--ar-accent);
}

/* ---------- Select -------------------------------------------------------- */

/* A native select keeps the platform picker on a phone and the grouped option
   list everywhere; only the shell around it is ours. */
.ar-link--block {
    display: inline-flex;
    align-items: center;
    min-height: var(--ar-tap);
    padding-inline: var(--ar-1);
}

.ar-select {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
}

.ar-select select {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    min-height: var(--ar-h-sm);
    padding: 0.25rem 2rem 0.25rem var(--ar-3);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface-2);
    color: var(--ar-ink);
    font: inherit;
    font-size: var(--ar-t-label);
    text-overflow: ellipsis;
    cursor: pointer;
}

.ar-select select:hover {
    border-color: var(--ar-line-strong);
}


.ar-select::after {
    content: '';
    position: absolute;
    right: 0.75rem;
    top: 50%;
    width: 0.4rem;
    height: 0.4rem;
    margin-top: -0.3rem;
    border-right: 1.5px solid var(--ar-ink-3);
    border-bottom: 1.5px solid var(--ar-ink-3);
    transform: rotate(45deg);
    pointer-events: none;
}

/* ---------- Navigation block ---------------------------------------------- */

/* The mode switch and its section tabs are two levels of one thing, so they live
   in one block and share its bottom edge. Apart, they read as two unrelated
   controls that happen to sit near each other. */
/* Pinned to the top of the scrolling content, so the way out and the section you
   are in stay put however long the page is — the manual especially.

   The sticky has to live on a full-width wrapper, not on .ar-nav itself: a sticky
   box can only travel inside its own containing block, and .ar-nav's parent is
   exactly as tall as .ar-nav, so it had nowhere to go and never stuck. The
   wrapper also spans the full scroller width, so content passes behind it edge to
   edge rather than beside it. */
.ar-navbar {
    position: sticky;
    top: 0;
    z-index: 10;
}


/* The nav owns the whole gap down to the content, so that gap cannot come out
   different per view. */
.ar-nav {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--ar-3);
    padding-block: var(--ar-gap-mode) var(--ar-8);
}

/* No rule at rest — the chips group by proximity. It appears only once something
   is passing underneath, where the pinned block genuinely needs an edge. It sits
   on .ar-nav, not the full-bleed wrapper, so it lines up with the content column
   like every other horizontal line in the app. */
.ar-nav::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: 1px;
    background: var(--ar-line);
    opacity: 0;
    transition: opacity 0.15s ease;
}

.ar-navbar.is-stuck .ar-nav::after {
    opacity: 1;
}

/* ---------- Mode switch --------------------------------------------------- */

/* The app's two working modes. A compact pill pair at the head of the content —
   not in the chrome, where it read as page navigation and crowded the bar. */
.ar-modes {
    display: inline-flex;
    gap: var(--ar-1);
    margin-block: 0;
    padding: var(--ar-1);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface);
}

.ar-mode {
    min-height: var(--ar-h-sm);
    padding-inline: var(--ar-5);
    border: 0;
    border-radius: var(--ar-r-pill);
    background: transparent;
    color: var(--ar-ink-2);
    font: inherit;
    font-size: var(--ar-t-label);
    font-weight: var(--ar-w-semi);
    cursor: pointer;
    transition: background var(--ar-ease), color var(--ar-ease);
}

.ar-mode:hover {
    color: var(--ar-ink);
}

/* A raised surface, not accent fill: a solid accent pill is what the page's one
   primary action wears, and a navigation state must not impersonate it. */
.ar-mode[aria-current="true"] {
    background: var(--ar-surface-hi);
    color: var(--ar-ink);
    box-shadow: var(--ar-shadow);
}

/* ---------- Section chips ------------------------------------------------- */

/* One component for section navigation, wherever it appears: Expert's sections
   and the manual's sections do the same job in the same place, so they are the
   same control. The mode switch above stays a segmented control — a track with
   options inside — which is what keeps the two levels apart. */
.ar-chips {
    display: flex;
    gap: var(--ar-2);
    align-self: stretch;
}

.ar-chips[hidden] {
    display: none;
}

.ar-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    min-height: var(--ar-h-sm);
    padding-inline: var(--ar-3);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface);
    color: var(--ar-ink-2);
    font: inherit;
    font-size: var(--ar-t-label);
    font-weight: var(--ar-w-medium);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color var(--ar-ease), color var(--ar-ease), background var(--ar-ease);
}

.ar-chip:hover {
    color: var(--ar-ink);
    border-color: var(--ar-line-strong);
}

/* ---------- Sections (advanced panels) ----------------------------------- */

#expertView,
#manualView {
    padding-block: 0;
}

.ar-panel {
    display: none;
    padding-block: 0 var(--ar-8);
}

.ar-panel > *:first-child,
.ar-manual > *:first-child,
.ar-step > *:first-child,
.ar-panel > *:first-child > *:first-child,
.ar-step > *:first-child > *:first-child {
    margin-top: 0;
}

.ar-panel.is-active {
    display: block;
}

.ar-section + .ar-section {
    margin-top: var(--ar-10);
}

/* A heading always owns a bigger break than the rows beneath it. */
.ar-section__head {
    margin-bottom: var(--ar-gap-head);
}

.ar-section__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--ar-4);
}

/* ---------- Fields ------------------------------------------------------- */

/* The value sits next to its label rather than at the far right, so the control
   can fill the column without putting the two 900px apart — and the panel keeps
   a single right edge. */
.ar-field__label {
    justify-content: flex-start;
}

.ar-field {
    display: flex;
    flex-direction: column;
    gap: var(--ar-2);
}

.ar-field + .ar-field {
    margin-top: var(--ar-6);
}

/* Label left, current value right — the pairing that makes a slider readable.
   The value wraps rather than running off the edge: a full 18-character device
   name plus the "AeroRemote_" prefix does not fit a phone on one line. */
.ar-field__label {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--ar-1) var(--ar-3);
    font-size: var(--ar-t-label);
    font-weight: var(--ar-w-semi);
}

.ar-field__label > * {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* A key's function can be long ("Insta360 — Start/Stop Rec., Power On/Off"), so
   the select gets the row's remaining width and the name column shrinks on a
   phone rather than truncating the only information the row carries. */
.ar-keyrow__name {
    width: auto;
    min-width: 3.25rem;
}

/* !important because a legacy rule pins #debounceValue to plain white and would
   otherwise break the pairing with the other slider readouts. */
.ar-field__value {
    color: var(--ar-accent) !important;
    font-variant-numeric: tabular-nums;
}

.ar-field__help {
    margin: 0;
    max-width: 62ch;
    font-size: var(--ar-t-meta);
    line-height: 1.5;
    color: var(--ar-ink-2);
}

/* A control you type into, so it takes the control fill like every button and
   select — not the card fill, which made it compete with the card below it. */
.ar-input {
    width: 100%;
    min-height: var(--ar-tap);
    padding: var(--ar-2) var(--ar-3);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface-2);
    color: var(--ar-ink);
    font: inherit;
    font-size: var(--ar-t-body);
}

.ar-input::placeholder {
    color: var(--ar-ink-3);
}


/* ---------- Two-up picker (mounting side) -------------------------------- */

/* A binary choice does not need two half-page slabs; the illustration only has
   to be big enough to read the orientation. */
.ar-pick2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ar-3);
    max-width: 28rem;
}

/* The one card-based picker in the app — it has to hold pictures. It carries the
   same selection mark as the two list pickers so "pick one" always looks the
   same, whatever shape the options are. */
.ar-pick2__opt {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ar-2);
    padding: var(--ar-3);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r);
    background: var(--ar-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
    transition: border-color var(--ar-ease), background var(--ar-ease);
}

/* Big enough to read the orientation, not so big that the least important
   control on the screen is also the largest. */
.ar-pick2__opt img {
    width: auto;
    height: 4rem;
}

.ar-pick2__opt span {
    font-size: var(--ar-t-label);
    font-weight: var(--ar-w-semi);
}

.ar-pick2__opt:hover {
    border-color: var(--ar-line-strong);
}

.ar-pick2__mark {
    position: absolute;
    top: var(--ar-2);
    right: var(--ar-2);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border: 1.5px solid var(--ar-line-strong);
    border-radius: 50%;
    color: transparent;
}

.ar-pick2__mark svg {
    width: 0.8125rem;
    height: 0.8125rem;
}

.ar-pick2__opt[aria-pressed="true"] .ar-pick2__mark {
    background: var(--ar-accent);
    border-color: var(--ar-accent);
    color: var(--ar-accent-ink);
}

/* ---------- Progress bar (firmware) -------------------------------------- */

.ar-meter {
    height: 0.375rem;
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface-hi);
    overflow: hidden;
}

.ar-meter__fill {
    height: 100%;
    width: 0%;
    border-radius: var(--ar-r-pill);
    background: var(--ar-accent);
    transition: width 250ms linear;
}

/* ---------- Done screen -------------------------------------------------- */

.ar-done {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: var(--ar-bg);
    padding: var(--ar-6);
    place-content: center;
    text-align: center;
}

.ar-done.is-visible {
    display: grid;
}

/* The gap alone governs, so the title cannot end up closer to the icon above it
   than to its own lede. Same rhythm as a step head. */
.ar-done__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ar-3);
    max-width: 26rem;
    margin-inline: auto;
}

.ar-done__inner > * {
    margin: 0;
}

.ar-done__mark {
    margin-bottom: var(--ar-2);
}

.ar-done__actions {
    margin-top: var(--ar-3);
}

.ar-done__mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background: rgba(52, 211, 153, 0.14);
    color: var(--ar-ok);
}

.ar-done__mark svg {
    width: 2rem;
    height: 2rem;
}

.ar-done__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ar-3);
    justify-content: center;
    margin-top: var(--ar-2);
}

/* ---------- Scrollers ----------------------------------------------------- */

/* Every strip that clips its content fades at the edge, so "there is more"
   always looks the same. Four strips had grown four different answers: a mask,
   a pair of arrows, and twice nothing at all. */
.ar-scroll-x {
    overflow-x: auto;
    scrollbar-width: none;
    scroll-behavior: smooth;
}

.ar-scroll-x.is-clip-end {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
}

.ar-scroll-x.is-clip-start {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(to left, #000 calc(100% - 2rem), transparent);
}

.ar-scroll-x.is-clip-start.is-clip-end {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
}

.ar-scroll-x::-webkit-scrollbar {
    display: none;
}

/* A note that asks a question rather than only stating one. The buttons sit
   inside the note's body so they read as belonging to it, and wrap on a phone
   rather than squeezing to two illegible columns. */
.ar-note__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ar-2);
    margin-top: var(--ar-3);
}

/* ---------- Rhythm -------------------------------------------------------- */

/* Inside a container that already manages its own gap, children must not add
   margins on top — that is how two lists inside one section ended up further
   apart (48px) than two whole sections (40px). */
.ar-keys__lists > .ar-field + .ar-field,
.ar-section__body > .ar-field + .ar-field,
.ar-section__body > .ar-details {
    margin-top: 0;
}

/* ---------- Focus --------------------------------------------------------- */

/* One ring for everything focusable. The browser default is a blue that is in
   nobody's palette, and three bespoke rings had grown up beside it. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--ar-accent);
    outline-offset: 2px;
    border-radius: var(--ar-r-sm);
}

/* ---------- Utility ------------------------------------------------------ */

.ar-stack {
    display: flex;
    flex-direction: column;
    gap: var(--ar-4);
}

.ar-stack--tight {
    gap: var(--ar-2);
}

.ar-center {
    text-align: center;
}

.ar-status-line {
    font-size: var(--ar-t-label);
    color: var(--ar-ink-2);
}

.ar-status-line--error {
    color: var(--ar-danger);
}

[hidden] {
    display: none !important;
}

/* ---------- Wider viewports ---------------------------------------------- */

@media (min-width: 40rem) {
    :root {
        --ar-gutter: var(--ar-6);
        --ar-measure: 46rem;
        --ar-t-display: 2rem;
        --ar-gap-mode: var(--ar-10);
    }

    body {
        font-size: var(--ar-t-body);
    }

    .ar-topbar__by {
        display: inline;
    }


    .ar-icon-btn__label {
        display: inline;
    }

    .ar-icon-btn {
        width: auto;
        gap: var(--ar-2);
        padding-inline: var(--ar-3);
        font: inherit;
        font-size: var(--ar-t-meta);
        font-weight: var(--ar-w-semi);
    }

    .ar-step {
        padding-block: 0 var(--ar-10);
    }
}

/* Wide viewports keep the same fixed-height shell — the action bar stays on the
   bottom edge at every size, so the primary action never scrolls out of reach.
   What changes here is only how the content column uses the extra width. */
@media (min-width: 60rem) {

    /* The editor is tall and the map is short, so the map rides alongside as a
       fixed narrow column instead of pushing the list down the page. */
    .ar-keys {
        grid-template-columns: minmax(0, 1fr) 11.5rem;
        column-gap: var(--ar-8);
        align-items: start;
    }

    /* Actions belong to the content column, so they end under it. */
    .ar-actions__inner {
        justify-content: flex-end;
    }

    .ar-actions .ar-btn--primary {
        flex: 0 0 auto;
        min-width: 11rem;
    }

    .ar-actions__spacer {
        display: none;
    }
}

@media (min-width: 64rem) {
    :root {
        --ar-gutter: var(--ar-8);
        --ar-measure: 58rem;
    }
}

@media (min-width: 100rem) {
    :root {
        --ar-measure: 64rem;
    }
}

/* ---------- Range input -------------------------------------------------- */

.ar-range {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 1.75rem;
    background: transparent;
    cursor: pointer;
}

.ar-range::-webkit-slider-runnable-track {
    height: 0.25rem;
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface-hi);
}

.ar-range::-moz-range-track {
    height: 0.25rem;
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface-hi);
}

.ar-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 1.375rem;
    height: 1.375rem;
    margin-top: -0.5625rem;
    border: 0;
    border-radius: 50%;
    background: var(--ar-accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.ar-range::-moz-range-thumb {
    width: 1.375rem;
    height: 1.375rem;
    border: 0;
    border-radius: 50%;
    background: var(--ar-accent);
}


.ar-range__ends {
    display: flex;
    justify-content: space-between;
    font-size: var(--ar-t-meta);
    color: var(--ar-ink-3);
}

/* ---------- Disclosure --------------------------------------------------- */

.ar-details {
    margin-top: var(--ar-6);
    border-top: 1px solid var(--ar-line);
    padding-top: var(--ar-4);
}

.ar-details__summary {
    display: flex;
    align-items: center;
    gap: var(--ar-2);
    min-height: var(--ar-tap);
    color: var(--ar-ink-2);
    font-size: var(--ar-t-label);
    font-weight: var(--ar-w-semi);
    cursor: pointer;
    list-style: none;
}

.ar-details__summary::-webkit-details-marker {
    display: none;
}

.ar-details__summary::before {
    content: '';
    width: 0.4rem;
    height: 0.4rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
    transition: transform var(--ar-ease);
}

.ar-details[open] .ar-details__summary::before {
    transform: rotate(45deg);
}

.ar-details__body {
    padding-top: var(--ar-4);
}

/* ---------- Legacy chrome that the shell replaced ------------------------ */

.dashboard,
.sidebar,
.top-header,
.mobile-overlay,
.burger-menu-btn,
.main-content > .header,
.quickstart-modal {
    display: none !important;
}

/* Banners keep working but join the shell grid instead of floating over it —
   the legacy rules pinned them to the viewport, which stacked them on top of
   each other now that they share a row. */
.ar-banners > *:not([hidden]) {
    position: static;
}

.ar-banners:empty,
.permanent-banners:empty {
    display: none;
}

.permanent-banner {
    padding-inline: var(--ar-4);
}

.bluetooth-warning-banner {
    position: static !important;
    top: auto !important;
    padding: var(--ar-3) var(--ar-4) !important;
    box-shadow: none !important;
}

.logging-notice {
    background: var(--ar-surface) !important;
    border-bottom: 1px solid var(--ar-line) !important;
    color: var(--ar-ink-2) !important;
}

/* Toasts: hidden until setStatus() shows one. */
.notification-container {
    display: none;
}

.notification-container.visible {
    display: block;
}

.notification-container.fade-out {
    animation: notificationFadeOut 0.3s ease-out forwards;
}

/* ---------- Video guide --------------------------------------------------- */

/* Shared by the intro step and the manual. Restyled onto the new tokens rather
   than inherited from the sheet that used to hold it. */
.qs-video-section {
    display: flex;
    flex-direction: column;
    gap: var(--ar-3);
}

.qs-video-embed {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--ar-r);
    overflow: hidden;
    background: var(--ar-surface-2);
}

.qs-video-embed iframe,
.qs-video-embed > div {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.qs-video-controls {
    display: flex;
    align-items: center;
    gap: var(--ar-2);
    min-width: 0;
}

/* The chapter strip scrolls sideways rather than wrapping into a block of chips
   that changes height as you page through it. */
.qs-chapters-strip {
    display: flex;
    gap: var(--ar-2);
    flex: 1;
    min-width: 0;
}

.qs-chapters-strip::-webkit-scrollbar {
    display: none;
}

.qs-chapter {
    flex: none;
    display: inline-flex;
    align-items: center;
    min-height: var(--ar-h-sm);
    padding: 0 var(--ar-3);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-pill);
    background: var(--ar-surface);
    color: var(--ar-ink-2);
    font: inherit;
    font-size: var(--ar-t-meta);
    font-weight: var(--ar-w-medium);
    white-space: nowrap;
    cursor: pointer;
    transition: border-color var(--ar-ease), color var(--ar-ease);
}

.qs-chapter:hover {
    color: var(--ar-ink);
    border-color: var(--ar-line-strong);
}

/* Was the only circle in the app and 32px in a 44px world. Now it is the same
   small control as everything else on the strip beside it. */
.qs-nav-btn {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--ar-h-sm);
    height: var(--ar-h-sm);
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r-sm);
    background: var(--ar-surface);
    color: var(--ar-ink-2);
    font-size: var(--ar-t-micro);
    cursor: pointer;
    transition: color var(--ar-ease), border-color var(--ar-ease);
}

.qs-nav-btn:hover:not(:disabled) {
    color: var(--ar-ink);
    border-color: var(--ar-line-strong);
}

/* ---------- Theme toggle icons -------------------------------------------- */

/* One button, two glyphs: show the theme it will switch to. */
.theme-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.theme-icon-sun {
    display: none;
}

:root[data-theme="light"] .theme-icon-moon {
    display: none;
}

:root[data-theme="light"] .theme-icon-sun {
    display: block;
}

/* ---------- Busy button --------------------------------------------------- */

.ar-btn.is-busy {
    opacity: 0.7;
    pointer-events: none;
}

/* Byte budget for the device name; the limit is a firmware buffer, not a
   character count, so the number has to be visible while typing. */
.ar-count {
    font-variant-numeric: tabular-nums;
    color: var(--ar-ink-3);
    white-space: nowrap;
}

.ar-count.is-full {
    color: var(--ar-warn);
}

/* ---------- Manual view --------------------------------------------------- */

.ar-manual {
    padding-bottom: var(--ar-12);
}

.ar-manual .manual-section + .manual-section {
    margin-top: var(--ar-10);
    padding-top: var(--ar-8);
    border-top: 1px solid var(--ar-line);
}

.ar-manual h2 {
    margin: 0 0 var(--ar-3);
    font-size: var(--ar-t-title);
    font-weight: var(--ar-w-bold);
    letter-spacing: -0.015em;
    color: var(--ar-ink);
    scroll-margin-top: 7rem;
}

.ar-manual h3 {
    margin: var(--ar-6) 0 var(--ar-2);
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
    color: var(--ar-ink);
}

.ar-manual h4 {
    margin: var(--ar-4) 0 var(--ar-1);
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-semi);
    color: var(--ar-ink);
}

.ar-manual p,
.ar-manual li {
    color: var(--ar-ink-2);
    max-width: 68ch;
}

.ar-manual p {
    margin: 0 0 var(--ar-3);
}

.ar-manual ol,
.ar-manual ul {
    margin: 0 0 var(--ar-4);
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: var(--ar-2);
}

.ar-manual strong {
    color: var(--ar-ink);
}

.ar-manual a {
    color: var(--ar-accent);
}

.ar-manual table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--ar-t-label);
    margin-bottom: var(--ar-4);
}

.ar-manual th,
.ar-manual td {
    padding: var(--ar-2) var(--ar-3);
    border-bottom: 1px solid var(--ar-line);
    text-align: left;
    vertical-align: top;
    color: var(--ar-ink-2);
}

.ar-manual th {
    color: var(--ar-ink-3);
    font-size: var(--ar-t-meta);
    font-weight: var(--ar-w-semi);
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* Wide reference tables scroll inside their own box rather than the page — and
   now actually have one, so a clipped row reads as clipped rather than broken. */
.ar-manual .mode-reference-table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
    border: 1px solid var(--ar-line);
    border-radius: var(--ar-r);
    background: var(--ar-surface);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
}

.ar-manual .mode-reference-table th,
.ar-manual .mode-reference-table td {
    padding-inline: var(--ar-4);
}

.ar-manual .manual-subsection {
    margin-top: var(--ar-6);
}

/* The manual's necessity markers are the same badge as everywhere else, so the
   surface is declared once and only the semantic colour varies. */
.section-flag {
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin-left: var(--ar-2);
    vertical-align: middle;
}

.section-flag.necessary {
    background: var(--ar-danger-wash);
    color: var(--ar-danger);
}

.section-flag.recommended {
    background: var(--ar-accent-wash);
    color: var(--ar-accent);
}

/* ---------- Changelog (inline, on the Device tab) ------------------------- */

.ar-changelog {
    display: flex;
    flex-direction: column;
    gap: var(--ar-5);
    max-height: 26rem;
    overflow-y: auto;
}

.ar-release__head {
    display: flex;
    align-items: baseline;
    gap: var(--ar-3);
    margin: 0 0 var(--ar-2);
}

.ar-release__version {
    font-size: var(--ar-t-body);
    font-weight: var(--ar-w-bold);
    font-variant-numeric: tabular-nums;
}

.ar-release__date {
    font-size: var(--ar-t-meta);
    color: var(--ar-ink-3);
}

.ar-release__list {
    margin: 0;
    padding-left: 1.125rem;
    display: flex;
    flex-direction: column;
    gap: var(--ar-1);
    font-size: var(--ar-t-label);
    color: var(--ar-ink-2);
}

.ar-release .ar-note {
    margin-top: var(--ar-2);
}

/* A row of small buttons inside a section body. */
.ar-btn-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ar-2);
}

/* Same specificity as the legacy `#changelogBtn { width: 100% }`, and later in
   source order, so it wins without reaching for !important. */
#changelogBtn {
    width: auto;
    margin-top: 0;
}

/* An icon slot holds either an emoji glyph or a 20px stroke icon; both sit on the
   same optical centre so a mixed list does not look ragged. */
.ar-item__icon svg {
    width: 1.25rem;
    height: 1.25rem;
    display: block;
    margin-inline: auto;
    color: var(--ar-ink-2);
}
