trips/mock/styles.css
Greg Pomerantz c367eba5cb Live web enrichment (SearXNG) + PostGIS spatial stack
Milestone 1 — live web search:
- mock/server.js: /search + /search-status proxy to the self-hosted
  SearXNG (third leg of the 3-source blend; engine endpoint stays
  server-side), /spatial + /spatial-status proxy to the spatial service
- mock/app.js: background enrichment of suggestion cards — each
  candidate gets a web element (discovery cards + "you might like"
  rows) that is checked via SearXNG in the background (one in-flight
  query per place, 1 h TTL, failures retry in ~5 min) and APPENDS
  sourced facts with provenance URLs; never reorders/rewrites the plan.
  New LLM tools: web_search (cite URLs) and poi_near (PostGIS). Status
  badge gains 'web' / 'spatial'.
- styles.css: .cc-web live-facts blocks, t-web verified chip

Milestone 2 — PostGIS spatial DB (code complete; needs docker access
to run — see spatial/README.md):
- spatial/: docker-compose (postgis/postgis:16-3.4 + osm2pgsql:16
  one-shot importer + spatiald), schema.sql (poi table w/ GIST index,
  spatial_extract bookkeeping, refresh_poi()), import.sh for the PBF
  extracts in ../osm, spatiald (Go, lib/pq): /health, /near
  (ST_DWithin), /nearest (KNN), /corridor (ST_Buffer along a route),
  with kind/name/extract/limit filters
2026-09-10 09:43:30 -04:00

524 lines
35 KiB
CSS

:root {
--ink: #1f2430; --ink2: #5b6472; --line: #e4e7ec; --bg: #f5f6f8;
--card: #ffffff; --accent: #b5533c; --accent2: #8f3f2d;
--ok: #2e9e5b; --warn: #c98a1b; --err: #c0392b;
--blue: #2f6fd6;
--shadow: 0 1px 3px rgba(20,24,35,.08), 0 8px 24px rgba(20,24,35,.07);
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif; color: var(--ink); background: var(--bg); }
.hidden { display: none !important; }
button { font: inherit; }
#map { position: fixed; inset: 0; z-index: 0; background: #dde3ea; }
.leaflet-container { font: inherit; }
/* ---------------- landing ---------------- */
#landing { position: fixed; inset: 0; z-index: 20; display: flex; align-items: center; justify-content: center;
background: linear-gradient(rgba(20,24,35,.28), rgba(20,24,35,.42)); }
.land-card { width: min(560px, 92vw); background: var(--card); border-radius: 18px; box-shadow: var(--shadow); padding: 34px 36px; }
.land-kicker { font-size: 11px; letter-spacing: .14em; color: var(--accent); font-weight: 700; margin-bottom: 10px; }
.land-card h1 { margin: 0 0 16px; font-size: 26px; font-weight: 700; letter-spacing: -.01em; }
.land-row { display: flex; gap: 8px; }
#dest { flex: 1; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: 10px; font-size: 15px; outline: none; }
#dest:focus { border-color: var(--accent); }
.land-div { display: flex; align-items: center; gap: 12px; color: var(--ink2); font-size: 12px; margin: 18px 0; }
.land-div::before, .land-div::after { content: ""; flex: 1; height: 1px; background: var(--line); }
#dropzone { border: 2px dashed #cfd4dd; border-radius: 14px; padding: 22px 18px; text-align: center; transition: all .15s; }
#dropzone.over { border-color: var(--accent); background: #fbf1ee; transform: scale(1.01); }
.dz-icon { font-size: 30px; margin-bottom: 8px; }
.dz-text { font-size: 13.5px; color: var(--ink2); line-height: 1.5; }
.dz-text b { color: var(--ink); font-size: 14.5px; }
.btn { border: 0; border-radius: 10px; padding: 11px 16px; font-size: 14px; font-weight: 600; cursor: pointer; transition: filter .12s, transform .05s; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: default; }
.btn.primary { background: var(--accent); color: #fff; }
.btn.primary:hover { filter: brightness(1.08); }
.btn.ghost { background: #eef0f4; color: var(--ink); }
.btn.ghost:hover { background: #e4e7ee; }
.btn.small { padding: 8px 12px; font-size: 12.5px; }
.btn.tiny { padding: 4px 9px; font-size: 11px; border-radius: 8px; }
/* ---------------- topbar ---------------- */
#topbar { position: fixed; top: 0; left: 0; right: 0; height: 46px; z-index: 15; background: var(--card);
display: flex; align-items: center; justify-content: space-between; padding: 0 16px; border-bottom: 1px solid var(--line); pointer-events: auto; }
.brand { font-weight: 800; letter-spacing: .12em; font-size: 13px; color: var(--accent); }
.crumb { font-size: 13px; font-weight: 600; margin-left: 12px; }
.crumb.sub { color: var(--ink2); font-weight: 500; }
/* trip picker (top-level trip selection) */
.trip-picker { position: relative; }
#crumb { border: none; background: transparent; font: inherit; color: inherit; cursor: pointer;
padding: 4px 8px; border-radius: 8px; display: flex; align-items: center; gap: 6px; max-width: 320px; }
#crumb:hover { background: #f2f5f8; }
#crumb .caret { font-size: 9px; color: var(--ink2); }
#crumb .t-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tripmenu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 60; width: 300px;
background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); padding: 6px; }
.trip-item { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%;
border: 0; background: none; padding: 8px 10px; border-radius: 8px; cursor: pointer; text-align: left; font: inherit; color: inherit; }
.trip-item:hover { background: #f2f5f8; }
.trip-item.cur { background: #eef4ff; }
.trip-item .ti-name { font-weight: 600; font-size: 13px; }
.trip-item .ti-sub { font-size: 11px; color: var(--ink2); }
.tb-left { display: flex; align-items: center; min-width: 0; }
.tb-right { display: flex; align-items: center; gap: 10px; }
.badge { font-size: 12.5px; background: #fdf3e3; color: #8a6116; border: 1px solid #f0dcae; padding: 5px 10px; border-radius: 999px; cursor: default; }
.badge.ok { background: #eaf6ef; color: #1f7a45; border-color: #c9e8d6; }
/* ---------------- app grid ---------------- */
#app { position: fixed; top: 46px; left: 0; right: 0; bottom: 0; z-index: 10; display: grid;
grid-template-columns: 354px 1fr 350px;
pointer-events: none; } /* map underneath must receive drags/clicks; children opt back in */
#rail, #chat { min-height: 0; pointer-events: auto; }
#rail { background: var(--card); border-right: 1px solid var(--line); display: flex; flex-direction: column; overflow: hidden; }
#rail-body, #chat-body { min-height: 0; }
#rail-body { flex: 1; overflow-y: auto; padding: 10px 12px 4px; }
#rail-body.drop-open { outline: 2px dashed var(--accent); outline-offset: -4px; border-radius: 8px; }
.rail-block { padding: 8px 12px 0; }
.rail-foot { border-top: 1px solid var(--line); padding: 10px 14px 12px; background: #fbfcfd; }
.mapwrap, #mapwrap { position: relative; pointer-events: none; } /* let wheel/drag reach the Leaflet map underneath */
#chat { background: var(--card); border-left: 1px solid var(--line); display: flex; flex-direction: column; }
#chat-body { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 10px; }
#chat-input-row { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); align-items: center; }
#doc-attach { cursor: pointer; line-height: 1; }
#doc-chips { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 12px 0; max-height: 54px; overflow-y: auto; }
#doc-chips.hidden { display: none; }
.dc { font-size: 11px; background: #eef0f4; border: 1px solid var(--line); color: var(--ink); border-radius: 10px; padding: 1px 8px; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.dc-k { opacity: .55; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 10px; }
#chat { position: relative; }
#chat.dropping::after {
content: 'Drop the flight booking to reconfigure the trip';
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
font: 600 15px/1.4 var(--sans, system-ui, sans-serif); color: #2f6df6; text-align: center;
background: rgba(238, 244, 255, 0.88); border: 3px dashed #2f6df6; border-radius: 12px;
pointer-events: none; z-index: 20; padding: 24px;
}
#chat-input { flex: 1; border: 1.5px solid var(--line); border-radius: 10px; padding: 10px 12px; font-size: 13.5px; outline: none; }
#chat-input:focus { border-color: var(--accent); }
/* ---------------- day strip (L1 overview) ---------------- */
#daystrip { padding: 10px 12px 2px; }
.strip-track { position: relative; height: 30px; background: #eef1f6; border-radius: 8px; overflow: hidden; }
.sb { position: absolute; top: 3px; bottom: 3px; border-radius: 5px; font-size: 9.5px; font-weight: 700;
display: flex; align-items: center; justify-content: center; overflow: hidden; white-space: nowrap;
padding: 0 3px; cursor: pointer; color: #fff; min-width: 12px; }
.sb.visit { background: var(--accent); }
.sb.meal { background: #5f8f4f; }
.sb.transit { background: #274b8f; }
.sb.region { background: #c98a1b; }
.sb.leg { background: #c3cad6; cursor: default; }
.sb.hotel { background: #7a8291; }
.sb.gap { background: transparent; cursor: default; }
.sb.dimmed { background: #fff; border: 1.5px dashed #b9c0cc; color: var(--ink2); }
.sb:hover { filter: brightness(1.1); z-index: 2; }
.strip-axis { position: relative; height: 14px; margin-top: 1px; }
.strip-axis .tick { position: absolute; transform: translateX(-50%); font-size: 9px; color: var(--ink2); }
/* ---------------- chips & facts ---------------- */
.transit-chip { display: flex; align-items: center; gap: 8px; background: #f2f5fa; border: 1px solid #dfe6f2;
border-radius: 10px; padding: 7px 10px; font-size: 12px; line-height: 1.4; cursor: pointer; }
.transit-chip:hover { border-color: var(--blue); }
.transit-chip .tt { font-weight: 700; }
.transit-chip .ts { color: var(--ink2); }
.tc { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600;
padding: 2px 7px; border-radius: 999px; white-space: nowrap; }
.t-user { background: var(--ink); color: #fff; }
.t-user::before { content: "📌"; font-size: 9px; }
.t-sched { background: #274b8f; color: #fff; }
.t-sched::before { content: "🎫"; font-size: 9px; }
.t-computed { background: #e7ebf2; color: var(--ink); }
.t-search { background: #e8f1fd; color: #1d4f9c; }
.t-search::before { content: "~"; font-weight: 800; }
.t-llm { background: transparent; border: 1.5px dashed #b9c0cc; color: var(--ink2); }
.t-llm::after { content: "est"; font-size: 9px; opacity: .8; }
.t-web { background: #e3f4e6; color: #1d7a35; }
.t-web::before { content: "✓"; font-weight: 800; }
/* live web facts on suggestion cards (background SearXNG enrichment) */
.cc-web { margin-top: 7px; font-size: 11px; color: var(--ink2); line-height: 1.5;
border-top: 1px dashed var(--line); padding-top: 6px; }
.cc-web:empty { display: none; }
.cc-web.busy { opacity: .75; font-style: italic; }
.cc-web .web-src a { color: #1d4f9c; font-weight: 700; text-decoration: none; }
.cc-web .web-src a:hover { text-decoration: underline; }
.cc-web .web-snip { display: block; margin: 1px 0 3px; }
.cc-web-sugg { border-top: none; padding-top: 2px; }
.pchip { font-size: 11.5px; color: var(--ink2); font-weight: 600; white-space: nowrap; }
.sug-note { font-size: 11px; color: var(--ink2); font-style: italic; }
/* ---------------- stop cards ---------------- */
.stop-card { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 6px 0; background: var(--card);
position: relative; transition: border-color .15s, box-shadow .15s; cursor: pointer; }
.stop-card:hover { border-color: #c9cfda; box-shadow: 0 2px 8px rgba(20,24,35,.06); }
.stop-card.flash { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(181,83,60,.15); }
.stop-card.dragging { opacity: .45; }
.stop-card.drop-target { border-color: var(--accent); border-style: dashed; background: #fdf6f3; }
.stop-card.st-maybe { border: 1.5px dashed #cfae5f; background: #fffdf6; }
.stop-card.st-alt { border: 1.5px dashed #9fb0cc; background: #f8fafd; }
.grip { cursor: grab; color: #c3c9d4; font-size: 14px; margin-right: 2px; user-select: none; letter-spacing: -2px; }
.grip:active { cursor: grabbing; }
.sc-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.sc-name { font-weight: 700; font-size: 13.5px; }
.sc-times { font-size: 12px; color: var(--ink2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sc-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; align-items: center; }
.sc-sub { font-size: 11.5px; color: var(--ink2); margin-top: 5px; }
.sc-sub a { color: var(--blue); text-decoration: none; }
.sc-acts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; align-items: center; }
.sc-state { cursor: default; }
.t-idea { background: #fdf3e3; color: #8a6116; border: 1px dashed #d9b96a; }
.t-backup { background: #eef1f6; color: #4a5a78; border: 1px dashed #9fb0cc; }
/* inline alternatives expander */
.alts { display: none; margin-top: 8px; border-top: 1px solid var(--line); padding-top: 6px; }
.alts.open { display: block; }
.altrow { display: flex; align-items: center; gap: 6px; padding: 5px 0; border-bottom: 1px dashed #eef0f4; flex-wrap: wrap; }
.altrow:last-child { border-bottom: 0; }
.ar-name { font-size: 12.5px; font-weight: 600; }
.altrow .pchip { font-size: 10.5px; }
/* rail item numbers (match the map markers) */
.num { width: 20px; height: 20px; border-radius: 50%; background: var(--ink); color: #fff; font-size: 11px;
font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.stop-card.st-maybe .num { background: #cfae5f; }
.stop-card.st-alt .num { background: #9fb0cc; }
.leg-row { display: flex; align-items: center; gap: 8px; margin: 2px 0 2px 22px; padding: 3px 8px; cursor: pointer;
border-radius: 8px; font-size: 12px; color: var(--ink2); }
.leg-row:hover { background: #eef0f4; }
.leg-ico { font-size: 13px; }
.leg-sub { font-size: 11px; color: var(--ink2); opacity: .8; }
.leg-row.dim { opacity: .55; }
/* travel-mode toggle (on foot vs taxi) — lives on the route card (the popup
a leg click opens) */
.mode-toggle { display: flex; align-items: center; gap: 6px; flex: 1; }
.l3-mode { display: flex; align-items: center; gap: 8px; margin: 2px 0 8px; }
.l3-mode .mode-btn { padding: 5px 6px; font-size: 12px; }
.mode-label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink2);
margin-right: 2px; white-space: nowrap; }
.mode-btn { flex: 1; border: 1px solid var(--line); background: var(--card); color: var(--ink2);
border-radius: 9px; padding: 6px 8px; font-size: 12.5px; font-weight: 600; cursor: pointer;
transition: background .15s, border-color .15s, color .15s; }
.mode-btn:hover { border-color: #c9cfda; }
.mode-btn.on { background: var(--ink); border-color: var(--ink); color: #fff; }
/* structural timeline cards: the airport you landed on + the hotel for the
night — rendered in the day timeline, not as editable stops */
.struct-card { border-left: 3px solid #c3cad6; }
.struct-card .sc-name { font-size: 13px; }
.arr-card { border-left-color: #274b8f; background: #f6f9ff; }
.hotel-card { border-left-color: #7a8291; background: #f7f8fa; }
.hotel-card .sc-times { font-weight: 600; }
/* vague / region placeholder stops */
.region-note { font-size: 11px; color: var(--ink2); margin-top: 5px; }
.refine-btn { margin-top: 7px; border: 1px solid var(--line); background: #f5f3ef; color: var(--accent);
border-radius: 999px; font-size: 11.5px; font-weight: 600; padding: 4px 10px; cursor: pointer; }
.refine-btn:hover { background: #fff; border-color: var(--accent); }
/* ---------------- "you might like" suggestion block ---------------- */
.sugg-title { font-size: 12px; font-weight: 700; color: var(--ink); margin-bottom: 6px; display: flex; align-items: center; gap: 8px; }
.sugg-note { font-weight: 500; color: var(--ink2); }
.sugg-open { margin-left: auto; border: 0; background: none; color: var(--blue); font-size: 11px; cursor: pointer; text-decoration: underline; }
.sugg-open:hover { color: var(--accent); }
.sugg-row { display: flex; align-items: center; gap: 6px; padding: 4px 6px; border-radius: 8px; font-size: 12.5px; flex-wrap: wrap; }
.sugg-row:hover { background: #f4f6fa; }
.sr-name { font-weight: 600; }
.sugg-row .pchip { font-size: 10.5px; }
/* ---------------- nudges ---------------- */
#nudges { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.nudge { border: 1px solid #e7d9f0; background: #f7f3fc; border-radius: 10px; padding: 9px 11px; font-size: 12px; line-height: 1.5; }
.nudge .nt { font-weight: 700; color: #5d3a8a; }
.nudge .nb { color: var(--ink2); margin-top: 3px; }
.nudge .btn { margin-top: 7px; }
.nudge-ok { font-size: 12px; color: #1f7a45; padding: 2px 0; }
.legend { display: flex; flex-wrap: wrap; gap: 5px 10px; margin-top: 10px; font-size: 10.5px; color: var(--ink2); align-items: center; }
.legend .tc { font-size: 10px; padding: 1px 6px; }
.budget-label { font-size: 11.5px; color: var(--ink2); margin-bottom: 5px; }
.budget-bar { height: 7px; background: #e7ebf2; border-radius: 99px; overflow: hidden; }
#budget-fill { height: 100%; width: 0; background: var(--ok); border-radius: 99px; transition: width .5s ease, background .3s; }
#budget-fill.warn { background: var(--warn); }
/* ---------------- discovery drawer (over the map, plan stays visible) ---------------- */
#discover { position: absolute; top: 12px; right: 12px; bottom: 12px; width: 348px; z-index: 12;
background: var(--card); border-radius: 16px; box-shadow: var(--shadow); pointer-events: auto;
display: flex; flex-direction: column; overflow: hidden; animation: slidein .22s ease; }
@keyframes slidein { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: none; } }
.disc-head { padding: 12px 14px 10px; border-bottom: 1px solid var(--line); position: relative; }
.disc-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.dchip { border: 1.5px solid var(--line); background: #fff; border-radius: 999px; padding: 5px 12px;
font-size: 12px; font-weight: 600; color: var(--ink2); cursor: pointer; transition: all .12s; }
.dchip:hover { border-color: var(--accent); color: var(--accent); }
.dchip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
#disc-title { font-size: 11.5px; color: var(--ink2); margin-top: 8px; }
#disc-title b { color: var(--ink); }
.disc-x { position: absolute; top: 10px; right: 10px; border: 0; background: #eef0f4; width: 26px; height: 26px;
border-radius: 50%; cursor: pointer; font-size: 11px; color: var(--ink); }
.disc-x:hover { background: #e2e5ec; }
.disc-list { flex: 1; overflow-y: auto; padding: 10px 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.disc-empty { font-size: 12.5px; color: var(--ink2); padding: 14px 6px; }
.candcard { border: 1px solid var(--line); border-radius: 13px; padding: 10px 12px; background: #fff;
transition: border-color .15s, box-shadow .15s; cursor: grab; }
.candcard:hover { border-color: #c9cfda; box-shadow: 0 2px 8px rgba(20,24,35,.07); }
.candcard.dragging { opacity: .5; }
.candcard.flash { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(181,83,60,.18); }
.cc-head { display: flex; gap: 10px; align-items: center; }
.cc-img { width: 46px; height: 46px; border-radius: 10px; overflow: hidden; position: relative; flex-shrink: 0;
display: flex; align-items: center; justify-content: center; }
.cc-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cc-emoji { font-size: 22px; }
.cc-name { font-weight: 700; font-size: 13.5px; line-height: 1.25; }
.cc-pitch { font-size: 12px; color: var(--ink2); margin-top: 6px; line-height: 1.45; }
.cc-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; align-items: center; }
.cc-tags { font-size: 10.5px; color: var(--ink2); margin-top: 6px; opacity: .85; }
.cc-acts { display: flex; gap: 6px; margin-top: 9px; flex-wrap: wrap; align-items: center; }
.cc-no { margin-left: auto; border: 0; background: none; color: var(--ink2); font-size: 11px; cursor: pointer; text-decoration: underline; }
.cc-no:hover { color: var(--err); }
/* discovery pins: numbered teardrops */
.candpin { width: 24px; height: 24px; background: var(--accent); color: #fff; font-weight: 700; font-size: 12px;
border-radius: 50% 50% 50% 0; transform: rotate(-45deg); display: flex; align-items: center; justify-content: center;
border: 2.5px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,.35); transition: transform .12s; cursor: pointer; }
.candpin:hover { transform: rotate(-45deg) scale(1.15); }
.candpin > * { transform: rotate(45deg); }
/* ---------------- comparison dock ---------------- */
#dock { position: fixed; left: 50%; transform: translateX(-50%); bottom: 14px; z-index: 30;
width: min(1060px, calc(100vw - 740px)); background: var(--card); border-radius: 16px; box-shadow: var(--shadow);
padding: 12px 16px 14px; animation: dockup .25s ease; }
@keyframes dockup { from { opacity: 0; transform: translate(-50%, 14px); } to { opacity: 1; transform: translate(-50%, 0); } }
.dock-head { display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--ink2); margin-bottom: 10px; }
.dock-clear { margin-left: auto; border: 0; background: none; color: var(--ink2); font-size: 11.5px; cursor: pointer; text-decoration: underline; }
.dock-clear:hover { color: var(--err); }
.dock-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 10px; }
.dock-col { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; background: #fbfcfe; }
.dc-name { font-weight: 700; font-size: 13px; display: flex; align-items: center; gap: 8px; }
.dc-thumb { width: 26px; height: 26px; border-radius: 7px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; }
.dc-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }
.dc-tags { font-size: 10.5px; color: var(--ink2); margin-top: 6px; }
.dc-acts { display: flex; gap: 6px; margin-top: 9px; flex-wrap: wrap; align-items: center; }
.dc-state { font-size: 11.5px; color: var(--ok); font-weight: 600; }
.dc-rm { margin-left: auto; border: 0; background: #eef0f4; width: 22px; height: 22px; border-radius: 50%; font-size: 10px; cursor: pointer; color: var(--ink2); }
.dc-rm:hover { background: #e2e5ec; color: var(--err); }
/* ---------------- chat ---------------- */
.msg { max-width: 94%; border-radius: 14px; padding: 10px 13px; font-size: 13.5px; line-height: 1.5; animation: pop .18s ease; }
@keyframes pop { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.msg.user { align-self: flex-end; background: var(--accent); color: #fff; border-bottom-right-radius: 4px; }
.msg.ai { align-self: flex-start; background: #eef0f4; border-bottom-left-radius: 4px; }
.msg.tool { align-self: flex-start; background: #f5f1fb; border: 1px solid #e5dbf2; border-radius: 10px; padding: 6px 10px; font-size: 11.5px; font-family: ui-monospace, Menlo, Consolas, monospace; color: #5d3a8a; max-width: 94%; }
.msg.tool .ta { color: #8a6116; }
.msg .src { display: block; font-size: 11px; color: var(--ink2); margin-top: 6px; }
.msg .src a { color: var(--blue); text-decoration: none; }
.typing { display: inline-flex; gap: 4px; padding: 12px 14px; }
.typing i { width: 6px; height: 6px; border-radius: 50%; background: #9aa3b2; animation: blink 1.2s infinite; }
.typing i:nth-child(2) { animation-delay: .2s; } .typing i:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 70%, 100% { opacity: .3; } 35% { opacity: 1; } }
.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.chip { border: 1.5px solid var(--line); background: #fff; border-radius: 999px; padding: 7px 13px; font-size: 12.5px; font-weight: 600; cursor: pointer; transition: all .12s; }
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.sel { background: var(--accent); border-color: var(--accent); color: #fff; }
.cards { display: flex; flex-direction: column; gap: 9px; margin-top: 10px; }
.scard { border: 1px solid var(--line); border-radius: 13px; overflow: hidden; background: #fff; box-shadow: var(--shadow); }
.scard-img { height: 96px; display: flex; align-items: center; justify-content: center; position: relative; }
.scard-img .skel { position: absolute; inset: 0; background: linear-gradient(100deg,#eceef2 40%,#f6f7fa 50%,#eceef2 60%); background-size: 200% 100%; animation: shimmer 1.2s infinite; }
@keyframes shimmer { to { background-position: -200% 0; } }
.scard-img .ph { font-size: 44px; opacity: 0; transition: opacity .5s; }
.scard-img.done .ph { opacity: 1; }
.scard-img .attr { position: absolute; right: 6px; bottom: 4px; font-size: 9px; color: rgba(255,255,255,.85); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
.scard-body { padding: 10px 12px; }
.scard-name { font-weight: 700; font-size: 13.5px; }
.scard-pitch { font-size: 12.5px; color: var(--ink2); margin: 4px 0 7px; line-height: 1.45; }
.scard-enrich { font-size: 11.5px; color: var(--blue); margin-top: 6px; opacity: 0; transition: opacity .6s; }
.scard-enrich.show { opacity: 1; }
.scard-enrich a { text-decoration: none; }
.scard-foot { display: flex; gap: 6px; align-items: center; margin-top: 8px; }
.scard-foot .sp { margin-left: auto; }
.scard { transition: opacity .4s; cursor: pointer; }
.scard.added { opacity: .55; }
.scard.maybe-card { opacity: .7; }
.scard.dropped { opacity: .3; cursor: default; }
.scard-name a { color: var(--ink); text-decoration: none; }
.scard-name a:hover { color: var(--accent); text-decoration: underline; }
.scard-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .6s; }
.scard-img.done img { opacity: 1; }
/* detail sheet */
.modal-card.wide { width: min(600px, 94vw); max-height: 86vh; overflow-y: auto; position: relative; padding: 0; }
.d-img { height: 150px; display: flex; align-items: center; justify-content: center; position: relative; }
.d-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.d-emoji { font-size: 56px; }
.d-actions { display: flex; gap: 8px; margin-top: 18px; }
.d-attr { position: absolute; right: 10px; bottom: 8px; font-size: 10px; color: rgba(255,255,255,.85); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
.d-body { padding: 18px 22px 20px; }
.d-title { display: flex; align-items: baseline; gap: 10px; }
.d-title a { font-size: 19px; font-weight: 700; color: var(--ink); text-decoration: none; }
.d-title a:hover { color: var(--accent); text-decoration: underline; }
.d-kind { font-size: 11px; color: var(--ink2); border: 1px solid var(--line); padding: 2px 8px; border-radius: 99px; }
.d-facts { display: flex; flex-wrap: wrap; gap: 7px; margin: 10px 0 12px; align-items: center; }
.d-summary { font-size: 13.5px; line-height: 1.6; color: var(--ink); }
.d-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.d-link { border: 1.5px solid var(--line); background: #fff; border-radius: 999px; padding: 7px 13px; font-size: 12.5px; font-weight: 600; color: var(--ink); text-decoration: none; transition: all .12s; }
.d-link:hover { border-color: var(--accent); color: var(--accent); }
.d-close { position: absolute; top: 10px; right: 12px; border: 0; background: rgba(255,255,255,.85); width: 28px; height: 28px; border-radius: 50%; cursor: pointer; font-size: 12px; color: var(--ink); z-index: 2; }
.d-close:hover { background: #fff; }
.pulse { animation: pulse .8s ease; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(181,83,60,.4); } 100% { box-shadow: 0 0 0 12px rgba(181,83,60,0); } }
/* ---------------- L3 editor ---------------- */
#l3-editor { position: absolute; left: 14px; bottom: 18px; z-index: 12; background: var(--card); border-radius: 14px;
box-shadow: var(--shadow); padding: 12px 14px; width: 300px; pointer-events: auto; }
.l3-title { font-weight: 700; font-size: 13.5px; }
.l3-hint { font-size: 11.5px; color: var(--ink2); margin: 5px 0 8px; line-height: 1.4; }
.l3-time { font-size: 12.5px; color: var(--ink2); display: flex; gap: 8px; align-items: center; }
#l3-close { float: right; margin-top: -4px; }
/* ---------------- modal ---------------- */
.modal { position: fixed; inset: 0; z-index: 40; background: rgba(20,24,35,.45); display: flex; align-items: center; justify-content: center; }
.modal-card { width: min(480px, 92vw); background: var(--card); border-radius: 16px; box-shadow: var(--shadow); padding: 24px 26px; }
.modal-card h2 { margin: 0 0 14px; font-size: 18px; }
#parse-table { width: 100%; border-collapse: collapse; font-size: 13px; }
#parse-table td { padding: 7px 4px; border-bottom: 1px solid var(--line); vertical-align: top; }
#parse-table td:first-child { color: var(--ink2); width: 34%; }
.conf { font-size: 10.5px; padding: 1.5px 7px; border-radius: 99px; font-weight: 700; margin-left: 6px; }
.conf.hi { background: #eaf6ef; color: #1f7a45; }
.conf.mid { background: #fdf3e3; color: #8a6116; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
.wp { cursor: grab; }
.leaflet-marker-icon.wp { transition: none; }
/* ---------------- day tabs ---------------- */
.daytabs { display: flex; gap: 6px; margin-left: 14px; align-items: center; }
.daytab { border: 1px solid var(--line); background: #fff; border-radius: 999px; padding: 5px 12px;
font-size: 12px; font-weight: 600; color: var(--ink2); cursor: pointer; transition: all .12s; }
.daytab:hover { border-color: var(--accent); color: var(--accent); }
.daytab.sel { background: var(--ink); border-color: var(--ink); color: #fff; }
.daytab.dep { cursor: default; background: transparent; border-style: dashed; color: var(--ink2); }
.daytab.dep:hover { border-color: var(--line); color: var(--ink2); }
.daytab.over { border-color: var(--accent); background: #fbf1ee; color: var(--accent); }
/* state menu popover */
.pop { position: absolute; top: 36px; right: 8px; z-index: 30; background: #fff; border: 1px solid var(--line);
border-radius: 10px; box-shadow: var(--shadow); padding: 4px; display: flex; flex-direction: column; min-width: 170px; }
.pop button { border: 0; background: none; text-align: left; padding: 7px 10px; font-size: 12.5px; border-radius: 7px; cursor: pointer; color: var(--ink); font-weight: 500; }
.pop button:hover { background: #eef0f4; }
.pop button.danger { color: var(--err); }
/* hotel / train pins */
.hotel-pin { font-size: 22px; transform: translate(-50%,-90%); transition: transform .15s; }
.hotel-pin.hotel-alt { filter: grayscale(1); opacity: .75; }
/* map markers: current-day numbered vs other-day dots */
.mk { background: #b5533c; color: #fff; width: 26px; height: 26px; border-radius: 50%;
display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px;
border: 2.5px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,.4); transition: transform .15s; }
.mkd { background: #fff; color: #8b93a3; border: 2px dashed #9aa3b2; box-shadow: none; }
/* topbar width relief: drop the verbose badges first */
@media (max-width: 1560px) { #offline-badge { display: none; } }
@media (max-width: 1320px) { #nudge-badge { display: none; } #crumb { max-width: 180px; } }
/* ---------------- landing demo chips ---------------- */
.land-demo { display: flex; align-items: center; gap: 8px; margin-top: 16px; font-size: 12px; color: var(--ink2); flex-wrap: wrap; }
.land-demo .chip { font-size: 12px; padding: 6px 12px; }
.land-demo .chip i { font-style: normal; font-size: 10px; opacity: .75; }
/* ---------------- scope toggle (Day | Trip) ---------------- */
.scope-toggle { display: flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; margin-left: 12px; }
.sct { border: 0; background: #fff; padding: 4px 12px; font-size: 12px; font-weight: 600; color: var(--ink2); cursor: pointer; }
.sct + .sct { border-left: 1px solid var(--line); }
.sct:hover { color: var(--accent); }
.sct.on { background: #f3ede9; color: var(--accent); }
/* ---------------- version pill + history ---------------- */
.verpill { display: flex; align-items: center; gap: 2px; background: #f2f4f8; border: 1px solid var(--line);
border-radius: 999px; padding: 2px 4px; position: relative; }
.vp-btn { border: 0; background: none; width: 24px; height: 24px; border-radius: 50%; cursor: pointer;
font-size: 12px; color: var(--ink); }
.vp-btn:hover { background: #e4e8ef; }
.vp-btn.off { opacity: .3; cursor: default; }
.vp-btn.off:hover { background: none; }
.vp-label { font-size: 12px; font-weight: 700; color: var(--ink2); cursor: pointer; padding: 0 6px; font-variant-numeric: tabular-nums; }
.vp-label:hover { color: var(--accent); }
.verlist { position: absolute; top: 52px; right: 16px; z-index: 50; width: 340px; max-height: 60vh; overflow-y: auto;
background: var(--card); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); padding: 6px; }
.ver-row { padding: 8px 10px; border-radius: 10px; cursor: pointer; font-size: 12px; line-height: 1.4; }
.ver-row:hover { background: #f2f4f8; }
.ver-row.cur { background: #f3ede9; }
.vr-main { color: var(--ink); }
.vr-cur { font-size: 10px; color: var(--accent); font-weight: 700; }
.vr-diff { color: var(--ink2); font-size: 11px; margin-top: 3px; }
/* ---------------- L0 trip overview ---------------- */
.trip-head { padding: 4px 2px 10px; }
.trip-title { font-size: 16px; font-weight: 800; }
.trip-sub { font-size: 11.5px; color: var(--ink2); margin-top: 3px; }
.trip-day { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin: 8px 0; cursor: pointer;
background: var(--card); transition: border-color .15s, box-shadow .15s; }
.trip-day:hover { border-color: #c9cfda; box-shadow: 0 2px 8px rgba(20,24,35,.06); }
.trip-day.cur { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(181,83,60,.12); }
.td-top { display: flex; justify-content: space-between; align-items: baseline; }
.td-label { font-weight: 700; font-size: 13px; }
.td-end { font-size: 11px; color: var(--ink2); font-variant-numeric: tabular-nums; }
.td-bar { height: 6px; background: #e7ebf2; border-radius: 99px; overflow: hidden; margin: 7px 0 6px; }
.td-fill { height: 100%; background: var(--ok); border-radius: 99px; transition: width .5s ease; }
.td-fill.warn { background: var(--warn); }
.td-meta { display: flex; gap: 8px; align-items: center; font-size: 11.5px; color: var(--ink2); flex-wrap: wrap; }
.td-names { font-size: 11px; color: var(--ink2); margin-top: 5px; opacity: .85; }
/* ---------------- offline bundle card ---------------- */
.offline-card { border: 1px solid var(--line); border-radius: 12px; padding: 11px 13px; margin: 12px 0 6px; background: #f7f9fc; }
.oc-title { font-weight: 700; font-size: 12.5px; }
.oc-sub { font-size: 11.5px; color: var(--ink2); margin-top: 5px; line-height: 1.5; }
.oc-progress { font-family: ui-monospace, Menlo, monospace; font-size: 11px; }
.offline-card .btn { margin-top: 9px; }
/* ---------------- mobile: single pane + bottom tab bar ---------------- */
#mobiletabs { display: none; }
@media (max-width: 860px) {
.pane-hidden { display: none !important; }
/* topbar: crumb + badge on row 1, horizontally scrollable day tabs on row 2 */
#topbar { height: auto; flex-wrap: wrap; row-gap: 8px; padding: 9px 12px; }
.tb-left { flex: 1 1 auto; min-width: 0; }
.crumb { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.daytabs { margin-left: 0; max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 2px; }
.daytab { flex-shrink: 0; white-space: nowrap; font-size: 11.5px; padding: 5px 10px; }
.badge { font-size: 11.5px; padding: 4px 9px; }
/* one pane at a time: Plan | Map | Chat */
#app { top: 92px; bottom: 58px; grid-template-columns: 1fr; grid-template-rows: 1fr; }
#rail { border-right: 0; }
#chat { border-left: 0; }
#mobiletabs { display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
height: 58px; background: var(--card); border-top: 1px solid var(--line); }
#mobiletabs button { flex: 1; border: 0; background: none; font-size: 11px; color: var(--ink2); }
#mobiletabs button.on { color: var(--accent); font-weight: 700; box-shadow: inset 0 2.5px 0 var(--accent); }
#rail-body, #chat-body { padding: 10px; }
.rail-foot { padding: 10px 12px; }
.stop-card { padding: 9px 10px; }
.msg { font-size: 13px; padding: 9px 11px; }
#chat-input-row { padding: 10px; }
.tc { font-size: 11px; }
.scope-toggle { margin-left: 8px; }
.verpill { transform: scale(.92); }
.verlist { width: min(320px, calc(100vw - 24px)); right: 8px; }
/* map overlays */
#l3-editor { left: 8px; right: 8px; width: auto; bottom: 10px; }
#discover { left: 8px; right: 8px; top: auto; bottom: 8px; width: auto; max-height: 62%; }
.candpin { width: 21px; height: 21px; font-size: 11px; }
/* comparison dock above the tab bar */
#dock { width: calc(100vw - 24px); bottom: 66px; padding: 10px 12px; }
.dock-grid { grid-template-columns: 1fr 1fr; }
/* landing + detail modal */
.land-card { padding: 24px 20px; }
.land-card h1 { font-size: 21px; }
.scard-img { height: 80px; }
.modal-card.wide { width: min(560px, 96vw); max-height: 88vh; }
.d-img { height: 120px; }
.d-body { padding: 14px 16px 16px; }
}