/* ============================================================================
   RIDER APP — the real stylesheet.
   ----------------------------------------------------------------------------
   The user app (/user-app/*, views/mobile/rider/*.ejs) restyled onto the same
   surface the driver app already stands on. It is a SKIN of the wireframe
   system, exactly as driver-app.css is: every class name below already
   existed, and not one line of markup in views/mobile/rider/ changed to make
   this file work. What changed is the list a restyle is allowed to change —
   fill, radius, shadow, glow, type scale, spacing, mark shapes, motion.

   WHY A SECOND FILE AND NOT A SHARED ONE. driver-app.css says on its own first
   screen that it is "loaded only by views/mobile/driver-layout.ejs" — the
   driver app is finished and shipped, and pulling a core out from under it to
   serve this restyle would put a working app at risk for a refactor nobody
   asked for. So the two apps fork, the same way driver-layout.ejs forked from
   layout.ejs. The token block below is deliberately IDENTICAL to the driver's,
   value for value: they are one design system rendered twice, and the day that
   stops being true is the day the extraction is worth doing.

   WHAT IT INHERITS, per design-system chapter 03's contract:

     The blue family      #111 does not appear in this file. Navy #092C4C is
                          the ink, #2c6fb5 the accent on the light column,
                          #86b6e8 the bloom on a dark plate.
     Inter, compensated   Self-hosted variable Inter (fonts.css), so weight 450
                          is a real instance. Body 450, emphasis 500, caps 600.
     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.
     Three motion curves  --d-ease / --d-ease-io / --d-spring.
     Alfred is the orb    The tab bar hosts a real ai-orb.js canvas, and that
                          slot is the door to AI mode (/user-app/ai). See
                          rider-ai.css for the mode itself.

   WHAT IS THIS APP'S OWN, AND NOT THE DRIVER'S:

     The countdown        A driver's home screen answers "what do I do next".
                          A rider's answers "when does my ride get here", so
                          the largest thing on it is a clock counting down, set
                          at 300 weight in tabular figures — a reading, never a
                          headline.
     The people           A driver's day is jobs; a rider's is a driver, a
                          vehicle and a room. .driver-card, .veh-block and the
                          hotel family are where this app spends its detail.
     The key card         The one object here with no equivalent anywhere else
                          in the product. It is the navy plate, because a key
                          is a thing you hold, not a row you read.

   NATIVE CONSTRAINTS carried over unchanged: safe-area insets on both bars,
   truly-fixed chrome with matching .scroll padding, the 480px centred shell,
   and -webkit-tap-highlight-color:transparent.

   Loaded only by views/mobile/rider-layout.ejs.
   ============================================================================ */


: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,
.tl-item .d,
.doc-row .d-info .st,
.notif-item .n-info .stamp,
.hero-trip .hero-tag,
.count-hero .ch-tag,
.kicker,
.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;
}
/* Two children: the title takes the slack, the actions 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.

   There is no mode switch up here, and there is no room for one either. The
   AI mode is reached from Alfred's slot in the tab bar, which is where he
   already lives on this surface — a segmented control in the header would be
   a second door into the same room, and the widest thing in the bar. */
.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;
}
.topbar-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }


.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);
}

/* ============================================================================
   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: var(--d-accent-line); }

/* The real "Alfred is answering" strip on an autonomous tenant's chat — see
   Company.alfredMode and riderApp.js's /chat/:id/escalate. */
.ai-handoff {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  background: var(--d-accent-dim);
  border-top: 1px solid var(--d-accent-line);
  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; }


/* ============================================================================
   BILLING ROWS
   Rider billing (an invoice, a contract, a billing entity) is a list of
   amounts against labels — the same row the driver app built for earnings,
   and rider/billing.ejs already asks for it by that name.
   ========================================================================== */
.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); }

/* 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; }

/* ============================================================================
   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-bottom: 1px solid var(--d-line);
  background: var(--d-card);
  cursor: default;
  min-height: var(--d-touch-lg);
}
.doc-row:last-child { border-bottom: none; }
/* The rider's own document row. The driver app draws a paper thumbnail with a
   folded corner here, because a licence and an insurance certificate are
   OBJECTS a driver hands over. A rider's documents are a passport scan and a
   travel letter — files, filed — so this one leads with the same accent-dim
   glyph tile every other list on this surface uses (.mi-ico, .n-ico), and the
   row reads as a list rather than as a shelf. */
.doc-row .d-ico {
  width: 40px; height: 40px; 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;
}
.doc-row .d-ico .material-symbols-outlined { font-size: 20px; }
.doc-row .d-info { flex: 1; min-width: 0; }
.doc-row .d-info .n { font-size: 14px; font-weight: 500; color: var(--d-ink); }
.doc-row .d-info .s { font-size: 11.5px; color: var(--d-ink-3); margin-top: 3px; }
.doc-row .d-info .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 .d-info .st.warn { color: var(--d-warn-ink); }
.doc-row .d-info .st.expired { color: var(--d-bad-ink); }

.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); }

/* ============================================================================
   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 COUNTDOWN — this app's own hero, and the reason it is not the driver's.
   ----------------------------------------------------------------------------
   The driver's home screen answers "what do I do next", so its hero is a job.
   A rider's answers one question and it is a question about TIME: when does my
   ride get here. So the largest mark on this screen is a clock, and it is set
   the way every figure that is the point of its card is set on this surface —
   large, light (300), tabular, ink — never as a headline at 700.

   The wireframe put this on the navy plate as a banner. It stays on the plate:
   a countdown is the one thing on the screen that is running, and the plate is
   how this system says "this is the live one" without spending the accent.
   ========================================================================== */
.countdown-big {
  display: flex; align-items: baseline; gap: 2px;
  padding: 16px 18px;
  margin-bottom: 12px;
  background: var(--d-plate);
  color: #fff;
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-plate-shadow);
}
.countdown-big .cd-n {
  font-size: 38px; font-weight: 600; letter-spacing: -0.045em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.countdown-big .cd-l {
  font-size: 14px; font-weight: 500; color: var(--d-bloom);
  margin: 0 10px 0 2px;
}
.countdown-big .cd-l:last-of-type { margin-right: 0; }

/* Now that the hero below is a plate too, the two of them separated by 12px of
   paper read as one slab with a slot cut through it. Joined, they read as what
   they are: the strip that is RUNNING, and under it the trip it is counting
   down to. The joint is a hairline, and the countdown drops to a flat #0F3B63
   — the plate's own top step — so the gradient runs unbroken across the seam
   instead of resetting at it. */
.countdown-big:has(+ .count-hero) {
  margin-bottom: 0;
  border-radius: var(--d-r-xl) var(--d-r-xl) 0 0;
  background: #0F3B63;
  border-bottom: 1px solid rgba(255, 255, 255, 0.13);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.countdown-big:has(+ .count-hero) + .count-hero {
  border-radius: 0 0 var(--d-r-xl) var(--d-r-xl);
  /* The top highlight belongs to the top of the joined object, not to the
     middle of it — otherwise a white line lands right under the hairline. */
  box-shadow:
    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);
}

/* ---------- The next trip, as a rider reads it ----------
   Same object as the driver's .hero-trip and the same live rail down its left
   edge, but the reading order is different: a rider wants the TIME first and
   the route second, and never needs the pax count or the quick-action pad. */
/* The next trip rides the PLATE, the same ground the Design System gives its
   own primary reading ("Fleet in service" wears `.dcard-ink`, and that card's
   gradient and this app's `--d-plate` are the same three navy steps). One
   screen, one live object: on a light column the plate is how this system says
   "this is the one that is running" without spending the accent on it. Every
   colour below is therefore measured against the plate's LIGHTEST step,
   #0F3B63, not against paper. */
.count-hero {
  display: block;
  position: relative;
  background: var(--d-plate);
  border: 1px solid transparent;
  border-radius: var(--d-r-xl);
  padding: 20px;
  margin-bottom: 12px;
  box-shadow: var(--d-plate-shadow);
  overflow: hidden;
  transition: transform var(--d-fast) var(--d-ease);
}
.count-hero:active { transform: scale(0.99); }
/* No live rail. On paper the rail was what marked this card as the running one;
   on the plate the plate itself does that job, and a second marker on top of it
   is one signal too many. */
.count-hero .ch-tag {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 10px;
  color: var(--d-bloom);
}
.count-hero .ch-tag .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--d-bloom);
  box-shadow: 0 0 0 3px var(--d-bloom-halo);
  animation: d-pulse 1.8s var(--d-ease-io) infinite;
}
.count-hero .ch-time {
  font-size: 34px; font-weight: 600; letter-spacing: -0.04em; line-height: 1;
  color: #fff; font-variant-numeric: tabular-nums;
}
.count-hero .ch-time small {
  font-size: 10.5px; font-weight: 600; color: rgba(255, 255, 255, 0.62);
  text-transform: uppercase; letter-spacing: 0.10em;
  margin-left: 9px;
}
.count-hero .ch-sub { font-size: 13.5px; color: rgba(255, 255, 255, 0.74); margin-top: 6px; font-weight: 500; }
.count-hero .ch-route { margin-top: 18px; }

/* The route marks are shared with the trip screens, where they sit on paper.
   Inside the plate they are re-stated on the dark ground and NOWHERE else —
   every override here is scoped to `.count-hero`. */
.count-hero .r-addr { color: #fff; }
.count-hero .r-meta { color: rgba(255, 255, 255, 0.62); }
.count-hero .r-dot { border-color: rgba(255, 255, 255, 0.45); background: transparent; }
.count-hero .r-dot.filled { background: #fff; border-color: #fff; }
.count-hero .ch-connector { background: rgba(255, 255, 255, 0.30); }

/* The primary action directly under the plate. It stays in the plate family —
   this app's CTA is a deep-navy plate, never a flat blue pill — but it cannot
   be the SAME navy as the card it follows, or the action reads as the bottom
   edge of the card instead of as the thing to press. It takes the LIT plate,
   the same three steps opened up (#17507F top), so it advances in front of the
   card rather than merging with it. */
.count-hero + .btn,
.count-hero + .btn-xl {
  background: var(--d-plate-lit);
}
.count-hero + .btn:active,
.count-hero + .btn-xl:active { background: var(--d-plate); }

/* The route inside it. .r-* rather than the driver's .hr-*, because the rider
   templates were written that way; the marks are identical on purpose — one
   product draws one route. */
.r-line { display: flex; align-items: flex-start; gap: 12px; }
.r-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;
}
.r-dot.filled { background: var(--d-g7); border-color: var(--d-g7); }
.r-addr { font-size: 15.5px; font-weight: 500; letter-spacing: -0.018em; color: var(--d-ink); }
.r-meta { font-size: 12.5px; color: var(--d-ink-3); margin-top: 2px; }
/* A solid hairline, indented to sit under the dots — the same call the trip
   list's .connector makes, and for the same reason: a dotted rule reads as an
   unfinished leg. */
.ch-connector {
  width: 2px; height: 20px; margin: 3px 0 3px 5px;
  background: var(--d-g4); border-radius: 1px;
}

/* ============================================================================
   THE PEOPLE AND THE VEHICLE
   A driver's day is a list of jobs. A rider's is a person who is coming to get
   them and the van they are coming in, so this is where this app spends its
   detail.
   ========================================================================== */
.driver-card {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  margin-bottom: 10px;
}
.driver-card .dc-info { flex: 1; min-width: 0; }
.driver-card .dc-info .n { font-size: 15px; font-weight: 500; letter-spacing: -0.018em; color: var(--d-ink); }
.driver-card .dc-info .m {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; color: var(--d-ink-3); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
/* The star is the accent, filled — a rating is a reading, and this is the one
   place on the screen where it is the point. */
.driver-card .dc-info .m .material-symbols-outlined {
  font-size: 15px; color: var(--d-accent);
  font-variation-settings: 'FILL' 1, 'wght' 400;
}
.driver-card .dc-actions { display: flex; gap: 8px; flex-shrink: 0; }
.driver-card .dc-actions .a {
  width: var(--d-touch); height: var(--d-touch); border-radius: 50%;
  border: 1px solid var(--d-line-2);
  background: var(--d-card);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-ink);
  box-shadow: var(--d-lift-1);
  transition: transform var(--d-fast) var(--d-ease), background var(--d-fast) var(--d-ease);
}
.driver-card .dc-actions .a:active { transform: scale(0.93); background: var(--d-sunk); }
.driver-card .dc-actions .a .material-symbols-outlined { font-size: 19px; }

.veh-block {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  margin-bottom: 10px;
}
/* The van, at the size a van is worth. A passenger matching a shape in a
   pickup lane needs to see the vehicle, not a 52px chip of it — so the frame
   is 4:3 and wide enough to read, and the image is cropped to the body rather
   than letterboxed inside a square. */
.veh-block .veh-ph {
  width: 88px; height: 66px; border-radius: var(--d-r-sm);
  border: 1px solid var(--d-line);
  background: var(--d-sunk);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-ink-3); flex-shrink: 0;
  overflow: hidden;
}
.veh-block .veh-ph .material-symbols-outlined { font-size: 26px; }
.veh-block .veh-ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A stand-in for the class is not a photo of this van and must not pass for
   one — but the class image is now a manufacturer's cutout on white, which
   already announces itself as a catalogue render and could never read as a
   snapshot of this vehicle. So the old desaturate/fade comes off: laid over the
   sunken tint at 92% it turned the cutout's white ground a dirty grey inside a
   white card. The tile goes white to match the image instead. (The hotel image
   is a real photograph and keeps the treatment.) */
.veh-block .veh-ph.is-class { background: #fff; }
.veh-block .veh-ph.is-class img { filter: none; opacity: 1; }
.veh-block .v-info { flex: 1; min-width: 0; }
.veh-block .v-info .n { font-size: 14.5px; font-weight: 500; color: var(--d-ink); }
.veh-block .v-info .m { font-size: 12px; color: var(--d-ink-3); margin-top: 3px; }
/* THE VAN NUMBER. This box used to hold the registration, and since no vehicle
   in this fleet has one it held an em-dash — a bordered box containing nothing,
   which tells a passenger less than no box at all. It now holds the number the
   van is actually called ("SkyHop 102" -> 102), set large, because that is the
   figure you match against the van pulling up to the kerb. Mono, because it is
   an identifier and not a quantity. A real registration, where one exists, is a
   different fact and rides the meta line with the seat count. */
.veh-block .van-no {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 12px;
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-sm);
  background: var(--d-sunk);
  flex-shrink: 0;
}
.veh-block .van-no .vn-k {
  font-size: 9px; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--d-ink-3);
}
.veh-block .van-no .vn-n {
  font-family: var(--mono);
  font-size: 21px; font-weight: 500; letter-spacing: 0.01em; line-height: 1.1;
  color: var(--d-ink); font-variant-numeric: tabular-nums;
}

/* Kept for any surface still passing a real registration. */
.veh-block .plate {
  font-family: var(--mono);
  font-size: 13px; font-weight: 500; letter-spacing: 0.06em;
  padding: 7px 10px;
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-xs);
  background: var(--d-sunk);
  color: var(--d-ink);
  flex-shrink: 0;
  white-space: nowrap;
}

/* ============================================================================
   HOTEL
   ========================================================================== */
.kicker {
  display: inline-flex; align-items: center; gap: 6px;
}
.kicker .dot { background: var(--d-accent) !important; }

.hotel-card {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
  margin-top: 12px;
  transition: transform var(--d-fast) var(--d-ease);
}
.hotel-card:active { transform: scale(0.99); background: var(--d-sunk); }
.hotel-card .hc-ico {
  width: 40px; height: 40px; 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;
}
.hotel-card .hc-ico .material-symbols-outlined { font-size: 20px; }
.hotel-card .hc-info { flex: 1; min-width: 0; }
.hotel-card .hc-info .n { font-size: 14.5px; font-weight: 500; color: var(--d-ink); margin-top: 4px; }
.hotel-card .hc-info .m { font-size: 12px; color: var(--d-ink-3); margin-top: 3px; }
.hotel-card .chev { color: var(--d-ink-4); }

.hotel-hero {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  padding: 20px;
  background: var(--d-card);
  border: 1px solid var(--d-line-2);
  border-radius: var(--d-r-xl);
  box-shadow: var(--d-lift-2);
  margin-bottom: 12px;
}
.hotel-hero .row-top { flex: 1; min-width: 0; }
.hotel-hero .hname { font-size: 21px; font-weight: 500; letter-spacing: -0.025em; line-height: 1.15; color: var(--d-ink); }
.hotel-hero .hsub { font-size: 13px; color: var(--d-ink-2); margin-top: 4px; font-weight: 500; }
/* Landscape, not square. It grows to the LEFT — the height is what sets the
   card's rhythm against the name and room number beside it, so that stays at
   88px and only the width opens up. A building photographed from the street is
   a wide subject anyway; the square was cropping it to a slot. */
.hotel-hero .h-photo {
  width: 148px; height: 88px; border-radius: var(--d-r-lg);
  background: var(--d-sunk);
  border: 1px solid var(--d-line);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--d-ink-4); flex-shrink: 0;
  overflow: hidden;
}
.hotel-hero .h-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Same rule as the van: an image standing in for the category is set back a
   little, so it never reads as a photograph of this actual building. */
.h-photo.is-class img, .hc-ico.is-class img { filter: saturate(0.78) contrast(0.96); opacity: 0.94; }

/* The home card gets the building too — it is the row that answers "where am I
   sleeping", and a 40px tinted square answered it with an icon. */
.hotel-card .hc-ico.is-class {
  width: 56px; height: 56px;
  background: var(--d-sunk); border-color: var(--d-line);
  overflow: hidden; padding: 0;
}
.hotel-card .hc-ico.is-class img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- The key card ----------
   The one object in this app with no equivalent anywhere else in the product,
   and the only place outside the splash and the AI mode where a rider screen
   goes dark. That is the argument for it: a room key is a THING YOU HOLD, not
   a row you read, and on this surface the navy plate is what an object is made
   of. Everything on it inverts — see the token block, which is the same trick
   .splash plays, for the same reason. */
.key-card {
  position: relative;
  background: var(--d-plate);
  color: #fff;
  border-radius: var(--d-r-xl);
  padding: 20px;
  margin-bottom: 12px;
  box-shadow: 0 14px 34px -16px rgba(9, 44, 76, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.16);
  overflow: hidden;
}
/* The bloom, arriving from one direction — Alfred's own light, and the only
   thing that keeps a dark plate this large from reading as a hole. */
.key-card::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(100% 80% at 85% 0%, var(--d-bloom-halo), transparent 62%);
  pointer-events: none;
}
.key-card > * { position: relative; }
.key-card .kc-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.key-card .kc-top .material-symbols-outlined { font-size: 22px; color: var(--d-bloom); }
.key-card .brand-chip {
  display: inline-flex; align-items: center;
  padding: 5px 11px;
  border: 1px solid var(--d-line-inv);
  background: rgba(255, 255, 255, 0.08);
  border-radius: var(--d-r-xs);
  font-size: 10px; font-weight: 600; letter-spacing: 0.10em;
  color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 60%;
}
.key-card .kc-label { color: var(--d-bloom); }
.key-card .kc-room {
  font-size: 46px; font-weight: 600; letter-spacing: -0.045em; line-height: 1;
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}
.key-card .kc-sub { font-size: 12.5px; color: var(--d-ink-on-dark); margin-top: 8px; }
.key-card .kc-divider { height: 1px; background: var(--d-line-inv); margin: 18px 0; }

.unlock-zone { text-align: center; }
/* 96px, well above the touch scale's top band, because this is the only
   control on the screen and it is pressed with a phone held up to a door. */
.unlock-btn {
  width: 96px; height: 96px; border-radius: 50%;
  border: 1px solid var(--d-line-inv);
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  transition: transform var(--d-base) var(--d-spring), background var(--d-base) var(--d-ease), box-shadow var(--d-base) var(--d-ease);
}
.unlock-btn .material-symbols-outlined { font-size: 38px; transition: color var(--d-base) var(--d-ease); }
.unlock-btn:active { transform: scale(0.94); }
/* Unlocked is a STATE, and a state gets the light — not a colour swap. The
   glyph changes too (lock -> lock_open), so this never relies on colour alone. */
.unlock-btn.unlocked {
  background: linear-gradient(180deg, #FFFFFF, #DCE7F3);
  border-color: transparent;
  box-shadow: 0 0 0 8px var(--d-bloom-halo), 0 12px 30px -12px rgba(134, 182, 232, 0.85);
}
.unlock-btn.unlocked .material-symbols-outlined { color: #0A2038; }
.unlock-lbl { font-size: 13.5px; font-weight: 500; margin-top: 14px; color: #fff; }
.unlock-hint { font-size: 11.5px; color: rgba(255, 255, 255, 0.55); margin-top: 6px; line-height: 1.45; }

.quick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* ============================================================================
   HELP
   ========================================================================== */
.cat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cat {
  padding: 16px 14px;
  background: var(--d-card);
  border: 1px solid var(--d-line);
  border-radius: var(--d-r-lg);
  box-shadow: var(--d-lift-1);
}
.cat .cico {
  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;
  margin-bottom: 12px;
}
.cat .cico .material-symbols-outlined { font-size: 20px; }
.cat .lb { font-size: 14px; font-weight: 500; letter-spacing: -0.015em; color: var(--d-ink); }
.cat .sub { font-size: 12px; color: var(--d-ink-3); margin-top: 4px; line-height: 1.45; }

/* ============================================================================
   RATING — the stars a rider actually taps.
   The template sets the colours inline (var(--w-line-2) empty, var(--w-black)
   picked), and both of those names are repointed at the top of this file, so
   the picked star is navy without a line of JS changing. What is added here is
   the touch target and the press, which the wireframe never gave it.
   ========================================================================== */
.star-pick {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; min-height: 44px;
  line-height: 1;
  transition: transform var(--d-fast) var(--d-spring), color var(--d-fast) var(--d-ease);
}
.star-pick:active { transform: scale(1.18); }

/* ---------- 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. */
.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); }
