/* =========================================================================
   TransitLive Web — Components
   Ports AlertCardComponents / GOAlertCard / UpcomingTab cards, the arrivals
   sheet, and the shared chip / badge / button vocabulary.
   ========================================================================= */

/* =========================================================================
   ALERT CARD
   ========================================================================= */
.alert-card {
    background: var(--ds-bg-secondary);
    border: var(--ds-stroke-hairline) solid var(--ds-hairline);
    border-radius: var(--ds-radius-20);
    overflow: hidden;
    /* Severity hue lands here; every child reads it. */
    --sev: var(--ds-alert-orange);
    --sev-rgb: 255, 159, 28;
}

.alert-card--suspended { --sev: var(--ds-alert-red);     --sev-rgb: 239, 68, 68; }
.alert-card--delay     { --sev: var(--ds-alert-orange);  --sev-rgb: 255, 159, 28; }
.alert-card--shuttle   { --sev: var(--ds-shuttle-blue);  --sev-rgb: 59, 130, 246; }
.alert-card--access    { --sev: var(--ds-accessible-blue); --sev-rgb: 82, 140, 203; }

/* --- Header ------------------------------------------------------------ */
.alert-card__head {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-12) var(--ds-space-14);
    /* The radial wash behind the header — the app's signature severity cue. */
    background:
        radial-gradient(120% 180% at 8% 50%,
            rgba(var(--sev-rgb), var(--ds-tint-wash-soft)) 0%,
            rgba(var(--sev-rgb), var(--ds-tint-wash-faint)) 38%,
            transparent 72%);
}

.alert-card__head::after {
    /* Hairline divider that stops short of the card edges, like the app. */
    content: "";
    position: absolute;
    left: var(--ds-space-16);
    right: 0;
    bottom: 0;
    height: var(--ds-stroke-hairline);
    background: var(--ds-hairline);
}

.sev-tile {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-10);
    background: var(--sev);
    color: #000;
    box-shadow: 0 0 16px rgba(var(--sev-rgb), var(--ds-glow-severity-alpha));
}

.sev-tile .icon { width: 20px; height: 20px; }

/* Shuttle / accessibility tiles carry light glyphs on their saturated fill. */
.alert-card--shuttle .sev-tile,
.alert-card--access .sev-tile { color: #fff; }

.alert-card__headings { flex: 1 1 auto; min-width: 0; }

.alert-card__title {
    margin: 0;
    font-size: var(--ds-fs-17);
    font-weight: var(--ds-fw-bold);
    color: var(--sev);
    letter-spacing: -0.01em;
    line-height: 1.2;
}

.alert-card--suspended .alert-card__title { color: var(--ds-text-red); }
.alert-card--delay .alert-card__title     { color: var(--ds-text-orange); }
.alert-card--shuttle .alert-card__title   { color: var(--ds-text-blue); }

.alert-card__subtitle {
    margin: 1px 0 0;
    font-size: var(--ds-fs-13);
    color: var(--ds-label-secondary);
    line-height: 1.25;
}

/* --- Line badge -------------------------------------------------------- */
.line-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-4);
    padding: var(--ds-space-4) var(--ds-space-10);
    border-radius: var(--ds-radius-pill);
    background: var(--line-color, var(--ds-label-secondary));
    color: var(--line-ink, var(--ds-ink-on-light));
    font-size: var(--ds-fs-12);
    font-weight: var(--ds-fw-bold);
    white-space: nowrap;
}

/* Circular numbered variant used in route rows and arrivals. */
.line-dot {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--line-color, var(--ds-label-secondary));
    color: var(--line-ink, var(--ds-ink-on-light));
    font-family: var(--ds-font-rounded);
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-heavy);
    font-variant-numeric: var(--ds-numeric);
}

/* --- Body -------------------------------------------------------------- */
.alert-card__body {
    padding: var(--ds-space-14);
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-10);
}

/* Station pair: dot — connecting rule — dot */
.route-row {
    display: flex;
    align-items: center;
    gap: var(--ds-space-10);
}

.route-row__name {
    font-size: var(--ds-fs-18);
    font-weight: var(--ds-fw-bold);
    color: var(--ds-label-primary);
    letter-spacing: var(--ds-tracking-title);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 42%;
}

.route-row__rule {
    flex: 1 1 auto;
    height: 3px;
    border-radius: 2px;
    background: var(--line-color, var(--ds-label-tertiary));
    min-width: var(--ds-space-16);
}

.route-row__stop {
    flex: 0 0 auto;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 2.5px solid var(--line-color, var(--ds-label-tertiary));
    background: var(--ds-bg-secondary);
}

/* Suspended segment: dashed rule + a caption underneath. */
.route-track {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-6);
}

.route-track__rule--dashed {
    flex: 1 1 auto;
    height: 4px;
    min-width: var(--ds-space-16);
    background-image: linear-gradient(to right,
        var(--line-color, var(--ds-label-tertiary)) 0 62%, transparent 62% 100%);
    background-size: 13px 4px;
    background-repeat: repeat-x;
}

.route-track__caption {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-6);
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-text-red);
}

.route-track__caption .icon { width: 17px; height: 17px; }

.route-track__caption--shuttle { color: var(--ds-text-blue); }

.route-track__caption--shuttle::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ds-system-green);
}

/* Shuttle line with the bus glyph pinned mid-span. */
.shuttle-line {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ds-space-10);
}

.shuttle-line__rule {
    flex: 1 1 auto;
    height: 3px;
    border-radius: 2px;
    background: var(--ds-shuttle-blue);
}

.shuttle-line__stop {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--ds-shuttle-blue);
}

.shuttle-line__glyph {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-8);
    background: var(--ds-shuttle-blue);
    color: #fff;
    border: 2px solid var(--ds-bg-secondary);
    box-shadow: var(--ds-glow-shuttle-dot);
}

.shuttle-line__glyph .icon { width: 17px; height: 17px; }

/* --- Chips ------------------------------------------------------------- */
.meta-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-6);
    align-self: flex-start;
    padding: var(--ds-space-5) var(--ds-space-10);
    border-radius: var(--ds-radius-pill);
    background: var(--ds-fill-neutral);
    color: var(--ds-label-secondary);
    font-size: var(--ds-fs-13);
    font-weight: var(--ds-fw-semibold);
}

.meta-chip .icon { width: 15px; height: 15px; }

.alert-card__text {
    margin: 0;
    font-size: var(--ds-fs-15);
    line-height: var(--ds-lh-body);
    color: var(--ds-label-secondary);
}

/* --- Schedule sub-card (Upcoming) -------------------------------------- */
.schedule-card {
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-12);
    border-radius: var(--ds-radius-12);
    background: var(--ds-fill-subtle);
}

.schedule-card__tile {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-10);
    background: rgba(var(--sev-rgb), var(--ds-tint-severity-fill));
    color: var(--sev);
}

.schedule-card__cols {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    min-width: 0;
}

.schedule-card__col { min-width: 0; }

.schedule-card__label {
    font-size: var(--ds-fs-11);
    font-weight: var(--ds-fw-bold);
    letter-spacing: var(--ds-tracking-caps);
    text-transform: uppercase;
    color: var(--ds-label-tertiary);
}

.schedule-card__date {
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-label-primary);
    white-space: nowrap;
}

.schedule-card__time {
    font-size: var(--ds-fs-13);
    color: var(--ds-label-secondary);
    font-variant-numeric: var(--ds-numeric);
}

.schedule-card__arrow { color: var(--ds-label-tertiary); flex: 0 0 auto; }

.cadence-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-4);
    padding: 3px var(--ds-space-10);
    border-radius: var(--ds-radius-pill);
    background: rgba(var(--sev-rgb), var(--ds-tint-severity-fill));
    color: var(--sev);
    font-size: var(--ds-fs-13);
    font-weight: var(--ds-fw-bold);
    margin-bottom: var(--ds-space-6);
}

.cadence-chip .icon { width: 13px; height: 13px; }

/* --- Shuttle banner ---------------------------------------------------- */
.shuttle-banner {
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-12);
    border-radius: var(--ds-radius-12);
    background: rgba(59, 130, 246, var(--ds-tint-wash-faint));
    border: var(--ds-stroke-thin) solid rgba(59, 130, 246, var(--ds-tint-shuttle-border));
}

.shuttle-banner__tile {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-10);
    background: var(--ds-shuttle-blue);
    color: #fff;
}

.shuttle-banner__title {
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-bold);
    color: var(--ds-text-blue);
}

.shuttle-banner__meta {
    font-size: var(--ds-fs-13);
    color: var(--ds-label-secondary);
    display: flex;
    align-items: center;
    gap: var(--ds-space-6);
}

.shuttle-banner__meta b {
    color: var(--ds-text-blue);
    font-weight: var(--ds-fw-semibold);
}

.shuttle-banner__meta b::before {
    content: "•";
    margin-right: var(--ds-space-4);
}

/* --- Footer actions ---------------------------------------------------- */
.alert-card__foot {
    display: flex;
    align-items: center;
    gap: var(--ds-space-10);
    padding: var(--ds-space-10) var(--ds-space-14) var(--ds-space-12);
    border-top: var(--ds-stroke-hairline) solid var(--ds-hairline);
}

.action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-space-8);
    height: 38px;
    padding: 0 var(--ds-space-14);
    border: 0;
    border-radius: var(--ds-radius-10);
    background: var(--ds-fill-neutral);
    color: var(--ds-label-primary);
    font-family: inherit;
    font-size: var(--ds-fs-14);
    font-weight: var(--ds-fw-semibold);
    cursor: pointer;
    transition: background var(--ds-dur-fast) var(--ds-ease-smooth),
                transform var(--ds-dur-fast) var(--ds-ease-smooth);
}

.action-btn:active { transform: scale(0.97); }
.action-btn--grow { flex: 1 1 auto; }

.action-btn--icon {
    width: 38px;
    padding: 0;
    flex: 0 0 auto;
    color: var(--ds-label-secondary);
}

.action-btn--icon.is-on { color: var(--ds-alert-orange); }

/* =========================================================================
   EMPTY / LOADING STATES
   ========================================================================= */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-60) var(--ds-space-24);
    text-align: center;
}

.empty-state__glyph {
    width: 64px;
    height: 64px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: rgba(48, 209, 88, 0.12);
    color: var(--ds-system-green);
}

.empty-state__glyph .icon { width: 34px; height: 34px; }
.empty-state--neutral .empty-state__glyph { background: rgba(255,255,255,0.06); color: var(--ds-label-tertiary); }

.empty-state__title {
    font-size: var(--ds-fs-22);
    font-weight: var(--ds-fw-bold);
    color: var(--ds-label-primary);
    letter-spacing: var(--ds-tracking-title);
}

.empty-state__text {
    font-size: var(--ds-fs-15);
    color: var(--ds-label-secondary);
    max-width: 30ch;
}

.skeleton {
    border-radius: var(--ds-radius-20);
    height: 168px;
    background: linear-gradient(100deg,
        var(--ds-bg-secondary) 30%,
        rgba(255, 255, 255, 0.05) 50%,
        var(--ds-bg-secondary) 70%);
    background-size: 220% 100%;
    animation: skeleton-sweep 1.4s var(--ds-ease-in-out) infinite;
}

@keyframes skeleton-sweep { from { background-position: 180% 0; } to { background-position: -60% 0; } }

/* =========================================================================
   BOTTOM SHEET  (ArrivalsSheet / AlertOverlayCard / Alert Guide / Settings)
   ========================================================================= */
.scrim {
    position: fixed;
    inset: 0;
    z-index: 45;
    background: rgba(0, 0, 0, 0.4);
    opacity: 0;
    transition: opacity var(--ds-dur-scene) var(--ds-ease-smooth);
}

.scrim.is-open { opacity: 1; }

.sheet {
    position: fixed;
    z-index: 50;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    border-radius: var(--ds-radius-28-sq) var(--ds-radius-28-sq) 0 0;
    background: var(--ds-bg-secondary);
    border-top: var(--ds-stroke-hairline) solid var(--ds-hairline);
    box-shadow: 0 -8px 48px rgba(0, 0, 0, 0.45);
    transform: translateY(100%);
    transition: transform var(--ds-dur-settle) var(--ds-ease-spring-soft);
    overflow: hidden;
    padding-bottom: var(--ds-safe-bottom);
}

.sheet.is-open { transform: none; }

/* Ambient severity/line glow bleeding from the sheet's top edge — the
   SheetMotionDriver gradient, minus the gyro (no equivalent on the web). */
.sheet__glow {
    position: absolute;
    inset: 0 0 auto 0;
    height: 240px;
    pointer-events: none;
    background: radial-gradient(80% 100% at 50% 0%,
        rgba(var(--glow-rgb, 255, 205, 0), 0.20) 0%,
        rgba(var(--glow-rgb, 255, 205, 0), 0.07) 42%,
        transparent 76%);
    opacity: var(--glow-on, 0);
    transition: opacity var(--ds-dur-scene) var(--ds-ease-smooth);
}

.grabber {
    flex: 0 0 auto;
    width: 40px;
    height: 5px;
    border-radius: var(--ds-radius-pill);
    background: var(--ds-separator-opaque);
    margin: var(--ds-space-8) auto var(--ds-space-4);
    position: relative;
    z-index: 1;
}

.sheet__head {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-6) var(--ds-space-20) var(--ds-space-10);
}

.sheet__title {
    flex: 1 1 auto;
    margin: 0;
    font-size: var(--ds-fs-28);
    font-weight: var(--ds-fw-bold);
    letter-spacing: var(--ds-tracking-title);
    color: var(--ds-label-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sheet__head-actions { display: flex; gap: var(--ds-space-8); flex: 0 0 auto; }

.sheet__body {
    position: relative;
    z-index: 1;
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0 var(--ds-space-20) var(--ds-space-20);
}

/* =========================================================================
   ARRIVALS ROWS
   ========================================================================= */
.arrival-row {
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    padding: var(--ds-space-11) 0;
    border-bottom: var(--ds-stroke-hairline) solid var(--ds-hairline);
}

.arrival-row:last-child { border-bottom: 0; }

.arrival-row__text { flex: 1 1 auto; min-width: 0; }

.arrival-row__dir {
    font-size: var(--ds-fs-18);
    font-weight: var(--ds-fw-bold);
    color: var(--ds-label-primary);
    letter-spacing: var(--ds-tracking-title);
}

.arrival-row__dest {
    font-size: var(--ds-fs-14);
    color: var(--ds-label-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.arrival-row__times { display: flex; gap: var(--ds-space-8); flex: 0 0 auto; }

.time-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-6);
    min-width: 66px;
    justify-content: center;
    padding: var(--ds-space-8) var(--ds-space-12);
    border-radius: var(--ds-radius-pill);
    background: var(--ds-fill-neutral);
    color: var(--ds-label-primary);
    font-family: var(--ds-font-rounded);
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-heavy);
    font-variant-numeric: var(--ds-numeric);
    white-space: nowrap;
}

.time-chip .icon { width: 15px; height: 15px; }

/* Due — imminent, green. */
.time-chip--due {
    background: rgba(48, 209, 88, var(--ds-tint-severity-fill));
    color: var(--ds-text-green);
}

.time-chip--due::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ds-system-green);
    box-shadow: var(--ds-glow-live);
}

/* Alerted — this trip is inside a delay, orange outline. */
.time-chip--alerted {
    background: rgba(255, 159, 28, var(--ds-tint-wash-faint));
    border: var(--ds-stroke-thin) solid rgba(255, 159, 28, 0.45);
    color: var(--ds-text-orange);
}

/* Scheduled (no live prediction) — de-emphasised with a clock glyph. */
.time-chip--scheduled { color: var(--ds-label-tertiary); }

/* =========================================================================
   SETTINGS  (grouped-list port)
   ========================================================================= */
.settings-group { margin-bottom: var(--ds-space-28); }

.settings-group__head {
    font-size: var(--ds-fs-13);
    font-weight: var(--ds-fw-bold);
    letter-spacing: var(--ds-tracking-caps-tight);
    text-transform: uppercase;
    color: var(--ds-label-secondary);
    padding: 0 var(--ds-space-4) var(--ds-space-8);
}

.settings-card {
    background: var(--ds-fill-subtle);
    border-radius: var(--ds-radius-14-sq);
    overflow: hidden;
}

/* Two cards in one group are two groupings — without a gap they butt into a
   single block and the split says nothing. iOS separates sibling insets the
   same way. */
.settings-card + .settings-card { margin-top: var(--ds-space-16); }

.settings-row {
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    min-height: 52px;
    padding: var(--ds-space-12) var(--ds-space-16);
    position: relative;
}

.settings-row + .settings-row::before {
    content: "";
    position: absolute;
    top: 0;
    left: var(--ds-space-16);
    right: 0;
    height: var(--ds-stroke-hairline);
    background: var(--ds-hairline);
}

.settings-row__label {
    flex: 1 1 auto;
    font-size: var(--ds-fs-17);
    color: var(--ds-label-primary);
}

.settings-row__value {
    font-size: var(--ds-fs-17);
    color: var(--ds-label-secondary);
    font-variant-numeric: var(--ds-numeric);
    /* A row showing a value AND a chevron has to lay them out together; a
       text-only value (the common case) renders identically either way. */
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-6);
}

/* A row that is a button still has to look like a row, not a button. */
button.settings-row {
    width: 100%;
    background: none;
    border: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

button.settings-row:active { background: var(--ds-fill-active); }

.settings-foot {
    font-size: var(--ds-fs-13);
    line-height: var(--ds-lh-body);
    color: var(--ds-label-secondary);
    padding: var(--ds-space-8) var(--ds-space-4) 0;
}

/* iOS switch */
.switch {
    position: relative;
    flex: 0 0 auto;
    width: 51px;
    height: 31px;
    border-radius: var(--ds-radius-pill);
    border: 0;
    padding: 0;
    background: rgba(120, 120, 128, 0.32);
    cursor: pointer;
    transition: background var(--ds-dur-fast) var(--ds-ease-smooth);
}

.switch::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
    transition: transform var(--ds-dur-fast) var(--ds-ease-smooth);
}

.switch[aria-checked="true"] { background: var(--ds-system-green); }
.switch[aria-checked="true"]::after { transform: translateX(20px); }

/* Segmented control (Appearance) */
.segmented {
    position: relative;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    padding: 2px;
    margin: var(--ds-space-8) var(--ds-space-12) var(--ds-space-4);
    border-radius: var(--ds-radius-pill);
    background: rgba(120, 120, 128, 0.24);
}

.segmented__opt {
    appearance: none;
    border: 0;
    background: transparent;
    border-radius: var(--ds-radius-pill);
    padding: var(--ds-space-8) var(--ds-space-12);
    font-family: inherit;
    font-size: var(--ds-fs-15);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-label-primary);
    cursor: pointer;
}

.segmented__opt[aria-selected="true"] {
    background: var(--ds-glass-pill-legacy);
    box-shadow: var(--ds-shadow-pill);
}

/* Slider (Panel glass) */
.slider {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 4px;
    border-radius: 2px;
    background: linear-gradient(to right,
        var(--ds-label-primary) 0 var(--fill, 55%),
        rgba(120, 120, 128, 0.32) var(--fill, 55%) 100%);
    outline: none;
}

.slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    cursor: pointer;
}

.slider::-moz-range-thumb {
    width: 28px; height: 28px; border: 0; border-radius: 50%;
    background: #fff; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); cursor: pointer;
}

/* =========================================================================
   ALERT GUIDE (legend) rows
   ========================================================================= */
.legend-row {
    display: flex;
    align-items: flex-start;
    gap: var(--ds-space-18);
    padding: var(--ds-space-16) 0;
    position: relative;
}

.legend-row + .legend-row::before {
    content: "";
    position: absolute;
    top: 0;
    left: 92px;
    right: 0;
    height: var(--ds-stroke-hairline);
    background: var(--ds-hairline);
}

.legend-swatch {
    position: relative;
    flex: 0 0 auto;
    width: 74px;
    height: 18px;
    border-radius: var(--ds-radius-pill);
    background: var(--swatch, var(--ds-alert-orange));
    box-shadow: 0 0 12px rgba(var(--swatch-rgb, 255, 159, 28), 0.55);
    margin-top: 4px;
}

/* Single-station alerts are not a coloured span — they are a dot ON the track,
   so the swatch has to read differently from Suspension or the two rows are
   indistinguishable. Muted track bar, pulsing dot centred on it, which is
   exactly what the map draws. */
.legend-swatch--station {
    background: var(--ds-label-quaternary);
    box-shadow: none;
}

.legend-swatch--station::before,
.legend-swatch--station::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    border-radius: 50%;
    transform: translate(-50%, -50%);
}

/* Expanding halo — the "pulsing" the copy describes. */
.legend-swatch--station::before {
    width: 26px;
    height: 26px;
    background: rgba(var(--swatch-rgb, 239, 68, 68), 0.55);
    animation: legend-station-pulse var(--ds-dur-alert-pulse) var(--ds-ease-out) infinite;
}

/* Solid core, always visible. */
.legend-swatch--station::after {
    width: 16px;
    height: 16px;
    background: var(--swatch, var(--ds-alert-red));
    box-shadow: 0 0 10px rgba(var(--swatch-rgb, 239, 68, 68), 0.8);
}

@keyframes legend-station-pulse {
    0%   { transform: translate(-50%, -50%) scale(0.6); opacity: 0.55; }
    70%  { opacity: 0; }
    100% { transform: translate(-50%, -50%) scale(1.9); opacity: 0; }
}

body.battery-saver .legend-swatch--station::before { animation: none; opacity: 0.35; }

@media (prefers-reduced-motion: reduce) {
    .legend-swatch--station::before { animation: none; opacity: 0.35; }
}

.legend-row__title {
    font-size: var(--ds-fs-20);
    font-weight: var(--ds-fw-bold);
    color: var(--ds-label-primary);
}

.legend-row__text {
    font-size: var(--ds-fs-17);
    color: var(--ds-label-secondary);
    line-height: var(--ds-lh-body);
}

/* =========================================================================
   DESKTOP
   ========================================================================= */
@media (min-width: 900px) {
    .sheet {
        left: auto;
        right: var(--ds-space-24);
        bottom: var(--ds-space-24);
        width: min(440px, 38vw);
        max-height: min(720px, calc(100vh - 140px));
        border-radius: var(--ds-radius-28-sq);
        transform: translateY(24px);
        opacity: 0;
        transition: transform var(--ds-dur-settle) var(--ds-ease-spring-soft),
                    opacity var(--ds-dur-select) var(--ds-ease-smooth);
    }

    .sheet.is-open { transform: none; opacity: 1; }
    .sheet__title { font-size: var(--ds-fs-28); }
    .grabber { display: none; }
    .scrim { background: rgba(0, 0, 0, 0.25); }
}

/* =========================================================================
   AD SLOTS
   Ports AdViews.swift: a thin adaptive banner pinned above the floating tab
   bar, and a native "SPONSORED" card that slots into the feed.

   Both COLLAPSE TO NOTHING until an ad actually fills them — the app reports
   a zero size on no-fill specifically so the layout does not reserve a blank
   rectangle, and the web should not be worse. A slot only takes up space once
   .is-filled is set, which Ads.fill() does when a provider renders into it.
   ========================================================================= */

.ad-slot {
    display: none;
    position: relative;
}

.ad-slot.is-filled { display: block; }

/* --- In-feed sponsored card ------------------------------------------- */
.ad-card {
    background: var(--ds-bg-secondary);
    border: var(--ds-stroke-hairline) solid var(--ds-hairline);
    border-radius: var(--ds-radius-20);
    padding: var(--ds-space-12) var(--ds-space-14) var(--ds-space-14);
}

.ad-card__head {
    display: flex;
    align-items: center;
    gap: var(--ds-space-8);
    margin-bottom: var(--ds-space-10);
}

/* 9pt heavy, tertiary — the app's exact treatment for this label. */
.ad-card__label {
    flex: 1 1 auto;
    font-size: var(--ds-fs-9);
    font-weight: var(--ds-fw-heavy);
    letter-spacing: var(--ds-tracking-caps);
    text-transform: uppercase;
    color: var(--ds-label-tertiary);
}

.ad-card__cta {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    height: 28px;
    padding: 0 var(--ds-space-12);
    border: 0;
    border-radius: var(--ds-radius-pill);
    background: var(--ds-system-blue);
    color: #fff;
    font-family: inherit;
    font-size: var(--ds-fs-12);
    font-weight: var(--ds-fw-bold);
    cursor: pointer;
}

/* The provider renders into this. 10px radius matches the app's media view. */
.ad-card__media {
    border-radius: var(--ds-radius-10);
    overflow: hidden;
    min-height: 120px;
}

.ad-card__media > * { max-width: 100%; display: block; }

/* --- Bottom banner -----------------------------------------------------
   Anchored bottom-LEFT and capped so it never reaches the map's right-hand
   FAB cluster (near-me + recenter). Full width and centred put it exactly on
   top of those buttons on a phone: at 375px the banner ran 16 to 359 and the
   recenter button lives at 315 to 359.

   --ad-banner-clear-right is the space the right cluster needs: a 44px FAB
   plus its 16px gutter plus a 12px gap. */
.ad-banner {
    --ad-banner-clear-right: 72px;
    position: fixed;
    z-index: 35;
    left: var(--ds-space-16);
    transform: none;
    /* Sits directly above the floating tab bar, clearing the safe area. */
    bottom: calc(var(--ds-safe-bottom) + var(--ds-space-12) + 56px + var(--ds-space-8));
    width: calc(100% - var(--ds-space-16) - var(--ad-banner-clear-right));
    max-width: 468px;
    border-radius: var(--ds-radius-12);
    overflow: hidden;
    background: var(--ds-bg-secondary);
    border: var(--ds-stroke-hairline) solid var(--ds-hairline);
    box-shadow: var(--ds-shadow-toast);
}

.ad-banner > * { max-width: 100%; display: block; }

/* Map tab only.
   The list tabs already carry in-feed sponsored cards, so a fixed banner over
   them as well is two ads stacked at the bottom of one screen — and it sits
   right on the tab bar. Buses has its own panel over the bottom of the screen.
   `:not([attr])` rather than `:has()`, which is a parse-time failure on older
   Safari and would take the whole block down with it. */
body:not([data-tab="map"]) .ad-banner { display: none !important; }

@media (min-width: 900px) {
    .ad-banner {
        left: var(--ds-space-24);
        width: var(--ds-tabbar-max);
        /* Clear of the tab bar, which anchors bottom-left on desktop. */
        bottom: calc(var(--ds-space-24) + 56px + var(--ds-space-8));
    }
}

/* =========================================================================
   STATION ALERT BANNER
   Shown at the top of the arrivals sheet when the station is inside an active
   disruption — the times below mean something different if it is.
   ========================================================================= */
.station-alert {
    display: flex;
    align-items: center;
    gap: var(--ds-space-12);
    width: 100%;
    margin-bottom: var(--ds-space-12);
    padding: var(--ds-space-10) var(--ds-space-12);
    border: 0;
    border-radius: var(--ds-radius-12);
    background: rgba(var(--sev-rgb), var(--ds-tint-wash-faint));
    box-shadow: inset 0 0 0 var(--ds-stroke-thin) rgba(var(--sev-rgb), 0.28);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    --sev: var(--ds-alert-orange);
    --sev-rgb: 255, 159, 28;
}

.station-alert--suspended { --sev: var(--ds-alert-red); --sev-rgb: 239, 68, 68; }

.station-alert__tile {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-8);
    background: var(--sev);
    color: #000;
}

.station-alert__tile .icon { width: 17px; height: 17px; }

.station-alert__text { flex: 1 1 auto; min-width: 0; }

.station-alert__title {
    display: block;
    font-size: var(--ds-fs-14);
    font-weight: var(--ds-fw-bold);
    color: var(--sev);
}

.station-alert__where {
    display: block;
    font-size: var(--ds-fs-12);
    color: var(--ds-label-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.station-alert__chev {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    color: var(--ds-label-tertiary);
}

/* Collapsed stand-in for a muted alert — present enough that the alert is not
   silently gone, quiet enough to stay out of the way, with a way back. */
.muted-alert {
    display: flex;
    align-items: center;
    gap: var(--ds-space-10);
    padding: var(--ds-space-10) var(--ds-space-14);
    border-radius: var(--ds-radius-12);
    background: var(--ds-fill-subtle);
    color: var(--ds-label-tertiary);
    font-size: var(--ds-fs-13);
}

.muted-alert__dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--chip-color, var(--ds-label-tertiary));
    opacity: 0.55;
}

.muted-alert__text {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.muted-alert__undo {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    padding: var(--ds-space-4) var(--ds-space-6);
    font-family: inherit;
    font-size: var(--ds-fs-13);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-text-blue);
    cursor: pointer;
}

/* The direction arrow is one glyph rotated per compass point — see
   Components.directionChip. */
.meta-chip__arrow { transition: transform var(--ds-dur-fast) var(--ds-ease-smooth); }

/* --- Ad slot placeholders (preview only) -------------------------------
   Shown when Settings → Preview ad slots is on, so placement can be judged
   before a provider is wired up. Deliberately obvious: a dashed outline and
   the word "slot", so it can never be mistaken for a real ad. */
.ad-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    border: 1px dashed var(--ds-label-quaternary);
    border-radius: var(--ds-radius-10);
    color: var(--ds-label-tertiary);
    text-align: center;
}

.ad-placeholder--feed { min-height: 120px; }
.ad-placeholder--banner { height: 50px; border-radius: var(--ds-radius-8); }

.ad-placeholder__tag {
    font-size: var(--ds-fs-11);
    font-weight: var(--ds-fw-bold);
    letter-spacing: var(--ds-tracking-caps);
    text-transform: uppercase;
}

.ad-placeholder__dim {
    font-size: var(--ds-fs-10);
    font-variant-numeric: var(--ds-numeric);
}

.ad-banner.is-preview { padding: var(--ds-space-4); }


/* =========================================================================
   HIGHLIGHTED SETTINGS ROW
   For the one row that is an announcement rather than a control. Carries the
   brand accent and a slow breath so it draws the eye without behaving like a
   button the user can press — there is nothing to press yet.
   ========================================================================= */
.settings-card--feature {
    position: relative;
    background: linear-gradient(
        135deg,
        rgba(236, 105, 100, 0.14),
        rgba(255, 205, 0, 0.08)
    );
    box-shadow: inset 0 0 0 var(--ds-stroke-thin) rgba(236, 105, 100, 0.32),
                0 0 22px rgba(236, 105, 100, 0.18);
    animation: feature-breathe 3.2s var(--ds-ease-in-out) infinite alternate;
}

@keyframes feature-breathe {
    from {
        box-shadow: inset 0 0 0 var(--ds-stroke-thin) rgba(236, 105, 100, 0.28),
                    0 0 14px rgba(236, 105, 100, 0.12);
    }
    to {
        box-shadow: inset 0 0 0 var(--ds-stroke-thin) rgba(236, 105, 100, 0.48),
                    0 0 30px rgba(236, 105, 100, 0.30);
    }
}

.settings-card--feature .settings-row__label {
    font-weight: var(--ds-fw-semibold);
}

/* The "Coming soon" side reads as a badge, not as a settings value. */
.settings-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-6);
    padding: var(--ds-space-4) var(--ds-space-10);
    border-radius: var(--ds-radius-pill);
    background: rgba(236, 105, 100, 0.18);
    color: var(--ds-brand-coral);
    font-size: var(--ds-fs-12);
    font-weight: var(--ds-fw-bold);
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.settings-badge .icon { width: 13px; height: 13px; }

body.light-mode .settings-badge { color: #C0433E; }

/* =========================================================================
   WIDGET SETUP  (Settings › Home Screen widget)
   Numbered steps for pasting the Scriptable widget in. Reuses the grouped-
   list vocabulary above; the only new shapes are the step number and the
   monospace literals in the line-filter example.
   ========================================================================= */

.setup-intro {
    font-size: var(--ds-fs-15);
    line-height: var(--ds-lh-body);
    color: var(--ds-label-secondary);
    padding: 0 var(--ds-space-4) var(--ds-space-16);
}

.setup-step {
    display: flex;
    align-items: flex-start;
    gap: var(--ds-space-12);
    padding: var(--ds-space-14) var(--ds-space-16);
    position: relative;
}

/* Inset past the number, so the rule separates the steps' text and does not
   cut through the column of digits. */
.setup-step + .setup-step::before {
    content: "";
    position: absolute;
    top: 0;
    left: calc(var(--ds-space-16) + 26px + var(--ds-space-12));
    right: 0;
    height: var(--ds-stroke-hairline);
    background: var(--ds-hairline);
}

.setup-step__n {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: var(--ds-radius-pill);
    background: rgba(236, 105, 100, 0.18);
    color: var(--ds-brand-coral);
    font-size: var(--ds-fs-13);
    font-weight: var(--ds-fw-bold);
    font-variant-numeric: var(--ds-numeric);
}

body.light-mode .setup-step__n { color: #C0433E; }

.setup-step__body {
    flex: 1 1 auto;
    min-width: 0;
}

.setup-step__title {
    font-size: var(--ds-fs-16);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-label-primary);
    margin-bottom: var(--ds-space-2);
}

.setup-step__text {
    font-size: var(--ds-fs-14);
    line-height: var(--ds-lh-body);
    color: var(--ds-label-secondary);
}

.setup-step__text + .setup-step__text { margin-top: var(--ds-space-8); }

.setup-step__text strong {
    color: var(--ds-label-primary);
    font-weight: var(--ds-fw-semibold);
}

/* The App Store step's button is an anchor; without this it carries the
   inherited underline and stops matching the button beside it. */
.setup-step .action-btn {
    margin-top: var(--ds-space-10);
    text-decoration: none;
}

.setup-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--ds-fs-13);
    padding: 1px var(--ds-space-5);
    border-radius: var(--ds-radius-5);
    background: var(--ds-fill-neutral);
    color: var(--ds-label-primary);
    white-space: nowrap;
}

/* Battery saver already means "stop animating things"; honour it here too. */
body.battery-saver .settings-card--feature,
body.battery-saver .settings-badge__pulse { animation: none; }

@media (prefers-reduced-motion: reduce) {
    .settings-card--feature,
    .settings-badge__pulse { animation: none; }
}
