/* mobile-first. Light mode is blue on warm paper, dark mode is green on
   black: the paper replaced white because MG is 不是全白的愛好者 and white
   merged with snow on the EBC basemap; the blue stayed because green is the
   dark theme's own (MG 2026-09-04: 藍色全不見了，綠色是深色在用的). Every accent is a variable so no hard-coded hue can survive a
   theme switch. */
:root {
  color-scheme: light;
  --page: #e8e4d8; --surface: #f4f1e8;
  --ink: #101826; --ink-2: #46536a; --muted: #525f73;
  --line: #d3d6d1;
  --accent: #1f66bd; --accent-2: #174f94; --accent-deep: #0d366b; --accent-ink: #ffffff;
  --hero-ink: #ffffff; --hero-ink-2: #c7dbf5; --hero-sky: #8fc4ff;
  --walker: #cf9a55; --walker-pack: #a17842;
  --scrim: 6, 24, 48;
  --shadow: 0 1px 2px rgba(16, 38, 74, .06), 0 6px 20px rgba(16, 38, 74, .07);
  --badge-bg: #fdeee7; --badge-ink: #a33f1c;
  --soon-bg: #f0b400; --soon-ink: #241a00;
  --rest-bg: #fdf4dd; --rest-ink: #7d5c05; --rest-chip: #8a6410;
}
/* Light by default; dark only when the reader chose it with the toggle. The
   OS setting used to switch it too -- MG 2026-09-14: 預設的佈景主題改爲淺色. */
:root[data-theme="dark"] {
  --page: #142019; --surface: #213028;
  --ink: #e9f2ec; --ink-2: #aec2b5; --muted: #a4b7aa;
  --line: #354b3d;
  --accent: #2fb178; --accent-2: #1c7a52; --accent-deep: #0a2a1c; --accent-ink: #04170f;
  --hero-ink: #ffffff; --hero-ink-2: #bfe0cd; --hero-sky: #7ad9a6;
  --scrim: 5, 20, 13;
  --shadow: 0 1px 2px rgba(0, 0, 0, .2), 0 6px 20px rgba(0, 0, 0, .16);
  --badge-bg: #33220f; --badge-ink: #eeb277;
  --soon-bg: #f0b400; --soon-ink: #241a00;
  --rest-bg: #2b2410; --rest-ink: #e3c069; --rest-chip: #4a3c14;
  color-scheme: dark;
}
/* Theme toggle: the glyph reports the mode you are *in* — sun while light,
   moon while dark. Only one of the two is ever displayed, so the button reads
   as a single control. Every rule here mirrors a palette rule above, so the
   icon can never disagree with the colours on screen. */
.theme-toggle { cursor: pointer; padding: 0; font: inherit; }
.theme-toggle .i-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .i-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .i-sun { display: none; }
:root[data-theme="light"] .theme-toggle .i-moon { display: none; }
:root[data-theme="light"] .theme-toggle .i-sun { display: block; }
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--page); color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", "Noto Sans TC", sans-serif;
  line-height: 1.55;
}
/* Per-language typography (MG 2026-09-05, 試試看). Apple picks the CJK face
   from <html lang>: zh-Hant gets PingFang, ja gets Hiragino -- which is why
   the Japanese pages read finer. English is 1.5-2x longer than either, so
   its paragraphs get a little more leading, a measure cap, and hyphenation
   instead of ragged edges. Chinese is left exactly as it was (the light
   weight was tried and rejected the same day). Headings and controls are
   left alone. */
:lang(en) { hyphens: auto; text-wrap: pretty; }
:lang(en) p, :lang(en) li { line-height: 1.65; max-width: 68ch; }
/* Hero */
.hero {
  position: relative; overflow: hidden; color: var(--hero-ink);
  /* Longhands, not the `background` shorthand. A shorthand holding a var()
     turns every longhand it covers into a pending-substitution value, resolved
     after the cascade — and WebKit lets that clobber a background-image a later
     rule set, where Chromium does not. The index carries its photograph in
     --hero-img and had it wiped on iOS; trip pages survived only because theirs
     is an inline style, which outranks the stylesheet either way. */
  background-color: var(--accent-deep);
  background-image: linear-gradient(155deg, var(--accent-deep) 0%, var(--accent-2) 55%, var(--accent) 100%);
}
/* Sized by its text alone, this banner was only as tall as the title, chips
   and download button needed — a short title left almost nothing of the
   photo showing before the notice box cut in right where the photo's own
   subject was (a deer, a ridgeline). Same fix as the homepage's landscape
   hero (LESSONS: "give the landscape hero room for a figure"), now applied
   to the one banner every trip page shares, not just that single photo. */
.hero.has-photo {
  background-color: var(--accent-deep);
  background-image: none;          /* cleared here, set again by .hero.tall / inline */
  background-position: center; background-size: cover; background-repeat: no-repeat;
  min-height: min(58vh, 460px);
}
/* The photo rides on the header's own background-image (set inline, so a stale
   cached stylesheet can never leave it stranded in the flow as a loose block). */
/* Scrim only where the text actually sits, so the photograph stays visible */
.hero.has-photo::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(var(--scrim), .76) 0%, rgba(var(--scrim), .48) 42%,
              rgba(var(--scrim), .16) 68%, rgba(var(--scrim), 0) 100%);
}
/* Actions sit in the flow beside the download button rather than floating in a
   corner, where a wrapped headline used to run underneath them. */
/* The download sits left, the round buttons right — but expressed as "push the
   download away from them" rather than as space-between, because a one-day trip
   has no zip to download and space-between with a single child is flex-start:
   the buttons dropped to the left edge and the page stopped matching every
   other trip. MG: 因為沒有「下載全部行程」的按鈕，導致功能按鈕的位置跟其他多日
   行程不同. Aligning to the end and letting the download claim the slack puts
   the controls in the same place whether or not there is anything beside them. */
.hero-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  justify-content: flex-end;
}
.hero-actions .dl-all { margin-right: auto; }
/* Publisher links: frosted discs that read as part of the photo's own UI */
.hero-links { display: flex; gap: 8px; flex: none; }
/* Seven 38 px targets and six 8 px gaps need 314 px, and only the very
   narrowest phones cannot give it: 360 px leaves 328 and 320 px leaves 288.
   So the wrap is scoped to those, not applied everywhere -- putting
   flex-wrap on .hero-links unconditionally makes it shrink to its share of
   the bar and break into two lines at 360 and 390 as well, which is where
   most readers are. 350 is the last width whose content box (318) still
   falls short. Shrinking the buttons is the other way out and is worse:
   38 px is the tap target, and the 32 px floor in
   tests/test_fold_affordance.py guards against a deleted rule rather than
   licensing smaller ones (2026-09-10). */
/* flex: none has to be lifted with it -- an item that refuses to shrink keeps
   its full width and then has nothing to wrap into. The thresholds are the
   widths at which the row stops fitting, and they move with the page's own AA
   control: 7 x 38 + 6 x 8 = 314 needs a 346 px page, and at xl the buttons are
   47 so 377 needs 409. Without the second rule the mark page overflowed by
   3 px at 390 with text enlarged -- caught by test_trip_reflow's size matrix,
   not by a sweep at standard size (2026-09-10). */
@media (max-width: 345px) {
  .hero-links { flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
}
@media (max-width: 410px) {
  :root[data-size="l"] .hero-links,
  :root[data-size="xl"] .hero-links {
    flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end;
  }
}
/* A Taiwan memory page has eight buttons (the Taiwan one into /baiyue/, MG
   2026-09-15), so its row stops fitting sooner. The widths are measured, not
   computed: a 1 px sweep of four memory pages (zh/en/ja) overflowed at
   346-374 px standard and 412-446 px xl without these rules, and at none with
   them. Scoped by class so the seven-button rows keep the thresholds above
   (test_trip_reflow caught 430 px at xl). */
@media (max-width: 375px) {
  .hero-links.long-row { flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
}
@media (max-width: 447px) {
  :root[data-size="l"] .hero-links.long-row,
  :root[data-size="xl"] .hero-links.long-row {
    flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end;
  }
}
.hero-links a, .hero-links button {
  width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  color: #fff; background: rgba(255, 255, 255, .15);
  border: 1px solid rgba(255, 255, 255, .34);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  transition: background .16s ease, transform .16s ease;
}
.hero-links a:focus-visible, .hero-links button:focus-visible {
  outline: 2px solid #fff; outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(var(--scrim), .55);
}
@media (hover: hover) and (pointer: fine) {
  .hero-links a:hover, .hero-links button:hover {
    background: rgba(255, 255, 255, .32); transform: translateY(-2px);
  }
}
.hero-links svg { width: 20px; height: 20px; display: block; }
/* Taiwan is a tall thin shape; at the row's 20 px it is 8 px wide, so this one
   glyph is drawn larger (MG 2026-09-15: 稍微再放大一點). The button is unchanged. */
.hero-links .baiyue-link svg, .page-tools .baiyue-link svg { width: 24px; height: 24px; }
/* Language switch: a plain glyph riding the same circle as the svg icons
   beside it (.hero-links a, .hero-links button above already gives it the
   disc/frost/hover/focus treatment) -- just needs its own type. */
.lang-toggle { font-size: 16px; font-weight: 600; line-height: 1; text-decoration: none; }
.foot-links { display: flex; gap: 8px; margin-bottom: 12px; }
.foot-links a {
  width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center;
  color: var(--ink-2); background: var(--surface); border: 1px solid var(--line);
  transition: color .16s ease, border-color .16s ease;
}
@media (hover: hover) and (pointer: fine) {
  .foot-links a:hover { color: var(--accent); border-color: var(--accent); }
}
.foot-links svg { width: 17px; height: 17px; }
.hero.has-photo h1, .hero.has-photo .sub, .hero.has-photo .hint {
  text-shadow: 0 1px 12px rgba(var(--scrim), .7);
}
/* Soft fade into the page instead of a silhouette — a jagged profile cut over
   a real photograph reads as torn paper, not as mountains. */
.hero.has-photo::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 96px; z-index: 2;
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--page) 0%, transparent) 0%,
              color-mix(in srgb, var(--page) 70%, transparent) 55%, var(--page) 100%);
  pointer-events: none;
}
.hero.has-photo .hero-inner { padding-bottom: 104px; }
/* A portrait hero that keeps the whole figure: on phones the box takes the
   photo's own 3:4 so cover crops nothing, and the melt into the page is a
   thin strip so the fade starts at the very bottom edge instead of climbing
   the subject's legs. Screens too wide for that box letterbox the photo on
   the hero's own deep tone rather than cropping the figure back out. */
.hero.tall {
  /* aspect-ratio grows the BOX to keep the ratio, and at 320 px the hero's own
     content is 460 px tall -- so the width was solved as 460 x 3/4 = 345 and
     the page carried a 25 px horizontal scrollbar (MG: 千萬不要產生滾軸). The
     clamp costs nothing: the hero stays 460 tall either way, it just stops
     bulging past the viewport. Measured on origin/main 2026-09-10, so this was
     live, not something the fold or the perf work introduced. */
  max-width: 100%;
  aspect-ratio: 3 / 4;
  background-image: var(--hero-img); background-position: var(--hero-pos);
}
.hero.tall::after {
  height: 46px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--page) 0%, transparent) 0%,
              var(--page) 100%);
}
/* Title and caption stay up top; the stat chips drop to the photo's bottom
   edge so the figure between them stays clear. On the wide banner there is no
   spare height, the auto margin collapses, and nothing moves. */
.hero.tall .hero-inner {
  padding-bottom: 14px; display: flex; flex-direction: column;
  height: 100%; box-sizing: border-box;
}
.hero.tall .hero-stats { margin-top: auto; }
.hero .hint-wide { display: none; }
/* A hero may carry a second photograph without changing its banner geometry —
   the trip pages use this where the index uses `tall`. */
.hero.swap { background-image: var(--hero-img); background-position: var(--hero-pos); }
/* WHICH photograph is a question about the screen's shape, not its size. An
   iPad held upright is 834 px across — wider than any phone breakpoint, yet
   still a portrait screen, where the portrait frame is the one that belongs.
   Width was standing in for orientation and got that case backwards. */
@media (orientation: landscape) {
  .hero.swap { background-image: var(--hero-wide); background-position: var(--hero-wide-pos); }
  /* A portrait that owns the phone hands the landscape screen a landscape
     frame instead of being letterboxed. Geometry returns to the standard
     banner — including aspect-ratio, since a phone turned sideways is landscape
     while still below the width breakpoint that used to clear it. */
  /* Deep enough for a figure, not just a strip of sky: left to size itself the
     banner is only as tall as its text, which crops a standing subject to a
     sliver. A floor in vh keeps a sideways phone from inheriting a desktop's
     idea of tall. */
  .hero.tall.has-wide {
    /* No url() in a custom property anywhere on the path that decides whether
       a photograph appears. Brave on iOS does not substitute one, and a failed
       var() does not fall back to the previous cascade winner — the property
       computes to `none`, so the hero went blank in landscape while portrait,
       served from the inline style, was fine. The real swap is emitted per
       page as literal URLs; this stays only so the geometry below still has a
       rule to hang on, and loses to the inline value either way. */
    background-image: var(--hero-wide);
    background-position: var(--hero-wide-pos);
    background-size: cover; aspect-ratio: auto; height: auto;
    min-height: min(64vh, 540px);
  }
  .hero.tall.has-wide::after {
    height: 96px;
    background: linear-gradient(180deg,
                color-mix(in srgb, var(--page) 0%, transparent) 0%,
                color-mix(in srgb, var(--page) 70%, transparent) 55%, var(--page) 100%);
  }
  .hero.tall.has-wide .hero-inner { padding-bottom: 104px; }
  .hero.has-wide .hint-tall { display: none; }
  .hero.has-wide .hint-wide { display: block; }
}
/* HOW TALL the box is stays a question about width: past phone width a 3:4
   box would swallow the screen, so the portrait frame letterboxes instead.
   Upright tablets land here — portrait photo, contained. */
@media (min-width: 700px) {
  .hero.tall {
    /* The height is a named value because the side fade has to know it. A
       contained photograph is as wide as this height times its own ratio, and
       a gradient laid over it has to be given that width in so many words: a
       gradient has no intrinsic size, so `contain` spreads it across the whole
       box rather than sizing it like the picture. Read from one place so the
       two cannot drift. */
    --hero-h: min(80vh, 740px);
    aspect-ratio: auto; height: var(--hero-h);
    background-size: contain; background-repeat: no-repeat;
  }
}
.hero-inner { max-width: 960px; margin: 0 auto; padding: 34px 16px 150px; position: relative; z-index: 2; }
/* The name reads whole, but the initials Taiwanese hikers actually say — TMB —
   stay at full strength while the rest of the letters ease back a little. */
/* The name and the line under it are one thing, so they sit together and the
   photograph's caption steps back — MG: 更靠近 hike365，因為它們是一組的.
   Before this the gaps above and below the line were 4px and 6px, near enough
   the same that it read as belonging to neither. */
/* The wordmark is the only heading on the site that is also a picture, and a
   picture needs room: at 1.75rem the walker's shoulders and waist were gone.
   A phone has none to spare, so 2.2rem is where it starts; every screen wider
   than one has room it was not using — MG: 我覺得可以更大一點說，尤其是在非行動
   頁面上. The steps reuse the breakpoints the layout already turns on rather
   than inventing sizes of their own. */
.hero h1 {
  font-size: 2.2rem; margin: 0 0 1px; letter-spacing: .01em;
  color: color-mix(in srgb, var(--hero-ink) 62%, transparent);
}
@media (min-width: 700px) { .hero h1 { font-size: 3rem; } }
@media (min-width: 960px) { .hero h1 { font-size: 3.7rem; margin-bottom: 3px; } }
/* The line under the name is half of one thing (MG: 它們是一組的), so it
   moves with it — left at 1rem under a 3.7rem heading it read as a caption
   that had wandered in from somewhere else. */
@media (min-width: 960px) { .hero .sub { font-size: 1.15rem; } }
/* Sized in em so the figure is a letter, not a picture beside one: it grows
   with the heading and stands on the same baseline. width is the advance an i
   would have taken. overflow visible because the pack reaches past the box. */
.hero h1 .wm-i {
  height: 1em; width: .36em; vertical-align: baseline; overflow: visible;
}
/* The walker is the one coloured thing in a wordmark of white letters, which is
   what lets it be a picture at all — MG: 文字都是白的大家會知道那是字. The colour
   is not chosen, it is measured: both hero photographs on this page show him in
   the same yellow jacket, and sampling them gives hue 32–39°. The first attempt
   took that hue and made it bright — 67% saturation against the jacket's 42–49%
   — which is why he said 比較跳. This keeps the hue and walks the saturation
   back toward the coat, stopping short of the photograph's own value, which is
   too dark to read against a dark banner. Shared by both themes: a jacket does
   not change colour when the page does. */
.hero h1 .wm-i .wk { fill: var(--walker); }
.hero h1 .wm-i .pk { fill: var(--walker-pack); }
/* A pointer where a pointer exists, and nothing else: no tooltip, no ring, no
   label. An easter egg that explains itself is a button. Touch devices get no
   hint at all, which is the same hint everyone had before they tried. */
.hero h1 .wm-i { cursor: pointer; }
.hero h1 .ini { color: var(--hero-ink); font-weight: 800; }
.hero h1 .sky { color: var(--hero-sky); font-weight: 800; }
.hero .sub { color: var(--hero-ink-2); margin: 0 0 18px; font-size: 1rem; }
.hero-stats { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; padding: 0; list-style: none; }
/* Dark glass, not white: these chips used to borrow their contrast from the
   scrim, which fades to nothing at the photo's foot — once they moved down
   there, white-on-white sat them on pale scree and vanished. Tinting with the
   scrim colour keeps them legible over whatever the picture puts behind them,
   and follows the theme for free. */
.hero-stats li {
  background: rgba(var(--scrim), .46); border: 1px solid rgba(255, 255, 255, .26);
  border-radius: 999px; padding: 4px 13px; font-size: .86rem;
  font-variant-numeric: tabular-nums;
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  text-shadow: 0 1px 3px rgba(var(--scrim), .6);
}
.hero .hint { color: var(--hero-ink-2); font-size: .84rem; margin: -2px 0 16px; }
.dl-all {
  display: inline-block; background: #ffffff; color: var(--accent-deep);
  padding: 11px 20px; border-radius: 12px; text-decoration: none; font-weight: 700;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
}
/* Photo-first header: the photograph runs uncovered and every word moves below
   it, set in page ink. No text on the photo means no scrim — the gradient
   existed to hold up type, and type that isn't there needs no holding. */
/* The banner takes each photograph's own proportions (aspect-ratio arrives
   inline per trip), so panoramas show whole instead of being cropped to a
   window sized by text that no longer lives there.
   Past the cap it used to crop, and cropping is what took the summit off Ama
   Dablam and the head off a figure on 玉山主峰. Moving the crop only chooses
   which end to lose — MG: 與其上下移動，整體縮小讓山體更清楚而且露出全照才是
   對的. So the photograph is contained instead, whole at any width, and the
   colour beside it is faded into rather than butted against, the way the foot
   of the banner already melts into the page.
   Under the cap nothing changes: the box takes the photo's own ratio, contain
   and cover agree, and the fade (as wide as the picture) falls outside the box
   and paints nothing.
   min-height: 0 unseats the floor .hero.has-photo needed back when its
   height was whatever the overlaid text added up to (LESSONS #90). */
.hero.bare {
  /* Named because the fade has to know it: a contained photograph is this
     height times its own ratio, and a gradient must be given that width in so
     many words. Same reasoning as --hero-h on the index. */
  --bare-h: min(62vh, 460px);
  min-height: 0; max-height: var(--bare-h);
  background-size: contain; background-repeat: no-repeat;
  /* width must be pinned: with aspect-ratio set, a max-height clamp makes the
     browser derive width FROM height, and the banner shrank off the right
     edge of a desktop window. Pinning width keeps the ratio driving height
     only, and past the cap the photo simply crops like before. */
  width: 100%;
}
.hero.bare::before { content: none; }  /* scrim held up text; no text now */
.hero.bare::after { content: none; }   /* hard edge — a fade eats the photo's foot */
.trip-head { max-width: 960px; margin: 0 auto; padding: 14px 16px 0; }
.trip-head .hint:first-child { margin: 0 0 12px; }
/* An aside, not a banner: accent ink and a hairline rule, both theme tokens.
   Whatever seasonal feeling it carries has to come from the words (and an
   emoji, which paints itself) — a hardcoded festive red or green would look
   wrong the moment the theme moved, which is exactly how the rest-day green
   broke against the dark theme's green-black (LESSONS #15). */
.headnote {
  margin: -4px 0 14px; padding-left: 11px; font-size: .88rem;
  color: var(--accent); border-left: 2px solid var(--accent);
}
/* A headnote may run to two lines when the trip has earned the room — the
   greeting leads, the fact that makes it true settles underneath. Both are
   block-level spans so the field stays a single trusted string. */
.headnote-lead, .headnote-fact { display: block; }
.headnote-lead { font-size: 1.02rem; font-weight: 600; letter-spacing: .01em; }
.headnote-fact { margin-top: 2px; font-size: .82rem; opacity: .82; }
/* Which hundred-peaks this trip bagged, and the standard routes they belong
   to. Surface tokens, not the card badge's dark scrim glass: this line sits
   on the page, and the photo-first header dresses everything in page ink. */
.trip-peaks {
  margin: 0 0 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
}
.peak-tag {
  padding: 2px 9px; border-radius: 999px; font-size: .76rem; font-weight: 600;
  color: var(--accent); background: var(--surface); border: 1px solid var(--line);
}
.peak-names { font-size: .82rem; color: var(--muted); }
/* Walked or planned. Nothing in .trip-peaks competes on specificity, so a
   single class is enough here — unlike the card, below. */
.route-kind {
  /* .8125rem = 13 px at the default size: the floor for small text an older
     reader still reads (review 2026-10-06); rem so the AA control scales it. */
  padding: 2px 9px; border-radius: 999px; font-size: .8125rem; font-weight: 600;
  color: var(--muted); background: var(--surface); border: 1px solid var(--line);
}
/* Plain accent on the page was 4.47:1 in light. The text takes the deeper
   accent-2 there (6.4:1); dark keeps accent (6.14:1), since its accent-2 is
   the darker one (3.2:1). --accent itself is untouched and the dashed border
   keeps it in both themes. */
.route-kind.planned {
  color: var(--accent-2); border-style: dashed; border-color: var(--accent);
  background: transparent;
}
:root[data-theme="dark"] .route-kind.planned { color: var(--accent); }
/* The group this trip went (or goes) with, and its LINE/Instagram/Facebook
   (pipeline/groups.py, MG 2026-09-14). Theme tokens only (LESSONS #15); the
   name may wrap at 320 px, never the page; each link is a 44 px target
   (Codex D005). */
.group-chip {
  display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; max-width: 100%;
  padding: 2px 3px 2px 10px; border-radius: 18px; font-size: .8rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--accent);
}
.group-name { font-weight: 600; overflow-wrap: anywhere; }
.group-link {
  display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.group-link svg { width: 22px; height: 22px; display: block; }
.group-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .group-link:hover { background: var(--accent); color: var(--surface); }
}
/* The letter carries the grade on its own. Colour-coding A→C+ would cost a
   hardcoded palette (LESSONS #15) and, worse, would be read as red=danger —
   a claim the catalogue never makes. No nowrap here either: the page's own
   AA control enlarges this text, and a pinned line overflows once it does
   (LESSONS #93). */
.peak-grade {
  margin-left: 3px; font-style: normal;
  font-size: .8125rem; font-weight: 600; color: var(--accent); opacity: .75;
}
.peak-legend { font-size: .8125rem; color: var(--muted); opacity: .7; }
/* A photoless trip puts this line on the accent gradient, where page ink
   (muted, accent, faded) drops to 1.4-2:1. Hero ink instead, at full opacity;
   the grade keeps full ink against the name's second level. */
.hero .peak-names { color: var(--hero-ink-2); }
.hero .peak-grade { color: var(--hero-ink); opacity: 1; }
.hero .peak-legend { color: var(--hero-ink-2); opacity: 1; }
/* Keeps a short phrase and its emoji from being split across lines — a lone
   🎄 orphaned onto its own row read as a rendering fault, not a flourish. */
.nb { white-space: nowrap; }
.hero .headnote {
  color: var(--hero-ink-2); border-left-color: rgba(255, 255, 255, .4);
}
/* The initials Taiwanese hikers actually say — TMB, EBC — hold full ink while
   the rest of the letters ease back. Colour has to carry that on its own: the
   weight below asks for 800 against an h1 already bold at 700, and system-ui
   has no 800 face on most platforms, so it resolves to no difference at all.
   72% left only 2.4:1 between the two inks and the effect did not read. 60%
   gives 3.5:1, and the title is large text, so it still sits at 4.5:1 against
   the page where 3:1 is the bar. */
.trip-head h1 {
  font-size: 1.65rem; margin: 0 0 4px; letter-spacing: .01em;
  color: color-mix(in srgb, var(--ink) 60%, transparent);
}
.trip-head h1 .ini { color: var(--ink); font-weight: 800; }
.trip-head .sub { color: var(--ink-2); margin: 0 0 6px; font-size: 1rem; }
.trip-head .hint { color: var(--muted); font-size: .84rem; margin: 0 0 14px; }
/* On the page the chips and control discs wear surface tokens — the scrim
   glass and white frost were costumes for standing on a photograph. */
.trip-head .hero-stats { margin: 0 0 14px; }
.trip-head .hero-stats li {
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-2);
  text-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: var(--shadow);
}
.trip-head .hero-actions { margin-bottom: 4px; }
.trip-head .hero-links a, .trip-head .hero-links button {
  color: var(--ink-2); background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow); -webkit-backdrop-filter: none; backdrop-filter: none;
}
@media (hover: hover) and (pointer: fine) {
  .trip-head .hero-links a:hover, .trip-head .hero-links button:hover {
    background: var(--surface); color: var(--ink); transform: translateY(-2px);
  }
}
.trip-head .hero-links a:focus-visible, .trip-head .hero-links button:focus-visible {
  outline: 2px solid var(--accent); box-shadow: none;
}
.trip-head .dl-all { background: var(--accent); color: #fff; }
.ridge { position: absolute; left: 0; right: 0; bottom: -1px; width: 100%; height: 150px; display: block; z-index: 0; }
/* Cards */
.wrap { max-width: 960px; margin: 0 auto; padding: 0 16px 48px; }
.legend { color: var(--ink-2); font-size: .8rem; margin: 0 0 12px; }
/* Safety notice: uses the hazard tokens already in the palette, so it reads as
   the same family as the per-day caution badges. */
.notice {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--badge-bg); color: var(--badge-ink);
  border-radius: 12px; padding: 12px 14px; margin: 16px 0 14px;
  font-size: .87rem; line-height: 1.62;
}
.notice svg { flex: none; width: 1.2em; height: 1.2em; margin-top: .18em; }
/* The guide page's three hard sentences — download the maps first, update
   before importing, follow the blue line — reuse the trip pages' notice tint
   rather than inventing a warning look. A reader arriving from a trip page has
   already learnt what that colour means there. */
.ofl-warn {
  background: var(--badge-bg); color: var(--badge-ink);
  border-radius: 12px; padding: 10px 14px; margin: 12px 0;
  font-size: .92rem; line-height: 1.7;
}
.ofl h2 { margin: 1.6em 0 .5em; }
.ofl h2.ofl-h-warn { color: var(--badge-ink); }
.ofl ul { padding-left: 1.4em; }
.ofl li { margin: .45em 0; }
.notice p { margin: 0; }
/* The body is one flex child so lead/list/tail stack instead of sitting in a row. */
/* The notices quote OSM tags -- demanding_alpine_hiking is 23 characters with
   no break opportunity, and at xl on a 320 px screen it is wider than the
   203 px it has to live in, so 羊畢羊's page scrolled sideways. break-word
   rather than anywhere: it only splits a word that would otherwise overflow,
   and leaves min-content sizing alone (2026-09-10). */
.notice-body { min-width: 0; overflow-wrap: break-word; }
.notice-points { margin: .5em 0 0; padding-left: 1.5em; }
.notice-points li { margin: .32em 0; }
.notice-points + p { margin-top: .55em; }
/* Notes, not warnings — no icon, no tinted panel, so the caution box above
   keeps its weight. */
.fieldnotes {
  margin: 0 0 16px; padding: 14px 16px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px;
}
.fieldnotes h2 { font-size: 1rem; margin: 0 0 6px; color: var(--ink); }
.fieldnotes h3 {
  font-size: .88rem; margin: 12px 0 4px; color: var(--accent); font-weight: 700;
}
.fieldnotes .fn-lead { margin: 0; font-size: .9rem; color: var(--ink-2); line-height: 1.75; }
.fieldnotes ul { margin: 0; padding-left: 1.3em; }
.fieldnotes li { margin: .3em 0; font-size: .9rem; color: var(--ink-2); line-height: 1.75; }
.howto { margin: 0 0 14px; font-size: .85rem; color: var(--ink-2); }
.howto summary {
  cursor: pointer; color: var(--accent); font-weight: 600;
  list-style-position: inside;
}
.howto p { margin: 8px 0 0 4px; line-height: 1.66; }
.wrap.flow .legend { padding-top: 4px; }
.grid { display: grid; gap: 18px; grid-template-columns: 1fr; position: relative; z-index: 2; }
@media (min-width: 768px) { .grid { grid-template-columns: 1fr 1fr; } }
/* The whole-trip card spans the pair. Two columns' worth is what MG asked for —
   以電腦版本的寬度就是 2 倍小卡片的大小 — and it is also what the picture needs:
   a fourteen-day profile squeezed into one column stops being a shape. */
@media (min-width: 768px) { .card-trip { grid-column: 1 / -1; } }
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  padding: 16px; display: flex; flex-direction: column; gap: 10px;
  box-shadow: var(--shadow); min-width: 0;
}
@media (hover: hover) and (pointer: fine) {
  .card { transition: transform .15s ease, box-shadow .15s ease; }
  .card:hover { transform: translateY(-3px);
    box-shadow: 0 4px 8px rgba(16, 38, 74, .09), 0 14px 34px rgba(16, 38, 74, .13); }
}
/* The day card folds (MG 2026-09-09 「全部的日子只有一行…我可以自由決定要不要
   展開」): the summary carries D-number, date, km, climb, the day's 上河／同段實走
   figures and the station chain, so a trip's shape reads in one screen and the
   pictures, tables and diagram come on demand. */
.day-fold { padding: 0; gap: 0; }
.day-fold > details > summary { cursor: pointer; padding: 14px 16px; display: flex;
  flex-direction: column; gap: 14px; list-style: none; }
.day-fold > details > summary::-webkit-details-marker { display: none; }
.day-fold > details[open] > summary { border-bottom: 1px solid var(--line); }
.day-fold > details > *:not(summary) { margin: 10px 16px 0; }
.day-fold > details > *:last-child { margin-bottom: 16px; }
.day-fold > details > p.chips, .day-fold > details > p.water, .day-fold > details > p.daypos,
.day-fold > details > .thumb-wrap, .day-fold > details > p.card-links { margin-top: 22px; }
.day-fold > details > .legs-wrap { margin-top: 22px; }
.sum-top { display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap; }
/* the badge is its own row under the two times: a day card is one day wide,
   so the rows never need to compete for space (MG 2026-09-09) */
.day-fold > details > summary > .badge { align-self: flex-start; }
.sum-meta { color: var(--ink-2); font-size: .85rem; font-variant-numeric: tabular-nums; }
.sum-route { font-weight: 600; line-height: 1.45; }
.day-fold .sum-route { font-size: 1.06rem; line-height: 1.7; }
.sum-sr { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.day-fold .sum-sr { gap: 10px; }
.day-fold summary .badge { font-size: .85rem; line-height: 1.6; padding: 4px 12px; }
.sum-sr .chip { font-size: .9rem; padding: 3px 12px; }
.sum-sr .lg-book { border-color: var(--accent); color: var(--accent); }
.sum-sr .lg-me { margin-left: 0; }
/* One pill on the right edge that opens or closes every day (MG 2026-09-09).
   The word is the point: two bare chevron circles read as scroll-to-top and
   scroll-to-bottom. Fixed, so it is there after scrolling; hidden in print. */
.fold-rail { position: fixed; z-index: 5;
  display: flex; flex-direction: column; align-items: stretch; gap: 8px;
  left: 50%; transform: translateX(-50%);
  top: calc(8px + env(safe-area-inset-top, 0px)); }
.fold-rail[hidden], .fold-toggle[hidden] { display: none; }
/* On a phone the right edge is where the diagram prints its own minutes and
   the bottom is where the station chain runs, so the pill rides the top edge
   instead (MG 2026-09-09). Wide enough and it moves to the right margin,
   clear of the content column. */
@media (min-width: 560px) {
  .fold-rail { left: auto; right: 12px; top: 50%; transform: translateY(-50%); }
}
.fold-toggle { display: flex; align-items: center; gap: 7px; padding: 8px 14px 8px 11px;
  border-radius: 999px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--shadow); cursor: pointer;
  font: inherit; font-size: .85rem; line-height: 1; white-space: nowrap;
  transition: background .16s ease, color .16s ease, transform .16s ease; }
@media (hover: hover) and (pointer: fine) {
  .fold-toggle:hover { background: var(--accent); color: #000; transform: translateY(-1px); }
}
.fold-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the same ＋／－ the folds use, so one vocabulary across the page */
.fold-ico { display: grid; place-items: center; width: 22px; height: 22px; flex: none;
  border-radius: 50%; border: 1px solid var(--accent); color: var(--accent);
  font-size: 13px; line-height: 1; }
.fold-ico > span { grid-area: 1 / 1; }
.fold-toggle[aria-expanded="false"] .fold-ico > span:last-child,
.fold-toggle[aria-expanded="true"] .fold-ico > span:first-child { display: none; }
.pins-toggle .fold-ico { color: var(--ink); border-color: var(--ink); }
.pins-toggle .fold-ico svg { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .fold-toggle:hover .fold-ico { border-color: currentColor; }
  .pins-toggle:hover .fold-ico { color: inherit; }
}
@media print { .fold-rail { display: none; } }
/* Phone + day bar (MG 2026-10-06, mock B): controls.js moves the rail into
   the left end of .daybar below 560px, so the pills cover nothing the bar
   does not. Sticky there, the D pills scroll sideways under it. The negative
   margins and left -8px eat the bar's padding, so it fills the bar's height
   and starts at its edge; the right end is the bar's fade, never here. */
.daybar > .fold-rail.in-bar { position: sticky; left: -8px; top: auto; z-index: 1;
  transform: none; flex: none; align-self: stretch;
  flex-direction: row; align-items: center; gap: 6px;
  margin: -7px 0 -7px -8px; padding: 7px 8px;
  background: var(--page); border-right: 1px solid var(--line); }
.in-bar .fold-toggle { box-shadow: none; padding: 3px 10px 3px 4px; font-size: .85rem; gap: 5px; }
.in-bar .fold-ico { width: 20px; height: 20px; }
.in-bar .pins-toggle { padding: 3px; }
/* icon only: the words are the button's aria-label and title (controls.js) */
.in-bar .pins-toggle .fold-label { display: none; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
/* Bigger and in full ink, rather than a chip, an accent tint or an underline.
   MG chose it from five: 加大全墨. The card already carries a map frame, a
   profile baseline and a row of chip borders, so an underline would have been
   a fourth kind of line, and the accent on this site means "you can tap this",
   which this cannot. Size and weight add no new vocabulary at all.
   MG: 總結卡片的標題我想要再更大一點 — 1.6rem, one clear step up from 1.18 and
   still well under the page heading's 2.2rem, which the next step up started
   competing with. */
.trip-name {
  font-weight: 800; color: var(--ink); font-size: 1.6rem; margin-left: auto;
  min-width: 0; overflow-wrap: anywhere;
}
.card h2 {
  font-size: 1.05rem; margin: 0; display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap; min-width: 0;
}
.dnum {
  background: linear-gradient(150deg, var(--accent-deep), var(--accent));
  color: #fff; border-radius: 9px; padding: 3px 9px; font-size: .95rem; letter-spacing: .02em;
}
.dnum.rest-num { background: var(--rest-chip); color: #fff; }
.card .date { color: var(--muted); font-weight: 400; font-size: .88rem; overflow-wrap: anywhere; }
.route { margin: 0; color: var(--ink); font-weight: 650; }
.badge {
  background: var(--badge-bg); color: var(--badge-ink);
  font-size: .75rem; padding: 3px 9px; border-radius: 999px;
  max-width: 100%; overflow-wrap: anywhere;
}
.badge.calm { background: var(--rest-bg); color: var(--rest-ink); }
.thumb {
  width: 100%; height: auto; border-radius: 12px;
}
/* The summit and hut icons ride over the thumbnail as vector, in the picture's
   own pixel coordinates. .thumb is width:100%/height:auto with no object-fit,
   so the image never crops and a percentage overlay registers exactly. */
.thumb-wrap { position: relative; display: block; }
.thumb-wrap .pins {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; opacity: .55;
}
.pin-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Off is stamped on the root before first paint, so a reader who turned the
   icons off never sees them flash on the way in. */
:root[data-pins="off"] .thumb-wrap .pins { display: none; }
/* The button says which state it is in by which glyph it shows, the way the
   theme toggle does. Colour alone could not: --muted and --ink-2 sit almost on
   top of each other on paper, and MG read the two states as the same button. */
.pins-toggle .i-pins-off { display: none; }
:root[data-pins="off"] .pins-toggle .i-pins-on { display: none; }
:root[data-pins="off"] .pins-toggle .i-pins-off { display: block; }
/* Fallback popover for browsers with no navigator.share (desktop Safari/
   Firefox, and desktop generally as of 2026-09-06): a small menu anchored
   under (or over, if there is no room) the share button by JS-computed
   `left`/`top` -- not a full-screen sheet, so it does not cover the article
   underneath it. No backdrop; outside click/Esc/scroll close it instead. */
.share-sheet {
  position: fixed; z-index: 90; width: max-content; max-width: 260px;
  display: flex; flex-direction: column; gap: 4px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 12px; padding: 6px 6px max(6px, env(safe-area-inset-bottom));
  box-shadow: var(--shadow);
}
.share-sheet-item {
  display: block; width: 100%; margin: 0; padding: 10px 14px;
  text-align: center; font: inherit; font-size: 16px; border: none; border-radius: 8px;
  background: transparent; color: var(--ink);
  text-decoration: none; cursor: pointer;
}
.share-sheet-item:focus-visible {
  background: var(--page); outline: none;
}
@media (hover: hover) and (pointer: fine) {
  .share-sheet-item:hover { background: var(--page); outline: none; }
}
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.day-fold p.chips { gap: 10px; }
.chip {
  background: var(--page); border: 1px solid var(--line); border-radius: 999px;
  padding: 2px 10px; font-size: .82rem; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
/* Water row inside the day fold (docs/PLAN-WATER.md). Small wrapping line:
   at 320 px the long km/name/status strings must break, never grow a
   horizontal scrollbar. Dots are high-sat blue (stable) / orange (unstable)
   so both the warm-paper light theme and the green-black dark theme keep
   them. .water-badge shares .badge. */
.water {
  font-size: .9rem; color: var(--ink-2); line-height: 1.85; margin: 0;
  overflow-wrap: anywhere; word-break: break-word;
}
.water-h { font-weight: 650; color: var(--ink); }
.water .water-h { display: block; margin-bottom: 4px; }
.wpt { font-variant-numeric: tabular-nums; }
.water .wpt { display: block; padding-left: 1.1em; text-indent: -1.1em; }
.wpt::before {
  content: ""; display: inline-block; width: .5em; height: .5em;
  margin-right: .28em; border-radius: 50%; vertical-align: .1em;
  background: #1876f2;
}
.wpt.w-stable::before { background: #1876f2; }
.wpt.w-unstable::before { background: #f26b1f; }
:root[data-theme="dark"] .wpt.w-stable::before { background: #4ea3ff; }
:root[data-theme="dark"] .wpt.w-unstable::before { background: #ff8a3d; }
.dl {
  align-self: flex-start; background: linear-gradient(150deg, var(--accent), var(--accent-2));
  color: var(--accent-ink); padding: 9px 18px; border-radius: 11px;
  text-decoration: none; font-weight: 650; font-size: .95rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .22);
}
/* Two links, not two buttons stacked: the GPX is what most readers came for,
   the marks are for the one who wants to see the place. */
.card-links { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* Legs (docs/PLAN-TIMETABLE.md, MG layout C 2026-09-08): guidebook minutes as
   chips, one line per leg, wrapping; the recording folded in <details>. */
.legs-wrap { margin: 10px 0 0; }
.lg-head { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 4px; }
.lg-head .lg-me { margin-left: auto; }  /* 我的實走 stays right even when 上河 has nothing to say (北二段, MG 2026-09-08) */
table.fold { width: 100%; border-collapse: collapse; font-size: .86rem; font-variant-numeric: tabular-nums; margin-top: 4px; }
table.fold th, table.fold td { padding: 6px 4px; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
table.fold th:first-child, table.fold td:first-child { text-align: left; white-space: normal; font-weight: 600; overflow-wrap: anywhere; }
table.fold thead th { color: var(--ink-2); font-weight: 400; border-bottom-color: var(--ink-2); }
.lg { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; min-width: 0; }
.lg-arrow { color: var(--ink-2); font-size: .85rem; }
.lg-to { font-weight: 600; flex: 1 1 8em; min-width: 0; overflow-wrap: anywhere; }
.lg-via { flex-basis: 100%; color: var(--ink-2); font-size: .8rem; overflow-wrap: anywhere; }
.lg .chip { font-size: .8rem; padding: 2px 9px; }
.lg-book { color: var(--accent); }
.lg-dim { color: var(--ink-2); }
.lg-facts { margin: 2px 0 0 1.2em; color: var(--ink-2); font-size: .82rem; overflow-wrap: anywhere; }
.chain { margin: 4px auto 0; font-size: 13px; }
.chain .ch-box { fill: var(--surface); stroke: var(--accent); stroke-width: 1.2; }
.chain .ch-name { fill: var(--ink); font-weight: 600; }
.chain .ch-line { stroke: var(--ink-2); stroke-width: 2; }
.chain .ch-arrow { fill: var(--ink-2); }
.chain .ch-book { fill: var(--accent); }
.chain .ch-via { fill: var(--ink-2); font-size: 11px; }
.chain .ch-mine { fill: var(--ink); }
.chain .ch-ratio { fill: var(--ink-2); font-size: 11px; }
.chain .ch-head { font-weight: 700; }
/* Every fold on the site says so: a chevron before the summary (MG 2026-09-08
   前面多個箭頭才知道可以打開). The status panel's 「展開全文」 keeps its own. */
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }
/* A circled ＋／－ at the START of the heading, not a small triangle and not
   at the far right: MG's own user testing (2026-09-09) found hikers did not
   know 「下載後怎麼匯入地圖 App？」 could be opened -- they read it as a heading
   with nothing after it -- and a control parked at the right edge is found
   only after the line has already been read past. A circle is the shape
   people recognise as a control, and it doubles as the state (＋ closed,
   － open). */
details > summary::before { content: "＋"; display: inline-grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--accent);
  color: var(--accent); font-size: 13px; line-height: 1; vertical-align: middle;
  margin-right: 8px; position: relative; top: -1px; background: color-mix(in srgb, var(--accent) 10%, transparent);
  transition: background .16s ease, color .16s ease; }
details[open] > summary::before { content: "－"; }
@media (hover: hover) and (pointer: fine) {
  details > summary:hover::before { background: var(--accent); color: var(--surface); }
}
/* The day card's summary is a column of rows, so an inline pseudo would take
   a row of its own: pin it to the first row instead. */
.day-fold > details > summary { position: relative; padding-left: 46px; }
.day-fold > details > summary::before { position: absolute; left: 14px; top: 17px; margin: 0; }  /* centred on the D-badge (14 + 30/2 - 24/2) */
@media (min-width: 560px) { .day-fold > details > summary { padding-left: 52px; } }
.st-more > summary::before { content: none; }
/* the fold sits on the card's floor whatever the diagram's height */
.legs-wrap { display: flex; flex-direction: column; flex: 1; }
.legs-mine { margin-top: auto; padding-top: 8px; }
.legs-mine summary { cursor: pointer; color: var(--accent); font-size: .9rem; display: flex; gap: 8px; align-items: center; }
/* The replay is a doorway, not a download: same weight as the marks link on a
   card, a full-width tap target at the head of a marks page. */
.mk-replay-row { margin: 14px 0 18px; }
.mk-replay { display: inline-block; padding: 10px 18px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink); text-decoration: none;
  font-weight: 700; }
/* Its own class, not a variant of .dl: the download toast binds to a.dl, and a
   class that says "this saves a file" attached to a link that navigates is a
   lie the script believed. In an in-app browser it went further and cancelled
   the click, so inside LINE the marks page could not be opened at all. */
.card-link {
  align-self: flex-start; padding: 9px 18px; border-radius: 11px;
  text-decoration: none; font-weight: 600; font-size: .95rem;
  color: var(--accent); border: 1px solid var(--line); background: none;
}
@media (hover: hover) and (pointer: fine) {
  .card-link:hover { background: var(--page); }
}

/* The marks page. Its own body class rather than the trip page's shell: there
   is no hero here, and a reader arrives from one day's card and leaves back to
   it, so the page is a detour and should not dress like a destination. */
.marks-body { background: var(--page); }
.marks-wrap { max-width: 680px; margin: 0 auto; padding: 16px 16px 40px; }
/* A planned day owes the reader its sources before its numbers. */
.mk-plan-lead {
  margin: 0 0 16px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-2); font-size: .86rem; line-height: 1.65;
}
.mk-back {
  display: inline-block; color: var(--accent); text-decoration: none;
  font-size: .95rem; font-weight: 600; padding: 6px 0;
}
/* Wide screens stop enlarging the picture. The photographs that come out of
   the recorder are 1080 on the long side, so a portrait one is 608 wide — and
   the column was 928, which meant every one of them was being blown up by half
   to fill it. That is where the softness on a desktop came from, not from the
   encoder. Phones are untouched: at 358px they never enlarged anything. */
@media (min-width: 960px) {
  /* Not two columns. The picture sits in the middle of the column with its
     numbers under it, the way they are on a phone — MG: 照片放正中間,
     海拔圖在照片下是最好看的. Side by side, whatever width the picture did not
     take became the width of everything else, so the profile — the same line
     every time, only the red dot moving — came out 330px wide under a portrait
     and 145px under a landscape, with the distance wrapping. A cap on the
     height is all a wide screen needs: nothing is enlarged past the 608px it
     actually is, and the mark still shortens enough to read several at once.

     890, because the number that matters is what a retina screen is handed.
     Nine of ten photographs here are 9:16, so this cap makes them 500 CSS px
     wide — 1000 device pixels on the 2x screen MG reads on, against a file
     that is 900. An eleven per cent enlargement; the export's 608px copies
     were being stretched by forty-eight, which is where the softness was.
     Going wider than this means adding a third size, not moving this number. */
  .mk-row .mk-shots img {
    max-height: 890px; width: auto; max-width: 100%; height: auto;
    margin-left: auto; margin-right: auto;
  }
}

/* Between days, at the foot of the page, where finishing one lands you.
   Stacked on a phone so a forty-character day title gets a whole line to
   itself; two across only where there is room for two. Whole block is the
   target, not the words inside it. */
.mk-steps { display: grid; gap: 10px; margin: 26px 0 6px; }
.mk-step {
  display: block; padding: 12px 14px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--line);
  text-decoration: none; color: var(--ink);
}
.mk-step.next { text-align: right; }
.mk-step-dir { display: block; color: var(--muted); font-size: .8rem; }
.mk-step-name { display: block; margin-top: 3px; font-size: .95rem; line-height: 1.5; }
.mk-step-name b { font-variant-numeric: tabular-nums; margin-right: 7px; }
@media (min-width: 960px) {
  .mk-steps { grid-template-columns: 1fr 1fr; }
  /* Named rather than auto-placed: on the first day there is no 上一天, and
     without this the lone 下一天 would sit in the left half and point the
     wrong way. */
  .mk-step.next { grid-column: 2; }
}
@media (hover: hover) and (pointer: fine) {
  .mk-step:hover { border-color: var(--accent); }
}
/* The opening line sits above the first mark rather than below the last, so
   its spacing is the finish's turned around. */
.mk-start { margin: 0 0 4px; }
@media (hover: hover) and (pointer: fine) {
  .mk-back:hover { text-decoration: underline; }
}
/* A marks page is often the only page someone is handed, so it carries the
   same credit and licence the trip page does. */
.mk-foot { margin-top: 26px; }
/* Wraps so the seven controls drop to their own line instead of off the page.
   They need 314 px whatever the screen, and at 320 the bar has 288 -- the trip
   page's own .hero-actions already wraps for exactly this, the mark page's bar
   did not, and it hung 22 px past the right edge on origin/main. Wrapping the
   BAR, not .hero-links: giving the control row itself flex-wrap makes it
   shrink to its share of the row and break into two lines at 360 and 390 too,
   which is the phone width most readers are on (measured 2026-09-10). */
.mk-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 2px; flex-wrap: wrap;
}
.mk-crumb {
  min-width: 0; font-size: .86rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mk-crumb a { color: var(--accent); text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .mk-crumb a:hover { text-decoration: underline; }
}
.mk-crumb span { margin: 0 6px; color: var(--muted); opacity: .7; }
.mk-crumb b { color: var(--ink-2); font-weight: 600; }
/* On a trip page the crumb sits under the photograph and over its caption,
   so it needs its own breathing room rather than the marks page's tight bar. */
.tp-crumb { margin: 2px 0 10px; }
.marks-body .hero-links a, .marks-body .hero-links button {
  color: var(--ink-2); background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow); -webkit-backdrop-filter: none; backdrop-filter: none;
}
@media (hover: hover) and (pointer: fine) {
  .marks-body .hero-links a:hover, .marks-body .hero-links button:hover {
    background: var(--surface); color: var(--ink); transform: translateY(-2px);
  }
}
.marks-body .hero-links a:focus-visible, .marks-body .hero-links button:focus-visible {
  outline: 2px solid var(--accent); box-shadow: none;
}
/* The trip's name, then the day. MG: 行程倒是不用玩花招但至少要清楚可辨識 —
   so no initial-letter treatment here, just the name at full ink. */
.mk-title { font-size: 1.4rem; margin: 10px 0 2px; color: var(--ink); line-height: 1.3; }
/* This page is the thing, not a day within a trip, so its heading is
   sized like one. MG: 標題的「把每天的 GPX 帶上山」要粗體放大. */
.ofl .mk-title { font-size: 2rem; font-weight: 800; margin: 14px 0 6px; }
.ofl .mk-sub { font-size: .95rem; }
@media (min-width: 700px) { .ofl .mk-title { font-size: 2.4rem; } }
.mk-sub { color: var(--muted); font-size: .88rem; margin: 0 0 14px; }
/* The overview and the walk are two different things and were running into
   each other. The map keeps a caption saying what it is; the list gets a
   heading and a rule, so the page reads as a map, then a walk. */
.mk-map-fig { margin: 0 0 4px; }
.mk-map {
  width: 100%; height: auto; display: block; border-radius: 12px;
  background: var(--surface);
}
.mk-map-fig figcaption {
  color: var(--muted); font-size: .8rem; padding: 6px 2px 0;
}
.mk-sec {
  font-size: 1.08rem; color: var(--ink); font-weight: 750;
  margin: 24px 0 16px; padding-top: 18px; border-top: 1px solid var(--line);
  letter-spacing: .01em;
}
/* The way back. The prose links down to a photograph; without this the reader
   has to find their place in the text again by scrolling. Quiet enough to sit
   beside a name without competing with it. */
.mk-ref {
  margin-left: 8px; font-size: .76rem; font-weight: 400; white-space: nowrap;
  color: var(--muted); text-decoration: none; vertical-align: 2px;
}
.mk-ref::before { content: "↑ "; }
@media (hover: hover) and (pointer: fine) {
  .mk-ref:hover { color: var(--accent); }
}
/* His words, set as prose rather than as bullets: the notice up on the trip
   page is the distilled report a walker reads before deciding to go, and this
   is the account of having gone. Reading measure a little narrower than the
   photographs, which want the full width. */
.mk-prose p { margin: 0 0 14px; color: var(--ink); line-height: 1.85; }
.mk-prose p:last-child { margin-bottom: 4px; }
.mk-prose a {
  color: var(--accent); text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  .mk-prose a:hover { border-bottom-color: var(--accent); }
}
.mk-prose ul { margin: 0 0 14px; padding-left: 1.4em; }
.mk-prose li { margin: .25em 0; color: var(--ink); line-height: 1.7; }
/* A picture standing between two paragraphs, not after the article. It needs
   air on both sides for that to read as deliberate rather than as the previous
   paragraph's illustration. */
.mk-prose-fig { margin: 16px 0 18px; }
/* The trip's last word, on the last day that has a page. Set apart, because it
   is not about that day. */
.mk-close {
  margin: 26px 0 18px; padding-top: 18px; border-top: 1px solid var(--line);
  color: var(--ink-2);
}
.mk-close p { margin: 0 0 10px; line-height: 1.85; }
.mk-close-fig { margin: 14px 0 0; }
.mk-close-fig img { width: 100%; height: auto; display: block; border-radius: 10px; }
.mk-close-fig figcaption { color: var(--muted); font-size: .8rem; padding: 6px 2px 0; }
/* A photograph belonging to the day's writing rather than to a mark — it sits
   under the prose it illustrates, captioned with when it was actually taken. */
.mk-day-fig { margin: 0 0 4px; }
/* Sits under the closing line, so it needs the room above that the prose
   illustration does not. */
.mk-fin-fig { margin-top: 12px; }
.mk-day-fig img { width: 100%; height: auto; display: block; border-radius: 10px; }
.mk-day-fig figcaption { color: var(--muted); font-size: .8rem; padding: 6px 2px 0; }
.mk-fin {
  margin: -14px 0 8px; text-align: center; color: var(--muted);
  font-size: .82rem; font-variant-numeric: tabular-nums;
}
.mk-fin span { margin-right: 6px; }
/* With a stretch drawn above it the line is part of the walk, so it drops the
   pull-up that tucks a bare footnote under the mark before it. */
.mk-fin.walked { margin: 0 0 8px; }
/* Someone else's photograph of the same spot, so it carries a caption where
   the mark's own pictures need none — the mark is their caption. */
.mk-extra { margin: 0; }
.mk-extra figcaption { color: var(--muted); font-size: .8rem; padding: 5px 2px 2px; }
/* No rail and no node beside each photograph. They were tried and they cost
   20px of width off every picture to draw a thread the interval line already
   makes — MG: 不如直接連起來或乾脆不要，圖片可以更大. The forward motion is in
   the words in the gap and in the profile filling behind the walker. */
/* Evidence beside the claim. Kept small — the same photograph appears at full
   size further down, so this one only has to show that the pond is really
   there. Side by side when a paragraph names more than one; that happens in
   sixteen paragraphs across the site. */
.mk-inline {
  display: flex; flex-wrap: wrap; gap: 12px; margin: 4px 0 16px;
  justify-content: center;
}
/* Bounded by height, not width, so a portrait and a landscape citing the same
   paragraph come out the same size on the page. Capped at 320 wide a portrait
   stood 570 tall — taller than the sentence it was supporting, which is the
   opposite of a footnote. */
.mk-cite { margin: 0; }
.mk-cite img {
  max-height: 300px; max-width: 100%; width: auto; height: auto;
  display: block; margin: 0 auto; border-radius: 10px; background: var(--surface);
}
.mk-cite figcaption {
  margin-top: 4px; color: var(--muted); font-size: .78rem; text-align: center;
}
.mk-list { list-style: none; margin: 0; padding: 0; }
.mk { margin: 0 0 30px; scroll-margin-top: 12px; }
.mk-gap {
  margin: -16px 0 16px; color: var(--ink-2); text-align: center;
  font-size: .82rem; font-variant-numeric: tabular-nums;
}
.mk-gap span { color: var(--muted); margin-right: 3px; }
/* <picture> is inline by default, which would leave it wrapping a block-level
   image; making it block keeps the box the same shape it was before the second
   size existed. */
.mk picture { display: block; }
.mk img {
  width: 100%; height: auto; display: block; border-radius: 10px;
  background: var(--surface); margin: 0 0 2px;
}
.mk-head { margin: 8px 0 0; font-size: 1rem; }
.mk-n { color: var(--muted); font-size: .82rem; font-variant-numeric: tabular-nums; }
.mk-name { font-weight: 650; color: var(--ink); }
.mk-meta {
  margin: 1px 0 0; color: var(--muted); font-size: .84rem;
  font-variant-numeric: tabular-nums;
}
.mk-note { margin: 3px 0 0; color: var(--ink-2); font-size: .9rem; }
/* Quieter than the note: this is about the file, not about the place. */
.mk-reseat { margin: 3px 0 0; color: var(--muted); font-size: .8rem; }
/* A gutter for the numbers, so the day's shape also says how high it is.
   ele=lo is drawn at y=51 and ele=hi at y=9 inside a box that is exactly 56px
   tall, which is why these two offsets are literal pixels and not percentages. */
.pf-wrap { position: relative; padding-left: 54px; margin-top: 7px; }
/* The coda keeps the gutter so it lines up with the chart above, and
   loses only the numbers. */
.pf-wrap.bare { margin-top: 4px; }
.pf-hi, .pf-lo {
  position: absolute; left: 0; width: 48px; text-align: right; line-height: 1;
  white-space: nowrap;   /* "2,857 m" wrapped the unit onto its own line */
  font-size: .66rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.pf-hi { top: 9px; transform: translateY(-50%); }
.pf-lo { top: 51px; transform: translateY(-50%); }
.pf {
  width: 100%; height: 56px; display: block; margin-top: 0;
  background: var(--surface); border: 1px solid var(--line); border-radius: 7px;
}
.pf-f { fill: var(--accent); opacity: .13; stroke: none; }
.pf-done { fill: var(--accent); opacity: .30; stroke: none; }
/* Same stretch, same fix: without this the line is 1.5px where it runs flat
   and 3px where it runs steep, because the horizontal scale is twice the
   vertical one. */
.pf-l { fill: none; stroke: var(--accent); stroke-width: 1.5;
        vector-effect: non-scaling-stroke; }
/* A halo so the other marks stay readable over the filled part as well as
   the open part — without it the fill swallows them. */
/* Sized in screen pixels, so the horizontal stretch that fits the line to the
   column cannot flatten them. Each dot is a halo drawn first and the dot over
   it, because a stroke cannot carry its own outline. */
.pf-oh, .pf-o, .pf-meh, .pf-me {
  fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
.pf-oh { stroke: var(--surface); stroke-width: 6.4; }
.pf-o  { stroke: var(--muted);   stroke-width: 4.4; }
.pf-meh { stroke: #fff;    stroke-width: 11.6; }
.pf-me  { stroke: #e34948; stroke-width: 8; }
.card.rest { border-style: dashed; }
/* 行前/行後 folds span the grid and open into their own two-column flow */
.phase { grid-column: 1 / -1; }
.phase summary {
  cursor: pointer; color: var(--ink-2); font-size: .9rem;
  padding: 8px 6px; border-radius: 10px;
}
@media (hover: hover) and (pointer: fine) {
  .phase summary:hover { background: var(--surface); }
}
.phase-days { display: grid; gap: 12px; margin-top: 8px; }
@media (min-width: 768px) { .phase-days { grid-template-columns: 1fr 1fr; } }
.card.rest .note { color: var(--ink-2); font-size: .92rem; margin: 0; }
/* Photo strip */
.shots { margin-top: 34px; }
.shots h2 { font-size: 1.05rem; margin: 0 0 4px; }
.shots .lead { color: var(--ink-2); font-size: .88rem; margin: 0 0 14px; }
.shots-grid { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 768px) { .shots-grid { grid-template-columns: 1fr 1fr; } }
.shot { margin: 0; }
.shot img {
  width: 100%; height: 220px; object-fit: cover; display: block;
  border-radius: 14px; border: 1px solid var(--line); box-shadow: var(--shadow);
}
.shot figcaption { color: var(--muted); font-size: .8rem; margin-top: 6px; }
.site-foot {
  margin-top: 32px; padding-top: 14px; border-top: 1px solid var(--line);
  color: var(--muted); font-size: .8rem;
}
.site-foot a { color: inherit; }

/* ---- Friendly reading (opt-in) -------------------------------------------
   Nothing above this line changes: with no data-size attribute the page is
   pixel-for-pixel the default design. These steps are percentages of the
   reader's own browser default, so someone who already enlarged text
   system-wide gets this on top of it instead of having it overwritten. Type,
   line-height and tap targets grow; the column width deliberately does not,
   so lines stay a comfortable length rather than running edge to edge. */
:root[data-size="l"] { font-size: 112.5%; }
:root[data-size="xl"] { font-size: 125%; }
:root[data-size="l"] body, :root[data-size="xl"] body { line-height: 1.68; }
:root[data-size="l"] .hero-links a, :root[data-size="l"] .hero-links button {
  width: 43px; height: 43px;
}
:root[data-size="xl"] .hero-links a, :root[data-size="xl"] .hero-links button {
  width: 47px; height: 47px;
}
:root[data-size="l"] .hero-links svg { width: 22px; height: 22px; }
:root[data-size="xl"] .hero-links svg { width: 24px; height: 24px; }
:root[data-size="l"] .baiyue-link svg { width: 26px; height: 26px; }
:root[data-size="xl"] .baiyue-link svg { width: 28px; height: 28px; }
:root[data-size="l"] .lang-toggle { font-size: 17.5px; }
:root[data-size="xl"] .lang-toggle { font-size: 19px; }
:root[data-size="l"] .foot-links a, :root[data-size="xl"] .foot-links a {
  width: 38px; height: 38px;
}
:root[data-size="l"] .foot-links svg, :root[data-size="xl"] .foot-links svg {
  width: 20px; height: 20px;
}
.size-toggle { cursor: pointer; padding: 0; font: inherit; }
/* Download feedback: phones acknowledge a download with almost nothing, so
   people tap again and save five copies. One quiet toast per tap. */
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%) translateY(8px);
  background: var(--ink); color: var(--surface); border-radius: 12px;
  padding: 10px 18px; font-size: .88rem; line-height: 1.5; max-width: 88vw;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .25); opacity: 0; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease; z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Webviews that cannot download at all (FB, IG…) get a standing notice */
.iab-warn {
  background: var(--badge-bg); color: var(--badge-ink);
  padding: 10px 16px; font-size: .85rem; line-height: 1.6; text-align: center;
}
/* ---- Whole-trip locators (pipeline/site_daylist.py; MG 2026-09-17 mock A/B/C) ---- */
/* Anchors land below the sticky bar, not behind it: #dN put a card's header
   at y=0, under the bar and (on a phone) under the fold rail as well, so a
   jump looked like nothing had moved (MG 2026-09-17). On a phone this was
   108px (rail lane + bar); the rail now rides in the bar, so the bar is at
   the top edge there too and only the notch inset differs (MG 2026-10-06). */
.card[id] { scroll-margin-top: calc(56px + env(safe-area-inset-top, 0px)); }
@media (min-width: 560px) { .card[id] { scroll-margin-top: 56px; } }
/* A. The sticky day bar. Anchors, so it works with JS off; the "on" class is
   the only thing the script adds. Horizontal scroll, never a second row: on a
   14-day trip at 320 px the pills would otherwise eat two lines of the fold
   work from 2026-09-09. */
.daybar {
  /* At the top edge (below the notch on a phone). The 56px lane it used to
     leave above itself on a phone was the floating fold rail's; since
     78a172fb6 controls.js moves the rail into this bar on phones, so the
     lane only showed content scrolling past (MG 2026-10-06). */
  position: sticky; top: env(safe-area-inset-top, 0px); z-index: 4;
  /* A grid item by accident of where it sits (.grid is two columns from
     768px): without these it took one column and stretched to that row's
     height, which stretched every pill into a full-height bar (MG 2026-09-17,
     screenshot). It spans the pair and hugs its own content instead. */
  grid-column: 1 / -1; align-self: start;
  display: flex; align-items: center; gap: 6px;
  padding: 7px 8px; margin: 0 0 12px; overflow-x: auto; scrollbar-width: none;
  background: color-mix(in srgb, var(--page) 92%, transparent);
  backdrop-filter: blur(6px); border-bottom: 1px solid var(--line);
  /* The scrollbar is hidden, so on a 14-day trip at 320 px the row just
     stopped at "D" with nothing to say there was more (review 2026-10-06).
     The last 24 px fade out instead. Only that strip: the rest of the bar
     keeps its tint and blur, and a mask changes no box. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
}
.daybar::-webkit-scrollbar { display: none; }
.dpill {
  flex: 0 0 auto; padding: 3px 10px; border-radius: 999px; font-size: .85rem;
  color: var(--ink); background: var(--surface); border: 1px solid var(--line);
  text-decoration: none;
}
.dpill.on { color: var(--surface); background: var(--accent); border-color: var(--accent); }
.dpill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* B. Where this day sits along the trip. Inside the fold, so a collapsed day
   costs nothing (MG 2026-09-17: 收起來的意思是點到的才打開). */
.daypos { margin: 10px 0 0; }
.daypos-bar {
  position: relative; display: block; height: 6px; border-radius: 3px; background: var(--line);
}
.daypos-seg {
  position: absolute; top: 0; height: 6px; border-radius: 3px; background: var(--accent);
}
.daypos-num { display: block; margin-top: 4px; font-size: .8rem; color: var(--muted); }
/* C. The day slices, laid over the profile strip that thumbs/trip.webp
   already draws (pipeline/site_daylist.py has the geometry). No second
   profile: the picture has one, it just could not be clicked. */
.prof-slices { position: absolute; inset: 0; display: block; }
.pseg { position: absolute; top: 74.5%; height: 20%; text-decoration: none; }
.pseg:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) and (pointer: fine) {
  .pseg:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}
/* V2 whole-trip day highlight: dim the map, redraw one day's line. The
   overlay sits inside .thumb-wrap so it shares the picture's box; .thumb
   stays width:100%/height:auto without cropping. */
.route-map { display: block; }
.route-overlay {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
}
.route-overlay .scrim { fill: #000; opacity: 0; }
.route-map[data-sel] .scrim { opacity: .42; }
:root[data-theme="dark"] .route-map[data-sel] .scrim { opacity: .58; }
.route-overlay .day { display: none; }
.route-overlay .day.on { display: inline; }
.route-overlay .casing {
  stroke: #fff; stroke-width: 8px; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
}
.route-overlay .line {
  stroke: #e34948; stroke-width: 4.6px; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
}
.route-overlay .prof { fill: var(--accent); fill-opacity: .22; stroke: none; }
.route-overlay .lbl {
  font: 700 26px system-ui, sans-serif; fill: #fff;
  paint-order: stroke; stroke: rgba(0,0,0,.72); stroke-width: 6px;
}
.route-overlay .credit {
  font: 700 14px system-ui, sans-serif; fill: #fff;
  paint-order: stroke; stroke: rgba(0,0,0,.65); stroke-width: 3px;
  opacity: 0;
}
.route-map[data-sel] .credit { opacity: 1; }
.day-pick {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; padding: 0;
}
.day-pick .rpill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 36px; padding: 4px 10px; border-radius: 999px;
  font: inherit; font-size: .85rem; font-variant-numeric: tabular-nums;
  border: 1px solid var(--line); background: var(--page); color: var(--ink-2);
  text-decoration: none; cursor: pointer;
}
.day-pick .rpill[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-ink); font-weight: 700;
}
.day-pick .rpill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pick-sum { display: flex; flex-direction: column; gap: 6px; margin: 8px 0 0; }
.pick-sum .pick-day:not([hidden]) { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.pick-sum .hint { color: var(--muted); font-size: .85rem; margin: 0; }
.pick-sum .no-line { color: var(--muted); font-size: .85rem; margin: 0; }
.pick-sum .go {
  align-self: flex-start; font-weight: 650; color: var(--accent);
  text-decoration: none;
}
.pick-sum .go:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.map-caveat { color: var(--muted); font-size: .76rem; margin: 8px 0 0; }
@media (min-width: 560px) {
  .daybar { top: 0; }
}

/* The offline guide's "what do I press on MY phone" tables. Wide screens get
   a real three-column table; below 560px each row unfolds into a small block
   (the task as a heading, then one line per phone) because three columns of
   prose inside 320px is unreadable -- and the readers this page was asked for
   are MG's older siblings. The phone name in the stacked view comes from
   data-ph rather than a repeated <span>, so the table markup stays one row
   per task in both layouts. */
.phones {
  margin: 18px 0 4px; border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden;
}
.phones-cap {
  margin: 0; padding: 9px 12px; font-weight: 700; font-size: .95rem;
  background: var(--surface);
}
.phones table { width: 100%; border-collapse: collapse; }
.phones th, .phones td {
  padding: 10px 12px; text-align: left; vertical-align: top;
  border-top: 1px solid var(--line); line-height: 1.55;
}
.phones thead th { font-weight: 600; color: var(--ink-2); white-space: nowrap; }
.phones tbody th { font-weight: 700; width: 27%; }
@media (max-width: 559px) {
  .phones thead { position: absolute; left: -9999px; }
  .phones table, .phones tbody, .phones tr, .phones th, .phones td {
    display: block; width: auto;
  }
  .phones tbody th {
    width: auto; border-top: 1px solid var(--line); padding-bottom: 2px;
  }
  .phones tbody td { border-top: 0; padding-top: 2px; padding-left: 12px; }
  .phones tbody td::before { content: attr(data-ph) "："; font-weight: 700; }
}

/* Route switcher panel: in the content flow, not a dropdown — .hero clips
   overflow for the photo, and pushing content down reads plainer than a cover. */
.routes-panel {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 10px; margin: 16px 0 4px; box-shadow: var(--shadow);
  display: grid; gap: 8px;
}
.routes-panel[hidden] { display: none; }
.routes-head { margin: 2px 4px 2px; font-size: .8rem; color: var(--muted); }
.routes-head-section {
  margin: 10px 4px 0; font-size: .74rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
}
.routes-head-section:first-of-type { margin-top: 2px; }
.routes-all {
  display: inline-flex; padding: 4px 8px; font-size: .85rem; color: var(--accent);
  text-decoration: none; white-space: nowrap;
}
/* `.route` already means the route line inside a day card, and both rules
   applied to both elements — the card's title sat 8 px further in than its own
   badge whenever a second trip existed. This card carries its own name. */
.trip-card {
  position: relative; display: flex; gap: 12px; align-items: center; padding: 8px;
  border-radius: 11px; text-decoration: none; color: inherit;
}
@media (hover: hover) and (pointer: fine) {
  a.trip-card:hover { background: var(--page); }
}
.trip-card img {
  width: 96px; height: 62px; object-fit: cover; border-radius: 8px; flex: none;
  background: var(--page);
}
/* The text column has to fill the row, or the floated badge stops at the end
   of the longest line instead of the card's right edge — invisible while the
   badge was absolutely positioned, because absolute measured the card. */
.trip-card > div { flex: 1; min-width: 0; }
/* Shared chip look for a peak count, wherever it appears — a card's own
   corner or a shelf heading's total. Tints itself from --scrim instead of
   trusting what's underneath, same reasoning as the hero stat chips after
   LESSONS #62. Written as `.trip-card .peak-badge` / a flex child rather than
   bare `.peak-badge` so it outranks the `.trip-card span` rule below, which
   would otherwise win on specificity and hand the card badge the wrong size
   and color (LESSONS #86). */
.peak-badge {
  padding: 1px 7px; border-radius: 999px; font-size: .7rem; font-weight: 700;
  line-height: 1.6; color: #fff; flex: none; font-variant-numeric: tabular-nums;
  background: rgba(var(--scrim), .74); text-shadow: 0 1px 2px rgba(var(--scrim), .6);
}
/* Re-asserts the badge's own font-size/color, not just position: the
   `.trip-card span` rule two lines down outranks bare `.peak-badge` on
   specificity and would otherwise quietly hand the card's badge its
   gray-caption styling instead of its own (LESSONS #86 — this is that
   bug's second occurrence, moved here when the position rule split out). */
/* Floated, not absolutely positioned. Absolute took the badge out of flow and
   a long title simply ran underneath it: on a phone the overseas cards read
   Tour du Mont B———, Mount Rinjani & Segar———. Taiwan titles are short enough
   in Chinese that nothing collided, so the corner looked safe until the corner
   had something wide in it. Floating inside the text column makes the title
   wrap around the badge instead of under it, and keeps it in the same corner.
   Font-size/colour restated because `.trip-card span` outranks a bare class
   (LESSONS #86/#88/#89). */
.trip-card .peak-badge {
  float: right; margin: 0 0 2px 8px; font-size: .7rem; color: #fff;
}
.trip-card strong { display: block; font-size: .98rem; }
.trip-card span { display: block; font-size: .82rem; color: var(--ink-2); }
.trip-card .route-stats { color: var(--muted); font-variant-numeric: tabular-nums; }
/* Four figures now share this line and it wraps on a phone. Each stat stays
   whole so a break never orphans a number from its label ("・宿" / "3420 m").
   <i> rather than <span>, which `.trip-card span` would turn into a block. */
.trip-card .route-stats .nb { font-style: normal; }
/* Two classes deep on purpose: `.trip-card span` above outranks any single
   class and would hand these the caption's size (LESSONS #86/#88/#89 — the
   same specificity trap, three times in one feature, now written down). */
.trip-card .route-tags { font-size: .78rem; color: var(--muted); }
/* Two classes again, and display/font-size/colour all restated: `.trip-card
   span` would otherwise blow the chip out to a full-width block in caption
   grey (LESSONS #86/#88/#89 — the same trap, now a fourth time). */
.trip-card .route-kind {
  display: inline-block; margin-right: 6px;
  font-size: .68rem; padding: 1px 7px; color: var(--muted);
}
.trip-card .route-kind.planned { color: var(--accent); }
/* Two classes and display restated, or `.trip-card span` turns each country
   chip into a full-width block in caption grey (LESSONS #86/#88/#89, the same
   trap a fifth time). Smaller than the trip page's .peak-tag because it sits
   on a card row, beside the 實走版 chip rather than under a heading, and in
   neutral ink rather than that rule's accent: on a card the accent means the
   whole row is a link, and three blue chips inside it read as three more. The
   cascade was already landing on ink-2 by accident here — declared so it is a
   choice. */
.trip-card .peak-tag {
  display: inline-block; margin-right: 5px; font-size: .7rem; font-weight: 600;
  padding: 1px 8px; color: var(--ink-2);
}
.trip-card.cur { background: var(--page); }
/* This page is reachable from every trip but links nowhere except into one,
   so it needs a way out that isn't the browser's back button. */
.routes-home {
  display: inline-block; margin: 18px 0 0; font-size: .85rem;
  color: var(--accent); text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .routes-home:hover { text-decoration: underline; }
}
.routes-title { font-size: 1.5rem; margin: 8px 0 6px; color: var(--ink); }
.routes-index { display: flex; flex-direction: column; gap: 4px; margin: 8px 0 18px; }
.routes-section {
  margin: 18px 0 2px; font-size: 1.05rem; color: var(--ink-2);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  /* The numbers drop to their own line rather than off the screen. English
     needs it at 320 px -- Taiwan's 100 Peaks plus 51 peaks plus 61 incl.
     planned is 344 px wide, and .sec-nums does not shrink. Wrapping is the
     fix that also survives whatever the next label or translation is;
     shortening this one string would not (2026-09-10). */
  flex-wrap: wrap;
}
/* The shelf's two numbers travel together at the right edge. Without a wrapper
   the heading's own space-between would push them to opposite ends of the
   line, which reads as two unrelated facts rather than one before and after.
   flex: none so a long label shrinks first -- the numbers are the point. */
/* padding-right mirrors .trip-card's own 8px, which insets every card's badge
   from the card edge. Without it the shelf's chip sits 8 px further right than
   the badges it is meant to line up with, and the column reads crooked
   (MG 2026-09-10: 這樣 51 岳才能跟其他卡片同顏色的膠囊切齊). */
/* A planned trip leaving within a week. Solid, not the dashed outline the
   ordinary 規劃版 chip wears -- it has to break out of the row of quiet chips
   beside it, because the person it is for reads this page every day and still
   forgets to pack (MG 2026-09-10). Warning-sign yellow, and the same yellow in
   both themes: --badge-ink was a rust red in light and a warm orange in dark,
   so the two themes disagreed about what it was, and the light one shouted
   (MG: 目前的淺色版紅色太顯眼了). Still a named role, not a hardcoded colour
   (LESSONS #15) -- the role simply does not move with the theme.
   Hidden until the browser has compared the date; [hidden] is asserted
   because .route-tags' own layout would otherwise beat it. */
.route-kind.soon-chip {
  background: var(--soon-bg); color: var(--soon-ink); border-color: var(--soon-bg);
  font-weight: 700;
}
.route-kind.soon-chip[hidden] { display: none; }

.sec-nums {
  display: flex; align-items: center; gap: 6px; flex: none; padding-right: 8px;
  /* margin-left: auto keeps it right-aligned once the heading wraps -- English
     at 320 and 390 puts the numbers on their own line, where space-between has
     nothing left to push against and they fell back to the left edge. */
  margin-left: auto;
}
.routes-head-section {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  flex-wrap: wrap;
}
/* Wraps for the same reason .routes-section does. At 320 px the English title
   (94) plus the five tool buttons (222) plus the gap is 328 in a 288 box, so
   the row hung 24 px off the right edge. It was live on origin/main and went
   unseen because the hero above it overflowed by one pixel more (345 vs 344)
   and scrollWidth only ever reports the widest thing (2026-09-10). */
.routes-head-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap;
}
/* The trip pages float these controls on the photo; here they sit on the page,
   so they dress in surface tokens instead of white glass. */
.page-tools { display: flex; gap: 8px; }
.page-tools a, .page-tools button {
  width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  color: var(--ink-2); background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow); cursor: pointer; padding: 0;
}
@media (hover: hover) and (pointer: fine) {
  .page-tools a:hover, .page-tools button:hover { color: var(--ink); }
}
.page-tools svg { width: 20px; height: 20px; }
.routes-index .trip-card { background: var(--surface); box-shadow: var(--shadow); }

/* Content entries at the top of the ≡ panel: labelled, because the control
   row above is for controls and an icon-only row of 8 was unreadable
   (MG 2026-09-07, 頁面 × 按鈕 table). */
.panel-entries { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }
.panel-entries a {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); color: var(--accent);
  text-decoration: none; font-size: .9rem; font-weight: 600;
}
.panel-entries svg { width: 18px; height: 18px; }
/* the tall thin Taiwan glyph, a size up like its button (site.css .baiyue-link) */
.panel-entries svg.i-taiwan { width: 21px; height: 21px; }
