/* mobile-first. Light mode is blue on near-white; dark mode is a green-black
   forest scheme. Every accent is a variable so no hard-coded hue can survive a
   theme switch. */
:root {
  color-scheme: light dark;
  --page: #e9eef5; --surface: #ffffff;
  --ink: #101826; --ink-2: #46536a; --muted: #7f8b9e;
  --line: #d9e1ec;
  --accent: #2a78d6; --accent-2: #1c5cab; --accent-deep: #0d366b; --accent-ink: #ffffff;
  --hero-ink: #ffffff; --hero-ink-2: #c7dbf5;
  --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;
  --rest-bg: #fdf4dd; --rest-ink: #7d5c05; --rest-chip: #8a6410;
}
/* Dark values live in a mixin-ish block applied from two scopes: the OS setting
   (unless the reader has explicitly stamped light) and the reader's own choice,
   which must win either way. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --page: #080d0a; --surface: #111a14;
    --ink: #e9f2ec; --ink-2: #aec2b5; --muted: #7b8e82;
    --line: #21301f;
    --accent: #2fb178; --accent-2: #1c7a52; --accent-deep: #0a2a1c; --accent-ink: #04170f;
    --hero-ink: #ffffff; --hero-ink-2: #bfe0cd;
    --scrim: 5, 20, 13;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 20px rgba(0, 0, 0, .34);
    --badge-bg: #33220f; --badge-ink: #eeb277;
  --rest-bg: #2b2410; --rest-ink: #e3c069; --rest-chip: #4a3c14;
    --rest-bg: #2b2410; --rest-ink: #e3c069; --rest-chip: #4a3c14;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --page: #080d0a; --surface: #111a14;
  --ink: #e9f2ec; --ink-2: #aec2b5; --muted: #7b8e82;
  --line: #21301f;
  --accent: #2fb178; --accent-2: #1c7a52; --accent-deep: #0a2a1c; --accent-ink: #04170f;
  --hero-ink: #ffffff; --hero-ink-2: #bfe0cd;
  --scrim: 5, 20, 13;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 20px rgba(0, 0, 0, .34);
  --badge-bg: #33220f; --badge-ink: #eeb277;
  --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; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .i-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .i-sun { 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;
}
/* Hero */
.hero {
  position: relative; overflow: hidden; color: var(--hero-ink);
  background: linear-gradient(155deg, var(--accent-deep) 0%, var(--accent-2) 55%, var(--accent) 100%);
}
.hero.has-photo {
  background: var(--accent-deep) center/cover no-repeat;
}
/* 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. */
.hero-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  justify-content: space-between;
}
/* Publisher links: frosted discs that read as part of the photo's own UI */
.hero-links { display: flex; gap: 8px; }
.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);
}
.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; }
.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;
}
.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: 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 {
    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 {
    aspect-ratio: auto; height: min(80vh, 740px);
    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. */
.hero h1 {
  font-size: 1.75rem; margin: 0 0 4px; letter-spacing: .01em;
  color: color-mix(in srgb, var(--hero-ink) 62%, transparent);
}
.hero h1 .ini { color: var(--hero-ink); 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: -12px 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);
}
.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; }
.notice p { margin: 0; }
/* The body is one flex child so lead/list/tail stack instead of sitting in a row. */
.notice-body { min-width: 0; }
.notice-points { margin: .5em 0 0; padding-left: 1.5em; }
.notice-points li { margin: .32em 0; }
.notice-points + p { margin-top: .55em; }
.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; } }
.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);
}
@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); }
}
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.card h2 { font-size: 1.05rem; margin: 0; display: flex; align-items: center; gap: 8px; }
.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; }
.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; white-space: nowrap;
}
.badge.calm { background: var(--rest-bg); color: var(--rest-ink); }
.thumb {
  width: 100%; height: auto; border-radius: 12px;
}
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.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;
}
.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);
}
.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;
}
.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"] .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;
}

/* 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-all {
  display: block; padding: 8px; font-size: .85rem; color: var(--accent);
  text-decoration: none;
}
/* `.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 {
  display: flex; gap: 12px; align-items: center; padding: 8px;
  border-radius: 11px; text-decoration: none; color: inherit;
}
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);
}
.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; }
.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;
}
.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); }
.routes-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* 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 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;
}
.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); }
