/* ============================================================
   Layout: the shell's two arrangements.

   html.is-app  — the app layout, on a handheld (or any window under
                  640px): a title bar across the top, five tabs along the
                  bottom, the view as a full page or as a sheet over the map.
   html.is-web  — the web layout: a nav bar with the brand and the same five
                  sections, then two panes: the view in a ~440px panel on
                  the left, the map filling the right. A view that asks for
                  it (wide: true) takes the whole width instead.

   html[data-view-layout="map"|"page"] says what the current view wants;
   html.is-wide is set for wide views on the web layout. The one element
   #content is the panel, the page or the sheet depending on these, so a
   view renders once whatever the layout.
   ============================================================ */

/* ---------------- Top bar (both layouts) ---------------- */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-chrome);
  background: var(--bar-bg);
  color: var(--bar-ink);
  /* the hairline is a border, so the measured height carries it */
  border-bottom: 1px solid var(--bar-edge);
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

.topbar-inner {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  height: calc(var(--nav-h) - 1px);
  padding: 0 16px;
}

/* The brand: the mark and the name. The mark is the app icon's drawing. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--bar-ink);
  text-decoration: none;
  font-weight: 850;
  font-size: 0.98rem;
  letter-spacing: -0.03em;
  white-space: nowrap;
}
.brand-mark { width: 30px; height: 30px; border-radius: var(--radius); }
.brand:focus-visible { outline-offset: 4px; }

.demo-tag { margin-left: -2px; }

/* Desktop nav links: each section is a route; the one you are at is
   inverted, which is what a sign does. Hover draws the section's colour
   under the name. */
.site-menu {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.site-menu a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 13px;
  border-radius: var(--radius);
  color: var(--bar-muted);
  font-weight: 700;
  font-size: 0.92rem;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: inset 0 -3px 0 transparent;
  transition:
    box-shadow var(--duration-quick) var(--ease-smooth-out),
    color var(--duration-quick) var(--ease-smooth-out),
    background-color var(--duration-quick) var(--ease-smooth-out);
}
.site-menu a .nav-icon { display: none; width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) {
  .site-menu a:hover { color: var(--bar-ink); background: var(--page-bg); box-shadow: inset 0 -3px 0 var(--route, var(--line-grey)); }
}
.site-menu a[aria-current="page"],
.site-menu a.is-active {
  color: var(--bar-bg);
  background: var(--bar-ink);
  box-shadow: none;
}
.site-menu a.is-active:hover { color: var(--bar-bg); background: var(--bar-ink); }

.route-home { --route: var(--route-home); --route-ink: var(--route-home-ink); }
.route-search { --route: var(--route-search); --route-ink: var(--route-search-ink); }
.route-plan { --route: var(--route-plan); --route-ink: var(--route-plan-ink); }
.route-status { --route: var(--route-status); --route-ink: var(--route-status-ink); }
.route-history { --route: var(--route-history); --route-ink: var(--route-history-ink); }

/* The gear: two faces in one cell, the outline at rest and the solid one
   while the menu is open, cross-faded and turned (the SCS icon swap). */
.settings-toggle {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--bar-ink);
  transition: box-shadow var(--duration-quick) var(--ease-smooth-out);
}
.settings-toggle svg {
  grid-area: 1 / 1;
  width: 20px;
  height: 20px;
  transition:
    opacity var(--icon-swap-dur) var(--icon-swap-ease),
    filter var(--icon-swap-dur) var(--icon-swap-ease),
    transform var(--icon-swap-dur) var(--icon-swap-ease),
    visibility var(--icon-swap-dur) var(--icon-swap-ease);
}
.settings-toggle .icon-fill,
.settings-toggle[aria-expanded="true"] .icon-line {
  opacity: 0;
  visibility: hidden;
  filter: blur(var(--icon-swap-blur));
  transform: rotate(45deg) scale(0.6);
}
.settings-toggle .icon-line,
.settings-toggle[aria-expanded="true"] .icon-fill {
  opacity: 1;
  visibility: visible;
  filter: blur(0);
  transform: none;
}
@media (hover: hover) and (pointer: fine) {
  .settings-toggle:hover { box-shadow: inset 0 -3px 0 var(--bar-ink); }
}

/* The app bar's pieces; the web layout does not draw them. */
.topbar-back,
.topbar-title,
.topbar-actions { display: none; }

/* Nothing in the bars animates until the shell has settled (app.js adds
   html.chrome-ready two frames after the first view mounts). */
html:not(.chrome-ready) .topbar *,
html:not(.chrome-ready) .tab-bar * { transition: none !important; }

/* The loading bar: when a view is still on its way 250ms after a tap, a
   green bar creeps along the foot of the top bar (the SCS loading bar). */
.load-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-quick) var(--ease-smooth-out);
}
.load-bar span { display: block; width: 0; height: 100%; background: var(--accent); }
.load-bar.is-going { opacity: 1; }
.load-bar.is-going span { animation: load-creep 8s cubic-bezier(0.1, 0.7, 0.2, 1) forwards; }
@keyframes load-creep { from { width: 0; } to { width: 94%; } }

/* ---------------- Tab bar (app layout only) ---------------- */
.tab-bar { display: none; }

/* ---------------- Stage: where the map and the view live ---------------- */
.stage {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  top: var(--nav-h);
}

.map-wrap {
  position: absolute;
  inset: 0;
  z-index: var(--z-map);
  background: var(--map-bg);
  overflow: hidden;
}
.map-wrap[hidden] { display: block !important; visibility: hidden; }

.content {
  position: absolute;
  z-index: var(--z-content);
  background: var(--page-bg);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  outline: none;
}

.view { padding: var(--after-title) var(--gutter) 48px; }
.view:empty { padding: 0; }

/* ---------------- The view's head: a black sign band ----------------
   The view's name on the sign, its eyebrow in the label voice over it, a
   bullet or two beside it (lead) and its actions at the right edge. */
.view-head {
  position: relative;
  background: var(--sign-bg);
  color: var(--sign-ink);
}
.view-head-inner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "eyebrow eyebrow eyebrow"
    "lead    title   actions"
    "sub     sub     sub";
  align-items: center;
  column-gap: 12px;
  padding: 22px var(--gutter) 22px;
}
.view-eyebrow { grid-area: eyebrow; margin: 0 0 8px; color: var(--sign-muted); }
.view-eyebrow:empty { display: none; }
.view-lead { grid-area: lead; display: flex; gap: 6px; align-items: center; }
.view-lead:empty { display: none; }
.view-title {
  grid-area: title;
  margin: 0;
  font-size: var(--t-head);
  font-weight: 850;
  line-height: 1.02;
  letter-spacing: -0.04em;
  color: var(--sign-ink);
  text-wrap: balance;
  overflow-wrap: anywhere;
}
.view-title:focus { outline: none; }
.view-lead:empty + .view-title { grid-column: 1 / 3; }
.view-actions { grid-area: actions; display: flex; gap: 4px; align-items: center; margin-right: -8px; }
.view-actions:empty { display: none; }
.view-actions .icon-btn { color: var(--sign-ink); }
.view-sub { grid-area: sub; margin: 10px 0 0; color: var(--sign-muted); font-size: var(--t-small); line-height: 1.45; }
.view-sub:empty { display: none; }
.view-head[hidden] { display: none !important; }

/* The drag handle belongs to the sheet; elsewhere it is not drawn. */
.sheet-handle { display: none; }

/* ============================================================
   Web layout
   ============================================================ */
html.is-web .topbar-inner {
  width: 100%;
  padding: 0 max(16px, env(safe-area-inset-left, 0px) + 16px) 0 20px;
}

html.is-web .content {
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--panel-w);
  border-right: 1px solid var(--bar-edge);
}
html.is-web .map-wrap { left: var(--panel-w); }

/* A wide view takes the whole width, on the page's own measure */
html.is-web.is-wide .content { width: 100%; border-right: 0; }
html.is-web.is-wide .map-wrap { visibility: hidden; }
html.is-web.is-wide .view-head-inner,
html.is-web.is-wide .view {
  max-width: 1180px;
  margin-inline: auto;
}
html.is-web.is-wide .view-head-inner { padding-top: 30px; padding-bottom: 30px; }
html.is-web.is-wide .view-title { font-size: var(--t-display); letter-spacing: -0.045em; }

/* A narrow window keeps the nav on one line by dropping the words for the
   icons, then the brand's name. */
@media (max-width: 1100px) {
  html.is-web .site-menu a { padding: 0 10px; }
}
@media (max-width: 900px) {
  html.is-web .site-menu a .nav-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  html.is-web .site-menu a .nav-icon { display: block; }
  html.is-web .site-menu a { padding: 0 11px; }
}
@media (max-width: 720px) {
  html.is-web .brand-name { display: none; }
}

/* ============================================================
   App layout
   ============================================================ */
html.is-app {
  --nav-h: calc(var(--appbar-h) + env(safe-area-inset-top, 0px));
  --tabbar-full: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  --gutter: 16px;
}

html.is-app .topbar-inner {
  height: var(--appbar-h);
  padding: 0 4px;
  justify-content: center;
}
/* the bar is the page's title bar: the name in the middle, Back at the
   left end, the view's own actions and the gear at the right */
html.is-app .brand,
html.is-app .site-menu,
html.is-app .demo-tag { display: none; }
html.is-app .topbar-title {
  display: block;
  line-height: 1.2;
  max-width: calc(100% - 184px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 1.02rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-align: center;
}
html.is-app .topbar-back {
  position: absolute;
  left: 4px;
  top: 50%;
  transform: translateY(-50%);
}
html.is-app .topbar-back:not([hidden]) { display: inline-grid; }
html.is-app .topbar-right {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
}
html.is-app .topbar-actions { display: flex; align-items: center; }
html.is-app .settings-toggle { width: 44px; height: 44px; }
/* on the home tab the bar's title is the brand: the mark and the name */
.topbar-title-mark { display: none; }
html.is-app.at-home .topbar-title { display: inline-flex; align-items: center; gap: 9px; }
html.is-app.at-home .topbar-title-mark { display: block; width: 26px; height: 26px; border-radius: var(--radius); }

/* ---------------- Tab bar ---------------- */
html.is-app .tab-bar {
  position: fixed;
  left: 0;
  right: 0;
  /* a pixel below the edge: iOS rounds the viewport so a bar sat exactly at
     0 showed a hairline of page beneath it */
  bottom: -1px;
  z-index: var(--z-chrome);
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  background: var(--bar-bg);
  border-top: 1px solid var(--bar-edge);
  padding: 6px max(4px, env(safe-area-inset-right, 0px)) calc(7px + env(safe-area-inset-bottom, 0px)) max(4px, env(safe-area-inset-left, 0px));
  transition: transform var(--duration-fast) var(--ease-smooth-out), opacity var(--duration-fast) var(--ease-smooth-out);
}
html.is-app .tab-bar a {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 3px;
  min-height: 46px;
  padding: 2px 2px 0;
  color: var(--bar-muted);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-smooth-out);
}
html.is-app .tab-bar svg { grid-area: 1 / 1; width: 25px; height: 25px; }
html.is-app .tab-bar .icon-fill { visibility: hidden; }
html.is-app .tab-bar a.is-active .icon-line { visibility: hidden; }
html.is-app .tab-bar a.is-active .icon-fill { visibility: visible; }
html.is-app .tab-bar a.is-active { color: var(--route-ink, var(--bar-ink)); }
html.is-app .tab-bar .tab-label {
  grid-row: 2;
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--bar-muted);
}
html.is-app .tab-bar a.is-active .tab-label { color: var(--bar-ink); font-weight: 800; }
html.is-app .tab-bar a:active { opacity: 0.6; }
html.is-app .tab-bar a:focus-visible { outline-offset: -2px; }

/* ---------------- Stage ---------------- */
html.is-app .stage {
  top: var(--nav-h);
  bottom: var(--tabbar-full);
}

/* A page: the view scrolls under the bars, the map is put away */
html.is-app[data-view-layout="page"] .content { inset: 0; }
html.is-app[data-view-layout="page"] .map-wrap { visibility: hidden; }

/* The title is in the bar, so a page's band only draws when it carries
   more than the name (a bullet, a line under it). The h1 stays for
   screen readers and for focus. */
html.is-app[data-view-layout="page"] .view-head.is-title-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
html.is-app[data-view-layout="page"] .view-head:not(.is-title-only) .view-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
html.is-app .view-head-inner { padding: 16px var(--gutter) 18px; }

/* ---------------- The sheet ----------------
   A map view on a phone: the map fills the stage and the view rides over
   it in a sheet with three rests (sheet.js): peek, half and full. The
   sheet is the full height and slides; --sheet-y is how much of it shows. */
html.is-app[data-view-layout="map"] .content {
  left: 0;
  right: 0;
  bottom: 0;
  top: auto;
  height: var(--sheet-full, 100%);
  max-height: 100%;
  overflow-y: hidden;
  transform: translate3d(0, calc(var(--sheet-full, 100%) - var(--sheet-y, 50%)), 0);
  will-change: transform;
  border-top: 0;
  box-shadow: 0 -2px 0 rgba(0, 0, 0, 0.08), 0 -12px 28px rgba(0, 0, 0, 0.14);
  touch-action: pan-y;
}
html.is-app[data-view-layout="map"].sheet-full .content { overflow-y: auto; }
html.is-app[data-view-layout="map"].sheet-settling .content {
  transition: transform 300ms cubic-bezier(0.22, 1.12, 0.36, 1);
}
/* the view's head is the top of the sheet: black, holding the grab bar,
   pinned while the body scrolls under its hard edge. Sticky only at full,
   the one rest where the body scrolls: a sticky box inside the moved sheet
   made Chromium stop drawing the map canvas above the sheet (it culled the
   canvas as if the sheet covered it). */
html.is-app[data-view-layout="map"] .view-head {
  position: relative;
  z-index: 3;
  touch-action: none;
}
html.is-app[data-view-layout="map"].sheet-full .view-head,
html.is-app[data-view-layout="map"].sheet-full .sheet-handle { position: sticky; top: 0; }
html.is-app[data-view-layout="map"] .view-head-inner { padding: 22px var(--gutter) 14px; }
html.is-app[data-view-layout="map"] .view-title { font-size: 1.32rem; letter-spacing: -0.03em; }
html.is-app[data-view-layout="map"] .view-eyebrow { margin-bottom: 5px; }
html.is-app[data-view-layout="map"] .view { padding-top: 14px; }

html.is-app[data-view-layout="map"] .sheet-handle {
  display: block;
  position: relative;
  top: 0;
  z-index: 4;
  width: 100%;
  height: 0;
  padding: 0;
  border: 0;
  background: transparent;
  touch-action: none;
}
/* the button's box is the grab zone over the head's top strip; the bar is
   drawn as two hinged halves that fold into a shallow V while dragged down */
html.is-app[data-view-layout="map"] .sheet-handle::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 24px;
}
.sheet-grip {
  position: absolute;
  top: 8px;
  left: 50%;
  width: 46px;
  height: 5px;
  margin-left: -23px;
  pointer-events: none;
}
.sheet-grip::before,
.sheet-grip::after {
  content: '';
  position: absolute;
  top: 0;
  width: 24px;
  height: 5px;
  border-radius: 2px;
  background: #6d6d6d;
  transition: transform 160ms ease;
}
.sheet-grip::before { left: 0; }
.sheet-grip::after { right: 0; }
html.sheet-drag-down .sheet-grip::before { transform: translateY(2px) rotate(14deg); }
html.sheet-drag-down .sheet-grip::after { transform: translateY(2px) rotate(-14deg); }
html.sheet-drag-up .sheet-grip::before { transform: translateY(2px) rotate(-14deg); }
html.sheet-drag-up .sheet-grip::after { transform: translateY(2px) rotate(14deg); }
.sheet-handle:focus-visible .sheet-grip::before,
.sheet-handle:focus-visible .sheet-grip::after { background: var(--accent); }
.sheet-handle:focus-visible { outline: none; }

/* map controls and attribution ride above the sheet */
html.is-app[data-view-layout="map"] .map-wrap { --map-bottom: var(--sheet-y, 0px); }

/* ---------------- While the keyboard is up ----------------
   A phone keyboard takes the bottom of the screen: the tab bar has nothing
   to do while somebody types, so it leaves, and the stage takes its room.
   --kb-inset is how much of the layout viewport the keyboard covers (0
   where the browser resized the view instead). */
html.is-app.kb-up .tab-bar { transform: translateY(100%); opacity: 0; pointer-events: none; }
html.is-app.kb-up .stage { bottom: var(--kb-inset, 0px); }

/* ---------------- Pull to refresh (phone pages) ----------------
   The page follows the finger down; the arrow sits above the content,
   hidden under the bar at rest, and flips once the pull would refresh
   (ui/pull.js). Only page views in the app layout draw it. */
.ptr { display: none; }
html.is-app[data-view-layout="page"] .ptr {
  display: grid;
  place-items: center;
  position: absolute;
  left: 50%;
  top: 0;
  width: 40px;
  height: 40px;
  margin-left: -20px;
  color: var(--muted);
  pointer-events: none;
  transform: translateY(calc(var(--pull, 0px) - 44px));
}
.ptr svg { width: 26px; height: 26px; transition: transform var(--duration-fast) var(--ease-smooth-out), opacity var(--duration-quick) var(--ease-smooth-out); }
.ptr.is-armed svg { transform: rotate(180deg); }
.ptr.is-loading svg { opacity: 0; }
html.is-pulling .content > .view,
html.is-pulling .content > .view-head,
html.is-pull-settling .content > .view,
html.is-pull-settling .content > .view-head { translate: 0 var(--pull, 0px); }
html.is-pull-settling .content > .view,
html.is-pull-settling .content > .view-head { transition: translate var(--duration-fast) var(--ease-smooth-out); }
html.is-pull-settling .ptr { transition: transform var(--duration-fast) var(--ease-smooth-out); }

/* ---------------- App niceties ---------------- */
html.is-installed a { -webkit-touch-callout: none; }
html.is-app, html.is-app body { touch-action: pan-x pan-y; }
html.is-app .map-wrap { touch-action: none; }

/* ---------------- Menu veil ----------------
   While a menu is open the content dims; the bars sit above the veil. */
html.menu-open body::before,
html.menu-closing body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(12, 15, 20, 0.22);
  pointer-events: none;
  animation: t-fade-in var(--dropdown-open-dur) var(--ease-smooth-out);
  transition: opacity var(--dropdown-close-dur) var(--ease-smooth-out);
}
html.menu-closing body::before { opacity: 0; animation: none; }
@keyframes t-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---------------- Print ---------------- */
@media print {
  .topbar, .tab-bar, .map-wrap, .sheet-handle { display: none !important; }
  .stage, .content { position: static !important; transform: none !important; height: auto !important; overflow: visible !important; }
  html, body { overflow: visible; height: auto; }
}
