/* 九华山三维导览 · 「宣纸与墨」
   Shared components and the desktop layout. Phone portrait and landscape live in mobile.css.
   Materials: chrome (small floating controls, frosted where the tier allows), sheet (opaque rice paper for anything
   people read), inset (fills inside a sheet), ink (primary / selected), zhu (only 居之林 and the seal).
   Spacing sits on a 4px grid. Only transform and opacity animate, except the rare user-triggered sheet height. */

:root{
 /* ink */
 --ink:#1c2a25;--ink-2:#394a43;--muted:#5c6962;--faint:#8d968f;
 /* rice paper */
 --paper:#fbf9f3;--paper-2:#f4f1e8;--paper-3:#e9e4d7;
 --line:rgba(28,42,37,.09);--line-2:rgba(28,42,37,.16);
 /* accents */
 --zhu:#b3382c;--zhu-deep:#962c22;--zhu-soft:#f8e8e3;
 --jin:#9a7431;--jin-soft:#f5eddb;
 --dai:#2f5e57;--dai-soft:#e3eeeb;
 /* categories */
 --c-temple:#9c5f2e;--c-sight:#3d7a57;--c-village:#667569;--c-service:#3b6a90;
 /* route modes (routes.js MODES / traveller.js) */
 --walk:#d9772a;--walk-soft:#fbeedd;--ride:#7150c4;--bus:#2e6bc8;
 --walk-deep:#a3521a; /* orange text and white-on-orange fills: 5.6:1 with white, 4.9:1 on --walk-soft, 5.3:1 on paper */
 /* surfaces */
 --chrome:rgba(251,249,243,.78);--chrome-solid:rgba(251,249,243,.97);--sheet:#fbf9f3;
 --blur:blur(20px) saturate(1.6);
 --zhu-fill:#b5392c; /* flat vermilion; depth comes from the inner highlight, not a gradient */
 --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .11 0 0 0 0 .16 0 0 0 0 .14 0 0 0 1.7 -.66'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)' opacity='.34'/%3E%3C/svg%3E");
 /* depth */
 --sh-1:0 .5px 1px rgba(20,32,27,.10),0 2px 6px -2px rgba(20,32,27,.10);
 --sh-2:0 .5px 1px rgba(20,32,27,.10),0 4px 10px -4px rgba(20,32,27,.12),0 14px 32px -14px rgba(20,32,27,.28);
 --sh-3:0 -1px 0 rgba(20,32,27,.04),0 -10px 36px -14px rgba(20,32,27,.34);
 --sh-4:0 2px 6px rgba(20,32,27,.08),0 24px 60px -20px rgba(20,32,27,.40);
 --hi:inset 0 1px 0 rgba(255,255,255,.9);          /* top highlight on paper sheets */
 --ring:inset 0 0 0 .5px rgba(255,255,255,.9),inset 0 1px 0 rgba(255,255,255,.75),0 0 0 .5px rgba(28,42,37,.10); /* chrome edge: a light inner rim over a hairline of ink */
 /* shape */
 --r-xs:8px;--r-sm:12px;--r-md:16px;--r-lg:22px;--r-sheet:24px;--r-pill:999px;
 /* type */
 --sans:"PingFang SC","HarmonyOS Sans SC","HarmonyOS Sans","MiSans","Microsoft YaHei","Noto Sans SC",system-ui,sans-serif;
 --serif:"Songti SC","Noto Serif SC","Source Han Serif SC","STSong","SimSun",serif;
 --fs-xs:11.5px;--fs-sm:13px;--fs-md:14px;--fs-lg:15.5px;--fs-xl:18px;--fs-2xl:22px;--fs-3xl:27px;
 /* motion */
 --ease-out:cubic-bezier(.2,.8,.2,1);--ease-in:cubic-bezier(.45,0,.8,.3);--ease-sheet:cubic-bezier(.22,1,.36,1);
 --spring:cubic-bezier(.34,1.32,.64,1);--ease-in-out:cubic-bezier(.65,0,.35,1);
 /* a real damped spring (ζ≈.72): one soft overshoot of 4% and a long settle; browsers without linear() keep --spring */
 --spring-soft:cubic-bezier(.3,1.2,.5,1);--spring-glide:cubic-bezier(.22,1,.36,1);
 --press:.08s;--release:.42s;
 --t-1:.14s;--t-2:.22s;--t-3:.32s;--t-4:.46s;
 /* layout */
 --st:env(safe-area-inset-top,0px);--sb:env(safe-area-inset-bottom,0px);
 --sl:env(safe-area-inset-left,0px);--sr:env(safe-area-inset-right,0px);
 --col-x:20px;--col-w:360px;--col-top:74px;
 --map-x:calc(var(--col-x) + var(--col-w) + 20px);--rail-w:84px;
 --pad:20px; /* horizontal padding inside sheets */
 color-scheme:light;
}
@supports (transition-timing-function:linear(0,1)){:root{
 --spring-soft:linear(0,.0303,.1064,.2095,.3253,.4431,.5556,.6581,.7478,.8236,.8857,.9347,.972,.9992,1.0179,1.0296,1.036,1.0383,1.0377,1.0352,1.0314,1.027,1.0225,1.0181,1.0141,1.0105,1.0074,1.0049,1.0029,1.0014,1.0003,.9995,.999,.9987,.9985,.9985,.9986,.9988,.9989,.9991,1);
}}

/* ---------- base ---------- */
*,*::before,*::after{box-sizing:border-box}
html,body{height:100%;margin:0;overflow:hidden;overscroll-behavior:none}
html{font-family:var(--sans);color:var(--ink);background:#dfe6e2;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{font-size:var(--fs-md);line-height:1.5}
h1,h2,h3,h4,p,ol,ul,dl,dd,figure{margin:0}
button,input{font:inherit;color:inherit;letter-spacing:inherit}
button{margin:0;padding:0;border:0;background:none;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
a{color:var(--dai);text-underline-offset:3px;-webkit-tap-highlight-color:transparent}
svg{display:block}
[hidden]{display:none!important}
:focus-visible{outline:2px solid var(--dai);outline-offset:2px}
:focus:not(:focus-visible){outline:none}
#app,#stage{position:fixed;inset:0;overflow:hidden}
/* Focus inside a moving sheet must not scroll the fixed map shell; lists scroll inside their own panes. */
#app{overflow:clip}
#stage{z-index:0;touch-action:none;background:linear-gradient(180deg,#4f9fe0 0%,#a8d4f0 52%,#fbe3c4 82%,#f7d2a8 100%)}
/* Direction A is a URL-gated prototype. The original chrome/layout stays in
   charge; this gradient also works before the map or without WebGL. */
.proto-a #stage{background:linear-gradient(180deg,#34486b 0%,#a9b1c7 38%,#f2c6a6 67%,#d9dce5 100%)}
.proto-a #stage>canvas{opacity:0;transition:opacity .7s ease-out}
.proto-a #stage.proto-a-ready>canvas{opacity:1}
.proto-a .loading{background-color:#e4d5cb;background-image:linear-gradient(180deg,#a9b1c7 0%,#f2d4bc 55%,#e1e2e8 100%)}
.proto-a .lens-ring{background:linear-gradient(90deg,rgba(31,39,59,.08),rgba(31,39,59,.38) 35%,rgba(31,39,59,.38) 65%,rgba(31,39,59,.08))}
.proto-a .ruler-alt{background:rgba(36,43,58,.90)}
.proto-a-skip{position:fixed;z-index:8;top:calc(88px + var(--st));left:50%;transform:translateX(-50%);min-height:40px;padding:0 16px;border:1px solid rgba(255,238,215,.32);border-radius:24px;background:rgba(36,43,58,.88);color:#fff2df;font:500 12px/1 var(--sans);letter-spacing:.08em;white-space:nowrap}
.proto-a-skip:active{transform:translateX(-50%) scale(.96)}
.proto-a-skip:focus-visible{outline:2px solid #fff2df;outline-offset:3px}
@media(prefers-reduced-motion:reduce){
 .proto-a *,.proto-a *::before,.proto-a *::after{animation:none!important;transition:none!important}
 .proto-a .load-art path{stroke-dashoffset:0}
}
canvas{display:block}
/* Touch: pinches on the UI must not zoom the page; long presses on controls should not select text. Card text stays selectable. */
.viewbar,.rail,.dock,.map-meta,.route-hud,.flight-hint,.sheet,dialog,.maplabel{touch-action:pan-x pan-y}
.viewbar,.rail,.dock,.map-meta,.route-hud,.flight-hint,.maplabel,.panel-head,.panel-tabs,.categories,.place-list,.route-card,.rh-stops,.sheet-grip,.tour-card{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}

/* ---------- materials ---------- */
.viewbar,.map-actions,#settings-toggle,#help-open,.dock,.route-hud,.flight-hint,.status{
 background:var(--chrome);-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);box-shadow:var(--ring),var(--sh-2)}
.sheet,.settings-wrap,dialog,.tour-card{background-color:var(--sheet);background-image:var(--grain)}

/* shared icon buttons */
.icon-btn{display:grid;place-items:center;flex:none;border-radius:50%;transition:background-color var(--t-1),color var(--t-1),scale var(--t-1) var(--ease-out)}
.icon-btn:active{scale:.92}
.icon-btn svg,.rail svg,.dock svg,.search svg{fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.icon-btn svg{width:18px;height:18px}

/* category tints: --c for dots, --c-ink for text on --c-soft tiles (≥4.8:1), --c-soft for tiles (solid colours, no color-mix needed) */
.c-temple{--c:var(--c-temple);--c-ink:#87502a;--c-soft:#f4e9de}
.c-sight,.c-nature{--c:var(--c-sight);--c-ink:#33704d;--c-soft:#e5f0e9}
.c-village,.c-hotel{--c:var(--c-village);--c-ink:#58675c;--c-soft:#ebeeeb}
.c-service,.c-transport{--c:var(--c-service);--c-ink:var(--c-service);--c-soft:#e4ecf3}

/* ---------- map chrome hide (JS: .map-chrome.is-hidden + inert) ---------- */
.map-chrome{transition:opacity .4s var(--ease-out),transform .4s var(--ease-out),visibility 0s}
.map-chrome.is-hidden{opacity:0;transform:translateY(-10px);visibility:hidden;pointer-events:none;
 transition:opacity .24s var(--ease-in),transform .24s var(--ease-in),visibility 0s linear .24s}
/* rail members only fade: #settings must never carry a transform (its phone sheet is position:fixed inside it) */
#settings.map-chrome,#settings.map-chrome.is-hidden{transform:none}
#help-open.is-hidden{transform:none}

/* ---------- loading seal ---------- */
.load-seal{flex:none;display:grid;place-content:center;width:42px;height:42px;border-radius:10px;background:var(--zhu-fill);color:#fbf1e6;
 font:600 15px/1.04 var(--serif);text-align:center;box-shadow:inset 0 0 0 2px #b23a2d,inset 0 0 0 3px rgba(251,241,230,.55),0 2px 6px -2px rgba(150,40,30,.45)}

/* ---------- view switcher ---------- */
.viewbar{position:absolute;z-index:5;display:flex;padding:4px;border-radius:14px}
.viewbar button{position:relative;z-index:1;display:grid;place-items:center;padding:0 16px;border-radius:10px;font-size:13.5px;font-weight:500;color:var(--ink-2);white-space:nowrap;transition:color var(--t-2)}
.viewbar button.active{color:#fbf9f3;font-weight:600}
.viewbar #featured-cta{color:var(--zhu);background:var(--zhu-soft);font-weight:600}
.seg-ind{position:absolute;z-index:0;top:4px;bottom:4px;left:0;width:var(--ind-w,0);transform:translateX(var(--ind-x,0));opacity:var(--ind-o,0);
 border-radius:10px;background:var(--ink);box-shadow:0 2px 6px -2px rgba(20,32,27,.45);
 transition:transform .52s var(--spring-soft),width .52s var(--spring-soft),opacity .2s}
.viewbar button{transition:color var(--t-2),background-color var(--t-1),scale var(--release) var(--spring-soft)}
.viewbar button:active{scale:.95;transition:color var(--t-2),background-color var(--t-1),scale var(--press) var(--ease-out)}
@media(hover:hover){.viewbar button:not(.active):not(#featured-cta):hover{color:var(--ink);background:rgba(28,42,37,.05)}.viewbar #featured-cta:hover{background:#f4dcd4}}

/* ---------- tool rail (no z-index, transform or backdrop-filter on .rail / #settings) ---------- */
/* The rail box itself lets taps and drags through to the map; only its buttons take them. */
.rail{position:absolute;display:flex;flex-direction:column;align-items:center;gap:8px;pointer-events:none}
.rail>*{pointer-events:auto}
.map-actions,#settings-toggle,#help-open{position:relative;z-index:5;
 transition:opacity .42s var(--ease-sheet),transform .42s var(--ease-sheet),visibility 0s,background-color var(--t-1),color var(--t-1),scale var(--t-1) var(--ease-out)}
#help-open.map-chrome.is-hidden{transition:opacity .24s var(--ease-in),visibility 0s linear .24s}
.map-actions{display:flex;flex-direction:column;width:44px;border-radius:22px}
.map-actions button,#settings-toggle,#help-open{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;color:var(--ink-2)}
.map-actions button{position:relative;transition:background-color var(--t-1),color var(--t-1),scale var(--t-1) var(--ease-out)}
.map-actions button:active,#settings-toggle:active,#help-open:active{scale:.92}
.map-actions button+button::before{content:"";position:absolute;top:0;left:14px;right:14px;height:1px;background:var(--line);transform:scaleY(.5)}
.rail svg{width:20px;height:20px}
#north-arrow{transform-box:fill-box;transform-origin:center;transition:transform .15s linear}
#north-arrow path{stroke:none}#north-arrow .n{fill:var(--zhu)}#north-arrow .s{fill:var(--faint)}
#settings-toggle>span,#help-open>span{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
#settings-toggle .chev{display:none}
#settings-toggle[aria-expanded="true"]{background:var(--ink);color:#fbf9f3;box-shadow:0 0 0 1px var(--ink),var(--sh-2)}
@media(hover:hover){
 .map-actions button:hover,#settings-toggle[aria-expanded="false"]:hover,#help-open:hover{background:var(--paper-3);color:var(--ink)}
}
/* tooltips for mouse users; the label is the button's aria-label */
@media(hover:hover) and (pointer:fine){
 .map-actions button::after,#settings-toggle::after,#help-open::after{content:attr(aria-label);position:absolute;right:calc(100% + 10px);top:50%;margin-top:-14px;
  height:28px;padding:0 10px;border-radius:var(--r-xs);background:var(--ink);color:#fbf9f3;font:500 12.5px/28px var(--sans);white-space:nowrap;
  opacity:0;visibility:hidden;pointer-events:none;transform:translateX(6px);transition:opacity var(--t-1),transform var(--t-1),visibility 0s linear var(--t-1)}
 .map-actions button:hover::after,#settings-toggle:hover::after,#help-open:hover::after{opacity:1;visibility:visible;transform:none;transition:opacity var(--t-2) .35s,transform .4s var(--spring-soft) .35s,visibility 0s .35s}
 #settings-toggle[aria-expanded="true"]::after{display:none}
}

/* ---------- layers & terrain (desktop popover; phone sheet in mobile.css) ---------- */
.settings{position:relative}
.settings-wrap{z-index:12}
#settings-body{display:flex;flex-direction:column}
.settings-head{display:flex;flex-direction:column;gap:2px;padding:16px 0 10px}
.settings-head b{font:600 16px/1.4 var(--serif);letter-spacing:.1em;color:var(--ink)}
.settings-head small{font-size:12px;color:var(--muted)}
.switch{position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:48px;border-top:1px solid var(--line);font-size:14.5px;color:var(--ink);cursor:pointer}
.switch input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.switch>span:last-child{order:1}
.track{order:2;flex:none;position:relative;width:44px;height:26px;border-radius:13px;background:rgba(28,42,37,.14);transition:background-color .28s var(--ease-out)}
.track::after{content:"";position:absolute;top:2px;left:2px;width:22px;height:22px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(20,32,27,.2),0 2px 6px -2px rgba(20,32,27,.25);transition:transform .46s var(--spring-soft),width .2s var(--ease-out)}
.switch input:checked+.track{background:var(--ink)}
.switch:active .track::after{width:26px}
.switch:active input:checked+.track::after{transform:translateX(14px)}
.switch input:checked+.track::after{transform:translateX(18px)}
.switch input:focus-visible+.track{outline:2px solid var(--dai);outline-offset:2px}
.height-control{padding:12px 0 2px;border-top:1px solid var(--line)}
.hc-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:6px;font-size:14.5px;color:var(--ink)}
.hc-row output{font-size:12.5px;color:var(--muted);font-variant-numeric:tabular-nums}
input[type=range]{-webkit-appearance:none;appearance:none;display:block;width:100%;height:28px;margin:0;background:none;cursor:pointer}
input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(90deg,var(--ink) var(--fill,0%),rgba(28,42,37,.14) var(--fill,0%))}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:22px;height:22px;margin-top:-9px;border-radius:50%;background:#fff;box-shadow:0 0 0 .5px rgba(28,42,37,.22),var(--sh-1);transition:transform .4s var(--spring-soft),box-shadow .2s}
input[type=range]:active::-webkit-slider-thumb{transform:scale(1.14);box-shadow:0 0 0 .5px rgba(28,42,37,.22),0 0 0 6px rgba(28,42,37,.08),var(--sh-1);transition:transform .12s var(--ease-out),box-shadow .12s}
input[type=range]::-moz-range-track{height:4px;border-radius:2px;background:rgba(28,42,37,.14)}
input[type=range]::-moz-range-progress{height:4px;border-radius:2px;background:var(--ink)}
input[type=range]::-moz-range-thumb{width:22px;height:22px;border:0;border-radius:50%;background:#fff;box-shadow:0 0 0 1px var(--line-2),var(--sh-1)}
input[type=range]:focus-visible{outline-offset:4px}

/* ---------- dock: search + 推荐路线 + 游览须知 ---------- */
.dock{position:absolute;z-index:5;transition:transform .42s var(--ease-sheet),opacity .42s var(--ease-sheet),visibility 0s}
.dock-search{display:flex;align-items:center;gap:10px;min-width:0;border-radius:14px;background:rgba(28,42,37,.055);color:var(--muted);font-size:14px;text-align:left;
 transition:background-color var(--t-1),scale var(--t-1) var(--ease-out)}
.dock-search svg{flex:none;width:20px;height:20px;color:var(--ink-2)}
.dock-search>span{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dock-btn{display:flex;align-items:center;justify-content:center;color:var(--ink-2);font-weight:500;border-radius:14px;
 transition:background-color var(--t-1),color var(--t-1),scale var(--t-1) var(--ease-out)}
.dock-btn svg{flex:none;width:20px;height:20px}
.dock button:active{scale:.97}
.dock-sep{flex:none;width:1px;height:28px;background:var(--line-2)}
@media(hover:hover){.dock-search:hover{background:rgba(28,42,37,.085)}.dock-btn:hover{background:rgba(28,42,37,.06);color:var(--ink)}}

/* ---------- map meta: status + scale ---------- */
.map-meta{position:absolute;z-index:3;display:flex;align-items:center;gap:12px;pointer-events:none;
 transition:opacity .42s var(--ease-sheet),transform .42s var(--ease-sheet),visibility 0s}
.map-meta>*{pointer-events:auto}
.status{flex:none;display:flex;align-items:center;gap:8px;min-width:0;height:30px;padding:0 12px;border-radius:var(--r-pill);font-size:12px;color:var(--ink-2)}
.status-dot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--c-sight);box-shadow:0 0 0 3px rgba(61,122,87,.18)}
#scene-status{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#scale-line{position:relative;flex:none;min-width:36px;padding:0 6px 2px;border-bottom:1.5px solid var(--ink-2);font-size:11px;line-height:1.2;text-align:center;font-variant-numeric:tabular-nums}
#scale-line:empty{display:none}
#scale-line::before,#scale-line::after{content:"";position:absolute;bottom:-1.5px;width:1.5px;height:6px;background:var(--ink-2)}
#scale-line::before{left:0}#scale-line::after{right:0}
/* A quiet, readable filing link below the map controls. */
.site-filing{position:fixed;z-index:5;left:0;right:0;bottom:calc(2px + var(--sb));text-align:center;font-size:11px;line-height:18px;pointer-events:none}
.site-filing a{display:inline-block;padding:0 6px;border-radius:3px;background:rgba(251,249,243,.88);color:#5c6962;text-decoration:none;white-space:nowrap;pointer-events:auto;touch-action:manipulation}
.site-filing a:hover,.site-filing a:focus-visible{text-decoration:underline}

/* ---------- flight hint ---------- */
.flight-hint{position:absolute;z-index:7;display:flex;align-items:center;gap:8px;width:max-content;max-width:calc(100% - 24px);height:40px;margin:0 auto;padding:0 16px 0 12px;border-radius:var(--r-pill);pointer-events:none;
 opacity:0;transform:translateY(-8px);transition:opacity .2s var(--ease-in),transform .2s var(--ease-in)}
.flight-hint.show{opacity:1;transform:none;transition:opacity .3s var(--ease-out),transform .3s var(--ease-out)}
.fh-dot{position:relative;flex:none;width:16px;height:16px}
.fh-dot::before{content:"";position:absolute;inset:5px;border-radius:50%;background:var(--ink)}
.fh-dot::after{content:"";position:absolute;inset:0;border-radius:50%;border:1.5px solid rgba(28,42,37,.14);border-top-color:var(--ink);animation:spin .9s linear infinite}
.fh-text{flex:none;font-size:12.5px;color:var(--muted)}
.fh-name{min-width:0;font:600 14px/1.2 var(--serif);letter-spacing:.06em;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ---------- map labels (CSS2D). three.js writes the root's transform / display / z-index every frame: only children animate ---------- */
.labels{position:absolute;inset:0;pointer-events:none}
.my-location{display:flex;flex-direction:column;align-items:center;gap:5px;pointer-events:none;white-space:nowrap;color:#fff;font-size:12px}
.my-location span{padding:3px 8px;border-radius:12px;background:#1672c4;box-shadow:0 2px 8px #0003}
.my-location i{display:block;width:12px;height:12px;border:3px solid #fff;border-radius:50%;background:#1672c4;box-shadow:0 0 0 4px #1672c433}
.my-location.is-stale span,.my-location.is-stale i{background:#677b88}
.my-location.is-stale i{box-shadow:0 0 0 4px #677b8833}
#locate[aria-pressed="true"]{color:#1672c4;background:#1672c414}
.location-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.maplabel{pointer-events:none;display:flex;flex-direction:column;align-items:center}
.maplabel button{pointer-events:auto;touch-action:none;display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 9px 0 7px;border-radius:var(--r-pill);
 background:rgba(251,249,243,.96);border:1px solid rgba(28,42,37,.09);box-shadow:0 .5px 1px rgba(20,32,27,.16),0 3px 10px -4px rgba(20,32,27,.24);
 color:var(--ink);font:500 12px/1 var(--sans);letter-spacing:.02em;white-space:nowrap;
 animation:lbIn .34s var(--spring-soft) backwards;transition:transform .36s var(--spring-soft),background-color var(--t-1),box-shadow var(--t-2)}
.maplabel button::before{content:"";flex:none;width:6px;height:6px;border-radius:50%;background:var(--c,var(--ink-2))}
.maplabel i{position:relative;display:block;width:1.5px;height:7px;background:rgba(251,249,243,.95);box-shadow:0 0 0 .75px rgba(28,42,37,.38);animation:lbFade .24s var(--ease-out) backwards}
.maplabel i::after{content:"";position:absolute;left:50%;bottom:-2.5px;width:5px;height:5px;margin-left:-2.5px;border-radius:50%;background:var(--c,var(--ink-2));box-shadow:0 0 0 2px rgba(255,255,255,.9)}
.maplabel button{position:relative}
/* Place labels (.pin; app.js placeLabel): the pill sits --dx/--dy from where its bottom centre would meet the point,
   by default on a short stem above it. The stem is a leader from the point to the pill's nearest edge, any length and
   angle, so a key label can stand clear of crowded spots and of the chrome. Route stops keep their own stem. */
.maplabel.pin button{left:var(--dx,0px);top:var(--dy,-7px)}
.maplabel.pin i{position:absolute;left:50%;bottom:0;width:var(--len,7px);height:1.5px;margin-bottom:-.75px;transform-origin:0 50%;transform:rotate(var(--ang,-90deg))}
.maplabel.pin i::after{left:-2.5px;top:50%;bottom:auto;margin:-2.5px 0 0}
.maplabel.pin.area button,.maplabel.pin.road button{top:var(--dy,0px)}
.maplabel.major button{height:27px;padding:0 11px 0 8px;gap:6px;font:600 13px/1 var(--serif);letter-spacing:.08em;background:#fbf4e4;border-color:rgba(154,116,49,.35);color:#5a4221}
.maplabel.major button::before{width:7px;height:7px;background:var(--jin)}
.maplabel.estimated button{border-style:dashed;border-color:rgba(154,116,49,.55)}
.maplabel.small button{height:20px;padding:0 7px 0 6px;gap:4px;font-size:10.5px}
.maplabel.small button::before{width:5px;height:5px}
.maplabel.hall button{color:#7a5a36}
/* village names are map lettering, not pins: a tight, dense paper halo (stacked 1–3px blurs) keeps thin strokes such as
   一 legible over dark roofs and forest, and a wider soft glow settles it on the terrain */
.maplabel.area button{height:auto;padding:0 0 0 .2em;background:none;border:0;box-shadow:none;color:#22392f;font:700 13px/1.2 var(--serif);letter-spacing:.2em;
 text-shadow:0 0 1px #fbf9f3,0 0 1px #fbf9f3,0 0 2px #fbf9f3,0 0 2px #fbf9f3,0 0 3px #fbf9f3,0 0 6px rgba(251,249,243,.9),0 0 10px rgba(251,249,243,.55)}
.maplabel.area button::before,.maplabel.area i,.maplabel.road button::before,.maplabel.road i{display:none}
.maplabel.road button{height:20px;padding:0 8px;font-size:10px;color:var(--ink-2);background:rgba(251,249,243,.88);border-color:rgba(28,42,37,.08);box-shadow:none;pointer-events:none}
@media(hover:hover){
 .maplabel:not(.area):not(.road) button:hover{transform:translateY(-1px);box-shadow:0 1px 2px rgba(20,32,27,.14),0 6px 14px -4px rgba(20,32,27,.34)}
 .maplabel:not(.area):not(.road):not(.major):not(.featured):not(.selected):not(.route-stop) button:hover{background:#fff}
}
.maplabel.selected button{background:var(--ink);border-color:var(--ink);color:#fbf9f3;animation:lbPop .32s var(--spring);
 box-shadow:0 0 0 4px rgba(28,42,37,.16),0 6px 16px -6px rgba(20,32,27,.5)}
.maplabel.selected button::before{background:#fbf9f3}
/* 居之林: vermilion, always on, with the only looping map animation: a soft ring at its ground dot */
.maplabel.featured button{height:30px;padding:0 13px 0 5px;gap:7px;background:var(--zhu-fill);border:1px solid rgba(255,226,210,.4);color:#fff;
 font:600 13.5px/1 var(--serif);letter-spacing:.1em;box-shadow:inset 0 1px 0 rgba(255,255,255,.22),0 1px 2px rgba(120,24,14,.25),0 8px 18px -8px rgba(150,40,30,.6)}
.maplabel.featured.selected button{box-shadow:0 0 0 4px rgba(179,56,44,.2),0 8px 18px -8px rgba(150,40,30,.6)}
.maplabel.featured button::before{display:none}
.maplabel.featured .lb-icon{flex:none;display:grid;place-items:center;width:21px;height:21px;border-radius:50%;background:rgba(255,255,255,.2)}
.maplabel.featured .lb-icon svg{width:12px;height:12px;fill:#fff}
.maplabel.featured i{width:2px;height:9px;background:var(--zhu);box-shadow:0 0 0 .75px rgba(255,255,255,.7)}
.maplabel.featured.pin button{top:var(--dy,-9px)}
.maplabel.featured.pin i{width:var(--len,9px);height:2px;margin-bottom:-1px}
.maplabel.featured i::after{width:7px;height:7px;margin-left:-3.5px;bottom:-3.5px;background:var(--zhu);box-shadow:0 0 0 2px #fff}
.maplabel.featured i::before{content:"";position:absolute;left:50%;bottom:-3.5px;width:7px;height:7px;margin-left:-3.5px;border-radius:50%;background:rgba(179,56,44,.5);
 animation:pulseRing 2.4s var(--ease-out) infinite;will-change:transform,opacity}
.maplabel.featured.pin i::after,.maplabel.featured.pin i::before{left:-3.5px;top:50%;bottom:auto;margin:-3.5px 0 0}

/* route stops: numbered disc on a stem; the name hangs beside the disc where it fits (routes.js placeNames) */
.rs-num{display:grid;place-items:center;flex:none;border-radius:50%;background:var(--walk-deep);color:#fff;font:700 11.5px/1 var(--sans);font-variant-numeric:tabular-nums}
.maplabel.route-stop button{position:relative;height:auto;padding:2px;gap:0;background:#fff;border:1.5px solid var(--walk);color:#5a3a12;
 box-shadow:0 1px 2px rgba(20,32,27,.18),0 4px 10px -4px rgba(20,32,27,.3)}
.maplabel.route-stop button::before{display:none}
.maplabel.route-stop .rs-num{width:22px;height:22px}
.maplabel.route-stop .rs-num.multi{width:auto;min-width:22px;padding:0 6px;border-radius:11px}
.maplabel.route-stop.start .rs-num{background:var(--zhu)}.maplabel.route-stop.end .rs-num{background:var(--ink)}
.maplabel.route-stop .rs-name{position:absolute;top:50%;left:calc(100% + 4px);display:flex;align-items:center;height:24px;margin-top:-12px;padding:0 9px;border-radius:var(--r-pill);
 background:rgba(251,249,243,.97);border:1px solid rgba(217,119,42,.45);box-shadow:0 1px 3px rgba(20,32,27,.18);font:600 12px/1 var(--sans);color:#5a3a12;white-space:nowrap;
 visibility:hidden;opacity:0;transition:opacity .2s,visibility 0s linear .2s}
.maplabel.route-stop.flip .rs-name{left:auto;right:calc(100% + 4px)}
.maplabel.route-stop.named .rs-name,.maplabel.route-stop.active .rs-name{visibility:visible;opacity:1;transition:opacity .2s,visibility 0s}
@media(hover:hover){.maplabel.route-stop:hover{z-index:100000!important}.maplabel.route-stop:hover .rs-name{visibility:visible;opacity:1;transition:opacity .2s,visibility 0s}}
/* no entrance animation on route-stop stems: its fill would override the .veiled fade */
.maplabel.route-stop i{height:10px;box-shadow:none;animation:none;transition:height .18s var(--ease-out),opacity .18s;background:linear-gradient(var(--walk),rgba(217,119,42,.25))}
.maplabel.route-stop i::after{background:var(--walk)}
.maplabel.route-stop.veiled i{opacity:.22}
.maplabel.route-stop.active{z-index:100000!important}
.maplabel.route-stop.active button{background:var(--walk-deep);border-color:var(--walk-deep);color:#fff;box-shadow:0 0 0 4px rgba(217,119,42,.25),0 6px 16px -6px rgba(90,58,18,.5)}
.maplabel.route-stop.active .rs-num{background:#fff;color:var(--walk-deep)}
.maplabel.route-stop.active .rs-name{background:var(--walk-deep);border-color:var(--walk-deep);color:#fff}
/* while a route is on the map, other place labels step aside */
body.route-on .maplabel:not(.route-stop):not(.selected){visibility:hidden}

/* ---------- sheets: directory (#panel) and place card (#card) ---------- */
.sheet{display:flex;flex-direction:column;overflow:hidden}
.directory{z-index:10}
.info-card{z-index:11}
.sheet-grip{display:none}
.panel-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 16px 8px var(--pad)}
.panel-head h2{font:600 21px/1.3 var(--serif);letter-spacing:.1em;color:var(--ink)}
#panel-close,#data-close{width:40px;height:40px;background:var(--paper-2);color:var(--ink-2)}
@media(hover:hover){#panel-close:hover,#data-close:hover{background:var(--paper-3);color:var(--ink)}}

/* tabs */
.panel-tabs{position:relative;flex:none;display:flex;margin:0 var(--pad);box-shadow:inset 0 -1px 0 var(--line)}
.panel-tabs button{flex:1;height:44px;font-size:14px;font-weight:500;color:var(--muted);transition:color var(--t-2)}
.panel-tabs button.active{color:var(--ink);font-weight:600}
@media(hover:hover){.panel-tabs button:not(.active):hover{color:var(--ink-2)}}
.tab-ind{position:absolute;left:0;bottom:0;height:2.5px;border-radius:2px;background:var(--ink);
 width:max(0px,calc(var(--tab-w,0px) - 44px));transform:translateX(calc(var(--tab-x,0px) + 22px));
 transition:transform .5s var(--spring-soft),width .5s var(--spring-soft)}
.tab-pane{flex:1;min-height:0;display:flex;flex-direction:column}
.tab-pane:not([hidden]){animation:fadeIn var(--t-2) var(--ease-out)}

/* shared scroll panes */
.route-list,.route-detail,.guide,.place-list,#data-content{overflow-y:auto;overscroll-behavior:contain;touch-action:pan-y;scrollbar-width:thin;scrollbar-color:rgba(28,42,37,.2) transparent}
/* scroll shadow: a paper cover rides with the content and hides a soft top shade until the pane is scrolled */
.route-list,.route-detail,.guide,.place-list,#data-content{
 background:linear-gradient(var(--sheet) 40%,rgba(251,249,243,0)) center top/100% 28px no-repeat local,
  linear-gradient(rgba(28,42,37,.10),rgba(28,42,37,0)) center top/100% 10px no-repeat scroll}
.route-detail:focus,.guide:focus,.place-list:focus{outline:none}
.route-detail:focus-visible,.guide:focus-visible,.place-list:focus-visible,.card-content:focus-visible{outline:2px solid var(--dai);outline-offset:-2px}

/* places */
.search{flex:none;display:flex;align-items:center;gap:10px;height:46px;margin:16px var(--pad) 0;padding:0 14px;border-radius:14px;background:var(--paper-2);border:1px solid transparent;
 transition:border-color var(--t-1),box-shadow var(--t-1),background-color var(--t-1)}
.search:focus-within{background:#fff;border-color:var(--dai);box-shadow:0 0 0 3px var(--dai-soft)}
.search svg{flex:none;width:18px;height:18px;color:var(--muted)}
.search input{flex:1;min-width:0;height:100%;padding:0;border:0;outline:0;background:none;font-size:15px;color:var(--ink)}
.search input:focus-visible{outline:none}
.search input::placeholder{color:var(--muted);opacity:1}
.search input::-webkit-search-cancel-button{-webkit-appearance:none}
.categories{flex:none;display:flex;gap:8px;margin-top:8px;padding:4px var(--pad);overflow-x:auto;scrollbar-width:none;overscroll-behavior-x:contain}
.categories::-webkit-scrollbar{display:none}
.categories button{position:relative;flex:none;height:36px;padding:0 14px;border-radius:var(--r-pill);background:var(--paper-2);font-size:13.5px;font-weight:500;color:var(--ink-2);
 transition:background-color var(--t-1),color var(--t-1),scale var(--t-1) var(--ease-out)}
.categories button:active{scale:.96}
.categories button.active{background:var(--ink);color:#fbf9f3}
@media(hover:hover){.categories button:not(.active):hover{background:var(--paper-3)}}
.list-summary{flex:none;margin:10px var(--pad) 4px;font-size:13px;line-height:1.5;color:var(--muted)}
.list-summary:empty{display:none}
.place-list{flex:1;min-height:0;padding:4px 12px 16px}
.place-item{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:60px;padding:10px 8px;border-radius:14px;text-align:left;transition:background-color var(--t-1)}
.place-item+.place-item::before{content:"";position:absolute;top:0;left:56px;right:8px;height:1px;background:var(--line);transition:opacity var(--t-1)}
.place-item:active{background:var(--paper-3)}
.place-item.selected,.place-item.featured{background:var(--dai-soft)}
.place-item.featured{background:var(--zhu-soft);margin-bottom:4px}
.place-item.selected::before,.place-item.selected+.place-item::before,.place-item.featured::before,.place-item.featured+.place-item::before{opacity:0}
.place-item.selected::after{content:"";position:absolute;left:0;top:12px;bottom:12px;width:3px;border-radius:0 3px 3px 0;background:var(--dai)}
.place-item.featured.selected::after{background:var(--zhu)}
@media(hover:hover){
 .place-item:not(.selected):not(.featured):hover{background:var(--paper-2)}
 .place-item:hover::before,.place-item:hover+.place-item::before{opacity:0}
}
.pi-icon{flex:none;display:grid;place-items:center;width:36px;height:36px;border-radius:10px;background:var(--c-soft,var(--paper-2));color:var(--c-ink,var(--ink-2));font:600 15px/1 var(--serif)}
.place-item.featured .pi-icon{background:var(--zhu-fill);color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.18)}
.pi-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.place-item strong{font:600 15px/1.35 var(--serif);letter-spacing:.04em;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.place-item.featured strong{color:var(--zhu-deep)}
.place-item small{font-size:13px;line-height:1.45;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.place-item small.estimate{text-decoration:underline dashed rgba(154,116,49,.6);text-decoration-thickness:1px;text-underline-offset:3px}
.place-list.animate .place-item{animation:fadeUp .3s var(--ease-out) backwards}
.empty{padding:18px;font-size:13px;line-height:1.7;color:var(--muted);text-align:center}

/* routes: list */
.route-list{flex:1;min-height:0;display:grid;align-content:start;gap:12px;padding:16px var(--pad) 24px}
.route-card{display:grid;justify-items:start;gap:6px;width:100%;padding:16px 16px 15px;border-radius:18px;text-align:left;background:var(--paper-2);
 transition:transform .5s var(--spring-soft),box-shadow .3s var(--ease-out),background-color .2s,scale var(--release) var(--spring-soft)}
.route-card:active{scale:.98;transition:transform .5s var(--spring-soft),box-shadow .3s var(--ease-out),background-color .2s,scale var(--press) var(--ease-out)}
@media(hover:hover){.route-card:hover{transform:translateY(-2px);background:#fdfcf8;box-shadow:var(--sh-2)}}
.rc-by{display:inline-flex;align-items:center;height:22px;padding:0 8px;border-radius:6px;background:var(--jin-soft);color:#7a5a24;font-size:12px;font-weight:600;letter-spacing:.04em;white-space:nowrap}
.route-card strong{margin-top:2px;font:600 17px/1.4 var(--serif);letter-spacing:.06em;color:var(--ink);word-break:keep-all;overflow-wrap:anywhere}
.rc-meta{font-size:13.5px;line-height:1.5;color:var(--ink-2);font-variant-numeric:tabular-nums}
.rc-fit{font-size:13.5px;line-height:1.6;color:var(--ink-2)}
.rc-path{font-size:13px;line-height:1.6;color:var(--muted);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.route-card.featured{background:#fbefea}
@media(hover:hover){.route-card.featured:hover{background:#fdf3ef}}
.route-card.featured .rc-by{background:var(--zhu-soft);color:var(--zhu)}

/* routes: detail */
.route-detail{flex:1;min-height:0;padding:4px var(--pad) 28px}
.route-detail:not([hidden]){animation:fadeIn var(--t-2) var(--ease-out)}
.route-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:4px}
.route-back{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding-right:8px;font-size:14px;font-weight:500;color:var(--ink-2)}
.route-back::before{content:"";width:8px;height:8px;margin-left:3px;border-left:1.7px solid currentColor;border-bottom:1.7px solid currentColor;transform:rotate(45deg)}
@media(hover:hover){.route-back:hover{color:var(--ink)}}
.route-title{margin-bottom:16px;font:600 21px/1.4 var(--serif);letter-spacing:.06em;color:var(--ink);word-break:keep-all;overflow-wrap:anywhere}
/* two by two: the route detail is never wider than about 390px, too narrow for four values such as "约 5–6 小时" side by
   side without breaking inside them; a value never wraps */
.route-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:16px}
.route-stats span{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;min-height:56px;padding:8px 6px;border-radius:var(--r-sm);background:var(--paper-2);text-align:center}
.route-stats b{font-size:16px;font-weight:600;line-height:1.25;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.route-stats small{font-size:11.5px;line-height:1.3;color:var(--muted)}
.route-actions{display:flex;gap:10px;margin-bottom:20px}
.route-actions .btn{height:46px}
.route-actions .route-play{flex:1}
.route-actions .btn.ghost{flex:none;padding:0 18px}
.route-play svg{fill:currentColor;stroke:none}
.route-summary{margin-bottom:20px;font-size:14.5px;line-height:1.75;color:var(--ink-2)}
.route-profile{position:relative;height:106px;margin-bottom:16px;padding:22px 0 20px}
.route-profile svg{width:100%;height:64px;overflow:visible}
.pf-area{fill:var(--walk-soft)}
.pf-line{fill:none;stroke:var(--walk);stroke-width:1.8;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.route-profile circle{fill:#fff;stroke:var(--walk-deep);stroke-width:1.5;vector-effect:non-scaling-stroke}
.route-profile span{position:absolute;font-size:11.5px;line-height:1;color:var(--muted);font-variant-numeric:tabular-nums}
.pf-cap{top:2px;left:0;font-weight:600;letter-spacing:.08em;color:var(--ink-2)}
.pf-hi{top:2px;right:0}.pf-lo{bottom:2px;right:0}
.route-steps{list-style:none;margin:0;padding:0}
.rs-stop button{position:relative;display:grid;grid-template-columns:26px minmax(0,1fr);column-gap:12px;align-items:center;width:100%;min-height:42px;padding:8px 8px 8px 8px;border-radius:var(--r-sm);text-align:left;
 transition:background-color var(--t-2),box-shadow var(--t-2)}
.rs-stop .rs-num{grid-row:span 2;align-self:start;width:26px;height:26px;font-size:12px}
.rs-stop:first-child .rs-num{background:var(--zhu)}.rs-stop:last-child .rs-num{background:var(--ink)}
.rs-stop strong{font-size:15px;font-weight:600;line-height:26px;color:var(--ink)}
.rs-stop small{font-size:12.5px;line-height:1.55;color:var(--muted)}
.rs-stop.active button{background:#fff;box-shadow:var(--sh-1)}
@media(hover:hover){.rs-stop:not(.active) button:hover{background:var(--paper-2)}}
/* a dashed walking line joins the discs through the legs */
.rs-stop:not(:first-child) button::before,.rs-stop:not(:last-child) button::after,.rs-leg::before{content:"";position:absolute;left:20px;width:2px;
 background:repeating-linear-gradient(to bottom,rgba(217,119,42,.55) 0 4px,transparent 4px 8px)}
.rs-stop:not(:first-child) button::before{top:0;height:8px}
.rs-stop:not(:last-child) button::after{top:34px;bottom:0}
.rs-leg{position:relative;display:grid;grid-template-columns:26px minmax(0,1fr);column-gap:12px;align-items:center;padding:0 8px}
.rs-leg::before{top:0;bottom:0}
.rs-leg .rs-icon{position:relative;z-index:1;justify-self:center;display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--sheet);border:1px solid var(--line-2);color:var(--ink-2)}
.rs-icon svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.rs-leg-text{padding:8px 0;font-size:12.5px;line-height:1.55;color:var(--muted)}
.rs-leg-text em{display:block;margin-top:2px;font-style:normal;font-size:12px;color:#8a5a1f}
.route-detail h4,.story-box h4{display:flex;align-items:center;gap:10px;font:600 16px/1.5 var(--serif);letter-spacing:.1em;color:var(--ink)}
.route-detail h4::before,.story-box h4::before{content:"";flex:none;width:6px;height:6px;background:var(--jin);transform:rotate(45deg)}
.route-detail h4{margin:24px 0 8px}
.route-tips{margin:0 0 8px;padding-left:20px;font-size:14px;line-height:1.75;color:var(--ink-2)}
.route-tips li+li{margin-top:4px}
.route-tips li::marker{color:var(--faint)}
.route-detail details.more{margin-top:12px}

/* guide (游览须知) */
.guide{flex:1;min-height:0;padding:12px var(--pad) 28px}
.guide-intro{margin-bottom:4px;font-size:12.5px;color:var(--muted)}
.guide-sec{border-bottom:1px solid var(--line)}
.guide-sec summary{position:relative;display:flex;flex-direction:column;gap:2px;padding:14px 36px 14px 0;list-style:none;cursor:pointer;-webkit-tap-highlight-color:transparent}
.guide-sec summary::-webkit-details-marker{display:none}
.guide-sec summary::after,details.more summary::after{content:"";position:absolute;right:8px;top:50%;width:8px;height:8px;margin-top:-6px;border-right:1.6px solid var(--ink-2);border-bottom:1.6px solid var(--ink-2);
 transform:rotate(45deg);opacity:.7;transition:transform .3s var(--ease-out),margin .3s var(--ease-out)}
.guide-sec[open] summary::after,details.more[open] summary::after{transform:rotate(225deg);margin-top:-2px}
.guide-sec summary b{font:600 16px/1.45 var(--serif);letter-spacing:.06em;color:var(--ink)}
.guide-sec summary small{font-size:12.5px;line-height:1.5;color:var(--muted)}
@media(hover:hover){.guide-sec summary:hover b{color:var(--dai)}}
.guide-body{padding-bottom:18px;font-size:14.5px;line-height:1.75;color:var(--ink-2)}
.guide-sec[open] .guide-body{animation:fadeIn var(--t-2) var(--ease-out)}
.guide-body>*+*{margin-top:10px}
.guide-body h4{margin-top:16px;font-size:14px;font-weight:600;color:var(--ink)}
.guide p.story{font-size:14.5px;line-height:1.8}
.guide-rows{display:grid;grid-template-columns:6em minmax(0,1fr);gap:8px 12px}
.guide-rows dt{font-size:12.5px;line-height:1.75;color:var(--muted);padding-top:1px}
.guide-rows dd{font-size:14.5px;line-height:1.7;color:var(--ink)}
.guide-list{padding-left:20px}.guide-list li+li{margin-top:4px}.guide-list li::marker{color:var(--faint)}
.guide-phones{list-style:none;padding:0}
.guide-phones li{display:flex;flex-direction:column;gap:8px;padding:12px 0;border-bottom:1px solid var(--line)}
.guide-phones li:last-child{border-bottom:0}
.guide-phones .who{font-size:14.5px;font-weight:600;color:var(--ink)}
.guide-phones .nums{display:flex;flex-wrap:wrap;gap:8px}
.guide-phones a{display:inline-flex;align-items:center;gap:8px;min-height:40px;padding:0 16px 0 12px;border-radius:var(--r-pill);background:var(--dai-soft);color:var(--dai);
 font-size:14.5px;font-weight:600;text-decoration:none;font-variant-numeric:tabular-nums;transition:background-color var(--t-1),scale var(--t-1) var(--ease-out)}
.guide-phones a::before{content:"";flex:none;width:15px;height:15px;background:currentColor;
 -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3.5h3l1.5 4-2 1.3a11 11 0 0 0 6.2 6.2l1.3-2 4 1.5v3a2 2 0 0 1-2 2A16.5 16.5 0 0 1 4.5 5.5a2 2 0 0 1 2-2z'/%3E%3C/svg%3E") center/contain no-repeat;
 mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3.5h3l1.5 4-2 1.3a11 11 0 0 0 6.2 6.2l1.3-2 4 1.5v3a2 2 0 0 1-2 2A16.5 16.5 0 0 1 4.5 5.5a2 2 0 0 1 2-2z'/%3E%3C/svg%3E") center/contain no-repeat}
.guide-phones a:active{scale:.97}
@media(hover:hover){.guide-phones a:hover{background:#d5e6e2}}
.guide-phones small{font-size:12px;line-height:1.5;color:var(--muted)}
.guide-note{font-size:12.5px;line-height:1.65;color:var(--muted)}
.guide-src{font-size:12px;line-height:1.7;color:var(--muted)}
.guide-src a{color:var(--dai)}
.guide-data{padding:16px 0 4px}
.guide-data button{min-height:44px;margin-top:8px;padding:0 12px;border-radius:var(--r-sm);background:var(--paper-2);color:var(--dai);font-size:13px}

/* how a paragraph should be read (guide.js kindLabel) */
.kind{display:inline-block;margin-right:6px;padding:1px 7px;border-radius:6px;font-size:11.5px;font-weight:600;line-height:1.5;letter-spacing:.04em;vertical-align:1px;background:var(--paper-3);color:var(--ink-2)}
.kind.k-history{background:var(--jin-soft);color:#7a5a24}
.kind.k-belief{background:var(--zhu-soft);color:var(--zhu)}
.kind.k-legend{background:#efe9f7;color:#6a4fa3}
.kind.k-building{background:var(--dai-soft);color:var(--dai)}
.kind.k-tip{background:var(--paper-3);color:var(--ink-2)}

/* ---------- place card ---------- */
/* The whole card scrolls, photos included, so on a short screen the reading area grows to the full card as soon as
   people scroll; the close button stays pinned (sticky, first in flex order, taking no room). Same scroll shadow as the
   other panes, laid over the paper grain. */
.info-card{overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:rgba(28,42,37,.2) transparent;
 background-image:linear-gradient(var(--sheet) 40%,rgba(251,249,243,0)),linear-gradient(rgba(28,42,37,.10),rgba(28,42,37,0)),var(--grain);
 background-size:100% 28px,100% 10px,auto;background-repeat:no-repeat,no-repeat,repeat;background-attachment:local,scroll,scroll;background-position:center top,center top,0 0}
.info-card>.close{position:sticky;top:12px;z-index:3;order:-1;align-self:flex-end;flex:none;width:36px;height:36px;margin:12px 12px -48px 0;background:rgba(251,249,243,.9);color:var(--ink);box-shadow:var(--sh-1);
 -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
@media(hover:hover){.info-card>.close:hover{background:#fff}}
.info-card>.card-hero{order:0}.info-card>.card-head{order:1}.info-card>.card-content{order:2}
.card-hero{position:relative;flex:none;display:flex;gap:3px;height:208px;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scrollbar-width:none;overscroll-behavior-x:contain;touch-action:pan-x;background:var(--paper-3)}
.card-hero::-webkit-scrollbar{display:none}
.card-hero a{position:relative;flex:0 0 86%;height:100%;overflow:hidden;scroll-snap-align:start;background:var(--paper-3)}
.card-hero a:only-child{flex-basis:100%}
.card-hero a:focus-visible{outline:none}
.card-hero a:focus-visible::after{content:"";position:absolute;inset:0;z-index:1;box-shadow:inset 0 0 0 3px var(--dai),inset 0 0 0 5px rgba(255,255,255,.92);pointer-events:none}
.card-hero img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .5s var(--ease-out)}
@media(hover:hover){.card-hero a:hover img{transform:scale(1.03)}}
.photo-date{position:absolute;left:10px;bottom:10px;padding:3px 8px;border-radius:var(--r-pill);background:rgba(20,26,23,.55);color:#fff;font-size:11px;line-height:1.4;pointer-events:none}
.card-head{flex:none;display:flex;flex-direction:column;align-items:flex-start;gap:6px;padding:16px var(--pad) 8px}
.info-card>.close:first-child+.card-head{padding-top:20px;padding-right:64px}
.tag{display:inline-flex;align-items:center;height:22px;padding:0 8px;border-radius:6px;background:var(--c-soft,var(--paper-2));color:var(--c-ink,var(--ink-2));font-size:12px;font-weight:600;letter-spacing:.04em;white-space:nowrap}
.info-card.featured .tag{background:var(--zhu-soft);color:var(--zhu)}
.card-head h2{font:600 25px/1.3 var(--serif);letter-spacing:.06em;color:var(--ink);word-break:keep-all;overflow-wrap:anywhere}
.info-card.featured .card-head h2{color:var(--zhu-deep)}
.card-head .sub{font-size:13px;line-height:1.5;color:var(--muted)}
.card-content{flex:1 0 auto;display:flex;flex-direction:column;gap:14px;padding:4px var(--pad) 24px}
.card-content>*{flex:none}
.card-content.swap{animation:fadeUp .28s var(--ease-out)}
.card-summary{display:flex;flex-direction:column;gap:12px}
/* meta line: "a · b · c"; a separator that would start a wrapped line falls into the clipped gutter */
.info-card .chips{display:flex;flex-wrap:wrap;margin-left:-15px;clip-path:inset(0 0 0 15px);font-size:13px;line-height:1.65;color:var(--muted)}
.info-card .chips span{position:relative;padding-left:15px}
.info-card .chips span::before{content:"·";position:absolute;left:4px;width:7px;text-align:center;color:var(--faint)}
.info-card .chips span:first-child{color:var(--ink-2)}
.card-summary .card-actions{display:flex;gap:10px}
.card-summary .btn{flex:1;height:48px}
.info-card p{font-size:14.5px;line-height:1.8;color:var(--ink-2)}
.info-card p.lead{font-size:14.5px}
.info-card p.highlight{padding:12px 14px 12px 16px;border-left:3px solid var(--jin);border-radius:0 var(--r-sm) var(--r-sm) 0;background:var(--jin-soft);color:#4d3a1c;line-height:1.75}
.highlight b{display:block;margin-bottom:4px;font:600 12.5px/1.4 var(--serif);letter-spacing:.24em;color:#85632a}
.story-box{display:flex;flex-direction:column;gap:10px}
.story-box h4{margin-top:4px}
.info-card p.story{line-height:1.8}
.transit{display:flex;flex-direction:column;gap:4px;padding:12px 14px;border-radius:var(--r-sm);background:var(--paper-2)}
.info-card .transit p{font-size:13.5px;line-height:1.6;color:var(--ink)}
.transit small{display:block;font-size:12px;line-height:1.6;color:var(--muted)}
.route-teaser{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border-radius:var(--r-md);background:var(--paper-2);text-align:left;
 transition:background-color var(--t-1),scale var(--t-1) var(--ease-out)}
.route-teaser:active{scale:.985}
@media(hover:hover){.route-teaser:hover{background:var(--paper-3)}}
.route-teaser>svg{flex:none;width:36px;height:36px;padding:8px;border-radius:50%;background:var(--walk-soft);fill:none;stroke:var(--walk-deep);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.route-teaser>span{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.route-teaser b{font-size:14.5px;font-weight:600;line-height:1.4;color:var(--ink)}
.route-teaser small{font-size:12.5px;line-height:1.5;color:var(--muted)}
.route-teaser::after{content:"";flex:none;width:8px;height:8px;margin-right:4px;border-right:1.7px solid var(--muted);border-top:1.7px solid var(--muted);transform:rotate(45deg)}
/* 资料与依据: a quiet disclosure row */
details.more{border-top:1px solid var(--line)}
details.more summary{position:relative;display:flex;align-items:center;min-height:48px;padding-right:32px;list-style:none;font-size:14px;font-weight:600;color:var(--ink-2);cursor:pointer;-webkit-tap-highlight-color:transparent}
details.more summary::-webkit-details-marker{display:none}
details.more[open]{padding-bottom:4px}
details.more[open]>:not(summary){animation:fadeIn var(--t-2) var(--ease-out)}
details.more p{margin:0 0 8px;font-size:13px;line-height:1.7;color:var(--muted)}
details.more p.coords{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.links{display:flex;flex-wrap:wrap;gap:6px 14px;margin:0 0 8px;font-size:13px;line-height:1.6}
.links a{color:var(--dai);text-decoration-color:rgba(47,94,87,.35)}
.links span{color:var(--muted)}
.photo-credits{margin-bottom:8px}
.photo-credits h4{margin:4px 0 6px;font-size:13px;font-weight:600;color:var(--ink-2)}
details.more .photo-credits p{margin:8px 0 2px;color:var(--ink-2)}
.photo-credit{font-size:12px;line-height:1.6;color:var(--muted);overflow-wrap:anywhere}
.photo-credit a{color:inherit;text-decoration:underline;text-underline-offset:2px}
/* building card: the action sits at the foot of the sheet */
.card-content>.card-actions{position:sticky;bottom:-24px;z-index:1;display:flex;gap:10px;margin:auto calc(-1 * var(--pad)) -24px;padding:16px var(--pad) 24px;
 background:linear-gradient(rgba(251,249,243,0),var(--sheet) 34%)}
.card-content>.card-actions .btn{flex:1;height:48px}
/* after a camera flight the card's parts follow one another */
.info-card.arrive .card-head,.info-card.arrive .card-content>*{animation:fadeUp .5s var(--ease-out) backwards}
.info-card.arrive .card-head{animation-delay:.06s}
.info-card.arrive .card-content>:nth-child(1){animation-delay:.12s}
.info-card.arrive .card-content>:nth-child(2){animation-delay:.18s}
.info-card.arrive .card-content>:nth-child(3){animation-delay:.24s}
.info-card.arrive .card-content>:nth-child(4){animation-delay:.3s}
.info-card.arrive .card-content>:nth-child(n+5){animation-delay:.36s}
.info-card.arrive .card-hero img{animation:heroIn .9s var(--ease-out) backwards}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border-radius:14px;font-size:14.5px;font-weight:600;line-height:1;text-decoration:none;white-space:nowrap;
 transition:scale var(--t-1) var(--ease-out),filter var(--t-1),background-color var(--t-1),border-color var(--t-1)}
.btn svg{flex:none;width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.btn:active{scale:.97}
.btn:disabled{opacity:.45;pointer-events:none}
.btn.primary{background:var(--ink);color:#fbf9f3;box-shadow:0 1px 2px rgba(20,32,27,.2)}
.btn.accent{background:var(--zhu-fill);color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.08),0 1px 2px rgba(120,24,14,.18),0 8px 18px -10px rgba(150,40,30,.55)}
.btn.ghost{background:#fffdf8;color:var(--ink);box-shadow:inset 0 0 0 1px var(--line-2),0 1px 1px rgba(20,32,27,.04)}
.btn .short{display:none}
@media(hover:hover){.btn.primary:hover{background:#2a3b34}.btn.accent:hover{background:#c0402f}.btn.ghost:hover{background:#fff}}

/* ---------- route bar ---------- */
.route-hud{position:absolute;z-index:6;display:flex;flex-direction:column;gap:8px;padding:10px 12px;border-radius:20px;animation:hudIn .42s var(--ease-sheet)}
.route-hud.playing{box-shadow:inset 0 2px 0 var(--walk),var(--ring),var(--sh-2)}
.rh-head{display:flex;align-items:center;gap:8px}
.rh-dot{position:relative;flex:none;width:10px;height:10px;margin:0 2px 0 4px;border-radius:50%;background:var(--walk);box-shadow:0 0 0 3px rgba(217,119,42,.18)}
.rh-dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--walk);opacity:0}
.route-hud.playing .rh-dot::after{animation:pulseRing 1.4s var(--ease-out) infinite}
.rh-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.rh-text b{font:600 15.5px/1.35 var(--serif);letter-spacing:.06em;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* the status wraps rather than squeezing the place to nothing: a paused note and the next stop may take two lines */
.rh-text small{display:flex;flex-wrap:wrap;min-width:0;font-size:12.5px;line-height:1.4;color:var(--ink-2);white-space:nowrap}
.rh-where{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* a status on its own (the stop count with "点 ▶ 开始预演", or "步行前往 …") takes a second line on a narrow phone rather than
   losing its end: breaks fall at the spaces between its parts, balanced, and anything past two lines ellipsizes */
.rh-text small>.rh-where:only-child{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;
 white-space:normal;word-break:keep-all;overflow-wrap:anywhere;text-wrap:balance}
.rh-note{flex:none;font-weight:600;color:var(--walk-deep)}
.route-hud .rh-play{position:relative;width:40px;height:40px;background:var(--ink);color:#fbf9f3}
.route-hud .rh-play svg{width:16px;height:16px;fill:currentColor;stroke:none}
.rh-list{position:relative;flex:none;height:40px;padding:0 14px;border-radius:var(--r-sm);background:var(--paper-2);font-size:13.5px;font-weight:600;color:var(--ink-2);
 transition:background-color var(--t-1),scale var(--t-1) var(--ease-out)}
.rh-list:active{scale:.96}
.route-hud .rh-close{position:relative;width:40px;height:40px;color:var(--muted)}
@media(hover:hover){.rh-list:hover{background:var(--paper-3);color:var(--ink)}.route-hud .rh-close:hover{background:var(--paper-3);color:var(--ink)}.route-hud .rh-play:hover{background:#2c3e37}}
.rh-bar{height:3px;margin:0 4px;border-radius:2px;background:var(--paper-3);overflow:hidden}
.rh-bar i{display:block;height:100%;background:var(--walk);transform-origin:left center;transform:scaleX(0)}
/* position:relative: routes.js scrolls by each stop's offsetLeft inside this strip (current stop 8px from the edge) */
/* 6px of room above and below the pills: the scroller clips, and focus rings and touch hit areas need it */
.rh-stops{position:relative;display:flex;align-items:center;gap:4px;margin:-6px -12px -6px;padding:6px 12px 8px;list-style:none;overflow-x:auto;scrollbar-width:none;overscroll-behavior-x:contain;
 -webkit-mask-image:linear-gradient(90deg,rgba(0,0,0,.2),#000 4px,#000 calc(100% - 12px),rgba(0,0,0,.15));mask-image:linear-gradient(90deg,rgba(0,0,0,.2),#000 4px,#000 calc(100% - 12px),rgba(0,0,0,.15))}
.rh-stops::-webkit-scrollbar{display:none}
.rh-stop{flex:none}
.rh-stop button{position:relative;display:flex;align-items:center;gap:5px;height:32px;padding:0 9px 0 7px;border-radius:var(--r-pill);background:#fffdf8;border:1px solid rgba(217,119,42,.4);
 font-size:12.5px;font-weight:600;color:#5a3a12;white-space:nowrap;transition:background-color var(--t-2),color var(--t-2),opacity var(--t-2),border-color var(--t-2)}
.rh-stop .rs-num{width:18px;height:18px;font-size:10.5px}
.rh-stop.start .rs-num{background:var(--zhu)}.rh-stop.end .rs-num{background:var(--ink)}
.rh-stop.done button{opacity:.5}
.rh-stop.current button{background:var(--walk-deep);border-color:var(--walk-deep);color:#fff;opacity:1}
.rh-stop.current .rs-num{background:#fff;color:var(--walk-deep)}
.rh-stop.next button{border-color:var(--walk)}
.rh-stop.next button::after{content:"下一站";margin-left:1px;font-size:10.5px;font-weight:600;color:var(--walk-deep)}
.rh-leg{flex:none;display:flex;align-items:center;gap:3px;height:24px;padding:0 4px;border-radius:var(--r-pill);font-size:11.5px;color:var(--muted);white-space:nowrap;
 transition:background-color var(--t-2),color var(--t-2),opacity var(--t-2)}
.rh-leg .rs-icon{display:grid;place-items:center;width:14px;height:14px}
.rh-leg svg{width:14px;height:14px}
.rh-leg.done{opacity:.45}
.rh-leg.moving{background:var(--walk-soft);color:var(--walk-deep);font-weight:600}
.rh-leg.moving .rs-icon{animation:rh-walk .9s ease-in-out infinite alternate}

/* ---------- gesture tour ---------- */
/* the card is centred in the free map area: each layout sets the container's padding to keep it clear of the chrome */
.gesture-tour{position:fixed;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;padding:24px;pointer-events:none}
.gesture-symbols{position:absolute;width:0;height:0;overflow:hidden}
.tour-card{position:relative;flex:none;width:min(320px,100%);padding:20px 20px 14px;border-radius:var(--r-lg);text-align:center;color:var(--ink);
 box-shadow:var(--hi),0 0 0 .5px rgba(28,42,37,.08),var(--sh-4);opacity:0;transform:translateY(10px) scale(.97);transition:opacity .4s var(--ease-out),transform .7s var(--spring-soft)}
.gesture-tour.show .tour-card{opacity:1;transform:none}
.tour-steps{display:grid}
.tour-step{grid-area:1/1;display:flex;flex-direction:column;align-items:center;opacity:0;transform:translateX(14px);transition:opacity .3s var(--ease-in),transform .3s var(--ease-in)}
.tour-step.active{transition:opacity .42s var(--ease-out) .08s,transform .6s var(--spring-soft) .08s}
.tour-step.active{opacity:1;transform:none}
.tour-art{width:150px;height:104px;margin-bottom:10px;overflow:visible}
.gesture-hand{fill:#fbf9f3;stroke:var(--ink);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.gesture-arrow{fill:none;stroke:var(--ink-2);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:4 5;opacity:.5}
.touch-halo{fill:rgba(47,94,87,.3);stroke:none}
.tour-step-label{font-size:12.5px;letter-spacing:.1em;color:var(--muted);font-variant-numeric:tabular-nums}
.tour-step strong{margin-top:6px;font:600 20px/1.4 var(--serif);letter-spacing:.08em;color:var(--ink)}
.tour-step p{margin-top:4px;font-size:14px;line-height:1.6;color:var(--ink-2)}
.t-mouse{display:none}
@media(hover:hover) and (pointer:fine){.t-mouse{display:inline}.t-touch{display:none}}
.tour-progress{display:flex;justify-content:center;gap:6px;margin:16px 0 10px}
.tour-progress i{width:6px;height:6px;border-radius:3px;background:var(--line-2);transition:width .5s var(--spring-soft),background-color .3s}
.tour-progress i.active{width:20px;background:var(--ink)}
.tour-return{font-size:13px;line-height:1.5;color:var(--muted)}
.tour-skip{display:inline-flex;align-items:center;gap:6px;height:40px;margin-top:12px;padding:0 16px;border-radius:var(--r-pill);background:var(--paper-2);font-size:13.5px;font-weight:500;color:var(--ink-2);
 pointer-events:none;transition:background-color var(--t-1),scale var(--t-1) var(--ease-out)}
.tour-skip span{font-size:16px;line-height:1;color:var(--muted)}
.gesture-tour.show .tour-skip{pointer-events:auto}
.tour-skip:active{scale:.96}
@media(hover:hover){.tour-skip:hover{background:var(--paper-3)}}
.tour-step.active .pan-hand{animation:guide-pan 2.2s cubic-bezier(.45,0,.55,1) infinite;transform-origin:90px 65px}
.tour-step.active .rotate-hand{animation:guide-rotate 2.4s cubic-bezier(.45,0,.55,1) infinite;transform-origin:90px 108px}
.tour-step.active .spread-left{animation:guide-spread-left 2.2s cubic-bezier(.45,0,.55,1) infinite}
.tour-step.active .spread-right{animation:guide-spread-right 2.2s cubic-bezier(.45,0,.55,1) infinite}

/* ---------- loading / error ---------- */
.loading{position:fixed;inset:0;z-index:50;display:grid;place-items:center;background-color:var(--paper);
 background-image:var(--grain),radial-gradient(120% 90% at 50% 42%,var(--paper) 50%,var(--paper-2) 100%);
 transition:opacity .6s var(--ease-out),visibility 0s linear .6s}
.loading.done{opacity:0;visibility:hidden}
.load-inner{display:flex;flex-direction:column;align-items:center;padding:24px;text-align:center;transition:transform .6s var(--ease-out)}
.loading.done .load-inner{transform:translateY(-8px)}
.load-seal{width:56px;height:56px;border-radius:13px;font-size:20px;box-shadow:inset 0 0 0 3px #b23a2d,inset 0 0 0 4.5px rgba(251,241,230,.55),0 6px 16px -6px rgba(150,40,30,.5)}
.loading h2{margin-top:20px;font:600 34px/1.2 var(--serif);letter-spacing:.3em;text-indent:.3em;color:var(--ink)}
.load-sub{margin-top:8px;font-size:13px;letter-spacing:.2em;text-indent:.2em;color:var(--muted)}
.load-art{width:160px;height:70px;margin:24px 0 16px}
.load-art path{fill:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:240;stroke-dashoffset:240;animation:draw 1.6s var(--ease-out) forwards}
.load-art .far{stroke:var(--faint)}
.load-art .near{stroke:var(--ink-2);animation-delay:.2s}
#load-text{min-height:1.6em;font-size:13px;line-height:1.6;color:var(--muted)}
.load-bar{position:relative;width:160px;height:2px;margin-top:14px;border-radius:1px;background:var(--paper-3);overflow:hidden}
.load-bar span{position:absolute;top:0;bottom:0;left:0;width:40%;border-radius:1px;background:var(--ink);animation:loadSlide 1.3s var(--ease-in-out) infinite}
.reload-btn{height:44px;margin-top:20px;padding:0 24px;border-radius:14px;background:var(--ink);color:#fbf9f3;font-size:14.5px;font-weight:600;transition:scale var(--t-1) var(--ease-out)}
.reload-btn:active{scale:.97}
.loading.failed .load-bar{display:none}
.loading.failed .load-art path{animation:none;stroke-dashoffset:0}
.loading.failed #load-text{max-width:min(340px,calc(100vw - 48px));font-size:14px;line-height:1.7;color:var(--ink-2)}

/* ---------- photo viewer ---------- */
.viewer{position:fixed;inset:0;z-index:40;background:rgba(12,16,14,.985);opacity:0;transition:opacity .26s var(--ease-out);touch-action:pan-x pan-y}
.viewer.show{opacity:1}
.viewer:not(.show){pointer-events:none}
.viewer-strip{display:flex;height:100%;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;overscroll-behavior:contain;scrollbar-width:none;touch-action:pan-x}
.viewer-strip::-webkit-scrollbar{display:none}
.viewer .slide{flex:none;display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);place-items:center;width:100%;height:100%;scroll-snap-align:center;scroll-snap-stop:always;
 padding:calc(64px + var(--st)) calc(16px + var(--sr)) calc(112px + var(--sb)) calc(16px + var(--sl))}
.viewer .slide img{width:auto;height:auto;max-width:100%;max-height:100%;object-fit:contain;border-radius:var(--r-xs);box-shadow:0 16px 48px rgba(0,0,0,.45)}
.viewer .icon-btn{position:absolute;width:44px;height:44px;background:rgba(255,255,255,.12);color:#fff;
 transition:background-color var(--t-1),opacity var(--t-2) var(--ease-out),scale var(--t-1) var(--ease-out)}
.viewer .icon-btn svg{width:20px;height:20px}
@media(hover:hover){.viewer .icon-btn:not(:disabled):hover{background:rgba(255,255,255,.22)}}
/* ‹ on the first photo and › on the last: dimmed and inert-looking. No pointer-events:none, or the click would fall
   through to #viewer, whose click closes the viewer */
.viewer .icon-btn:disabled{opacity:.3;cursor:default;scale:none}
.viewer-close{top:calc(12px + var(--st));right:calc(12px + var(--sr))}
.viewer .viewer-prev,.viewer .viewer-next{top:50%;width:48px;height:48px;margin-top:-24px}
.viewer-prev{left:calc(16px + var(--sl))}.viewer-next{right:calc(16px + var(--sr))}
@media(hover:none){.viewer-prev,.viewer-next{display:none!important}}
.viewer-count{position:absolute;top:calc(24px + var(--st));left:50%;transform:translateX(-50%);font-size:13px;line-height:20px;letter-spacing:.08em;color:rgba(255,255,255,.8);font-variant-numeric:tabular-nums;pointer-events:none}
.viewer-caption{position:absolute;left:0;right:0;bottom:0;max-height:44%;overflow-y:auto;padding:48px calc(24px + var(--sr)) calc(20px + var(--sb)) calc(24px + var(--sl));
 background:linear-gradient(rgba(12,16,14,0),rgba(12,16,14,.88) 46%);color:#fff;font-size:13px;line-height:1.6;text-align:center}
.viewer-caption .photo-credit{margin-top:4px;font-size:11.5px;color:rgba(255,255,255,.7)}
.viewer-caption a{color:inherit}
.viewer-caption a,.photo-credit a{white-space:nowrap} /* a licence name never splits across lines */

/* ---------- data dialog ---------- */
dialog{padding:0;border:0;color:var(--ink);box-shadow:var(--hi),var(--sh-4);overflow:hidden}
dialog[open]{display:flex;flex-direction:column}
dialog::backdrop{background:rgba(20,30,25,.32);animation:fade .3s var(--ease-out)}
dialog.closing::backdrop{animation:fadeOut .19s var(--ease-in) forwards}
.dialog-head{flex:none;display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:22px 20px 14px 28px}
.eyebrow{display:block;font-size:12px;font-weight:600;line-height:1.4;letter-spacing:.12em;color:var(--muted)}
.dialog-head h2{margin-top:4px;font:600 20px/1.4 var(--serif);letter-spacing:.06em;color:var(--ink)}
#data-content{flex:1;min-height:0;padding:0 28px 28px;font-size:14px;line-height:1.75;color:var(--ink-2)}
#data-content:focus{outline:none}
#data-content p{margin:0 0 12px}
#data-content h3{margin:24px 0 8px;font:600 16px/1.5 var(--serif);letter-spacing:.08em;color:var(--ink)}
#data-content table{width:100%;margin:4px 0 16px;border-collapse:collapse;font-size:13.5px}
#data-content th{padding:0 12px 8px 0;border-bottom:1px solid var(--line-2);text-align:left;font-size:12px;font-weight:600;letter-spacing:.08em;color:var(--muted)}
#data-content td{padding:12px 12px 12px 0;border-bottom:1px solid var(--line);vertical-align:top;line-height:1.7}
#data-content td:first-child{width:8.5em;font-weight:600;color:var(--ink)}
#data-content b{font-weight:600;color:var(--ink)}
#data-content small{font-size:12.5px;line-height:1.6;color:var(--muted)}
#data-content a{color:var(--dai);text-decoration-color:rgba(47,94,87,.35)}

/* ---------- toast ---------- */
#toast{position:absolute;z-index:30;left:0;right:0;bottom:28px;width:max-content;max-width:calc(100% - 32px);margin:0 auto;padding:11px 18px;border-radius:var(--r-pill);
 background:var(--ink);color:#fbf9f3;font-size:14px;line-height:1.4;box-shadow:var(--sh-2);pointer-events:none;
 opacity:0;transform:translateY(10px);transition:opacity .25s var(--ease-in),transform .25s var(--ease-in)}
#toast.show{opacity:1;transform:none;transition:opacity .3s var(--ease-out),transform .3s var(--ease-out)}

/* ---------- desktop / tablet layout (everything that is not a phone; mirrors app.js compactViewport) ---------- */
@media (min-width:961px),(min-width:821px) and (orientation:portrait),(min-width:821px) and (min-height:521px){
 /* The dock / directory / card sit directly below the unified top menu. */
 .dock{top:var(--col-top);left:var(--col-x);width:var(--col-w);display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:10px;border-radius:20px}
 .dock-search{grid-column:1/-1;height:48px;padding:0 14px;font-size:14.5px}
 .dock-sep{display:none}
 .dock-btn{gap:8px;height:44px;font-size:14px;background:rgba(28,42,37,.045)}
 body.panel-open .dock,body.card-open .dock{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .26s var(--ease-in),visibility 0s linear .26s}
 .directory,.info-card{position:absolute;top:var(--col-top);left:var(--col-x);bottom:20px;width:var(--col-w);border-radius:20px;box-shadow:var(--hi),var(--sh-4)}
 .directory{transition:transform .42s var(--ease-sheet),opacity .42s var(--ease-sheet),visibility 0s}
 .directory.closed{transform:translateX(-24px);opacity:0;visibility:hidden;pointer-events:none;transition:transform .28s var(--ease-in),opacity .28s var(--ease-in),visibility 0s linear .28s}
 .info-card{transform:translateX(-16px);opacity:0;pointer-events:none;transition:transform .26s var(--ease-in),opacity .26s var(--ease-in)}
 .info-card.show{transform:none;opacity:1;pointer-events:auto;transition:transform .42s var(--ease-sheet),opacity .42s var(--ease-sheet)}
 .guide-rows{grid-template-columns:5em minmax(0,1fr)}
 /* map area to the right of the column */
 .viewbar{top:20px;left:var(--col-x);height:42px}
 .rail{top:20px;right:20px;gap:10px}
 .settings-wrap{position:absolute;top:0;right:calc(100% + 10px);width:280px;padding:0 16px 12px;border-radius:18px;box-shadow:var(--hi),var(--sh-4);transform-origin:top right;
  transition:opacity .22s var(--ease-out),transform .5s var(--spring-soft),visibility 0s}
 .settings.collapsed .settings-wrap{opacity:0;transform:scale(.94) translateX(6px);visibility:hidden;pointer-events:none;transition:opacity .22s var(--ease-in),transform .22s var(--ease-in),visibility 0s linear .22s}
 .route-hud{top:20px;left:var(--map-x);right:var(--rail-w);max-width:640px;margin:0 auto}
 .map-meta{left:var(--map-x);right:20px;bottom:28px}
 .flight-hint{top:76px;left:var(--map-x);right:var(--rail-w)}
 body.route-on .flight-hint{top:140px}
 .gesture-tour{padding:72px var(--rail-w) 64px var(--map-x)}
 #toast{left:calc(var(--col-x) + var(--col-w));bottom:64px} /* above the credits row */
 /* a card on a short screen: a lower photo strip leaves more of the first view for reading */
 .card-hero{height:clamp(150px,calc(26.7vh - 32px),208px)}
 dialog{width:min(640px,calc(100vw - 48px));max-width:640px;max-height:80vh;border-radius:var(--r-lg)}
 dialog[open]{animation:popIn .3s var(--ease-out)}
 dialog.closing{animation:popOut .19s var(--ease-in) forwards}
}
/* ---------- touch: every control gets a hit area of at least 44px, the visuals stay as drawn ---------- */
@media (pointer:coarse){
 .viewbar button::before{content:"";position:absolute;left:0;right:0;top:-6px;bottom:-6px}
 .info-card>.close::before{content:"";position:absolute;inset:-4px;border-radius:50%}
 #panel-close,#data-close,.tour-skip,.guide-phones a{position:relative}
 #panel-close::before,#data-close::before{content:"";position:absolute;inset:-2px;border-radius:50%}
 .categories button::before{content:"";position:absolute;inset:-4px}
 .tour-skip::before,.guide-phones a::after{content:"";position:absolute;left:0;right:0;top:-2px;bottom:-2px}
 .rh-stop button::before{content:"";position:absolute;left:-2px;right:-2px;top:-6px;bottom:-8px}
 input[type=range]{height:44px}
 .links{row-gap:14px}
 .links a,.photo-credit a{display:inline-block;padding:8px 0;margin:-8px 0}
}

/* ---------- press and release: the press lands in 80ms, the release springs back with one soft overshoot ---------- */
:is(.icon-btn,.map-actions button,.dock-search,.dock-btn,.categories button,.rh-list,.tour-skip,.reload-btn,.guide-phones a,.route-teaser,.btn){
 transition:background-color var(--t-1),color var(--t-1),border-color var(--t-1),box-shadow var(--t-2),filter var(--t-1),scale var(--release) var(--spring-soft)}
:is(.icon-btn,.map-actions button,.dock-search,.dock-btn,.categories button,.rh-list,.tour-skip,.reload-btn,.guide-phones a,.route-teaser,.btn):active{
 transition:background-color var(--t-1),color var(--t-1),border-color var(--t-1),box-shadow var(--t-2),filter var(--t-1),scale var(--press) var(--ease-out)}
.map-actions button:active,.icon-btn:active{scale:.9}
#settings-toggle,#help-open{transition:opacity .42s var(--ease-sheet),transform .42s var(--ease-sheet),visibility 0s,background-color var(--t-1),color var(--t-1),scale var(--release) var(--spring-soft)}
#settings-toggle:active,#help-open:active{transition:opacity .42s var(--ease-sheet),transform .42s var(--ease-sheet),visibility 0s,background-color var(--t-1),color var(--t-1),scale var(--press) var(--ease-out)}

/* ---------- press feedback where the standalone scale property is missing (Chromium < 104 WebViews) ---------- */
@supports not (scale:1){
 .btn:active,.dock button:active,.rh-list:active,.tour-skip:active,.reload-btn:active,.guide-phones a:active,.route-teaser:active{transform:scale(.97)}
 .categories button:active{transform:scale(.96)}
 .icon-btn:active,.map-actions button:active,#settings-toggle:active,#help-open:active{transform:scale(.92)}
}

/* ---------- while the loader is up the indicators take their first place without sliding in (light :has enhancement) ---------- */
#app:has(> #loading:not([hidden])) :is(.seg-ind,.tab-ind){transition:none}

/* ---------- first settle-in, while the loader fades (light :has enhancement; without it nothing animates) ---------- */
#app:has(> #loading.done:not([hidden])) > :is(.dock,.viewbar){animation:settle .5s var(--ease-out) backwards}
#app:has(> #loading.done:not([hidden])) > .viewbar{animation-delay:.12s}
#app:has(> #loading.done:not([hidden])) > .rail :is(.map-actions,#settings-toggle,#help-open){animation:settle .5s .18s var(--ease-out) backwards}

/* ---------- keyframes ---------- */
@keyframes fadeIn{from{opacity:0;transform:translateY(6px)}}
@keyframes fadeUp{from{opacity:0;transform:translateY(8px)}}
@keyframes heroIn{from{opacity:0;transform:scale(1.05)}}
@keyframes lbFade{from{opacity:0}}
@keyframes lbIn{from{opacity:0;transform:translateY(3px) scale(.94)}}
@keyframes lbPop{0%{transform:scale(.92)}55%{transform:scale(1.05)}100%{transform:none}}
@keyframes pulseRing{0%{transform:scale(1);opacity:.55}70%,100%{transform:scale(3.6);opacity:0}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes loadSlide{from{transform:translateX(-100%)}to{transform:translateX(250%)}}
@keyframes settle{from{opacity:0;transform:translateY(10px)}}
@keyframes hudIn{from{opacity:0;transform:translateY(-8px)}}
@keyframes popIn{from{opacity:0;transform:scale(.97)}}
@keyframes popOut{to{opacity:0;transform:scale(.97)}}
@keyframes sheetUp{from{transform:translateY(100%)}}
@keyframes sheetDown{to{transform:translateY(100%)}}
@keyframes sideIn{from{transform:translateX(calc(100% + 16px))}}
@keyframes sideOut{to{transform:translateX(calc(100% + 16px))}}
@keyframes fade{from{opacity:0}}
@keyframes fadeOut{to{opacity:0}}
@keyframes rh-walk{from{transform:translateX(-2px)}to{transform:translateX(2px)}}
@keyframes guide-pan{0%,100%{transform:translateX(-19px)}50%{transform:translateX(19px)}}
@keyframes guide-rotate{0%,100%{transform:translateX(-12px) rotate(-10deg)}50%{transform:translateX(12px) rotate(10deg)}}
@keyframes guide-spread-left{0%,100%{transform:translateX(9px)}50%{transform:translateX(-14px)}}
@keyframes guide-spread-right{0%,100%{transform:translateX(-9px)}50%{transform:translateX(14px)}}

/* ---------- html.lite (流畅 / 标准 tiers, the phone default): no blur over the moving map, no grain, no label pulse ---------- */
.lite .viewbar,.lite .map-actions,.lite #settings-toggle,.lite #help-open,.lite .dock,.lite .route-hud,.lite .flight-hint,.lite .status{
 background:var(--chrome-solid);-webkit-backdrop-filter:none;backdrop-filter:none}
.lite #settings-toggle[aria-expanded="true"]{background:var(--ink)}
.lite .info-card>.close{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgba(251,249,243,.96)}
.lite .sheet,.lite .settings-wrap,.lite dialog,.lite .tour-card,.lite .loading{background-image:none}
.lite .info-card{background-image:linear-gradient(var(--sheet) 40%,rgba(251,249,243,0)),linear-gradient(rgba(28,42,37,.10),rgba(28,42,37,0))}
.lite .maplabel.featured i::before{animation:none;display:none}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
 *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
 .maplabel.featured i::before,.fh-dot::after{animation:none!important;opacity:0}
 .load-bar span{animation:none!important;width:100%;opacity:.35}
 .rh-leg.moving .rs-icon{animation:none!important}
}
