/* DEC-207: visual refresh of the token system only (values below), not the philosophy behind it --
   the color-coded card system (bike/auto/car/parcel/demand-hot, further down this file) and the
   restrained, low-bandwidth button approach are deliberate accessibility choices for a rural,
   low-literacy audience and stay untouched. Reference: groww.in (teal/green, generous whitespace,
   flat cards with minimal shadow) plus Uber's confident large-type hierarchy -- adapted, not copied
   wholesale, since this app's own constraints (low-literacy, low-bandwidth) come first. */
:root {
  /* DEC-223: owner chose the full purple+gold rebrand after comparing it live against a gold-
     accent-only alternative ("this purple better looks"). --bike/--bike-dark/--bike-container are
     NEW, carrying the OLD teal values forward -- .card-bike used to read off --primary directly,
     which would have merged Bike's own distinct color into the general brand color the moment
     --primary changed, breaking the "tell Bike/Auto/Car apart at a glance" accessibility goal
     DEC-207's own comment above protects. Decoupling first keeps that system fully intact. */
  --bike: #0F766E;
  --bike-dark: #0B5B54;
  --bike-container: #CCFBF1;
  /* New, same decoupling reasoning as --bike above: .card-auto/.card-car previously read literal
     hex (#B45309/#92400E) and var(--info) directly. --info is also used elsewhere for plain
     informational badges/banners unrelated to vehicle branding, so tying Car's identity color to
     it meant a future informational-color change would silently recolor Car too. Named tokens,
     same values carried forward, so nothing currently on screen changes from this alone. */
  --auto: #B45309;
  --auto-dark: #92400E;
  --auto-container: #FEF3C7;
  --car: #1D4ED8;
  --car-dark: #1E3A8A;
  --car-container: #DBEAFE;
  --primary: #5B21B6;
  --primary-dark: #3B0764;
  --primary-container: #F5E6C8;
  --gold: #D4A017;
  --gold-dark: #8A6D1F;
  --accent-container: #FEF3C7;
  /* Was a flat, generic slate-blue (#F8FAFC) -- a barely-warmed off-white ties the neutral to the
     teal brand instead of reading as an unrelated default. */
  --background: #F7FAF9;
  --surface: #FFFFFF;
  /* New: a subtle nested-surface tint for secondary/inset content, Groww-style layering without
     reaching for a drop shadow every time. */
  --surface-sunken: #F1F5F4;
  --text-primary: #111827;
  --text-secondary: #4B5563;
  /* New: lightest supporting text (captions, muted metadata) -- previously overloaded onto
     --text-secondary for everything regardless of actual emphasis. */
  --text-tertiary: #9CA3AF;
  /* Lightened from #D1D5DB -- Groww's flat cards lean on thin hairlines, not heavy borders, now
     that cards also get a touch more radius/padding below. */
  --border: #E5E7EB;
  --success: #166534;
  --warning: #92400E;
  --danger: #B91C1C;
  --info: #1D4ED8;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;

  --radius-card: 20px;
  --radius-input: 14px;
  /* DEC-350c. The full pill (28px, clamped to a stadium on every button height) was tried next and
     was itself wrong in a different way -- owner: "it's the button size, make it match the tiles."
     A stadium button sitting inside a --radius-card (20px) rectangular card, right next to
     .summary-tile's own 20px-radius rectangles, reads as a foreign shape dropped into this app's
     own card language, not as "sleek" -- the clash was radius vocabulary, not roundness amount.
     Tied directly to --radius-card rather than a separate literal: buttons and cards now always
     share one rounding scale by construction, so a future card redesign can never let them drift
     apart the way 16px (too square) and 28px (too round) both silently did. */
  --radius-button: var(--radius-card);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: #e2e8f0;
  /* Owner saw a real Telugu name ("శంకర్ వి", confirmed correctly stored -- garbled only on screen)
     render as mismatched glyphs in Admin. The old stack named no Indic-script font at all and just
     hoped the OS would silently substitute one -- it clearly didn't, on at least this one machine.
     "Nirmala UI" is Windows' own bundled font covering Telugu/Kannada/Tamil/Malayalam since Windows 8;
     "Noto Sans" is Google's broad-coverage fallback for everything else. Both go first so a name in
     any of this app's 4 non-Latin languages has a real font to use instead of an implicit guess, with
     every previously-working Latin font kept after them, unchanged, as the same fallback it always was. */
  font-family: "Nirmala UI", "Noto Sans", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--text-primary);
}

.lab {
  display: flex;
  min-height: 100vh;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-6);
  padding: var(--space-6);
  flex-wrap: wrap;
}

/* Real bug reported live: was min-height, not height -- a screen with more content than the frame
   simply grew the whole .phone taller than the viewport instead of #screen's own
   `overflow-y: auto` (below) containing the scroll to just the content area. That made the ENTIRE
   PAGE scroll instead, pushing status-bar/bottom-nav out of view along with it -- exactly backwards
   from how a real app or this same mock phone frame should behave. A fixed height makes #screen
   the only thing that scrolls, keeping status-bar/bottom-nav pinned, matching a real device. */
.phone {
  width: 390px;
  height: 780px;
  background: var(--background);
  border-radius: 36px;
  border: 10px solid #1f2937;
  box-shadow: 0 20px 50px rgba(0,0,0,0.25);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
}

/* On a real phone the device itself already provides the "phone" frame — the fixed 390px
   mockup width/bezel above is only meant for previewing on a desktop browser. Without this,
   the mockup doesn't fit real narrow viewports and forces horizontal/vertical scrolling to see
   content that would otherwise fit on one screen. */
@media (max-width: 480px) {
  .lab {
    padding: 0;
    gap: 0;
    align-items: stretch;
  }
  .phone {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    border: none;
    border-radius: 0;
    box-shadow: none;
  }
  .devpanel {
    width: 100%;
    border-radius: 0;
  }
}

.status-bar {
  background: #1f2937;
  color: #fff;
  font-size: 12px;
  padding: var(--space-2) var(--space-4);
  display: flex;
  justify-content: space-between;
}

/* DEC-194: inside the real native app (Capacitor), initNativeShell() adds this class to <body> --
   the OS's own real status bar (colored to match, via the StatusBar plugin) already sits above the
   webview, so this mocked clock/label bar would just be a confusing duplicate. Browser/PWA usage
   is completely unaffected -- the class is never added outside the native wrapper. */
body.native-shell .status-bar { display: none; }

/* Real bug reported live on a native Android build: .devpanel ("Prototype controls" -- fake data
   states, jump-to-screen, devpanel-only test hooks) was rendering unconditionally everywhere,
   including the real app real drivers/passengers install. At the mobile CSS breakpoint (below)
   .phone and .devpanel both stretch to 100% width and stack vertically, so on an actual phone this
   pushed all real content below a full screen of dev-only controls, requiring a scroll just to see
   the app. Same native-shell hook as .status-bar above -- hidden only inside the native wrapper,
   the web/Netlify preview (where this panel is still a useful QA tool) is unaffected. */
body.native-shell .devpanel { display: none; }
/* .lab centers/stretches around two children (.phone + .devpanel); with the second one gone in the
   native app, drop the layout rules that were reserving space/alignment for it. */
body.native-shell .lab { justify-content: center; gap: 0; }

/* Safe-area insets (DEC-194): keeps content clear of notches/camera cutouts and the home-indicator
   bar on modern phones. env(safe-area-inset-*) only reports non-zero on devices that need it and
   requires viewport-fit=cover (set on both apps' index.html) -- a harmless no-op everywhere else,
   including desktop preview and older devices. */
.phone {
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

/* Screen titles sit in a flex row between two icon buttons. At a fixed 22px a long translation
   ("ప్రయాణం ప్రచురించండి — కారు") broke onto three lines and pushed the whole header down, so the
   size now scales with the viewport and the line-height is tightened. Shorter title strings do the
   rest; this makes the header resilient to any future translation without needing another pass. */
.title {
  font-size: clamp(17px, 5.2vw, 22px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  min-width: 0;
  margin: 0;
}

.subtitle {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-secondary);
  margin: 2px 0 0;
}

.back-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
/* Malayalam builds long single words -- "പ്രസിദ്ധീകരിക്കുക" is one unbreakable run with no space for
   normal wrapping to use, so a screen title overflowed its row by 10px. Same remedy the phone number
   already needed on .field-row .v: allow a break inside the word, used only when it truly cannot fit,
   so every shorter-word language is untouched. */
.back-row .title { min-width: 0; overflow-wrap: break-word; }

/* DEC-345: was a bare glyph with no bounds -- easy to miss and easy to mis-tap. Now a real 40px
   circular target with a visible pressed state, matching the round icon buttons used elsewhere. */
.back-btn {
  border: none;
  background: none;
  font-size: 19px;
  cursor: pointer;
  color: var(--text-primary);
  line-height: 1;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  padding: 0;
  flex-shrink: 0;
  transition: background-color 0.15s ease;
}
.back-btn:active { background: rgba(15, 23, 42, 0.07); }
.back-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.screen {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
  padding-bottom: 90px;
}
/* Restarted by JS on real navigation only (goTo, not every render) via a class toggle + forced
   reflow -- #screen itself persists across renders (only its innerHTML is swapped each time), so
   the animation would not replay on its own the way a freshly-created element's would. */
.screen.view-enter { animation: screenEnter 180ms ease-out; }
@keyframes screenEnter {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.hero {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  margin: 0 0 var(--space-1);
}
/* The 4px above is right for a title with its own subtitle underneath -- they are one unit, and 12
   of the admin portal's 19 .hero uses are exactly that pairing. It is wrong everywhere else: both
   app Home screens put a real content block straight after the title, which then sat 4px below it
   while every other block on the screen was separated by 12 (measured on Home: 12 / 4 / 12 / 12 /
   12 -- the title was the only break in an otherwise even rhythm). Scoped to the sibling rather
   than changed on .hero itself so the title+subtitle pairs keep their tight spacing, and so any
   future hero without a subtitle picks the right gap up on its own. Adjacent-sibling margins
   collapse, so this resolves to 12 rather than stacking on the 4. */
.hero + :not(.subtitle) { margin-top: var(--space-3); }

/* Owner: "No need to all Upper cases. and could be Normal case" -- sentence case reads lighter
   and is genuinely easier to parse for a low-literacy audience than the previous all-caps
   micro-label treatment; weight/color alone still carry the "this is a section heading" signal. */
/* Text hierarchy (owner: "Main heading and hint should not be same level of text size. Hint always
   smaller size", referencing GoVia/Hopr polish). These three classes were ALL 14px in the same grey,
   so a heading, a real content line and an explanatory aside were indistinguishable. The ladder is
   now heading 15/700 in primary ink -> content 14 -> subtitle 13 -> hint 12, which separates them by
   size AND weight AND colour rather than relying on any one signal. Done in CSS, so it holds
   identically in English, Telugu, Kannada and Tamil without touching a single string. */
/* Was 15px/700/--text-primary -- the SAME weight class as a .card-title (19px/700), just 2px
   smaller, so a section label and the card content under it fought for attention instead of one
   clearly leading. This is the Apple "group header, not content" pattern: small, uppercase,
   tracked, and muted to --text-tertiary (#9CA3AF -- already a real token, just never used here).
   Top margin widened --space-6 (24px) -> --space-8 (32px, also already defined) so the wider gap
   does more of the section-to-section separation that the label's own boldness used to carry.
   Reviewed live via mockup (owner: "even colors too") before shipping; touches every screen in
   both apps that uses .section-label (76 combined usages) since it's one shared class. */
.section-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin: var(--space-8) 0 var(--space-2);
}
.section-label:first-child { margin-top: 0; }

/* Place selector */
.place-field {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-4);
  min-height: 52px;
  cursor: pointer;
  margin-bottom: var(--space-3);
}
/* Fourth time today this exact bug showed up (driver departure row, three parcel controls, now
   here): a flex child's default min-width is its OWN unwrapped content width, not 0 -- so a place
   name plus its "From:"/"To:" label, in a language whose words run longer than English, refused to
   shrink and pushed the whole row, and the whole page, wider than the phone screen. `.place-field`
   is one shared component used 6 times across both apps, so fixing it here protects every one of
   them at once instead of chasing each call site individually. */
.place-field > div { min-width: 0; }
.place-field .value { overflow-wrap: break-word; }

/* Swap From/To (DEC-302). Went through several placements before landing here: right side collided
   with the mic button, left collided with the From dot, a fixed top:56px landed ON the text because
   the field's real height (~74px) was taller than the assumed 56px minimum. Fixed properly: the
   wrapper this sits in contains ONLY the From field (never From+To together), so `bottom: 0` anchors
   to From's own true rendered bottom edge regardless of its real height. Owner, on the visual style:
   "do not highlight with blue, simple two arrows without round" -- no filled circle, no color chip,
   just the plain ⇅ character sitting at the seam. */
.swap-from-to {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translate(-50%, 50%);
  z-index: 1;
  width: 28px;
  height: 28px;
  background: var(--surface);
  border: none;
  color: var(--text-secondary);
  font-size: 20px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.place-field .dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}
.place-field.from .dot { background: var(--primary); }
.place-field.to .dot { background: var(--danger); }
/* Admin portal design pass: a real CSS dot (same shape language as the from/to pair above) instead
   of a 🔴 emoji marking a driver row as real DB data rather than sample/demo data -- an emoji circle
   renders inconsistently across platforms/fonts, a CSS one is exact and themeable. */
.live-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--danger); margin-right: 5px; vertical-align: 1px; }

.place-field .label {
  font-size: 12px;
  color: var(--text-secondary);
  display: block;
}
/* Owner: "why cant use FROM: Select Startpoint side by side to save the space" -- inline label,
   deliberately NOT reusing .label (display:block would force it back onto its own line). Keeps the
   field's full tap-target width (unlike a side-by-side two-column layout, which was tried and
   rejected for narrowing each tap zone) while cutting the field roughly in half vertically. */
.place-field .inline-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}
.place-field .value {
  font-size: 18px;
  font-weight: 600;
}
.place-field .value.placeholder {
  font-weight: 400;
  color: var(--text-secondary);
}

.mic-inline {
  margin-left: auto;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 50%;
  border: none;
  background: var(--primary-container);
  color: var(--primary-dark);
  font-size: 18px;
  cursor: pointer;
}

.mic-btn {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  border-radius: var(--radius-input);
  border: none;
  background: var(--primary);
  color: #fff;
  font-size: 20px;
  cursor: pointer;
}

.speak-btn {
  border: none;
  background: none;
  color: var(--primary);
  font-size: 15px;
  cursor: pointer;
  padding: 0 0 0 6px;
  vertical-align: middle;
}

.speak-all-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--primary);
  background: var(--primary-container);
  color: var(--primary-dark);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  margin-top: var(--space-2);
}

.swap-btn {
  width: 100%;
  display: flex;
  justify-content: flex-end;
  margin-top: -8px;
  margin-bottom: var(--space-3);
}
.swap-btn button {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 999px;
  width: 40px;
  height: 40px;
  font-size: 16px;
  cursor: pointer;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.chip {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 999px;
  padding: var(--space-2) var(--space-3);
  font-size: 14px;
  cursor: pointer;
  transition: transform 0.1s ease, background-color 0.15s ease;
}
.chip:active { transform: scale(0.96); background: #F3F4F6; }

.route-chip {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--primary-container);
  border: 1px solid var(--primary);
  border-radius: var(--radius-input);
  padding: var(--space-4);
  margin-bottom: var(--space-2);
  cursor: pointer;
  min-height: 52px;
  transition: transform 0.1s ease;
}
.route-chip:active { transform: scale(0.98); }
.route-chip-icon { font-size: 18px; }
.route-chip-text { font-size: 17px; font-weight: 600; color: var(--primary-dark); display: block; }
.route-chip-via { font-size: 12px; color: var(--primary-dark); opacity: 0.75; margin-top: 2px; }
.route-chip-body { flex: 1; }
.route-chip-remove {
  border: none;
  background: none;
  color: var(--primary-dark);
  font-size: 16px;
  cursor: pointer;
  padding: 4px 8px;
  flex-shrink: 0;
}

/* Buttons -- kept deliberately restrained (a soft shadow + a quick press response), not flashy:
   this app stays minimal-text/low-bandwidth for a rural, low-literacy audience (CLAUDE.md), so the
   goal is a clear sense of "this is tappable" and real tactile feedback on tap, never decoration
   for its own sake. Same rule for every button variant/size across both apps, not a one-off.
   DEC-353: height reduced app-wide (52px -> 46px, still above the 44px accessibility minimum) after
   the owner asked for less height on two separate buttons on two different screens -- fixing it
   once here means every current and future button matches by construction, rather than each one
   needing its own special case found and fixed individually. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 46px;
  border-radius: var(--radius-button);
  border: none;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 var(--space-4);
  width: 100%;
  /* A button's own text is an anonymous flex child of the button box, subject to the same default
     min-width-is-content-width rule as everything else fixed today. Two of these side by side in a
     narrow grid column (e.g. Take Photo / Replace Photo) still overflowed by a few px in Tamil even
     after wrapping across two lines, because one Tamil word alone was wider than the column. */
  overflow-wrap: break-word;
  text-align: center;
  transition: transform 0.1s ease, box-shadow 0.15s ease, background-color 0.15s ease, opacity 0.15s ease;
}
.btn:active { transform: scale(0.98); }
/* Keyboard focus was invisible before -- the only affordance was :active, which a keyboard never
   fires. Uses the accent rather than the primary so it stays visible on a primary button too. */
.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* DEC-345. Flattened. These carried a two-stop gradient and a 10px coloured glow (DEC-210), which
   is the glossy treatment that dates an interface -- and on this app it was doing real damage
   beyond taste: .btn-primary doubles as the SELECTED state for every toggle group (Yes/No, the
   0.5/1/2km chips, the parcel sizes), so a chip merely being chosen came with a full call-to-action
   glow and shouted as loudly as "Confirm & Publish". Flat colour lets a selected chip read as
   selected and leaves the real CTA to carry weight through size and position instead.
   Owner: "make all these buttons sleek like what i provided reference and better than that".
   Better than flat-and-dull: a 1px darker seat under the button gives it a physical edge without
   any gloss, so it still looks pressable rather than painted on. */
.btn-primary {
  background: var(--primary);
  color: #fff;
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.18), 0 1px 2px rgba(15, 23, 42, 0.12);
}
.btn-primary:active { background: var(--primary-dark); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.22); }
.btn-secondary {
  background: var(--surface);
  color: var(--text-primary);
  /* A slightly stronger border replaces the drop shadow: these sit in groups beside a primary, and
     a shadow on each made a row of chips look like a row of floating cards. */
  border: 1.5px solid #DCD9E3;
  box-shadow: none;
}
.btn-secondary:active { background: #F3F4F6; border-color: var(--primary); }
/* A CHOSEN OPTION MUST NOT LOOK LIKE THE SCREEN'S SUBMIT BUTTON. Selected options used to render
   as .btn-primary -- the identical solid purple as the real CTA sitting right under them, so on
   Send a Parcel the chosen "1 km" (a preference) and "Search vehicles" (the action that moves you
   forward) were the same object visually, and the eye had no way to tell which one commits you.
   Deliberately reuses .size-pick.selected's exact tint/border rather than inventing a second
   selected-state look, so the app has ONE selection language across sizes, timing and distance --
   and solid-fill purple goes back to meaning exactly one thing per screen: the forward action. */
.btn-choice.selected {
  background: #EDE9FE;
  border-color: #7C3AED;
  border-width: 2px;
  color: var(--primary-dark);
}
.btn-danger-outline { background: var(--surface); color: var(--danger); border: 1.5px solid var(--danger); box-shadow: none; }
.btn-danger-outline:active { background: #FEF2F2; box-shadow: none; }
/* Disabled needs to read as "not yet", not as a faded button of unknown state -- opacity alone left
   the primary looking lilac and still inviting. Flat grey is unambiguous. */
.btn:disabled, .btn[disabled] {
  background: #E9E7EE; color: #9A94A6; box-shadow: none; border-color: transparent;
  opacity: 1; cursor: not-allowed; transform: none;
}
.btn-block { margin-top: var(--space-3); }
/* A small leading icon inside a .btn label (e.g. Profile's Terms/Privacy/Report/Instagram rows,
   owner: "Add INSTA symbol for easy recognition... also any other symbols for other buttons") --
   .btn is already display:inline-flex with a gap, so this only needs to size the icon itself;
   stroke/fill stay currentColor, so it already matches the button's own text color (white on a
   primary button, the app's dark text on a secondary one) with no extra color rule needed. */
.btn-ico { display: inline-flex; flex: 0 0 auto; }
.btn-ico svg { width: 18px; height: 18px; }
/* Call + WhatsApp side by side (owner: stacked full-width buttons looked heavy). Two equal halves; a long Telugu/
   Tamil label wraps inside its own half rather than pushing the other button off. */
.contact-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
.contact-actions .btn { flex: 1 1 0; min-width: 0; margin-top: 0; padding: 8px 6px; font-size: 15px; line-height: 1.2; text-align: center; text-decoration: none; box-sizing: border-box; overflow-wrap: anywhere; }

/* DEC-210: real elevation -- owner asked for a bolder look closer to Groww's actual product
   dashboard (portfolio/stat cards), not just the flatter marketing-site read DEC-207 went with.
   Two-layer shadow (tight-then-soft) is the real technique behind a "floating" card; border
   lightened to near-invisible since the shadow now carries the separation, not the border. */
/* DEC-367, owner: "make nice cool border line". The border here was rgba(17,24,39,0.04) -- 4%
   opacity, i.e. effectively invisible, so every card was defined by its shadow alone and read as a
   soft blur rather than a crisp panel. Switched to the app's own --border token, the same line
   already drawn by inputs and the .review-line hairlines, so cards now share one border language
   with everything else instead of having a near-invisible one of their own. Variants that set their
   own colour (.card-parcel, .card-highlight, .card-bike/car/auto) still override this as before. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--space-5);
  margin-bottom: var(--space-3);
  box-shadow: 0 1px 3px rgba(17, 24, 39, 0.06), 0 4px 12px rgba(17, 24, 39, 0.04);
}
/* Press feedback for the 31 real onclick cards (mode summaries, main-road options, driver-list
   entries...) -- every .btn already presses via transform:scale(0.98) on tap, but a whole tappable
   CARD gave zero response, silent right up until the screen actually changed. Scoped to [onclick]
   specifically, not .card itself, since plenty of cards (detail/review lists, static info) are NOT
   tappable and giving them a press animation would imply an action that doesn't exist -- worse than
   no motion at all. [onclick] needs no markup changes: every real instance already carries it
   inline, consistently, the same attribute a screen reader or `cursor:pointer` audit would find. */
.card[onclick] { transition: transform 0.1s ease; }
.card[onclick]:active { transform: scale(0.98); }
.card-title {
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 var(--space-1);
  overflow-wrap: break-word;
}

/* Bike vs Auto vs Car: distinct colors so villagers can tell them apart at a glance without
   reading -- same idea as color-coding a bus vs an auto stand back home. DEC-422 kept this signal
   as a full-bleed pale card fill + a 5px left accent stripe ("try different UI, light back ground
   color... instead of thick colors" -- a paler fill, not a different mechanism). Supersedes that:
   the card itself goes neutral white, and BOTH the color and the vehicle's shape now live in one
   place, the icon badge below -- a real silhouette is a stronger "which mode is this" signal than
   a tinted rectangle ever was, so nothing about the at-a-glance goal is being traded away, just
   moved from the whole card onto the one element built to carry it. */
.card-icon {
  width: 44px;
  height: 44px;
  border-radius: 13px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.card-icon svg { width: 28px; height: 21px; display: block; }
/* Owner caught a real bug the grid version of this introduced: measured an 18px gap between
   "2 Bikes nearby" and the fare line under it, vs 8px everywhere else on the same card. Cause --
   grid-row:1/-1 makes .card-icon (a fixed 44px) span every row of column 2's auto-height content;
   when the FIRST of those rows (the title, ~26px) is naturally shorter than 44px, the track-sizing
   algorithm inflates that first row to help satisfy the icon's height, even though the combined
   height of the LATER rows was already more than enough on its own. Tried grid-auto-rows:min-content
   first -- didn't help, confirmed live by measuring computed grid-template-rows before and after.
   Fixed by taking the icon out of grid/flow sizing entirely: position:absolute (relative to this
   own position:relative card, whose containing block for an absolute child is its padding box --
   same box a grid column 1 would have started from, so the icon lands in the identical visual
   spot), then reserving its width with plain padding-left on the card instead of a grid column.
   Every remaining child (title, route-line, field-row, freshness) is back to normal block flow --
   no grid, so no track to inflate -- stacked by their own existing margins exactly as .route-line/
   .field-row/.freshness already space themselves everywhere else in the app. Scoped to these three
   selectors specifically (not a blanket .card-icon rule) since the class is also used on ~10 other,
   unrelated cards (parcel, demand-hot, trip-history) that never had this grid and must not change. */
.card-bike, .card-auto, .card-car {
  background: var(--surface);
  border: 1px solid var(--border);
  position: relative;
  padding-left: calc(44px + var(--space-3) + var(--space-5));
}
.card-bike .card-icon, .card-auto .card-icon, .card-car .card-icon {
  /* top/left match var(--space-5) -- an absolutely positioned child's containing block is the
     padding EDGE (i.e. 0,0 sits flush against the border, ignoring the card's own padding, since
     padding only offsets normal-flow content). Needs the explicit --space-5 inset to land where
     the card's own 20px padding used to place grid column 1, not at the card's bare inner edge. */
  position: absolute;
  top: var(--space-5);
  left: var(--space-5);
}
/* Whisper border (rgba per-mode border-color on .card-bike/.card-auto/.card-car) removed. It
   earned its place when the badge was the only structural change on an otherwise plain white
   card and needed help reading as a distinct block. With .section-label now quiet/tracked and
   real space between sections (next change, same review), the card boundary and the badge
   together already do that job -- a colored border at that point answers a question nothing was
   asking anymore. Kept the plain var(--border) hairline from the shared rule above; nothing
   mode-specific about the border itself now, same as before the whisper was ever added. */
.card-bike .card-icon { background: var(--bike-container); color: var(--bike); }
.card-bike .card-title { color: var(--bike-dark); }
.card-auto .card-icon { background: var(--auto-container); color: var(--auto); }
.card-auto .card-title { color: var(--auto-dark); }
.card-car .card-icon { background: var(--car-container); color: var(--car); }
.card-car .card-title { color: var(--car-dark); }
/* Approved main-road access points (P-16): a real vehicle currently running near this stop reads
   as available (same green as a fresh/live badge elsewhere) vs a curated stop with nothing running
   there right now, kept visually muted so it never looks like a live option. */
.card-mainroad-available {
  background: #DCFCE7;
  border: 1px solid var(--success);
  border-left: 5px solid var(--success);
}
.card-mainroad-available .card-title { color: var(--success); }
.card-mainroad-unavailable {
  background: var(--surface);
  border: 1px solid var(--border);
  opacity: 0.7;
}
/* Send a Parcel (release-2.0): its own violet family so it reads as a distinct kind of action, not
   a fourth vehicle type competing with Bike/Auto/Car's green/amber/blue. */
.card-parcel {
  background: #EDE9FE;
  border: 1px solid #7C3AED;
  border-left: 5px solid #7C3AED;
}
.card-parcel .card-title { color: #5B21B6; }
/* Someone on the other side of the trip is blocked waiting on this passenger's answer (DEC-251) --
   owner: "Driver can not wait for approve. These things should happen quickly." A steady card reads
   as just more content, so this one breathes to pull the eye, using the same violet as .card-parcel
   (this only ever wraps a parcel decision) rather than introducing another color. Deliberately a
   slow, low-contrast pulse on the border/glow only -- never the text, which must stay readable for
   someone reading slowly, and never a flash rate that could bother a light-sensitive reader. */
.card-urgent {
  background: #EDE9FE;
  border: 2px solid #7C3AED;
  animation: urgentPulse 2s ease-in-out infinite;
  padding: var(--space-3);
}
.card-urgent .card-title { color: #5B21B6; font-size: 16px; line-height: 1.3; }
/* These two share one job -- announce a status change, offer 1-2 short actions -- across driver and
   passenger alike, so their buttons get one compact treatment here rather than repeating inline
   styles at every call site (renderPendingCounterAlerts, counterOutcomeCards, renderParcelStatusAlerts).
   Owner, on seeing "View in Parcels" wrap to two lines: "reduce the Size of the button nicer look
   (UI). like one line Statement/max two lines." */
.card-urgent .btn, .card-good .btn {
  min-height: 40px;
  font-size: 14px;
  padding: 8px 10px;
}
@keyframes urgentPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(124, 58, 237, 0.45); }
  50% { box-shadow: 0 0 0 8px rgba(124, 58, 237, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .card-urgent { animation: none; box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.35); }
  .screen.view-enter { animation: none; }
}
/* Good-news counterpart (DEC-251): a driver's proposed price was accepted. Green reads as settled
   and needs no pulse -- there is nothing left for them to decide, only to know. */
.card-good {
  background: #ECFDF5;
  border: 2px solid #059669;
  padding: var(--space-3);
}
.card-good .card-title { color: #065F46; font-size: 16px; line-height: 1.3; }
/* Highest-demand card on Driver Home (DEC-146): a real, actionable "there's income near you" signal
   deserves the same distinct-color treatment as Bike/Auto/Car/Parcel, not a plain white card sitting
   flat among status tiles — owner: "whichever the demand is available that particular element should
   have better visibility." Its own warm orange family (unused by any other card) reads as "hot
   opportunity," never confusable with a booking type. Only applied when real demand exists — an
   empty/zero state stays plain, so the color keeps meaning "something to act on," not decoration. */
.card-demand-hot {
  background: #FFEDD5;
  border: 1px solid #EA580C;
  border-left: 5px solid #EA580C;
}
.card-demand-hot .card-title { color: #9A3412; }
.icon-badge {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  line-height: 1;
  margin: 0 auto var(--space-2);
  background: rgba(255, 255, 255, 0.65);
}
.size-pick {
  flex: 1;
  text-align: center;
  cursor: pointer;
  border-width: 2px;
  border-color: transparent;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.size-pick.selected {
  border-color: #7C3AED;
  background: #EDE9FE;
}
.size-pick .icon-badge { background: rgba(124, 58, 237, 0.08); }
/* .required-mark (red "*") removed: the parcel form already spells out "(optional)" on the fields
   that are optional, so everything else being required is implied -- marking it twice, once in
   words and once in a symbol, said the same thing in two vocabularies. The asterisk was also the
   weaker half: it is a desktop-form convention that carries no meaning for a first-smartphone user,
   while validation already highlights any missing field in red at the moment it matters. */
.route-line {
  font-size: 14px;
  color: var(--text-secondary);
  margin: 0 0 var(--space-2);
}

/* Owner: "its Difficult to identify the difference main Subject versus just info (hint) for user.
   Always hint should be small letter." Correct -- .subtitle, .route-line and .section-label were all
   14px in the same secondary grey, so an explanatory aside looked exactly like real trip content and
   competed with it. `.hint` is the third tier: visibly smaller and lighter, for lines the driver can
   skip without missing anything. Headings stay 14px/600, real content stays 14px, hints are 12px.
   Not for errors -- those must keep their weight and their danger colour.
   Follow-up, owner again (this session, on the Home "Trip published" card): route-line at 14px and
   hint at 12px still read as "almost same level of size" next to each other in practice -- a 2px gap
   is not enough separation once real content (route-line) sits directly above an instruction (hint)
   in the same card, rather than in different cards where the size difference is judged in isolation.
   Pushed hint one step further (11px, more opacity) so the tiers are unambiguous side by side; the
   route-line side of this same gap is widened per-card where a route is genuinely that card's
   headline (see .card-highlight .route-line below) rather than by changing this shared class, which
   plenty of other screens still use as a plain secondary caption below a real .card-title. */
.hint {
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-secondary);
  opacity: 0.65;
  margin: 2px 0 0;
}
.field-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: 15px;
  padding: var(--space-1) 0;
  /* Seventh instance of the same flex bug, surfaced by Malayalam: min-width:0 lets TEXT shrink, but
     a value containing the seats stepper is fixed-width buttons that cannot shrink at all, so a
     longer label ("ബാക്കിയുള്ള സീറ്റുകൾ") pushed the row 8px past its card on four driver screens.
     Wrapping only engages when the row genuinely does not fit, so every language that already fitted
     on one line still does. */
  flex-wrap: wrap;
}
/* Sixth instance of today's flex/min-width bug -- .field-row is the shared label/value pattern used
   across both apps for things like "Seats" / "Fare", and a longer Tamil label pushed the page wider
   the same way. min-width:0 lets long text wrap instead. */
.field-row .k { color: var(--text-secondary); min-width: 0; }
/* A phone number ("+919951035405") is one unbreakable run of digits -- no space for min-width:0's
   wrapping to use, so it just kept its full width and overflowed. overflow-wrap allows a break
   between digits as a last resort, only ever used when the number genuinely doesn't fit. */
.field-row .v { font-weight: 600; min-width: 0; overflow-wrap: break-word; text-align: right; }
/* Owner: on the Bike result tile, "Closest pickup" was bolded exactly as heavily as the fare above
   it -- "Only Price should be important." Scoped to .field-row.quiet rather than changing .field-row
   .v itself, which is the shared bold-value convention every OTHER field-row in both apps relies on
   (Seats, Departure, Drop location, Expires in...) and stays untouched. Applied only to the three
   pickup-TIME rows (an estimate in minutes) -- not the several other `t("pickup")` rows that show a
   pickup LOCATION (a place name), which aren't competing with price for attention the same way. */
.field-row.quiet .v { font-weight: 400; color: var(--text-secondary); }

.driver-strip {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-2) 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}
.driver-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary-container);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
}
.driver-name { font-size: 16px; font-weight: 600; }
.driver-vehicle { font-size: 13px; color: var(--text-secondary); }

.contact-strip {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-1) 0;
  padding: 6px var(--space-2);
  background: var(--primary-container);
  border-radius: var(--radius-input);
}
.contact-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 700;
  flex-shrink: 0;
}
.contact-role { font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.02em; }
.contact-name { font-size: 15px; font-weight: 700; }
.contact-phone { font-size: 14px; font-weight: 600; color: var(--primary); text-decoration: none; }

/* "How to use RMN" 3-step guide (DEC-300) -- shown at the bottom of both apps' Home. Steps carry a
   real done/current/upcoming state, so this doubles as "what do I do next?" rather than being a
   static block of marketing text. */
.hiw {
  margin-top: var(--space-5);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--space-4);
}
.hiw-head { display: flex; align-items: center; gap: var(--space-2); }
/* Fifth instance of today's flex/min-width bug, this time in the shared onboarding box (DEC-300),
   used by both apps -- .hiw-title is flex:1 with no min-width:0, so its default min-width (its own
   unwrapped text) pushed the whole card, and the page, wider in Tamil. */
/* min-width:0 alone lets this wrap across lines but does not help a single WORD that is itself too
   wide for the column -- Tamil/Kannada compound words in the title ("பயன்படுத்துவது") have no internal
   space to break at, so at a narrow column (icon + toggle button both take their own space first)
   that one word could still push the box wider. overflow-wrap lets it break mid-word as a last resort,
   the same class of gap as the phone number below, just for prose instead of digits. */
.hiw-title { flex: 1; min-width: 0; overflow-wrap: break-word; margin: 0; font-size: 15px; font-weight: 700; color: var(--text-primary); }
.hiw-toggle {
  background: none;
  border: none;
  padding: 6px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--primary-dark);
  cursor: pointer;
}
/* DEC-300b: passenger guide shows Ride and Parcel steps together, each under its own heading. */
.hiw-group-heading {
  margin: var(--space-4) 0 var(--space-2);
  font-size: 13px;
  font-weight: 700;
  color: var(--primary-dark);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.hiw-steps:first-of-type { margin-top: var(--space-3); }
.hiw-group-heading:first-child { margin-top: var(--space-3); }
.hiw-steps { display: flex; flex-direction: column; gap: var(--space-3); }
.hiw-step { position: relative; display: flex; gap: var(--space-3); align-items: flex-start; }
.hiw-step > div { min-width: 0; }
/* Connector line between the numbered markers, so the three read as one sequence. */
.hiw-step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 15px;
  top: 36px;
  bottom: calc(-1 * var(--space-3));
  width: 2px;
  background: var(--border);
}
.hiw-step.done:not(:last-child)::before { background: var(--success); opacity: 0.4; }
.hiw-num {
  z-index: 1;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  background: var(--surface);
  border: 2px solid var(--border);
  color: var(--text-tertiary);
}
.hiw-step.done .hiw-num { background: var(--success); border-color: var(--success); color: #fff; }
.hiw-step.current .hiw-num { background: var(--primary); border-color: var(--primary); color: #fff; }
.hiw-step-title { margin: 4px 0 2px; font-size: 15px; font-weight: 600; color: var(--text-primary); overflow-wrap: break-word; }
.hiw-step.upcoming .hiw-step-title { color: var(--text-secondary); }
.hiw-step-body { margin: 0; font-size: 13px; line-height: 1.45; color: var(--text-secondary); overflow-wrap: break-word; }
/* Sits on its OWN line under the step title, not inline after it. It used to be appended inside
   the title paragraph with margin-left, which broke two ways: on a long step title the pill got
   orphaned onto a line by itself and read as a floating stray element, and because it was inside
   the same <p> with no separating space the title's text content ran together ("...to acceptYou
   are here") for screen readers. Own-line is also the only placement that stays predictable across
   all five languages -- the Tamil label is more than twice the width of the English one, so an
   inline pill would wrap in some languages no matter how the title is worded. */
.hiw-here {
  display: inline-block;
  margin: 2px 0 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: var(--primary-container);
  color: var(--primary-dark);
}

.freshness {
  font-size: 13px;
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-2);
}
.freshness .fdot { width: 8px; height: 8px; border-radius: 50%; background: var(--success); }
.freshness.older .fdot { background: var(--warning); }
.freshness.stale .fdot { background: var(--danger); }
.freshness.older { color: var(--warning); }
.freshness.stale { color: var(--danger); }

.badge {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
}
.badge-info { background: var(--primary-container); color: var(--primary-dark); }
.badge-warning { background: var(--accent-container); color: var(--warning); }
.badge-success { background: #DCFCE7; color: var(--success); }
.badge-danger { background: #FEE2E2; color: var(--danger); }
/* Owner reviewed a mockup of a real worst case -- a provisional driver in a commercial taxi,
   already vouched for -- showing all three badges plus the mode-colored title stacked on one
   card: four competing hues. Picked "keep the safety-relevant one colored, neutralize the rest"
   over changing anything shared: .badge-warning (provisional/new-driver, a real trust signal
   worth noticing) and .badge-success (Verified, the common good-standing state) are untouched.
   This promotes an inline style renderCarCard already used for the private-vehicle badge
   (background:var(--border);color:var(--text-secondary)) to a real class, since it's now used
   in three places instead of being worth repeating inline each time. */
.badge-neutral { background: var(--border); color: var(--text-secondary); }

.disclaimer {
  font-size: 13px;
  color: var(--text-secondary);
  background: var(--accent-container);
  border-radius: var(--radius-input);
  padding: var(--space-3);
  margin: var(--space-2) 0;
}

.banner {
  border-radius: var(--radius-input);
  padding: var(--space-3);
  font-size: 14px;
  margin-bottom: var(--space-3);
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}
.banner-offline { background: #F1F5F9; color: var(--text-secondary); border: 1px solid var(--border); }
.banner-stale { background: #FEF3C7; color: var(--warning); border: 1px solid #FDE68A; }
.banner-error { background: #FEE2E2; color: var(--danger); border: 1px solid #FECACA; }
.banner-unauth { background: #F1F5F9; color: var(--text-secondary); border: 1px solid var(--border); }

.tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.tab {
  flex: 1;
  text-align: center;
  padding: var(--space-3);
  border-radius: var(--radius-input);
  border: 1px solid var(--border);
  background: var(--surface);
  font-weight: 600;
  cursor: pointer;
  font-size: 15px;
}
.tab.active {
  background: var(--primary-container);
  border-color: var(--primary);
  color: var(--primary-dark);
}

.empty-state, .error-state {
  text-align: center;
  padding: var(--space-8) var(--space-4);
  color: var(--text-secondary);
}
.empty-state .icon, .error-state .icon { font-size: 40px; margin-bottom: var(--space-2); }

.skeleton {
  background: linear-gradient(90deg, #e5e7eb 25%, #f3f4f6 37%, #e5e7eb 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
  border-radius: var(--radius-input);
}
@keyframes shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
.skeleton-card { height: 92px; margin-bottom: var(--space-3); }

/* Place picker list */
.search-input {
  width: 100%;
  min-height: 52px;
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  padding: 0 var(--space-4);
  font-size: 16px;
  margin-bottom: var(--space-4);
}
.place-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.place-row:last-child { border-bottom: none; }
.place-row .name { font-size: 16px; font-weight: 600; }
.place-row .hierarchy { font-size: 13px; color: var(--text-secondary); }

/* Map placeholder */
.map-box {
  height: 220px;
  border-radius: var(--radius-card);
  background: repeating-linear-gradient(45deg, #CCFBF1, #CCFBF1 10px, #E6FFFB 10px, #E6FFFB 20px);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--primary-dark);
  font-weight: 600;
  margin-bottom: var(--space-3);
  text-align: center;
  padding: var(--space-4);
}

/* Bottom nav */
/* Real bug found live: "Footer buttons are not visible in App. its very much down." bottom:0 on an
   absolutely-positioned child sits at the containing block's PADDING edge, not its content edge --
   so this ignored .phone's own padding-bottom:env(safe-area-inset-bottom) entirely and sat at the
   true outer edge instead, pushing the nav down into (or behind) a real device's system gesture bar
   on any phone that reserves one. env() here (not .phone's padding) is what actually keeps it clear. */
.bottom-nav {
  position: absolute;
  bottom: env(safe-area-inset-bottom, 0px);
  left: 0;
  right: 0;
  background: var(--surface);
  box-shadow: 0 -1px 4px rgba(17, 24, 39, 0.06);
  display: flex;
}
.bottom-nav button {
  flex: 1;
  border: none;
  background: none;
  padding: var(--space-2) 0 var(--space-3);
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.bottom-nav button.active { color: var(--primary); font-weight: 600; }
.bottom-nav .icon { display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; padding: 4px 16px; transition: background-color 0.15s ease; }
.bottom-nav .icon svg { width: 22px; height: 22px; }
/* DEC-210: filled pill behind just the icon on the active tab -- same pattern Uber/Ola/Groww all
   use for bottom nav, reads as more confident than color-only. Scoped to .icon, not the whole
   flex:1 button, so it's a compact pill rather than a full-width colored strip. */
.bottom-nav button.active .icon { background: var(--primary-container); }

/* Dev / QA control panel (not part of the product UI) */
.devpanel {
  width: 300px;
  background: #1f2937;
  color: #e5e7eb;
  border-radius: 16px;
  padding: var(--space-4);
  font-size: 13px;
}
.devpanel h3 {
  margin: 0 0 var(--space-2);
  font-size: 14px;
  color: #fff;
}
.devpanel p { color: #9ca3af; margin: 0 0 var(--space-4); }
.devpanel .group { margin-bottom: var(--space-4); }
.devpanel label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-2);
  color: #d1d5db;
}
.devpanel select, .devpanel button.devbtn {
  width: 100%;
  padding: var(--space-2);
  border-radius: 8px;
  border: 1px solid #374151;
  background: #111827;
  color: #e5e7eb;
  margin-bottom: var(--space-2);
  font-size: 13px;
}
.devpanel .note {
  font-size: 11px;
  color: #6b7280;
  border-top: 1px solid #374151;
  padding-top: var(--space-3);
  margin-top: var(--space-2);
}

/* Owner: Passenger Home should fit one screen without scrolling -- keep the original card look
   (full-width, same colors/border) for the Repeat-last-ride/favourite chip and the From/To fields,
   just reduce their size. Scoped to .home-compact (wraps only those 3 elements on Home, see
   renderP03) so every other screen reusing .route-chip/.place-field keeps its normal size. */
.home-compact .route-chip { padding: 8px var(--space-3); min-height: 40px; margin-bottom: var(--space-2); }
.home-compact .route-chip-icon { font-size: 15px; }
.home-compact .route-chip-text { font-size: 14px; }
.home-compact .place-field { padding: 10px var(--space-3); min-height: 44px; margin-bottom: var(--space-2); }
.home-compact .place-field .label { font-size: 11px; }
.home-compact .place-field .value { font-size: 15px; }
.home-compact .mic-inline { width: 32px; height: 32px; font-size: 14px; }

/* In-app update prompt (DEC-328). Sits above everything including the bottom nav (z-index 60 vs the
   nav's own stacking) because it must be answerable from any screen in either app. Centred rather
   than a bottom sheet so it cannot be mistaken for the nav bar it covers. */
.update-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(15, 23, 42, 0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.update-card {
  /* DEC-526. Was using an undefined "radius-lg" token, so the card
     rendered with sharp square corners against an app that rounds every other card/button the same
     20px. Two-layer shadow (tight + soft) matches the "floating" treatment DEC-210 already set for
     real elevated cards elsewhere, instead of this dialog's own flatter one-layer shadow. */
  background: var(--surface); border-radius: var(--radius-card);
  padding: 28px 22px 22px; width: 100%; max-width: 340px;
  box-shadow: 0 2px 6px rgba(17, 24, 39, 0.08), 0 20px 44px -12px rgba(17, 24, 39, 0.28);
  text-align: center;
}
.update-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--primary-container); color: var(--primary-dark);
  margin-bottom: 14px;
}
.update-icon svg { width: 27px; height: 27px; }
.update-title { font-size: 19px; font-weight: 700; color: var(--text-primary); margin: 0 0 8px; text-wrap: balance; }
.update-version {
  display: inline-block; font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
  color: var(--primary-dark); background: var(--primary-container);
  padding: 3px 11px; border-radius: 999px; margin: 0 0 12px;
}
.update-body { font-size: 14px; color: var(--text-secondary); margin: 0 0 18px; line-height: 1.5; }

/* Pre-publish review rows (DEC-340). One grouped card of iconed lines rather than a stack of
   separate boxes -- the icon gives each value something to anchor on when scanning, and the hairline
   between rows does the separating that a box per row would do far more heavily. Icons sit in the
   same soft circle the mic and stepper buttons already use, so this reads as PakaPaka rather than as a
   borrowed pattern. */
.review-line { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--border); }
.review-line:last-child { border-bottom: none; }
.review-ico {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--accent-container);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; flex-shrink: 0;
  /* Emoji carried their own color regardless of CSS; the drawn stroke="currentColor" icons that
     replaced them (DEC-453 follow-up) need an explicit one against --accent-container's warm
     cream, so this is the first time .review-ico has ever needed a `color` at all. --gold-dark is
     the same warm-accent foreground the purple+gold rebrand (DEC-223) already pairs with amber
     backgrounds elsewhere. */
  color: var(--gold-dark);
}
.review-k { color: var(--text-secondary); font-size: 14px; flex: 1; min-width: 0; }
.review-v { font-weight: 700; font-size: 15px; text-align: right; overflow-wrap: anywhere; }

/* Editable price inside a review line (DEC-342). Sized to the four digits a fare ever needs, so the
   place name keeps the room instead; right-aligned because the eye compares these down a column. */
.stop-price-input {
  width: 62px; padding: 5px 8px;
  font-size: 15px; font-weight: 700; text-align: right;
  border: 1px solid var(--border); border-radius: var(--radius-input);
  background: var(--surface); color: var(--text-primary);
}
.stop-price-input:focus { outline: none; border-color: var(--primary); border-width: 2px; padding: 4px 7px; }

/* Delivery-code entry (DEC-347). A short code is not a sentence: centred, wide-tracked and large, so
   a driver typing what someone reads aloud can check it back at a glance before committing. */
.code-input {
  display: block; width: 100%; max-width: 200px; margin: 0 auto;
  padding: 12px 8px;
  font-size: 26px; font-weight: 700; letter-spacing: 0.32em; text-indent: 0.32em;
  text-align: center;
  border: 1.5px solid var(--border); border-radius: var(--radius-input);
  background: var(--surface); color: var(--text-primary);
}
.code-input::placeholder { color: #C9C5D2; font-weight: 600; }
.code-input:focus { outline: none; border-color: var(--primary); border-width: 2px; padding: 11.5px 7.5px; }

/* A destructive action that should stay available without competing with the primary one. */
.btn-textlink {
  display: block; width: 100%; margin-top: var(--space-3);
  background: none; border: none; cursor: pointer;
  color: var(--danger); font-size: 15px; font-weight: 600;
  padding: 10px; border-radius: var(--radius-button);
}
.btn-textlink:active { background: #FEF2F2; }
.btn-textlink:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }

/* Trip-list route timeline (DEC-349). Reference: GoVia's My Trips card uses a green/red dot pair
   joined by a line to show From->To without repeating the word "From"/"To" on every row -- adapted
   here rather than copied: PakaPaka's own place-field already colors From purple and To red (see
   .place-field .dot above), so this reuses THAT pairing instead of GoVia's green/red, keeping one
   consistent meaning for "purple dot = start" across the whole app rather than two conventions. */
.route-dots { display: flex; flex-direction: column; align-items: center; padding-top: 3px; }
.route-dots .rd-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.route-dots .rd-dot.from { background: var(--primary); }
.route-dots .rd-dot.to { background: var(--danger); }
.route-dots .rd-line { width: 1.5px; flex: 1; min-height: 14px; background: var(--border); margin: 3px 0; }
.trip-card-route { display: flex; gap: 10px; }
.trip-card-route .stops { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; gap: 6px; }
.trip-card-route .stop-name { font-weight: 700; font-size: 15px; line-height: 1.25; overflow-wrap: anywhere; }

/* Quick-action row on a trip card -- reference: GoVia's Riders/Parcels/Requests pill row. Reuses
   .btn-secondary at a smaller height rather than a new pill style, so it stays visually part of
   this app's existing button language instead of introducing a second button shape. */
.trip-card-actions { display: flex; gap: 8px; margin-top: var(--space-2); }
.trip-card-actions .btn { min-height: 38px; font-size: 13px; padding: 0 8px; }

/* Home's empty-state icon (DEC-350). Reference: Hopr's "Allow location access" screen leads with a
   large icon set inside its own soft coloured backdrop, not a bare emoji floating in whitespace --
   that backdrop is what makes a plain glyph read as designed rather than placeholder. Reuses the
   accent tone already established elsewhere (.review-ico, badge-warning) rather than introducing a
   new colour, so this reads as the same app, not a borrowed screen bolted on. */
.empty-icon-badge {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--accent-container);
  display: flex; align-items: center; justify-content: center;
  font-size: 32px; margin: 0 auto var(--space-2);
}
/* vehicleIcon()'s SVGs carry no intrinsic size (same note as the route-chip icon above) -- sized
   here for the noTripCard() vehicle badges that drop one straight into this circle. */
.empty-icon-badge svg { width: 40px; height: 30px; }

/* Framed accent card (DEC-352). Owner, on the review screen's route card: "put some nice colred
   line surrounded look for Govia and Hope reference" -- both references frame their headline fact
   (GoVia's route+date, Hopr's step card) with a visible border rather than letting it sit as a
   plain white box indistinguishable from the cards below it. Reuses the exact violet .card-parcel
   already established in this app (border + thicker left accent + tinted fill) under a generic
   name, since a route summary being violet-framed has nothing to do with parcels -- same look,
   correct name for where it is used. */
.card-highlight {
  background: #EDE9FE;
  border: 1px solid #7C3AED;
  border-left: 5px solid #7C3AED;
}
.card-highlight .card-title { color: #5B21B6; }

/* An empty result card ("No Bike drivers on this route right now") has no .card-title at all, so
   its .route-line IS the card's headline -- but it was inheriting the shared secondary-caption grey
   meant for a line sitting UNDER a real title. The result was the only sentence on the card being
   the faintest thing on it, with the .hint beneath it fainter still: a whole tier of hierarchy
   below where it belonged. Follows the same per-card approach as .card-highlight .route-line above
   rather than touching the shared class, which other screens still use as a true secondary line. */
.card-empty .route-line { color: var(--text-primary); font-weight: 600; }

/* Save-route pill (DEC-354). Was borrowing .speak-all-btn, which is genuinely four read-aloud
   buttons elsewhere -- restyling that class to fix this one would have changed all of them, so this
   gets its own. Owner: "make it better visible / reduce this save this route": nowrap + no shrink so
   it can never wrap to two lines when the route name beside it is long (the actual cause of it
   looking cramped), and a heavier border with the full-strength primary for contrast, since the
   previous 1px on a pale cream fill barely separated it from the page. */
.save-route-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1.5px solid var(--primary);
  background: var(--primary-container);
  color: var(--primary);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  margin-left: var(--space-2);
}
.save-route-btn:active { background: var(--primary); color: #fff; }


/* Day-of-week chips for a regular trip (DEC-376). Reference: GoVia's own filter chips (All/Rides/
   Parcel) and Raahi One's (All/Action Needed/Driving) -- a selected chip goes solid dark, an
   unselected one stays a light outline, which reads instantly at arm's length in sunlight and needs
   no legend. Sized so all seven fit one row on a 360px screen without wrapping or shrinking below
   the 44px touch minimum in height. */
.day-chip-row { display: flex; gap: 6px; margin: var(--space-2) 0 var(--space-3); }
.day-chip {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  padding: 0 2px;
  border-radius: var(--radius-input);
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text-primary);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.day-chip.on { background: var(--text-primary); border-color: var(--text-primary); color: var(--surface); }
/* Preset row sits above the day chips: the two patterns nearly every rural driver actually wants,
   so the common case is one tap rather than five.
   Real bug found live testing the Tamil language pass (this session): three flex:0 0 auto buttons
   with no wrap wanted more width than the phone screen has once labels are "இன்று மட்டும்" /
   "திங்–வெள்" / "தினமும்" instead of English's shorter "Just today" / "Mon–Fri" / "Every day" -- the
   third button was clipped off the right edge with no way to reach it. Same flex/min-width family of
   bug already fixed on .field-row (see its own comments) for the identical reason surfaced by
   Malayalam/Tamil labels; wrapping only engages when a language's labels genuinely don't fit one row,
   so English/Telugu/Kannada, which already fit, render identically to before. */
.day-preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--space-2); }
.day-preset {
  flex: 0 0 auto; min-height: 34px; padding: 0 14px;
  border-radius: 999px; border: 1.5px solid var(--border);
  background: var(--surface); color: var(--text-primary);
  font-size: 13px; font-weight: 600; cursor: pointer;
}

/* Regular-trip card (DEC-377). The first cut put a full-width .btn next to a "Pause" button, and
   since .btn is width:100% the delete control stretched into a huge bar with a tiny x floating in
   it. Actions now sit in a flex row where only the icon button is fixed-width, which is also the
   shape GoVia's own My Trips card uses (a text action beside compact icon actions). */
.card-actions { display: flex; gap: 8px; margin-top: var(--space-3); }
.card-actions .btn { margin-top: 0; flex: 1 1 auto; }
.card-actions .btn-icon {
  flex: 0 0 46px;
  width: 46px;
  padding: 0;
  font-size: 17px;
}
/* Facts as chips rather than three label/value rows: at a glance a driver wants days, time and
   seats, and stacked field-rows made a card of three near-identical lines. Reference: the compact
   BIKE / 1 seats / 40 Kg chips on GoVia's ride cards. */
.meta-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--space-2) 0 0; }
.meta-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--surface-sunken);
  color: var(--text-secondary);
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
}
.recurring-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.recurring-badge { flex: 0 0 auto; }
/* Same per-place flex tracks as DEC-370: two rural names plus an arrow overflow constantly, and
   truncating the whole string as one unit would drop the destination. */
.recurring-route { display: flex; align-items: baseline; gap: 5px; flex: 1; min-width: 0; margin: 0; }
.rr-place { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rr-arrow { flex: 0 0 auto; }
.recurring-return { margin: 6px 0 0; font-size: 13px; color: var(--text-secondary); }
/* Paused reads as inactive without hiding anything -- the card is still fully legible. */
.recurring-paused { opacity: 0.72; }
/* Selected preset (DEC-377). Same solid-dark convention as .day-chip.on, so "Mon-Fri" chosen as a
   preset and Mon-Fri lit up in the day row read as the same state, not two different ones. */
.day-preset.on { background: var(--text-primary); border-color: var(--text-primary); color: var(--surface); }

/* Toast + in-app confirm (DEC-378). Appended directly to .phone (or body) rather than going through
   the string-template render() cycle -- a toast must survive whatever the next render does, and a
   confirm overlay must exist independently of the screen underneath it. */
.app-toast {
  position: absolute;
  left: 50%;
  bottom: 96px;
  transform: translate(-50%, 12px);
  max-width: calc(100% - 48px);
  background: var(--text-primary);
  color: var(--surface);
  padding: 12px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  box-shadow: 0 8px 24px rgba(0,0,0,0.22);
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 60;
  pointer-events: none;
}
.app-toast.show { opacity: 1; transform: translate(-50%, 0); }
.app-toast-error { background: var(--danger); }

.confirm-overlay {
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
  z-index: 70;
}
.confirm-card {
  background: var(--surface);
  border-radius: var(--radius-card);
  padding: var(--space-5);
  width: 100%;
  max-width: 320px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.25);
}
.confirm-msg { margin: 0 0 var(--space-4); font-size: 15px; line-height: 1.4; color: var(--text-primary); }
.confirm-actions { display: flex; gap: 10px; }
.confirm-actions .btn { flex: 1; margin-top: 0; }
/* A solid destructive action, distinct from .btn-danger-outline's low-emphasis inline use --
   this button IS the decision the driver is making, so it carries full weight. */
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:active { filter: brightness(0.92); }

/* DEC-385. Owner, seeing Resume/Manage trip/Publish new trip all rendered as identical outline
   pills: "These are plain, you shoud differentiate some how in UI. Refer GoVia butons differentiate
   between buttons" -- then, on the whole screen at once: "Entire page plan, user dont know which is
   what to differentiage." Three visually distinct categories now exist, matching what a driver is
   actually choosing between rather than three lookalike buttons:
     - .btn-primary (solid, existing)   = the one thing worth doing right now (e.g. Resume when
       paused). Used CONDITIONALLY, not fixed to one button -- which action is "primary" depends on
       state (see noTripCard()).
     - .btn-secondary (outline, existing) = navigate/inspect (Manage trip, Pause) -- lower stakes,
       always available, never the one thing screaming for attention.
     - .btn-add-dashed (new, below) = create something NEW, a different category of action entirely
       from managing what already exists. GoVia's own reference draws exactly this distinction: a
       dashed "+ Create new ride" box sits visually apart from its solid ride-row cards above it,
       never rendered as just another pill in the same row. */
.btn-add-dashed {
  background: transparent;
  color: var(--primary);
  border: 1.5px dashed var(--primary);
  box-shadow: none;
}
.btn-add-dashed:active { background: var(--primary-container); }

/* DEC-389. Owner: "what you used is light Green is not visible at all" -- .badge-success is pale
   mint text-on-mint (#DCFCE7 on --success #166534), fine for a small inline confirmation but too
   low-contrast for a status flag meant to be read at a glance. Solid fill, white text, sized up --
   "Make it bigger, choose another good bold Green color refer go Via green" -- matching GoVia's own
   vivid, saturated green branding rather than a pastel. Scoped to its own class rather than
   redefining .badge-success everywhere, so other, already-fine uses of that pale badge elsewhere in
   the app (e.g. "Verified") are untouched. */
.badge-running {
  background: #16A34A;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: 999px;
}

/* DEC-389. Owner: "Pause (Light Orange/light yellow..ect)" -- Pause was plain .btn-secondary,
   identical to every neutral navigate action beside it, with no hint that tapping it changes
   something. Reuses the exact light-amber pairing already established for badge-warning
   (--accent-container/--warning) rather than inventing a new color -- a caution tone, deliberately
   softer than .btn-danger's red, since pausing is reversible and not the risky action delete is. */
.btn-caution { background: var(--accent-container); color: var(--warning); box-shadow: none; }
.btn-caution:active { filter: brightness(0.96); }

/* DEC-390. Owner, on GoVia's own results list: "See highlated Rectangle/Square box how they
   differentiated nicel look in UI ... These color code learnings for both Passenger adn Driver
   app." Their departure time and price are bold and colored -- the two facts a rider actually
   scans a results list FOR -- while everything else stays plain label/value text. Reuses this
   app's own --primary accent (not a new color) so a scanned time/price reads as "the important
   number on this card" using the same emphasis language the rest of the app already speaks,
   applied wherever a results-list card shows a time or a fare. */
.fact-emphasis { color: var(--primary); font-weight: 700; }

/* DEC-397. Owner: "If its Running then border Green, If its Pasuesed the Oragneg border something
   like UI may be better thinking." A third, complementary signal alongside the existing corner
   badge and headline color -- the badge stays the sharp small "look here" flag (red when paused,
   per the owner's own earlier explicit choice), while this is the calmer ambient frame around the
   WHOLE card, the first thing the eye catches scanning the screen before reading any text. Orange
   reuses --warning (the same amber family already established for the Pause button, .btn-caution)
   rather than a new color, so border and button read as one coordinated "paused" language. */
.card-state-running { border: 2px solid #16A34A; }
.card-state-paused { border: 2px solid var(--warning); }

/* DEC-397. Owner, on the same card: "Type Upper case R" -- badge text was lowercase-styled by
   inheritance in one place; forced capitalization so "Running"/"Paused" always render capitalized
   regardless of what case the underlying string happens to be. */
.badge-running, .badge-corner { text-transform: capitalize; }

/* DEC-397. Bigger, corner-positioned sizing for a status badge -- separate from color so existing
   badge-warning/badge-success/badge-danger uses elsewhere (many, and much smaller-context) are
   never resized. Combine with a color class, e.g. class="badge badge-warning badge-corner". */
.badge-corner { font-size: 13px; padding: 5px 14px; position: absolute; top: 14px; right: 14px; }


/* How-it-works row (shared markup) */
.hiw-bulb { width: 32px; height: 32px; border-radius: 10px; background: var(--accent-container); color: var(--warning); display: grid; place-items: center; flex: 0 0 auto; }
.hiw-bulb svg { width: 18px; height: 18px; }
.hiw-headtext { flex: 1; min-width: 0; }
.hiw-step-note { display: block; font-size: 12.5px; color: var(--text-secondary); margin-top: 1px; }

/* ---------- Language pill + card (shared; large, native-script, tick + colour) ---------- */
.lang-row { display: flex; justify-content: flex-end; margin-bottom: var(--space-2); }
.lang-pill { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; min-height: 44px; padding: 0 14px 0 10px; font: inherit; font-size: 16px; font-weight: 600; color: var(--primary-dark); background: #EDE9FE; border: 1.5px solid #7C3AED; border-radius: 999px; cursor: pointer; transition: transform 0.1s ease; }
.lang-pill:active { transform: scale(0.96); }
.lang-pill:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.lang-pill-ic { display: inline-grid; place-items: center; width: 30px; height: 30px; border-radius: 9px; background: #EDE9FE; color: var(--primary); flex: 0 0 auto; }
.lang-pill .lang-pill-ic { width: 26px; height: 26px; background: transparent; }
.lang-pill-ic svg { width: 18px; height: 18px; }
.lang-card { background: var(--surface); border: 1px solid var(--border); border-radius: 20px; padding: var(--space-4); margin-bottom: var(--space-4); box-shadow: 0 1px 3px rgba(17, 24, 39, 0.06), 0 4px 12px rgba(17, 24, 39, 0.04); }
.lang-head { display: flex; align-items: center; gap: 8px; margin-bottom: var(--space-3); }
.lang-head b { font-size: clamp(11px, 3.3vw, 13px); font-weight: 600; line-height: 1.35; color: var(--text-primary); min-width: 0; white-space: nowrap; }
.lang-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.lang-btn { display: flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 6px; font: inherit; font-size: 16px; font-weight: 600; color: var(--text-primary); background: var(--surface); border: 1.5px solid #DCD9E3; border-radius: 16px; cursor: pointer; transition: transform 0.1s ease; }
.lang-btn:active { transform: scale(0.97); }
.lang-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.lang-btn.on { background: #EDE9FE; border: 2px solid #7C3AED; color: var(--primary-dark); }
.lang-tick { display: inline-flex; flex: 0 0 auto; width: 18px; height: 18px; padding: 3px; border-radius: 50%; background: var(--primary); color: #fff; }
.lang-tick svg { width: 100%; height: 100%; }

.lang-chev { display: inline-flex; width: 16px; height: 16px; transition: transform 0.15s ease; }
.lang-chev svg { width: 100%; height: 100%; }
.lang-pill[aria-expanded="true"] .lang-chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .lang-chev { transition: none; } }
.lang-first { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); padding: var(--space-8) var(--space-2) var(--space-6); text-align: center; }
.lang-first-ic { width: 64px; height: 64px; border-radius: 20px; background: #EDE9FE; color: var(--primary); display: grid; place-items: center; }
.lang-first-ic svg { width: 36px; height: 36px; }
.lang-first-h { margin: 0; font-size: 20px; font-weight: 700; line-height: 1.4; color: var(--text-primary); overflow-wrap: anywhere; }
.lang-first .lang-grid { width: 100%; }
.lang-btn.big { min-height: 64px; font-size: 22px; }

/* Read-aloud button (drawn icon) */
.speak-icon { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; border: 1.5px solid var(--border); background: var(--surface); color: var(--primary); display: grid; place-items: center; cursor: pointer; transition: transform 0.1s ease; }
.speak-icon svg { width: 22px; height: 22px; }
.speak-icon:active { transform: scale(0.94); }
.speak-icon:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* A short pick-one row (2-4 options) that stays on ONE line and only wraps when a language needs it.
   Grid, not flex: .btn is width:100%, so flex-basis:auto turned each button into its own full row. */
.choice-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--space-2); }
.choice-row .btn { width: auto; min-height: 46px; padding: 0 6px; font-size: 15px; line-height: 1.2; overflow-wrap: break-word; margin-top: 0; }
/* Languages whose labels are long words: two columns, the odd one out spans the row -- never a word cut mid-way. */
.choice-row.long { grid-template-columns: 1fr 1fr; }
.choice-row.long .btn:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* The one-time first-launch chooser is a whole screen, so it keeps big two-column buttons. */
.lang-first .lang-grid { grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.lang-first .lang-grid .lang-btn:last-child:nth-child(odd) { grid-column: 1 / -1; }
.lang-btn.big { min-height: 64px; font-size: 22px; padding: 0 12px; }
.lang-first-h { font-size: 16px; }

/* Compact language button: sits in a row of buttons instead of taking a row of its own. */
.lang-pill.compact { margin-left: auto; min-height: 46px; padding: 0 10px 0 6px; font-size: 15px; gap: 4px; }
.lang-pill.compact .lang-pill-ic { width: 22px; height: 22px; }
.lang-pill.compact .lang-chev { width: 14px; height: 14px; }
/* Keep the bottom nav above scrolled content (a step badge with z-index:1 was showing through it). */
.bottom-nav { z-index: 10; }
/* Space above the festival/announcement banner so it never touches the button above it. */
.home-announce { margin-top: var(--space-3); }

/* Route chips (Repeat last ride, regular routes, recents): a white card with the vehicle in a tinted square
   and a chevron, instead of a loud beige-filled bar. */
.route-chip { background: var(--surface); border: 1px solid var(--border); box-shadow: 0 1px 3px rgba(17, 24, 39, 0.06); padding: 8px 12px; min-height: 56px; }
.route-chip:hover { border-color: var(--primary); }
.route-chip:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.route-chip-text { font-size: 16px; color: var(--text-primary); }
.route-chip-via { color: var(--text-secondary); opacity: 1; }
.route-chip-ic { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; flex: 0 0 auto; background: var(--surface-sunken); color: var(--primary); }
.route-chip-ic svg { width: 26px; height: 20px; }
.route-chip-ic.bike { background: var(--bike-container); color: var(--bike); }
.route-chip-ic.car { background: var(--car-container); color: var(--car); }
.route-chip-go { color: var(--primary); display: inline-flex; width: 18px; height: 18px; flex: 0 0 auto; }
.route-chip-go svg { width: 100%; height: 100%; }

/* Parcel history card header: every place name stays on ONE line (ellipsis only if truly longer than
   the card), status is a dot + plain text on its own line -- no boxed pill to collide with the route. */
.pc-route { flex: 1; min-width: 0; }
.pc-place { font-size: 15px; font-weight: 700; line-height: 1.35; color: #5B21B6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pc-arrow { font-size: 13px; line-height: 1.1; color: var(--text-secondary); }
.status-line { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--text-secondary); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.status-line.st-ok { color: var(--success); }
.status-line.st-wait { color: var(--warning); }
.status-line.st-info { color: var(--primary-dark); }

/* Parcel history card: same structure as .card-car/.card-bike (white card, absolute icon tile), with
   violet as the one small difference so a parcel still reads as its own kind of entry. */
.card-parcel-hist {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid #7C3AED;
  position: relative;
  padding-left: calc(44px + var(--space-3) + var(--space-5));
}
.card-parcel-hist .card-icon { position: absolute; top: var(--space-5); left: var(--space-5); background: #EDE9FE; color: #7C3AED; }
.card-parcel-hist .card-title { color: #5B21B6; }
/* Live parcels (waiting / accepted / picked up) keep the filled violet so they stand apart from
   finished history and from ride cards; finished ones stay plain white. */
.card-parcel-hist.is-active { background: #EDE9FE; border-color: #7C3AED; border-left-width: 5px; }
.card-parcel-hist.is-active .card-icon { background: #DDD6FE; }

/* In-app notifications (0182): bell on Home + list screen */
.notif-bell { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 44px; min-height: 44px; flex: 0 0 auto; border: 1.5px solid #DCD9E3; border-radius: 999px; background: var(--surface); color: var(--primary-dark); cursor: pointer; }
.notif-count { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--danger); color: #fff; font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; }
.notif-item { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card); padding: var(--space-4); margin-bottom: var(--space-2); }
.notif-item.unread { border-left: 4px solid #7C3AED; background: #F5F3FF; }
.notif-title { margin: 0 0 2px; font-size: 15px; font-weight: 700; color: var(--text-primary); }
.notif-route { margin: 0; font-size: 14px; color: var(--text-secondary); }
.notif-time { margin: 4px 0 0; font-size: 12px; color: var(--text-secondary); }
