/* ============================================================================
   DRIVER APP — the real stylesheet.
   ----------------------------------------------------------------------------
   This file is the answer to design-system debt 05: "643 lines of CSS inside
   views/mobile/layout.ejs. They cannot be linked, cached, shared, or loaded by
   this document — extracting them is a prerequisite for the mobile restyle, not
   a cleanup after it." So the extraction happened first, and this is where it
   landed.

   It is a SKIN of the wireframe system, not a redesign of it. Every class name
   below already existed; the markup in views/mobile/driver/*.ejs is untouched.
   What changed is the list the design system allows a restyle to change: fill,
   radius, shadow, glow, type scale, spacing, mark shapes, motion curves.

   WHAT IT INHERITS, per chapter 03's contract ("Inherits, no discussion"):

     The blue family      Black as the accent was the single biggest thing
                          separating mobile from the product. #111 is gone from
                          this file entirely — it is navy #092C4C now, the same
                          ink the landing and the dashboard spend.
     Inter, compensated   Self-hosted variable Inter (see fonts.css), so weight
                          450 is a real instance. Body 450, emphasis 500, small
                          caps 600 — not the wireframe's 600/700 on every label,
                          chip, tab and button.
     Radius minimum 6px   Cards at 2px and 4px are the wireframe's tell.
     Caps are micro       9.5–10.5px at 600 with wide tracking, never a 12px/700
                          uppercase section heading. .sec-hd h3 is a real
                          heading now.
     Three motion curves  --d-ease / --d-ease-io / --d-spring, with the duration
                          bands, replacing the wireframe's two keyframes.
     Alfred is the orb    The tab bar hosts a real ai-orb.js canvas, not a black
                          circle with a filled glyph. See § TAB BAR.

   WHAT IT DECIDES, per the same contract ("Open, and genuinely mobile's"):

     Ground     Light. #F8F9FB canvas, white cards, navy ink. A phone is used
                outdoors and the one real argument for the wireframe's light
                ground survives the restyle — but it is the dashboard's light
                COLUMN, warmed and contrast-raised, not the landing's near-black.
                The AI mode is the single exception and goes dark; see
                driver-ai.css for why.
     Elevation  Hairlines stay — but as INK hairlines on the brand navy
                (rgba(9,44,76,·)), never neutral grey. Shadow is used, but the
                dashboard's soft 30px blur is expensive on a phone GPU and
                nearly invisible at arm's length, so the bands here are short
                and tight: --d-lift-1..3 top out at a 24px blur.
     Touch      None of the other three chapters has a touch scale, so this file
                defines one: --d-touch 44 / --d-touch-md 52 / --d-touch-lg 64.
                Hover is not a hierarchy level on a handset; :active is.

   NATIVE CONSTRAINTS — these are not style decisions and they survive any
   restyle, so every value below is carried over unchanged from the wireframe:
   safe-area insets on both bars, truly-fixed chrome with matching .scroll
   padding, the 480px centred shell, and -webkit-tap-highlight-color:transparent.

   Scoped to nothing: this file is loaded only by views/mobile/driver-layout.ejs.
   The rider app keeps the grayscale wireframe in views/mobile/layout.ejs,
   untouched, until that restyle is its own piece of work.
   ============================================================================ */

:root {
  /* ==========================================================================
     THE ONE HUE. Lifted from app-dark.css's light content column, value for
     value — which is the actual source of truth, as the design system says on
     its own first screen: "marketing.css and app-dark.css — this page loads
     them, it doesn't copy them."

     The first cut of this file took its palette from design-system.css (the
     SkyHop v2 sheet: navy #092C4C with orange #F99D26). That is a different
     system. Alfred is "a near-black surface, blue light arriving from one
     direction" — there is no orange in it. The accent below is the landing's
     own #86b6e8 carried down to a value that has contrast on white (4.6:1),
     exactly as the dashboard's light column does it, so the phone reads as the
     same brand as the public site rather than as a second one.
     ========================================================================== */
  --d-g0: #ffffff;   /* raised surface — cards, bars, fields */
  --d-g1: #ecebef;   /* the canvas behind them */
  --d-g2: #f1f3f7;   /* muted fill */
  --d-g3: #e3e7ee;   /* hairline */
  --d-g4: #cdd5e1;   /* strong hairline */
  --d-g5: #6b7a95;   /* tertiary text */
  --d-g6: #4a5775;   /* secondary text */
  --d-g7: #082541;   /* primary text */
  --d-g8: #041a2e;   /* emphasis */

  /* The accent marks ONE thing. It is never a decoration. */
  --d-accent:      #2c6fb5;
  --d-accent-2:    #1d5896;
  --d-accent-dim:  rgba(44, 111, 181, 0.10);
  --d-accent-line: rgba(44, 111, 181, 0.38);
  /* The landing's own bloom. Only for use ON a dark plate, where it has the
     contrast the light column denies it. */
  --d-bloom:       #86b6e8;
  --d-bloom-halo:  rgba(134, 182, 232, 0.16);

  /* Status. These are the dashboard's light-column values, and they are status
     only — --d-warn is an amber because a warning is amber, not because this
     product has an orange. Direction and state always ship a glyph or a sign
     alongside, never colour on its own. */
  --d-ok:       #17b26a;
  --d-ok-ink:   #0f8f53;
  --d-ok-soft:  rgba(23, 178, 106, 0.10);
  --d-warn:     #e08b2a;
  --d-warn-ink: #b06614;
  --d-warn-soft: rgba(224, 139, 42, 0.12);
  --d-bad:      #f04438;
  --d-bad-ink:  #c0281d;
  --d-bad-soft: rgba(240, 68, 56, 0.10);

  /* ---- Semantic surfaces ---- */
  --d-canvas:  var(--d-g1);
  --d-card:    var(--d-g0);
  --d-sunk:    var(--d-g2);
  --d-sunk-2:  #eef2f8;
  --d-lift:    #f6f8fb;

  /* ---- Ink ---- */
  --d-ink:   var(--d-g7);
  --d-ink-2: var(--d-g6);
  --d-ink-3: var(--d-g5);
  --d-ink-4: #8d99b1;
  --d-ink-on-dark: rgba(232, 236, 245, 0.72);

  /* ---- Hairlines: ink on the brand, never neutral grey. One shadow/border
          colour for the whole surface, as a channel triple. ---- */
  --d-ink-rgb:     9, 44, 76;
  --d-line:        rgba(9, 44, 76, 0.08);
  --d-line-2:      rgba(9, 44, 76, 0.14);
  --d-line-strong: rgba(9, 44, 76, 0.22);
  --d-line-inv:    rgba(255, 255, 255, 0.14);

  /* ---- Elevation. The dashboard's own bands, shortened: a 30px blur is
          expensive on a phone GPU and nearly invisible at arm's length. ---- */
  --d-lift-1: 0 1px 2px rgba(9, 44, 76, 0.05);
  --d-lift-2: 0 2px 8px rgba(9, 44, 76, 0.10);
  --d-lift-3: 0 10px 30px -10px rgba(9, 44, 76, 0.22);
  --d-lift-chrome: 0 1px 0 rgba(9, 44, 76, 0.06), 0 6px 18px -14px rgba(9, 44, 76, 0.30);

  /* ---- The navy plate. The primary action on the light column, matched to
          app-dark.css value for value: the landing's own ground turned the
          other way up, with the lit rim that keeps a dark plate from reading
          as a hole punched in the page. ---- */
  --d-plate:     linear-gradient(180deg, #0F3B63 0%, #082541 58%, #041A2E 100%);
  --d-plate-lit: linear-gradient(180deg, #17507F 0%, #0C3057 58%, #072138 100%);
  --d-plate-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    inset 0 -1px 0 rgba(0, 0, 0, 0.25),
    0 1px 2px rgba(4, 26, 46, 0.28),
    0 8px 20px -10px rgba(4, 26, 46, 0.55);

  /* ---- Radii. 6px is the floor; the plate and its family sit at 10. ---- */
  --d-r-xs:   6px;
  --d-r-sm:   8px;
  --d-r-md:  10px;
  --d-r-lg:  14px;
  --d-r-xl:  18px;
  --d-r-2xl: 24px;
  --d-r-full: 999px;

  /* ---- Touch scale. Mobile's to define; this is the definition. ---- */
  --d-touch:    44px;
  --d-touch-md: 52px;
  --d-touch-lg: 64px;

  /* ---- Motion ---- */
  --d-ease:    cubic-bezier(0.22, 1, 0.36, 1);
  --d-ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --d-spring:  cubic-bezier(0.34, 1.56, 0.64, 1);
  --d-fast:   150ms;
  --d-base:   240ms;
  --d-slow:   400ms;
  --d-slower: 600ms;

  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* ============================================================================
   THE WIREFRAME NAMES, REPOINTED.
   ----------------------------------------------------------------------------
   138 inline styles across the 21 driver templates reach for --w-text-3,
   --w-line, --w-fill and friends. Those are not decoration: an undefined var()
   makes the whole declaration invalid at computed-value time, so dropping the
   names would not have left those rules looking dated — it would have left
   captions inheriting body ink and bordered boxes with no border at all.

   So the names stay and the VALUES move. Every one is an alias onto the token
   above it, which means each of those inline styles keeps the intent it was
   written with (--w-text-3 meant "tertiary", and still does) and picks up the
   new palette without a single edit to the markup. It is the whole restyle
   contract in one block: skin, not structure.

   --w-black is the one worth reading twice. It was #111, and black as the
   accent is the single biggest thing the design system says separated mobile
   from the rest of the product. Every inline style that asked for black now
   gets navy, and there is no #111 left anywhere in this app.
   ========================================================================== */
:root {
  --w-bg:     var(--d-canvas);
  --w-canvas: var(--d-canvas);
  --w-card:   var(--d-card);
  --w-line:   var(--d-line);
  --w-line-2: var(--d-line-2);
  --w-line-3: var(--d-line-strong);
  --w-fill:   var(--d-sunk);
  --w-fill-2: var(--d-sunk-2);
  --w-text:   var(--d-ink);
  --w-text-2: var(--d-ink-2);
  --w-text-3: var(--d-ink-3);
  --w-text-4: var(--d-ink-4);
  --w-black:  var(--d-g7);
  /* Asked for by one template and never defined by the wireframe — it has been
     resolving to nothing this whole time. It is the accent. */
  --w-accent: var(--d-accent);
}

/* ============================================================================
   BASE
   ========================================================================== */
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
html, body { overflow-x: hidden; }
body {
  background: var(--d-canvas);
  font-family: var(--font);
  color: var(--d-ink);
  min-height: 100vh;
  /* 15px, not 14. The wireframe set 14px and then pushed half its labels to
     10px to fit; at arm's length outdoors that is the floor of legible. */
  font-size: 15px;
  font-weight: 450;
  line-height: 1.5;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; border: none; background: none; outline: none; }
button { cursor: pointer; }
ul { list-style: none; }
h1, h2, h3, h4 { font-weight: 500; letter-spacing: -0.02em; line-height: 1.15; }
b, strong { font-weight: 600; }

/* One weight axis, matched to the surface: the light column compensates icons
   exactly the way it compensates type, so 400 here against the dashboard dark
   chrome's 300. */
.material-symbols-outlined {
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  user-select: none;
  vertical-align: middle;
}

/* The micro-label. This replaces every 12px/700 uppercase "section heading" in
   the wireframe — caps are a label here, never a heading. */
.d-caps,
.sec-hd .link,
.stop .lbl,
.kv .k,
.metric .ml,
.strip .k,
.p-stats .ps .l,
.cal-day .dow,
.cal-month .cm-dow,
.tl-item .d,
.doc-row .di .st,
.notif-item .n-info .stamp,
.earn-hero .period,
.hero-trip .hero-tag,
.key-card .kc-label {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--d-ink-3);
}

.tabular, .d-num { font-variant-numeric: tabular-nums; }

/* ============================================================================
   SHELL
   The 480px cap, the fixed bars and the safe-area arithmetic are native
   constraints, carried over value for value.
   ========================================================================== */
.m-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  max-width: 480px;
  margin: 0 auto;
  background: var(--d-canvas);
}

/* ---------- Topbar ---------- */
.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  /* A FIXED height, not a minimum. With min-height the bar grew whenever a
     screen passed a subtitle, so the switch sat a few pixels lower on Trips
     than on a screen without one — the control that is supposed to be the one
     fixed point in the app moved as you walked around it. The title and the
     subtitle both truncate rather than wrap (see .topbar h2 / .sub), so a hard
     height is safe. The AI bar declares the same number. */
  height: calc(64px + var(--safe-top));
  padding: var(--safe-top) 16px 0;
  background: rgba(255, 255, 255, 0.88);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--d-line);
  box-shadow: var(--d-lift-chrome);
  flex-shrink: 0;
  position: fixed; top: 0; left: 0; right: 0;
  max-width: 480px; margin: 0 auto; z-index: 20;
}
/* Three children: the title takes the slack, the actions and the switch refuse
   to shrink below their contents. Nothing in a bar may impose a width the
   viewport cannot give it — one min-width on one control is enough to make
   every screen scroll sideways, which is exactly how the dashboard lost its
   phone layout for as long as the dark theme existed.

   THE SWITCH IS LAST, AND IT IS FLUSH RIGHT. It used to sit between the title
   and the action icons, which put it at a different x on every screen — the
   title is "Trips" on one and "Earnings" on the next — and at a different x
   again in AI mode, where there are no action icons at all. A control that
   governs the whole app cannot move when you change screens inside it. As the
   last child against the app's one 16px gutter — the same gutter .scroll
   uses, so the title sits on the same left edge as the cards under it — its
   right edge lands in the same
   place on every screen and in both modes, which is the only position that
   makes it feel like one object you are toggling rather than two you are
   hunting for. Both bars carry the metrics below for the same reason. */
.topbar-title { flex: 1 1 auto; min-width: 0; overflow: hidden; }
.topbar h2 {
  font-size: 22px; font-weight: 500; letter-spacing: -0.025em; color: var(--d-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topbar .sub {
  font-size: 12px; color: var(--d-ink-3); margin-top: 2px; font-weight: 450; letter-spacing: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The switch sits between the two and never gives ground. */
.topbar .dmode { flex: 0 0 auto; }
.topbar-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

body.driving-mode .topbar-actions a[href$="/alerts"],
body.driving-mode .topbar-actions a[href$="/notifications"] { display: none; }
body.driving-mode .map-sheet [data-then] { display: none; }

.icon-btn {
  width: var(--d-touch); height: var(--d-touch);
  border-radius: 50%;
  background: var(--d-card);
  border: 1px solid var(--d-line-2);
  box-shadow: var(--d-lift-1);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-ink); position: relative; cursor: pointer; flex-shrink: 0;
  transition: transform var(--d-fast) var(--d-ease), background var(--d-fast) var(--d-ease);
}
.icon-btn:active { transform: scale(0.93); background: var(--d-sunk); }
.icon-btn .material-symbols-outlined { font-size: 21px; }
/* The badge is the accent doing its job: it marks the one thing that changed. */
.icon-btn .badge {
  position: absolute; top: 1px; right: 1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--d-accent);
  border: 2px solid var(--d-card);
  box-shadow: 0 0 0 1px var(--d-accent-line);
}

/* ---------- Detail header ---------- */
.detail-hd {
  display: flex; align-items: center; gap: 12px;
  padding: calc(12px + var(--safe-top)) 16px 12px;
  background: rgba(255, 255, 255, 0.88);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--d-line);
  box-shadow: var(--d-lift-chrome);
  flex-shrink: 0;
  position: fixed; top: 0; left: 0; right: 0;
  max-width: 480px; margin: 0 auto; z-index: 20;
}
.detail-hd .titles { flex: 1; min-width: 0; }
.detail-hd .titles h3 { font-size: 16px; font-weight: 500; letter-spacing: -0.02em; color: var(--d-ink); }
.detail-hd .titles .m { font-size: 12px; color: var(--d-ink-3); margin-top: 1px; font-weight: 450; }
.detail-hd .icon-btn { border-color: var(--d-line); }

/* ---------- Scroll body ---------- */
.scroll {
  flex: 1; overflow-y: auto; overflow-x: hidden;
  padding: 16px 16px calc(24px + var(--safe-bottom));
  -webkit-overflow-scrolling: touch;
}
.scroll::-webkit-scrollbar { display: none; }
.scroll.flush { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.scroll.has-topbar { padding-top: calc(76px + var(--safe-top)); }
.scroll.has-detailhd { padding-top: calc(68px + var(--safe-top)); }
.scroll.flush.has-topbar { padding-top: 0; margin-top: calc(76px + var(--safe-top)); }
.scroll.flush.has-detailhd { padding-top: 0; margin-top: calc(68px + var(--safe-top)); }
.scroll.has-tabbar { padding-bottom: calc(104px + var(--safe-bottom)); }

/* ---------- The app's own edge, on anything wider than a phone ----------
   The shell caps at 480 and centres, and its canvas is --d-g1 — which is also
   what `body` is painting behind it. Identical values, so on a desktop browser
   the app had no boundary at all: the topbar and the tab bar read as two white
   bands floating on a grey page with nothing holding them together, and the
   content in between simply dissolved into the window.

   Below 481px none of this applies: there the shell IS the viewport, and the
   body's colour only ever shows during overscroll rubber-banding, where it has
   to be the canvas or the bounce flashes a different colour.

   The fixed bars need the edge too. They are capped and centred to line up with
   the shell, but they are positioned against the VIEWPORT, so a shadow on
   .m-shell passes behind them and the column would break at both ends. */
@media (min-width: 481px) {
  body { background: #dde2ea; }
  .m-shell {
    box-shadow: 0 0 0 1px rgba(9, 44, 76, 0.10), 0 18px 50px -24px rgba(9, 44, 76, 0.28);
  }
  .topbar, .detail-hd, .tab-bar, .chat-hd, .cta-bar {
    border-left: 1px solid rgba(9, 44, 76, 0.10);
    border-right: 1px solid rgba(9, 44, 76, 0.10);
  }
}

/* ============================================================================
   TAB BAR — and Alfred, who is the orb here.
   The wireframe made him a 52px black circle with a filled glyph, which the
   design system lists as debt 04: "Alfred appears three ways". This is the
   third one being retired. The circle is a dark well (particles are drawn
   additively, so Alfred's surface is dark on every chapter, including this
   light one) hosting a real ai-orb.js canvas.
   ========================================================================== */
.tab-bar {
  display: flex; justify-content: space-around; align-items: flex-end;
  padding: 8px 6px calc(24px + var(--safe-bottom));
  background: rgba(255, 255, 255, 0.90);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid var(--d-line);
  box-shadow: 0 -1px 0 rgba(9, 44, 76, 0.05), 0 -10px 28px -20px rgba(9, 44, 76, 0.40);
  flex-shrink: 0;
  position: fixed; left: 0; right: 0; bottom: 0;
  max-width: 480px; margin: 0 auto; z-index: 20;
}
.tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--d-ink-3); font-size: 10.5px; font-weight: 500; letter-spacing: -0.005em;
  padding: 6px 8px; min-height: var(--d-touch); border-radius: var(--d-r-md);
  cursor: pointer; flex: 1;
  transition: color var(--d-fast) var(--d-ease);
}
.tab .material-symbols-outlined { font-size: 23px; transition: font-variation-settings var(--d-base) var(--d-ease); }
.tab.active { color: var(--d-g7); font-weight: 600; }
.tab.active .material-symbols-outlined { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
.tab:active { transform: scale(0.96); }

.tab.alfred { position: relative; gap: 7px; }
.tab.alfred .alfred-orb {
  position: relative;
  width: 56px; height: 56px; border-radius: 50%;
  background: radial-gradient(120% 120% at 50% 20%, #123A62 0%, #071F38 55%, #04162A 100%);
  display: inline-flex; align-items: center; justify-content: center;
  margin-top: -24px;
  border: 3px solid var(--d-card);
  box-shadow: 0 8px 20px -8px rgba(9, 44, 76, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  overflow: hidden;
  transition: transform var(--d-base) var(--d-spring), box-shadow var(--d-base) var(--d-ease);
}
.tab.alfred:active .alfred-orb { transform: scale(0.94); }
.tab.alfred .alfred-orb canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* The glyph is the fallback, not the design: ai-orb.js hides it once the WebGL
   context is live, and it stays if the device has no WebGL at all. */
.tab.alfred .alfred-orb .material-symbols-outlined {
  position: relative; z-index: 1;
  font-size: 25px; color: #fff;
  font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  /* Handed over, not switched. The orb needs a few frames to build its field,
     and cutting the glyph the instant mount() returns leaves an empty well for
     exactly that long. It dissolves instead, and the particles come up under
     it. Opacity rather than display, so nothing reflows during the handoff. */
  transition: opacity var(--d-slower) var(--d-ease);
  pointer-events: none;
}
.tab.alfred .alfred-orb.orb-live .material-symbols-outlined { opacity: 0; }
.tab.alfred.active { color: var(--d-g7); }
.tab.alfred.active .alfred-orb {
  box-shadow: 0 8px 22px -8px rgba(9, 44, 76, 0.60),
              0 0 0 3px var(--d-bloom-halo),
              inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* ============================================================================
   MODE SWITCH — Assisted / AI.
   The dashboard's control, rebuilt for a thumb and for a light ground. Same
   reasoning, value for value: a recessed track and a raised thumb (that
   relationship is the whole reason a segmented control reads as pressable),
   ONE plate that slides rather than two buttons where one is darker, a grid so
   the halves are actually halves, and only AI gets the accent — Assisted is
   the default and a default should not announce itself.

   Real links, not a client-side toggle: /driver-app/home and /driver-app/ai,
   so a mode survives a refresh and works with the back button.
   ========================================================================== */
.dmode {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 0; padding: 3px;
  background: rgba(9, 44, 76, 0.07);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-full);
  box-shadow: inset 0 1px 2px rgba(9, 44, 76, 0.08);
  flex-shrink: 0;
}
.dmode-thumb {
  position: absolute; top: 3px; left: 3px;
  width: calc(50% - 3px); height: calc(100% - 6px);
  border-radius: var(--d-r-full);
  background: var(--d-card);
  box-shadow: var(--d-lift-2);
  transition: transform var(--d-base) var(--d-ease), background var(--d-base) var(--d-ease), box-shadow var(--d-base) var(--d-ease);
}
.dmode-opt {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  min-height: 34px; padding: 0 12px;
  font-size: 12px; font-weight: 500; letter-spacing: -0.005em;
  color: var(--d-ink-3);
  transition: color var(--d-base) var(--d-ease);
  white-space: nowrap;
}
.dmode-opt .material-symbols-outlined { font-size: 17px; }
.dmode-opt.active { color: var(--d-ink); font-weight: 600; }
/* AI selected: the plate slides right and takes the navy. */
.dmode.dmode-ai .dmode-thumb {
  transform: translateX(100%);
  background: var(--d-plate);
  box-shadow: var(--d-plate-shadow);
}
.dmode.dmode-ai .dmode-opt.active { color: #fff; }
.dmode.dmode-ai .dmode-opt.active .material-symbols-outlined { color: var(--d-bloom); }
/* The labels go and the glyphs stay below 420px — the same call the dashboard
   makes at 1180px, for the same reason. A switch that has to be read is worth
   less than the width it takes from the title beside it, and on a handset that
   width is the difference between the topbar fitting and the topbar scrolling
   sideways. Glyph-only the switch is 76px; with labels it is ~150px. */
@media (max-width: 479px) {
  .dmode-txt { display: none; }
  .dmode-opt { padding: 0 11px; }
}

/* ============================================================================
   SURFACES
   ========================================================================== */
/* display:block stays load-bearing: real navigation renders several of these as
   <a href>, and an anchor defaults to display:inline. */
.card {
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  padding: 16px;
  display: block;
}
.card + .card { margin-top: 12px; }
a.card, .card[onclick] { transition: transform var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease); }
a.card:active, .card[onclick]:active { transform: scale(0.99); box-shadow: var(--d-lift-1); }

.sec-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 20px 2px 10px; }
/* A real heading, not a caps label. */
.sec-hd h3 { font-size: 14px; font-weight: 600; letter-spacing: -0.015em; text-transform: none; color: var(--d-ink); }
.sec-hd .link { color: var(--d-accent); cursor: pointer; }

.m-empty {
  text-align: center; padding: 48px 24px;
  color: var(--d-ink-3); font-size: 14px; font-weight: 450; line-height: 1.55;
}

/* ---------- Chip / pill ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  font-size: 10.5px; font-weight: 600;
  color: var(--d-ink-2);
  border-radius: var(--d-r-xs);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.chip.dark { background: var(--d-plate); color: #fff; border-color: transparent; box-shadow: var(--d-plate-shadow); }
.chip .material-symbols-outlined { font-size: 13px; }
.chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--d-ink-3); }
.chip.dark .dot { background: var(--d-bloom); }

.pill-row { display: flex; gap: 7px; overflow-x: auto; margin: 0 -16px 14px; padding: 0 16px 4px; }
.pill-row::-webkit-scrollbar { display: none; }
.pill {
  padding: 8px 14px; min-height: 36px;
  display: inline-flex; align-items: center;
  background: var(--d-card);
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-full);
  font-size: 12.5px; font-weight: 500;
  color: var(--d-ink-2);
  white-space: nowrap; flex-shrink: 0; cursor: pointer;
  box-shadow: var(--d-lift-1);
  transition: all var(--d-fast) var(--d-ease);
}
.pill.on { background: var(--d-plate); color: #fff; border-color: transparent; box-shadow: var(--d-plate-shadow); font-weight: 600; }
.chip-row { display: flex; flex-wrap: wrap; gap: 7px; padding: 4px 2px; }

/* ============================================================================
   BUTTONS — the navy plate.
   The design system's primary action on a light ground, matched value for
   value: #0f3b63 -> #082541 -> #041a2e, 10px radius, a lit top rim. Without
   the inset highlight a dark plate reads as a hole punched in the page.
   ========================================================================== */
.btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%;
  min-height: var(--d-touch-md);
  padding: 14px 18px;
  border: none;
  background: var(--d-plate);
  color: #fff;
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.005em;
  border-radius: var(--d-r-md);
  box-shadow: var(--d-plate-shadow);
  transition: transform var(--d-fast) var(--d-ease), background var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease);
}
.btn:active { transform: scale(0.985); background: var(--d-plate-lit); }
.btn .material-symbols-outlined { font-size: 19px; }
.btn[disabled] { opacity: 0.38; pointer-events: none; box-shadow: none; }

/* Secondary is a white plate at the same radius — the design system's own
   pairing. Not a dashed outline; dashed borders are the wireframe's tell. */
.btn.ghost {
  background: var(--d-card);
  color: var(--d-ink);
  border: 1px solid var(--d-line-2);
  box-shadow: var(--d-lift-1);
}
.btn.ghost:active { background: var(--d-sunk); transform: scale(0.985); }
.btn.danger {
  background: var(--d-card);
  color: var(--d-bad-ink);
  border: 1px solid rgba(198, 42, 47, 0.28);
  box-shadow: var(--d-lift-1);
}
.btn.danger:active { background: var(--d-bad-soft); }

/* The screen's primary action. Thumb-sized on purpose — 64px is the touch
   scale's top band, down from the wireframe's 68 now that the plate carries
   weight by contrast rather than by size. */
.btn-xl {
  width: 100%;
  min-height: var(--d-touch-lg);
  padding: 18px 20px;
  font-size: 17px; font-weight: 600; letter-spacing: -0.015em;
  border-radius: var(--d-r-lg);
  background: var(--d-plate);
  color: #fff; border: none;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  cursor: pointer;
  box-shadow: 0 10px 24px -10px rgba(9, 44, 76, 0.60), inset 0 1px 0 rgba(255, 255, 255, 0.16);
  transition: transform var(--d-fast) var(--d-ease), background var(--d-fast) var(--d-ease);
}
.btn-xl:active { transform: scale(0.985); background: var(--d-plate-lit); }
.btn-xl.ghost {
  background: var(--d-card); color: var(--d-ink);
  border: 1px solid var(--d-line-2);
  box-shadow: var(--d-lift-2);
}
.btn-xl .material-symbols-outlined { font-size: 25px; }

.cta-bar {
  padding: 12px 16px calc(16px + var(--safe-bottom));
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  border-top: 1px solid var(--d-line);
  box-shadow: 0 -8px 24px -20px rgba(9, 44, 76, 0.45);
  flex-shrink: 0;
}
.cta-bar.split { display: grid; grid-template-columns: var(--d-touch-md) 1fr; gap: 10px; }
.cta-bar.split-eq { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cta-bar .sec {
  width: var(--d-touch-md); height: var(--d-touch-md);
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  border-radius: var(--d-r-md);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--d-ink);
  box-shadow: var(--d-lift-1);
}
.cta-bar .sec:active { background: var(--d-sunk); }

/* ---------- Avatar ---------- */
.avatar {
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--d-accent-dim);
  border: 1px solid var(--d-line);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-accent);
  font-size: 13px; font-weight: 600; letter-spacing: 0.01em;
  flex-shrink: 0; overflow: hidden;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.sm { width: 30px; height: 30px; font-size: 10.5px; }
.avatar.md { width: 36px; height: 36px; font-size: 12px; }
.avatar.lg { width: 58px; height: 58px; font-size: 17px; }
.avatar.xl { width: 88px; height: 88px; font-size: 24px; font-weight: 500; }

/* ============================================================================
   FIELDS
   The focus ring lives on the wrapper, never also on the inner input.
   ========================================================================== */
.field { margin-top: 16px; }
.field label {
  display: block;
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.10em; text-transform: uppercase;
  color: var(--d-ink-3);
  margin-bottom: 7px;
}
/* A field states its own ink. It never inherits it.
   This is not defensive style — it was a real bug: the login sits inside
   .splash, which is the navy plate and sets color:#fff for the text on it. The
   field's own ground is white, so an .input that inherited its colour rendered
   white type on a white field. The phone number went in and nothing appeared,
   which reads exactly like an input that refuses to accept typing. Any
   component with its own background has to carry its own foreground. */
.input {
  width: 100%;
  min-height: var(--d-touch-md);
  padding: 13px 15px;
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  color: var(--d-ink);
  border-radius: var(--d-r-md);
  display: flex; align-items: center; gap: 10px;
  font-size: 15px;
  box-shadow: var(--d-lift-1);
  transition: border-color var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease);
}
.input:focus-within {
  border-color: var(--d-accent);
  box-shadow: 0 0 0 4px var(--d-accent-dim);
}
.input input { flex: 1; min-width: 0; background: none; color: var(--d-ink); -webkit-text-fill-color: var(--d-ink); }
.input input:focus { outline: none; box-shadow: none; }
.input input::placeholder { color: var(--d-ink-4); }
.input .material-symbols-outlined { color: var(--d-ink-3); font-size: 19px; }

.textarea-mock {
  background: var(--d-card);
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-md);
  padding: 12px 14px;
  min-height: 96px;
  font-size: 14px; line-height: 1.5;
  width: 100%; resize: none;
  color: var(--d-ink); -webkit-text-fill-color: var(--d-ink);
  box-shadow: var(--d-lift-1);
  transition: border-color var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease);
}
.textarea-mock:focus { border-color: var(--d-accent); box-shadow: 0 0 0 4px var(--d-accent-dim); }
.textarea-mock::placeholder { color: var(--d-ink-4); }

/* ---------- Switch / segmented ---------- */
.switch {
  width: 46px; height: 28px; border-radius: var(--d-r-full);
  border: 1px solid var(--d-line-2);
  background: var(--d-sunk-2);
  position: relative; cursor: pointer; flex-shrink: 0;
  box-shadow: inset 0 1px 2px rgba(9, 44, 76, 0.08);
  transition: background var(--d-base) var(--d-ease), border-color var(--d-base) var(--d-ease);
}
.switch::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--d-card);
  box-shadow: var(--d-lift-2);
  transition: transform var(--d-base) var(--d-ease);
}
.switch.on { background: var(--d-plate); border-color: transparent; }
.switch.on::after { transform: translateX(18px); }

.seg {
  display: flex;
  padding: 3px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-md);
  background: rgba(9, 44, 76, 0.05);
  box-shadow: inset 0 1px 2px rgba(9, 44, 76, 0.06);
  gap: 3px;
}
.seg > * {
  flex: 1; min-height: 38px;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 8px 8px; text-align: center;
  font-size: 12.5px; font-weight: 500;
  color: var(--d-ink-3);
  border-radius: calc(var(--d-r-md) - 4px);
  border: none;
  cursor: pointer;
  transition: all var(--d-base) var(--d-ease);
}
.seg > *.on {
  background: var(--d-card);
  color: var(--d-ink);
  font-weight: 600;
  box-shadow: var(--d-lift-2);
}

/* ============================================================================
   THE TRIP SPINE — the one thing this app is actually for.
   ========================================================================== */
@keyframes d-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.88); }
}
@keyframes d-halo {
  0%   { box-shadow: 0 0 0 0 rgba(44, 111, 181, 0.40); }
  70%  { box-shadow: 0 0 0 8px rgba(44, 111, 181, 0); }
  100% { box-shadow: 0 0 0 0 rgba(44, 111, 181, 0); }
}

/* ---------- Home hero: the next trip ---------- */
.hero-trip {
  display: block;
  position: relative;
  background: var(--d-card);
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-xl);
  padding: 20px;
  box-shadow: var(--d-lift-3);
  overflow: hidden;
}
/* The live rail: the accent marking the one thing on this screen that is
   happening now. It replaces the wireframe's 1.5px black outline, which spent
   the heaviest mark in the system on a card that was already the largest. */
.hero-trip::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--d-accent), var(--d-accent-2));
}
.hero-trip .hero-tag {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 10px;
  color: var(--d-accent-2);
}
.hero-trip .hero-tag .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--d-accent);
  animation: d-pulse 1.8s var(--d-ease-io) infinite;
}
/* A figure that is the point of the card is not a heading: large and light. */
.hero-trip .hero-time {
  font-size: 34px; font-weight: 600; letter-spacing: -0.04em; line-height: 1;
  color: var(--d-ink); font-variant-numeric: tabular-nums;
  padding: 0; background: none; border: none;
}
.hero-trip .hero-eta { font-size: 13.5px; color: var(--d-ink-2); margin-top: 6px; font-weight: 500; }
.hero-trip .hero-route { margin-top: 18px; }
.hero-trip .hero-route .hr-line { display: flex; align-items: flex-start; gap: 12px; padding: 7px 0; }
.hero-trip .hero-route .hr-dot {
  width: 12px; height: 12px; border-radius: 50%; margin-top: 5px;
  border: 2.5px solid var(--d-g4); background: var(--d-card); flex-shrink: 0;
}
.hero-trip .hero-route .hr-dot.filled {
  background: var(--d-g7); border-color: var(--d-g7);
}
.hero-trip .hero-route .hr-addr { font-size: 15.5px; font-weight: 500; letter-spacing: -0.018em; color: var(--d-ink); }
.hero-trip .hero-route .hr-meta { font-size: 12.5px; color: var(--d-ink-3); margin-top: 2px; }
.hero-trip .hero-pax {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 0 0; margin-top: 14px;
  border-top: 1px solid var(--d-line);
  font-size: 13.5px; font-weight: 500; color: var(--d-ink-2);
}
.hero-trip .hero-pax .material-symbols-outlined { font-size: 19px; color: var(--d-ink-3); }
.hero-trip .hero-actions { display: grid; grid-template-columns: var(--d-touch-lg) 1fr; gap: 10px; margin-top: 16px; }
.hero-trip .hero-actions .quick {
  min-height: var(--d-touch-lg);
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  border-radius: var(--d-r-lg);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--d-ink);
  box-shadow: var(--d-lift-1);
}
.hero-trip .hero-actions .quick:active { background: var(--d-sunk); }
.hero-trip .hero-actions .quick .material-symbols-outlined { font-size: 25px; }

/* ---------- Trip rows ---------- */
.strip {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px; margin-bottom: 12px;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  cursor: pointer;
}
.strip .v { font-size: 24px; font-weight: 600; margin-top: 4px; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.strip .side { text-align: right; }

.trip-card {
  display: block; position: relative;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  padding: 14px;
  margin-bottom: 10px;
  cursor: pointer;
  overflow: hidden;
  transition: transform var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease);
}
.trip-card:active { transform: scale(0.99); }
.trip-card.live { border-color: var(--d-line-2); box-shadow: var(--d-lift-2); }
.trip-card.live::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--d-accent), var(--d-accent-2));
}
.trip-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 12px; }
.trip-head .t { font-size: 16.5px; font-weight: 500; letter-spacing: -0.02em; color: var(--d-ink); }
.trip-head .in { font-size: 12px; color: var(--d-ink-3); margin-top: 2px; font-weight: 450; }

.route { display: grid; grid-template-columns: 20px 1fr; gap: 12px; }
.route-line { display: flex; flex-direction: column; align-items: center; padding-top: 5px; }
.dot {
  width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid var(--d-g4); background: var(--d-card);
  flex-shrink: 0;
}
.dot.filled { background: var(--d-g7); border-color: var(--d-g7); }
/* A solid hairline, not a dotted rule. The dotted connector was reading as an
   unfinished state on every completed leg. */
.connector { flex: 1; width: 2px; min-height: 22px; margin: 3px 0; background: var(--d-g4); border-radius: 1px; }
.stop { padding-bottom: 12px; }
.stop:last-child { padding-bottom: 0; }
.stop .lbl { font-size: 9.5px; }
.stop .addr { font-size: 13.5px; font-weight: 500; margin-top: 3px; letter-spacing: -0.012em; color: var(--d-ink); }
.stop .meta { font-size: 12px; color: var(--d-ink-3); margin-top: 2px; }

.trip-detail .route { padding: 20px !important; grid-template-columns: 24px 1fr; gap: 14px; }
.trip-detail .stop { padding-bottom: 18px; }
.trip-detail .stop .addr { font-size: 17px; letter-spacing: -0.02em; margin-top: 4px; }
.trip-detail .dot { width: 13px; height: 13px; }

.trip-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--d-line);
}
.pax-cnt { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 500; color: var(--d-ink-2); }
.pax-cnt .material-symbols-outlined { font-size: 16px; color: var(--d-ink-3); }
.go-btn {
  padding: 7px 13px; min-height: 32px;
  background: var(--d-plate); color: #fff;
  border-radius: var(--d-r-xs);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.07em;
  display: inline-flex; align-items: center; gap: 5px;
  cursor: pointer;
  box-shadow: var(--d-plate-shadow);
}
.go-btn.ghost { background: var(--d-card); color: var(--d-ink); border: 1px solid var(--d-line-2); box-shadow: var(--d-lift-1); }
.go-btn .material-symbols-outlined { font-size: 13px; }

/* ---------- Trip detail chrome ---------- */
.hero-time {
  padding: 18px 16px;
  background: var(--d-card);
  border-bottom: 1px solid var(--d-line);
  flex-shrink: 0;
}
.hero-time .bt {
  font-size: 34px; font-weight: 600; letter-spacing: -0.04em; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--d-ink);
}
.hero-time .bt small {
  font-size: 11px; color: var(--d-ink-3); font-weight: 600;
  margin-left: 8px; text-transform: uppercase; letter-spacing: 0.10em;
}
.hero-chips { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }

.kv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 16px; padding: 16px; }
.kv .k { font-size: 10px; }
.kv .v { font-size: 14px; font-weight: 500; margin-top: 4px; color: var(--d-ink); }
.kv .v small { color: var(--d-ink-3); font-weight: 450; margin-left: 3px; }

.data-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border-top: 1px solid var(--d-line);
  min-height: var(--d-touch-md);
}
.data-row:first-child { border-top: none; }
.data-row .p-info { flex: 1; min-width: 0; }
.data-row .p-info .n { font-size: 14px; font-weight: 500; color: var(--d-ink); }
.data-row .p-info .m { font-size: 12px; color: var(--d-ink-3); margin-top: 3px; display: flex; gap: 10px; flex-wrap: wrap; }
.data-row .p-info .m span { display: inline-flex; align-items: center; gap: 4px; }
.data-row .p-info .m .material-symbols-outlined { font-size: 13px; }

.mini-actions { display: flex; gap: 6px; }
.mini-actions .mi {
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--d-line-2); background: var(--d-card);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--d-ink);
  box-shadow: var(--d-lift-1);
}
.mini-actions .mi:active { background: var(--d-sunk); }
.mini-actions .mi .material-symbols-outlined { font-size: 17px; }

.flight-strip {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; margin: 12px 16px;
  border: none;
  background: var(--d-sunk);
  border-radius: var(--d-r-md);
}
.flight-strip .ico {
  width: 34px; height: 34px; border-radius: var(--d-r-sm);
  border: 1px solid var(--d-line); background: var(--d-card);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-accent); flex-shrink: 0;
}
.flight-strip .fi { flex: 1; min-width: 0; }
.flight-strip .fl { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; color: var(--d-ink); }
.flight-strip .fm { font-size: 11.5px; color: var(--d-ink-3); margin-top: 2px; }

/* ============================================================================
   CHAT
   ========================================================================== */
.chat-hd {
  padding: calc(12px + var(--safe-top)) 16px 12px;
  background: rgba(255, 255, 255, 0.90);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--d-line);
  display: flex; align-items: center; gap: 12px; flex-shrink: 0;
}
.chat-hd .who { flex: 1; min-width: 0; }
.chat-hd .who .n { font-size: 14.5px; font-weight: 600; letter-spacing: -0.015em; color: var(--d-ink); }
.chat-hd .who .s { font-size: 11.5px; color: var(--d-ink-3); margin-top: 1px; display: inline-flex; align-items: center; gap: 5px; }

.chat-scroll {
  flex: 1; overflow-y: auto;
  background: var(--d-canvas);
  padding: 16px;
  display: flex; flex-direction: column; gap: 10px;
}
.chat-scroll::-webkit-scrollbar { display: none; }
.msg-time {
  font-size: 10.5px; color: var(--d-ink-4); text-align: center;
  font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 8px 0 4px;
}
.bubble {
  max-width: 80%;
  padding: 10px 14px;
  border-radius: var(--d-r-xl);
  font-size: 14px; line-height: 1.45;
  border: 1px solid var(--d-line);
  background: var(--d-card);
  color: var(--d-ink);
  box-shadow: var(--d-lift-1);
}
.bubble.in { align-self: flex-start; border-bottom-left-radius: var(--d-r-xs); }
.bubble.out {
  align-self: flex-end;
  background: var(--d-plate); color: #fff;
  border-color: transparent;
  border-bottom-right-radius: var(--d-r-xs);
  box-shadow: var(--d-plate-shadow);
}
.bubble .stamp { font-size: 10px; opacity: 0.62; margin-top: 5px; }
.bubble.is-ai { background: var(--d-accent-dim); border-color: rgba(44,111,181,0.25); }

/* The real "Alfred is answering" strip on an autonomous tenant's chat — see
   Company.alfredMode and driverApp.js's /chat/:id/escalate. Never shown once
   a thread is already escalated: nothing left to hand off at that point. */
.ai-handoff {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  background: var(--d-accent-dim);
  border-top: 1px solid rgba(44,111,181,0.2);
  font-size: 12px; color: var(--d-accent-2);
}
.ai-handoff .material-symbols-outlined { font-size: 17px; }
.ai-handoff .t { flex: 1; font-weight: 500; }
.ai-handoff button {
  padding: 7px 12px; border-radius: var(--d-r-full);
  background: var(--d-g0); border: 1px solid var(--d-line-2);
  font-family: inherit; font-size: 11.5px; font-weight: 600; color: var(--d-ink);
}

.quick-replies {
  display: flex; gap: 7px; overflow-x: auto;
  padding: 10px 14px;
  background: var(--d-card);
  border-top: 1px solid var(--d-line);
}
.quick-replies::-webkit-scrollbar { display: none; }
.qr {
  padding: 8px 14px; min-height: 36px;
  display: inline-flex; align-items: center;
  background: var(--d-sunk);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-full);
  font-size: 12.5px; font-weight: 500;
  color: var(--d-ink-2);
  cursor: pointer; flex-shrink: 0;
  transition: all var(--d-fast) var(--d-ease);
}
.qr:active { background: var(--d-plate); color: #fff; border-color: transparent; }

.chat-input {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px calc(16px + var(--safe-bottom));
  background: var(--d-card);
  border-top: 1px solid var(--d-line);
}
.ci-input {
  flex: 1; min-width: 0;
  background: var(--d-sunk);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-full);
  padding: 11px 16px;
  display: flex; align-items: center; gap: 10px;
  transition: border-color var(--d-fast) var(--d-ease), box-shadow var(--d-fast) var(--d-ease);
}
.ci-input:focus-within { border-color: var(--d-accent); box-shadow: 0 0 0 4px var(--d-accent-dim); background: var(--d-card); }
.ci-input input { flex: 1; min-width: 0; font-size: 14.5px; background: none; }
.ci-input input:focus { outline: none; box-shadow: none; }
.ci-input input::placeholder { color: var(--d-ink-4); }
.ci-send {
  width: var(--d-touch); height: var(--d-touch); border-radius: 50%;
  background: var(--d-plate); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0;
  box-shadow: var(--d-plate-shadow);
  transition: transform var(--d-fast) var(--d-ease);
}
.ci-send:active { transform: scale(0.93); }

.chat-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  background: var(--d-card);
  border-bottom: 1px solid var(--d-line);
  cursor: pointer;
  min-height: var(--d-touch-lg);
}
.chat-row:active { background: var(--d-sunk); }
.chat-row .cr { flex: 1; min-width: 0; }
.chat-row .cr .top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.chat-row .cr .n { font-size: 14.5px; font-weight: 600; letter-spacing: -0.015em; color: var(--d-ink); }
.chat-row .cr .tm { font-size: 11px; color: var(--d-ink-3); flex-shrink: 0; }
.chat-row .cr .msg { font-size: 12.5px; color: var(--d-ink-3); margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-row .cnt {
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--d-r-full);
  background: var(--d-accent); color: #fff;
  font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

/* ============================================================================
   PROFILE
   ========================================================================== */
.profile-hero {
  padding: 28px 18px 24px;
  background: var(--d-card);
  border-bottom: 1px solid var(--d-line);
  text-align: center; flex-shrink: 0;
  position: relative; overflow: hidden;
}
.profile-hero::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 120px;
  background: radial-gradient(120% 100% at 50% 0%, rgba(9, 44, 76, 0.06), transparent 70%);
  pointer-events: none;
}
.profile-hero > * { position: relative; }
.profile-hero .name { font-size: 20px; font-weight: 500; margin-top: 12px; letter-spacing: -0.025em; color: var(--d-ink); }
.profile-hero .role { font-size: 12.5px; color: var(--d-ink-3); margin-top: 3px; }
.profile-hero .rating-row {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 13px;
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  border-radius: var(--d-r-full);
  font-size: 12.5px; font-weight: 600;
  margin-top: 14px;
  box-shadow: var(--d-lift-1);
}
.profile-hero .rating-row .material-symbols-outlined { font-size: 16px; color: var(--d-accent); font-variation-settings: 'FILL' 1, 'wght' 400; }

.p-stats {
  display: grid; grid-template-columns: 1fr 1fr 1fr;
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  margin-top: 18px;
  background: var(--d-card);
  box-shadow: var(--d-lift-1);
  overflow: hidden;
}
.p-stats .ps { padding: 14px 10px; text-align: center; border-right: 1px solid var(--d-line); }
.p-stats .ps:last-child { border-right: none; }
.p-stats .ps .n { font-size: 22px; font-weight: 600; letter-spacing: -0.03em; color: var(--d-ink); font-variant-numeric: tabular-nums; }
.p-stats .ps .l { font-size: 9.5px; margin-top: 4px; }

.menu-item {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  min-height: var(--d-touch-lg);
  border-bottom: 1px solid var(--d-line);
  cursor: pointer;
  transition: background var(--d-fast) var(--d-ease);
}
.menu-item:last-child { border-bottom: none; }
.menu-item:active { background: var(--d-sunk); }
.menu-item .mi-ico {
  width: 38px; height: 38px; border-radius: var(--d-r-md);
  border: 1px solid var(--d-line);
  background: var(--d-accent-dim);
  color: var(--d-accent);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.menu-item .mi-ico .material-symbols-outlined { font-size: 20px; }
.menu-item .mi-info { flex: 1; min-width: 0; }
.menu-item .mi-info .n { font-size: 14.5px; font-weight: 500; color: var(--d-ink); }
.menu-item .mi-info .s { font-size: 12px; color: var(--d-ink-3); margin-top: 2px; }
.menu-item .chev { color: var(--d-ink-4); }
.menu-item .val { font-size: 12.5px; color: var(--d-ink-3); font-weight: 450; margin-right: 4px; }

/* ============================================================================
   EARNINGS & METRICS
   A figure that is the point of a card is set large and light — 46px at 300,
   with its unit trailing at caption size in muted ink. Weight 500 at that size
   reads as a headline rather than as a reading.
   ========================================================================== */
.earn-hero {
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-xl);
  padding: 22px;
  margin-bottom: 14px;
  box-shadow: var(--d-lift-2);
}
.earn-hero .period {
  display: inline-block;
  padding: 4px 10px;
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-xs);
  background: var(--d-card);
}
.earn-hero .big {
  font-size: 46px; font-weight: 600; letter-spacing: -0.045em;
  margin-top: 14px; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--d-ink);
}
.earn-hero .change {
  font-size: 12.5px; color: var(--d-ink-3); margin-top: 8px;
  display: inline-flex; align-items: center; gap: 5px; font-weight: 500;
}
.earn-hero .change .material-symbols-outlined { font-size: 16px; }

.metric-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.metric {
  padding: 15px;
  border: 1px solid var(--d-line);
  background: var(--d-card);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
}
.metric .ml { font-size: 10px; }
.metric .mv {
  font-size: 26px; font-weight: 600; letter-spacing: -0.03em; margin-top: 6px;
  font-variant-numeric: tabular-nums; color: var(--d-ink); line-height: 1.05;
}
.metric .ms { font-size: 11.5px; color: var(--d-ink-3); margin-top: 4px; }

.earn-item {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border-top: 1px solid var(--d-line);
  min-height: var(--d-touch-md);
}
.earn-item:first-child { border-top: none; }
.earn-item .ico-box {
  width: 38px; height: 38px; border-radius: var(--d-r-md);
  border: 1px solid var(--d-line);
  background: var(--d-accent-dim);
  color: var(--d-accent);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.earn-item .ico-box .material-symbols-outlined { font-size: 19px; }
.earn-item .info { flex: 1; min-width: 0; }
.earn-item .info .n { font-size: 13.5px; font-weight: 500; color: var(--d-ink); }
.earn-item .info .s { font-size: 11.5px; color: var(--d-ink-3); margin-top: 2px; }
.earn-item .amt { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--d-ink); }

/* Driving-insight bars. The fill is navy, and the rate is stated in figures
   beside it — a bar's length is the reading, its colour is not. */
.insight-row .ir-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.insight-row .ir-n { font-size: 14px; font-weight: 500; color: var(--d-ink); }
.insight-row .ir-s { font-size: 12.5px; color: var(--d-ink-3); font-weight: 500; font-variant-numeric: tabular-nums; }
.insight-row .ir-bar {
  height: 8px; background: var(--d-sunk-2);
  border-radius: var(--d-r-full); overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(9, 44, 76, 0.07);
}
.insight-row .ir-fi {
  height: 100%;
  background: linear-gradient(90deg, var(--d-accent), var(--d-accent-2));
  border-radius: var(--d-r-full);
  transition: width var(--d-slow) var(--d-ease);
}

/* Alfred's card on a light screen: a dark well, because his surface is dark on
   every chapter. */
.alfred-card {
  background: var(--d-plate);
  color: #fff;
  border-radius: var(--d-r-lg);
  padding: 16px;
  margin-bottom: 14px;
  display: flex; gap: 12px;
  box-shadow: 0 8px 22px -12px rgba(9, 44, 76, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.alfred-card .a-ico {
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.10);
  border: 1px solid var(--d-line-inv);
  color: var(--d-bloom);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.alfred-card .a-ico .material-symbols-outlined { font-size: 19px; }
.alfred-card .a-info { flex: 1; min-width: 0; }
.alfred-card .a-info .a-tag {
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--d-bloom); margin-bottom: 4px;
}
.alfred-card .a-info .a-title { font-size: 15px; font-weight: 500; letter-spacing: -0.018em; }
.alfred-card .a-info .a-msg { font-size: 13px; color: var(--d-ink-on-dark); margin-top: 5px; line-height: 1.45; }

.chart-mock {
  height: 120px;
  border: 1px solid var(--d-line);
  background: var(--d-card);
  border-radius: var(--d-r-md);
  margin-top: 12px; padding: 10px;
  position: relative;
}
.chart-mock svg { width: 100%; height: 100%; }

/* ============================================================================
   CALENDAR
   ========================================================================== */
.cal-strip { display: flex; gap: 6px; padding: 8px 0 16px; }
.cal-day {
  flex: 1; text-align: center; display: block;
  padding: 10px 4px; min-height: var(--d-touch-md);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-md);
  background: var(--d-card);
  box-shadow: var(--d-lift-1);
  cursor: pointer;
  transition: all var(--d-fast) var(--d-ease);
}
.cal-day.today { background: var(--d-plate); color: #fff; border-color: transparent; box-shadow: var(--d-plate-shadow); }
.cal-day.selected:not(.today) { border: 1.5px solid var(--d-accent); box-shadow: 0 0 0 3px var(--d-accent-dim); }
.cal-day .dow { font-size: 9.5px; opacity: 0.72; }
.cal-day.today .dow { color: rgba(255, 255, 255, 0.72); }
.cal-day.today .dm { color: #fff; }
.cal-day .dm { font-size: 17px; font-weight: 600; color: var(--d-ink); margin-top: 3px; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; }
.cal-day .dc { display: flex; justify-content: center; gap: 3px; margin-top: 6px; height: 5px; }
.cal-day .dc i { width: 5px; height: 5px; border-radius: 50%; background: var(--d-g5); display: inline-block; }
.cal-day.today .dc i { background: var(--d-bloom); }

.cal-month { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; margin-bottom: 6px; }
.cal-month .cm-dow { text-align: center; font-size: 9.5px; padding-bottom: 6px; }
.cal-month .cal-day { padding: 8px 2px; min-height: 44px; }
.cal-month .cal-day .dm { font-size: 13.5px; font-weight: 600; }

.time-slot { display: grid; grid-template-columns: 48px 1fr; gap: 12px; padding: 6px 0; }
.time-slot .tt { font-size: 11.5px; font-weight: 600; color: var(--d-ink-3); padding-top: 14px; font-variant-numeric: tabular-nums; }

.avail-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; min-height: var(--d-touch-lg);
  border-bottom: 1px solid var(--d-line);
  background: var(--d-card);
}
.avail-row:last-child { border-bottom: none; }

/* ============================================================================
   TIMELINE · DOCUMENTS · NOTIFICATIONS
   ========================================================================== */
.timeline { position: relative; padding-left: 22px; }
.timeline::before {
  content: ''; position: absolute; left: 6px; top: 6px; bottom: 6px;
  width: 2px; background: var(--d-g4); border-radius: 1px;
}
.tl-item { position: relative; padding-bottom: 20px; }
.tl-item::before {
  content: ''; position: absolute; left: -20px; top: 5px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--d-g4); background: var(--d-card);
}
.tl-item.done::before { background: var(--d-g7); border-color: var(--d-g7); }
.tl-item .d { font-size: 9.5px; }
.tl-item .t { font-size: 14px; font-weight: 500; margin-top: 3px; color: var(--d-ink); }
.tl-item .m { font-size: 12.5px; color: var(--d-ink-3); margin-top: 3px; line-height: 1.45; }

.doc-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  background: var(--d-card);
  box-shadow: var(--d-lift-1);
  margin-bottom: 10px;
  cursor: pointer;
  min-height: var(--d-touch-lg);
}
.doc-row:active { background: var(--d-sunk); }
.doc-row .doc-ph {
  width: 46px; height: 58px; border-radius: var(--d-r-xs);
  border: 1px solid var(--d-line-2);
  background: var(--d-sunk);
  position: relative; flex-shrink: 0;
}
.doc-row .doc-ph::after {
  content: ''; position: absolute; top: 0; right: 0;
  width: 13px; height: 13px; background: var(--d-card);
  border-left: 1px solid var(--d-line-2);
  border-bottom: 1px solid var(--d-line-2);
  border-bottom-left-radius: 2px;
}
.doc-row .di { flex: 1; min-width: 0; }
.doc-row .di .n { font-size: 14px; font-weight: 500; color: var(--d-ink); }
.doc-row .di .m { font-size: 11.5px; color: var(--d-ink-3); margin-top: 3px; }
.doc-row .di .st { font-size: 9.5px; margin-top: 6px; }
/* Status is never colour alone in this app — these pair with the glyph the
   template already renders beside them. */
.doc-row .di .st.warn { color: var(--d-warn-ink); }
.doc-row .di .st.expired { color: var(--d-bad-ink); text-decoration: none; }

.notif-item {
  display: flex; gap: 12px;
  padding: 14px 16px;
  background: var(--d-card);
  border-bottom: 1px solid var(--d-line);
  position: relative;
}
.notif-item:last-child { border-bottom: none; }
.notif-item.unread { background: var(--d-accent-dim); }
.notif-item.unread::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--d-accent);
}
.notif-item .n-ico {
  width: 40px; height: 40px; border-radius: var(--d-r-md);
  border: 1px solid var(--d-line);
  background: var(--d-card);
  color: var(--d-accent);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.notif-item .n-ico .material-symbols-outlined { font-size: 20px; }
.notif-item .n-info { flex: 1; min-width: 0; }
.notif-item .n-info .t { font-size: 14px; font-weight: 600; letter-spacing: -0.012em; color: var(--d-ink); }
.notif-item .n-info .m { font-size: 12.5px; color: var(--d-ink-2); margin-top: 3px; line-height: 1.45; }
.notif-item .n-info .stamp { font-size: 9.5px; color: var(--d-ink-4); margin-top: 6px; }

/* ============================================================================
   LOGIN · OTP · NOTES · PLACEHOLDERS
   ========================================================================== */
.otp-cell {
  width: 100%; min-width: 0; height: 60px; padding: 0;
  text-align: center;
  font-size: 24px; font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--d-ink); -webkit-text-fill-color: var(--d-ink);
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  border-radius: var(--d-r-md);
  box-shadow: var(--d-lift-1);
  font-family: inherit;
  caret-color: var(--d-accent);
  transition: all var(--d-fast) var(--d-ease);
}
.otp-cell:focus {
  outline: none;
  border-color: var(--d-accent);
  box-shadow: 0 0 0 4px var(--d-accent-dim);
}
.otp-cell.filled { border-color: var(--d-line-strong); }

.info-note {
  padding: 12px 14px;
  border: 1px solid var(--d-line);
  background: var(--d-sunk);
  border-radius: var(--d-r-md);
  display: flex; gap: 10px;
  margin-top: 12px;
  font-size: 12.5px; color: var(--d-ink-2); line-height: 1.45;
}
.info-note .material-symbols-outlined { font-size: 18px; flex-shrink: 0; margin-top: 1px; color: var(--d-g5); }
.info-note strong { display: block; margin-bottom: 3px; font-size: 13px; color: var(--d-ink); }

.ph {
  background: var(--d-sunk);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--d-ink-4);
}
.logo-box {
  width: 60px; height: 60px;
  border: 1px solid var(--d-line);
  background: var(--d-accent-dim);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em;
  color: var(--d-accent);
  border-radius: var(--d-r-lg);
  overflow: hidden;
}
.logo-box img { width: 100%; height: 100%; object-fit: contain; }

/* The splash is the one place the app goes dark — it is the moment before the
   product, and it is where the brand plate belongs. */
.splash {
  min-height: 100vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  background: var(--d-plate);
  color: #fff;
}
.splash .logo-box {
  width: 96px; height: 96px; font-size: 11px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--d-line-inv);
  color: #fff;
  border-radius: var(--d-r-2xl);
}
.splash .brand { font-size: 26px; font-weight: 300; letter-spacing: -0.025em; }
.splash .sub { font-size: 10.5px; font-weight: 600; color: var(--d-bloom); text-transform: uppercase; letter-spacing: 0.14em; }

/* ---------- The splash inverts the ink scale ----------
   The sign-in screen's body copy is written with the wireframe names in inline
   styles — var(--w-text-2) for "Sign in with email & password instead",
   var(--w-text-3) for the helper lines and the OR rule. Those names are a
   SEMANTIC layer ("secondary ink", "tertiary ink"), not fixed colours, so on a
   ground that inverts they have to resolve to inverted values or the whole
   screen reads as near-invisible grey on navy.
   Redefining the tokens here fixes every one of those inline styles at once,
   without touching a single template. Components that carry their own light
   background (the field, the note) spend --d-* and are unaffected. */
.splash {
  --w-text:   #FFFFFF;
  --w-text-2: rgba(255, 255, 255, 0.78);
  --w-text-3: rgba(255, 255, 255, 0.58);
  --w-text-4: rgba(255, 255, 255, 0.40);
  --w-line:   rgba(255, 255, 255, 0.16);
  --w-line-2: rgba(255, 255, 255, 0.22);
  --w-line-3: rgba(255, 255, 255, 0.28);
  --w-fill:   rgba(255, 255, 255, 0.07);
  --w-card:   rgba(255, 255, 255, 0.07);
}

/* ---------- Controls ON the splash ----------
   The splash is the navy plate, and .btn IS the navy plate — so the sign-in
   screen's primary action was navy on navy and very nearly vanished. The
   design system's rule for a dark ground is the one the AI mode already
   follows: the landing's CTA is a near-white plate carrying a blue bloom, and
   the navy plate is that same object turned the other way up for light
   surfaces. On the splash it turns back.
   Same reason the secondary drops to a hairline: a white-bordered white button
   beside a white plate is two primaries. */
.splash .btn,
.splash .btn-xl {
  background: linear-gradient(180deg, #FFFFFF, #DCE7F3);
  color: #0A2038;
  box-shadow: 0 10px 26px -12px rgba(134, 182, 232, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.splash .btn:active,
.splash .btn-xl:active { background: linear-gradient(180deg, #F2F6FB, #CFDDEC); }
.splash .btn.ghost,
.splash .btn-xl.ghost {
  background: rgba(255, 255, 255, 0.07);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: none;
}
.splash .btn.ghost:active { background: rgba(255, 255, 255, 0.13); }
/* The note and the field keep their light grounds, so they keep their own ink
   too — see the comment on .input. Only the rule between them inverts. */
.splash .info-note {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.72);
}
.splash .info-note strong { color: #fff; }
.splash .info-note .material-symbols-outlined { color: var(--d-bloom); }
.splash .field label { color: rgba(255, 255, 255, 0.55); }

/* ============================================================================
   MAP CHROME
   ========================================================================== */
.map-fab {
  width: var(--d-touch); height: var(--d-touch); border-radius: 50%;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid var(--d-line);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--d-ink);
  box-shadow: var(--d-lift-2);
  transition: transform var(--d-fast) var(--d-ease);
}
.map-fab:active { transform: scale(0.93); }
.map-fab .material-symbols-outlined { font-size: 21px; }
.map-right { position: absolute; right: 14px; top: 14px; z-index: 5; display: flex; flex-direction: column; gap: 10px; }
.map-sheet {
  position: absolute; bottom: 0; left: 0; right: 0;
  background: var(--d-card);
  border-top: 1px solid var(--d-line);
  border-radius: var(--d-r-2xl) var(--d-r-2xl) 0 0;
  padding: 8px 0 20px;
  z-index: 10;
  box-shadow: 0 -10px 30px -18px rgba(9, 44, 76, 0.45);
  max-height: 58%; overflow-y: auto;
}
.map-sheet::-webkit-scrollbar { display: none; }
.map-sheet-body { padding: 4px 16px 8px; }

/* ============================================================================
   OVERLAYS
   ========================================================================== */
.modal-scrim {
  position: fixed; inset: 0;
  background: rgba(4, 21, 37, 0.45);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  z-index: 500;
  display: none; align-items: flex-end; justify-content: center;
}
.modal-scrim.open { display: flex; animation: d-fade var(--d-base) var(--d-ease); }
@keyframes d-fade { from { opacity: 0; } to { opacity: 1; } }
.modal-sheet {
  background: var(--d-card);
  width: 100%; max-width: 480px;
  border-radius: var(--d-r-2xl) var(--d-r-2xl) 0 0;
  padding: 8px 0 calc(28px + var(--safe-bottom));
  box-shadow: 0 -16px 40px -20px rgba(4, 21, 37, 0.50);
  animation: d-rise var(--d-slow) var(--d-ease);
}
@keyframes d-rise { from { transform: translateY(18px); opacity: 0.4; } to { transform: none; opacity: 1; } }
.sheet-handle { width: 42px; height: 4px; background: var(--d-g4); border-radius: var(--d-r-full); margin: 6px auto 14px; }
.modal-body { padding: 8px 20px; }
.modal-body h4 { font-size: 18px; font-weight: 500; letter-spacing: -0.022em; margin-bottom: 8px; color: var(--d-ink); }
.modal-body p { font-size: 13.5px; color: var(--d-ink-2); line-height: 1.55; }

.toast {
  position: fixed; top: calc(16px + var(--safe-top)); left: 50%;
  transform: translateX(-50%) translateY(-24px);
  background: var(--d-plate); color: #fff;
  padding: 12px 16px;
  border-radius: var(--d-r-md);
  font-size: 13px; font-weight: 500;
  z-index: 700;
  display: flex; align-items: center; gap: 9px;
  opacity: 0;
  transition: opacity var(--d-base) var(--d-ease), transform var(--d-base) var(--d-ease);
  max-width: 320px; pointer-events: none;
  box-shadow: 0 12px 28px -12px rgba(4, 21, 37, 0.60), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ============================================================================
   GLOBAL LOADER — Alfred, thinking.
   The wireframe spun a bordered ring around a black circle. Alfred has a
   thinking state and this is what it is for: the orb itself, in the well, with
   a single soft halo instead of two counter-rotating rings.
   ========================================================================== */
.m-loader {
  position: fixed; inset: 0; z-index: 999;
  display: flex; align-items: center; justify-content: center;
  background: rgba(248, 249, 251, 0.68);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--d-fast) var(--d-ease);
}
.m-loader.show { opacity: 1; pointer-events: all; }
.m-loader-ring {
  width: 84px; height: 84px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  animation: d-halo 1.8s var(--d-ease-io) infinite;
}
.m-loader-orb {
  position: relative;
  width: 64px; height: 64px; border-radius: 50%;
  background: radial-gradient(120% 120% at 50% 20%, #123A62 0%, #071F38 55%, #04162A 100%);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 26px -10px rgba(9, 44, 76, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.m-loader-orb canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.m-loader-orb .material-symbols-outlined {
  position: relative; z-index: 1;
  font-size: 26px; color: #fff;
  font-variation-settings: 'FILL' 1, 'wght' 400;
  animation: d-pulse 1.4s var(--d-ease-io) infinite;
}
.m-loader-orb.orb-live .material-symbols-outlined { opacity: 0; transition: opacity var(--d-slower) var(--d-ease); }
.m-loader-orb.orb-live { box-shadow: 0 10px 30px -10px rgba(9, 44, 76, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 0 0 1px rgba(134, 182, 232, 0.18); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ============================================================================
   THE CARD WALL, on a phone
   ----------------------------------------------------------------------------
   The dashboard's .dcard family, brought across value for value. A reading is
   set the same way on both surfaces: the figure large and light with its cents
   taking the gap back, the secondary numbers on one hairline strip instead of
   in four competing boxes, and direction always carrying an arrow and a sign
   because colour alone is not a reading.
   ========================================================================== */
.dcard {
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  padding: 18px;
}
.dcard + .dcard, .dcard + .dcard-row, .dcard-row + .dcard { margin-top: 12px; }
.dcard-title { font-size: 13px; font-weight: 450; color: var(--d-ink-3); letter-spacing: -0.005em; }

/* Two tiles side by side, the way the overview walls them. */
.dcard-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.dcard-row .dcard { margin-top: 0; padding: 16px; }

/* ---- the display numeral ---- */
.dfig { display: flex; align-items: baseline; gap: 8px; line-height: 1; flex-wrap: wrap; margin-top: 12px; }
.dfig-lead {
  font-size: 46px; font-weight: 600; color: var(--d-ink);
  letter-spacing: -0.045em; font-variant-numeric: tabular-nums;
}
.dfig-tail { font-size: 14px; font-weight: 450; color: var(--d-ink-3); letter-spacing: -0.005em; }
.dfig-sm .dfig-lead { font-size: 32px; letter-spacing: -0.03em; }
.dfig-sm .dfig-tail { font-size: 12.5px; }
/* Cents are part of the same word as the dollars — they take the gap back. */
.dfig-cents { margin-left: -5px; }

/* ---- direction is a status: arrow and sign, never colour alone ---- */
.dtrend {
  display: flex; align-items: center; gap: 6px; margin-top: 10px;
  font-size: 13px; font-weight: 450;
}
.dtrend .material-symbols-outlined { font-size: 18px; }
.dtrend b { font-weight: 600; font-variant-numeric: tabular-nums; }
.dtrend.up { color: #17864f; }
.dtrend.down { color: #b0392c; }
.dtrend-vs { color: var(--d-ink-3); font-weight: 450; }
.dmeta-note { font-size: 12.5px; color: var(--d-ink-3); margin-top: 10px; line-height: 1.45; }

/* ---- the secondary readings, on one rule ---- */
.dstrip {
  display: flex; gap: 12px; margin-top: 15px; padding-top: 15px;
  border-top: 1px solid rgba(9, 44, 76, 0.07);
}
.dstrip-cell { flex: 1; min-width: 0; }
.dstrip-label { font-size: 11px; color: var(--d-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dstrip-val {
  margin-top: 5px; font-size: 17px; font-weight: 600; color: var(--d-ink);
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}

/* ---- INK. The plate this app already spends on its primary action, carrying
        the reading that matters most. Text is measured against the plate's
        lightest step (#0f3b63): white at 62% is 5.47:1 for the caption, and
        the figure itself runs 11.5:1. ---- */
.dcard-ink {
  background: linear-gradient(160deg, #0f3b63 0%, #082541 55%, #041a2e 100%);
  border-color: transparent;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.25),
    0 1px 2px rgba(4, 26, 46, 0.30),
    0 16px 36px -20px rgba(4, 26, 46, 0.70);
}
.dcard-ink .dcard-title { color: rgba(255, 255, 255, 0.62); }
.dcard-ink .dfig-lead { color: #fff; }
.dcard-ink .dfig-tail, .dcard-ink .dmeta-note { color: rgba(255, 255, 255, 0.66); }
.dcard-ink .dstrip { border-top-color: rgba(255, 255, 255, 0.14); }
.dcard-ink .dstrip-label { color: rgba(255, 255, 255, 0.62); }
.dcard-ink .dstrip-val { color: #fff; }
/* The delta keeps its job on ink — the dark-ground steps, not the light ones. */
.dcard-ink .dtrend.up { color: #46c88a; }
.dcard-ink .dtrend.down { color: #f08b7d; }
.dcard-ink .dtrend-vs { color: rgba(255, 255, 255, 0.62); }

/* ---- VEIL. A tile lifted by light rather than by a heavier border. ---- */
.dcard-veil {
  background: linear-gradient(160deg, #1b4f80 0%, #14406c 55%, #0c2c4e 100%);
  border-color: transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 10px 26px -18px rgba(4, 26, 46, 0.65);
}
.dcard-veil .dcard-title { color: rgba(255, 255, 255, 0.66); }
.dcard-veil .dfig-lead { color: #fff; }
.dcard-veil .dmeta-note { color: rgba(255, 255, 255, 0.62); }

/* ---- the plot ----
   The engine draws the SVG at the container's real pixel size, so the
   container has to HAVE one: without a resolved height it drew past the card
   and over the tiles below it. Clipped as well, so a marker label at the very
   top of the range cannot escape either. */
.dcard-plot {
  margin-top: 14px;
  height: 160px; max-height: 160px;
  overflow: hidden; position: relative;
}
.dcard-plot svg { display: block; max-width: 100%; }

/* ---------- The splash wears the real wordmark ----------
   What was here was a 96px rounded square containing the literal word "LOGO" —
   the wireframe's placeholder, never replaced. The file already carries its own
   white-to-#B0D6FF gradient fills, which is why the landing and the dashboard
   header both use it on dark with a glow and no invert; inverting it produces a
   muddy orange. The navy plate is the ground it was drawn for, so it gets the
   same treatment here and the same optical size relationship. */
/* ==========================================================================
   THE SPLASH GOES DEEPER, AND ALFRED IS ON IT
   --------------------------------------------------------------------------
   Two changes that belong together.

   THE GROUND. --d-plate opens at #0F3B63, which is the right value for a
   BUTTON — a small lit object read against white. Run full-bleed behind a
   sign-in screen the same gradient reads as a mid-blue wash, and it is the
   one screen with nothing else on it to set a scale against. This is the
   same plate taken down toward the product's own near-black, which is where
   the landing and the AI view already sit.

   It is declared as its own token rather than by moving --d-plate, because
   --d-plate is also the fill of every primary button in the app (see
   "Controls ON the splash" above) — darkening it there would repaint the
   whole product to fix one screen.

   The particles are drawn ADDITIVELY, so this is not only a brand decision:
   every step the ground goes down is a step of contrast the orb gets for
   free. The design system's note that Alfred sits in "a dark well because
   particles wash out on a light ground" is the same fact from the other end.
   ========================================================================== */
.splash {
  --d-plate-deep: linear-gradient(177deg, #0B2C4C 0%, #061A30 46%, #030E1B 100%);
  background: var(--d-plate-deep);
}
/* The directional pool the rest of the product lights its dark grounds with.
   Behind everything, and it never intercepts a tap. */
.splash::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(760px 520px at 50% 6%,  rgba(134, 182, 232, 0.16), transparent 64%),
    radial-gradient(620px 460px at 18% 102%, rgba(44, 111, 181, 0.12), transparent 70%);
}
.splash { position: relative; }
.splash > * { position: relative; z-index: 1; }

/* ---------- Alfred, at the door ----------
   IT FLOATS. No dish, no rim, no bordered circle — the design system's
   contract names "Alfred is the orb, not a glyph in a black circle" as
   something mobile inherits without discussion, and at this size an opaque
   disc turns a presence into a dark marble sitting on the screen.

   Sized off one custom property so the negative margins that pull the
   wordmark up under the halo stay in proportion at every width. The halo
   runs out well inside the box — it is a glow, not an edge — so the box is
   deliberately bigger than the orb looks. */
.sm-orb { --orb: min(208px, 24vh); }
.sm-orb {
  position: relative; width: var(--orb); height: var(--orb);
  margin: calc(var(--orb) * -0.10) auto calc(var(--orb) * -0.07);
}
/* The canvas must be SQUARE and larger than the box it sits in — the shader
   only renders a true sphere on a square canvas. Both are load-bearing. */
.sm-orb canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  mix-blend-mode: screen;
  /* The diffuse halo is still a level or two above the ground where it meets
     the canvas edge, and being cut there is what draws a square around
     Alfred. Only the outermost 12% of the radius is faded — the tail and
     nothing else. Masking further in dims the sphere's own rim, which is the
     part that reads as glow. */
  -webkit-mask-image: radial-gradient(circle closest-side, #000 88%, transparent 100%);
          mask-image: radial-gradient(circle closest-side, #000 88%, transparent 100%);
}
/* Inset to where the sphere actually sits, so on a device with no WebGL the
   fallback is the same size as the thing it stands in for — a glow rather
   than a missing rectangle. */
.sm-bloom {
  position: absolute; inset: 16%; border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(134, 182, 232, 0.42) 0%, rgba(120, 168, 224, 0.17) 46%, rgba(134, 182, 232, 0) 74%);
  animation: sm-breathe 4.5s ease-in-out infinite;
}
@keyframes sm-breathe { 0%, 100% { transform: scale(1); opacity: 0.9; } 50% { transform: scale(1.1); opacity: 1; } }
/* Once real particles are drawing, the placeholder steps back to being their
   bloom instead of standing in for them. Handed over, not switched — the orb
   needs a few frames to build its field. */
.sm-orb.is-on .sm-bloom {
  opacity: 0.55;
  transition: opacity var(--d-slower) var(--d-ease);
}

@media (prefers-reduced-motion: reduce) {
  /* Ambient, infinite, and carrying no information — the whole class of
     motion the design system stops outright. The bloom stays as a still
     glow, so the screen keeps its presence without anything moving; the
     particle field is never mounted at all (see login.ejs). */
  .sm-bloom { animation: none; }
}

.splash-mark { margin-bottom: 26px; }
.splash-mark img {
  height: 22px; width: auto; display: block;
  filter: drop-shadow(0 0 14px rgba(134, 182, 232, 0.32));
}
.splash-mark .sm-sub {
  display: block; margin-top: 10px;
  font-size: 10.5px; font-weight: 500; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--d-bloom);
}

/* ---------- Fields on the navy plate ----------
   The resting and focused states were separated only by a border hue and a 4px
   ring of --d-accent-dim. That colour is rgba(44,111,181,0.10) — an accent at
   10% alpha, measured to sit on white. On the plate it lands a couple of
   percent away from the ground and disappears, so both states read the same.
   The fix is not a stronger ring on a white card: it is to let the field belong
   to the plate. Resting is a faint well cut into the navy; focused lifts to a
   brighter glass with a bloom rim. The difference is ground, border, rim and
   icon at once — four signals, so it survives sunlight and a cracked screen.

   Inverting the ground means the ink has to be restated, because this is the
   exact screen where an inherited colour once rendered white type on a white
   field. It is stated here, including the -webkit-text-fill-color that iOS
   needs, and including the autofill override — Chrome paints its own pale
   yellow-blue ground over autofilled inputs, which on a dark field looks like a
   rendering fault. There is no way to set that background directly; a large
   inset shadow is the only thing that covers it. */
.splash .input {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  color: #fff;
}
.splash .input input {
  color: #fff; -webkit-text-fill-color: #fff;
  caret-color: var(--d-bloom);
}
.splash .input input::placeholder { color: rgba(255, 255, 255, 0.38); }
.splash .input .material-symbols-outlined {
  color: rgba(255, 255, 255, 0.50);
  transition: color var(--d-fast) var(--d-ease);
}
.splash .input:focus-within {
  background: rgba(255, 255, 255, 0.13);
  border-color: var(--d-bloom);
  box-shadow: 0 0 0 4px rgba(134, 182, 232, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.splash .input:focus-within .material-symbols-outlined { color: var(--d-bloom); }
.splash .input input:-webkit-autofill,
.splash .input input:-webkit-autofill:focus {
  -webkit-text-fill-color: #fff;
  -webkit-box-shadow: 0 0 0 60px #0d3357 inset;
  caret-color: var(--d-bloom);
}

/* The code cells are the same field in six pieces, so they say the same thing.
   Filled is its own state here and not a lesser focus: six cells where four are
   full and one is live has to show all three readings at a glance. */
.splash .otp-cell {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  color: #fff; -webkit-text-fill-color: #fff;
  font-weight: 600;
  caret-color: var(--d-bloom);
}
.splash .otp-cell.filled {
  background: rgba(255, 255, 255, 0.11);
  border-color: rgba(255, 255, 255, 0.30);
}
.splash .otp-cell:focus {
  background: rgba(255, 255, 255, 0.15);
  border-color: var(--d-bloom);
  box-shadow: 0 0 0 2.5px rgba(134, 182, 232, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.splash .field label { color: rgba(255, 255, 255, 0.62); }

/* ==========================================================================
   THE BOTTOM CHROME GOES NAVY, AND SO DOES THE SEGMENT
   --------------------------------------------------------------------------
   Both were white-on-white: a 90%-white bar over a #F5F7FA canvas, and a
   segment whose selected pill was --d-card (white) on a 5% navy track. They
   read as absence rather than as chrome — the tab bar in particular had to
   borrow a shadow to prove it was there at all.

   Navy is not a new colour here. It is --d-plate, the same family the primary
   button, the "Start shift" band and the sign-in screen already wear, so the
   bottom of every screen now closes on the brand rather than fading out.
   ========================================================================== */

/* ---------- The tab bar ----------
   Kept translucent with its blur: content scrolling under it should still be
   felt, and a solid bar on a phone reads as a second screen edge. */
.tab-bar {
  background: linear-gradient(180deg, rgba(11, 44, 76, 0.93) 0%, rgba(6, 26, 48, 0.97) 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.10);
  /* The old shadow was a NAVY shadow, there to lift a white bar off a white
     page. A dark bar does not need lifting — what it needs is the hairline of
     light along its top edge that every other dark surface in this product
     carries, plus a soft dark pool beneath the seam. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06),
              0 -14px 34px -18px rgba(2, 10, 20, 0.75);
}
/* The ink scale inverts with the ground, or the labels vanish. --d-ink-on-dark
   is the token the product already uses for exactly this. */
.tab { color: var(--d-ink-on-dark); }
/* Was --d-g7 (#082541) — navy text, which on a navy bar is invisible. This had
   to change or the active tab would have disappeared with the ground.

   It lands on --accent-2 rather than white. The system reserves --accent
   (#86b6e8) for "the active state, the focus, the live figure" and says of
   --accent-2 "not a UI text colour" — this is a deliberate exception, taken so
   the bar's selected item speaks the same pale blue as the End shift band and
   the wordmark's gradient, instead of being the one pure white in the chrome.
   It also reads louder, not quieter, for it: 11.1:1 on the bar against the
   7.5:1 --accent would have given. */
.tab.active { color: #C3DCF5; }

/* ---------- Alfred's slot on the new bar ----------
   The 3px white rim existed to cut a dark orb out of a WHITE bar. That job is
   gone, and left alone the rim reads as a white donut. It becomes the same
   light hairline the rest of the dark chrome uses — still a ring, so the tap
   target keeps its edge, but no longer a cut-out. */
.tab.alfred .alfred-orb {
  border-color: rgba(255, 255, 255, 0.13);
  box-shadow: 0 8px 20px -8px rgba(2, 10, 20, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.tab.alfred.active { color: #C3DCF5; }
.tab.alfred.active .alfred-orb {
  box-shadow: 0 8px 22px -8px rgba(2, 10, 20, 0.7),
              0 0 0 3px var(--d-bloom-halo),
              inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

/* ---------- The segment ----------
   One component, six instances (Map/List, All/Upcoming/Completed, and the
   segments on earnings, alerts, schedule and trip history). It changes in one
   place so those six stay one control — a toggle that is blue on the trips
   screen and grey on the earnings screen is two components wearing one name.

   The selected pill takes the navy plate: the segment's whole job is to say
   which of two or three things you are looking at, and a white pill on a grey
   track was making that with elevation alone. Now it is made with ink. */
.seg {
  border-color: rgba(44, 111, 181, 0.22);
  background: rgba(44, 111, 181, 0.09);
  box-shadow: inset 0 1px 2px rgba(9, 44, 76, 0.07);
}
.seg > * { color: rgba(29, 88, 150, 0.78); }
.seg > *.on {
  background: var(--d-plate);
  color: #FFFFFF;
  box-shadow: 0 2px 8px rgba(9, 44, 76, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
/* The icon inside a selected item is part of the label, not a separate mark. */
.seg > *.on .material-symbols-outlined { color: inherit; }

/* Above 481px the shell is a centred column on a grey desk and every fixed bar
   takes a navy hairline down each side to keep that column unbroken. On a navy
   bar a navy hairline is not there — it inverts with the ground, like the ink. */
@media (min-width: 481px) {
  .tab-bar {
    border-left-color: rgba(255, 255, 255, 0.10);
    border-right-color: rgba(255, 255, 255, 0.10);
  }
}

/* ==========================================================================
   THE SHIFT CONTROL — one object, two states, both from the system's palette
   --------------------------------------------------------------------------
   This was two unrelated things: a navy band to go on duty and a white card to
   come off it, each written twice in home.ejs as inline styles. They are not
   two components. They are one control in its two states, and the whole job of
   the band is to say WHICH state you are in before you have read a word of it.
   So they share everything but the colour.

   Navy had to go regardless: with the tab bar now on the navy plate, a navy
   band an inch above it stopped reading as "the thing to press" and started
   reading as more chrome.

   ---- the two colours, and where they come from ----
   #67e8a6 · go. The design system is explicit: "The only green in the system,
   with one use: the live dot on the route chip. It has no token because there
   should be no second use without a decision." Putting the driver on duty is
   that second use, and this block is the decision being recorded.

   #c3dcf5 · stop. The system's --accent-2. Coral (--danger) was tried here
   and pulled: its stated rule of use is "invalid field, error message, a hint
   that became a problem", and ending a shift is none of the three — it is the
   ordinary end of an ordinary day, and dressing it as a hazard every evening
   is how a warning colour stops meaning anything. --accent-2's own rule is
   "the light end of a gradient, and code colour — NOT a UI text colour",
   which this respects: it is a surface here, and the ink on it is navy.

   The asymmetry is the point. Going on duty is the one action on that screen
   and it is the brightest object on it; coming off duty is a quiet, expected
   thing you will do once. They are not peers, and only one of them is lit.

   Both are declared HERE and not in :root. A global token hands the next
   screen a colour to reach for without deciding anything, and for the green
   the absence of a token IS the rule working. Scoped to this component,
   nothing else inherits either one.

   NEITHER is --d-ok or --d-bad. Those two scales (#17b26a, #f04438) are
   declared in this file and in rider-app.css and are the mobile chapter's own
   invention: --d-ok is used in exactly one place in the whole product
   (rider-flow.css) and --d-bad in one component. They are drift, not the
   palette, and building a state out of them would have put a second green
   into a system that names exactly one.

   FILLED, not plated. Both are light colours specified as marks on dark
   ground; dragging either into a dark gradient invents a value the system
   never names. Navy ink measures 11.5:1 on the mint and 12.5:1 on the pale
   blue — white would be 2.3:1 and 1.4:1, which is why the ink is navy on
   both and not white on either.
   ========================================================================== */
.shift-cta {
  --shift-ink: #041A2E;

  display: flex; align-items: center; gap: 12px;
  margin-top: 14px; padding: 14px;
  border-radius: var(--d-r-lg);
  background: var(--shift-fill);
  color: var(--shift-ink);
  cursor: pointer;
  box-shadow: 0 10px 26px -14px var(--shift-shadow), inset 0 1px 0 rgba(255, 255, 255, 0.40);
  transition: transform var(--d-fast) var(--d-ease), background var(--d-fast) var(--d-ease);
}
.shift-cta.go {
  --shift-fill:   #67E8A6;
  --shift-lit:    #4FD991;
  --shift-shadow: rgba(23, 138, 90, 0.55);
}
.shift-cta.end {
  --shift-fill:   #C3DCF5;
  --shift-lit:    #AECDEE;
  --shift-shadow: rgba(60, 106, 156, 0.38);
}
.shift-cta:active { transform: scale(0.99); background: var(--shift-lit); }
.shift-cta .shift-cta-i {
  width: 36px; height: 36px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--d-r-sm);
  /* The ink at low alpha, not white at low alpha: on a light ground a white
     wash is invisible, and the chip has to read as a recess. */
  background: rgba(4, 26, 46, 0.13);
  color: var(--shift-ink);
}
.shift-cta .shift-cta-t { flex: 1; min-width: 0; }
.shift-cta .shift-cta-n { font-size: 13px; font-weight: 600; }
/* 0.78 alpha still measures ~5.4:1 on the mint and ~6.2:1 on the pale blue —
   the line is quieter than the label without dropping out of contrast. */
.shift-cta .shift-cta-s { font-size: 11px; opacity: 0.78; margin-top: 1px; }
.shift-cta .shift-cta-go { color: var(--shift-ink); opacity: 0.55; }

/* The confirm sheet's two actions. Side by side, equal width: they are a
   question's two answers, and stacking them implies an order of preference
   the sheet has no business asserting. Cancel sits left, where a thumb
   travelling up the screen reaches it first. */
.m-confirm-btns {
  display: flex; gap: 10px;
  padding: 20px 20px 0;
}
.m-confirm-btns .btn { flex: 1; }
/* The body is optional — a short question does not need a second paragraph
   restating it, and an empty <p> would still take its line-height. */
#mConfirmB[hidden] { display: none !important; }
