/* assets/css/map.css: /map's own styles (welcome_map.php), moved out of the page in
   One Map stage 2.5 (6 October 2026). They were 173 KB of inline CSS that every visit
   carried in the HTML, the front door's guests included; as a file they are fetched
   once and cached (?v= is the file's mtime, like style.css). Loaded right after the
   page's one PHP-dependent rule (the ?goto= hero hide), in the same place the block
   stood, so the cascade is unchanged. Checks read it through pg_map_source(). */
  html,body{margin:0;height:100%;background:var(--pg-map-void);color:var(--pg-text);
    font-family:var(--pg-font-body);overflow:hidden}
  /* Full-bleed map behind everything. When a banner is on top (live-trip strip
     sets --live-h), the map's TOP edge drops with the chrome so the map is framed
     in the visible band, not hidden under the opaque strip (Jorg 2026-07-14). */
  #pg-map{position:fixed;top:var(--live-h,0px);left:0;right:0;bottom:0;z-index:0;background:var(--pg-map-void);-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}   /* iOS: a touch-and-hold must NOT start the native callout/magnifier — that fires touchcancel and would abort the long-press-to-select before it fires (Jorg 2026-07-18) */
  /* Space backdrop for the satellite 3D globe: a CSS starfield behind a transparent map. */
  #pg-stars{position:fixed;inset:0;z-index:0;display:none;background-color:#05070d;
    background-image:radial-gradient(1px 1px at 20% 30%,#fff,transparent),radial-gradient(1px 1px at 70% 62%,#cfe0ff,transparent),radial-gradient(1.6px 1.6px at 42% 82%,#fff,transparent),radial-gradient(1px 1px at 85% 22%,#fff,transparent),radial-gradient(1px 1px at 55% 12%,#e8eeff,transparent),radial-gradient(1.4px 1.4px at 12% 72%,#fff,transparent),radial-gradient(1px 1px at 33% 52%,#dfe8ff,transparent),radial-gradient(1px 1px at 78% 84%,#fff,transparent),radial-gradient(1px 1px at 8% 18%,#fff,transparent),radial-gradient(1.3px 1.3px at 62% 8%,#dfe8ff,transparent),radial-gradient(1px 1px at 92% 48%,#fff,transparent),radial-gradient(1px 1px at 48% 44%,#cfe0ff,transparent),radial-gradient(1.5px 1.5px at 27% 66%,#fff,transparent),radial-gradient(1px 1px at 74% 36%,#fff,transparent),radial-gradient(1px 1px at 5% 52%,#e8eeff,transparent),radial-gradient(1.2px 1.2px at 88% 68%,#fff,transparent),radial-gradient(1px 1px at 38% 22%,#fff,transparent),radial-gradient(1px 1px at 63% 90%,#dfe8ff,transparent),radial-gradient(1.4px 1.4px at 17% 92%,#fff,transparent),radial-gradient(1px 1px at 96% 12%,#fff,transparent),radial-gradient(1px 1px at 50% 72%,#cfe0ff,transparent),radial-gradient(1px 1px at 30% 6%,#fff,transparent)}
  body.space-on #pg-map{background:transparent}
  /* Cold-load veil: sits between the map (z0) and the chrome/hero (z2+), so the
     brand chrome renders instantly over a calm graticule instead of a black hole.
     .light = boot base is mono/street (light void); JS adds it before first paint. */
  #pg-boot{position:fixed;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;pointer-events:none;
    background:repeating-linear-gradient(0deg,rgba(255,255,255,.04) 0 1px,transparent 1px 72px),
               repeating-linear-gradient(90deg,rgba(255,255,255,.04) 0 1px,transparent 1px 72px),#05070d;
    transition:opacity .5s ease}
  #pg-boot.light{background:repeating-linear-gradient(0deg,rgba(12,16,20,.06) 0 1px,transparent 1px 72px),
               repeating-linear-gradient(90deg,rgba(12,16,20,.06) 0 1px,transparent 1px 72px),#e8ecf1}
  #pg-boot.off{opacity:0}
  #pg-boot img{width:56px;height:56px;opacity:.6;animation:pg-boot-pulse 1.6s ease-in-out infinite}
  @keyframes pg-boot-pulse{0%,100%{transform:scale(1);opacity:.45}50%{transform:scale(1.1);opacity:.85}}
  @media (prefers-reduced-motion: reduce){#pg-boot img{animation:none}}
  #pg-map .maplibregl-ctrl-attrib{font-size:9px;opacity:.55}
  .pg-hero,.pg-stats,.pg-card{position:fixed;z-index:2}
  /* Top bar */
  /* Chrome sits ABOVE the hero scrim (z 5 > 2) so the logo is never veiled by it. */
  /* Unified top bar (Phase 1, 2026-07-12): NO bar surface on the map lens — the
     controls float on the map, each on its own frosted chip, flush to the top
     edge at the data bar's height (--pg-chrome-h). Same anatomy as .rail-top: brand ·
     fixed-width search · [modes float below] · lens chip · tasks · avatar. */
  /* z7: the chrome (and its search dropdown) sits ABOVE the mode panel (z6) —
     the results were sliding behind the panel window (Jorg 2026-07-12). */
  /* Where anything floating is allowed to start: the chrome is --pg-chrome-h tall and
     sits at --live-h, so this is its bottom edge plus the same 16px of air the
     left/right gutters use. It exists because that offset was written FIVE
     different ways — the card at 72, the lightbox at 74, the dock at 76, the
     trips bar at 122, and the mode rail and timezone bar at 64 — so the rail
     ended up clearing the Pelgrim logo by eight pixels and looked stuck to it
     (Jorg, 2026-07-25). New floating surfaces use this, not another number. */
  :root{--pg-below-chrome:calc(var(--live-h,0px) + var(--pg-chrome-h,48px) + 16px)}   /* was a flat 72 = the old 56px bar + 16px of air */
  /* ⛔ z-index 13, RAISED FROM 7 (2026-08-30). Jorg: "if I use the search box, the
     drop-down goes behind the flights, hotels and destinations buttons." The
     dropdown carries z-index 20 and it never mattered: `.pg-chrome` is `fixed` with
     a z-index, so it OPENS A STACKING CONTEXT and the 20 is measured inside it,
     against its siblings — never against `.pg-modes` (9) or the airport card (10).
     Exactly the same shape as the rail's flyout, found the same day.
     ⚠ 13 clears .pg-modes (9), the airport card (10), .ar-listing (11), #pg-mapctl
     (11) and the rail (12), and stays below the phone scrim (1000) and drawer
     (1001). The bar occupies the top --pg-chrome-h and the rail starts at the same
     token, so raising it
     over the rail costs nothing: they do not overlap. */
  /* ⚠ HEIGHT COMES FROM --pg-chrome-h (assets/style.css :root), because the rail
     and the cards below both position off it. See that token's note. */
  .pg-chrome{position:fixed;z-index:13;top:var(--live-h,0px);left:0;right:0;display:flex;align-items:center;justify-content:space-between;gap:14px;
    height:var(--pg-chrome-h,48px);box-sizing:border-box;padding:0 14px;background:none}
  .pg-left{display:flex;align-items:center;gap:12px;flex:none}   /* logo + About drawer, like the data lens .rail-left */
  .pg-logo{flex:none}
  /* Logo: no box — plain white wordmark that sits ON TOP, like the H1, with a
     strong text-shadow so it holds over bright imagery. */
  /* Matched to the data chrome's .rail-brand (2026-07-12): same 22px compass
     mark, same 1.05rem/700 body type, mark in currentColor — one brand. */
  .pg-logo{display:inline-flex;align-items:center;gap:.5rem;font-family:var(--pg-font-body);font-weight:700;font-size:1.28rem;letter-spacing:0;cursor:pointer;white-space:nowrap;
    color:var(--pg-text);text-shadow:0 1px 3px rgba(0,0,0,.75), 0 2px 22px rgba(0,0,0,.55)}
  .pg-logo .spark{color:#e8a64a;display:inline-flex}   /* amber compass on both lenses (Jorg 2026-07-12) */
  /* Search + mode bar are a centered pair; logo pins left, controls pin right. */
  .pg-center{display:flex;align-items:center;gap:8px;min-width:0;flex:1 1 auto}
  /* Search fills a flexible wrapper (grows to a cap, shrinks to nothing) so it
     yields space before the rigid mode menu can be pushed off the bar. */
  /* Fixed-width band, identical to the data chrome (2026-07-12): same size at
     every window width — no more huge-on-half-4K / tiny-on-full-4K. */
  .pg-search-wrap{position:relative;display:none;flex:0 1 420px;min-width:220px;max-width:520px}   /* shown only once you're exploring (not on the hero) */
  /* Sized/typed to match the data chrome's nav-search input (2026-07-12):
     13px type, 6px radius, ⌕ inside-left (the icon pseudo below, wide screens). */
  /* Darker glass + brighter placeholder (Jorg 2026-07-12): over light basemap
     areas (Greenland!) the .5 glass washed the resting text out. */
  /* ⚠ 34px, DOWN FROM 38, AND THE FONT IS UNTOUCHED AT 13px. Jorg asked for a
     shorter bar without smaller type, so the padding goes and the text does not:
     34 - 2px borders - 12px padding leaves an 18px content box for a 13px face. */
  .pg-search{width:100%;min-width:0;height:34px;font-family:var(--pg-font-body);font-size:13px;color:var(--pg-text);box-sizing:border-box;
    background:rgba(12,16,20,.55);border:1px solid rgba(255,255,255,.16);border-radius:8px;padding:6px 12px 6px 30px;
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  .pg-search::placeholder{color:#b7bfc7}
  /* Phone-only clear/close ✕ (2026-07-16) — hidden on desktop so it can't stack below the field. */
  .pg-search-x{display:none}
  @media(min-width:1181px){
    .pg-search-wrap::before{content:'⌕';position:absolute;left:10px;top:50%;transform:translateY(-50%);font-size:15px;color:var(--pg-muted);pointer-events:none;line-height:1;z-index:1}
  }
  /* (placeholder colour set above — brighter for light basemaps, 2026-07-12) */
  .pg-search:focus{outline:none;border-color:rgba(255,255,255,.32);background:rgba(12,16,20,.72)}
  /* Collapsed search: a magnifying-glass button that opens the input as a popover,
     used when the bar is too narrow to hold an inline field without cramping the chrome. */
  .pg-search-icon{display:none;width:42px;height:42px;box-sizing:border-box;align-items:center;justify-content:center;font-size:19px;
    color:var(--pg-text);background:rgba(12,16,20,.5);border:1px solid rgba(255,255,255,.14);border-radius:8px;cursor:pointer;
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  .pg-search-icon:hover{background:rgba(12,16,20,.72)}
  .pg-search-results{position:absolute;top:calc(100% + 6px);left:0;width:clamp(300px,30vw,520px);max-height:360px;overflow:auto;display:none;z-index:20;
    background:rgba(16,20,25,.96);border:1px solid var(--pg-hairline);border-radius:10px;padding:6px;
    backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);box-shadow:0 14px 40px rgba(0,0,0,.5)}
  .pg-search-results.open{display:block}
  /* Search sits DEAD-CENTER of the bar on desktop (same rule as the data lens'
     .rail-search): absolute to the fixed chrome, so logo+About on the left and
     controls on the right don't shift it off-centre (Jorg 2026-07-12). JS still
     toggles display; this only changes where it sits when shown. */
  @media (min-width:769px){
    .pg-search-wrap{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);flex:none;width:min(520px,42vw);max-width:520px;min-width:0}
    /* Unify the top-bar chip cluster on the map lens (Jorg 2026-07-16): About + Demo
       match the 38px of Data/notifications/avatar/search, so nothing sits proud. */
    .pg-chrome .lt-demo{height:38px;box-sizing:border-box;padding:0 11px}
  }
  /* Dark scrollbars EVERYWHERE on the map surface (Jorg 2026-07-12: the search
     dropdown scrolled white/grey — make the dark thumb the house theme for every
     window on this page: panel body, drops, cards, menus, the lot). */
  *{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.30) rgba(16,20,25,.35)}
  *::-webkit-scrollbar{width:9px;height:9px}
  *::-webkit-scrollbar-track{background:rgba(16,20,25,.35)}
  *::-webkit-scrollbar-thumb{background:rgba(255,255,255,.28);border-radius:5px}
  *::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.42)}
  /* "See all results" row: pinned first, visually a door not a result. */
  .pg-sr-all{border-bottom:1px solid rgba(255,255,255,.08);margin-bottom:4px}
  .pg-sr-all .t{color:var(--pg-amber)}
  /* ↺ Reset search (Air mode): styled like the filter selects it sits under. */
  .pg-ar-rst{cursor:pointer;text-align:center;color:var(--pg-body);background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline)}
  .pg-ar-rst:hover{background:rgba(255,255,255,.14);color:var(--pg-text)}
  /* ── In-map auth panel (Jorg 2026-07-12): log in / create account without
        leaving the map environment. Posts to login.php, and every outcome comes
        back here; since PEL-29 it is the only sign-in box. ── */
  .pg-auth{position:fixed;inset:0;z-index:60;display:none;align-items:center;justify-content:center;background:rgba(5,7,13,.55);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
  .pg-auth.open{display:flex}
  .pg-auth-box{position:relative;width:min(92vw,380px);max-height:88vh;overflow:auto;background:rgba(16,20,25,.97);border:1px solid var(--pg-hairline);border-radius:14px;padding:22px;box-shadow:0 18px 50px rgba(0,0,0,.55)}
  .pg-auth-tabs{display:flex;gap:4px;margin-bottom:14px;background:rgba(255,255,255,.06);border-radius:9px;padding:3px}
  .pg-auth-tabs button{flex:1;padding:8px 6px;border:0;border-radius:7px;background:none;color:var(--pg-body);font-weight:600;font-size:13px;cursor:pointer}
  .pg-auth-tabs button.on{background:var(--pg-amber);color:#1b1405}
  .pg-auth-f label{display:block;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--pg-muted);margin:10px 0 4px}
  .pg-auth-f label .opt{text-transform:none;letter-spacing:0}
  .pg-auth-f input{width:100%;box-sizing:border-box;font-size:14px;color:var(--pg-text);background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);border-radius:8px;padding:9px 11px;outline:none}
  .pg-auth-f input:focus{border-color:rgba(255,255,255,.35)}
  .pg-auth-cta{width:100%;margin-top:14px;padding:10px;border:0;border-radius:9px;background:var(--pg-amber);color:#1b1405;font-weight:700;font-size:14px;cursor:pointer}
  .pg-auth-cta:hover{filter:brightness(1.08)}
  .pg-auth-note{margin-top:8px;font-size:11.5px;color:var(--pg-muted)}
  .pg-auth-or{margin:14px 0 8px;text-align:center;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--pg-muted)}
  .pg-auth-oauth{display:flex;gap:8px}
  .pg-auth-oauth a{flex:1;text-align:center;padding:9px;border-radius:9px;border:1px solid var(--pg-hairline);background:rgba(255,255,255,.06);color:var(--pg-text);text-decoration:none;font-size:13px;font-weight:600}
  .pg-auth-oauth a:hover{background:rgba(255,255,255,.12)}
  .pg-auth-x{position:absolute;top:10px;right:10px;background:none;border:0;color:var(--pg-muted);font-size:15px;cursor:pointer}
  .pg-auth-x:hover{color:var(--pg-text)}
  .pg-auth-err{margin:2px 0 8px;padding:8px 11px;border-radius:8px;background:rgba(220,60,60,.14);border:1px solid rgba(220,60,60,.42);color:#f2b1b1;font-size:12.5px;line-height:1.4}
  /* PEL-29: what login.php's own page used to say now says here. */
  .pg-auth-ok{margin:2px 0 10px;padding:8px 11px;border-radius:8px;background:rgba(34,197,94,.12);border:1px solid rgba(34,197,94,.4);color:#bbf7d0;font-size:12.5px;line-height:1.4}
  .pg-auth-h{font-size:18px;font-weight:800;color:var(--pg-text);margin:2px 28px 8px 0}
  .pg-auth-p{font-size:13px;line-height:1.5;color:var(--pg-body);margin:0 0 10px}
  .pg-auth-p a,.pg-auth-info a,.pg-auth-note a{color:var(--pg-amber)}
  .pg-auth-p strong{color:var(--pg-text)}
  .pg-auth-info{margin:4px 0 0;padding:10px 12px;border-radius:8px;background:rgba(232,166,74,.10);border:1px solid rgba(232,166,74,.35);color:#e8ceab;font-size:12.5px;line-height:1.5}
  .pg-auth-f label.pg-auth-optin{display:flex;gap:8px;align-items:flex-start;margin:12px 0 0;font-size:12px;letter-spacing:0;text-transform:none;line-height:1.45;color:var(--pg-muted);cursor:pointer}
  .pg-auth-f .pg-auth-optin input{width:auto;flex:none;margin:2px 0 0;padding:0;accent-color:var(--pg-amber)}
  .pg-auth-wl{margin-top:16px;padding-top:14px;border-top:1px solid var(--pg-hairline)}
  .pg-auth-wl-h{font-size:14px;font-weight:700;color:var(--pg-text);margin:0 0 6px}
  .pg-auth-wl-f{display:flex;gap:8px;flex-wrap:wrap}
  .pg-auth-wl-f input{flex:1 1 170px;min-width:0;box-sizing:border-box;font-size:14px;color:var(--pg-text);background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);border-radius:8px;padding:9px 11px;outline:none}
  .pg-auth-wl-f button{flex:none;padding:9px 13px;border-radius:8px;border:1px solid rgba(255,255,255,.28);background:transparent;color:var(--pg-text);font-size:13px;font-weight:600;cursor:pointer}
  .pg-auth-wl-f button:hover{background:rgba(255,255,255,.10)}
  .pg-sr{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:7px;cursor:pointer}
  .pg-sr:hover{background:rgba(255,255,255,.08)}
  .pg-sr .ic{width:20px;text-align:center;font-size:13px;flex:none}
  .pg-sr .ic.air{color:var(--pg-amber)} .pg-sr .ic.hotel{color:var(--pg-vermilion)}
  .pg-sr .col{min-width:0}
  .pg-sr .t{font-weight:600;font-size:13.5px;color:var(--pg-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-sr .s{font-size:11.5px;color:var(--pg-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-sr-more{margin-top:4px;border-top:1px solid rgba(255,255,255,.10);border-radius:0 0 7px 7px}
  .pg-sr-more .ic{color:var(--pg-live);font-weight:700}
  .pg-sr-more .t{color:var(--pg-amber)}
  .pg-sr-info{cursor:default}
  .pg-sr-info:hover{background:none}
  .pg-sr-info .ic{color:var(--pg-amber)}
  .pg-sr-info .t{color:var(--pg-muted)}
  /* ── Bottom-left map controls: Layers flyout + zoom + 3D + full screen (explore only) ── */
  /* THE MAP CONTROL BLOCK (2026-08-30). Layers + zoom + full screen, and nothing
     else: these are the controls that must travel with the map into a widget or a
     full-screen view, so they live in one block with one position. My data left
     this bar for the My-map panel in the same change; .pg-filter is moved out by
     placeModePanelNodes() on both tiers, so it was never really here at runtime.
     ⛔ It sat at left:44px bottom:34px, the EXACT coordinates of .pg-stats, and
     painted over it (z-index 7 against 2). Bottom-right resolves that collision. */
  .pg-mapctl{position:fixed;right:44px;bottom:34px;z-index:7;display:none;gap:8px;align-items:flex-end}
  .pg-mapbtn{font-family:var(--pg-font-body);font-size:12.5px;color:var(--pg-text);background:rgba(12,16,20,.72);
             border:1px solid rgba(255,255,255,.16);border-radius:9px;height:34px;padding:0 12px;cursor:pointer;line-height:1;
             display:inline-flex;align-items:center;box-sizing:border-box;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
  .pg-mapbtn:hover{background:rgba(20,26,32,.88);border-color:rgba(255,255,255,.28)}
  .pg-mapbtn.on{background:var(--pg-amber);color:#0b0d10;border-color:transparent;font-weight:700}
  /* ── Layers / My-data: OPEN state ─────────────────────────────────────────
     Jorg 2026-07-17: "if you select one of the items, it becomes orange, except for
     the two layer buttons... the line around the pill gets a little bit whiter. This
     change is too minimally visible."
     It wasn't subtle — it was ACCIDENTAL. Neither button had an open state at all:
     .open goes on the WRAPPER (#pg-layers), not on .pg-mapbtn, so what he was seeing
     was the plain :hover border left over from the tap. This styles the real thing.
     Deliberately NOT amber, and he was right to keep them apart: amber means "this is
     the view you are looking at" (the four modes + Calendar). Layers and My data are
     tools you open OVER a view — they change how it draws, not what it is. Same fill
     would say they're the same kind of thing.
     So: white ink on a bright glass fill, 2px ring. Reads as "this panel is open",
     loudly, without ever being mistaken for the active view. */
  .pg-layers.open > .pg-mapbtn,
  .pg-mine.open > .pg-mapbtn{
    background:rgba(255,255,255,.20);
    border-color:rgba(255,255,255,.92);
    border-width:2px;
    color:#fff;
    /* WIDTH MUST NOT CHANGE — this chip has neighbours, and a chip that grows when you
       open it shunts the whole row sideways under your thumb.
       Two things wanted to grow it, both found by measuring rather than reasoning:
        - the 1px→2px border. box-sizing:border-box only constrains dimensions that are
          SET; height is (34px / 38px in the bar) so it ate inward, but width is auto,
          so the border added 2px. Paid back with 12px→11px padding.
        - font-weight:400→700. Bold text is wider text; it was still drifting 0.6px
          after the padding fix. Dropped — the white fill and the 2px ring already
          shout, and weight was the least of the three signals.
       Verified: width identical open vs closed, neighbour does not move. */
    padding-left:11px; padding-right:11px;
    box-shadow:0 0 0 3px rgba(255,255,255,.10);
  }
  .pg-layers{position:relative}
  .pg-layers-menu{position:absolute;right:0;bottom:calc(100% + 8px);min-width:196px;display:none;flex-direction:column;gap:7px;z-index:3;
                  padding:11px 12px;border-radius:11px;background:rgba(12,16,20,.92);border:1px solid rgba(255,255,255,.16);
                  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:0 10px 30px rgba(0,0,0,.45)}
  .pg-layers:hover .pg-layers-menu,.pg-layers.open .pg-layers-menu{display:flex}
  /* transparent bridge across the gap so hover survives the move from button to menu */
  .pg-layers-menu::after{content:'';position:absolute;left:0;right:0;top:100%;height:10px}
  .pg-lm-h{font-family:var(--pg-font-mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--pg-muted);margin-top:2px}
  .pg-lm-bases{display:flex;gap:5px}
  .pg-lm-bases button{flex:1;font-family:var(--pg-font-body);font-size:11.5px;color:var(--pg-body-bright);
                      background:rgba(255,255,255,.06);border:1px solid transparent;border-radius:7px;padding:6px 4px;cursor:pointer}
  .pg-lm-bases button:hover{background:rgba(255,255,255,.12)}
  .pg-lm-bases button.on{background:var(--pg-amber);color:#0b0d10;font-weight:700}
  .pg-lm-ov{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--pg-text);cursor:pointer}
  .pg-lm-ov input{accent-color:var(--pg-amber);margin:0}
  /* Names + States read as children of Country lines: indent + a dotted branch */
  .pg-lm-ov.sub{margin-left:15px;position:relative}
  .pg-lm-ov.sub::before{content:'';position:absolute;left:-9px;top:-3px;bottom:50%;width:7px;
    border-left:1px dotted rgba(255,255,255,.4);border-bottom:1px dotted rgba(255,255,255,.4)}
  .pg-lm-ov.sub + .pg-lm-ov.sub::before{top:-11px}   /* longer stem for the 2nd child so the line reads continuous */
  .pg-lm-note{font-size:10.5px;color:var(--pg-muted);line-height:1.3;display:none}
  /* "Your map" personal-layer toggles: only shown on the personal (My map) base. */
  /* "My data" menu: personal layers, mirrors the Layers flyout. */
  .pg-mine{position:relative}
  .pg-mine-menu{position:absolute;left:0;bottom:calc(100% + 8px);min-width:190px;display:none;flex-direction:column;gap:6px;z-index:3;
    padding:11px 12px;border-radius:11px;background:rgba(12,16,20,.92);border:1px solid rgba(255,255,255,.16);
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:0 10px 30px rgba(0,0,0,.45)}
  .pg-mine:hover .pg-mine-menu,.pg-mine.open .pg-mine-menu{display:flex}
  .pg-mine-menu::after{content:'';position:absolute;left:0;right:0;top:100%;height:10px}
  .pg-mn{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--pg-text);cursor:pointer}
  .pg-mn.hide{display:none}
  /* Two columns (Jorg, 2026-08-30). Auto-flow, so a ninth row wraps rather than
     breaking the shape, and .pg-mn.hide still collapses a row the mode excludes. */
  .pg-mn-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px 10px;margin-top:2px}
  .pg-mn-acts{display:flex;gap:6px;margin:10px 0 2px}
  .pg-mn-acts button{flex:1;font-family:var(--pg-font-body);font-size:11px;color:var(--pg-body);
    background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);border-radius:7px;
    padding:5px 0;cursor:pointer;line-height:1.2}
  .pg-mn-acts button:hover{background:rgba(255,255,255,.14);color:var(--pg-text)}
  /* Off-default signal: a dot on the button that clears it. Amber, the colour this
     page already uses for "your attention", and it appears ONLY when it means
     something — an always-lit marker teaches nothing. */
  .pg-mn-acts button.off-default{border-color:rgba(245,158,11,.55);color:var(--pg-amber,#f59e0b);font-weight:600}
  .pg-mn-acts button.off-default::before{content:'●';font-size:7px;vertical-align:2px;margin-right:5px}
  /* Time range: ONE row at the head of the My-map panel — label left, select
     right. It filters the trips list AND the personal layers, which is why it sits
     above both rather than inside either. */
  .pg-tr-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
    padding:8px 12px;border-bottom:1px solid rgba(255,255,255,.08)}
  .pg-tr-l{font-family:var(--pg-font-mono);font-size:10px;font-weight:600;letter-spacing:.14em;
    text-transform:uppercase;color:var(--pg-muted);white-space:nowrap}
  .pg-tr-row select{flex:none;max-width:52%;background:rgba(255,255,255,.08);
    border:1px solid var(--pg-hairline);color:var(--pg-text);border-radius:7px;
    padding:4px 8px;font:inherit;font-size:12px;cursor:pointer}
  .pg-tr-row select option{color:#111}
  .pg-mn input{accent-color:var(--pg-amber);margin:0}
  .pg-mn-year{margin-bottom:2px}
  .pg-mn-year select{width:100%;box-sizing:border-box;background:rgba(255,255,255,.08);border:1px solid var(--pg-hairline);
    color:var(--pg-text);font-family:var(--pg-font-body);font-size:12px;border-radius:7px;padding:5px 7px;cursor:pointer}
  .pg-mn-year select option{color:#111}
  .pg-mine-legend{display:flex;align-items:center;gap:6px;margin-top:6px;padding-top:8px;border-top:1px solid rgba(255,255,255,.12);font-size:10.5px;color:var(--pg-muted)}
  .pg-mine-legend .sw{width:12px;height:12px;border-radius:3px;display:inline-block}
  .pg-mine-legend .sw.stay{background:var(--cat-countries,#3b82f6)}
  .pg-mine-legend .sw.touch{background:var(--cat-countries,#3b82f6);opacity:.4}
  /* My data MERGED INTO My map (2026-08-30, Jorg). The layer list renders INLINE
     inside the .pg-world panel instead of behind a ◆ My data popover on the control
     bar, which is why the bar could shrink to the travelling controls. The ids are
     deliberately unchanged: updateMineMenu() selects #pg-mine-menu .pg-mn and
     so it did not have to be rewritten to be moved. (The drift panel that also
     lived here was removed later the same day — see the note by PG_DEFAULTS.) */
  .pg-mine-inline{position:static;display:block}
  .pg-mine-inline .pg-mine-menu{position:static;display:flex;width:auto;min-width:0;max-width:none;
    margin:0;padding:9px 12px 10px;border:0;border-top:1px solid rgba(255,255,255,.08);
    border-radius:0;background:none;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}
  .pg-mine-inline .pg-mine-menu::after{content:none}
  /* Per-mode filter select, styled like a map control (bottom bar, not the top row). */
  .pg-filter{display:none;align-items:flex-end;gap:8px}
  .pg-fsel{font-family:var(--pg-font-body);font-size:12.5px;color:var(--pg-text);background:rgba(12,16,20,.72);
    border:1px solid rgba(255,255,255,.16);border-radius:9px;height:34px;padding:0 10px;cursor:pointer;
    backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
  .pg-fsel:hover{background:rgba(20,26,32,.88)}
  /* Live count of direct destinations for the current alliance/airline filter, so a
     filter change gives immediate feedback even while the card is tucked (Jorg 2026-07-18). */
  .pg-air-count{display:inline-flex;align-items:center;height:34px;font-family:var(--pg-font-mono);font-size:12px;font-weight:600;color:var(--cat-flights,#f59e0b);background:rgba(245,158,11,.12);border:1px solid rgba(245,158,11,.42);border-radius:9px;padding:0 11px;white-space:nowrap}
  .pg-modes #pg-filter .pg-air-count{width:100%;box-sizing:border-box;justify-content:center;height:38px}
  .pg-fsel option{color:#111}
  /* SATELLITE-ONLY ROWS ONLY (fixed 2026-07-26). This was written as a
     descendant selector on the whole panel, so switching off satellite killed
     pointer-events on EVERY .pg-lm-ov in it — Auto by zoom, Show time zones,
     Colour by my time, and then Day & night. The country line/name/state rows
     really are satellite-only, because the CARTO bases print their own; nothing
     else in this panel is. Surfaced by Jorg on 2026-07-26 ("I can't untick the
     day/night and timezone layers anymore"), but it has been true since the
     time-zone layer landed on 07-19 — the second checkbox is what made it
     obvious. Opt IN with .ovonly rather than opting the rest out, so a row added
     later is clickable by default instead of mysteriously dead. */
  .pg-mapctl.no-ov .pg-lm-ov.ovonly{opacity:.4;pointer-events:none}
  .pg-mapctl.no-ov .pg-lm-note.ovonly{display:block}
  .pg-lm-note.always{display:block}
  /* ── THE TWO SQUARES (Jorg, 2026-08-30) ─────────────────────────────────
     "Create a square out of layers and create a square out of the four other
     buttons, and place them next to each other on the bottom line." Both are
     --pg-sq on a side, so the pair reads as one control block. Before this the
     bar carried a 34px pill, a 3-wide horizontal strip and a loose button, all
     different shapes on one line. */
  /* ⚠ HOISTED to :root 2026-08-30 so the airport card can RESERVE this block
     rather than guess its size. It was declared on .pg-mapctl, which meant the one
     element that needed to avoid the controls could not read how big they are. */
  :root{--pg-sq:68px}
  .pg-mapctl{--pg-sq:68px}
  /* ⛔ THE TRACKS MUST BE FRACTIONS, NOT HALVES OF --pg-sq, or this square comes
     out 2px BIGGER than the Layers one beside it (Jorg: "not exactly the same
     size... maybe a few pixels"). With box-sizing:border-box and no explicit size,
     the element sizes to its CONTENT: two 34px tracks make a 68px content box, and
     the 1px border is then added OUTSIDE it, so the box measures 70px while Layers
     measures 68px with the border counted in. State the size and let the tracks
     divide what is left. */
  .pg-zoom{display:grid;width:var(--pg-sq);height:var(--pg-sq);
           grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(2,1fr);
           box-sizing:border-box;border:1px solid rgba(255,255,255,.16);
           border-radius:9px;overflow:hidden;background:rgba(12,16,20,.72);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
  .pg-zoom button{font-family:var(--pg-font-body);font-size:16px;color:var(--pg-text);background:none;border:none;
                  width:100%;height:100%;cursor:pointer;line-height:1;display:flex;align-items:center;justify-content:center}
  /* Grid lines drawn by position, not by source order: right edge on the left
     column, bottom edge on the top row. The single-cell touch case below lands on
     the 4th child, which takes neither, so no stray border is left hanging. */
  .pg-zoom button:nth-child(odd){border-right:1px solid rgba(255,255,255,.14)}
  .pg-zoom button:nth-child(-n+2){border-bottom:1px solid rgba(255,255,255,.14)}
  .pg-zoom button:hover{background:rgba(255,255,255,.1)}
  /* Layers is the other square: the icon over its label, same side as the 2×2. */
  .pg-mapctl .pg-layers > .pg-mapbtn{width:var(--pg-sq);height:var(--pg-sq);padding:0;
    flex-direction:column;justify-content:center;gap:5px;font-size:11px;line-height:1.1}
  .pg-mapctl .pg-layers > .pg-mapbtn .di{font-size:19px;line-height:1}
  /* When the chrome gets tight, the search collapses to the icon so the right-hand
     controls never wrap. Tap the glass → the field drops down as a popover. */
  @media(max-width:1180px){
    .pg-search-wrap{flex:none;max-width:none}   /* collapsed: shrink to the icon, don't hog space */
    .pg-search-wrap .pg-search{display:none}
    .pg-search-icon{display:inline-flex}
    .pg-search-wrap.mini-open .pg-search{display:block;position:absolute;top:calc(100% + 8px);left:0;width:min(80vw,340px)}
    .pg-search-wrap.mini-open .pg-search-results{top:calc(100% + 60px);width:min(80vw,340px)}
  }
  /* (2026-07-12) The ≥1500px absolute-centering is retired — it collapsed the
     centre group to min-content, which was the search shrinking on full-4K. */
  .pg-chrome-r{display:flex;align-items:center;gap:12px;flex:none;white-space:nowrap}
  /* Log in: quiet frosted glass chip. */
  .pg-login{color:var(--pg-text);text-decoration:none;font-family:var(--pg-font-body);font-size:15px;font-weight:600;line-height:1.2;box-sizing:border-box;cursor:pointer;white-space:nowrap;flex:none;
    padding:10px 16px;border-radius:8px;background:rgba(12,16,20,.55);border:1px solid rgba(255,255,255,.14);
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  .pg-login:hover{background:rgba(12,16,20,.7)}
  .pg-login:hover{opacity:1}
  /* Register: loud orange in the chrome (Jorg 2026-07-10 — should jump out past Log in). */
  .pg-register{color:#fff;text-decoration:none;font-size:15px;font-weight:700;line-height:1.2;white-space:nowrap;flex:none;
    padding:10px 18px;border-radius:8px;background:var(--pg-vermilion);border:1px solid var(--pg-vermilion);box-shadow:var(--pg-shadow-cta)}
  .pg-register:hover{filter:brightness(1.06)}
  /* Register CTA has two labels; desktop shows the full one. The phone block near
     the bottom of this file flips them (the full label overflows a guest bar). */
  .pg-cta-full{display:inline}
  .pg-cta-mini{display:none}
  /* Logged-in profile menu (lets you log out / open the dashboard to test overlays) */
  .pg-profile{position:relative}
  .pg-profile-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:170px;display:none;flex-direction:column;
    background:rgba(16,20,25,.95);border:1px solid var(--pg-hairline);border-radius:10px;padding:6px;
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 12px 34px rgba(0,0,0,.5)}
  .pg-profile-menu.open{display:flex}
  /* Avatar-only account control (unified bar Phase 1, 2026-07-12) + tasks chip. */
  .pg-avatar-btn{width:38px;height:38px;border-radius:50%;padding:0;cursor:pointer;flex:none;overflow:hidden;
    display:inline-flex;align-items:center;justify-content:center;font-family:var(--pg-font-body);font-weight:800;font-size:15px;
    color:#0b0d10;background:linear-gradient(135deg,var(--pg-amber),var(--pg-vermilion));border:2px solid rgba(255,255,255,.28)}
  .pg-avatar-btn img{width:100%;height:100%;object-fit:cover;display:block}
  .pg-avatar-btn:hover{border-color:rgba(255,255,255,.55)}
  .pg-menu-name{padding:9px 11px 7px;font-size:12px;font-weight:700;color:var(--pg-muted);border-bottom:1px solid var(--pg-hairline);margin-bottom:4px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}
  .pg-tasks-chip{position:relative;width:40px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;padding:9px 0;font-size:15px}
  .pg-task-badge{position:absolute;top:-5px;right:-5px;background:#dc2626;color:#fff;font-size:9.5px;font-weight:700;border-radius:99px;padding:1px 5px;line-height:1.3}
  .pg-profile-menu a{color:var(--pg-text);text-decoration:none;font-size:14px;font-weight:600;padding:9px 11px;border-radius:7px}
  .pg-profile-menu a:hover{background:rgba(255,255,255,.08)}
  .pg-profile-menu .pg-about-legal{padding:9px 11px 4px;margin-top:4px;border-top:1px solid var(--pg-hairline);font-size:12px;color:var(--pg-muted)}
  .pg-profile-menu .pg-about-legal a{display:inline;padding:0;background:none;font-size:12px;color:var(--pg-muted)}
  /* Hero pitch, upper-left ~top 30%, legible via directional scrim + text-shadow (§3) */
  /* Full-viewport scrim (horizontal, fades to 0 mid-screen) so there's no hard
     div edge/line. The copy sits in a fixed-width inner block on the left. */
  /* ⛔ NO RAIL WHILE THE HERO IS UP. The hero's copy is left-aligned from x=44 and
     the rail is fixed over x=0..168, so a rail here covers the H1, the sub-copy and
     more than half of the "Try the live demo" button. The rail belongs to browsing,
     and browsing begins when the hero goes — see window.pgHeroShow(), its one owner.
     ⚠ Desktop only in effect: below 769px the rail is display:none anyway and the
     hero sits at the BOTTOM of the screen, so nothing here changes the phone. */
  body.hero-up .nav-rail{display:none}
  .pg-hero{left:0;right:0;top:0;bottom:0;display:flex;flex-direction:column;justify-content:center;
    padding:0 20px 0 44px;pointer-events:none;
    background:linear-gradient(90deg, rgba(8,11,15,.95) 0, rgba(8,11,15,.9) 200px, rgba(8,11,15,.66) 360px, rgba(8,11,15,.34) 490px, rgba(8,11,15,.12) 610px, rgba(8,11,15,0) 760px)}
  .pg-hero-inner{max-width:560px;pointer-events:none}
  .pg-hero-inner>*{pointer-events:auto}
  .pg-eyebrow{color:var(--pg-amber);font-family:var(--pg-font-mono);font-weight:600;font-size:11px;letter-spacing:.16em;
    text-transform:uppercase;margin:0 0 16px;text-shadow:var(--pg-shadow-body)}
  .pg-h1{font-family:var(--pg-font-display);font-weight:900;font-size:clamp(33px,5.4vw,60px);line-height:.95;
    margin:0;letter-spacing:-.03em;text-shadow:var(--pg-shadow-h1)}
  .pg-sub{max-width:34ch;margin:18px 0 26px;font-size:17px;line-height:1.5;color:var(--pg-body-bright);text-shadow:var(--pg-shadow-body)}
  .pg-cta{display:inline-flex;align-items:center;gap:8px;background:var(--pg-vermilion);color:#fff;text-decoration:none;
    font-family:var(--pg-font-body);font-weight:700;font-size:16px;padding:14px 24px;border-radius:9px;box-shadow:var(--pg-shadow-cta)}
  .pg-cta:hover{filter:brightness(1.06)}
  /* Browse = a frosted/opaque secondary button next to the demo CTA (chrome-chip style) */
  .pg-cta-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .pg-cta2{display:inline-flex;align-items:center;color:var(--pg-text);text-decoration:none;cursor:pointer;
    font-family:var(--pg-font-body);font-weight:700;font-size:16px;padding:14px 20px;border-radius:9px;
    background:rgba(12,16,20,.55);border:1px solid rgba(255,255,255,.14);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  .pg-cta2:hover{background:rgba(12,16,20,.72)}
  /* The quiet third row under the hero CTAs — a link out to /about, not a button. */
  .pg-hero-about{display:inline-block;margin-top:12px;color:var(--pg-body);text-decoration:none;
    font-size:13.5px;border-bottom:1px solid rgba(255,255,255,.28);padding-bottom:1px}
  .pg-hero-about:hover{color:var(--pg-text);border-bottom-color:rgba(255,255,255,.6)}
  /* Map-hint: plain text (no box), to avoid stacking too many boxes on the hero */
  .pg-micro{display:block;margin-top:16px;font-family:var(--pg-font-mono);font-size:12px;color:var(--pg-muted);
    letter-spacing:.02em;text-shadow:var(--pg-shadow-body)}
  .pg-dismiss{display:inline-block;margin-top:12px;color:var(--pg-body);font-size:14px;font-weight:600;text-decoration:none;cursor:pointer}
  /* Live stats atom, lower-left, on the bottom vignette (§4.7) */
  .pg-stats{left:44px;bottom:34px;display:flex;align-items:baseline;gap:20px;font-size:13px;color:var(--pg-body-bright);
    text-shadow:var(--pg-shadow-body);flex-wrap:wrap}
  .pg-stats .live{display:inline-flex;align-items:center;gap:6px;color:var(--pg-live);font-family:var(--pg-font-mono);font-weight:600;font-size:10.5px;letter-spacing:.12em}
  .pg-stats .live .dot{width:7px;height:7px;border-radius:50%;background:var(--pg-live);box-shadow:0 0 7px var(--pg-live);animation:pg-blip 1.5s ease-in-out infinite}
  @keyframes pg-blip{0%,100%{opacity:.35;transform:scale(.8)}50%{opacity:1;transform:scale(1.2)}}
  @media(prefers-reduced-motion:reduce){.pg-stats .live .dot{animation:none}}
  .pg-stats b{font-family:var(--pg-font-display);font-weight:800;font-size:22px}
  .pg-stats .amber{color:var(--pg-amber)}
  .pg-stats span.u{color:var(--pg-muted);margin-left:4px;font-family:var(--pg-font-mono);font-size:11px}
  /* Demo hotel photo pin in the hero (round thumbnail, white ring). */
  .pg-hotel-pin{width:34px;height:34px;border-radius:50%;background-size:cover;background-position:center;
    border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.5);cursor:pointer}
  .pg-hotel-pin:hover{border-color:var(--pg-amber)}
  /* Bottom vignette so the stats atom stays legible over bright imagery (§3) */
  .pg-vig{position:fixed;left:0;right:0;bottom:0;height:34vh;z-index:1;pointer-events:none;background:var(--pg-vignette)}
  /* ── The hotel balloon (2026-09-02) ──────────────────────────────────────
     "very small font a balloon or something with the name of the hotel pointing to
     that circle" (Jorg). Deliberately SMALL: it names one dot, it is not a panel,
     and the moment it grows stats it becomes the card it replaced.
     ⚠ It sits in a maplibregl popup, so the arrow, the anchoring and the flip near
     an edge are MapLibre's, not ours — the pin card had to hand-roll all three and
     the file's own note says an object-anchored popover "would spend its life
     clamped to an edge" at 390px. A popup solves that by construction. */
  .pg-hb-pop .maplibregl-popup-content{padding:0;background:rgba(18,23,28,.97);border-radius:9px;
    box-shadow:0 4px 18px rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.16)}
  .pg-hb-pop .maplibregl-popup-tip{border-top-color:rgba(18,23,28,.97);border-bottom-color:rgba(18,23,28,.97)}
  .pg-hb{display:flex;align-items:stretch;gap:0;max-width:min(62vw,240px)}
  .pg-hb .nm{display:block;padding:7px 10px;font-family:var(--pg-font-body);font-size:11.5px;
    font-weight:600;line-height:1.25;color:var(--pg-text);text-decoration:none;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .pg-hb a.nm:hover{background:rgba(255,255,255,.10);text-decoration:none}
  /* ⚠ 44px minimum on the star: it is a touch target on the surface this whole
     change exists for, and the map's own controls already hold that floor. */
  .pg-hb .st{flex:none;min-width:34px;min-height:34px;display:inline-flex;align-items:center;
    justify-content:center;font:inherit;font-size:14px;line-height:1;cursor:pointer;
    color:var(--pg-text);background:none;border:0;border-left:1px solid rgba(255,255,255,.14)}
  .pg-hb .st:hover{background:rgba(255,255,255,.12)}
  @media(max-width:768px){ .pg-hb .nm{font-size:12.5px;padding:9px 12px} .pg-hb .st{min-width:44px;min-height:44px} }

  /* Placeholder pin card (to be replaced by the shared in-app lightbox, §4.6) */
  .pg-card{right:24px;top:50%;transform:translateY(-50%);width:300px;background:rgba(20,24,29,.95);
    border:1px solid var(--pg-hairline);border-radius:14px;padding:16px 16px 14px;display:none;box-shadow:0 12px 40px rgba(0,0,0,.5);
    backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}
  /* WIDTH, not a second surface: see .pg-card.wide beside the .pg-itin rule
     below, which is where it has to sit to win the cascade. */
  /* Live "traveller now" header — the moment, above the itinerary. */
  .pg-card-live{border:1px solid rgba(245,158,11,.34);background:rgba(245,158,11,.09);
    border-radius:11px;padding:10px 12px;margin:10px 0 4px}
  .pg-card-live .lt{font-weight:700;color:var(--pg-text);font-size:13px;line-height:1.35}
  .pg-card-live .ls{color:var(--pg-body);font-size:11.5px;margin-top:2px}
  .pg-card-live .lx{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
  .pg-card-live .lx a{font-family:var(--pg-font-mono);font-size:10px;font-weight:700;letter-spacing:.06em;
    text-transform:uppercase;color:var(--pg-text);background:rgba(255,255,255,.10);padding:4px 8px;
    border-radius:6px;text-decoration:none}
  .pg-card-live .lx a:hover{background:rgba(255,255,255,.18);text-decoration:none}
  /* The confirm action is a BUTTON, not another chip: it writes, and the two
     link-chips beside it only navigate. Looking alike would be a lie. */
  .pg-card-live .lc{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:9px}
  .pg-card-live .pg-live-yes{font:inherit;font-size:11.5px;font-weight:700;cursor:pointer;
    border:0;border-radius:7px;padding:7px 12px;background:var(--pg-amber,#f59e0b);color:#0b1220}
  .pg-card-live .pg-live-yes:hover{filter:brightness(1.08)}
  .pg-card-live .pg-live-yes[disabled]{opacity:.55;cursor:default}
  .pg-card-live .lch{font-size:10.5px;color:var(--pg-muted)}
  .pg-card-live .ln{display:flex;gap:7px;align-items:baseline;flex-wrap:wrap;margin-top:9px;
    padding-top:8px;border-top:1px solid rgba(245,158,11,.26)}
  .pg-card-live .lnv{font-family:var(--pg-font-mono);font-size:9.5px;font-weight:700;letter-spacing:.09em;
    color:var(--pg-amber);text-transform:uppercase}
  .pg-card-live .lnt{font-weight:600;color:var(--pg-text);font-size:12px}
  .pg-card.collapsed .pg-card-live{display:none !important}
  /* Head doors: the width toggle stays in this lens; ↗ is the ONE lens jump. */
  #pg-card-wide,#pg-card-data{color:var(--pg-text);opacity:.55;background:none;border:0;font-size:13px;
    cursor:pointer;line-height:1;text-decoration:none;padding:0 3px}
  #pg-card-wide:hover,#pg-card-data:hover{opacity:1;text-decoration:none}
  .pg-card .k{font-family:var(--pg-font-mono);font-weight:600;font-size:10.5px;letter-spacing:.14em;color:var(--pg-amber);text-transform:uppercase}
  .pg-card h3{font-family:var(--pg-font-display);font-weight:900;font-size:24px;margin:1px 0 2px}
  .pg-card .meta{color:var(--pg-muted);font-family:var(--pg-font-mono);font-size:12px}
  .pg-card .row{display:flex;flex-wrap:wrap;gap:10px 16px;margin:14px 0 14px}   /* wrap, don't clip: "5 continents" was truncated to "cont" at the card edge (2026-07-19) */
  .pg-card .row div b{font-family:var(--pg-font-display);font-weight:800;font-size:22px;display:block}
  .pg-card .row div span{color:var(--pg-faint);font-size:11px;font-family:var(--pg-font-mono)}
  .pg-card .add{display:block;text-align:center;background:var(--pg-vermilion);color:#fff;text-decoration:none;font-weight:700;
    padding:11px;border-radius:9px;box-shadow:var(--pg-shadow-cta)}
  .pg-card .x{color:var(--pg-text);opacity:.55;background:none;border:0;font-size:15px;cursor:pointer;line-height:1}
  /* Phase 2.3: EVERY detail card (trip/route/hotel/airport/place — one component)
     is a moveable, collapsible window like the mode panel: drag by the kind row,
     ▾ collapses to kind + title. Desktop only for drag (mobile = bottom sheet). */
  .pg-card .x:hover{opacity:1}
  /* ⛔ 8x13 PIXELS, THREE PIXELS FROM THE CLOSE BUTTON. Jorg, 2026-08-30: "there is
     a collapse and close button on the top right ... they are so close together, and
     the collapse button is so small that it's unclear what it exactly is."
     Measured before: collapse 8x13, close 11x15, gap 3px. The PHONE already sized
     this control 48x48 (see the media block far below); desktop never did, so the
     smaller pointer target got the smaller button — backwards.
     ⚠ The GLYPH grows with the box: a 28px button around a 13px chevron is a big
     empty square, which reads as broken rather than as generous. */
  #pg-card-min{color:var(--pg-text);opacity:.55;background:none;border:0;font-size:18px;cursor:pointer;line-height:1;
    width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border-radius:8px}
  #pg-card-min:hover{opacity:1;background:rgba(255,255,255,.10)}
  .pg-card .x{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;
    border-radius:8px;font-size:17px;line-height:1}
  .pg-card .x:hover{background:rgba(255,255,255,.10)}
  /* Header row: kind label + collapse/close buttons share ONE line (Jorg 2026-07-17e:
     "put the close and collapse buttons on the same row as Trip"), so the card loses the
     empty band above the title and collapses shorter. */
  .pg-card-head{display:flex;align-items:center;justify-content:space-between;gap:8px}
  .pg-card-head .k{flex:1;min-width:0}
  /* ⚠ gap was 2px, which put a 3px channel between two controls that do opposite
     things (collapse vs close). 8px is the same step the header row already uses. */
  .pg-card-hbtns{display:flex;align-items:center;gap:8px;flex:none}
  @media(min-width:769px){ .pg-card .k{cursor:grab} }
  .pg-card.collapsed :is(.meta,.row,.pg-card-detail,.pg-card-expand,.pg-card-nudge,.add,.pg-card-wl){display:none !important}
  .pg-card.collapsed h3{font-size:16px;margin:4px 0 0}
  /* Desktop: keep the detail card inside the viewport. The max-height/scroll rules
     below were phone-only, so a busy airport's connecting-flights card ran off the top
     AND bottom, and collapsing a tall route froze an off-screen top (the card seemed to
     vanish). Top-anchored below the chrome (--pg-chrome-h), a bottom gap, scroll the overflow
     (Jorg 2026-07-18). Fixes both the airport overflow and the route "disappears on collapse". */
  @media(min-width:769px){
    /* padding-top:0 so the header sits at the TRUE top edge — no padding band above it
       for the title to scroll into (Jorg 2026-07-18: "the top bar must be at the top of
       the box, the title must scroll behind it, not above it"). */
    /* ⛔ IT HAS TO CLEAR THE MAP CONTROLS, NOT JUST THE VIEWPORT. Jorg, 2026-08-30:
       "if I click on Amsterdam Airport ... the list is so long, but it goes behind
       the two squares on the bottom right. I think it should stop just above it."
       Measured: the card ended at 523 and #pg-mapctl spans 455..523, so the last
       68px of a busy hub's list sat under the squares — and the card is z-index 2
       against their 11, so it lost. The old reserve was 88px (72 top + a 16 gap)
       and knew nothing about the controls.
       ⚠ Reserved FROM --pg-sq rather than a literal 68, so resizing the control
       block moves this with it: 72 top + the block + two 16px gaps. */
    .pg-card{ top:calc(var(--live-h,0px) + var(--pg-chrome-h,48px) + 16px); bottom:auto; transform:none; padding-top:0;
      max-height:calc(100dvh - var(--live-h,0px) - 72px - var(--pg-sq,68px) - 32px);
      overflow-y:auto; overflow-x:hidden; overscroll-behavior:contain; }
    /* Header pinned flush to the card top, fully opaque, full-bleed; ALL content
       (incl. the title) scrolls UNDER it. overflow-x:hidden kills the h-scrollbar the
       full-bleed -16px side margins would otherwise cause. */
    .pg-card-head{ position:sticky; top:0; z-index:2; background:#14181d; margin:0 -16px 4px; padding:14px 16px 8px; }
    /* Collapsed = header + title only; never clip it (a two-line airport title was
       clipping away entirely and read as the card vanishing). */
    .pg-card.collapsed{ max-height:none; overflow:hidden; }   /* hidden (not visible) so the square header can't cover the card's rounded top corners (Jorg 2026-07-18) */
    .pg-card.collapsed .pg-card-head{ position:static; margin:0 -16px 0; padding:12px 16px 2px; }
    .pg-card.collapsed h3{ margin:0 0 6px; }
  }
  .pg-card-detail{margin:6px 0 10px;font-size:12.5px;color:var(--pg-body);line-height:1.5}
  /* Selected hotel photo pin: the zoomed-into hotel wears a vermilion ring so it
     stands out from every other white-ringed photo pin (Jorg 2026-07-12). */
  .pg-hotel-pin.sel{border-color:var(--pg-vermilion);box-shadow:0 0 0 3px rgba(210,80,47,.5),0 1px 7px rgba(0,0,0,.55);transform:scale(1.15);z-index:5}
  /* Future trips: badged in the list; the ✈ toggle in the trips head hides them. */
  .pg-trip .ft{flex:none;font-family:var(--pg-font-mono);font-size:9px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
    color:#0b0d10;background:var(--pg-amber);border-radius:99px;padding:1px 7px;margin-left:6px}
  .pg-trip .ft-live{color:#052e16;background:#4ade80}   /* ongoing = the live-strip green, not amber */
  .pg-trips-fut{display:flex;align-items:center;gap:4px;font-size:10.5px;color:var(--pg-muted);cursor:pointer;white-space:nowrap}
  /* Grip dots on the trips bar when it is its OWN floating window (mobile);
     inside the mode panel it's a section, so no grip — that would be a lie. */
  .pg-trips-t::before{content:'⠿ ';color:var(--pg-muted)}
  .pg-modes .pg-trips-t::before{content:none}
  .pg-trips-fut input{accent-color:var(--pg-amber);margin:0}
  .pg-card-detail .dh{font-family:var(--pg-font-mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--pg-amber);margin:10px 0 3px}
  .pg-card-detail .rl{margin:1px 0}
  .pg-card-detail .rl b{font-weight:700;color:var(--pg-text);font-family:var(--pg-font-mono);font-size:12px;margin-right:2px}
  .pg-card-detail .cx{display:flex;flex-wrap:wrap;gap:5px;margin-top:4px}
  .pg-card-detail .chip{font-family:var(--pg-font-mono);font-size:11px;padding:2px 8px;border-radius:20px;background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);color:var(--pg-text);white-space:nowrap}
  .pg-card-detail .hint{color:var(--pg-muted);font-size:11px;margin-top:8px;line-height:1.4}
  /* Transport route card: scrollable list of the trips this corridor belongs to. */
  .pg-card-detail .pg-tx-trips{display:flex;flex-direction:column;gap:4px;max-height:184px;overflow-y:auto;margin-top:3px}
  .pg-card-detail .pg-tx-trip{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;text-align:left;
    background:rgba(255,255,255,.06);border:1px solid var(--pg-hairline);border-radius:8px;padding:6px 10px;cursor:pointer;color:var(--pg-text);font-family:inherit}
  .pg-card-detail .pg-tx-trip:hover{background:rgba(255,255,255,.13);border-color:var(--pg-amber)}
  .pg-card-detail .pg-tx-trip .nm{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
  .pg-card-detail .pg-tx-trip .yr{font-family:var(--pg-font-mono);font-size:11px;color:var(--pg-muted);flex:none}
  .pg-card-nudge{font-size:11px;color:var(--pg-muted);margin:2px 0 9px;line-height:1.4}
  /* Wishlist + visit-log row (registered): two half-width chips above Expand. */
  .pg-card-wl{display:flex;gap:6px;margin:0 0 8px}
  .pg-card-wl button,.pg-card-wl a{flex:1;box-sizing:border-box;text-align:center;padding:8px 6px;border-radius:9px;font-family:var(--pg-font-body);
    font-size:12.5px;font-weight:600;color:var(--pg-text);background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.16);
    cursor:pointer;text-decoration:none;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-card-wl button:hover,.pg-card-wl a:hover{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.28)}
  .pg-card-wl button.on{background:var(--cat-rewards,#d946a0);border-color:transparent;color:#fff}
  .pg-card-wl button.done{opacity:.65;cursor:default}
  /* Route → plan board row (Slice 1): chips share the wl look; the picker
     stacks select/title/actions inside the same row — no new floating surface. */
  .pg-plan-row{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0}
  .pg-plan-row button,.pg-plan-row a{flex:1;box-sizing:border-box;text-align:center;padding:8px 6px;border-radius:9px;font-family:var(--pg-font-body);
    font-size:12.5px;font-weight:600;color:var(--pg-text);background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.16);
    cursor:pointer;text-decoration:none;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-plan-row button:hover,.pg-plan-row a:hover{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.28)}
  .pg-plan-row select,.pg-plan-row input{flex:1 1 100%;box-sizing:border-box;padding:7px 8px;border-radius:8px;font-family:var(--pg-font-body);
    font-size:12.5px;color:var(--pg-text);background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.16)}
  .pg-plan-row select option,.pg-plan-row select optgroup{background:#14181d;color:#e6e9ec}
  .pg-plan-act{display:flex;gap:6px;flex:1 1 100%}
  .pg-plan-act #pg-plan-go{flex:1}
  .pg-plan-act #pg-plan-cancel{flex:0 0 auto;min-width:38px}
  .pg-plan-msg{flex:1 1 100%;font-size:12.5px;padding:6px 2px;color:var(--pg-text)}
  .pg-plan-msg a{color:var(--cat-flights,#e8a64a);text-decoration:none;font-weight:600}
  .pg-plan-msg a:hover{text-decoration:underline}
  .pg-plan-msg.err{color:var(--cat-alerts,#e5484d)}
  /* "Expand" tease: visible affordance on every card; opens the register gate. */
  .pg-card-expand{display:block;width:100%;box-sizing:border-box;text-align:center;margin:0 0 8px;padding:9px;border-radius:9px;
    background:rgba(255,255,255,.06);border:1px solid var(--pg-hairline);color:var(--pg-text);
    font-family:var(--pg-font-body);font-size:13px;font-weight:600;cursor:pointer}
  .pg-card-expand:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.28)}
  .pg-gate{position:fixed;inset:0;z-index:60;display:none;align-items:center;justify-content:center;background:rgba(6,10,16,.62);
    backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
  .pg-gate.open{display:flex}
  .pg-gate-box{position:relative;width:min(400px,92vw);background:var(--pg-surface);border:1px solid var(--pg-hairline);
    border-radius:16px;padding:22px 22px 20px;box-shadow:0 24px 64px rgba(0,0,0,.6)}
  .pg-gate-k{font-family:var(--pg-font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--pg-amber);margin-bottom:6px}
  .pg-gate-t{font-family:var(--pg-font-display);font-weight:900;font-size:1.25rem;line-height:1.15;margin-bottom:8px;color:var(--pg-text)}
  .pg-gate-b{color:var(--pg-body);font-size:13.5px;line-height:1.5;margin:0 0 16px}
  .pg-gate-cta{display:block;text-align:center;background:var(--pg-vermilion);color:#fff;text-decoration:none;font-weight:700;padding:11px;border-radius:9px;box-shadow:var(--pg-shadow-cta)}
  .pg-gate-sub{display:block;text-align:center;margin-top:10px;color:var(--pg-muted);font-size:12px;text-decoration:none}
  .pg-gate-sub:hover{color:var(--pg-body)}
  .pg-gate-x{position:absolute;top:10px;right:13px;background:none;border:0;color:var(--pg-muted);font-size:16px;cursor:pointer;line-height:1}
  /* In-map detail lightbox: a right-anchored panel over the map (an iframe embed). */
  /* Starts BELOW the top bar so the chrome (search + modes) is always reachable. */
  .pg-lightbox{position:fixed;top:calc(74px + var(--live-h,0px));left:0;right:0;bottom:0;z-index:70;display:none;align-items:center;justify-content:flex-end}
  .pg-lightbox.open{display:flex}
  /* Narrow variant for text cards (prize board, extension) — the 840px panel
     left ~280px of dead air around 560px content (Jorg 2026-07-20). */
  .pg-lightbox.lb-narrow .pg-lb-panel{width:min(620px,94vw)}
  /* No full-page dim (Jorg, 2026-07-12): the panel floats over a still-visible
     map; the backdrop stays only as the click-outside-to-close hit area. */
  .pg-lb-backdrop{position:absolute;inset:0;background:transparent}
  /* Panel sizes to the embed's content (JS sets height from the posted height);
     the CSS value is a modest default before the first message so short content
     doesn't flash a tall box. */
  .pg-lb-panel{position:relative;width:min(840px,94vw);height:min(70vh,500px);max-height:88vh;margin-right:min(4vw,56px);
    background:var(--pg-surface);border:1px solid var(--pg-hairline);border-radius:14px;overflow:hidden;box-shadow:0 18px 60px rgba(0,0,0,.6)}
  .pg-lb-frame{width:100%;height:100%;border:0;background:var(--pg-ink);display:block}
  .pg-lb-close{position:absolute;top:10px;right:12px;z-index:2;width:36px;height:36px;border-radius:50%;
    border:1px solid var(--pg-hairline);background:rgba(12,16,20,.85);color:var(--pg-text);font-size:16px;cursor:pointer;
    backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
  .pg-lb-close:hover{background:rgba(20,26,32,.95)}
  /* Full-canvas overlay (drafting-table pilot 2, 2026-07-12): "a big canvas in
     front of the canvas" — a large centred surface in the map design language,
     home for the read-only Calendar viewer. Distinct from .pg-lightbox (which is
     right-anchored + content-sized); this one is centred, fixed-large, and its
     iframe scrolls internally. */
  .pg-canvas-backdrop{position:fixed;inset:0;z-index:78;background:rgba(6,10,16,.25);opacity:0;pointer-events:none;transition:opacity .28s}
  .pg-canvas-backdrop.open{opacity:1;pointer-events:auto}
  .pg-canvas{position:fixed;z-index:79;top:50%;left:50%;transform:translate(-50%,-48%) scale(.98);opacity:0;pointer-events:none;
    transform-origin:50% 100%;
    width:min(1760px,96vw);height:min(1040px,94vh);display:flex;flex-direction:column;overflow:hidden;
    background:rgba(14,18,23,.92);border:1px solid var(--pg-hairline);border-radius:16px;
    box-shadow:none;backdrop-filter:blur(20px) saturate(1.1);-webkit-backdrop-filter:blur(20px) saturate(1.1);
    transition:opacity .3s ease,transform .45s cubic-bezier(.4,0,.2,1)}
  .pg-canvas.open{opacity:1;pointer-events:auto;transform:translate(-50%,-50%) scale(1)}
  .pg-canvas.narrow{width:min(900px,96vw)}
  /* Minimize: the panel shrinks and falls toward the bottom-centre restore chip
     over ~0.45s so the eye can follow it on a big screen (Jorg, 4K). */
  .pg-canvas.tuck{opacity:0;pointer-events:none;transform:translate(-50%,42vh) scale(.10)}
  .pg-canvas-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex:none;
    padding:14px 18px;border-bottom:1px solid var(--pg-hairline)}
  .pg-canvas-title{display:flex;align-items:center;gap:9px;font-family:var(--pg-font-display);font-weight:900;font-size:19px;color:var(--pg-text)}
  .pg-canvas-title .g{color:var(--pg-amber);font-size:17px;line-height:1}
  .pg-canvas-sub{font-family:var(--pg-font-mono);font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--pg-muted);margin-left:4px}
  .pg-canvas-actions{display:flex;align-items:center;gap:8px}
  .pg-canvas-full{color:var(--pg-body);text-decoration:none;font-size:12px;font-weight:600;padding:7px 11px;border-radius:8px;
    border:1px solid var(--pg-hairline);background:rgba(255,255,255,.05)}
  .pg-canvas-full:hover{background:rgba(255,255,255,.1);color:var(--pg-text)}
  .pg-canvas-x{width:34px;height:34px;border-radius:50%;border:1px solid var(--pg-hairline);background:rgba(255,255,255,.06);
    color:var(--pg-text);font-size:16px;cursor:pointer;line-height:1;display:flex;align-items:center;justify-content:center}
  .pg-canvas-x:hover{background:rgba(255,255,255,.12)}
  .pg-canvas-frame{flex:1 1 auto;width:100%;border:0;background:var(--pg-ink);display:block}
  /* Chrome launcher chip — matches the frosted About/tasks/avatar chips (38px). */
  /* .pg-cal-btn moved out of the top bar and into #pg-discover (2026-07-16). It
     inherits the mode-button look from `.pg-discover button` so it can't drift from
     its four neighbours — the old chip styling (38px square, own glass, own radius)
     was for a top-bar control and would have made it the one odd item in the row.
     Only the width override survives: the modes are icon+label, and so is this. */
  .pg-cal-btn{cursor:pointer}
  .pg-canvas-min{width:34px;height:34px;border-radius:50%;border:1px solid var(--pg-hairline);background:rgba(255,255,255,.06);
    color:var(--pg-text);font-size:17px;cursor:pointer;line-height:1;display:flex;align-items:center;justify-content:center}
  .pg-canvas-min:hover{background:rgba(255,255,255,.12)}
  /* Restore chip: shown while the overlay is minimized so you can peek at the map
     behind it and bring the calendar back (Jorg, 2026-07-12). Sized up + a brief
     pop + a soft amber glow so it's noticeable landing on a 4K screen. */
  .pg-canvas-restore{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(14px);z-index:77;
    display:none;align-items:center;gap:10px;cursor:pointer;padding:12px 22px;border-radius:99px;
    background:rgba(14,18,23,.94);border:1px solid var(--pg-amber);color:var(--pg-text);font-family:var(--pg-font-body);
    font-size:15px;font-weight:700;box-shadow:0 14px 40px rgba(0,0,0,.55),0 0 0 4px color-mix(in srgb,var(--pg-amber) 22%,transparent);
    backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);opacity:0;transition:opacity .25s,transform .25s}
  .pg-canvas-restore.show{display:flex;opacity:1;transform:translateX(-50%) translateY(0);animation:pgRestorePop .5s cubic-bezier(.2,1.3,.4,1) both}
  .pg-canvas-restore .g{color:var(--pg-amber);font-size:18px;line-height:1}
  /* Live-trip "you are here" pulse (phase 2, 2026-07-13): a soft expanding green
     ping + a solid dot at the traveller's current location. Click opens the trip. */
  .pg-live-marker{position:relative;width:26px;height:26px;cursor:pointer}
  .pg-live-marker .pg-live-dot{position:absolute;inset:8px;border-radius:50%;background:#22c55e;
    border:2px solid #fff;box-sizing:border-box;box-shadow:0 0 10px rgba(34,197,94,.9),0 1px 5px rgba(0,0,0,.5);
    animation:pgLiveDot 1.5s ease-in-out infinite}
  .pg-live-marker .pg-live-ping{position:absolute;inset:2px;border-radius:50%;background:rgba(34,197,94,.7);
    animation:pgLivePing 1.6s cubic-bezier(0,0,.2,1) infinite}
  @keyframes pgLivePing{0%{transform:scale(.45);opacity:.9}80%,100%{transform:scale(2.4);opacity:0}}
  @keyframes pgLiveDot{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.82);opacity:.75}}
  /* The marker that travels a leg: a green directional pointer (radar bleep) that
     rotates to the heading — flying/driving/boating in the true direction of
     travel (Jorg 2026-07-14). Hotels keep their own pulse pin. */
  .pg-live-mover{width:26px;height:26px;pointer-events:none;position:relative}
  .pg-live-mover .pg-live-mover-pulse{position:absolute;left:50%;top:50%;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;
    background:rgba(34,197,94,.45);animation:pgLivePing 1.9s cubic-bezier(0,0,.2,1) infinite}
  .pg-live-mover .pg-live-mover-rot{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;transition:transform .12s linear}
  .pg-live-mover .pg-live-mover-rot svg{width:20px;height:20px;filter:drop-shadow(0 0 4px rgba(34,197,94,.95)) drop-shadow(0 1px 2px rgba(0,0,0,.6))}
  .pg-live-mover .pg-live-mover-dot{display:block;width:14px;height:14px;border-radius:50%;background:#22c55e;
    border:2px solid #fff;box-sizing:border-box;box-shadow:0 0 12px 2px rgba(34,197,94,.9),0 1px 4px rgba(0,0,0,.55)}
  @keyframes pgRestorePop{0%{transform:translateX(-50%) translateY(14px) scale(.7)}60%{transform:translateX(-50%) translateY(-2px) scale(1.06)}100%{transform:translateX(-50%) translateY(0) scale(1)}}
  @media (max-width:768px){
    .pg-canvas{width:100vw;height:100vh;max-width:none;border-radius:0;top:0;left:0;transform:none;transform-origin:center}
    .pg-canvas.open{transform:none}
  }
  /* Trips tab: a left-side list panel over the map (shown only in Trips mode). */
  .pg-trips{position:fixed;left:14px;top:calc(122px + var(--live-h,0px));z-index:6;width:min(320px,86vw);max-height:calc(100vh - 330px);display:none;flex-direction:column;   /* below the floating mode pill (unified bar, 2026-07-12) */
    background:rgba(12,16,20,.82);border:1px solid var(--pg-hairline);border-radius:13px;overflow:hidden;
    backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 14px 40px rgba(0,0,0,.5)}
  .pg-trips.open{display:flex}
  .pg-trips-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;border-bottom:1px solid var(--pg-hairline)}
  .pg-trips-t{font-family:var(--pg-font-mono);font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--pg-amber)}
  .pg-trips-head select{background:rgba(255,255,255,.08);border:1px solid var(--pg-hairline);color:var(--pg-text);
    font-family:var(--pg-font-body);font-size:12px;border-radius:7px;padding:4px 7px;cursor:pointer}
  .pg-trips-head select option{color:#111}
  /* FIVE ROWS, THEN SCROLL (Jorg, 2026-08-30): "show a max of five trips more
     closely together... make a scroll box of those five trips so you can scroll down
     to eternity if you have many more." The cap is expressed in ROWS rather than as
     a vh number, so it stays five when the row height changes; --pg-trip-row is the
     one place that height is stated and .pg-trip is sized from the same variable. */
  /* ⚠ --pg-trip-row MUST EQUAL THE RENDERED ROW HEIGHT, and 28px did not: the row
     lays out at 30px (two baselines plus 5px padding either side), so the box came
     out 150px against the 160px five rows need and CLIPPED THE FIFTH by 10px — a
     scrollbar appearing on an account with exactly five trips. Measured, not
     assumed. If .pg-trip's font or padding changes, re-measure and change this. */
  .pg-trips-list{--pg-trip-row:30px;overflow-y:auto;padding:5px 6px;
    max-height:calc(var(--pg-trip-row) * 5 + 10px);
    scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.28) transparent}
  .pg-trips-list::-webkit-scrollbar{width:9px}
  .pg-trips-list::-webkit-scrollbar-track{background:transparent}
  .pg-trips-list::-webkit-scrollbar-thumb{background:rgba(255,255,255,.20);border-radius:8px;border:2px solid transparent;background-clip:padding-box}
  .pg-trips-list::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.34);background-clip:padding-box}
  .pg-trip{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
    min-height:var(--pg-trip-row,30px);box-sizing:border-box;padding:5px 10px;border-radius:8px;cursor:pointer}
  .pg-trip:hover{background:rgba(255,255,255,.07)}
  .pg-trip.on{background:var(--pg-vermilion)}
  .pg-trip .nm{font-weight:600;font-size:12.5px;color:var(--pg-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
  .pg-trip.on .nm{color:#fff}
  .pg-trip .yr{flex:none;font-family:var(--pg-font-mono);font-size:10.5px;color:var(--pg-muted)}
  .pg-trip.on .yr{color:rgba(255,255,255,.85)}
  .pg-trips-empty{padding:16px 14px;color:var(--pg-muted);font-size:13px}
  /* Panel framework: the head is a drag handle; the ▾ button collapses the body. */
  .pg-trips-head{cursor:move;user-select:none;-webkit-user-select:none}
  .pg-trips-head-r{display:flex;align-items:center;gap:8px}
  .pg-pnl-min{background:none;border:0;color:var(--pg-muted);font-size:13px;cursor:pointer;line-height:1;padding:2px 4px;border-radius:5px}
  .pg-pnl-min:hover{color:var(--pg-text);background:rgba(255,255,255,.08)}
  .pg-trips.dragging{opacity:.97;box-shadow:0 20px 60px rgba(0,0,0,.6)}
  /* Destinations legend: explains the map colouring (bottom-right, mode-scoped). */
  /* ── Time-zone ruler strips (Time zones layer 2026-07-19) ──────────────────
     Thin fixed bands over the map, under every control (z2 < mapctl z7 & cards).
     pointer-events:none: the map pans straight through them. Cells are
     absolutely positioned by the JS sampler; a hairline separates neighbours. */
  .pg-tzbar{position:fixed;left:0;right:0;height:22px;z-index:2;display:none;pointer-events:none;
    font-family:var(--pg-font-mono);font-size:10.5px;font-weight:600;letter-spacing:.04em;
    background:rgba(5,7,13,.42);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);overflow:hidden}
  .pg-tzbar.on{display:block}
  .pg-tzbar.top{top:var(--pg-below-chrome)}   /* was the same too-tight 64 as the rail */
  .pg-tzbar.bot{bottom:0}
  .pg-tz-cell{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;
    color:rgba(255,255,255,.92);text-shadow:0 1px 2px rgba(0,0,0,.6);border-left:1px solid rgba(255,255,255,.22);white-space:nowrap}
  .pg-tz-cell:first-child{border-left:0}
  .pg-tz-cell.home{color:var(--pg-amber,#fbbf24)}
  .pg-tz-cell.hi{background:rgba(255,255,255,.2);color:#fff;font-weight:700}
  /* "My time" hover chip: band stats while hovering in the personal colour mode */
  .pg-tz-stat{position:fixed;left:50%;transform:translateX(-50%);bottom:30px;z-index:3;display:none;pointer-events:none;
    font-family:var(--pg-font-mono);font-size:11.5px;font-weight:600;letter-spacing:.03em;color:#fff;
    background:rgba(5,7,13,.78);border:1px solid rgba(255,255,255,.18);border-radius:999px;padding:6px 14px;white-space:nowrap}
  .pg-tz-stat.on{display:block}
  @media (max-width:768px){
    .pg-tz-stat{bottom:calc(var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))) + 30px)}
  }
  /* "Nights per time zone" overview card (my-time mode) — the ranked answer to
     "where was I the most", bars log-scaled to match the fills */
  .pg-tz-rank{position:fixed;right:30px;bottom:64px;z-index:6;display:none;min-width:216px;max-width:256px;
    background:rgba(5,7,13,.82);border:1px solid rgba(255,255,255,.14);border-radius:12px;padding:12px 14px;
    font-family:var(--pg-font-mono);font-size:11px;color:#fff;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
  .pg-tz-rank.on{display:block}
  .pg-tz-rank-t{font-size:9.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--pg-amber,#fbbf24);margin-bottom:8px}
  .pg-tz-rank-row{display:flex;align-items:center;gap:8px;margin-top:5px}
  .pg-tz-rank-utc{width:62px;flex:none;color:rgba(255,255,255,.85)}
  .pg-tz-rank-bar{flex:1;height:7px;border-radius:3px;background:rgba(255,255,255,.08);overflow:hidden}
  .pg-tz-rank-bar i{display:block;height:100%;border-radius:3px}
  .pg-tz-rank-n{width:50px;flex:none;text-align:right}
  @media (max-width:768px){ .pg-tz-rank{display:none !important} }   /* phone = view product; overview deferred there */
  @media (max-width:768px){
    .pg-tzbar.top{top:calc(env(safe-area-inset-top,0px) + 64px)}
    .pg-tzbar.bot{bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px)))}
  }
  .pg-legend{position:fixed;right:30px;bottom:34px;z-index:6;display:none;max-width:280px;
    background:rgba(12,16,20,.82);border:1px solid var(--pg-hairline);border-radius:11px;padding:11px 13px;
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:0 12px 34px rgba(0,0,0,.45)}
  .pg-legend.open{display:block}
  .pg-legend-t{font-family:var(--pg-font-mono);font-size:9.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--pg-amber);margin-bottom:8px}
  .pg-legend-row{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--pg-body);margin-top:6px}
  .pg-legend-toggle{width:100%;box-sizing:border-box;background:none;border:0;font:inherit;text-align:left;cursor:pointer;padding:1px 0;-webkit-tap-highlight-color:transparent}
  .pg-legend-toggle:hover{color:var(--pg-text)}
  .pg-legend-toggle.off{opacity:.42}
  .pg-legend-toggle.off .pg-legend-sw{filter:grayscale(1)}
  .pg-legend-sw{width:26px;height:11px;border-radius:3px;flex:none}
  .pg-legend-sw.grad{background:linear-gradient(90deg, color-mix(in srgb, var(--cat-countries,#3b82f6) 28%, transparent), var(--cat-countries,#3b82f6))}
  .pg-legend-sw.city{background:#fff;border:1px solid var(--cat-places,#159a86);border-radius:50%;width:11px;height:11px}
  /* YOUR countries share the catalogue's hue — only the white outline is yours.
     These swatches mirror myCountriesLayer() exactly: alpha 150 stayed, 60
     touched, white line at 120. If those alphas change, change these. */
  .pg-legend-sw.mine-stayed{background:color-mix(in srgb, var(--cat-countries,#3b82f6) 67%, transparent);box-shadow:inset 0 0 0 1px rgba(255,255,255,.55)}
  .pg-legend-sw.mine-night{background:color-mix(in srgb, var(--cat-countries,#3b82f6) 33%, transparent);box-shadow:inset 0 0 0 1px rgba(255,255,255,.55)}
  .pg-legend-sw.mine-touched{background:color-mix(in srgb, var(--cat-countries,#3b82f6) 16%, transparent);box-shadow:inset 0 0 0 1px rgba(255,255,255,.55)}
  /* A remembered country (q4): alpha 22 and a half-strength outline in myCountriesLayer(). */
  .pg-legend-sw.mine-memory{background:color-mix(in srgb, var(--cat-countries,#3b82f6) 9%, transparent);box-shadow:inset 0 0 0 1px rgba(255,255,255,.28)}
  .pg-legend-sw.mine-never{background:rgba(255,255,255,.07);box-shadow:inset 0 0 0 1px rgba(255,255,255,.18)}
  /* Solid = yours. Mirrors myCitiesLayer: full-strength cat-places, white line. */
  .pg-legend-sw.mine-city{background:var(--cat-places,#159a86);border:1px solid rgba(255,255,255,.88);border-radius:50%;width:11px;height:11px}
  .pg-legend-mine{margin-top:9px;padding-top:8px;border-top:1px solid rgba(255,255,255,.10)}
  .pg-legend-st{font-family:var(--pg-font-mono);font-size:9px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--pg-body);opacity:.7}
  .pg-legend-note{font-size:11px;color:var(--pg-muted);margin-top:9px;line-height:1.35}
  /* "Only approved" tick box: rides the Hotels filter row next to the chain select,
     so the ONE chain/sub-brand filter governs both the carpet and the gold pins.
     pg-hwl-* NOT pg-wl-* — the wishlist owns pg-wl-btn on this page. */
  .pg-hwl-only{display:none;align-items:center;gap:7px;cursor:pointer;white-space:nowrap}
  .pg-hwl-only input{accent-color:#d4af37;margin:0;cursor:pointer}
  .pg-hwl-only .sw{width:10px;height:10px;border-radius:50%;background:#d4af37;border:1px solid rgba(255,255,255,.55);flex:none}
  .pg-hwl-only .n{font-family:var(--pg-font-mono);font-size:10.5px;color:var(--pg-muted)}
  .pg-hwl-only.on{border-color:rgba(212,175,55,.55);background:rgba(212,175,55,.14);color:#e8cf7a}
  /* Story panel: quiet trigger in the chrome + a right-side glass drawer (§ his ask) */
  .pg-story-trigger{color:var(--pg-text);text-decoration:none;font-family:var(--pg-font-body);font-size:13px;font-weight:600;cursor:pointer;line-height:1.2;box-sizing:border-box;white-space:nowrap;
    height:38px;padding:0 14px;display:inline-flex;align-items:center;border-radius:8px;background:rgba(12,16,20,.55);border:1px solid rgba(255,255,255,.16);
    backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}   /* match the Data/tasks/avatar chip glass + 38px height */
  .pg-story-trigger:hover{background:rgba(12,16,20,.7)}
  .pg-story-backdrop{position:fixed;inset:0;z-index:9;background:rgba(6,10,16,.4);opacity:0;pointer-events:none;transition:opacity .3s}
  .pg-story-backdrop.open{opacity:1;pointer-events:auto}
  .pg-story{position:fixed;right:0;bottom:0;top:auto;z-index:10;width:min(470px,94vw);
    max-height:calc(100vh - 92px);   /* stay below the top bar; grow up from the bottom, never fill the whole height */
    display:flex;flex-direction:column;overflow:hidden;
    transform:translateX(102%);transition:transform .42s cubic-bezier(.2,.8,.2,1);
    background:rgba(14,18,23,.82);backdrop-filter:blur(22px) saturate(1.1);-webkit-backdrop-filter:blur(22px) saturate(1.1);
    border-left:1px solid var(--pg-hairline);border-top:1px solid var(--pg-hairline);border-radius:16px 0 0 0;box-shadow:-24px 0 64px rgba(0,0,0,.55)}
  .pg-story.open{transform:none}
  .pg-story-head{display:flex;align-items:center;justify-content:space-between;padding:22px 24px 14px;border-bottom:1px solid var(--pg-hairline);flex:none}
  .pg-story-head h2{font-family:var(--pg-font-display);font-weight:900;font-size:24px;margin:0}
  .pg-story-x{background:rgba(255,255,255,.08);border:1px solid var(--pg-hairline);color:var(--pg-text);width:32px;height:32px;
    border-radius:50%;font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center}
  .pg-story-body{overflow:auto;min-height:0;padding:20px 24px 28px;-webkit-overflow-scrolling:touch;
    color-scheme:dark;scrollbar-color:#3a434d transparent}   /* dark scrollbar in the dark drawer (Jorg 2026-07-12) */
  .pg-story-body::-webkit-scrollbar{width:11px}
  .pg-story-body::-webkit-scrollbar-thumb{background:#3a434d;border-radius:6px;border:2px solid rgba(12,16,20,.9)}
  .pg-story-body::-webkit-scrollbar-track{background:transparent}
  .pg-story-intro{color:var(--pg-body);font-size:15px;line-height:1.55;margin:0 0 20px}
  .pg-card2{display:flex;gap:14px;padding:15px;border-radius:12px;background:var(--pg-surface-raised);border:1px solid var(--pg-hairline);margin-bottom:10px}
  .pg-card2 .ico{width:40px;height:40px;flex:none;border-radius:10px;background:rgba(210,80,47,.15);color:var(--pg-vermilion);display:flex;align-items:center;justify-content:center}
  .pg-card2 h4{font-family:var(--pg-font-display);font-weight:800;font-size:15.5px;margin:1px 0 5px}
  .pg-card2 p{color:var(--pg-body);font-size:13.5px;line-height:1.5;margin:0}
  .pg-story-sub{font-family:var(--pg-font-mono);font-weight:600;font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--pg-amber);margin:24px 0 12px}
  .pg-panel-sec{margin-bottom:18px}
  .pg-panel-sec h4{font-family:var(--pg-font-display);font-weight:800;font-size:15.5px;margin:0 0 5px}
  .pg-panel-sec p{color:var(--pg-body);font-size:14px;line-height:1.55;margin:0}
  .pg-story-diff{display:grid;grid-template-columns:1fr 1fr;gap:12px}
  .pg-story-diff div{border-top:2px solid var(--pg-hairline);padding-top:10px}
  .pg-story-diff b{font-family:var(--pg-font-display);font-weight:700;font-size:13.5px;display:block;margin-bottom:4px}
  .pg-story-diff span{color:var(--pg-muted);font-size:12px;line-height:1.45;display:block}
  .pg-story-cta{display:flex;gap:10px;flex-wrap:wrap;padding:16px 24px;border-top:1px solid var(--pg-hairline);flex:none;background:rgba(11,13,16,.5)}
  .pg-story-cta a{flex:1;text-align:center;text-decoration:none;font-weight:700;font-size:14px;padding:12px;border-radius:9px}
  .pg-story-cta .demo{background:var(--pg-vermilion);color:#fff}
  .pg-story-cta .reg{color:var(--pg-text);background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.30)}
  /* News drawer (2026-07-12, News pilot): Pelgrim weekly posts in the story drawer. */
  .pg-news-item{padding:15px 0;border-bottom:1px solid var(--pg-hairline)}
  .pg-news-item:first-child{padding-top:2px}
  .pg-news-item:last-child{border-bottom:0}
  .pg-news-meta{display:flex;align-items:center;gap:8px;margin-bottom:7px}
  .pg-news-badge{font-family:var(--pg-font-mono);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--pg-amber);border:1px solid var(--pg-hairline);border-radius:6px;padding:1px 7px}
  .pg-news-date{font-size:12px;color:var(--pg-muted);margin-left:auto}
  .pg-news-title{font-size:15px;line-height:1.45;font-weight:600;color:var(--pg-text)}
  .pg-news-fams{margin-top:7px;font-size:12.5px;color:var(--pg-body)}
  .pg-news-det{margin-top:9px}
  .pg-news-det summary{cursor:pointer;font-size:12.5px;font-weight:600;color:var(--pg-amber);list-style:none;outline:none}
  .pg-news-det summary::-webkit-details-marker{display:none}
  .pg-news-det summary::before{content:'▸ ';font-size:11px}
  .pg-news-det[open] summary::before{content:'▾ '}
  .pg-news-hotels{margin-top:9px;display:flex;flex-direction:column;gap:6px}
  .pg-news-hotel{font-size:13px;line-height:1.35;color:var(--pg-body)}
  .pg-news-hotel a{color:var(--pg-text);font-weight:500;text-decoration:none;border-bottom:1px solid var(--pg-hairline)}
  .pg-news-hotel a:hover{border-bottom-color:var(--pg-amber)}
  .pg-news-hotel .op{margin-left:5px;padding:0 6px;border-radius:8px;font-size:10.5px;font-weight:600;color:#fff;background:#0891b2}
  .pg-news-hotel .sub{color:var(--pg-muted);margin-left:3px}
  /* Discover mode bar: lives IN the top row (middle of the chrome), shown once the
     pitch is dismissed. Frosted pill to match the other chrome controls. */
  /* ── Phase 2 (2026-07-12): the MODE PANEL — a moveable, collapsible window
        holding the mode switcher + the ACTIVE mode's world (pattern: mobile
        prototype 1C's mode-aware drawer, floating on desktop). On desktop the
        mode pill, per-mode filters, Trips bar and Destinations legend are
        slotted INTO it (JS placeModePanelNodes); mobile keeps every node in its
        original spot and never shows the panel. ── */
  /* The MAP MENU bar is SLIM (Jorg 2026-07-12): just the mode icons. Each mode's
     world is the pinnable side flyout .pg-world, so the bar no longer grows. */
  /* Repack glide + drag/first-paint suppression are centralised on .pg-dock-pill
     in includes/dock_pill.php — don't add a transition here. */
  .pg-modes{position:fixed;top:var(--pg-below-chrome);left:14px;z-index:6;width:92px;display:none;flex-direction:column;
    background:rgba(12,16,20,.82);border:1px solid var(--pg-hairline);border-radius:13px;overflow:visible;
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:0 10px 30px rgba(0,0,0,.45)}
  @media(min-width:769px){
    .pg-modes:has(.pg-discover.open){display:flex}   /* panel lives exactly when the modes do */
  }
  .pg-modes-head{display:flex;align-items:center;gap:6px;padding:7px 8px;cursor:grab;flex:none}
  .pg-modes-head .grip{color:var(--pg-muted);font-size:12px}
  .pg-modes-head .t{flex:1;font-family:var(--pg-font-mono);font-size:8px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--pg-amber);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-modes.collapsed .pg-modes-body, .pg-modes.collapsed .pg-world{display:none}
  .pg-modes-body{display:flex;flex-direction:column;min-height:0;overflow:hidden;border-radius:0 0 13px 13px}
  /* Mode WORLD = the pinnable side flyout. Positioned right of the bar; flips left
     when the bar is docked on the right; hidden when unpinned or during play. */
  .pg-world{position:absolute;top:0;left:100%;margin-left:6px;width:320px;max-height:calc(100vh - 140px);overflow:auto;
    display:flex;flex-direction:column;background:rgba(12,16,20,.82);border:1px solid var(--pg-hairline);border-radius:13px;
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 10px 30px rgba(0,0,0,.45)}
  .pg-modes.pg-dock-right .pg-world{left:auto;right:100%;margin-left:0;margin-right:6px}
  .pg-modes:not(.world-pinned) .pg-world, .pg-modes.playing .pg-world{display:none}
  /* Filter-panel collapse (Jorg 2026-07-14): hide the filters, keep the mode
     buttons + the header strip (with the expand chevron) so it's reachable. */
  .pg-modes.world-collapsed .pg-world-body{display:none}
  .pg-modes.world-collapsed .pg-world{width:auto;min-width:150px}
  /* The whole flyout header is the collapse target on desktop too (Jorg 2026-07-17b),
     mirroring the phone: title + chevron with dead space between = one hit strip. */
  .pg-world-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:9px 12px;border-bottom:1px solid rgba(255,255,255,.08);flex:none;cursor:pointer}
  .pg-world-head:hover{background:rgba(255,255,255,.04)}
  .pg-world-t{font-family:var(--pg-font-mono);font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--pg-amber);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-world-pin{background:none;border:0;cursor:pointer;font-size:13px;padding:0;opacity:.85;line-height:1}
  .pg-world-pin:hover{opacity:1}
  .pg-modes:not(.world-pinned) .pg-world-pin{opacity:.4;filter:grayscale(1)}
  .pg-world-body{display:flex;flex-direction:column;min-height:0;overflow:auto}
  /* Inside the panel the four modes stack VERTICALLY as icon+label rows, like the
     data + admin pills (Jorg 2026-07-12: "go vertical, with a few small icons"). */
  .pg-modes .pg-discover, .pg-modes .pg-discover.open{position:static;display:flex;flex-direction:column;width:auto;gap:2px;padding:2px 8px 8px;background:none;border:0;border-radius:0}
  .pg-modes .pg-discover button{flex:none;display:flex;flex-direction:column;align-items:center;gap:3px;text-align:center;padding:8px 4px;white-space:normal;width:100%;border-radius:8px}
  .pg-modes .pg-discover button .di{display:block;font-size:21px;line-height:1}
  .pg-modes .pg-discover button .dl{font-size:11px;font-weight:600;line-height:1.1}
  .pg-mine-master{display:flex;align-items:center;gap:7px;padding:7px 12px 9px;font-size:12px;color:var(--pg-body);cursor:pointer;border-top:1px solid rgba(255,255,255,.08)}
  .pg-mine-master input{accent-color:var(--pg-amber);margin:0}
  .pg-mine-warn{padding:0 12px 9px;font-size:11.5px;line-height:1.45;color:#e6c26a}
  .pg-mine-warn a{color:var(--pg-amber);font-weight:600}
  /* The mode's WORLD: filters stack vertically; trips + legend become sections. */
  /* align-items:stretch overrides the base .pg-filter's flex-end: in THIS column
     layout flex-end shrink-wraps children to max-content — the route finder sized
     itself to the longest airport name in the dropdown, right-aligned, and spilled
     LEFT past the panel edge into overflow:hidden (Jorg 2026-07-12 screenshot). */
  .pg-modes #pg-filter{flex-direction:column;align-items:stretch;gap:6px;padding:2px 10px 10px;border-top:1px solid rgba(255,255,255,.08)}
  .pg-modes #pg-filter .pg-fsel{width:100%;max-width:none;box-sizing:border-box}
  .pg-modes #pg-filter #pg-air-route{min-width:0}   /* stretched width wins; drop names ellipsise inside it */
  .pg-modes .pg-trips{position:static;width:auto;max-height:34vh;border:0;border-top:1px solid rgba(255,255,255,.08);border-radius:0;background:none;box-shadow:none}
  .pg-modes .pg-trips-head{cursor:default}
  .pg-modes .pg-legend{position:static;left:auto;right:auto;bottom:auto;max-width:none;display:none;margin:0;border:0;border-top:1px solid rgba(255,255,255,.08);border-radius:0;background:none;box-shadow:none}
  .pg-modes .pg-legend.open{display:block}
  .pg-modes .pg-legend-t{display:none}   /* the panel header already names the mode */
  /* Interactive itinerary inside the trip card (Phase 2.1): segment rows are the
     trip's remote control — flight isolates its arc, stay zooms to the hotel. */
  .pg-itin{margin-top:2px}
  .pg-itin-row{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:7px;cursor:pointer}
  .pg-itin-row:hover{background:rgba(255,255,255,.08)}
  .pg-itin-row.on{background:rgba(255,255,255,.12)}
  .pg-itin-row.mute{opacity:.55;cursor:default}
  .pg-itin-row .ic{flex:none;width:18px;text-align:center;font-size:13px}
  .pg-itin-row .ic.f{color:var(--cat-flights,#f59e0b)} .pg-itin-row .ic.s{color:var(--cat-stays,#7c3aed)}
  .pg-itin-row .m{min-width:0;flex:1}
  .pg-itin-row .m .l{display:block;font-weight:600;font-size:12.5px;color:var(--pg-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-itin-row .m .u{display:block;font-size:10.5px;color:var(--pg-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-itin-row .dt{flex:none;width:36px;font-family:var(--pg-font-mono);font-size:10px;color:var(--pg-muted)}
  /* Edit stays quiet until the row is under the cursor: an itinerary is for
     READING first. There is no hover on touch, so there it is simply visible. */
  .pg-itin-edit{flex:none;border:0;background:none;color:var(--pg-amber);cursor:pointer;font:inherit;
    font-size:12px;padding:2px 5px;border-radius:6px;opacity:0;transition:opacity .12s}
  .pg-itin-row:hover .pg-itin-edit,.pg-itin-edit:focus-visible{opacity:1}
  .pg-itin-edit:hover{background:rgba(245,158,11,.16)}
  /* The row you are ON. Same amber as the live block above it, so the panel
     tells one story: this is where you are, and that is its arc on the map. */
  .pg-itin-row.now{background:rgba(245,158,11,.10);border-left:2px solid var(--pg-amber);padding-left:6px}
  .pg-itin-row.now .l{color:var(--pg-text)}
  .pg-itin-row.now .nowchip{margin-left:7px;font-family:var(--pg-font-mono);font-size:9px;font-weight:700;
    letter-spacing:.1em;text-transform:uppercase;color:var(--pg-ink);background:var(--pg-amber);
    padding:1px 5px;border-radius:4px;vertical-align:1px}
  @media (hover:none){.pg-itin-edit{opacity:.75}}
  /* An itinerary needs elbow room: the trip card runs wider than the base card. */
  .pg-card:has(.pg-itin){width:380px}
  /* WIDTH, not a second surface. The expanded panel existed because the panel was
     too narrow to read a trip, and it answered that by covering the map the panel
     is there to talk to. A wider panel keeps the conversation and buys the room.
     It must be declared HERE, after the rule above and carrying .pg-itin itself:
     :has() counts toward specificity, so a bare `.pg-card.wide` TIES with
     `.pg-card:has(.pg-itin)` at (0,2,0) and then loses on source order. Measured
     on prod: the class toggled, localStorage stuck, and the card stayed 380px. */
  .pg-card.wide:has(.pg-itin),.pg-card.wide{width:520px}
  .pg-itin-all{margin-top:6px;padding:6px 8px;border-radius:7px;font-size:11.5px;font-weight:600;color:var(--pg-amber);cursor:pointer}
  .pg-itin-all:hover{background:rgba(255,255,255,.08)}
  .pg-itin-ctl{display:flex;gap:10px;align-items:center;margin-top:6px}
  .pg-itin-ctl span{padding:6px 8px;border-radius:7px;font-size:11.5px;font-weight:600;color:var(--pg-amber);cursor:pointer}
  .pg-itin-ctl span:hover{background:rgba(255,255,255,.08)}
  /* ── Air route finder (From ⇄ To), FlightConnections-style (2026-07-12) ── */
  #pg-air-route{position:relative}
  .pg-ar-row{display:flex;gap:5px;align-items:center}
  .pg-ar-row input{flex:1;min-width:0;box-sizing:border-box;font-family:var(--pg-font-body);font-size:12.5px;color:var(--pg-text);
    background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);border-radius:7px;padding:7px 9px;outline:none}
  .pg-ar-row input:focus{border-color:rgba(255,255,255,.35)}
  #pg-ar-swap{flex:none;width:30px;height:30px;border-radius:7px;background:rgba(255,255,255,.07);border:1px solid var(--pg-hairline);color:var(--pg-text);cursor:pointer;font-size:13px;line-height:1}
  #pg-ar-swap:hover{background:rgba(255,255,255,.14)}
  .pg-ar-drop{display:none;max-height:240px;overflow:auto;margin-top:5px;background:rgba(16,20,25,.97);border:1px solid var(--pg-hairline);border-radius:9px;padding:4px}
  .pg-ar-drop.open{display:block}
  .pg-ar-h{font-family:var(--pg-font-mono);font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--pg-muted);padding:5px 8px 2px}
  .pg-ar-it{display:flex;gap:8px;align-items:baseline;padding:6px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--pg-text)}
  .pg-ar-it:hover{background:rgba(255,255,255,.08)}
  .pg-ar-it .c{font-family:var(--pg-font-mono);font-weight:700;color:var(--cat-flights,#f59e0b);flex:none;min-width:34px}
  .pg-ar-it .n{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-ar-it .s{flex:none;font-size:10px;color:var(--pg-muted)}
  .pg-ar-sortbar,.pg-apd-sortbar{display:flex;gap:4px;padding:1px 4px 6px}
  .pg-ar-sort,.pg-apd-sort{flex:1;font-family:var(--pg-font-mono);font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--pg-muted);background:rgba(255,255,255,.05);border:1px solid var(--pg-hairline);border-radius:6px;padding:4px 3px;cursor:pointer}
  .pg-ar-sort.on,.pg-apd-sort.on{color:var(--cat-flights,#f59e0b);border-color:rgba(245,158,11,.5);background:rgba(245,158,11,.12)}
  .pg-ar-sort .ar,.pg-apd-sort .ar{font-size:8px;margin-left:2px;vertical-align:1px}
  /* Airport card's inline destinations list — the To-box list, brought into the card. */
  .pg-apd{margin-top:6px}
  .pg-apd-list{display:flex;flex-direction:column;gap:1px}
  .pg-apd-row{display:flex;align-items:center;gap:9px;padding:7px 6px;border-radius:7px;cursor:pointer}
  .pg-apd-row:hover{background:rgba(255,255,255,.06)}
  .pg-apd-row .c{flex:none;min-width:34px;font-family:var(--pg-font-mono);font-weight:700;font-size:12px;color:var(--cat-flights,#f59e0b)}
  .pg-apd-row .m{flex:1;min-width:0}
  .pg-apd-row .m .t{display:block;font-size:12.5px;font-weight:600;color:var(--pg-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-apd-row .m .u{display:block;font-size:10.5px;color:var(--pg-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-apd-row .km{flex:none;font-family:var(--pg-font-mono);font-size:10px;color:var(--pg-muted);text-align:right;line-height:1.3}
  .pg-rte-ep{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer}
  .pg-rte-ep:hover{background:rgba(255,255,255,.06)}
  .pg-rte-ep .c{flex:none;min-width:30px;font-family:var(--pg-font-mono);font-weight:700;font-size:11px;color:var(--cat-flights,#f59e0b)}
  .pg-rte-ep .n{flex:1;min-width:0;font-size:11.5px;color:var(--pg-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pg-rte-ep .go{flex:none;font-size:10px;color:var(--cat-flights,#f59e0b)}
  .pg-route-play{display:block;width:100%;margin:8px 0 2px;padding:9px;border-radius:8px;border:1px solid rgba(245,158,11,.5);background:rgba(245,158,11,.14);color:var(--cat-flights,#f59e0b);font-family:var(--pg-font-body);font-weight:700;font-size:13px;cursor:pointer}
  .pg-route-play:hover{background:rgba(245,158,11,.22)}
  @media(max-width:768px){ #pg-air-route{flex:1 1 100%} }
  @media(max-width:768px){ .pg-modes.ar-listing{ z-index:11 !important; } }   /* Air dropdown open => over the airport card (z10) */
  @media(max-width:768px){
    .pg-modes{display:none !important}   /* mobile keeps the rail row + original surfaces */
  }
  .pg-discover{display:none;flex:none;gap:4px;padding:4px;border-radius:10px;background:rgba(12,16,20,.55);border:1px solid rgba(255,255,255,.14);
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
  .pg-discover.open{display:inline-flex}
  .pg-discover button{background:transparent;border:0;color:var(--pg-body-bright);font-family:var(--pg-font-body);font-weight:600;
    font-size:13.5px;padding:8px 14px;border-radius:8px;cursor:pointer;white-space:nowrap}
  .pg-discover button .di{display:none}   /* icons only show in the vertical panel; mobile/hero keeps labels */
  /* #C94B2C, not --pg-vermilion: white on #D2502F is 4.26:1, under 4.5 for 13.5px
     text. Same shade as .pb-chip.on in style.css (PEL-34), so both phone bars match. */
  .pg-discover button.on{background:#C94B2C;color:#fff}
  .pg-discover button:not(.on):hover{background:rgba(255,255,255,.08)}
  .pg-discover .pg-chain{margin-left:4px;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18);color:var(--pg-text);
    font-family:var(--pg-font-body);font-size:13px;font-weight:600;border-radius:8px;padding:7px 10px;cursor:pointer}
  .pg-discover .pg-chain option{color:#111}
  /* Trips toggle: a sub-control of My map, set off by a divider (not a peer mode). */
  /* ── Phone chrome, ≤768px (iPhone/Android; iPad portrait benefits too).
        Desktop ≥769 is untouched. Built 2026-07-12 after the emulated iPhone walk:
        the one-row chrome overflowed (modes under the profile button, filters and
        zoom pushed off-screen, card under the control bar). Approach: top bar
        becomes TWO rows (logo·search·account over a swipeable mode rail) via
        display:contents — no DOM moves; bottom bar wraps its filters onto their
        own row; the card becomes a true bottom sheet ABOVE the controls. ── */
  @media(max-width:768px){
    .pg-chrome{flex-wrap:wrap;gap:10px;row-gap:10px;height:auto;padding:calc(10px + env(safe-area-inset-top)) 12px 12px;z-index:8}   /* two rows again: height:auto overrides the desktop --pg-chrome-h; above the trips bar (z6) so the open search overlay wins */
    .pg-center{display:contents}   /* dissolve: search + mode rail become chrome flex items */
    .pg-logo{order:1;font-size:18px}
    .pg-search-wrap{order:2}
    .pg-chrome-r{order:3;gap:8px}
    .pg-discover{order:4;flex:0 0 100%;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:2px}
    .pg-discover.open{display:flex}   /* keep the hero's hidden→open lifecycle; flex (not inline-flex) so the rail fills its row */
    .pg-discover::-webkit-scrollbar{display:none}
    .pg-discover button{flex:none}
    /* Account controls compact: About ▾ → an ⓘ chip; profile name ellipsises.
       TWO buttons need this, not one (fixed 2026-07-15c):
         #pg-about-btn  = the GUEST acquisition menu (welcome_map's own, original).
         (the .abt-trigger chip that used to sit here left with the drawer, 08-30)
                          which logged-in users get since the 07-12 chrome unification.
       Only the first had the rule, so guests collapsed to ⓘ and members kept a
       full-width "About ▾" — which pushed the member top bar onto TWO ROWS and
       squeezed the wordmark out of the logo. The mobile rule had been left pointing
       at the component the unification replaced. This is the "mobile stopped
       tracking desktop" root cause in one concrete instance; the 07-12 notes flagged
       "mobile About-pill vs lens_topbar crowding to eyeball" and it never was. */
    #pg-about-btn,
    #pg-about-btn::before,
    /* the caret is a separate <span> inside the shared chip — hide it, ⓘ carries the affordance */
    .pg-discover{position:static}   /* mobile keeps the full-width rail row, not the floating pill */
    .pg-lens-data{padding:9px 12px;font-size:13.5px}
    .pg-login{padding:9px 12px;font-size:13.5px}
    .pg-register{padding:9px 12px;font-size:13.5px}
    /* The legend rides inside the mode popover on a phone, whose title bar already
       says DESTINATIONS — hide the legend's own title so it doesn't read twice (2026-07-19). */
    #pg-legend .pg-legend-t{display:none}
    /* Search opens as a FIXED full-width overlay (the absolute popover overflowed). */
    .pg-search-wrap.mini-open .pg-search{position:fixed;left:12px;right:12px;top:calc(112px + env(safe-area-inset-top));width:auto;z-index:21}
    .pg-search-wrap.mini-open .pg-search-results{position:fixed;left:12px;right:12px;top:calc(158px + env(safe-area-inset-top));width:auto;max-height:46vh}
    /* ⭐ THE CONTROL BLOCK STAYS ON THE MAP, BOTTOM RIGHT, on the phone exactly as on
       the desktop — same two squares, same 16px inset from the right. It used to be
       reparented into the bottom sheet by phoneMoves, so it inherited the sheet's
       horizontal scroll and could be pushed off-screen; the 2026-08-30 finding that
       #pg-mapctl sat 247px beyond the right edge at 390px was that, and this removes
       the cause rather than the symptom.
       ⚠ LIFTED CLEAR OF THE SHEET, not laid over it: --pg-bar-h is the one number
       that tracks the bar's height (47px), and the safe-area inset is added because
       a phone's home indicator sits below both. */
    .pg-mapctl{
      left:auto; right:16px;
      /* ⭐ +5, AND IT IS A GAP AGAIN RATHER THAN A CORRECTION (2026-09-02).
         This used to read +14, with the reason written out: "the variable says 47px
         and the bar measures 56px ... it has drifted, by 9px". So 14 was 9 of repair
         plus 5 of actual gap. --pg-bar-h is now MEASURED off #pg-modes at runtime,
         so the 9 is gone from every consumer at once and only the 5 belongs here.
         ⛔ THIS HAD TO MOVE IN THE SAME CHANGE. Leaving +14 against a variable that
         is finally right over-lifts the controls by exactly the amount it used to be
         short — the same 9px, in the other direction, and just as invisible from a
         desktop probe. */
      bottom:calc(var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))) + 5px);
      flex-wrap:nowrap; gap:8px; align-items:flex-end;
    }
    /* ⚠ No rule for #pg-filter here, and that is checked rather than assumed: the
       `moves` list slots it into the sheet on BOTH tiers at boot, so it is never a
       child of the control block by the time this could apply. Measured at 390px —
       ctl.querySelector('#pg-filter') is null. A rule for it would be dead CSS
       describing a layout that no longer exists. */
    .pg-filter{order:-1;flex:0 0 100%;display:flex;gap:6px;min-width:0}
    .pg-filter .pg-fsel{min-width:0;max-width:48vw}
    .pg-mapbtn{white-space:nowrap}
    /* Hero: bottom sheet (as before) + CTA wrap for narrow phones. */
    .pg-hero{width:100%;top:auto;bottom:0;height:auto;justify-content:flex-end;padding:0 18px calc(20px + env(safe-area-inset-bottom));
      background:linear-gradient(0deg,var(--pg-scrim) 0%,rgba(6,10,16,.2) 60%,rgba(6,10,16,0) 100%)}
    .pg-cta-row{flex-wrap:wrap}
    .pg-stats{display:none}
    /* ── The on-map info card (Option D §9) ────────────────────────────────
       "Tapping a pin, arc or airport must NOT reuse the bar (which is the map's
       global controls). It should rise as an object-anchored popover — same visual
       family, dismissed by tapping the map — carrying that object's detail."
       Under B this was bottom:0 — a second bottom sheet, stacking with the mode
       sheet on a 932px screen until the map disappeared behind furniture. That is
       why B needed the pg:cardopen hack to force the mode sheet down.
       Under D it sits ON the bar's top line, in the popover's visual family, and
       never underneath it. Same family, different job: the bar's panel answers
       "what am I looking at", the card answers "what is THIS thing".
       Note it is NOT anchored to the tapped pin's pixel position: on a 390px screen
       an object-anchored popover would spend its life clamped to an edge, and the
       map pans under your thumb. Bar-anchored is the honest reading of §9's intent
       ("its own surface, not the bar's"), and it keeps the dismiss model identical. */
    .pg-card{left:8px;right:8px;top:auto;width:auto;transform:none;z-index:10;
      bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px)));
      max-height:52vh;overflow:auto;border-radius:14px 14px 0 0;background:rgba(18,23,28,.97);
      border:1px solid rgba(255,255,255,.14);
      padding-top:0;padding-bottom:14px}
    /* Destinations legend: lifted clear of the (possibly two-row) control bar. */
    .pg-legend{left:12px;right:12px;bottom:calc(104px + env(safe-area-inset-bottom));max-width:none}
    /* Trips bar: full-width chip BELOW the two-row chrome; expanded list capped. */
    .pg-trips{left:12px;right:12px;width:auto;top:calc(140px + env(safe-area-inset-top));max-height:calc(100vh - 320px)}
    /* ⛔ FIVE ROWS AND A SCROLLER, THE SAME AS DESKTOP. Jorg, 2026-08-31: "the my map
       menu shows all trip ... maximize the trip to 5 and if it's more create a scroll
       box within the panel for that, basically the same as in desktop."
       38vh is ~320px on a 844px phone — eleven rows — so on any real account the trip
       list ate the panel and pushed Default / All / None out of sight. That is why he
       could not find them: they were never removed, only shoved below the fold.
       ⚠ Same arithmetic as the desktop rule and the same --pg-trip-row, so the two
       cannot drift: five rows plus the list's own 5px top and bottom padding. Getting
       this wrong by 2px is what clipped the fifth trip on desktop in August. */
    .pg-trips-list{max-height:calc(var(--pg-trip-row,30px) * 5 + 10px)}
  }
  /* Narrow phones: the wordmark yields to the spark (✦ stays tappable as the
     home/reset control) so guest chrome [✦ ⌕ ⓘ Log-in Sign-up] holds ONE row. */
  @media(max-width:480px){
    .pg-logo{font-size:0;gap:0}
    .pg-logo .spark{font-size:22px}
    .pg-lens-data{font-size:0;width:40px;height:40px;padding:0;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box}
    .pg-lens-data::before{content:'◫';font-size:17px}
  }
  /* Touch devices zoom by pinching — the +/− buttons just eat bar space. Full
     screen is NOT in that group and now shares their box, so hide the three and
     let it fill the square rather than hiding the container it moved into. */
  @media(pointer:coarse){
    /* ── THE TOUCH CONTROL BAR: three pills, horizontal ──────────────────────
       Jorg, 2026-08-31: "maybe it's also not needed on a mobile screen to have
       plus/minus. only center, full screen and layers. you can make the pills small
       and place them horizontal as a bar."
       ⭐ ZOOM IN / OUT GO because the screen already has pinch — two buttons for a
       gesture the device does natively. CENTRE and FULL SCREEN stay because nothing
       on a phone replaces them.
       ⛔ BUT THE ORIGINAL RULE HID CENTRE TOO, leaving one cell holding only the
       full-screen glyph — which iOS often cannot render — so the square read as
       empty: "just a black square. nothing to see in it."
       ⚠⚠ AND NO BROWSER PROBE COULD HAVE CAUGHT IT. `pointer:coarse` never matches a
       desktop iframe, so every measurement reported all four buttons present at
       33x33. The documented "cannot emulate touch" limit does not only cost
       INTERACTION — it silently skips whole media queries, so a layout can be broken
       on the device and perfect in every probe. Exercise these declarations by
       swapping the query, or do not claim to have checked them. */
    .pg-zoom > #pg-zin, .pg-zoom > #pg-zout{display:none}
    /* One row, one height, small pills. 40px tall is the tap floor that still reads
       as a bar rather than as three buttons. */
    .pg-mapctl{gap:6px; align-items:center}
    .pg-mapctl .pg-layers{width:auto; height:40px}
    .pg-mapctl .pg-layers > .pg-mapbtn{width:44px; height:40px; border-radius:10px}
    /* ⚠ Icon only. "Layers" beside a 44px pill wraps or truncates, and the icon is
       the same one the desktop square shows above its label. */
    .pg-mapctl .pg-layers > .pg-mapbtn .dl{display:none}
    .pg-mapctl .pg-layers > .pg-mapbtn .di{font-size:17px}
    /* ⚠ border-box and a 1fr row, NOT an explicit 40px one. The base rule gives this
       a 1px border, so an explicit 40px row plus that border made the pill 42px tall
       and sat it ONE PIXEL below the Layers pill beside it — measured at 741 against
       742, which is exactly the kind of thing that reads as "slightly wrong" and
       never gets diagnosed. Let the declared height include the border and let the
       row fill it. */
    /* ⛔⛔ AUTO COLUMNS, NOT A FIXED TWO. This is the real cause of "the right button
       is still empty and doesn't do anything", and the SVG I swapped in yesterday was
       treating a symptom that was never it.
       welcome_map.php's own handler hides #pg-fs on iPhone Safari — "iPhone Safari has
       NO element-fullscreen API (iPad does) — hide the button there instead of leaving
       a dead control" — via style.display='none'. With `grid-template-columns:44px
       44px` the track stayed anyway, so the pill kept its 88px width and rendered a
       44px slab of empty dark glass where the button used to be. A hidden child in a
       FIXED grid does not give its space back.
       ⚠ So the button really is dead on an iPhone, and that is a PLATFORM limit rather
       than a bug: there is no element-fullscreen API there to call. The fix is that
       the pill now measures itself from the buttons that actually exist. */
    .pg-zoom{
      width:auto; height:40px; box-sizing:border-box;
      grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:44px;
      grid-template-rows:1fr;
      border-radius:10px;
    }
    /* The 2x2 dividers were drawn for a square; in a row only the middle one is
       between two cells. */
    .pg-zoom button:nth-child(odd){border-right:0}
    .pg-zoom button:nth-child(-n+2){border-bottom:0}
    .pg-zoom > #pg-zreset{border-right:1px solid rgba(255,255,255,.14)}
    .pg-zoom button{font-size:17px}
  }

  /* ══════════════════════════════════════════════════════════════════════════
     CONCEPT B — the phone bottom sheet                        (Jorg, 2026-07-15c)
     ══════════════════════════════════════════════════════════════════════════
     Direction B out of the A/B/C fork: on a phone the chrome is ONE persistent,
     thumb-first bottom sheet instead of five floating surfaces scattered around
     the screen. At rest it shows the mode switcher under the thumb; drag it up
     and it becomes the active mode's world (filter, trips, legend, wishlist,
     my-data, layers).

     THE KEY MOVE — and the reason this is small rather than a rewrite:
     #pg-modes is ALREADY the desktop dock pill, and placeModePanelNodes()
     already reparents #pg-discover / #pg-filter / #pg-trips / #pg-legend into its
     slots on desktop. The old mobile branch scattered those nodes back to
     separate homes and then hid the pill — which is exactly why the phone lost
     the world panel and the wishlist. So B does not add a second chrome:
     #pg-modes IS the sheet on a phone. Same element, same slots, same JS, two
     skins. That is the "content contract" answer to the two-chromes maintenance
     risk — a node cannot exist on desktop and go missing on phone, because there
     is only one container and it is this one.

     Peek vs open reuses the EXISTING .world-collapsed class (which already hides
     .pg-world-body) rather than inventing a state. Desktop is untouched: every
     rule below is inside the phone media query.
     ────────────────────────────────────────────────────────────────────────── */
  @media(max-width:768px){

    /* ── The sheet shell ───────────────────────────────────────────────── */
    /* !important on the geometry: pgDockPill writes inline left/top from
       localStorage for the desktop pill. The JS skips the dock on phone, but a
       stale saved position must not be able to fling the sheet off-screen. */
    /* ══ OPTION D: the sheet becomes a BAR ═══════════════════════════════════
       Spec: docs/Option D Mobile design.pdf (design team + Jorg, 2026-07-16).
       D keeps every win of B and removes its two-step tap-then-swipe: a tab both
       selects the mode AND opens its panel, and the panel rises ABOVE the bar
       exactly like the desktop .pg-layers popover already does.

       WHAT SURVIVES FROM B — and it is the important part. B's guarantee was that
       #pg-modes IS the phone surface: same element as the desktop dock pill, same
       placeModePanelNodes() slots, so a node cannot exist on desktop and vanish on
       phone. That is what fixed the phone silently losing the route finder, the
       legend, the trips list and the wishlist. D does NOT introduce a second
       chrome: this is still #pg-modes, still the same slots, still the same JS.
       Only its SHAPE changes — sheet → bar — and its world moves from an inline
       drag-up to a popover. The container contract is untouched.

       Fixed height, not max-height: a bar has one size. B's max-height + transition
       existed to animate peek→open, and D has no peek. */
    .pg-modes{
      display:flex !important;
      position:fixed !important;
      left:0 !important; right:0 !important; top:auto !important;
      bottom:0 !important;
      width:100% !important; max-width:none !important;
      transform:none !important;
      flex-direction:column;
      gap:0;
      z-index:9;                       /* over the map + mapctl, under the search overlay */
      /* §2 dimensions: app glass + a 1px top hairline.
         THE GLASS IS ON ::before, NOT HERE — deliberately (Jorg, device pass
         2026-07-16: "the bottom scroll bar from left to right [doesn't work]... I
         see a little bit of calendar falling off the screen").
         The row is a proper scroller (810px of chips in a 390px bar, verified) and
         scrollLeft moves it — but a SWIPE did nothing on his iPhone. Cause: this
         element was position:fixed WITH backdrop-filter, and the scroller was its
         child. On iOS, touch-scrolling a child of a backdrop-filtered fixed box is
         unreliable — same family as the containing-block trap that bit three times
         on 07-15, hitting touch instead of layout this time.
         So the blur moves to a sibling pseudo-element painted behind the row, and
         the scroller is no longer inside a filtered box. Identical pixels, working
         gesture. NB Chrome-on-desktop has no touch, which is exactly why the rig
         insisted this was fine — programmatic scrollLeft exercises a different code
         path than a finger, and I tested the wrong one. */
      background:transparent;
      /* Explicitly none: the DESKTOP .pg-modes rule sets backdrop-filter:blur(10px)
         and it inherits straight through this media block. Clearing the background
         without clearing the filter left the scroller inside a filtered box anyway —
         i.e. the fix looked done and changed nothing. The blur now lives only on
         ::before. */
      -webkit-backdrop-filter:none;
      backdrop-filter:none;
      border:0;
      /* STRAIGHT top edge — no radius. §2 is explicit and correct: a rounded top
         clips the chips as they scroll horizontally underneath it, and the bar
         reads as a card instead of a bar. The popover that sits on this line
         shares it, so the two read as one continuous surface. */
      border-radius:0;
      box-shadow:0 -10px 34px rgba(0,0,0,.5);
      max-height:none;
      /* ⛔ THE FULL SAFE-AREA INSET WAS 34px OF EMPTY GLASS UNDER THE CHIPS. Jorg,
         2026-08-28: "the bottom footer has a lot of blank space below my map,
         flights, hotels, etc. That row of buttons can be placed a lot lower.
         Remove the additional blank space, which is an additional row."
         Arithmetic: the chip row is ~30px of chips inside 11px padding = 52px, and
         this line added env(safe-area-inset-bottom) — 34px on an iPhone with a home
         indicator — entirely BELOW them. Two thirds of a row of nothing.
         ⚠ THE INSET IS NOT DELETED. It exists so touch targets clear the home
         indicator, and zeroing it would put the chips under the bar you swipe up
         from. It is reduced: 14px is given back to the layout and the rest kept,
         with a 4px floor for devices that report no inset at all. */
      /* ⚠ REDUCED AGAIN 2026-08-31, same complaint from the same person: "the bottom
         bar still has quite some black space between bottom edge and bottom of text.
         minimize that." The 08-28 pass gave back 14px of the inset; below the chips
         that still left ~20px here plus 7px inside .pg-modes-body — 27px under a row
         with 10px above it. Now 24px is given back, leaving ~10px on an iPhone, and
         the body's own bottom padding drops to 4px: about 14px below against 10px
         above, which reads as a row in a bar rather than a row floating in one.
         ⛔ STILL NOT ZERO. The inset exists so the chips clear the home indicator you
         swipe up from; deleting it trades a cosmetic complaint for an unusable row. */
      padding:0 0 max(2px, calc(env(safe-area-inset-bottom,0px) - 24px));
      overflow:visible;   /* the popover is reparented out, but nothing here clips */
      transition:none;
    }
    /* The bar's glass, as a layer BEHIND the row rather than a filter AROUND it.
       pointer-events:none so it can never intercept the swipe it exists to sit
       under — the whole point of moving it here. */
    .pg-modes::before{
      content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
      background:rgba(18,23,28,.96);
      -webkit-backdrop-filter:blur(20px) saturate(1.1);
      backdrop-filter:blur(20px) saturate(1.1);
      border-top:1px solid rgba(255,255,255,.18);
    }
    /* The row rides above the glass. position:relative gives it a stacking level
       without making it a containing block for anything that matters. */
    .pg-modes .pg-modes-body{ position:relative; z-index:1; }

    /* B's peek state is gone: a bar has no peek. Kept as a no-op override so any
       stale .world-collapsed left on the element by B's JS can't resize the bar. */
    .pg-modes.world-collapsed{ max-height:none; }

    /* §10 + LEGAL: "keep the attribution legible and unobstructed (legal
       requirement)". The bar is fixed to the bottom and MapLibre pins its ctrl
       containers to bottom:0 — so the bar sat straight on top of the OpenStreetMap
       / Esri credit and hid it. Measured: attribution bottom 844 vs bar top 781.
       That is an ODbL/Esri licence term, not a polish item, and it fails silently.
       Lift the controls to sit ON the bar's top line. --pg-bar-h is the single
       source for the bar's height so this offset cannot drift away from it. */
    /* ⚠ 47px, DOWN FROM 63px, and it has to move with the bar. This is the single
       source for lifting MapLibre's attribution onto the bar's top line — an ODbL
       and Esri licence term, not polish — so a bar that got shorter while this
       stayed at 63 would float the credit in mid-air over the map. Chips ~30px
       inside 10px/7px padding = 47px. */
    /* ⚠ A PRE-JS FLOOR, NOT THE ANSWER. The bar publishes its measured height into
       this variable at runtime (see the ResizeObserver near the card handlers); this
       value only holds until that first measurement. 56px because that is what the
       bar was measured at — the old 47px named the chip row alone and left every
       consumer 9px short, which is F-11's overlapping card.
       ⚠ THE FLOOR CARRIES THE INSET TOO, since 2026-09-05. The token means one
       thing — the distance from the viewport's bottom edge to the top of the bar
       — and the MEASURED value is a border-box height that already includes the
       bar's safe-area padding. A floor of a bare 56px would mean something
       different from the value that replaces it milliseconds later, which is the
       disagreement that let nine consumers add the inset a second time. */
    :root{ --pg-bar-h: calc(56px + env(safe-area-inset-bottom,0px)); }
    .maplibregl-ctrl-bottom-left,
    .maplibregl-ctrl-bottom-right,
    .mapboxgl-ctrl-bottom-left,
    .mapboxgl-ctrl-bottom-right{
      bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))) !important;
      z-index:7;
    }

    /* ── THE SCRIM IS GONE (Jorg, device pass 2026-07-16) ─────────────────────
       "When the panel is out from the bottom, I am unable to move the map anymore.
        Even with destinations, when the panel is closed, I can't even move the map
        anymore... I really need to click again on hotels."
       §4 asks for "a transparent scrim over the map [to catch] the tap". I built it
       literally, and it was wrong: a full-bleed element over the map catches the
       dismiss tap AND every pan, pinch and drag. The map went dead the moment a
       panel opened — which contradicts §1's own "Map stays the hero". A hero you
       cannot touch is wallpaper.
       Dismiss now rides MapLibre's own click event instead (see the JS). MapLibre
       already distinguishes a click from a drag, so panning survives and a genuine
       tap still closes the panel — which is what the scrim was for. The element is
       kept, inert, purely so nothing that references #pg-scrim throws.
       The lesson worth keeping: a spec can name a mechanism that defeats its own
       principle. §1 is the principle; the scrim was only ever an implementation. */
    .pg-scrim{ display:none !important; }

    /* Hero state: no sheet. The hero's job is one decision — demo or browse — and
       it already suppresses every other control. The sheet is the EXPLORE state;
       it rises on the same hidden→open lifecycle the mode rail already uses. */
    .pg-modes:not(:has(.pg-discover.open)){ display:none !important; }

    /* ── The grab handle is GONE (Option D §4) ─────────────────────────── */
    /* "No grabber, no swipe-to-expand, no drag-to-reposition. The bar and its
       popovers have one home — the bottom."
       B needed a handle because opening the world was a second gesture: tap a mode,
       then swipe up. D deletes the gesture, so the affordance for it has nothing
       left to afford. The whole header goes — including the ::after grab zone that
       used to extend 26px down over the mode rail, which now would only sit in
       front of the tabs eating taps for a drag that no longer exists.
       The element stays in the DOM (desktop renders it as the dock pill's drag
       header); the phone simply doesn't show it. */
    .pg-modes .pg-modes-head{ display:none !important; }

    /* ── Body: the mode rail, always visible, thumb-height ─────────────── */
    /* The BODY is the scroller now, not #pg-discover — so the modes and the Layers /
       My-data controls sit on ONE scrollable row together (Jorg: "place it on the bar
       that you can scroll from left to right"). Nesting a scroller inside a scroller
       would fight the swipe. */
    /* With the grab handle gone (D §4), the body IS the bar. Padding is set so the
       row lands on §2's ~62px: 40px chips + 11px above and below. The safe-area
       inset is on .pg-modes, below this, so the chips stay off the home indicator
       without the bar's glass stopping short of the screen edge. */
    .pg-modes .pg-modes-body{
      flex:none; border-radius:0;
      display:flex; flex-direction:row; align-items:center; gap:8px;
      /* ⚠ ASYMMETRIC ON PURPOSE: less below than above, because whatever the inset
         gives back is already empty space under the row. 11/11 read as a row floating
         in the middle of the bar. */
      padding:10px 12px 4px;
      overflow-x:auto; overflow-y:hidden;
      -webkit-overflow-scrolling:touch; scrollbar-width:none;
      overscroll-behavior-x:contain;
      /* Animates any scrollLeft assignment — which is how the tap-a-clipped-chip
         scroll gets its glide (scrollTo({behavior:'smooth'}) measured as a no-op on
         this element). The drag handler sets scrollLeft too, so it is exempted below
         or every finger-move would be chased by a 300ms animation and feel like mud. */
      scroll-behavior:smooth;
      /* touch-action:none, and the JS owns the drag (see the drag-to-scroll block).
         Native touch scrolling here failed on Jorg's iPhone twice and I could not
         diagnose it — this harness has no touch, so every theory was a guess.
         `none` stops the browser competing for the gesture: if native scrolling
         were left enabled AND it works on some device, both it and the pointer
         handler would move the row and it would scroll at double speed. One owner.
         Wheel/trackpad are unaffected by touch-action, so desktop keeps scrolling
         natively. */
      touch-action:none;
    }
    .pg-modes .pg-modes-body::-webkit-scrollbar{ display:none; }

    /* ── The chips arrive from the right, once, on load ────────────────────
       Jorg 2026-07-16: "make people aware it's a scrollable bar when the page is
       loaded... it swipes in from the side so you see it move and bounce one time
       or something like that. Make it a fun feeling. It needs to be so fast that it
       doesn't disrupt the workflow, but it does make it clear there's movement."
       This is the cheapest possible answer to the problem his device pass exposed:
       a row that scrolls and a row that doesn't look identical at rest, so he
       reported "I cannot scroll" when he could. A fade would say "here is a bar";
       arriving from the right says "this bar came from somewhere, and there is more
       of it over there". The motion IS the affordance.
       On the chips, not the bar: the glass should already be in place, and only its
       contents should look like they slid in.
       Timing, 2nd pass — Jorg: "the animation of the bottom bar moving inwards from
       the side when loading the page can be a bit slower. I barely see it, if at
       all." Two reasons he barely saw it, both fixed here: .34s was over before the
       map had finished painting (so it competed with the boot veil for attention),
       and 28px of travel is less than half a chip — it read as a settle, not an
       arrival. Now .62s, 96px of travel, and a short delay so it starts AFTER the
       first tiles land and has the eye to itself.
       Still one overshoot, still under a second: it must be done before a thumb
       arrives, or it becomes something you wait through on every load. */
    .pg-modes .pg-modes-body > *{
      animation:pg-chips-in .62s cubic-bezier(.18,1.28,.4,1) .18s both;
    }
    @keyframes pg-chips-in{
      from{ transform:translateX(96px); opacity:0 }
      to  { transform:none;             opacity:1 }
    }
    /* The Layers / My-data group trails the modes, so the row reads as a sequence
       arriving from the right rather than one block sliding — which is what makes
       the "there is more over there" point. Widened with the longer duration; at
       .06s the stagger was invisible. */
    .pg-modes #pg-modes-slot-ctl{ animation-delay:.30s; }
    @media (prefers-reduced-motion: reduce){
      .pg-modes .pg-modes-body > *{ animation:none; }
    }
    /* §2: "Right-edge fade or a peeking half-chip signals more when the row
       overflows (member view)." Worth having for a reason Jorg's device pass made
       plain: he reported "I cannot scroll the bottom bar to the left" — and the row
       DOES scroll (810px of chips in a 390px bar, verified). With no scrollbar, no
       fade and chips ending flush at the edge, a row that scrolls and a row that
       doesn't look identical. "I can't" and "I didn't know I could" are the same
       screenshot. The fade is the difference.
       pointer-events:none — it must never eat a tap meant for the chip beneath it.
       It hangs off .pg-modes (which does not scroll), NOT off the scroller: an
       absolute child of a scrolling box scrolls away with the content, so a fade
       there would slide off the edge on the first swipe — visible at rest, gone
       exactly when it is doing its job. `bottom` clears the safe-area inset so the
       gradient covers the chip row and not the home indicator. */
    .pg-modes::after{
      content:''; position:absolute; right:0; top:0;
      bottom:env(safe-area-inset-bottom,0px);
      width:34px; pointer-events:none; z-index:2;
      background:linear-gradient(90deg, rgba(18,23,28,0) 0%, rgba(18,23,28,.96) 78%);
    }
    .pg-modes #pg-modes-slot-discover,
    .pg-modes #pg-modes-slot-ctl{ display:flex; align-items:center; flex:none; }
    /* A hairline between the modes and the global controls: they are different kinds
       of thing (which view vs how it's drawn) and shouldn't read as one list. */
    .pg-modes #pg-modes-slot-ctl:not(:empty){
      border-left:1px solid rgba(255,255,255,.12); padding-left:8px; margin-left:2px;
    }
    /* Horizontal on phone (desktop stacks it vertically in the pill); the parent
       scrolls, so this one just lays out. */
    .pg-modes .pg-discover,
    .pg-modes .pg-discover.open{
      display:flex !important;
      flex-direction:row !important;
      gap:6px;
      width:auto;
      padding:0; overflow:visible;
      background:none; border:0; border-radius:0;
    }
    /* width/flex-direction need !important: the desktop pill sizes these to
       width:100% and stacks icon-over-label for the VERTICAL rail. Inherited into
       a row that made each button 406px wide, so the rail scrolled to 1666px and
       showed exactly one mode — the other three were off-screen right. */
    .pg-modes .pg-discover button{
      flex:none;
      display:inline-flex !important;
      flex-direction:row !important;
      width:auto !important;
      align-items:center; gap:6px;
      min-height:40px; padding:0 14px;
      border-radius:11px;
      font-size:13.5px; font-weight:600;
      white-space:nowrap;
    }
    /* Icons come back on phone — they are the fastest thing to hit with a thumb.
       (The base rule hides .di outside the vertical desktop panel.) */
    .pg-modes .pg-discover button .di{ display:inline !important; font-size:14px; }

    /* ── World: the POPOVER above the bar (Option D §5) ─────────────────── */
    /* B had the world inline inside the sheet, revealed by dragging. D raises it as
       a popover anchored on the bar's straight top line — the same rule the desktop
       .pg-layers menu already uses (bottom: calc(100% + 8px)). §1: "Phone and
       desktop share one interaction model, which is the guard against the drift
       that produced today's broken phone chrome."
       Anchored to the BAR, not to the viewport: it is the bar's panel, and if the
       bar ever changes height the panel follows without a second magic number.

       §5 says to reparent this to <body> "to escape the bar's stacking/overflow
       context", as #pg-layers-menu does. Not needed here, and worth saying why:
       .pg-layers-menu is position:FIXED inside an ancestor with backdrop-filter —
       which becomes the containing block for fixed descendants — inside .pg-modes'
       overflow:hidden. That is the 07-15 trap. This popover is position:ABSOLUTE
       against .pg-modes itself (already fixed), and D's bar sets overflow:visible
       because it no longer has a sheet to clip. So there is nothing to escape: it
       anchors correctly and follows the bar for free. Reparenting anyway would
       trade that for a manual bottom offset to maintain. If .pg-modes ever regains
       overflow:hidden, this breaks and the reparent comes back. */
    .pg-modes .pg-world{
      display:flex; flex-direction:column;
      min-height:0;
      position:absolute;
      left:8px; right:8px;
      /* §5 contradicts itself here: "sharing its straight top line — reuse the
         desktop rule bottom: calc(100% + 8px)" AND "its bottom meets the bar's
         straight edge". Those are different geometries — the +8px is a gap. The
         desktop .pg-layers menu has that gap because it's a detached menu floating
         over the map; this popover is specified to read as ONE continuous surface
         with the bar ("the popover that sits on it shares that straight top line",
         §2). Intent wins over the copied rule: bottom:100% puts its bottom exactly
         on the bar's top edge, no seam, which is what both §2 and the rest of §5
         describe. */
      bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px)));
      top:auto; width:auto; max-width:none;
      transform:none;
      /* Glass on ::before for the same reason as the bar: .pg-world-body scrolls
         vertically, and a scroller inside a backdrop-filtered box is the thing that
         killed the bar's swipe on iOS. The panel's content is capped at 60dvh and
         WILL scroll (My map's trips + wishlist already do), so it would have hit
         the identical bug the first time a list got long — just later, and further
         from the cause. Fix both while the reason is fresh.
         backdrop-filter:none is load-bearing — the desktop .pg-world rule sets
         blur(14px) and it inherits into this block. */
      background:transparent;
      -webkit-backdrop-filter:none;
      backdrop-filter:none;
      border:1px solid rgba(255,255,255,.14);
      /* Rounded TOP corners are fine (it's a card); the bottom meets the bar's
         straight edge, so the two read as one surface. §5. */
      border-radius:14px 14px 0 0;
      box-shadow:0 -18px 50px rgba(0,0,0,.5);
      /* Content-height, capped. Never full height — the map must stay visible (§1,
         "Map stays the hero"). */
      max-height:60vh; max-height:60dvh;
      overflow:hidden;
      z-index:10;
    }
    .pg-modes.world-collapsed .pg-world{ display:none; }
    /* ⛔ THE LEGEND CARRIES ITS OWN TITLE AND IT IS SLOTTED INSIDE THE PANEL THAT
       ALREADY NAMES IT. Jorg, 2026-09-02: "destinations has 2 times the title, so
       remove 1." #pg-legend is slotted into .pg-world-body, whose head is
       #pg-world-title and reads "Destinations" the moment that mode is active — so
       the word printed twice, once per owner.
       ⚠ HIDDEN ONLY WHERE IT IS SLOTTED, never deleted from the markup: the legend
       renders in other places where nothing else names it, and removing the element
       would leave those untitled. Scoped to the panel, which is the only context
       where the duplication exists. */
    .pg-modes .pg-world-body .pg-legend-t{ display:none; }
    /* The panel's glass, behind its content — see the note above. inset:-1px so it
       sits under the 1px border rather than leaving a hairline gap at the top. */
    .pg-modes .pg-world::before{
      content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
      border-radius:inherit;
      background:rgba(18,23,28,.97);
      -webkit-backdrop-filter:blur(20px) saturate(1.1);
      backdrop-filter:blur(20px) saturate(1.1);
    }
    .pg-modes .pg-world-head,
    .pg-modes .pg-world-body{ position:relative; z-index:1; }
    /* Entrance: a short rise + fade (§5, ~200ms ease-out).
       clip-path, NOT transform:translateY — same lesson the search taught an hour
       earlier. translateY moves the element's real box, so the panel measured 877
       against the bar's 870 while Layers/My-data sat flush at 869: an 8px
       disagreement between three surfaces that are meant to share one line, caused
       entirely by an animation that hadn't settled. Worse, if the animation stalls
       the panel just IS 8px out of place, permanently.
       clip-path only masks paint: the box is in its final position from frame one,
       the rise still reads, and a stalled animation degrades to "it appeared". */
    .pg-modes .pg-world{
      animation:pg-pop-rise .2s cubic-bezier(.2,.8,.2,1);
    }
    @keyframes pg-pop-rise{
      from{ opacity:0; clip-path:inset(12% 0 0 0 round 14px 14px 0 0) }
      to  { opacity:1; clip-path:inset(0 0 0 0 round 14px 14px 0 0) }
    }
    @media (prefers-reduced-motion: reduce){
      .pg-modes .pg-world{ animation:pg-pop-fade .2s ease-out; }
      @keyframes pg-pop-fade{ from{ opacity:0 } to{ opacity:1 } }
    }
    /* The WHOLE header collapses the panel, not just the ▾ (Jorg 2026-07-17: "if I
       click anywhere in the top bar from my map till the collapse button, then the
       whole thing should collapse. The same with air, hotels, destinations").
       Right call: the header is a title and a chevron with dead space between them,
       and that dead space looks exactly like the rest of the affordance. A 44px-tall
       strip that does nothing across most of its width is a target you have to aim
       at. Now the strip IS the target and the ▾ is just the icon on it. */
    .pg-modes .pg-world-head{
      flex:none; padding:11px 14px 6px;
      display:flex; align-items:center; justify-content:space-between;
      cursor:pointer; -webkit-tap-highlight-color:transparent;
      min-height:44px; box-sizing:border-box;
    }
    .pg-modes .pg-world-head:active{ background:rgba(255,255,255,.05); }
    /* The ✕ comes back: with no grabber and no drag, the header's close button is
       how you dismiss without hunting for the active tab. (Tapping the map or the
       active tab still work — §4.)
       Jorg's device pass: "there is a collapse button to down, but it is extremely
       small... Response is actually pretty good with touch, so that's okay. It's
       just the visualization. The size is just too small."
       Exactly right, and a useful distinction: the HIT AREA was already 44px (the
       touch-target rule further down), so it responded fine — it was the GLYPH that
       was 13px, sized for a mouse. Only the drawing was wrong. */
    .pg-modes .pg-world-head .pg-pnl-min{
      display:inline-flex; align-items:center; justify-content:center;
      font-size:20px; line-height:1;
      min-width:44px; min-height:44px;
      margin:-8px -8px -8px 0;     /* absorb the bigger box so the head doesn't grow */
      color:var(--pg-text);
    }
    .pg-modes .pg-world-body{
      overflow-y:auto; -webkit-overflow-scrolling:touch;
      overscroll-behavior:contain;      /* don't scroll-chain into the map behind */
      max-height:calc(60dvh - 44px);
      padding:0 12px 12px;
    }
    /* The Calendar tab's pane. The iframe scrolls itself, so the pane is a fixed
       window onto it rather than something the world-body scrolls — nesting the two
       scrollers would make the agenda fight the panel. */
    #pg-cal-pane{ display:flex; flex-direction:column; gap:8px; }
    #pg-cal-pane iframe{
      width:100%; height:calc(60dvh - 104px); min-height:220px;
      border:0; border-radius:10px; background:transparent; display:block;
    }
    /* §5: "Primary actions bottom-anchored inside each panel so they stay in thumb
       reach even when the panel is tall." */
    #pg-cal-pane .pg-cal-full{
      flex:none; text-align:center; text-decoration:none;
      font-size:13px; font-weight:600; color:var(--pg-amber,#e8a64a);
      padding:9px; border-radius:9px;
      background:rgba(255,255,255,.05); border:1px solid rgba(255,255,255,.12);
    }
    /* Slotted nodes shed their floating-surface skins inside the sheet.
       NO `display` HERE — deliberately. The first cut forced display:flex!important,
       which overrode the app's OWN visibility logic for every slotted node: #pg-filter
       is inline-styled display:none until its mode is active, and #pg-trips is
       logged-in-only. Forcing them visible leaked YOUR TRIPS to guests (Jorg's
       device pass) and made the sheet show panels that had no business being open —
       most of the "it's unstable, things move around". Geometry only; the app
       decides what is shown. */
    .pg-modes .pg-world-body #pg-filter,
    .pg-modes .pg-world-body #pg-trips,
    .pg-modes .pg-world-body #pg-legend,
    .pg-modes .pg-world-body #pg-mapctl{
      position:static !important;
      left:auto !important; right:auto !important; bottom:auto !important; top:auto !important;
      transform:none !important;
      width:auto !important; max-width:none !important;
      background:none !important; box-shadow:none !important;
      border:0 !important; border-radius:0 !important;
      margin:0 0 8px;
    }
    /* Layers / My data now live ON the rail, so they are chips in a row, not a block
       in a panel. The flyouts open UPWARD out of the sheet (there is nothing below a
       bottom sheet) and are pinned to the viewport, not to the chip — a menu anchored
       to a chip you can scroll horizontally would slide off with it. */
    .pg-modes #pg-modes-slot-ctl #pg-mapctl{
      position:static !important;
      left:auto !important; right:auto !important; bottom:auto !important; top:auto !important;
      transform:none !important;
      width:auto !important; max-width:none !important;
      background:none !important; box-shadow:none !important; border:0 !important;
      display:flex !important; flex-wrap:nowrap; gap:6px; align-items:center; margin:0;
    }
    .pg-modes #pg-modes-slot-ctl .pg-mapbtn{ flex:none; white-space:nowrap; }

    /* ── The flyouts are REPARENTED TO <body>, and they must be ────────────
       Jorg: "if I click layers with my finger, nothing happens." The menu was
       opening into a 0px window. Two rules of mine combined to do it:
         .pg-modes { backdrop-filter: blur(20px); overflow: hidden; }
       A backdrop-filter (like transform/filter) creates a CONTAINING BLOCK for
       position:fixed descendants. So the flyout stopped being positioned against
       the viewport and started being positioned against the 86px sheet — and was
       then clipped away by the sheet's own overflow:hidden. It was opening
       perfectly, just inside a box 86px tall with hidden overflow.
       Same family as the About-drawer trap in the 07-12 notes (a fixed drawer
       inside .pg-chrome's stacking context), and the same cure: move it to <body>.
       The JS does the move; these rules style it once it's there. */
    /* Visibility is driven by .open ON THE MENU (mirrored from the wrapper by the
       observer), because the stock descendant selector cannot reach it out here. */
    .pg-flyout-phone{ display:none !important; }
    .pg-flyout-phone.open{ display:flex !important; }
    .pg-flyout-phone{
      position:fixed !important;
      /* 8px inset + the bar's own height token — matching the mode panel exactly.
         Jorg 2026-07-16: "the layer and my data layers are too high above the bottom
         bar. There's a row in between. It's not the same height as the other pop-up
         layers."
         Measured: mode panel bottom 878, these at 836 — a 34px band of map showing
         underneath, which is why they read as a different kind of thing.
         Cause: `bottom: env(...) + 96px` — a literal from Concept B, whose sheet was
         96px tall at peek. D's bar is 62px, so the number was 34px stale the moment
         the sheet became a bar. Anchored to --pg-bar-h now, the same token the
         attribution and the card use, so all three move together if the bar's height
         ever changes again and none of them can drift on their own. */
      left:8px !important; right:8px !important;
      top:auto !important;
      bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))) !important;
      width:auto !important; max-width:none !important;
      max-height:60dvh; overflow-y:auto; -webkit-overflow-scrolling:touch;
      overscroll-behavior:contain;
      z-index:12;
    }
    .pg-modes #pg-modes-slot-ctl .pg-layers,
    .pg-modes #pg-modes-slot-ctl .pg-mine{ position:static; }
    /* The legend is a horizontal row of swatch+caption pairs built for a wide
       flyout; at 430 it squeezed into three ~90px columns of wrapped text. Stack it. */
    .pg-modes .pg-world-body #pg-legend{ flex-direction:column !important; align-items:flex-start; gap:6px; }
    .pg-modes .pg-world-body #pg-legend > *{ display:flex; align-items:center; gap:8px; }
    /* Layers/My-data flyouts inside the sheet: drop upward-floating, sit inline. */
    .pg-modes .pg-world-body .pg-layers-menu,
    .pg-modes .pg-world-body .pg-mine-menu{
      position:static; width:auto; max-width:none; margin-top:6px;
    }

    /* ── The card shares the sheet's language and sits above it ────────── */
    .pg-card{
      z-index:10;
      /* Jorg: "if I click a flight arc and see the route box, it is not scrollable,
         so I cannot completely see the bottom." The card is a fixed-height bottom
         sheet; a route card (carriers both ways + a trips list) simply runs past it
         with no way down. The card scrolls now, and stops short of the mode sheet so
         the two never overlap. */
      /* Cap so the sheet's TOP never climbs over the top chrome bar, whatever the
         content height (a big hub like AMS has a long trips + routes list). Reserve the
         bottom bar (--pg-bar-h), both safe-area insets, and the ~62px top bar + a small
         gap (Jorg 2026-07-18: "the box is too high, it goes over the top menu; the max
         is just below the top menu"). 100dvh so Safari's toolbar doesn't inflate it. */
      max-height:calc(100dvh - var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))) - env(safe-area-inset-top,0px) - 74px);
      overflow-y:auto; -webkit-overflow-scrolling:touch;
      overscroll-behavior:contain;
    }
    /* Close/collapse must stay put while the body scrolls under them. */
    .pg-card-head{ position:sticky; top:0; z-index:2; background:rgba(18,23,28,.97); margin:0 -16px; padding:7px 16px 3px; }

    /* ── Playing a trip: the card gets out of the way ──────────────────── */
    /* Jorg: "when I clicked Play Trip, the trip box is hiding half the screen —
       auto-hide the box. If possible put a little label for each thing being shown
       directly on the map... don't show the whole box, it takes half the screen."
       .pg-card.collapsed already existed for exactly this shape: it hides meta, stats,
       detail, expand, nudge, CTA and the wishlist row, leaving the h3 — which IS the
       label ("Mandarin Oriental Doha", "Amsterdam → Doha"). So the play loop just
       collapses the card rather than inventing a second subtitle component. */
    body.pg-playing .pg-card{
      max-height:none; overflow:visible;
      border-radius:14px 14px 0 0;
    }
    /* While Play trip runs (phone), the card shrinks to a SINGLE row above the bottom
       bar: JUST the currently-animating segment (Jorg 2026-07-17f: "you would only see
       one row above the bottom menu bar showing the trip segment jumping"). The header
       (kind + buttons) AND the trip name are hidden; only the itinerary's own .on row
       shows — city → city, the hotel, IATA + dates — updating live as the reel advances,
       so the map is the hero and the card is one thin label. Tapping the row (a human
       take-over) stops playback and restores the full card, as does the reel finishing. */
    body.pg-playing .pg-card.collapsed{ padding:8px 12px 10px; }
    body.pg-playing .pg-card.collapsed .pg-card-head,
    body.pg-playing .pg-card.collapsed h3{ display:none !important; }
    body.pg-playing .pg-card.collapsed .pg-card-detail{ display:block !important; }
    body.pg-playing .pg-card.collapsed .pg-itin{ margin:0; }
    body.pg-playing .pg-card.collapsed .pg-itin-row{ display:none; }
    body.pg-playing .pg-card.collapsed .pg-itin-row.on{ display:flex; padding:8px 6px; cursor:default; }
    body.pg-playing .pg-card.collapsed .pg-itin-row.on .m .l{ font-size:13.5px; }
    body.pg-playing .pg-card.collapsed .pg-itin-ctl{ display:none; }

    /* ── Hero: a scrim so the pitch survives a bright basemap ─────────── */
    /* Jorg's device pass: "the world map is too light for it, the white fonts fall
       away against the background." The hero is white type straight onto satellite
       imagery — legibility depends on whatever happens to be under it, which over
       Sahara or cloud is nothing. A bottom-anchored gradient is better than a solid
       box: it darkens the type without drawing a rectangle across the map, and it
       fades out before the horizon so the map still reads as the hero. */
    /* Reaches higher than the first cut (Jorg: "the Living Atlas of Your Travels is
       barely readable") — the eyebrow sits at the very TOP of the hero block, which
       is exactly where the old gradient had already faded out. Full opacity now runs
       past the eyebrow before it starts to fall away. */
    .pg-hero{
      background:linear-gradient(to top,
        rgba(8,10,14,.96) 0%, rgba(8,10,14,.95) 58%,
        rgba(8,10,14,.90) 84%, rgba(8,10,14,.62) 92%,
        rgba(8,10,14,.24) 97%, rgba(8,10,14,0) 100%);
      padding-top:104px;
    }
    /* Guests only: with the sheet absent on the hero, nothing else claims the
       bottom, so the scrim can run to the edge. */
    .pg-hero-inner{ max-width:none; }

    /* ── The "What is Pelgrim?" panel flies in from the LEFT ───────────── */
    /* Jorg: "the fly-in happens from the right side instead of the left side.
       Let's keep that the same as the web version. Move it to the left."
       The About drawer (abt-drawer) already comes from the left; pg-story was the
       one surface still arriving from the right, so the two info panels contradicted
       each other. Phone only — desktop keeps its right-hand story panel until we
       decide to unify there too. */
    .pg-story{
      right:auto !important; left:0 !important;
      transform:translateX(-102%);
      width:min(470px,94vw);
    }
    .pg-story.open{ transform:none; }

    /* ── Top bar, Concept B: ONE row ───────────────────────────────────── */
    /* The demo chip ships "◉ Demo · Exit ✕" (118px) and pushed the avatar off the
       right edge on a 430 screen (Jorg's device pass). The "· Exit ✕" tail is the
       expendable half — tapping the chip still exits, and the tooltip still says so. */
    /* Jorg 2026-07-16: "the demo exit purple button is slightly taller, a few pixels,
       than the info search pills." In Chrome it measures 38px — identical to .abt-trigger
       and .pg-search-icon, no shadow, same border — so I cannot reproduce it here and am
       not going to guess at Safari's box maths a third time. Instead: remove every way it
       COULD differ. It was the only chip in the row sized by padding rather than by the
       shared height rule, and padding + a line-height the others don't share is exactly
       how a box ends up a few pixels proud. Fixed height, border-box, line-height:1,
       align-self:center — nothing left to disagree about. (The 07-15c note above this
       block records the same complaint about .lt-demo being "a few pixels higher"; it was
       patched with alignment then and is back, which is the argument for removing the
       cause rather than nudging it.) */
    .lt-demo{
      font-size:12px; padding:0 9px;
      height:38px; min-height:38px; box-sizing:border-box;
      line-height:1; align-self:center;
      display:inline-flex; align-items:center; justify-content:center;
    }
    .lt-demo span{ display:none; }

    /* ── One control height across the whole bar ───────────────────────── */
    /* Jorg: "the search bar is bigger than the info box, the info icon box is bigger
       than the login box, Create-a-free-account is the same as info — it would be
       nice if everything was the same." They were each sized independently: About by
       width/height, login/register by padding, search by its own box. One token, one
       height, one radius, everything vertically centred. */
    .pg-chrome #pg-about-btn,
    .pg-chrome .pg-search-icon,
    .pg-chrome .pg-login,
    .pg-chrome .pg-register,
    .pg-chrome .lt-demo,
    .pg-chrome .pg-mapbtn{
      height:38px; min-height:38px; box-sizing:border-box;
      display:inline-flex; align-items:center; justify-content:center;
      border-radius:10px;
    }
    .pg-chrome #pg-about-btn,
    .pg-chrome .pg-search-icon{ width:38px; padding:0; }
    .pg-chrome .pg-login,
    .pg-chrome .pg-register{ padding:0 12px; font-size:13px; white-space:nowrap; }

    /* ── OPTICAL CORRECTION, not a bug fix ────────────────────────────────────
       Jorg reported three times that a solid chip looks taller than its neighbours
       (sign-up vs log-in; the demo-exit pill vs info/search). Every time, a full
       computed-style diff came back with ZERO differences: same height 38, same top
       10, same bottom 48, same padding, border, box-sizing, line-height. The boxes
       are identical to the pixel.
       What differs is the FILL. In both pairs the chip that reads as taller is the
       solid saturated one (vermilion, purple) and the one it is judged against is
       translucent dark (rgba(12,16,20,.55)) over a bright map. A bright, hard-edged
       shape looks larger than a dark, soft-edged shape of the same size — the
       irradiation illusion. His eye is right and the geometry is right; they just
       disagree.
       So: correct the optics, not the maths. The solid chips lose 1px so they LOOK
       level with the glass ones. This is a deliberate lie in the stylesheet — hence
       the size of this comment. Do not "fix" it back to 38 because a diff says the
       heights are unequal; that is the point.
       If a future chip is solid-filled, it belongs in this list. If one turns
       translucent, take it out. */
    .pg-chrome .pg-register,
    .pg-chrome .lt-demo{ height:37px; min-height:37px; }
    /* Jorg 2026-07-16: "the sign-up button is still taller than the login button."
       The boxes are pixel-identical (both 38px, same top, same bottom) — what he was
       seeing is the CTA glow: box-shadow 0 14px 30px -12px in vermilion at 70%,
       i.e. a 30px halo pushed 14px BELOW the button. On a 60px-tall bar that reads
       as extra height. The shadow exists so register "jumps out past Log in"
       (2026-07-10), but on a phone the vermilion fill already does that job at this
       size; the glow only adds fake height. Desktop keeps it. */
    .pg-chrome .pg-register{ box-shadow:none; }

    /* ── The guest bar has to FIT (Jorg, iPhone, 2026-07-16) ────────────────── */
    /* "'Create a free account'... goes outside the width of my phone." A guest bar
       carries five things — logo, ⓘ, ⌕, Log in, and the register CTA — and the
       full label alone is 155px of a 390px screen. So the CTA takes its short
       label here. Same trick public_layout already uses for the same reason.
       Measured after: the whole bar lands ~57px inside the right edge at 390px,
       which is the margin it needs, because Safari's font metrics differ from the
       Chrome rig I verify in and the rig has been wrong about this bar before. */
    .pg-chrome .pg-cta-full{ display:none; }
    .pg-chrome .pg-cta-mini{ display:inline; }
    /* The chrome's own padding is tightened further down this block (search for
       "padding-left:8px") — it must be set THERE, not here: a later .pg-chrome rule
       in the same media block re-declares padding and would silently win. That is
       exactly what happened on the first attempt at this fix. */
    .pg-chrome .pg-left{ min-width:0; }
    .pg-chrome .pg-chrome-r{ min-width:0; }

    /* ── The guest About dropdown opened off the LEFT edge ─────────────── */
    /* Jorg: "that pop-up box falls outside the left side of the screen... it needs to
       be moved a little bit to the right." Cause: .pg-profile-menu is
       position:absolute; right:0 — anchored to the RIGHT edge of its trigger. On
       desktop the trigger sits far right, so the menu grows leftward into free space.
       On a phone the ⓘ sits at x=12, so "grow leftward" means straight off-screen.
       Anchor it to the LEFT of the trigger instead and cap it to the viewport. */
    .pg-chrome .pg-profile-menu{
      right:auto; left:0;
      min-width:0; width:max-content;
      max-width:calc(100vw - 24px);
    }

    /* ── The search popover ran off the right edge ─────────────────────── */
    /* Jorg: "the gap on the left side is OK, on the right side it falls outside."
       The popover is `position:absolute; left:0; width:min(80vw,340px)` — anchored to
       a .pg-search-wrap that sits at x=183, so 183+340 = 523 on a 430 screen. It was
       never going to fit; the width was chosen against the viewport but positioned
       against the icon. Pin it to the VIEWPORT instead (position:fixed, both edges),
       which also stops the wrap resizing and nudging the icon sideways on open —
       Jorg: "when I click on search the icon moves a few pixels to the right."
       NB the class is .mini-open, not .open — an earlier cut of this fix targeted the
       wrong class and silently did nothing. */
    /* ── Search: fill the bar at rest, take the whole bar when open ─────────
       Jorg 2026-07-16: "It is a little bit sad when there is space left on the left
       and the right side. It should autofill it with the same margins... When you
       click on it, it needs to open very fast, with an animation opening to the left
       and right... It needs to show the whole bar on that top bar level, so it can go
       over the info box, over the logo."
       At rest the wrap was pinned to 38px, so any spare width in the top row just sat
       there as a gap. It now GROWS into whatever the logo/ⓘ and the account controls
       leave — one flexible item between two fixed groups, so the margins stay equal by
       construction rather than by arithmetic. min-width:0 is what lets a flex item
       actually shrink below its content on a narrow screen. */
    .pg-search-wrap{ flex:1 1 auto !important; width:auto !important; max-width:none !important; min-width:0 !important; }
    .pg-chrome .pg-search-icon{
      width:100% !important; min-width:0;
      justify-content:flex-start; gap:8px; padding:0 11px !important;
    }
    /* Open: the field lands ON the top bar's own row (not below it) and spans the
       screen, covering the logo, the ⓘ and the account controls. z-index above the
       chrome's children — it is deliberately taking the whole bar. */
    .pg-search-wrap.mini-open .pg-search{
      position:fixed !important;
      left:8px !important; right:8px !important;
      top:calc(11px + env(safe-area-inset-top,0px)) !important;
      height:38px !important;
      width:auto !important; max-width:none !important;
      box-sizing:border-box; z-index:30;
      /* "an animation opening to the left and right" — done with clip-path, NOT
         transform:scaleX.
         scaleX was the obvious choice and it was wrong: it scales the element's
         actual box, so anything measuring the field mid-flight sees a 145px control
         instead of a 414px one — and if the animation ever fails to run (it froze at
         frame 0 in testing) you are left with a permanently squashed bar rather than
         a missing animation. A broken control is worse than a static one.
         clip-path only masks what's painted: the box is full-width from the first
         frame, the reveal opens from the centre outward exactly as asked, and a
         failure mode is "it appeared instantly", which is fine. Still compositor-
         driven, still .14s ("very fast"). */
      animation:pg-search-open .14s ease-out;
    }
    @keyframes pg-search-open{
      from{ clip-path:inset(0 32% 0 32% round 9px); opacity:.35 }
      to  { clip-path:inset(0 0 0 0 round 9px);     opacity:1 }
    }
    @media (prefers-reduced-motion: reduce){
      .pg-search-wrap.mini-open .pg-search{ animation:none }
    }
    .pg-search-wrap.mini-open .pg-search-results{
      position:fixed !important;
      left:8px !important; right:8px !important;
      top:calc(57px + env(safe-area-inset-top,0px)) !important;
      width:auto !important; max-width:none !important;
      max-height:calc(100vh - 120px); overflow-y:auto; z-index:30;
    }
    /* The ⌕ chip hides while the field owns the row — two search affordances at once
       reads as a bug. */
    .pg-search-wrap.mini-open .pg-search-icon{ opacity:0; pointer-events:none; }
    /* The ✕ rides ON the open field, right-aligned, above it in z so the input's own
       padding-right keeps the text from running underneath. Only exists while open. */
    .pg-search-x{ display:none; }
    .pg-search-wrap.mini-open .pg-search-x{
      display:inline-flex; align-items:center; justify-content:center;
      position:fixed; z-index:31;
      right:12px; top:calc(11px + env(safe-area-inset-top,0px));
      width:38px; height:38px; padding:0;
      background:none; border:0; cursor:pointer;
      color:var(--pg-text); font-size:15px; line-height:1;
      -webkit-tap-highlight-color:transparent;
    }
    .pg-search-wrap.mini-open .pg-search{ padding-right:42px !important; }

    /* ── Card controls: touch targets ──────────────────────────────────── */
    /* Jorg, twice: "the Collapse and Close buttons are too small... especially with
       your thumb." 44px is Apple's MINIMUM, which is the floor for a precise tap, not
       a comfortable one for a control you hit while holding the phone one-handed.
       48px + a wider glyph. */
    .pg-card .x,
    .pg-card #pg-card-min{
      width:48px; height:48px;
      display:inline-flex; align-items:center; justify-content:center;
      font-size:19px; line-height:1;
    }
    /* Same treatment for every other close/collapse chevron on the phone.
       #abt-dclose was REMOVED from this list 2026-07-16. It was the reason the
       About drawer's ✕ came out visibly fatter than its ⧉ neighbour — Jorg: "the
       Copy Shared Link is a much smaller box than the Close box... the closing
       button is really maybe too big." This rule is an ID selector (1-0-0), so it
       beat the drawer's own .abt-dhead chip sizing (0-1-1) and no amount of
       tidying in about_drawer.php could have won. The drawer now sizes its own
       header chips, in one place, and they can't disagree. */
    .pg-story-x, .pg-pnl-min{
      min-width:44px; min-height:44px;
      display:inline-flex; align-items:center; justify-content:center;
    }

    /* ── The profile menu could not reach "Sign out" ───────────────────── */
    /* Jorg: "the profile menu doesn't scroll, so you cannot go to log out through
       that menu." It is a desktop dropdown with ~14 items; on a 932px screen hanging
       off a 60px bar it simply runs past the bottom of the viewport with nothing to
       scroll. Sign out is the last item, so it was unreachable. */
    .pg-chrome .ribbon-avatar-menu{
      max-height:calc(100vh - 92px - env(safe-area-inset-bottom,0px));
      overflow-y:auto; -webkit-overflow-scrolling:touch;
      overscroll-behavior:contain;
    }

    /* ── The Info chip belongs to the RIGHT of the logo ────────────────── */
    /* Jorg: "the info box is still left of the Pelgrim logo. Move it to the right."
       .pg-left is a flex row and the markup already puts the logo first, but the
       chip still painted first — so force it explicitly rather than depend on
       source order that clearly isn't behaving. Brand leads, chrome follows. */
    .pg-left{ flex-wrap:nowrap; }
    .pg-left .pg-logo{ order:1; }
    .pg-left #pg-about-btn{ order:2; }

    /* ── The demo pill says what it does ───────────────────────────────── */
    /* Jorg: "the purple demo pill only says demo and not demo exit... if you make the
       font small enough, maybe you can call it exit demo." I had hidden the "· Exit ✕"
       tail to win width back; that was the wrong economy — the pill stopped saying
       what tapping it does. Restored at 11px instead. There is room: the right cluster
       only spends 111px of 430. */
    .lt-demo span{ display:inline; font-size:11px; opacity:.9; }
    .lt-demo{ gap:4px; }
    /* SUPERSEDED 2026-07-16 — the wrap GROWS into the spare width now.
       This rule pinned it to 40px to stop a 220px min-width pushing the avatar off
       a 430 screen. That min-width is still wrong, but the cure went too far: with
       the wrap frozen at 40px, whatever the logo/ⓘ and the account controls left
       over just sat there as dead air. Jorg: "It is a little bit sad when there is
       space left on the left and the right side. It should autofill it."
       The real fix is min-width:0 (which lets the item shrink when there ISN'T
       room) plus flex-grow (which lets it take room when there is) — one rule that
       handles both directions instead of a constant that handles neither.
       Kept as a comment, not deleted: this is the THIRD .pg-search-wrap width pin in
       this file, and they overwrote each other silently. If you are about to add a
       fourth, edit the one below instead. */
    .pg-search-wrap{
      flex:1 1 auto !important;
      min-width:0 !important; width:auto !important; max-width:none !important;
    }
    /* Jorg: "the profile picture falls outside the screen by a few pixels — bring the
       info, search, calendar and demo pills closer together." And: "the demo exit pill
       is a few pixels higher than the other pills." Both come from the same place —
       the bar's gaps were desktop-sized (12px between every control, plus .lt-group's
       own gap), and .lt-demo aligned itself while the rest inherited the bar's
       alignment. Tighten the gaps and align everything from one place. */
    /* padding 12 → 8 (Jorg 2026-07-16): "the Pelgrim account can move a little bit
       more to the left if it's so small, because there's quite a gap to the left of
       the compass and the edge of the left side of the screen." Buys 8px across the
       row, which the guest bar (5 controls) needs more than the member bar does. */
    .pg-chrome{ flex-wrap:nowrap; row-gap:0; gap:6px; align-items:center; padding-left:8px; padding-right:8px; }
    .pg-center{ display:contents; }
    .pg-left{ gap:7px; }
    .pg-chrome-r{ gap:6px; align-items:center; }
    .lt-group{ gap:6px; align-items:center; }
    /* .lt-demo sat a few px proud of its neighbours: it is inline-flex with its own
       line-height and no explicit self-alignment, so it centred on the text baseline
       rather than the row. Pin it like everything else. */
    .pg-chrome .lt-demo{ align-self:center; margin:0; line-height:1; }
    /* The mode rail has moved into the sheet, so it no longer needs a chrome row. */
    .pg-chrome > .pg-discover{ display:none !important; }
  }
  /* ══════════════════════════════════════════════════════════════════════════
     PHONE LANDSCAPE — ask for portrait rather than ship a broken page
     ══════════════════════════════════════════════════════════════════════════
     Jorg turned his phone by accident: "the landscape front page really looks bad,
     you cannot read anything... I'm not saying we need to design a landscape front
     page, but at least can we prevent that aspect ratio from being shown at all?"

     The hero is a bottom-anchored block sized for ~932px of height. At 430px of
     height it has nowhere to go: headline, sub, two CTAs and the scrim collide.
     Designing a second hero for a viewport nobody browses a travel map in is not
     worth a day; saying "turn it round" costs twenty lines and is honest.

     THE DISCRIMINATOR IS HEIGHT, NOT ORIENTATION. An iPad Pro in landscape is
     1366×1024 and perfectly capable — it must never see this. Phones in landscape
     are ~375–430px tall, so `max-height:500px` catches every phone and no tablet.
     `orientation:landscape` alone would have hit every iPad. Also scoped to coarse
     pointers so a short desktop window is never told to rotate a mouse.
     ────────────────────────────────────────────────────────────────────────── */
  @media (orientation:landscape) and (max-height:500px) and (pointer:coarse){
    .pg-rotate{ display:flex !important; }
    /* Freeze the page underneath: no scrolling a layout we have just disowned. */
    html, body{ overflow:hidden; }
  }
  .pg-rotate{
    display:none;
    position:fixed; inset:0; z-index:99999;
    flex-direction:column; align-items:center; justify-content:center;
    gap:14px; padding:24px calc(24px + env(safe-area-inset-right)) 24px calc(24px + env(safe-area-inset-left));
    background:#0b0d10; color:var(--pg-text,#e8eaed); text-align:center;
  }
  .pg-rotate-ico{ font-size:38px; line-height:1; color:var(--pg-amber,#e8a64a); }
  .pg-rotate h2{ margin:0; font:700 19px/1.25 var(--pg-font-display,inherit); }
  .pg-rotate p{ margin:0; max-width:34ch; font-size:13.5px; line-height:1.5; color:var(--pg-body,#cdd3d2); }
  .pg-rotate small{ font-family:var(--pg-font-mono,inherit); font-size:11px; color:var(--pg-muted,#8b9391); letter-spacing:.04em; }

  /* The wordmark stays on BOTH bars at phone width (Jorg, 2026-07-15c: "on the
     front page there needs to be a compass with the name Pelgrim — otherwise you
     don't see the name anywhere else on the site, and I think it fits").
     I had argued the guest hero carries the brand in its headline so the bar could
     keep a bare compass. Wrong: the headline says "Your travels, on one living map"
     — it never says PELGRIM. The product name appeared nowhere on the phone front
     door. Overrides the ≤480 `.pg-logo{font-size:0}` collapse above, which existed
     to buy width back; the collapsed search + 38px controls have since paid for it.
     Logo a touch smaller than the member bar's so the guest CTAs still fit. */
  @media(max-width:480px){
    .pg-logo{ font-size:14px; gap:5px; }
    .pg-logo .spark{ font-size:18px; }
    body.pg-authed .pg-logo{ font-size:15px; gap:6px; }
  }

  /* ⭐ THE LAYOUT: Map, Split, List (One Map stage 3.2, 7 October 2026; decisions q3, q5,
     q10). welcome_map.php's pgSetLayout() sets body.pg-layout-split or -list.
     Split: the panel sits between the rail and the map, and the MAP starts at the
     panel's edge, so nothing it draws hides under the list. List: the panel takes the
     whole width; the mode row stays on top of it, so the panel's head clears the row.
     --pg-panel-w is the divider's width (pgPanelClamp: 280 to 720 px, at most 60% of
     the room beside the rail); the min() here keeps a narrowed window from losing the
     map. In Split the mode row wraps inside the map's width rather than run off it
     (measured 7 Oct at 1024 px: a 532 px panel cut the layout switch off).
     ⛔ The ground is the THEME's surface, text and border (q10), never a fixed dark: the
     panel is a page of rows on paper or atlas, unlike the frosted chips floating on the
     map. ⚠ Desktop only; the phone sheet is 3.6. */
  .pg-panel, .pg-layout-sw, .pg-panel-grab, .pg-world-list{display:none}
  .pg-panel-x{margin-left:auto;align-self:center;font:inherit;font-size:14px;line-height:1;padding:4px 6px;border:0;border-radius:6px;
    background:transparent;color:var(--color-muted);cursor:pointer}
  .pg-panel-x:hover{background:var(--color-surface-2);color:var(--color-text)}
  /* ⭐ THE PHONE: A SHEET AT THREE HEIGHTS (3.6). The map stays full screen; the panel
     rises from the bar (--pg-bar-h, measured off #pg-modes): peek shows the head and a
     row, half the list beside a visible map, full is List and stops under the top bar.
     The handle steps through them; a drag snaps to the nearest. */
  @media (max-width:768px){
    body.pg-layout-split .pg-panel, body.pg-layout-list .pg-panel{
      display:flex;flex-direction:column;position:fixed;left:0;right:0;z-index:9;box-sizing:border-box;
      bottom:var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px)));height:50dvh;
      background:var(--color-surface);color:var(--color-text);border-top:1px solid var(--color-border);
      border-radius:16px 16px 0 0;box-shadow:0 -10px 30px rgba(0,0,0,.35);transition:height .2s ease}
    body[data-sheet="peek"] .pg-panel{height:132px}
    body[data-sheet="half"] .pg-panel{height:50dvh}
    body[data-sheet="full"] .pg-panel{height:calc(100dvh - var(--pg-chrome-bottom, 62px) - var(--pg-bar-h, calc(56px + env(safe-area-inset-bottom,0px))))}
    .pg-panel-grab{display:block;flex:none;width:100%;height:22px;padding:0;border:0;background:transparent;cursor:grab;touch-action:none}
    .pg-panel-grab span{display:block;width:40px;height:5px;margin:0 auto;border-radius:3px;background:var(--color-border)}
    body[data-sheet] .pg-panel-head{padding-top:4px}
    .pg-panel-divider{display:none}
    /* A page in the sheet IS the card's page: on a phone the card would stack on it. */
    body.pg-has-page .pg-card{display:none !important}
    .pg-world-list:not([hidden]){display:inline-flex;align-items:center;font:inherit;font-size:12px;font-weight:600;
      padding:4px 10px;border-radius:999px;border:1px solid rgba(255,255,255,.28);background:transparent;color:inherit;cursor:pointer}
  }
  @media (min-width:769px){
    .pg-discover .pg-layout-sw{display:inline-flex;align-items:stretch;margin-left:6px}
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button{border-radius:0;padding:8px 10px;gap:5px}
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button:first-child{border-radius:9px 0 0 9px}
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button:last-child{border-radius:0 9px 9px 0}
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button + button{border-left-width:0}
    /* The pressed layout is a light fill, not the vermilion of a pressed mode: two
       vermilion chips side by side would read as two modes. */
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button.on,
    .chrome-unified .pg-modes #pg-discover .pg-layout-sw button.on:hover{background:rgba(255,255,255,.88);border-color:rgba(255,255,255,.88);color:#14181d}

    body.pg-layout-split .pg-panel, body.pg-layout-list .pg-panel{
      display:flex;flex-direction:column;position:fixed;z-index:8;
      top:calc(var(--live-h,0px) + var(--pg-chrome-h,48px));bottom:0;left:var(--rail-w,0px);
      width:min(var(--pg-panel-w,380px),(100vw - var(--rail-w,0px)) * .6);box-sizing:border-box;
      background:var(--color-surface);color:var(--color-text);border-right:1px solid var(--color-border)}
    body.pg-layout-list .pg-panel{width:auto;right:0;border-right:0;padding-top:56px}
    /* The map's own controls float at z-index 11; with the map covered they control
       nothing. visibility, not display: _pgMapCtl.show() writes an inline display. */
    body.pg-layout-list .pg-mapctl, body.pg-layout-list .pg-legend{visibility:hidden}
    body.pg-layout-split #pg-map, body.pg-layout-split .pg-tzbar{left:calc(var(--rail-w,0px) + min(var(--pg-panel-w,380px),(100vw - var(--rail-w,0px)) * .6))}
    body.chrome-unified.pg-layout-split .pg-modes{left:calc(var(--rail-w,0px) + min(var(--pg-panel-w,380px),(100vw - var(--rail-w,0px)) * .6) + 16px) !important;
      max-width:calc(100vw - var(--rail-w,0px) - min(var(--pg-panel-w,380px),(100vw - var(--rail-w,0px)) * .6) - 32px)}
    body.chrome-unified.pg-layout-split .pg-modes #pg-discover{flex-wrap:wrap;row-gap:6px}
    body.chrome-unified.pg-layout-split .pg-modes .pg-world{width:min(320px, calc(100% - 14px));box-sizing:border-box}
    /* The divider: 10 px to grab, a 2 px line that shows on hover, focus and drag. */
    .pg-panel-divider{position:absolute;top:0;bottom:0;right:-6px;width:10px;cursor:col-resize;touch-action:none;z-index:1}
    .pg-panel-divider::after{content:'';position:absolute;top:0;bottom:0;left:4px;width:2px;background:transparent}
    .pg-panel-divider:hover::after, .pg-panel-divider:focus-visible::after,
    body.pg-panel-dragging .pg-panel-divider::after{background:var(--color-primary)}
    .pg-panel-divider:focus-visible{outline:none}
    body.pg-layout-list .pg-panel-divider{display:none}
    body.pg-panel-dragging{cursor:col-resize;-webkit-user-select:none;user-select:none}
  }

  /* The panel's content (3.3, 3.4): one look for the desktop column and the phone sheet. */
  .pg-panel-head{padding:14px 16px 10px;border-bottom:1px solid var(--color-border)}
  .pg-panel-line{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
  .pg-panel-t{font-weight:700;font-size:14px}
  .pg-panel-n{font-size:12px;color:var(--color-muted)}
  .pg-panel-tools{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:8px;font-size:12px}
  .pg-panel-q{font:inherit;font-size:12px;border:1px solid var(--color-border);background:var(--color-surface-2);color:var(--color-text);
    border-radius:999px;padding:3px 10px;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .pg-panel-q[hidden]{display:none}
  .pg-panel-view{display:inline-flex;align-items:center;gap:6px;color:var(--color-text);cursor:pointer;margin-left:auto}
  .pg-panel-body{flex:1 1 auto;overflow:auto;min-height:0}
  /* The rows (3.3): a row is a link to its page (a new tab opens it); a plain click
     lands it on the map. "Yours" wears the visited tokens (stage 0.1). */
  .pg-row{display:block;padding:9px 16px;border-bottom:1px solid var(--color-border);color:var(--color-text);text-decoration:none}
  .pg-row:hover, .pg-row:focus-visible{background:var(--color-surface-2);text-decoration:none;outline:none}
  /* 3.4: the row of what the map has selected (a dot, a pick, a row click). */
  .pg-row.on{background:var(--color-surface-2);box-shadow:inset 3px 0 0 var(--color-primary)}
  .pg-row-t{font-weight:600;font-size:13.5px}
  .pg-row-s{display:block;font-size:12px;color:var(--color-muted);margin-top:2px}
  .pg-row-mine{margin-left:6px;font-size:10.5px;font-weight:700;padding:1px 6px;border-radius:999px;vertical-align:1px;
    background:var(--color-visited);color:var(--color-visited-ink);border:1px solid var(--color-visited-line)}
  .pg-panel-empty, .pg-panel-foot{margin:0;padding:14px 16px;font-size:13px;color:var(--color-muted)}
  .pg-panel-foot a{color:var(--color-primary-ink);font-weight:600}
  .pg-panel-more{display:block;margin:12px 16px;padding:8px 12px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;
    border:1px solid var(--color-border);border-radius:8px;background:var(--color-surface);color:var(--color-text)}
  .pg-panel-more:hover{background:var(--color-surface-2)}

  /* ⭐ A PAGE AS A PANEL (One Map stage 4). While the panel holds a page, the page takes
     the panel's place below the handle; "← List" brings the list back. The page's
     text is the server's (includes/map_panel.php), on the theme's tokens like the rows. */
  .pg-panel-page{display:none}
  .pg-panel.has-page .pg-panel-head, .pg-panel.has-page .pg-panel-body{display:none}
  .pg-panel.has-page .pg-panel-page{display:block;flex:1 1 auto;overflow:auto;min-height:0}
  .pg-page-bar{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:8px;padding:8px 12px;
    background:var(--color-surface);border-bottom:1px solid var(--color-border)}
  .pg-page-back{font:inherit;font-size:12px;font-weight:600;padding:4px 10px;border-radius:999px;cursor:pointer;
    border:1px solid var(--color-border);background:transparent;color:var(--color-text)}
  .pg-page-back:hover{background:var(--color-surface-2)}
  .mp{padding:12px 16px 28px;color:var(--color-text);font-size:13.5px;line-height:1.45}
  .mp a{color:var(--color-primary-ink)}
  .mp-crumbs{font-size:12px;color:var(--color-muted)}
  .mp-crumbs a{color:var(--color-muted);text-decoration:none}
  .mp-title{margin:4px 0 2px;font-size:20px;line-height:1.2;color:var(--color-text)}
  .mp-code{color:var(--color-muted);font-weight:600}
  .mp-sub{margin:0 0 12px;font-size:13px;color:var(--color-muted)}
  .mp-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0 0 12px}
  .mp-facts div{border:1px solid var(--color-border);border-radius:8px;padding:7px 10px}
  .mp-facts dt{font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--color-muted)}
  .mp-facts dd{margin:2px 0 0;font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
  .mp-facts small{font-size:11px;font-weight:500;color:var(--color-muted)}
  .mp-you{margin:0 0 12px;padding:8px 10px;border-radius:8px;font-size:13px;
    background:var(--color-visited);color:var(--color-visited-ink);border:1px solid var(--color-visited-line)}
  .mp-you a{color:inherit;font-weight:700}
  .mp-sec{margin:16px 0 0}
  .mp-sec h2{margin:0 0 4px;font-size:14px;color:var(--color-text)}
  .mp-note{margin:0 0 6px;font-size:12px;color:var(--color-muted)}
  .mp-note.mp-gap{margin-top:10px}
  .mp-rows{list-style:none;margin:0;padding:0;border-top:1px solid var(--color-border)}
  .mp-rows a{display:block;padding:7px 0;border-bottom:1px solid var(--color-border);color:var(--color-text);text-decoration:none}
  .mp-rows a:hover{background:var(--color-surface-2)}
  .mp-rows .t{font-weight:600}
  .mp-rows .s{display:block;font-size:12px;color:var(--color-muted)}
  .mp-chips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
  .mp-chips a{display:inline-block;padding:3px 10px;border:1px solid var(--color-border);border-radius:999px;font-size:12px;color:var(--color-text);text-decoration:none}
  .mp-chips a:hover{background:var(--color-surface-2)}
  .mp-links{margin:16px 0 0;display:flex;gap:14px;flex-wrap:wrap;font-size:13px}
  /* Chains (4.3): the chain's own colour band (its ink read off it, chain_ink_on), "yours"
     chips in the visited tokens, the About text folded. */
  .mp-band{margin:-12px -16px 12px;padding:12px 16px 14px}
  .mp-band .mp-title{color:inherit;margin:2px 0 0}
  .mp-band-crumbs, .mp-band-crumbs a{color:inherit;opacity:.88}
  .mp-band-sub{margin:2px 0 0;font-size:12.5px;opacity:.9}
  .mp-chips a.mp-mine{background:var(--color-visited);color:var(--color-visited-ink);border-color:var(--color-visited-line)}
  .mp-about{margin:14px 0 0;border:1px solid var(--color-border);border-radius:8px}
  .mp-about summary{cursor:pointer;padding:8px 10px;font-weight:600}
  .mp-about-body{padding:0 12px 10px;font-size:13px}
  .mp-about-body h1, .mp-about-body h2{font-size:14px;margin:12px 0 4px}
  .mp-drill-h{font-size:15px;margin:4px 0 8px}
  .mp-sec h2 small{font-weight:400;color:var(--color-muted)}
  .mp-swatch{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:0;border:1px solid var(--color-border)}
  /* 3.4: a list row hovered rings its dot (one MapLibre marker, never a deck repaint). */
  .pg-list-ring{width:22px;height:22px;border-radius:50%;box-sizing:border-box;pointer-events:none;
    border:3px solid var(--color-primary);box-shadow:0 0 0 2px rgba(255,255,255,.92),0 0 10px rgba(0,0,0,.45)}
