:root{
  --bg:#0c141c; --panel:#131d27; --card:#1b2733; --pill:#28333e;
  --pill-txt:#c2cdd6; --txt:#eef3f7; --muted:#8d9ba6; --line:#26333d;
  --rust:#ec7c67; --accent:#63cabf; --white:#fff;
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}
*{box-sizing:border-box;}
html,body{height:100%;}
html,body{scrollbar-width:none;-ms-overflow-style:none;}
html::-webkit-scrollbar,body::-webkit-scrollbar{width:0;height:0;display:none;}
html,body{height:100%;overflow-x:hidden;max-width:100%;overscroll-behavior:none;}
/* iOS black-translucent shifts the doc up by inset-top; grow it back so the bottom isn't left blank. */
html{min-height:calc(100% + env(safe-area-inset-top, 0px));}
body{margin:0;background:var(--bg);color:var(--txt);font-family:var(--sans);
  -webkit-font-smoothing:antialiased;overflow:hidden;overscroll-behavior:none;-webkit-tap-highlight-color:transparent;}
.app{position:relative;height:100vh;width:100%;}
.map{position:absolute;inset:0;background:var(--bg);}

.notice{position:absolute;top:14px;left:14px;z-index:12;max-width:380px;
  background:rgba(19,29,39,.94);backdrop-filter:blur(8px);border:1px solid var(--line);
  border-radius:12px;padding:16px 18px;display:none;box-shadow:0 8px 24px rgba(0,0,0,.4);}
.notice.show{display:block;}
.notice h2{font-size:15px;margin:0 0 8px;color:var(--rust);}
.notice p{color:var(--muted);font-size:13px;line-height:1.55;margin:0 0 8px;}
.notice code{font-family:var(--mono);background:#0e1720;padding:1px 5px;border-radius:4px;color:var(--accent);font-size:12px;}
.notice ul{margin:6px 0 0;padding-left:16px;color:var(--muted);font-size:13px;line-height:1.6;}

.tabs{position:fixed;top:calc(14px + env(safe-area-inset-top, 0px));left:calc(14px + env(safe-area-inset-left, 0px));right:calc(14px + env(safe-area-inset-right, 0px));display:flex;gap:8px;
  overflow-x:auto;padding:4px;scrollbar-width:none;z-index:15;}
.tabs::-webkit-scrollbar{display:none;}
.tab{flex:none;border:none;cursor:pointer;font-family:var(--sans);font-size:14px;
  font-weight:600;color:var(--pill-txt);background:rgba(19,29,39,.9);
  backdrop-filter:blur(8px);padding:9px 16px;border-radius:999px;transition:.15s;
  white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.3);}
.tab:hover{background:rgba(40,51,62,.95);}
.tab.active{background:var(--white);color:#12313a;}

.panel{position:absolute;top:calc(62px + env(safe-area-inset-top, 0px));right:calc(14px + env(safe-area-inset-right, 0px));bottom:calc(14px + env(safe-area-inset-bottom, 0px));width:360px;max-width:calc(100% - 28px);
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  box-shadow:0 20px 50px rgba(0,0,0,.45);display:flex;flex-direction:column;overflow:hidden;z-index:15;}
.panel-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:none;padding:22px;scrollbar-width:none;-ms-overflow-style:none;}
.panel-scroll::-webkit-scrollbar{width:0;height:0;display:none;}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin:0 0 8px;}
.p-title{font-size:19px;font-weight:700;line-height:1.25;letter-spacing:-.02em;margin:0 0 10px;color:var(--txt);}
.p-summary{font-size:14px;color:var(--muted);line-height:1.5;margin:0 0 18px;}
.daystats{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);font-size:12px;
  color:#9fc3ef;background:rgba(66,133,244,.12);border:1px solid rgba(66,133,244,.35);
  border-radius:999px;padding:6px 14px;margin:0 0 18px;text-decoration:none;
  cursor:pointer;transition:background .15s,border-color .15s,transform .15s;}
.daystats:hover{background:rgba(66,133,244,.22);border-color:rgba(66,133,244,.6);transform:translateY(-1px);}
.daystats .go{width:13px;height:13px;margin-left:2px;opacity:.85;}
.leg{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:11.5px;
  color:var(--muted);padding:2px 0 10px 26px;position:relative;}
.leg::before{content:"";position:absolute;left:12px;top:-6px;bottom:4px;width:2px;
  background:rgba(66,133,244,.35);border-radius:1px;}
.leg .arrow{color:#4285F4;}
.leg.walk{color:#2fd6a0;}
.leg.walk::before{background:rgba(47,214,160,.4);}
.leg.walk .arrow{color:#2fd6a0;}
.openroute{display:inline-flex;align-items:center;gap:8px;background:var(--white);
  color:#12313a;border:none;border-radius:10px;padding:11px 16px;font-family:var(--sans);
  font-size:14px;font-weight:600;cursor:pointer;text-decoration:none;margin-bottom:22px;transition:.15s;}
.openroute:hover{transform:translateY(-1px);box-shadow:0 6px 16px rgba(0,0,0,.3);}
.openroute svg{width:16px;height:16px;}
.period{font-size:15px;font-weight:700;color:var(--txt);margin:18px 0 10px;}
.period:first-of-type{margin-top:0;}
.stop{display:flex;gap:11px;background:var(--card);border-radius:12px;padding:12px;margin-bottom:10px;position:relative;}
/* ✓ done. Absolutely placed so it can't push the row's layout around; the two lines it could
   overlap (time strip and name) carry the matching inset instead — scoped to .stop so the
   starred cards, which share .stop-name, keep their full width. */
.stop-done{position:absolute;top:8px;right:8px;width:24px;height:24px;border-radius:50%;padding:0;
  border:1.5px solid var(--line);background:rgba(15,23,32,.55);color:var(--muted);
  font-size:12px;line-height:1;display:grid;place-items:center;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:background .15s,border-color .15s,color .15s;}
.stop-done:hover{border-color:#7ed492;color:#7ed492;}
.stop-done.on{background:#2fa06a;border-color:#3fc487;color:#06180f;font-weight:700;
  box-shadow:0 0 0 3px rgba(47,160,106,.18);}
/* ✕ skip — sits directly under the ✓, same size so the text's padding-right still clears both.
   Bottom-right was tried and reverted: it read as a stray control rather than a pair with the ✓,
   and clearing it cost the card either an empty row underneath or a narrower text column.
   Red rather than green because the two mean different things: ✓ is a note to yourself that you've
   been somewhere (the stop stays on the map and in the day's distance), ✕ takes the stop OUT of the
   route and the route is recomputed straight past it. */
.stop-skip{position:absolute;top:38px;right:8px;width:24px;height:24px;border-radius:50%;padding:0;
  border:1.5px solid var(--line);background:rgba(15,23,32,.55);color:var(--muted);
  font-size:11px;line-height:1;display:grid;place-items:center;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:background .15s,border-color .15s,color .15s;}
.stop-skip:hover{border-color:#e2707a;color:#e2707a;}
.stop-skip.on{background:#b4404c;border-color:#d45563;color:#fff;font-weight:700;
  box-shadow:0 0 0 3px rgba(180,64,76,.18);}
/* Only the two lines the stacked buttons actually overlap need the inset — the address, notes and
   hours below them run the full width of the card. */
.stop .stop-time,.stop .stop-name{padding-right:28px;}
/* Done: you've been there, but it's still part of the day — dim it a little, don't cross it out. */
.stop.done{opacity:.62;}
/* Skipped: out of the route entirely — fade it back and strike the name. Both can be set at once,
   and skip's stronger fade is what you see. */
.stop.skip{opacity:.42;}
.stop.skip .stop-name{text-decoration:line-through;text-decoration-color:rgba(255,255,255,.35);}
.leg.skip{opacity:.28;}
.leg.done{opacity:.28;}   /* legacy hook — legs no longer use it, kept so old markup still fades */
.stop-num{flex:none;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  font-family:var(--mono);font-weight:700;font-size:12px;align-self:flex-start;margin-top:1px;box-shadow:0 1px 3px rgba(0,0,0,.4);}
.thumb{flex:none;width:56px;height:56px;border-radius:9px;display:grid;place-items:center;
  background:linear-gradient(135deg,#243440,#1a2731);border:1px solid #2c3a45;}
.thumb{overflow:hidden;}
.thumb svg{width:22px;height:22px;opacity:.5;}
.thumb img{width:100%;height:100%;object-fit:cover;display:block;}
a.stop.link{text-decoration:none;color:inherit;transition:background .15s;}
a.stop.link:hover{background:#23323e;}
.stop-rating{font-size:12px;color:var(--muted);margin-bottom:3px;}
.stop-rating .star{color:#e6b84f;}
.stop-body{min-width:0;}
.stop-time{font-family:var(--mono);font-size:12px;color:var(--accent);margin-bottom:2px;}
.stop-name{font-size:14.5px;font-weight:600;color:var(--txt);line-height:1.25;margin-bottom:3px;}
/* opening hours under a stop in the day list. The slot is emitted empty while the Details record
   is still being fetched, so :empty keeps it from adding a gap to rows that never fill. */
.stop-hours{font-size:12px;line-height:1.4;margin-bottom:3px;}
.stop-hours:empty{display:none;}
.sh-line{display:inline-flex;align-items:center;gap:4px;cursor:pointer;
  user-select:none;-webkit-user-select:none;padding:1px 0;}
.sh-b{font-weight:600;}
.sh-b.open{color:#7ed492;}
.sh-b.closed{color:var(--rust);}
.sh-r{color:var(--muted);}
.sh-car{color:var(--muted);font-size:10px;transition:transform .18s ease;}
.sh-line.open .sh-car{transform:rotate(180deg);}
.sh-full{display:block;color:var(--muted);font-size:11.5px;margin:2px 0 1px;
  padding-left:8px;border-left:2px solid var(--line);}
.sh-full[hidden]{display:none;}   /* an author display: wins over the UA [hidden] rule */
.stop-note{font-size:12.5px;color:var(--muted);line-height:1.4;}
.stop-note.flag{color:var(--rust);}
.stop-note.flag::before{content:"\26A0  ";}
.ebadge{display:inline-block;font-size:10px;font-weight:700;padding:1px 6px;border-radius:999px;vertical-align:middle;margin-left:6px;}
.ebadge.charge,.ebadge.cat-charge{background:#28381c;color:#b6e26a;}
.ebadge.stay,.ebadge.cat-stay{background:#2a2138;color:#c8a8f0;}
.ebadge.poi,.ebadge.cat-poi{background:#1e2f3a;color:#8fb8c4;}
.ebadge.cat-food{background:#39291a;color:#f0a868;}
.ebadge.cat-scenic{background:#182f38;color:#6ec6e6;}
.ebadge.cat-museum{background:#2c2038;color:#d0a0e0;}
.ebadge.cat-hike{background:#1e331e;color:#8fd08f;}
/* ---- edit mode ---- */
.edit-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:2px 0 4px;}
.edit-head h1{font-size:19px;margin:0;}
.edit-hint{font-size:12px;color:var(--muted);margin:0 0 14px;line-height:1.5;}
.ebtn{border:1px solid var(--line);background:#18242e;color:var(--txt);border-radius:9px;
  padding:8px 13px;font-size:13px;font-weight:600;cursor:pointer;transition:background .15s;}
.ebtn:hover{background:#20303b;}
.ebtn.primary{background:var(--accent);border-color:var(--accent);color:#06212b;}
.ebtn.primary:hover{filter:brightness(1.08);}
.ebtn.ghost{background:transparent;}
.elist{display:flex;flex-direction:column;gap:8px;}
.erow{position:relative;overflow:hidden;border-radius:12px;background:#7a2130;}
.erow .swipe-hint{position:absolute;right:16px;top:0;bottom:0;display:flex;align-items:center;color:#ffd7d7;font-size:12px;font-weight:700;pointer-events:none;}
.erow-inner{display:grid;grid-template-columns:auto auto 1fr auto auto;
  grid-template-areas:"handle icon name dwell del" "handle icon sub sub sub";
  align-items:center;column-gap:10px;row-gap:2px;padding:11px 12px;background:var(--card);position:relative;}
/* Reorder. The transition is scoped to #elist.reordering so it can't lag the swipe-to-delete
   drag, which drives .erow's transform directly and must stay glued to the finger. */
#elist.reordering .erow{transition:transform .19s cubic-bezier(.2,.7,.3,1);}
#elist.reordering .erow.dragging{transition:none;}   /* the held row tracks the pointer 1:1 */
#elist.reordering .erow.settling{transition:transform .17s cubic-bezier(.2,.7,.3,1);}
#elist.reordering .eleg{transition:opacity .15s;}
#elist.reordering .eleg.muted{opacity:.16;}
#elist.reordering{cursor:grabbing;}
.erow.dragging{z-index:5;opacity:.97;box-shadow:0 14px 30px rgba(0,0,0,.55);}
.erow.dragging .erow-inner{background:#20303b;}
.erow.settling{box-shadow:0 4px 12px rgba(0,0,0,.25);transition:transform .17s cubic-bezier(.2,.7,.3,1),box-shadow .17s ease;}
.ehandle{grid-area:handle;cursor:grab;color:var(--muted);font-size:17px;line-height:1;padding:4px 3px;touch-action:none;user-select:none;-webkit-user-select:none;}
/* The stop number rides in the grip's own column — stacked above ⠿ rather than given a column of
   its own, which would have taken ~24px out of the name on a phone. It's the same number as the
   pin on the map, so a row can be read straight against it. .ehandle keeps its grid-area
   declaration; it's inert now that the handle is a flex child rather than a grid item. */
.egrip{grid-area:handle;display:flex;flex-direction:column;align-items:center;gap:1px;
  cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;}
.enum{font-family:var(--mono);font-size:11px;font-weight:700;line-height:1;color:var(--accent);
  min-width:14px;text-align:center;user-select:none;-webkit-user-select:none;}
.ehandle:active{cursor:grabbing;}
.ethumb{grid-area:icon;width:34px;height:34px;border-radius:8px;overflow:hidden;display:grid;place-items:center;background:#0f1a22;}
.ethumb img{width:100%;height:100%;object-fit:cover;}
.ethumb svg{width:19px;height:19px;}
.erow-inner .en{grid-area:name;font-size:14px;font-weight:600;color:var(--txt);line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.erow-inner .en.ename{cursor:pointer;}
.erow-inner .en.ename:hover{color:var(--accent);}
.erow-inner .em{grid-area:sub;font-size:11.5px;color:var(--muted);line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.edel{grid-area:del;align-self:center;border:none;background:transparent;color:var(--muted);font-size:15px;cursor:pointer;padding:5px 7px;border-radius:8px;}
.edel:hover{background:#3a2130;color:#ff8a8a;}
.eadd{margin-top:15px;position:relative;}
.eadd input{width:100%;box-sizing:border-box;border:1px solid var(--line);background:#0f1a22;color:var(--txt);
  border-radius:10px;padding:11px 12px;font-size:14px;outline:none;}
.eadd input:focus{border-color:var(--accent);}
.eac{position:absolute;left:0;right:0;top:calc(100% + 6px);background:#12202a;border:1px solid var(--line);
  border-radius:10px;overflow:hidden;z-index:8;max-height:360px;overflow-y:auto;box-shadow:0 16px 40px rgba(0,0,0,.55);}
.eac .eac-item{padding:10px 12px;font-size:13px;color:var(--txt);cursor:pointer;border-bottom:1px solid rgba(255,255,255,.05);}
.eac .eac-item:last-child{border-bottom:none;}
.eac .eac-item small{display:block;color:var(--muted);font-size:11px;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.eac .eac-item:hover{background:#1b2c37;}
.ebusy{font-size:12px;color:var(--accent);margin-top:9px;}
.ebar{display:flex;gap:8px;margin-top:18px;}
.ebar .ebtn{flex:1;text-align:center;}
.eday-manage{display:flex;gap:8px;margin-top:10px;}
.eday-manage .ebtn{flex:1;text-align:center;font-size:12.5px;}
.ebtn.danger{color:#ff8a8a;border-color:#4a2530;}
.ebtn.danger:hover{background:#3a2130;}
/* duration picker overlay */
.edur{position:fixed;inset:0;background:rgba(6,12,18,.6);backdrop-filter:blur(3px);display:grid;place-items:center;z-index:60;}
.edur-card{background:#12202a;border:1px solid var(--line);border-radius:16px;padding:20px;width:min(320px,90vw);box-shadow:0 24px 60px rgba(0,0,0,.6);}
.edur-h{font-size:14px;color:var(--muted);text-align:center;margin-bottom:14px;line-height:1.5;}
.edur-h b{color:var(--txt);font-size:15px;}
.edur-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;}
.edur-grid button{border:1px solid var(--line);background:#18242e;color:var(--txt);border-radius:10px;padding:12px 8px;font-size:14px;font-weight:600;cursor:pointer;}
.edur-grid button:hover{background:var(--accent);border-color:var(--accent);color:#06212b;}
.edur-x{margin-top:12px;width:100%;border:none;background:transparent;color:var(--muted);font-size:13px;cursor:pointer;padding:8px;border-radius:8px;}
.edur-x:hover{background:#1b2c37;}
/* start-time control */
.estart{display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:10px 14px;margin:0 0 12px;}
.estart label{font-size:13px;font-weight:600;color:var(--muted);}
.estart input[type=time]{background:#0f1a22;border:1px solid var(--line);color:var(--txt);border-radius:8px;padding:7px 10px;font-size:14px;font-family:var(--mono);color-scheme:dark;}
.estart input[type=time].locked{opacity:.4;cursor:not-allowed;}
.estart:has(input.locked) label{opacity:.5;}
.estart-note{font-size:11.5px;color:var(--accent);margin:-6px 0 12px;padding:0 4px;line-height:1.4;}
/* dwell chip + category button on edit rows */
/* The dwell chip and (on chargers) the link chip share one grid cell, so adding the link button
   doesn't introduce a sixth column — and an empty column's gap — on every other row. */
.echips{grid-area:dwell;display:flex;align-items:center;gap:6px;}
.elink,.emove{border:1px solid var(--line);background:#18242e;color:var(--muted);font-size:12px;
  line-height:1;padding:5px 7px;border-radius:999px;cursor:pointer;}
.elink:hover,.emove:hover{background:#20303b;color:var(--txt);}
.elink.on{border-color:var(--accent);background:rgba(90,169,255,.12);}
.edwell{grid-area:dwell;align-self:center;border:1px solid var(--line);background:#18242e;color:var(--muted);font-size:12px;font-weight:600;
  border-radius:999px;padding:4px 9px;cursor:pointer;white-space:nowrap;}
.edwell:hover{background:#20303b;color:var(--txt);}
.edwell.anchored{border-color:var(--accent);color:var(--accent);background:rgba(90,169,255,.1);}
/* Move to another day. Shares the charger chip's pill styling by being named in those rules —
   NOT by also wearing .elink, which is what let the later querySelectorAll('.elink') binding in
   renderEditList() overwrite its onclick with chargerForm(). */
.emove{filter:grayscale(.25);}
/* A stop that's on its way to another day: parked under the list until Done, undoable until then. */
.emoved{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted);
  background:#131f28;border:1px dashed var(--line);border-radius:10px;padding:7px 10px;}
.emoved b{color:var(--accent);font-weight:700;}
.emoved .eundo{margin-left:auto;border:none;background:transparent;color:var(--accent);
  font-size:11.5px;font-weight:700;cursor:pointer;padding:3px 6px;border-radius:7px;}
.emoved .eundo:hover{background:#1b2c37;}
/* Day picker inside the .edur sheet — scrolls once a trip is longer than the card. */
.emove-list{display:flex;flex-direction:column;gap:7px;max-height:44vh;overflow-y:auto;}
.emove-list button{border:1px solid var(--line);background:#18242e;color:var(--txt);border-radius:10px;
  padding:10px 12px;font-size:13.5px;font-weight:600;cursor:pointer;text-align:left;}
.emove-list button:hover{background:var(--accent);border-color:var(--accent);color:#06212b;}
.emove-list small{display:block;font-weight:500;font-size:11px;color:var(--muted);margin-top:2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.emove-list button:hover small{color:#06212b;}
/* ★ Starred sits above the days in the same picker: it's a destination like any other, just not
   a dated one, so it reads in the list's gold rather than the accent the day buttons use. */
.emove-list .emove-star{border-color:rgba(255,209,102,.45);color:#ffd166;}
.emove-list .emove-star:hover{background:#ffd166;border-color:#ffd166;color:#2a2205;}
.emove-list .emove-star:hover small{color:#2a2205;}
.emoved.star b{color:#ffd166;}
.eleg{margin:5px 0 5px 46px;display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
  color:var(--muted);border:1px solid var(--line);background:#131f28;border-radius:999px;padding:3px 10px;cursor:pointer;}
.eleg:hover{color:var(--txt);border-color:var(--accent);}
.eleg.walk{color:#2fd6a0;border-color:rgba(47,214,160,.4);}
.etravel{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted);margin-top:10px;}
.etm{flex:1;border:1px solid var(--line);background:#131f28;color:var(--muted);border-radius:10px;padding:8px;font-size:12.5px;font-weight:600;cursor:pointer;}
.etm:hover{color:var(--txt);}
.etm.on{border-color:var(--accent);color:var(--accent);background:rgba(90,169,255,.1);}
.etime-row{display:flex;gap:8px;align-items:center;}
/* Custom dwell (h / m), revealed by the Custom cell in .edur-grid */
.edur-custom{display:flex;gap:8px;margin-top:8px;}
.edur-custom label{flex:1;display:flex;flex-direction:column;gap:4px;font-size:11px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;color:var(--muted);}
.edur-custom input{width:100%;box-sizing:border-box;background:#0f1a22;border:1px solid var(--line);
  color:var(--txt);border-radius:10px;padding:9px 10px;font-family:var(--mono);font-size:14px;outline:none;}
.edur-custom input:focus{border-color:var(--accent);}
.etime-row input[type=time]{flex:1;background:#0f1a22;border:1px solid var(--line);color:var(--txt);border-radius:10px;padding:9px 10px;font-family:var(--mono);font-size:14px;}
.ebadge.anchor{background:rgba(90,169,255,.14);color:var(--accent);}
.ebadge.anchor.late{background:rgba(255,138,138,.16);color:#ff8a8a;}
.stop-warn{font-size:12px;color:#ff9d7a;line-height:1.4;margin:3px 0 2px;font-weight:600;}
.ethumb.catbtn{cursor:pointer;position:relative;}
.ethumb.catbtn:hover{outline:2px solid var(--accent);outline-offset:1px;}
/* category grid used in add / change-type sheets */
.edur-lbl{font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);margin:14px 0 8px;text-align:left;}
.ecat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;}
.ecat{display:flex;flex-direction:column;align-items:center;gap:5px;border:1px solid var(--line);background:#18242e;color:var(--txt);
  border-radius:11px;padding:10px 4px;font-size:12px;font-weight:600;cursor:pointer;}
.ecat .eci{width:22px;height:22px;display:grid;place-items:center;}
.ecat .eci svg{width:22px;height:22px;}
.ecat:hover{background:#20303b;}
.ecat.on{border-color:var(--accent);background:#12303a;box-shadow:0 0 0 1px var(--accent) inset;}
.edur-grid button.on{border-color:var(--accent);background:#12303a;color:var(--txt);box-shadow:0 0 0 1px var(--accent) inset;}
.edur-row{display:flex;gap:8px;margin-top:16px;}
.edur-row .ebtn{flex:1;}
.chk{display:flex;gap:12px;align-items:flex-start;background:var(--card);border-radius:12px;padding:13px;margin-bottom:10px;cursor:pointer;}
.chk input{appearance:none;-webkit-appearance:none;margin:1px 0 0;width:20px;height:20px;flex:none;
  border:1.5px solid var(--muted);border-radius:5px;background:transparent;cursor:pointer;position:relative;}
.chk input:checked{background:var(--accent);border-color:var(--accent);}
.chk input:checked::after{content:"\2713";position:absolute;inset:0;display:grid;place-items:center;color:#0c141c;font-size:13px;font-weight:700;}
.chk-head{font-size:14px;font-weight:600;color:var(--txt);}
.chk.flag .chk-head{color:var(--rust);}
.chk-txt{font-size:12.5px;color:var(--muted);line-height:1.45;margin-top:2px;}
.chk.done .chk-head{text-decoration:line-through;opacity:.6;}
.chk.done .chk-txt{opacity:.5;}
.foot{font-size:11.5px;color:#5f6d78;line-height:1.5;margin-top:18px;border-top:1px solid var(--line);padding-top:14px;}

/* Bottom sheet: invisible wrapper on desktop, Google-Maps-style sheet on mobile. */
.sheet{display:contents;}
.grab,.phead{display:none;}
.sheet-glass{display:none;}

@media (max-width:760px){
  body{overflow:hidden;}
  .app{height:100%;}
  /* Full-screen map with explicit dimensions so Google Maps always has a sized container.
     In standalone PWA, 100vh spans the whole screen (behind the island + home indicator). */
  .map{position:fixed;top:0;left:0;width:100vw;height:100vh;margin:0;}
  .sheet{display:flex;flex-direction:column;position:fixed;left:0;right:0;bottom:0;z-index:30;
    background:transparent;
    border:1px solid rgba(255,255,255,.08);border-bottom:none;border-radius:18px 18px 0 0;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.06),0 -14px 44px rgba(0,0,0,.5);height:var(--sheet-h,82vh);
    transform:translateY(var(--sheet-y,60vh));transition:transform .28s cubic-bezier(.4,0,.2,1);
    will-change:transform;overflow:hidden;}
  /* Frosted map-glass on its OWN layer behind the sheet — a sibling, so the sheet's own
     transform can't trap it and it isn't an ancestor of the header (no nested blur). It
     tracks the sheet by reading the same --sheet-y / --sheet-h. */
  .sheet-glass{display:block;position:fixed;left:0;right:0;bottom:0;z-index:29;height:var(--sheet-h,82vh);
    transform:translateY(var(--sheet-y,60vh));transition:transform .28s cubic-bezier(.4,0,.2,1);will-change:transform;
    background:rgba(15,23,32,.72);-webkit-backdrop-filter:blur(26px) saturate(1.3);backdrop-filter:blur(26px) saturate(1.3);
    border-radius:18px 18px 0 0;pointer-events:none;}
  .sheet-glass.dragging{transition:none;}
  .sheet.dragging{transition:none;}
  .grab{display:flex;justify-content:center;padding:9px 0 5px;cursor:grab;touch-action:none;flex:none;}
  .grab span{width:42px;height:5px;border-radius:99px;background:#3a4b57;}
  /* WashHistoryPanel-style frosted header: STICKY inside the scroll container so its
     backdrop-filter shares the rows' compositing context — the only arrangement iOS will
     actually sample the scrolling content into (an outside overlay can't). The long feather
     mask makes rows dissolve smoothly under the title instead of hard-clipping. */
  /* padding-bottom is the feather zone the content dissolves through — halved (30→14) to
     tighten the gap between the route chip and the summary; mask stops track it. */
  .glasshead{position:sticky;top:0;z-index:5;padding-bottom:14px;
    background:rgba(15,23,32,.55);-webkit-backdrop-filter:blur(14px) saturate(1.5);backdrop-filter:blur(14px) saturate(1.5);
    -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 14px),rgba(0,0,0,.72) calc(100% - 10px),rgba(0,0,0,.42) calc(100% - 6px),rgba(0,0,0,.18) calc(100% - 3px),transparent);
    mask-image:linear-gradient(to bottom,#000 calc(100% - 14px),rgba(0,0,0,.72) calc(100% - 10px),rgba(0,0,0,.42) calc(100% - 6px),rgba(0,0,0,.18) calc(100% - 3px),transparent);}
  /* The frost used to stand DOWN for the whole gesture: starting a swipe puts a transform on
     #panelBody, which promotes it to its own compositing layer, and for a frame the header's
     backdrop-filter had nothing to sample and flashed clear before settling. Swapping in a
     near-opaque fill hid the flash — but it also meant the blur switched off the moment you
     started dragging and snapped back on release, which is the flicker between the header and the
     card you can see mid-swipe.
     Treat the cause instead. The flash came from the layer tree CHANGING under the header, not
     from the layer existing — the note above says it settles. So keep #panelBody on its own layer
     at all times (see .panel-body below): nothing is promoted when the gesture starts, there is
     nothing to re-composite, and the frost never has a frame where its backdrop is missing. The
     .swiping class stays (the JS still toggles it) as a one-line place to put this rule back if
     some device still flashes. */
  .tabs{position:relative;z-index:6;top:auto;left:auto;right:auto;margin:0;padding:6px 12px 6px;flex:none;touch-action:none;overscroll-behavior:contain;background:transparent;}
  .phead{display:block;padding:7px 18px 4px;flex:none;touch-action:none;background:transparent;}
  .phead .eyebrow{margin:0 0 4px;}
  .phead .p-title{font-size:16.5px;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  .phead .daystats{margin:6px 0 0;}
  /* Collapsed: hide the notes and give the chip room to clear the home indicator. */
  .p-summary{transition:opacity .25s ease;margin-top:2px;}
  .sheet.peeked .p-summary{opacity:0;}
  .sheet.peeked .phead{padding-bottom:calc(8px + env(safe-area-inset-bottom, 0px));}
  .panel{position:relative;inset:auto;flex:1;width:auto;max-width:none;margin:0;border:none;border-radius:0;box-shadow:none;min-height:0;background:transparent;}
  /* #panel is the scroll container; the sticky header lives inside it (so its blur can
     sample the rows). No top/side padding here — the header spans full width and the body
     carries the content insets. padding-bottom adds the off-screen slice for reachability. */
  .panel-scroll{padding:0 0 calc(24px + env(safe-area-inset-bottom,0px) + var(--sheet-lift, var(--sheet-y, 0px)) + var(--pager-h, 0px));touch-action:pan-y;}
  /* Promoted permanently, not on demand: this is the layer whose sudden appearance used to blank
     the header's backdrop-filter for a frame. Existing from the start costs one layer and buys a
     frost that never blinks. The inline translateX() the swipe sets overrides this while the card
     is moving and falls back to it when cleared, so the promotion is continuous either way. */
  .panel-body{padding:0 22px;transform:translateZ(0);}
  /* Neighbor-day preview that slides in during a horizontal swipe. Same padding as the
     live list (it borrows .panel-scroll) but static and non-interactive.
     It used to start at top:var(--head-h) — parked directly BENEATH the frosted header instead of
     running up behind it. That's the hard edge you see on the incoming card mid-swipe: the live
     pane scrolls under .glasshead and dissolves through its feather mask, while the peek was butted
     against the header's bottom edge with nothing for the blur to sample. So the two panes couldn't
     match no matter what the frost did.
     Start it at the top of the sheet instead and push its own body down by the same --head-h, so it
     lines up with the live pane exactly as before but now has content behind the glass. .glasshead
     is z-index 5 to the peek's 1, so the header still paints over it — it just has something to
     blur now.
     will-change:transform is gone from this rule on purpose. It promoted the peek to a persistent
     compositing layer of its own, which is the one structural difference left between it and the
     live pane — and the live pane's frost works. The swipe sets an inline transform anyway, so the
     pane still gets promoted for the duration of the gesture; it just isn't sitting on a separate
     layer before and after it. */
  .day-peek{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden!important;pointer-events:none;z-index:1;}
  /* No padding-top here on purpose. It was meant to reproduce the offset the peek used to get
     from its own `top`, but padding-top is exactly what stops .det-photo's -22px margin collapsing
     through — the collapse is what lifts the body up under the frost in the first place. makePeek()
     measures the live body's real top and writes it to the pane's inline `top` instead, so this box
     is identical to the live one and the hero tucks under the glass the same way. */
  .notice{position:absolute;top:calc(14px + env(safe-area-inset-top,0px));left:14px;right:14px;max-width:none;}
}
/* .brand (the bear logo, its drag styling and its ride/fade states) removed — there is no logo
   on screen and nothing rides the route. If any markup for it is left anywhere it now renders
   unstyled, so delete the element too rather than relying on this. */

a[href^="http://maps.google.com/maps"]{display:none !important}
a[href^="https://maps.google.com/maps"]{display:none !important}

.gmnoprint a, .gmnoprint span, .gm-style-cc {
    display:none;
}
.gmnoprint div {
    background:none !important;
}
.gm-style img[alt="Google"],
.remlist{list-style:none;margin:0 0 14px;padding:0;}
.rem{display:flex;align-items:flex-start;gap:10px;background:var(--card);border-radius:12px;
  padding:12px;margin-bottom:9px;border-left:3px solid transparent;}
.rem.imp{border-left-color:var(--rust);}
.rem-done{appearance:none;-webkit-appearance:none;margin:1px 0 0;width:20px;height:20px;flex:none;
  border:1.5px solid var(--muted);border-radius:5px;background:transparent;cursor:pointer;position:relative;}
.rem-done:checked{background:var(--accent);border-color:var(--accent);}
.rem-done:checked::after{content:"✓";position:absolute;inset:0;display:grid;place-items:center;color:#0c141c;font-size:13px;font-weight:700;}
.rem-body{flex:1;min-width:0;}
.rem-head{font-size:14px;font-weight:600;color:var(--txt);word-break:break-word;}
.rem.imp .rem-head{color:var(--rust);}
.rem-note{font-size:12.5px;color:var(--muted);line-height:1.45;margin-top:2px;word-break:break-word;}
.rem.done .rem-head{text-decoration:line-through;opacity:.55;}
.rem.done .rem-note{opacity:.45;}
.rem-btn{flex:none;background:none;border:none;color:var(--muted);cursor:pointer;font-size:14px;
  padding:2px 5px;line-height:1;border-radius:6px;transition:.12s;}
.rem-btn:hover{color:var(--txt);background:rgba(255,255,255,.06);}
.rem-btn.del:hover{color:var(--rust);}
.rem-edit{flex:1;display:flex;flex-direction:column;gap:8px;}
.rem-edit input,.addrem input{width:100%;background:#0e1720;border:1px solid var(--line);
  border-radius:8px;padding:9px 10px;color:var(--txt);font-family:var(--sans);font-size:14px;}
.rem-edit input:focus,.addrem input:focus{outline:none;border-color:var(--accent);}
.ed-row,.addrow{display:flex;align-items:center;gap:12px;}
.impcheck{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted);cursor:pointer;user-select:none;}
.impcheck input{width:16px;height:16px;accent-color:var(--rust);cursor:pointer;}
.btn-a{background:var(--accent);color:#0c141c;border:none;border-radius:8px;padding:8px 16px;
  font-weight:600;font-size:13px;cursor:pointer;font-family:var(--sans);}
.btn-b{background:none;border:1px solid var(--line);color:var(--muted);border-radius:8px;
  padding:8px 14px;font-size:13px;cursor:pointer;font-family:var(--sans);}
.addrem{background:var(--card);border:1px dashed var(--line);border-radius:12px;padding:12px;
  margin-bottom:14px;display:flex;flex-direction:column;gap:8px;}
.addrem .addrow{justify-content:space-between;}
.syncnote{font-size:11px;color:var(--muted);margin:0 0 12px;font-family:var(--mono);}
.syncnote.off{color:var(--rust);}
/* ---- in-page place detail ---- */
.det-photo{position:relative;margin:-22px -22px 14px;height:170px;background:#0e1720;overflow:hidden;}
.det-photo img{width:100%;height:100%;object-fit:cover;display:block;}
/* Multi-photo hero: a scroll-snapped filmstrip. Each slide is exactly one frame wide, so the
   dot index is just scrollLeft / clientWidth. */
.det-gal{display:flex;height:100%;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;overscroll-behavior-x:contain;}
.det-gal::-webkit-scrollbar{display:none;}
.det-gal img{flex:0 0 100%;width:100%;height:100%;object-fit:cover;scroll-snap-align:center;}
.det-dots{position:absolute;left:0;right:0;bottom:8px;display:flex;justify-content:center;gap:6px;
  pointer-events:none;}
.det-dots i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.45);
  box-shadow:0 1px 2px rgba(0,0,0,.5);transition:background .18s,transform .18s;}
.det-dots i.on{background:#fff;transform:scale(1.25);}
/* Photo credit for the visible slide. Google supplies these as ready-made anchors and requires
   them to be shown wherever the photo is; only the active one is visible. */
.det-att{position:absolute;left:10px;right:44px;bottom:6px;font-size:10px;line-height:1.3;
  color:rgba(255,255,255,.72);text-shadow:0 1px 3px rgba(0,0,0,.85);pointer-events:none;}
.det-att span{display:none;}
.det-att span.on{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.det-att a{color:inherit;pointer-events:auto;}
.det-gal{cursor:zoom-in;}

/* ---- fullscreen photo viewer ---- */
.photo-lb{position:fixed;inset:0;z-index:120;background:rgba(6,10,14,.97);
  display:flex;align-items:center;justify-content:center;}
.lb-gal{display:flex;width:100%;height:100%;overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;
  overscroll-behavior:contain;}
.lb-gal::-webkit-scrollbar{display:none;}
.lb-gal img{flex:0 0 100%;width:100%;height:100%;object-fit:contain;scroll-snap-align:center;}
.lb-dots{position:absolute;left:0;right:0;bottom:calc(18px + env(safe-area-inset-bottom,0px));
  display:flex;justify-content:center;gap:7px;pointer-events:none;}
.lb-dots i{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.4);transition:background .18s,transform .18s;}
.lb-dots i.on{background:#fff;transform:scale(1.25);}
.lb-count{position:absolute;top:calc(16px + env(safe-area-inset-top,0px));left:0;right:0;
  text-align:center;font-size:13px;color:rgba(255,255,255,.75);pointer-events:none;}
.lb-att{position:absolute;left:16px;right:16px;bottom:calc(38px + env(safe-area-inset-bottom,0px));
  text-align:center;font-size:11px;color:rgba(255,255,255,.6);}
.lb-att span{display:none;}
.lb-att span.on{display:block;}
.lb-att a{color:rgba(255,255,255,.8);}
.lb-close{position:absolute;top:calc(12px + env(safe-area-inset-top,0px));right:12px;
  width:38px;height:38px;border:none;border-radius:50%;background:rgba(0,0,0,.5);color:#fff;
  font-size:16px;cursor:pointer;display:grid;place-items:center;}
.det-photo .noimg{position:absolute;inset:0;display:grid;place-items:center;opacity:.35;}
.det-photo .noimg svg{width:44px;height:44px;}
.det-close{position:absolute;top:10px;right:10px;width:30px;height:30px;border:none;border-radius:50%;
  background:rgba(12,20,28,.75);color:var(--txt);font-size:15px;cursor:pointer;display:grid;place-items:center;}
.det-notes{background:#20303c;border-radius:12px;padding:12px 14px;margin:14px 0;}
.det-notes .nh{font-size:12px;font-weight:600;color:var(--muted);margin-bottom:4px;}
.det-notes .nt{font-size:13.5px;color:var(--txt);line-height:1.5;}
.det-notes.yours{background:#182631;border:1px solid var(--line);}
.det-notes.yours .empty{color:var(--muted);font-style:italic;}
.ynote-row{display:flex;gap:8px;margin-top:8px;}
.ynote-ta{width:100%;min-height:70px;resize:vertical;background:#0e1720;border:1px solid var(--line);
  border-radius:8px;padding:9px 10px;color:var(--txt);font-family:var(--sans);font-size:13.5px;line-height:1.5;}
.ynote-ta:focus{outline:none;border-color:var(--accent);}
.ynote-edit{background:none;border:1px solid var(--line);color:var(--muted);border-radius:8px;
  padding:5px 12px;font-size:12px;cursor:pointer;margin-top:8px;font-family:var(--sans);}
.ynote-edit:hover{color:var(--txt);border-color:var(--muted);}
.det-row{display:flex;align-items:flex-start;gap:10px;padding:9px 0;border-top:1px solid var(--line);
  font-size:13.5px;color:var(--txt);text-decoration:none;word-break:break-word;}
.det-row .ic{flex:none;width:16px;text-align:center;opacity:.6;}
a.det-row:hover{color:var(--accent);}
.copyrow{cursor:pointer;position:relative;}
.copyrow .copyval{flex:1;}
.copyrow .copytip{flex:none;align-self:center;display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:8px;color:var(--muted);opacity:.7;cursor:pointer;
  transition:color .15s,opacity .15s,background .15s;}
.copyrow .copytip svg{width:16px;height:16px;display:block;}
.copyrow:hover{color:var(--accent);}
.copyrow:hover .copytip{color:var(--accent);opacity:1;background:rgba(255,255,255,.07);}
.copyrow .copytip:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.copyrow.copied .copytip{color:var(--accent);opacity:1;background:transparent;}
.dnt a.dlink{color:var(--accent);text-decoration:none;word-break:break-all;}
.dnt a.dlink:hover{text-decoration:underline;}
.det-say{font-size:13px;color:var(--muted);line-height:1.5;margin:12px 0 4px;}
.det-stayname{font-size:14px;color:var(--txt);font-weight:600;margin:-4px 0 6px;}
.det-say b{color:var(--txt);font-weight:600;}
.det-gmap{display:inline-block;font-size:12.5px;color:var(--accent);text-decoration:none;margin:8px 0 78px;}
/* A sticky footer over scrolling content only reads as solid if the surface behind it IS solid.
   The original gradient to var(--panel) assumed that; on the mobile sheet the surface is
   translucent glass over the map, so the rows underneath stayed legible straight through it.
   The first attempt at a fix used .glasshead's feather MASK, which was worse: a mask makes the
   bar's own top edge semi-transparent, which is precisely where the phone-number row was showing
   through. So: a near-opaque bar in the sheet's own tone (it reads as part of the same surface,
   not a slab on top of it), and the soft edge moved OUTSIDE the bar as a ::before that fades up
   over content already scrolled past. Nothing the bar itself covers can bleed through. */
/* Anchored to the bottom of the glass, and now with the right number to do it.
   The geometry: .sheet is bottom:0 / height:var(--sheet-h) / translateY(var(--sheet-y)), so the
   scroll container's bottom edge hangs var(--sheet-y) px BELOW the screen. A sticky bottom inset
   is measured from THAT edge, which is why bottom:0 parked the bar a sheet-offset above where it
   looked like it should be, and bottom:-22px was a fixed guess at a moving number.
   That offset used to be --sheet-y itself. It can't be: setSheetY() writes the variable the
   instant a detent is chosen, but .sheet animates its transform to it over .28s, so for a third
   of a second the bar is anchored to where the sheet is GOING while the sheet is still where it
   was — and if a snap is interrupted the two never reconverge and the bar strands itself
   mid-card, with the notes and address flowing on underneath it (sticky keeps its slot in the
   flow, so nothing below moves out of the way). --sheet-lift is the same number measured off the
   sheet's real rect every frame it can move, so it cannot drift. --sheet-y stays as the fallback
   for the frame before the first measurement lands.
   Opaque fill (no backdrop-filter — WebKit won't paint it under .sheet-glass's border-radius +
   overflow anyway) and the home-indicator inset inside its own padding. */
.det-pager{position:sticky;bottom:var(--sheet-lift,var(--sheet-y,0px));z-index:5;margin:0 -22px;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 16px calc(12px + env(safe-area-inset-bottom,0px));
  background:#0f1720;}
.det-pager::before{content:'';position:absolute;left:0;right:0;bottom:100%;height:20px;pointer-events:none;
  background:linear-gradient(to top,#0f1720,rgba(15,23,32,0));}
/* The peek pane doesn't scroll, and sticky never lifts an element above its natural position, so
   the incoming card's bar needs pinning by hand — to the same line. */
.day-peek .det-pager{display:none;}   /* the mounted bar stays put while the cards slide under it */

/* ---- the stop pager, mounted on <body> --------------------------------------------------------
   Everything above describes an anchor that cannot be expressed from inside the card. A sticky
   inset is measured from the scrollport's CONTENT edge, so #panel's padding-bottom (which carries
   the sheet's off-screen slice for reachability) lifts the bar by that much again — ~230px, which
   is what parked it under the hero with the notes flowing on underneath. And position:fixed is no
   escape from in there, because .sheet declares will-change:transform and is therefore a
   containing block for fixed descendants.
   Out here there is no transformed ancestor and no scroller between the bar and the viewport:
   bottom:0 IS the bottom of the screen, and the home indicator is its own padding. Above .sheet
   (30) and its glass (29), below the lightbox (120) and the modals. */
#detPager{position:fixed;left:0;right:0;bottom:0;z-index:31;display:none;
  align-items:center;justify-content:space-between;gap:10px;
  padding:12px 16px calc(12px + env(safe-area-inset-bottom,0px));
  background:#0f1720;}
#detPager.on{display:flex;}
#detPager::before{content:'';position:absolute;left:0;right:0;bottom:100%;height:20px;pointer-events:none;
  background:linear-gradient(to top,#0f1720,rgba(15,23,32,0));}
/* Riding the sheet down to the peek bar, or opening explore, takes the bar with it — it belongs
   to the card, and the card isn't readable at those states. */
body:has(.sheet.peeked) #detPager,body:has(.sheet.exploring) #detPager{display:none;}
.pg-btn{border:none;border-radius:999px;padding:9px 14px;font-size:13px;font-weight:600;cursor:pointer;
  background:#28333e;color:var(--txt);display:inline-flex;align-items:center;gap:6px;}
.pg-btn.day{background:var(--white);color:#12313a;}
.pg-btn:disabled{opacity:.35;cursor:default;}
.pg-count{font-size:12px;color:var(--muted);font-family:var(--mono);}


/* ===== Explore / place search ============================================================= */
.explore-bar{position:fixed;z-index:20;top:calc(10px + env(safe-area-inset-top,0px));
  left:calc(12px + env(safe-area-inset-left,0px));right:calc(12px + 46px + 8px + env(safe-area-inset-right,0px));
  display:flex;align-items:center;gap:9px;height:46px;padding:0 12px;border-radius:23px;
  background:rgba(19,29,39,.82);-webkit-backdrop-filter:blur(16px) saturate(1.3);backdrop-filter:blur(16px) saturate(1.3);
  border:1px solid rgba(255,255,255,.09);box-shadow:0 6px 22px rgba(0,0,0,.4);color:var(--muted);}
.explore-ico{flex:none;color:var(--muted);cursor:pointer;}
#exploreInput{flex:1 1 auto;min-width:0;border:none;outline:none;background:transparent;color:var(--txt);
  font-family:var(--sans);font-size:16px;padding:0;-webkit-appearance:none;}
#exploreInput::placeholder{color:var(--muted);}
#exploreInput::-webkit-search-cancel-button{display:none;-webkit-appearance:none;}
.explore-clear{flex:none;display:none;border:none;background:rgba(255,255,255,.08);color:var(--pill-txt);
  width:26px;height:26px;border-radius:50%;font-size:13px;line-height:1;cursor:pointer;}
.explore-bar.has-text .explore-clear,.sheet.exploring~.explore-bar .explore-clear{display:block;}
body:has(.sheet.exploring) .explore-clear,.explore-bar.has-text .explore-clear{display:block;}
.explore-bar.loading .explore-ico{animation:exspin .8s linear infinite;transform-origin:50% 50%;}
@keyframes exspin{to{transform:rotate(360deg);}}

/* While exploring, the sheet's frosted header holds the results header instead of the day title.
   The glasshead itself STAYS (frost, feather mask, grab handle) so the results scroll behind it
   exactly like the itinerary does — only the day tabs are hidden. */
.sheet.exploring .glasshead .tabs{display:none;}

/* Lives inside the frosted glasshead now — no background/border of its own, so it reads as part
   of the same glass surface as the day header does. */
.ex-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:2px 4px 2px 0;background:transparent;border:none;}
.ex-htext{display:flex;flex-direction:column;line-height:1.15;min-width:0;}
.ex-count{color:var(--txt);font-weight:700;font-size:16px;}
.ex-q{color:var(--muted);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.ex-done{flex:none;border:none;background:var(--pill);color:var(--txt);font-weight:700;font-size:14px;
  padding:8px 16px;border-radius:999px;cursor:pointer;}
/* Full-bleed cards: span the sheet's width, separated by hairlines (Google-Maps style) rather
   than floating as inset boxes. */
.ex-list{padding:0 0 calc(24px + env(safe-area-inset-bottom,0px) + var(--sheet-lift,var(--sheet-y,0px)));}
.ex-card{display:flex;gap:13px;padding:14px 18px;margin:0;border-radius:0;background:transparent;
  border:none;border-bottom:1px solid var(--line);cursor:pointer;
  transition:background .15s ease,box-shadow .15s ease;}
.ex-card:active{background:rgba(255,255,255,.03);}
.ex-card.on{background:#1b2735;box-shadow:inset 3px 0 0 var(--accent);}
.ex-thumb{flex:none;width:74px;height:74px;border-radius:12px;background:#26333d center/cover no-repeat;
  position:relative;overflow:hidden;}
.ex-thumb:not(.has)::after{content:"";position:absolute;inset:0;background:
  radial-gradient(circle at 50% 42%, rgba(255,255,255,.10) 0 22%, transparent 23%);}
.ex-body{flex:1 1 auto;min-width:0;}
.ex-name{color:var(--txt);font-weight:700;font-size:16px;line-height:1.2;margin-bottom:3px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.ex-meta{color:var(--pill-txt);font-size:13.5px;margin-bottom:2px;}
.ex-star{color:#f5c518;font-weight:700;}
.ex-cnt{color:var(--muted);}
.ex-sub{color:var(--muted);font-size:12.5px;line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.ex-open{color:#7ed492;font-weight:600;}
.ex-closed{color:var(--rust);font-weight:600;}
.ex-actions{display:flex;gap:8px;margin-top:9px;}
.ex-add{border:none;background:var(--accent);color:#06231f;font-weight:700;font-size:13px;padding:7px 13px;border-radius:999px;cursor:pointer;}
.ex-link{display:inline-flex;align-items:center;text-decoration:none;background:var(--pill);color:var(--pill-txt);
  font-weight:600;font-size:13px;padding:7px 13px;border-radius:999px;}

/* ---- "already saved" chips -----------------------------------------------------------------
   Tinted outlines rather than filled pills: these sit two lines above the solid --accent "Add to
   day" button, and a second filled pill in the same card reads as a second call to action. They
   are status, not an offer. */
.ex-saved{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px;}
.ex-chip{display:inline-flex;align-items:center;font:inherit;font-size:11.5px;font-weight:700;
  line-height:1;padding:5px 9px;border-radius:999px;white-space:nowrap;
  background:transparent;border:1px solid var(--line);color:var(--pill-txt);}
.ex-chip.star{color:#ffd166;border-color:rgba(255,209,102,.45);background:rgba(255,209,102,.12);}
.ex-chip.day {color:var(--accent);border-color:rgba(99,202,191,.42);background:rgba(99,202,191,.12);}
button.ex-chip{cursor:pointer;-webkit-appearance:none;appearance:none;}
button.ex-chip:active{filter:brightness(1.25);}

/* Detail page banner. On mobile .det-head is hidden (the frosted phead carries the title), so
   this lands directly under the photo hero — the first thing you read about the place. */
.det-saved{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:14px 0 2px;
  padding:10px 12px;border-radius:12px;background:var(--card);border:1px solid var(--line);}
.det-saved .dsv-t{font-size:12px;font-weight:700;color:var(--muted);
  letter-spacing:.04em;text-transform:uppercase;font-family:var(--mono);}
.det-saved .ex-chip{font-size:12.5px;padding:6px 11px;}

/* day picker */
.ex-daypick{position:fixed;inset:0;z-index:80;display:flex;align-items:flex-end;justify-content:center;
  background:rgba(0,0,0,.5);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);}
.ex-daypick-card{width:100%;max-width:460px;margin:0 10px calc(14px + env(safe-area-inset-bottom,0px));
  background:var(--panel);border:1px solid var(--line);border-radius:20px;padding:16px;box-shadow:0 -10px 40px rgba(0,0,0,.5);
  animation:exrise .22s cubic-bezier(.4,0,.2,1);}
@keyframes exrise{from{transform:translateY(20px);opacity:0;}to{transform:none;opacity:1;}}
.ex-dp-title{color:var(--txt);font-weight:700;font-size:16px;margin:2px 4px 12px;}
/* Pulled up under the title rather than shrinking the title's own margin — the note only exists
   when the place is already saved somewhere, and the no-note spacing must not change with it. */
.ex-dp-note{color:var(--accent);font-size:12.5px;font-weight:600;margin:-7px 4px 12px;}
.ex-dp-days{display:flex;flex-direction:column;gap:7px;max-height:46vh;overflow-y:auto;}
.ex-dp-days button{display:flex;flex-direction:column;align-items:flex-start;gap:1px;text-align:left;
  border:1px solid var(--line);background:var(--card);color:var(--txt);border-radius:12px;padding:11px 14px;cursor:pointer;
  position:relative;}
.ex-dp-days button b{font-size:15px;}
.ex-dp-days button span{color:var(--muted);font-size:13px;}
/* Already there: tinted, with a ✓ on the right. Still clickable — see pickDay(). */
.ex-dp-days button.has{border-color:rgba(99,202,191,.45);background:rgba(99,202,191,.10);padding-right:38px;}
.ex-dp-days button.has span{color:var(--accent);}
.ex-dp-days button.has::after{content:"\2713";position:absolute;right:14px;top:50%;transform:translateY(-50%);
  color:var(--accent);font-size:16px;font-weight:700;}
.ex-dp-days button.ex-dp-star.has{border-color:rgba(255,209,102,.5);background:rgba(255,209,102,.10);}
.ex-dp-days button.ex-dp-star.has span,
.ex-dp-days button.ex-dp-star.has::after{color:#ffd166;}
.ex-dp-cancel{width:100%;margin-top:10px;border:none;background:var(--pill);color:var(--pill-txt);
  font-weight:700;font-size:15px;padding:12px;border-radius:12px;cursor:pointer;}

/* toast */
.ex-toast{position:fixed;z-index:90;left:50%;bottom:calc(28px + env(safe-area-inset-bottom,0px));transform:translate(-50%,14px);
  background:#eef3f7;color:#0c141c;font-weight:700;font-size:14px;padding:11px 20px;border-radius:999px;
  box-shadow:0 8px 30px rgba(0,0,0,.5);opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;}
.ex-toast.show{opacity:1;transform:translate(-50%,0);}

/* desktop: search bar sits top-left over the map; the day chips start after it (they're a
   fixed full-width bar, so without this they'd sit underneath the search bar) */
@media (min-width:761px){
  .explore-bar{top:14px;left:14px;right:auto;width:340px;height:44px;}
  .tabs{left:calc(14px + 340px + 10px + 44px + 10px);}   /* clear the search bar AND the GPS button */
}

/* editable day title + description (edit panel) */
.emeta{display:grid;grid-template-columns:1fr auto;gap:6px 8px;align-items:center;margin:10px 0 4px;}
.emeta label{grid-column:1/-1;color:var(--muted);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;margin-top:4px;}
.emeta #edTitle{grid-column:1;background:var(--card);border:1px solid var(--line);border-radius:10px;
  color:var(--txt);font-family:var(--sans);font-size:15px;font-weight:600;padding:10px 12px;outline:none;}
.emeta #edTitle:focus{border-color:var(--accent);}
.etitle-auto{grid-column:2;white-space:nowrap;padding:10px 12px;font-size:13px;}
.emeta #edSummary{grid-column:1/-1;background:var(--card);border:1px solid var(--line);border-radius:10px;
  color:var(--txt);font-family:var(--sans);font-size:14px;line-height:1.4;padding:10px 12px;outline:none;resize:vertical;}
.emeta #edSummary:focus{border-color:var(--accent);}

/* the results header sits in the glass header — give it the same side inset as the day title */
.sheet.exploring .phead{padding:7px 18px 10px;touch-action:none;}
/* Detail view, collapsed: the peek strip used to land on the top of the photo hero, which tells
   you nothing about which place is open. The sticky header carries a compact name + rating line
   instead. Hidden at full height, where the real title and photo are already on screen.
   (.phead is display:none on desktop, so this is mobile-only for free.) */
.det-mini{min-width:0;}
.det-mini-t{font-size:16.5px;font-weight:650;line-height:1.25;color:var(--txt);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.det-mini-s{font-size:12.5px;color:var(--muted);margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
/* The sticky mini header is the title on mobile at every height, so the body's copy of the
   eyebrow/title/rating would just be the same thing twice. Desktop keeps it: .phead (and so the
   mini) is display:none above 760px. */
@media (max-width:760px){
  .sheet.ex-detail .det-head{display:none;}
}
.sheet.exploring .ex-count{font-size:17px;}
/* results are full-bleed: drop the body's side padding while exploring */
.sheet.exploring .panel-body{padding:0;}
/* ...but the place-detail page is a normal page — give it the day view's gutters back, so the
   photo hero's -22px bleed lines up and the text isn't glued to the screen edges. */
.sheet.exploring.ex-detail .panel-body{padding:0 22px;}

/* ---- GPS / my-location button (same glass as the search bar) ---- */
.geo-btn{position:fixed;z-index:20;top:calc(10px + env(safe-area-inset-top,0px));
  right:calc(12px + env(safe-area-inset-right,0px));
  width:46px;height:46px;display:flex;align-items:center;justify-content:center;
  border-radius:50%;cursor:pointer;color:#4285F4;
  background:rgba(19,29,39,.82);-webkit-backdrop-filter:blur(16px) saturate(1.3);backdrop-filter:blur(16px) saturate(1.3);
  border:1px solid rgba(255,255,255,.09);box-shadow:0 6px 22px rgba(0,0,0,.4);
  transition:transform .12s ease,background .15s ease;}
.geo-btn:active{transform:scale(.93);}
.geo-btn.on{color:#7fb0ff;background:rgba(66,133,244,.18);border-color:rgba(66,133,244,.45);}
.geo-btn.locating svg{animation:geospin 1s linear infinite;transform-origin:50% 50%;}
@keyframes geospin{to{transform:rotate(360deg);}}
.geo-btn.denied{color:var(--muted);}

/* ===== Trip menu ========================================================================== */
/* The ☰ trigger sits directly under the GPS button, same glass treatment. */
.trip-btn{position:fixed;z-index:20;top:calc(10px + 46px + 8px + env(safe-area-inset-top,0px));
  right:calc(12px + env(safe-area-inset-right,0px));
  width:46px;height:46px;display:flex;align-items:center;justify-content:center;
  border-radius:50%;cursor:pointer;color:var(--pill-txt);
  background:rgba(19,29,39,.82);-webkit-backdrop-filter:blur(16px) saturate(1.3);backdrop-filter:blur(16px) saturate(1.3);
  border:1px solid rgba(255,255,255,.09);box-shadow:0 6px 22px rgba(0,0,0,.4);
  transition:transform .12s ease;}
.trip-btn:active{transform:scale(.93);}
/* Desktop: top-right corner, above the itinerary panel (.panel starts at top:62px, so the strip
   above it is free) and clear of the search bar / GPS / tabs, which all live on the LEFT of the
   top row on wide screens.
   This override must sit AFTER the base .trip-btn rule above — same specificity, so source order
   decides. Putting it in the earlier @media block up the file is what left the button stranded
   below the row: the base rule's top/right simply won. */
@media (min-width:761px){
  .trip-btn{top:14px;right:14px;left:auto;bottom:auto;width:44px;height:44px;}
}
.trip-menu{position:fixed;inset:0;z-index:60;background:rgba(6,10,14,.66);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  display:grid;place-items:center;padding:18px;
  padding-top:calc(18px + env(safe-area-inset-top,0px));padding-bottom:calc(18px + env(safe-area-inset-bottom,0px));}
.trip-card{width:min(430px,100%);max-height:100%;overflow-y:auto;background:#131d27;border:1px solid var(--line);
  border-radius:16px;padding:16px;box-shadow:0 18px 60px rgba(0,0,0,.55);display:flex;flex-direction:column;gap:10px;}
.trip-head{color:var(--txt);font-weight:700;font-size:17px;margin:2px 4px;}
.trip-list{display:flex;flex-direction:column;gap:7px;}
.trip-row{display:flex;flex-direction:column;align-items:flex-start;gap:1px;text-align:left;
  border:1px solid var(--line);background:var(--card);color:var(--txt);border-radius:12px;padding:11px 14px;cursor:pointer;}
.trip-row b{font-size:15px;}
.trip-row span{color:var(--muted);font-size:13px;}
.trip-row.cur{border-color:rgba(99,202,191,.45);background:rgba(99,202,191,.10);}
.trip-row.cur span{color:var(--accent);}
.trip-empty{color:var(--muted);font-size:13.5px;padding:8px 4px;}
.trip-new-toggle{border:1px dashed var(--line);background:transparent;color:var(--pill-txt);
  border-radius:12px;padding:11px 14px;cursor:pointer;font:inherit;font-weight:600;text-align:left;}
.trip-new{display:flex;flex-direction:column;gap:9px;border:1px solid var(--line);border-radius:12px;
  padding:12px;background:rgba(255,255,255,.02);}
.trip-new input{border:1px solid var(--line);background:#0e161e;color:var(--txt);border-radius:9px;
  padding:9px 11px;font:inherit;font-size:14px;outline:none;width:100%;box-sizing:border-box;}
.trip-new input:focus{border-color:var(--accent);}
.tn-l{display:flex;align-items:center;justify-content:space-between;gap:10px;color:var(--muted);font-size:13.5px;}
.tn-l input{width:56%;}
.tn-create{border:none;background:var(--accent);color:#06231f;border-radius:10px;padding:11px 14px;
  cursor:pointer;font:inherit;font-weight:700;}
.tn-err{color:#e2707a;font-size:13px;}
.trip-close{border:1px solid var(--line);background:transparent;color:var(--muted);border-radius:10px;
  padding:10px 14px;cursor:pointer;font:inherit;}

@media (min-width:761px){
  .geo-btn{top:14px;right:auto;left:calc(14px + 340px + 10px);width:44px;height:44px;}
}

/* ---- ★ Starred: the pill, the saved-place cards, and the star row in the day picker ---- */
.tab.star{font-size:15px;line-height:1;padding:9px 14px;color:#ffd166;}
.tab.star.active{background:#ffd166;color:#3a2c05;}

/* ★ list filter chip — sits between the blurb and the cards */
.sfav-filter{display:flex;margin:-6px 0 12px;}
.chip-tgl{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
  background:#18242e;color:var(--muted);border-radius:999px;padding:6px 12px;
  font-size:12.5px;font-weight:600;cursor:pointer;line-height:1;}
.chip-tgl:hover{background:#20303b;color:var(--txt);}
.chip-tgl.on{background:rgba(182,226,106,.12);border-color:rgba(182,226,106,.45);color:#b6e26a;}

.sfav-list{display:flex;flex-direction:column;gap:10px;margin-top:6px;}
.sfav{display:flex;gap:12px;padding:12px;border:1px solid var(--line);border-radius:14px;
  background:var(--card);cursor:pointer;transition:background .15s;}
.sfav:hover{background:#20303b;}
.sfav .thumb{flex:none;width:58px;height:58px;border-radius:10px;overflow:hidden;
  display:flex;align-items:center;justify-content:center;background:#0e1720;}
.sfav .thumb img{width:100%;height:100%;object-fit:cover;}
.sfav .thumb svg{width:26px;height:26px;}
.sfav .stop-body{min-width:0;flex:1;}
/* The note block on a ★ card: same component as the day-stop one, dialled down so it reads as
   part of the card rather than a panel sitting inside it. */
.sfav-notes{background:#182631;border:1px solid var(--line);border-radius:10px;
  padding:9px 11px;margin:9px 0 0;}
/* No note yet → no panel at all, just a quiet link that sits on the card's own background. */
.sfav-notes.bare{background:none;border:none;padding:0;margin:7px 0 0;}
.sfav-notes.bare .ynote-edit{margin:0;padding:3px 0;border:none;background:none;
  font-size:12px;color:var(--muted);opacity:.75;}
.sfav-notes.bare .ynote-edit:hover{color:var(--accent);opacity:1;border:none;background:none;}
.sfav-notes .nh{font-size:11px;}
.sfav-notes .nt{font-size:12.5px;}
.sfav-notes .empty{color:var(--muted);font-style:italic;}
.sfav-notes .ynote-ta{min-height:56px;font-size:13px;}
/* Distance from you, in the \u2605 card's meta line. Accent-coloured because it's the thing the list
   is now ordered by \u2014 it should be the part of that line your eye lands on. */
.sfav-dist{color:var(--accent);font-weight:700;white-space:nowrap;}
.sfav-sorted{display:block;margin-top:3px;font-size:11.5px;color:var(--muted);}
.sfav-actions{display:flex;gap:6px;align-items:center;margin-top:10px;}
.sfav-actions .ebtn{padding:6px 10px;font-size:12.5px;}
.sfav-actions .sfav-move{flex:1;text-align:center;}
.sfav-actions .sfav-del{flex:none;padding:6px 9px;}

.ex-dp-star b{color:#ffd166;}

/* ---- single tapped POI: Done sits on the card, and the card is the whole sheet ---- */
.ex-card-done{margin-left:auto;flex:none;border:none;cursor:pointer;
  background:var(--pill);color:var(--txt);font-weight:700;font-size:13px;
  padding:7px 14px;border-radius:999px;}
.ex-card-done:hover{background:#33404c;}
.sheet.one-place .ex-card{border-bottom:none;}
.sheet.one-place .ex-card.on{background:transparent;}   /* nothing to distinguish — it's the only one */

/* ---- explore card: ★ on the action row, Done pinned top-right (single place) ---- */
.ex-card{position:relative;}
.ex-fav{margin-left:auto;flex:none;border:1px solid var(--line);background:transparent;color:var(--muted);
  font-size:15px;line-height:1;padding:7px 11px;border-radius:999px;cursor:pointer;transition:all .15s;}
.ex-fav:hover{background:#20303b;color:#ffd166;}
.ex-fav.on{background:#ffd166;border-color:#ffd166;color:#3a2c05;}
.ex-card-done{position:absolute;top:12px;right:14px;z-index:2;margin:0;flex:none;border:none;cursor:pointer;
  background:var(--pill);color:var(--txt);font-weight:700;font-size:13px;padding:6px 13px;border-radius:999px;}
.ex-card-done:hover{background:#33404c;}
.sheet.one-place .ex-name{padding-right:74px;}   /* keep the title clear of the Done pill */

/* detail page for a searched / tapped place */
.ex-det-actions{display:flex;align-items:center;gap:8px;margin:16px 0 4px;}
.ex-det-actions .ex-add{padding:9px 16px;font-size:14px;}
.ex-det-actions .ex-fav{padding:9px 13px;font-size:16px;}
.det-photo .noimg{display:flex;align-items:center;justify-content:center;height:100%;font-size:34px;color:var(--muted);}

/* the autocomplete dropdown hangs off the search bar (which is position:fixed → a containing block) */
.explore-bar .eac{top:calc(100% + 8px);border-radius:14px;overflow:hidden;z-index:30;box-shadow:0 14px 30px rgba(0,0,0,.45);}

/* ---- iOS: never let focusing a field zoom the page ------------------------------------------
   Safari auto-zooms whenever you focus a text control whose font-size is under 16px — and in a
   fixed-layout PWA like this there's nothing to pinch back out against, so you're stuck zoomed
   in. Every edit-mode field was 12–15px, hence the trap. Bumping them to 16px on touch devices
   is the fix Apple actually intends (maximum-scale=1 / user-scalable=no would also work, but it
   disables pinch-zoom for everyone, which is an accessibility regression).
   !important is deliberate: several of the rules being overridden are ID-scoped (.emeta #edTitle),
   so a plain element selector would lose on specificity. */
@media (pointer: coarse){
  input[type="text"], input[type="search"], input[type="time"], input[type="number"],
  input[type="url"], input[type="email"], input[type="tel"], input:not([type]),
  textarea, select{ font-size:16px !important; }
}

/* ---- ★ overlay toggle: pinned to the header's top-right, under the day pills ---- */
.phead{position:relative;}
.starstoggle{position:absolute;top:6px;right:18px;z-index:3;
  display:inline-flex;align-items:center;gap:5px;cursor:pointer;
  border:1px solid var(--line);background:rgba(16,26,34,.72);color:var(--muted);
  font-family:var(--sans);font-size:13px;font-weight:700;line-height:1;
  padding:8px 13px;border-radius:999px;transition:all .15s;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);}
.starstoggle:hover{background:#20303b;color:#ffd166;}
.starstoggle .n{font-weight:600;opacity:.8;}
.starstoggle.on{background:#ffd166;border-color:#ffd166;color:#3a2c05;}
.starstoggle.on .n{opacity:.7;}
.phead .p-title{padding-right:76px;}      /* keep the title clear of the pill */
/* Desktop: .phead is hidden and the header sits in .panel-body, so anchor the pill there. */
@media (min-width:761px){
  .panel-body{position:relative;}
  .starstoggle{top:0;right:0;}
  .panel-body>.p-title{padding-right:76px;}
}

/* ---- opening hours on the place detail page ---- */
.det-hours{cursor:pointer;user-select:none;-webkit-user-select:none;}
.det-htoday{flex:1;min-width:0;}
.det-hcar{flex:none;color:var(--muted);font-size:12px;transition:transform .18s ease;}
.det-hours.open .det-hcar{transform:rotate(180deg);}
.det-hweek{margin:2px 0 4px;padding:8px 10px 10px 34px;border-bottom:1px solid var(--line);}
.det-hrow{display:flex;justify-content:space-between;gap:14px;
  font-size:13.5px;color:var(--muted);padding:4px 0;}
.det-hrow span:first-child{flex:none;min-width:92px;}
.det-hrow span:last-child{text-align:right;}
.det-hrow.today{color:var(--txt);font-weight:700;}
