/* Dapper Delivery - shared app shell.
   Served to the four WebAssembly apps as _content/DapperDelivery.WebUi/base.css, and linked BEFORE
   each app's own app.css so an app can override anything here simply by restating it.

   What lives here: the brand tokens and the status palette, the reset, typography, the shell
   (topbar/content), and everything more than one surface renders the same way - buttons and chips,
   badges, banners, alerts, the console form controls and modal, the stop card and route header the
   driver and dispatch surfaces share, empty states, the address type-ahead, the install prompt, the
   environment capsule. Also the two OS-preference rules (prefers-reduced-motion and the light-only
   colour-scheme declaration), which have to apply everywhere to be worth having.

   What does NOT: anything one surface styles differently, which each app then restates. Admin is a
   desktop roster among three mobile-first surfaces, so it overrides content width, heading margin,
   the badge and button geometry and the type-ahead placement; merchant keeps a softer language
   (10px radii, outline buttons, quieter labels) and overrides most of the form controls; driver and
   merchant make the topbar a flex row, which dispatch must not be because its bar carries a nav.

   Adding a rule here changes all four - if only one surface wants it, it belongs in that app's
   stylesheet. Colours go through a token: three different reds drifted apart when there was nothing
   to point at. tests/DapperDelivery.Web.UiTests renders all four and will catch a change here that
   breaks one of them. */

:root {
    /* Dapper Delivery brand tokens - see /brand/STYLE_GUIDE.md.
       Monochrome charcoal + ivory with a single brass accent. */
    --ink: #1a1814;            /* charcoal - top bar, on-dark ground */
    --ink-2: #14130f;          /* onyx - deepest */
    --ivory: #f4efe6;          /* cream - marks/text on dark */
    --topbar-bg: #14130f;
    --surface: #ffffff;
    --content-bg: #fbf8f2;     /* warm paper */
    --border: #e6dfd2;         /* warm hairline */
    --text: #211e18;           /* warm near-black */
    --muted: #6e675b;          /* warm grey */
    --accent: #8a6d40;         /* text-safe brass: links, button text, focus */
    --brass: #b08d57;          /* brass fills: primary buttons */
    --brass-dark: #7e6435;     /* fill hover */
    --accent-soft: rgba(176, 141, 87, 0.14);
    --font-sans: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
    --font-display: "Cormorant Garamond", "EB Garamond", "Hoefler Text", Baskerville, Georgia, "Times New Roman", serif;

    /* Elevation. One card shadow and one popover shadow, so surfaces don't each mix their own grey. */
    --shadow-card: 0 1px 2px rgba(20, 19, 15, 0.05);
    --shadow-pop: 0 8px 22px rgba(20, 19, 15, 0.18);

    /* Status palette: semantic state, not brand. */
    --ok: #15803d;                  /* text on --ok-bg */
    --ok-bg: #dcfce7;
    --ok-border: #bbf7d0;
    --warn: #b45309;
    --warn-bg: #fef3c7;
    --warn-border: #fcd34d;
    --err: #b91c1c;
    --err-bg: #fee2e2;
    --err-border: #fecaca;
    --err-border-strong: #f87171;   /* .btn-danger hover */
    --info: #1d4ed8;
    --info-bg: #dbeafe;
    --neutral: #475569;
    --neutral-bg: #e2e8f0;
    /* Deeper red for a failure that owns the screen, rather than a badge tint. */
    --danger: #a3402f;

    /* `only` is load-bearing: without it Chrome for Android may force-dark the page. Dark mode
       later = `light dark` plus a prefers-color-scheme block restating these tokens. */
    color-scheme: only light;
}

/* Near-zero rather than none, so animationend/transitionend still fire. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

* {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
    font-family: var(--font-sans);
    color: var(--text);
    background: var(--content-bg);
    font-size: 17px;
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
    /* Addresses and notes are free text; one long token would otherwise scroll a 375px phone sideways. */
    overflow-wrap: break-word;
}

/* Prose wants 1.5; headings and controls size from their own box instead. */
h1,
h2,
h3 {
    line-height: 1.2;
}

button,
input,
select,
.btn-primary,
.btn-secondary,
.btn-chip,
.btn-danger,
.badge {
    line-height: 1.25;
}

h1 {
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    margin: 0 0 0.5rem;
}

/* <FocusOnNavigate Selector="h1"> moves focus to the heading on every navigation (keeps keyboard/
   screen-reader users oriented). The focus move is what we want; the visible outline box around the
   heading isn't - a heading is not an interactive control, so suppress its ring only. */
h1:focus,
h1:focus-visible {
    outline: none;
}

/* <FocusOnNavigate Selector="h1"> focuses the heading on every navigation and adds
   tabindex="-1" to make it focusable - which the browser then rings with its default
   focus outline. Suppress it: this focus is programmatic, not the user tabbing here. */
[tabindex="-1"]:focus {
    outline: none;
}

a {
    color: var(--accent);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

.muted {
    color: var(--muted);
}

/* ---------- Shell ---------- */

.app {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}

/* Wraps because dispatch's nav cannot fit one phone row, and the auto margins below need a flex row. */
.topbar {
    background: var(--topbar-bg);
    color: var(--ivory);
    padding: 0.75rem 1rem;
    padding-top: max(0.75rem, env(safe-area-inset-top));
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}

.topbar-signout {
    font-size: 0.85rem;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    color: inherit;
}

/* In a flex topbar the lockup pushes everything after it - sign-out, env capsule - to the far right. */
.topbar .brand {
    margin-right: auto;
}

.brand:hover {
    text-decoration: none;
}

/* Official gentleman emblem, framed as an ivory oval cameo (echoes the poster). Worn by the
   topbar .brand lockup and the admin sidebar's .nav-brand alike, so it is styled bare.
   The transparent PNG sits on the ivory medallion fill. */
.cameo {
    width: 46px;
    height: 48px;
    border-radius: 50%;
    background: var(--ivory);
    border: 2px solid var(--brass);
    overflow: hidden;
    flex-shrink: 0;
}

.cameo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 8%;
    display: block;
}

/* The large sign-in cameo; the topbar wears .cameo. Block, not inline: otherwise width/height/
   margin:auto do nothing and the border paints as fragments around a natural-size img. */
.emblem {
    display: block;
    width: 168px;
    height: 182px;
    margin: 0.5rem auto 0.85rem;
    border-radius: 50%;
    background: var(--ivory);
    border: 3px solid var(--brass);
    box-shadow: 0 0 0 1px var(--border), 0 12px 36px rgba(20, 19, 15, 0.16);
    overflow: hidden;
}

.emblem img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 6%;
    display: block;
}

/* The same lockup as the topbar's, centred under the large emblem. Paper ground here rather than
   charcoal, so the colours differ from .brand .title / .brand .subtitle. */
.emblem-text {
    align-items: center;
    margin: 0 0 1.75rem;
}

.emblem-text .title {
    color: var(--text);
}

.emblem-text .subtitle {
    color: var(--accent);
}

/* Wordmark + app name. One type scale across all four apps - see /brand/STYLE_GUIDE.md.
   Geometry is shared by every surface; colour is set per ground below, because the bar
   is charcoal and the sign-in page is paper. */
.brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.brand-text .title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.25rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.brand-text .subtitle {
    font-size: 0.66rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
}

.brand .title {
    color: var(--ivory);
}

.brand .subtitle {
    color: var(--brass);
}

/* Colour-coded environment capsule at the right edge of the header, level with the app subtitle, so a
   driver can tell a dev/test build from prod at a glance. Colours are set inline from AppIcon.AccentFor -
   the same source the favicon band uses - so the tab icon and this capsule always match. Prod shows no
   capsule. Bottom-aligned because the subtitle is the lockup's bottom line; merchant, whose lockup has
   no subtitle, re-centres it. */
.env-pill {
    align-self: flex-end;
    margin: 0 0 0.3rem 0.75rem;
    padding: 0.2rem 0.7rem;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    white-space: nowrap;
}

.content {
    flex: 1;
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    padding: 1.25rem 1rem calc(2rem + env(safe-area-inset-bottom));
}

/* ---------- Sign-in (Home) ---------- */

.lead {
    font-size: 1.05rem;
    margin: 0 0 1.25rem;
}

.signin {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.handle-input {
    width: 100%;
    padding: 0.85rem 1rem;
    font-size: 1.1rem;
    font-family: inherit;
    border: 1px solid var(--border);
    border-radius: 0.6rem;
    background: var(--surface);
    color: var(--text);
}

.handle-input:focus {
    /* Transparent rather than none: forced-colors strips box-shadow, and none would leave no ring. */
    outline: 2px solid transparent;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.btn-primary,
.btn-secondary {
    font-size: 1rem;
    font-family: inherit;
    font-weight: 600;
    border-radius: 0.6rem;
    padding: 0.85rem 1.1rem;
    cursor: pointer;
    border: 1px solid transparent;
}

.btn-primary {
    background: var(--brass);
    color: var(--ink-2);
}

.btn-primary:hover {
    background: var(--brass-dark);
    color: var(--ivory);
    text-decoration: none;
}

.btn-primary:disabled,
.btn-secondary:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn-secondary {
    background: var(--surface);
    color: var(--text);
    border-color: var(--border);
    display: inline-block;
}

.btn-secondary:hover {
    border-color: var(--accent);
    text-decoration: none;
}

/* A SIZE MODIFIER, not a button in its own right: pair it with .btn-primary, .btn-secondary or
   .btn-danger. For a small standalone button use .btn-chip, which brings its own chrome. */
.btn-sm {
    padding: 0.6rem 0.9rem;
    font-size: 0.9rem;
    flex: none;
    white-space: nowrap;
}

/* A small self-contained button: row actions, filter toggles, reorder arrows. Carries its own chrome
   precisely so it does not need composing with .btn-secondary. .active is the chosen/on state. */
.btn-chip {
    font-family: inherit;
    font-weight: 600;
    border-radius: 0.5rem;
    cursor: pointer;
    background: var(--surface);
    color: var(--accent);
    border: 1px solid var(--border);
    padding: 0.3rem 0.7rem;
    font-size: 0.82rem;
    white-space: nowrap;
}

.btn-chip:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.btn-chip.active {
    background: var(--brass);
    color: var(--ink-2);
    border-color: var(--brass);
}

.btn-chip:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.hint {
    margin-top: 1.5rem;
    font-size: 0.9rem;
}

/* ---------- Forms, dialogs and destructive actions ----------
   Admin and dispatch use these as-is; merchant and driver override only what differs. */

/* A header row with the page heading on the left and a primary action on the right.
   Never wraps: the action holds the heading line at every width. */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.page-head h1 {
    margin-bottom: 0;
}

/* When the row tightens, the heading gives before a button label folds mid-word. */
.page-head button {
    white-space: nowrap;
}

/* Marks the noun in a page-head action label; phones keep only the verb ("+ Add"). */
@media (max-width: 600px) {
    .page-head .wide-only {
        display: none;
    }
}

.field-label {
    display: block;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--muted);
    font-weight: 700;
    margin: 1rem 0 0.35rem;
}

/* The standard text control. Every surface renders one of these; only density and width caps vary. */
.input,
.select,
.textarea {
    width: 100%;
    max-width: 32rem;
    padding: 0.6rem 0.75rem;
    font-size: 0.95rem;
    font-family: inherit;
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    background: var(--surface);
    color: var(--text);
}

.input:focus,
.select:focus,
.textarea:focus {
    /* Transparent rather than none: forced-colors strips box-shadow, and none would leave no ring. */
    outline: 2px solid transparent;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Tighter, full-bleed variants for inputs sitting inside repeating rows and grids. */
.input.compact,
.select.compact {
    max-width: none;
    padding: 0.45rem 0.6rem;
    font-size: 0.9rem;
}

.inline-note {
    font-size: 0.82rem;
    color: var(--muted);
}

/* Two controls sharing one row: the halves of a delivery window on the dispatch board and the merchant
   order form, or the address field plus its Save button on a driver's route. */
.field-row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

/* One checkbox and its label. Admin stacks several inside a scrolling .checkbox-list; the merchant form
   uses a single one on its own. */
.checkbox-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.95rem;
    cursor: pointer;
}

/* ---------- Modal ----------
   Shared by the admin roster editors and the dispatch board's create/assign dialogs. */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(20, 19, 15, 0.5);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 1rem;
    z-index: 100;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.modal {
    /* One knob for the dialog's inset; .modal-scroll uses it to run the scroll region to the edges. */
    --modal-pad: 1.5rem;
    background: var(--surface);
    border-radius: 0.75rem;
    padding: var(--modal-pad);
    width: 100%;
    max-width: 34rem;
    box-shadow: 0 10px 40px rgba(20, 19, 15, 0.3);
    /* Auto margins center a modal that fits the viewport. */
    margin: auto;
    /* A column capped to the visible viewport: only the .modal-scroll child shrinks and scrolls, so the
       heading, banner and action row stay in view however long the form is. dvh tracks the visible
       viewport on iOS (vh ignores the toolbars); the 2rem is the backdrop's padding. */
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 2rem);
    max-height: calc(100dvh - 2rem);
}

.modal h2 {
    margin: 0 0 0.25rem;
}

/* A wider modal for the multi-section merchant editor. */
.modal.modal-wide {
    max-width: 56rem;
}

.modal-scroll {
    /* min-height 0 lets this flex child shrink below its content and scroll; its siblings keep their
       natural height (flex's default min-height:auto), so the body is the only part that ever moves. */
    min-height: 0;
    overflow-y: auto;
    /* The scroll region runs out to the dialog's edges, so the scrollbar sits in the side padding a
       full inset away from the fields, and focus rings never clip at the scroll edge. */
    margin: 0 calc(var(--modal-pad) * -1);
    padding: 0 var(--modal-pad);
    scrollbar-width: thin;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.5rem;
}

/* On a phone the dialog is a bottom sheet: full width, pinned to the bottom edge, top corners only.
   Confirmation-sized dialogs keep their natural height; tall editors fill the screen and scroll in
   .modal-scroll. */
@media (max-width: 600px) {
    .modal-backdrop {
        padding: 0;
    }

    .modal {
        --modal-pad: 1rem;
        max-width: none;
        margin: auto 0 0;
        border-radius: 0.9rem 0.9rem 0 0;
        max-height: 100vh;
        max-height: 100dvh;
        padding-bottom: max(var(--modal-pad), env(safe-area-inset-bottom));
    }

    /* Thumb-sized halves instead of desktop's right-aligned pair. */
    .modal-actions > * {
        flex: 1;
    }
}

/* A destructive action sized for a table row. */
.btn-danger {
    font-family: inherit;
    font-weight: 600;
    border-radius: 0.5rem;
    cursor: pointer;
    border: 1px solid var(--err-border);
    background: var(--err-bg);
    color: var(--err);
    padding: 0.3rem 0.7rem;
    font-size: 0.82rem;
    white-space: nowrap;
}

.btn-danger:hover {
    border-color: var(--err-border-strong);
}

.btn-danger:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* ---------- Address type-ahead (AddressField.razor) ----------
   What the listbox and its rows are. Placement differs per surface, so each app sets its own. */

.address-suggestions {
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
}

.address-suggestion {
    display: flex;
    justify-content: space-between;
    gap: 0.6rem;
    cursor: pointer;
}

.address-suggestion:hover,
.address-suggestion.is-active {
    background: var(--accent-soft);
}

.address-suggestion-text {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

/* A saved drop stacks: who it's for, the address, then the merchant's standing notes. A bare
   register match is just the middle line, so the column collapses to one row unstyled. */
.address-suggestion-who {
    font-weight: 700;
}

.address-suggestion-standing {
    font-size: 0.85rem;
    color: var(--accent);
}

/* Only a register hit carries a precision note - a saved drop has already been delivered to. */
.address-suggestion-note {
    flex: none;
    font-size: 0.7rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* ---------- Stop cards, route headers and empty states ----------
   Shared by the driver route and the dispatch desk. Inert in admin and merchant. */

.route-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.route-head-main {
    min-width: 0;
}

.route-status {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin: 0;
}

.stops {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.stops-count {
    color: var(--muted);
    font-weight: 600;
}

.stop {
    display: flex;
    gap: 0.85rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.85rem;
    padding: 1rem;
    box-shadow: var(--shadow-card);
}

.stop-top {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.4rem;
}

.stop-body {
    flex: 1;
    min-width: 0;
}

.stop-address {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0.1rem 0 0.5rem;
    line-height: 1.3;
}

.stop-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
}

.stop-actions {
    margin-top: 0.85rem;
}

.order-id {
    margin-left: auto;
    color: var(--muted);
    font-size: 0.85rem;
    font-weight: 600;
}

.meta {
    font-size: 0.92rem;
}

.meta-label {
    color: var(--muted);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.03em;
    font-weight: 700;
    margin-right: 0.2rem;
}

.footnote {
    margin-top: 1.5rem;
    font-size: 0.9rem;
}

/* A round icon-only control (the refresh button on the route and board heads). 2.6rem clears the
   44px tap target. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    flex-shrink: 0;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 1.25rem;
    line-height: 1;
    box-shadow: var(--shadow-card);
}

.icon-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
    text-decoration: none;
}

/* ---------- Empty / all caught up ---------- */

.empty {
    text-align: center;
    padding: 3rem 1.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.85rem;
    box-shadow: var(--shadow-card);
}

.empty .muted {
    margin: 0;
    max-width: 24rem;
    margin-inline: auto;
}

.empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    margin-bottom: 1rem;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1;
}

.empty-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    margin: 0 0 0.35rem;
}

/* ---------- Badges (shared with console palette) ---------- */

.badge {
    display: inline-block;
    padding: 0.18rem 0.6rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
}

.badge-grey { background: var(--neutral-bg); color: var(--neutral); }

.badge-blue { background: var(--info-bg); color: var(--info); }

.badge-green { background: var(--ok-bg); color: var(--ok); }

.badge-amber { background: var(--warn-bg); color: var(--warn); }

.badge-red { background: var(--err-bg); color: var(--err); }

.badge-next { background: var(--brass); color: var(--ink-2); }

.alert {
    background: var(--err-bg);
    border: 1px solid var(--err-border);
    color: var(--err);
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
}

/* ---------- Result banner ---------- */

.banner {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6rem;
    padding: 0.75rem 1rem;
    border-radius: 0.6rem;
    margin-top: 1.25rem;
    margin-bottom: 1.25rem;
    font-weight: 600;
}

.banner-ok {
    background: var(--ok-bg);
    border: 1px solid var(--ok-border);
    color: var(--ok);
}

.banner-err {
    background: var(--err-bg);
    border: 1px solid var(--err-border);
    color: var(--err);
}

/* Succeeded-with-caveats lines inside a .banner-ok. Lives here because ResultBanner renders it for
   every app, not just the ones that pass Warnings today. */
.banner-warn {
    font-size: 0.88rem;
    font-weight: 600;
}

.banner-close {
    margin-left: auto;
    background: none;
    border: none;
    color: inherit;
    font-size: 1rem;
    cursor: pointer;
    opacity: 0.7;
    padding: 0.2rem 0.3rem;
    line-height: 1;
}

.banner-close:hover {
    opacity: 1;
    text-decoration: none;
}

/* ---------- Blazor error UI ---------- */

#blazor-error-ui {
    background: var(--warn-bg);
    border-top: 1px solid var(--warn-border);
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.1);
    display: none;
    left: 0;
    padding: 0.75rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 1rem;
    top: 0.75rem;
}

/* ---------- Sign-in + install prompt ---------- */

/* Sign-in failures (wrong code, rate limited). Distinct from the in-route action banners: this one sits
   under the form rather than at the top of a stop card. */
.signin-error {
    margin: 1rem 0 0;
    padding: 0.75rem 1rem;
    border-radius: 0.6rem;
    border: 1px solid var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--text);
}

/* A text-weight button for secondary choices ("use a different number", "not now") - a real <button> so it
   stays keyboard-reachable, styled to read as a link. */
.btn-link {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--accent);
    text-decoration: underline;
    cursor: pointer;
}

.btn-link:disabled {
    opacity: 0.55;
    cursor: default;
}

/* The add-to-home-screen nudge. Kept visually quiet: it is advice, not a blocker - but it is what keeps an
   iPhone driver signed in past seven days, so it should not be easy to miss either. */
.install-prompt {
    margin: 1.75rem 0 0;
    padding: 1rem;
    border: 1px dashed var(--border);
    border-radius: 0.6rem;
    background: var(--surface);
}

.install-prompt p {
    margin: 0 0 0.75rem;
    font-size: 0.95rem;
}

.install-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
