/* ═══════════════════════════════════════════════════════════════════════════
   HAPPY TRAILS — one stylesheet for the whole site
   version 3.1

   Every page loads this file and nothing else. Which page is which is decided
   by a class on <body>:

     body.page-map     the main map          (index.html)
     body.page-trail   a single trail's page (beltline.html)
     body.page-text    a reading page        (Trails / About / Contact)

   The two map pages share their whole interface — the navigation bar, the
   corner title, the left rail, the panel, the layer switches, the legend, the
   round buttons. Those are written once here, with both pages' selectors
   listed together, so a change lands on both. Where the two genuinely want
   different values, the variable is declared once below and overridden in the
   page block that wants something else.

   HOW IT IS LAID OUT
     ①  the variables, all of them, in one block
     ②  the three page blocks, each overriding only what it must
     ③  the shared interface, then what belongs to one page or the other
     ④  the reading pages
     ⑤  the responsive rules, last, so they win
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ ①  THE VARIABLES ══════════════════════════════════════════════════════
   Change a value here and it changes everywhere it is used. The twelve at the
   bottom of this block are the ones the two map pages disagree about; their
   value here is the default and section ② overrides it.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{

  /* THE NAVIGATION BAR */
  --bar-height:        40px;
  --bar-pad:           clamp(14px, 3vw, 30px);
  --bar-bg:            #ffffff;
  --bar-line:          rgba(0,0,0,.10);
  --bar-text:          #3d3d3d;
  --bar-brand:         #6cc24a;
  --bar-here:          #e8503a;
  --bar-brand-size:    17px;
  --bar-link-size:     11.5px;
  --bar-link-gap:      clamp(11px, 2.2vw, 22px);

  /* SPACING */
  --edge-gap:          clamp(14px, 3vw, 34px);
  --gutter:            18px;

  /* THE TOP BAND — the corner title and its link buttons */
  --title-height:      44px;
  --title-links:       35px;
  --band-top:          calc(var(--title-height) + var(--title-links) + var(--title-pad) * 2);
  --trail-link-size:   9.5px;
  --trail-link-gap:    7px;
  --trail-link-top:    11px;

  /* THE LEFT RAIL AND ITS PANEL */
  --rail-top:          8px;
  --rail-gap:          10px;
  --compass-size:      52px;
  --compass-arrow:     22px;
  --compass-drop:      8px;
  --panel-width-wide:  min(438px, 88vw);
  --panel-gap:         12px;
  --panel-radius:      16px;
  --panel-slide:       .34s;
  --panel-ease:        cubic-bezier(.22, 1, .36, 1);

  /* THE ROUND BUTTONS AND CONTROLS */
  --control-size:      46px;
  --control-gap:       10px;
  --button-shadow:     0 4px 16px rgba(0,0,0,.28);
  --button-fade:       .2s;

  /* THE LEGEND AND THE LAYER SWITCHES */
  --swatch-width:      44px;
  --swatch-height:     20px;
  --switch-columns:    2;   /* THE MAIN MAP'S layer panel only. A trail
                              page's switches are one per row at every
                              size — it has two or three of them, and in
                              two columns they were a pair of narrow boxes
                              with their names broken across lines for a
                              panel that was no shorter for it. */
  --switch-off:        rgba(255,255,255,.20);
  --switch-slide:      .22s;
  --switch-gap:        7px;

  /* COLOURS */
  --accent-soft:       #e0a323;

  /* ── THE TRAIL COLOURS ────────────────────────────────────────────────
     The line you walk along, and the line on the elevation graph, are drawn
     in the same green the trails are drawn in on the main map — so a route
     means the same colour wherever you meet it.

     A WISHFUL trail — one that does not exist yet — is purple instead, all
     the way through: its route, its elevation line, its readouts and its
     kicker. That is switched on by one class, body.trail-wishful, near the
     bottom of this file; a page opts in with SETTINGS.trailKind = "wishful".
     Nothing else has to change. */
  --route-line:        #4ecf4e;   /* built trails, on the map and the graph */
  --route-line-wish:   #e84fff;   /* trails that are only proposed          */
  --route-glow:        rgba(78,207,78,.55);
  --route-glow-wish:   rgba(232,79,255,.55);
  --text:              #f4f2ee;
  --text-quiet:        #a9a49c;
  --text-faint:        rgba(255,255,255,.45);
  --panel:             rgba(18,20,23,.78);
  --panel-edge:        rgba(255,255,255,.13);
  --shadow:            0 18px 50px rgba(0,0,0,.45);
  --map-backdrop:      #1e1e1e;
  --backdrop:          #efe8d8;
  --pin-green:         #6cc24a;
  --pin-purple:        #c78bf0;
  --pin-text:          #14310c;
  --pin-text-purple:   #2b0f3d;
  --wishful:           #8e5bd0;
  --wishful-edge:      rgba(158,110,222,.62);
  --wishful-panel:     rgba(31,22,44,.66);
  /* the same two, lighter, for a note that sits INSIDE a dark card —
     see .tm-judgement. A dark panel on a dark card reads as a hole. */
  --wishful-panel-soft:rgba(255,255,255,.055);
  --wishful-edge-soft: rgba(158,110,222,.34);
  --wishful-kicker:    #c39bf0;   /* on the dark panel, where pale reads */
  /* THE SAME PURPLE THE WISHFUL TRAILS THEMSELVES ARE DRAWN IN.
     The pale lavender above is right on a dark panel and wrong over the
     map, where the background is the artwork's own light paper and a pale
     tint of anything simply disappears. The type-and-length line over the
     map takes this one instead: it is the trail's own colour, so the line
     naming the trail and the line drawn on the map now agree. */
  --wishful-kicker-ink:#e84fff;

  /* TYPE */
  --font-body:         "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display:      "Iowan Old Style", Georgia, "Times New Roman", serif;
  --note-size:         11.5px;

  /* EVERYTHING ELSE — the trail page's cards, media, blur and
     elevation graph, and the map pin sizes. Named as they were. */
  --arrow-bg:          rgba(8,10,12,.55);
  --arrow-bg-hover:    var(--accent);
  --arrow-size:        32px;
  --band-bottom:       calc(var(--readout-row) + var(--readout-gap) + var(--profile-height) + var(--readout-drop));
  --caption-fade:      .22s;
  /* the waypoint stepper, bottom left */
  --stepper-size:      34px;
  --stepper-gap:        8px;
  --stepper-drop:      10px;   /* how far above the readouts it sits */
  --stepper-bg:        rgba(255,255,255,.10);
  --stepper-bg-hover:  rgba(255,255,255,.22);
  --stepper-edge:      rgba(255,255,255,.16);
  --stepper-ink:       rgba(255,255,255,.78);
  --stepper-off:       .28;    /* opacity when there is nowhere to go */
  /* the button where one trail meets another */
  --cross-bg:          rgba(38,86,140,.86);
  --cross-bg-hover:    rgba(52,112,178,.96);
  --cross-edge:        rgba(150,196,240,.45);
  --shot-height:       132px;   /* the picture at the top of a trail card */
  /* Buy me a coffee. Their own yellow, warmed slightly to sit with the site's
     amber rather than shout over it. */
  --over-veil-ink:     #f2f0ea;   /* title text over the top veil */
  --over-veil-kicker:  #e0a323;
  --coffee-nav:        #e8503a;   /* in the white bar — the site's orange   */
  --coffee-nav-hover:  #c0392b;
  --coffee-ink:        #ffdd55;   /* on the dark panel — their own yellow   */
  --coffee-ink-hover:  #ffe680;
  --coffee-bg:         rgba(255,221,85,.07);
  --coffee-edge:       rgba(255,221,85,.24);
  /* the picture behind the opening panel, and the veil that keeps its text
     readable. Subtle on purpose: enough to see what the trail looks like,
     not so much that the words fight it. */
  --opening-veil:      .66;
  --opening-veil-top:  .46;
  /* how much clear picture there is above the kicker and below the hint. The
     panel's own padding surrounds the WORDS; this is picture with nothing on
     it at all, and it is the difference between a photograph you can see and a
     dark background you assume is one. */
  --opening-picture:   clamp(22px, 4.5vh, 54px);
  /* the "scroll for more" line at the foot of a card, on a phone */
  /* the "turn your phone" screen */
  --turn-veil:         rgba(8,10,12,.92);
  --caption-size:      11px;
  --card-blur:         10px;
  --card-body:         14px;   /* the paragraphs inside a card. Every tenth
                                 of a millimetre off this is another line of
                                 text in the same card, which is the whole
                                 reason it is a variable. */
  /* Everything in a card that is NOT the picture, added up: the padding, the
     heading, the text window, the pager, the facts. The picture takes what is
     left of the column, so this number is how the card is kept inside it.
     ANYTHING ADDED TO A CARD HAS TO BE ADDED HERE TOO, or the card grows past
     the bottom of its column and starts overhanging the screen. */
  --card-chrome:       300px;
  --card-lean:         .1;
  --card-lift:         50%;
  --card-line:         1.65;
  --card-media:        4/3;
  --card-media-min:    130px;
  --card-panel:        rgba(18,20,23,.66);
  --card-radius:       18px;
  --card-sit:          50%;
  --card-text-lines:   10;   /* the most lines a card will show at once.
                               The engine shows fewer on a short window —
                               see cardFitsWindow — so this is a ceiling,
                               not a promise. It was 7, which on a tall
                               screen left the card ending well above the
                               readouts with the text still in pages. */
  --card-title:        24px;
  --card-width:        min(540px, 44vw);
  --close-fade:        .15s;
  /* the room a card has: everything between where its column starts and
     the readouts at the foot of the screen */
  --column-height:     calc(100vh - var(--bar-height) - var(--card-top) - var(--band-bottom));
  /* how much is kept clear above the card. On a narrow screen the card is
     full width and this has to clear the corner title; on a wide one it
     does not, and the responsive block near the end of this file cuts it
     right down. */
  --card-top:          var(--band-top);
  --dot-off:           rgba(255,255,255,.42);
  --dot-on:            #fff;
  --dot-size:          6px;
  --handle-colour:     #fff;
  --handle-grip:       30px;
  --handle-hit:        44px;
  --handle-line:       2px;
  --hint-bob-speed:    1.9s;
  --knob-colour:       #fff;
  /* the buffering spinner on a video */
  --spinner-size:      34px;
  --spinner-weight:     3px;
  --spinner-track:     rgba(255,255,255,.22);
  --spinner-lit:       #fff;
  --spinner-speed:     .8s;

  --knob-size:         7px;
  --maplink-size:      9.5px;
  --media-ease:        cubic-bezier(.4, 0, .2, 1);
  --media-slide:       .45s;
  --pin-lift:          1.08;
  --pin-radius:        999px;
  --pin-size:          13px;
  --profile-height:    58px;
  --profile-line:      rgba(255,255,255,.78);
  --reader-fade:       .18s;
  --readout-drop:      26px;
  --readout-gap:       10px;
  --readout-row:       42px;
  --readout-size:      clamp(17px, 2.3vw, 24px);
  --screen-veil-centre: .34;
  --screen-veil-edge:  .70;
  /* how far down the opening screen its darkening has faded to nothing. The
     panel travels up and off, and without this its bottom edge would sweep up
     the map as a hard horizontal line. Below this point there is no veil, so
     there is no edge to see. */
  --screen-veil-corner: .30;   /* at the very top, where the title is */
  --screen-veil-ends:  86%;
  --scroll-length:     900vh;
  --shade-bottom:      .55;
  --shade-edges:       .20;
  /* A short, light version of the bottom band, so the corner title has
     something to sit on. Deliberately much weaker than the bottom — that one
     carries readouts over a busy map, this one only has to lift a heading. */
  --shade-top:         .30;
  --shade-top-depth:   13%;
  --text-turn:         .3s;
  --trail-ahead:       rgba(60,45,25,.55);
  --trail-outline:     rgba(255,255,255,.55);
  --trail-walked:      var(--route-line);
  --walker-ring:       76px;
  --walker-size:       16px;
  --walker-speed:      2.4s;
  --wpdot-colour:      rgba(255,255,255,.9);
  --wpdot-ring:        rgba(0,0,0,.45);
  --wpdot-size:        5px;

  /* THE READING PAGES — Trails, About, Contact */
  --read-width:        min(940px, 100%);
  --read-top:          46px;    /* below the navigation bar                  */
  --read-gap:          46px;    /* between one section and the next          */
  --card-min:          260px;   /* a trail card stops shrinking here and the
                                   grid drops to one column                  */

  /* ── THE TWELVE THE TWO MAP PAGES DISAGREE ABOUT ──────────────────────────
     These are the defaults; section ② below changes them per page. They are
     kept together rather than scattered so it is obvious which values are
     page-dependent and which are the whole site's.                         */
  /* ╔══════════════════════════════════════════════════════════════════════╗
     ║  THE ACCENT COLOUR — CHANGE IT HERE AND NOWHERE ELSE                 ║
     ║                                                                      ║
     ║  This red is the site's one accent: the walking point, the active    ║
     ║  navigation link, the route buttons on the main map, every hover.    ║
     ║  Everything that uses it says var(--accent), so this line and the    ║
     ║  map-page override 20-odd lines below are the only two places a red  ║
     ║  is written down. Change both and the whole site changes.            ║
     ║                                                                      ║
     ║  NOT the trail line — that is --route-line, below, and it is green.  ║
     ╚══════════════════════════════════════════════════════════════════════╝ */
  --accent:            #c0392b;   /* map page: #e8503a — see body.page-map */
  --map-edge-shadow:   none;   /* map page: 0 0 90px rgba(0,0,0,.55) */
  --over-map-ink:      #2c2418;   /* map page: #f4f2ee */
  --over-map-kicker:   #94661a;   /* map page: #e0a323 */
  --over-map-quiet:    #7b6a4c;   /* map page: #b9b2a4 */
  --panel-bg:          rgba(20,22,26,.90);   /* map page: rgba(20,22,26,.94) */
  --panel-bg-blur:     20px;   /* map page: 0px */
  --panel-blur:        16px;   /* map page: 10px */
  --panel-width:       min(310px, 76vw);   /* map page: min(320px, 82vw) */
  --switch-height:     20px;   /* map page: 18px */
  --switch-width:      34px;   /* map page: 30px */
  --title-pad:         22px;   /* map page: 20px */
}


/* ═══ ②  THE THREE KINDS OF PAGE ════════════════════════════════════════════
   Each block overrides only what it must. body.page-map and body.page-trail
   both get the map interface; body.page-text gets none of it.
   ═══════════════════════════════════════════════════════════════════════════ */

/* the main map — light interface over a dark drawing */
body.page-map{
  --accent:            #e8503a;
  --map-edge-shadow:   0 0 90px rgba(0,0,0,.55);
  --over-map-ink:      #f4f2ee;
  --over-map-kicker:   #e0a323;
  --over-map-quiet:    #b9b2a4;
  --panel-bg:          rgba(20,22,26,.94);
  --panel-bg-blur:     0px;
  --panel-blur:        10px;
  --panel-width:       min(320px, 82vw);
  --switch-height:     18px;
  --switch-width:      30px;
  --title-pad:         20px;
}

/* a single trail's page — dark interface over pale paper. The variables in ①
   are already this page's values, so there is nothing to restate; its layout
   rules are with the <body> rules further down. */


/* ═══ ③  THE INTERFACE ══════════════════════════════════════════════════════
   Shared rules list both pages' selectors together; the rest belongs to one
   page or the other and is prefixed ht- (the main map) or tm- (a trail).
   ═══════════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════════
   SCROLLING TRAIL MAP — stylesheet
   version 5.3

   Everything you are likely to want to change lives in the :root block below.
   Change a value there and it changes everywhere it is used. Below that block
   is plain layout, grouped and labelled, which you can ignore unless you want
   to rearrange things.

   The first group in :root is SCREEN REGIONS. Nothing on this page carries its
   own private offset any more — every element is placed against one of a few
   named regions, so moving an edge moves everything that leans on it.
   ═══════════════════════════════════════════════════════════════════════════ */




/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT — from here down it is plumbing
   ═══════════════════════════════════════════════════════════════════════════ */*,
*{ box-sizing:border-box; }

/* ── <body> ───────────────────────────────────────────────────────────────
   What every page shares is here; what only one kind of page wants is in the
   three blocks below it. That split matters more than it looks: the main map
   fills the window and must NOT scroll, while a trail page IS a long scroll —
   scrolling is the whole mechanism, it is what walks you along the route. When
   the two stylesheets were merged into one file both pages had a plain `body`
   rule, the map's `overflow:hidden` won, and the trail page could not be
   scrolled at all. Hence the scoping. */
/* ── THE SCROLLBAR KEEPS ITS SEAT ────────────────────────────────────────
   On a reading page whose length changes — filter the Wishful thinking list
   and it can go from twelve cards to one — the scrollbar appears and vanishes
   with it, and on Windows and Linux, where the scrollbar takes real width, the
   whole page jumps sideways by fifteen pixels every time. It is a small jump
   and it is the most distracting thing on the page, because everything moves
   at once and none of it moved for a reason.

   `scrollbar-gutter: stable` reserves the space whether or not there is
   anything to scroll, so the page's width stops depending on its height. It
   costs nothing where scrollbars are overlaid (macOS, phones) — there is no
   width to reserve. The fallback for browsers that do not know the property
   is the older trick of always showing the track, which is uglier and does
   the same job.

   Only on the reading pages. The map pages do not scroll at all, so there is
   nothing to reserve and a permanent gutter beside a full-bleed map would be
   a stripe of nothing down the edge of the artwork. */
html:has(body.page-text){ scrollbar-gutter:stable; }
@supports not (scrollbar-gutter: stable){
  html:has(body.page-text){ overflow-y:scroll; }
}

body{
  margin:0;
  color:var(--text);
  font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;
  overscroll-behavior:none;
}

/* a trail page: it scrolls, and the ground around the artwork is its own
   paper colour so panning past the edge is not a jolt */
body.page-trail{
  background:var(--backdrop);
  overscroll-behavior-y:none;
}

/* ── the map ─────────────────────────────────────────────────────────────
   #tm-stage is a fixed window; #tm-world is the artwork, moved by one transform.
   The blur at the start and finish is applied to the stage rather than the
   artwork, so it is measured in screen pixels and does not grow and shrink
   with the zoom. The engine sets --map-blur; the stylesheet only says where
   it goes and how strong it may get.                                        */
/* ── the site's navigation bar ────────────────────────────────────────────
   Shared with the other pages on the site, so it is deliberately plain: an
   opaque strip that owns the top --bar-height of the window. Everything else
   on the page starts below it, which is why nothing else has to know it is
   there. Change --bar-height and the map, the title and the cards all follow.
   Its z-index is above every other layer so a card can never ride over it. */#tm-bar,
#ht-bar{
  position:fixed; top:0; left:0; right:0; height:var(--bar-height); z-index:40;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:0 var(--bar-pad);
  background:var(--bar-bg); border-bottom:1px solid var(--bar-line);
}
#tm-barBrand{
  font:700 var(--bar-brand-size)/1 var(--font-body); letter-spacing:.01em;
  color:var(--bar-brand); text-decoration:none; white-space:nowrap;
}
#tm-barNav{ display:flex; gap:var(--bar-link-gap); }
#tm-barNav a{
  font:500 var(--bar-link-size)/1 var(--font-body);
  letter-spacing:.09em; text-transform:uppercase; white-space:nowrap;
  color:var(--bar-text); text-decoration:none;
  transition:color var(--button-fade);
}
#tm-barNav a:hover{ color:var(--bar-here); }
#tm-barNav a.tm-here{
  color:var(--bar-here); text-decoration:underline; text-underline-offset:4px;
}

/* ── the map ─────────────────────────────────────────────────────────────
   Everything below sits under the bar rather than behind it. The engine reads
   the stage's own size when it works out what to centre, so the walker lands
   in the middle of the map area and not the middle of the window.          */
#tm-stage{
  position:fixed; top:var(--bar-height); left:0; right:0; bottom:0;
  z-index:0; overflow:hidden;
  --map-blur:0px;                       /* set frame by frame from the engine */
}
/* the filter is only switched on while there is actually something to blur —
   an always-on filter would cost a rendering pass during the whole walk */
#tm-stage.tm-blurred{ filter:blur(var(--map-blur)); }#tm-world,
#ht-world{
  position:absolute; top:0; left:0;
  transform-origin:0 0;
  will-change:transform;
  box-shadow:var(--map-edge-shadow);
}
#tm-world > svg, #tm-world > img{ display:block; }
#tm-trail{ position:absolute; top:0; left:0; overflow:visible; pointer-events:none; }
#tm-labels{
  position:absolute; top:0; left:0;
  /* --tag-fade is written by the engine on every frame of the pull-back. The
     names hold their size on screen, so once the whole map is in view a dozen
     of them at full size cover the map they are naming; they fade out and
     leave the route, the rings and the picture. See draw(). */
  --tag-fade:1;
}

/* ── waypoint labels and the moving point ────────────────────────────── */
.tm-label{ position:absolute; transform-origin:50% 50%; }
/* a chip you can click to bring its waypoint card back */
.tm-label.tm-clickable{ cursor:pointer; }
.tm-label.tm-clickable .tm-tag{ transition:background var(--button-fade), color var(--button-fade); }
.tm-label.tm-clickable:hover .tm-tag{ background:var(--accent); color:#fff; border-color:transparent; }
/* the moving point is decoration — never let it eat a click */
#tm-walker{ pointer-events:none; }
.tm-label .tm-dot{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:11px; height:11px; border-radius:50%;
  background:var(--backdrop); border:2.5px solid #fff;
  box-shadow:0 2px 8px rgba(0,0,0,.6);
}
/* ── the ring the page draws on the route at each waypoint ────────────────
   Sizes come from SETTINGS.waypointSize / waypointRing, which the engine
   writes onto :root — the numbers stay in the HTML with the rest of the
   settings, and the shape stays here. The whole chip is counter-scaled as the
   map zooms, so this holds the size given whatever the zoom, and it sits over
   the satellite view because the page draws it rather than the artwork. */
.tm-label .tm-pin{
  position:absolute; left:0; top:50%;
  width:var(--marker-size, 15px); height:var(--marker-size, 15px);
  margin-left:calc(var(--marker-size, 15px) / -2);
  transform:translateY(-50%);
  border-radius:50%; box-sizing:border-box;
  background:#fff;
  /* THE PIN IS PART OF THE ROUTE, so it is the route's colour — green on a
     built trail, purple on a wishful one, both of which fall out of
     --route-line without this rule knowing which it is.

     It was the site's red accent, left over from when the route was red too.
     Once the route went green the pin stayed behind, and since the artwork
     draws its own ring underneath at the route colour, every waypoint on every
     trail was a red ring sitting on top of a green one. */
  border:var(--marker-ring, 4px) solid var(--route-line);
  box-shadow:0 1px 5px rgba(0,0,0,.45);
}
.tm-label.tm-wishful .tm-pin{
  border-width:var(--marker-ring-wish, 3px);
  border-color:var(--wishful);
}
.tm-label.tm-clickable .tm-pin{ transition:transform var(--button-fade); }
.tm-label.tm-clickable:hover .tm-pin{ transform:translateY(-50%) scale(1.18); }

.tm-label .tm-tag{
  opacity:var(--tag-fade, 1);
  /* clear of the ring, whatever size the ring is */
  position:absolute; left:calc(var(--marker-size, 15px) / 2 + 7px);
  top:50%; transform:translateY(-50%);
  white-space:nowrap; padding:3px 9px; border-radius:999px;
  background:var(--panel); border:1px solid var(--panel-edge);
  backdrop-filter:blur(6px);
  font:600 10.5px/1.6 var(--font-body); letter-spacing:.05em; text-transform:uppercase;
}
#tm-walker .tm-dot{
  width:var(--walker-size); height:var(--walker-size);
  background:var(--accent); border:3px solid #fff;
}
#tm-walker .tm-ring{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:var(--walker-size); height:var(--walker-size);
  border-radius:50%; border:2px solid var(--accent);
  animation:pulse var(--walker-speed) ease-out infinite;
}
@keyframes pulse{
  from{ opacity:.9; width:var(--walker-size); height:var(--walker-size); }
  to  { opacity:0;  width:var(--walker-ring); height:var(--walker-ring); }
}

/* ── the shade over the map ──────────────────────────────────────────── */
#tm-shade{
  position:fixed; top:var(--bar-height); left:0; right:0; bottom:0;
  z-index:1; pointer-events:none;
  background:
    radial-gradient(125% 95% at 50% 45%, rgba(0,0,0,0) 42%, rgba(0,0,0,var(--shade-edges)) 100%),
    linear-gradient(to bottom,
      rgba(0,0,0,var(--shade-top)), rgba(0,0,0,0) var(--shade-top-depth),
      rgba(0,0,0,0) 60%, rgba(0,0,0,var(--shade-bottom)));
}

/* ── interface layer ─────────────────────────────────────────────────── */
/* The interface layer starts below the bar too, so every region measured
   inside it — --band-top and the rest — counts from the top of the map, not
   the top of the window. */
#tm-ui{
  position:fixed; top:var(--bar-height); left:0; right:0; bottom:0;
  z-index:3; pointer-events:none;
}

/* the top band. Its height is --band-top, which is also what the card column
   measures down from — so a taller title, or another link button wrapping
   onto a second row, pushes the cards down by itself. */
#tm-topbar{
  position:absolute; top:0; left:0; right:0; min-height:var(--band-top);
  display:flex; gap:16px; align-items:flex-start; justify-content:space-between;
  padding:var(--title-pad) var(--edge-gap);
}
#tm-brand{ max-width:46ch; }
#tm-brand .tm-kicker{
  font:600 10.5px/1 var(--font-body); letter-spacing:.22em; text-transform:uppercase;
  color:var(--over-map-kicker); margin-bottom:8px;
}
#tm-brand h1{
  margin:0; font:700 clamp(15px,2.1vw,21px)/1.25 var(--font-body); letter-spacing:-.01em;
  color:var(--over-map-ink);
}

/* ── the link buttons under the corner title ──────────────────────────────
   Small pills for the things a walker might want off the page: the map file
   itself, the Wikipedia entry, the route on Google Maps. Each one is written
   in WORDS.trailLinks; a link with an empty href is left off the page
   altogether, and if none of them has an href the whole row disappears —
   so there is nothing to comment out when a trail has no links.           */#tm-links,
#ht-links{
  display:flex; flex-wrap:wrap; gap:var(--trail-link-gap);
  margin-top:var(--trail-link-top);
}#tm-links:empty,
#ht-links:empty{ display:none; }
#tm-links a{
  pointer-events:auto; cursor:pointer;
  font:600 var(--trail-link-size)/1 var(--font-body);
  display:inline-flex; align-items:center; gap:5px;
  letter-spacing:.11em; text-transform:uppercase; text-decoration:none;
  color:var(--over-map-ink);
  background:rgba(255,255,255,.62); border:1px solid rgba(60,45,25,.28);
  padding:6px 10px; border-radius:999px; backdrop-filter:blur(6px);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}#tm-links a:hover,
#ht-links a:hover{ color:#fff; background:var(--accent); border-color:transparent; }#tm-links a:focus-visible,
#ht-links a:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:2px; }
#tm-topright{ display:flex; align-items:center; gap:12px; }
#tm-version{ font:500 10px/1 var(--font-body); letter-spacing:.14em; color:var(--over-map-quiet); }

.tm-button{
  pointer-events:auto; cursor:pointer;
  font:600 11px/1 var(--font-body); letter-spacing:.06em; text-transform:uppercase;
  color:var(--text-quiet); background:var(--panel); border:1px solid var(--panel-edge);
  padding:9px 12px; border-radius:999px; backdrop-filter:blur(10px);
  transition:color var(--button-fade), background var(--button-fade);
}
.tm-button:hover{ color:var(--text); }

/* ── the compass ──────────────────────────────────────────────────────────
   It lives in the page rather than in the artwork, so it stays in the corner
   however far the map is panned or zoomed. The map is drawn north-up, so the
   needle never has to turn. */
/* THE LEFT RAIL — the compass and the two panel buttons, in one fixed column.
   Left-hand side because the waypoint cards live on the right. It hangs off
   the bottom of the top band, so restyling the corner title carries it along.
   Nothing in here ever moves: that is what keeps the buttons attached to the
   panel they open. */
#tm-rail{
  position:absolute; z-index:5;
  left:var(--edge-gap);
  /* --rail-drop is written by the page, and only on a phone, to lower the rail
     until no waypoint card can cut a button in half. See placeRail(). It is 0
     everywhere else, so this reads exactly as it did before. */
  top:calc(var(--band-top) + var(--compass-drop) + var(--rail-drop, 0px));
  display:flex; flex-direction:column; gap:var(--rail-gap);
}

#tm-compass{
  width:var(--compass-size); height:var(--compass-size); border-radius:50%;
  display:grid; place-items:center;
  background:var(--panel); border:1px solid var(--panel-edge);
  backdrop-filter:blur(10px); box-shadow:0 4px 16px rgba(0,0,0,.28);
}#tm-compass[hidden],
#ht-compass[hidden]{ display:none; }#tm-compass svg,
#ht-compass svg{
  width:var(--compass-arrow); height:var(--compass-arrow);
  fill:var(--accent); margin-bottom:-3px;
}#tm-compass span,
#ht-compass span{ font:700 10px/1 var(--font-body); letter-spacing:.1em; color:var(--text); }

/* the two round buttons under the compass */
.tm-railBtn{
  pointer-events:auto; cursor:pointer; padding:0;
  width:var(--compass-size); height:var(--compass-size); border-radius:50%;
  display:grid; place-items:center;
  background:var(--panel); border:1px solid var(--panel-edge);
  color:var(--text-quiet);
  backdrop-filter:blur(10px); box-shadow:0 4px 16px rgba(0,0,0,.28);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}.tm-railBtn[hidden],
.ht-railBtn[hidden]{ display:none; }.tm-railBtn svg,
.ht-railBtn svg{ width:20px; height:20px; }.tm-railBtn:hover,
.ht-railBtn:hover{ color:var(--text); }.tm-railBtn.is-on,
.ht-railBtn.is-on{ background:var(--accent); border-color:transparent; color:#fff; }.tm-railBtn:focus-visible,
.ht-railBtn:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:3px; }
/* the label is for screen readers; the icon and the tooltip carry it on screen */.tm-railName,
.ht-railName{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}

/* ── the one panel both buttons open ──────────────────────────────────────
   It is anchored to the rail, not to the window edge, and slides out from
   behind it. Only one exists and its contents are swapped, so there is never
   a second panel to get out of step with. */
#tm-panel{
  position:absolute; z-index:5;
  left:calc(var(--edge-gap) + var(--compass-size) + var(--panel-gap));
  top:calc(var(--band-top) + var(--compass-drop));
  width:var(--panel-width);
  max-height:calc(100% - var(--band-top) - var(--compass-drop) - var(--gutter));
  display:flex; flex-direction:column;
  background:var(--panel-bg); border:1px solid var(--panel-edge);
  border-radius:var(--panel-radius); box-shadow:var(--shadow);
  backdrop-filter:blur(var(--panel-bg-blur)) saturate(1.2);
  overflow:hidden; transform-origin:0 0;

  /* THE CLOSED STATE. All three of these matter:
       opacity        makes it fade rather than vanish
       visibility     takes it out of the accessibility tree, and — with the
                      0s delay below — waits until the fade has finished
       pointer-events stops it catching clicks while it is invisible

     That last one was a bug up to 5.2: a panel at opacity 0 is still a solid
     pane as far as the pointer is concerned, so a closed panel sat over the
     map swallowing clicks meant for waypoints beneath it. The `hidden`
     attribute alone does NOT fix it — an element with a display of its own
     overrides what [hidden] would do — hence the rule below as well. */
  opacity:0; transform:translateX(-10px) scale(.98);
  visibility:hidden; pointer-events:none;
  transition:opacity var(--panel-slide) var(--panel-ease),
             transform var(--panel-slide) var(--panel-ease),
             visibility 0s linear var(--panel-slide);
}
#tm-panel.is-open{
  opacity:1; transform:none;
  visibility:visible; pointer-events:auto;
  transition:opacity var(--panel-slide) var(--panel-ease),
             transform var(--panel-slide) var(--panel-ease),
             visibility 0s;
}
/* and the belt to that pair of braces: [hidden] means gone, whatever display
   the rule above asked for. The engine sets this once the fade has played. */#tm-panel[hidden],
#ht-panel[hidden]{ display:none; }#tm-panelTop,
#ht-panelTop{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:14px 12px 12px 16px;
}#tm-panelTop h2,
#ht-panelTop h2{
  margin:0; font:700 10.5px/1 var(--font-body);
  letter-spacing:.18em; text-transform:uppercase; color:var(--accent-soft);
}
#tm-panelTop .tm-close{ position:static; width:24px; height:24px; font-size:16px; }#tm-panelNote,
#ht-panelNote{
  margin:0 16px 12px; font:400 12px/1.55 var(--font-body); color:var(--text-quiet);
}#tm-panelNote[hidden],
#ht-panelNote[hidden]{ display:none; }
#tm-panelBody{ overflow:auto; padding:0 16px 16px; }

/* ── the legend list ────────────────────────────────────────────────────── */.tm-legend,
.ht-legend{ list-style:none; margin:0; padding:0; display:grid; gap:11px; }.tm-legend li,
.ht-legend li{ display:flex; align-items:center; gap:12px; }.tm-legend span,
.ht-legend span{ font:400 12.5px/1.35 var(--font-body); color:var(--text); }
/* Each row's drawing is a file in the legend/ folder — legend/trails.svg and
   so on — named after the row's `swatch` in WORDS.legend. They come straight
   out of the Happy Trails Illustrator file, so they arrive at wildly different
   proportions: a bike-lane line is 11:1, the golf square is 1:1, the stairs
   are taller than wide. Each is fitted inside one box of this size, which is
   what keeps every label on the same left margin however different the
   drawings are. The Happy Trails map uses the same box. */.tm-sw,
.ht-sw{
  flex:0 0 var(--swatch-width);
  width:var(--swatch-width); height:var(--swatch-height);
  display:block; object-fit:contain;
}

/* ── the layer switches ─────────────────────────────────────────────────── */
/* ONE PER ROW, ALWAYS, ON A TRAIL PAGE.
   The main map's panel holds a dozen switches and genuinely needs two columns
   or the list runs off the bottom of a phone. A trail page has two or three.
   In two columns those became a pair of narrow boxes with their names broken
   across lines, side by side, for no reason — the panel was as tall either
   way. Full width also means the switch and its note read as one line of
   English rather than as a cell in a table.

   This is why the count is a variable rather than a number written in each
   rule: the two panels want different answers and the difference is stated
   once, here. */
.tm-switches{
  display:grid; gap:var(--switch-gap);
  grid-template-columns:1fr;
}
/* On the MAIN MAP, a group holding a single switch gives it the whole width
   rather than half of it with an empty hole beside it. `1 / -1` means "first
   grid line to last", so it holds whatever --switch-columns is set to and needs
   no change if the column count ever does.
   Swap :only-child for :last-child:nth-child(odd) if you would also like the
   last switch of an odd-numbered group to stretch across. */
.ht-switches > .ht-switch:only-child{
  grid-column: 1 / -1;
}
.tm-switch{
  display:flex; align-items:flex-start; gap:12px; width:100%; text-align:left;
  padding:11px 12px; border-radius:12px; cursor:pointer;
  background:rgba(255,255,255,.045); border:1px solid var(--panel-edge);
  transition:background var(--button-fade), border-color var(--button-fade);
}.tm-switch:hover,
.ht-switch:hover{ background:rgba(255,255,255,.09); }.tm-switch:focus-visible,
.ht-switch:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:2px; }.tm-switch .tm-track,
.ht-switch .ht-track{
  flex:0 0 auto; width:var(--switch-width); height:var(--switch-height);
  margin-top:1px; border-radius:999px; position:relative;
  background:var(--switch-off); transition:background var(--switch-slide);
}.tm-switch .tm-knobby,
.ht-switch .ht-knobby{
  position:absolute; top:2px; left:2px;
  width:calc(var(--switch-height) - 4px); height:calc(var(--switch-height) - 4px);
  border-radius:50%; background:#fff;
  transition:transform var(--switch-slide) var(--panel-ease);
}.tm-switch.is-on .tm-track,
.ht-switch.is-on .ht-track{ background:var(--accent); }.tm-switch.is-on .tm-knobby,
.ht-switch.is-on .ht-knobby{
  transform:translateX(calc(var(--switch-width) - var(--switch-height)));
}
/* A SWITCH THAT IS NOT A CONTROL.
   On a wishful trail the Wishful thinking switch has nothing to hide — the
   whole route is proposed — so the engine renders it locked on. It keeps its
   place in the panel, because a panel that gains and loses rows between trails
   is harder to read than one that always looks the same, but it is plainly not
   pressable: dimmed, the ordinary pointer rather than the hand, and no hover.

   The dimming is on the row rather than on each part of it, so the track, the
   knob and both lines of text fade together and the row still reads as one
   thing. `disabled` on the button is what actually prevents the press; this is
   only what says so. */
.tm-switch.is-locked{
  opacity:.45; cursor:default;
}
.tm-switch.is-locked:hover{ background:rgba(255,255,255,.045); }

.tm-switchText b{
  display:block; font:600 12.5px/1.25 var(--font-body); color:var(--text);
}
.tm-switchText small{
  display:block; margin-top:3px;
  font:400 11px/1.4 var(--font-body); color:var(--text-quiet);
}

/* ── waypoint cards ──────────────────────────────────────────────────── */
/* The card column: everything left over between the two bands, held against
   the right-hand edge. Never centred on the window — a tall card centred on
   the window runs underneath the numbers along the bottom. The engine measures
   this column and gives the card's text however many lines actually fit.

   left and right are both set and the width is capped, so the column is as
   wide as --card-width allows and no wider; margin-left:auto spends whatever
   is left over on the left, holding it against the right edge. Lift the cap
   (--card-width:none, which is what a phone does) and the column simply fills
   the width between the two margins. */
/* THE COLUMN THE CARD LIVES IN.
   It starts below the top band because on a narrow screen the card is full
   width and would otherwise cover the corner title. On a WIDE screen it would
   not: the title ends around x=330 and the card starts past the middle of the
   window, so the two cannot touch, and reserving the title's height for the
   card there costs it 80 pixels of height for nothing. --card-top is that
   reservation, and the responsive block at the foot of this file is where it
   is set: the full band on narrow screens, a much smaller clearance on wide
   ones. Every pixel it saves goes to the text. */
#tm-cards{
  position:absolute;
  top:var(--card-top, var(--band-top)); bottom:var(--band-bottom);
  left:var(--edge-gap); right:var(--edge-gap);
  width:auto; max-width:var(--card-width); margin-left:auto;
}
/* Where the card sits in that column, and the small rise as it fades in, are
   both here rather than in the engine — the engine only reports how far
   through the fade it is, as --card-nudge (a plain number of pixels). */
.tm-card{
  position:absolute; right:0; width:100%;
  bottom:var(--card-sit);
  transform:
    translateY(calc(var(--card-lift) + var(--card-nudge, 0) * var(--card-lean) * 1%))
    translateY(calc(var(--card-nudge, 0) * 1px));
  background:var(--card-panel); border:1px solid var(--panel-edge);
  border-radius:var(--card-radius); box-shadow:var(--shadow);
  backdrop-filter:blur(var(--card-blur)) saturate(1.2);
  overflow:hidden; opacity:0; will-change:opacity, transform;
}
/* ── a wishful-thinking card ──────────────────────────────────────────────
   Everything about it is the ordinary card; only the colour changes. The
   border is deliberately thin — it should read as a marked variant, not as a
   different component. */
.tm-card.tm-wishful{
  background:var(--wishful-panel);
  border-color:var(--wishful-edge);
}
.tm-card.tm-wishful .tm-count{ color:var(--wishful-kicker); }
.tm-card.tm-wishful .tm-facts{ border-top-color:var(--wishful-edge); }
/* its name chip on the map, and the arrows on its picture, follow the card */
.tm-label.tm-wishful .tm-tag{
  border-color:var(--wishful-edge); color:var(--wishful-kicker);
}
.tm-label.tm-clickable.tm-wishful:hover .tm-tag{
  background:var(--wishful); color:#fff; border-color:transparent;
}
/* and so does its dot on the elevation graph */
#tm-profile .tm-wpdot.tm-wishful{
  background:var(--wishful-kicker); border-color:rgba(0,0,0,.5);
}

/* the × that closes a card. It sits over the photo, top right. */
.tm-close{
  position:absolute; top:10px; right:10px; z-index:2;
  width:28px; height:28px; padding:0; border-radius:50%;
  display:grid; place-items:center; cursor:pointer;
  /* The × is drawn with a lot of empty space under it in most fonts, so a
     glyph centred by the grid still sits low. line-height:0 takes the font's
     own vertical metrics out of the sum and lets place-items centre the ink
     itself. */
  font:400 18px/0 var(--font-body); color:var(--text);
  background:rgba(8,10,12,.55); border:1px solid var(--panel-edge);
  backdrop-filter:blur(6px);
  transition:background var(--close-fade), color var(--close-fade), transform var(--close-fade);
}.tm-close:hover,
.ht-close:hover{ background:var(--accent); border-color:transparent; transform:scale(1.08); }
.tm-close:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:2px; }

/* ── the picture area ─────────────────────────────────────────────────────
   A fixed-shape window (--card-media) holding one or more slides. Every
   picture and video inside is object-fit:cover, so anything you drop in is
   scaled and centre-cropped to fill the window exactly — a portrait photo, a
   square one and a 16:9 one all sit correctly without being squashed.      */
.tm-media{
  position:relative; margin:0; overflow:hidden;
  /* width:100% is not decoration — without it the cap below makes the browser
     narrow the picture to keep the 4:3 ratio, instead of keeping it full
     width and cropping the top and bottom, which is what we want. */
  width:100%;
  aspect-ratio:var(--card-media); background:#1b1e22;
  /* the cap that keeps the whole card inside its column on a short window */
  max-height:max(var(--card-media-min),
                 calc(var(--column-height) - var(--card-chrome)));
}
.tm-track{
  display:flex; width:100%; height:100%;
  transition:transform var(--media-slide) var(--media-ease);
}
.tm-slide{ flex:0 0 100%; position:relative; height:100%; }
/* ── the buffering spinner ────────────────────────────────────────────────
   Shown while a video is fetching enough of itself to play, and again if it
   runs dry part-way through. Without it the picture area simply sits there,
   which reads as a broken card rather than a loading one — and the first play
   of a video that has so far fetched only its metadata is exactly when that
   happens.

   It is a ring with one brighter quarter, turned by a CSS animation, so it
   keeps moving even while the main thread is busy decoding video. */
.tm-spinner{
  position:absolute; left:50%; top:50%;
  width:var(--spinner-size); height:var(--spinner-size);
  margin:calc(var(--spinner-size) / -2) 0 0 calc(var(--spinner-size) / -2);
  border-radius:50%;
  border:var(--spinner-weight) solid var(--spinner-track);
  border-top-color:var(--spinner-lit);
  animation:tm-spin var(--spinner-speed) linear infinite;
  opacity:0; pointer-events:none; z-index:1;
  transition:opacity .18s ease;
}
/* the engine puts this on the slide while its video is waiting */
.tm-slide.is-buffering .tm-spinner{ opacity:1; }
@keyframes tm-spin{ to{ transform:rotate(360deg); } }

.tm-slide img, .tm-slide video{
  display:block; width:100%; height:100%;
  object-fit:cover;          /* fill the window, crop whatever hangs over */
  object-position:center;
}
.tm-caption{
  position:absolute; left:10px; bottom:9px;
  font:500 9.5px/1 var(--font-body); letter-spacing:.14em; text-transform:uppercase;
  color:rgba(255,255,255,.6); text-shadow:0 1px 6px rgba(0,0,0,.8);
}

/* ── the before/after slide ───────────────────────────────────────────────
   Two pictures stacked in the same box. The top one is clipped to the left of
   the handle, so dragging the handle wipes between them. Both are cover-
   cropped, exactly like every other picture, so the two line up.
   --split is the handle position as a percentage; the engine sets it.      */
.tm-compare{ position:relative; width:100%; height:100%; --split:50%; }
.tm-compare img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:center;
}
.tm-compare .tm-before{
  /* inset(top right bottom left) — keep only what is left of the handle, so
     "before" fills the left of the picture and "after" shows through on the
     right, which is the way round people expect to read it */
  clip-path:inset(0 calc(100% - var(--split)) 0 0);
}
.tm-compare-label{
  position:absolute; bottom:12px; z-index:2;
  padding:4px 9px; border-radius:var(--radius-pill);
  background:rgba(8,10,12,.6); color:#fff; backdrop-filter:blur(6px);
  font:600 9.5px/1 var(--font-body); letter-spacing:.14em; text-transform:uppercase;
  pointer-events:none; transition:opacity var(--button-fade);
}
.tm-compare-label.is-before{ left:12px; }
.tm-compare-label.is-after{ right:12px; }

.tm-compare-handle{
  position:absolute; top:0; bottom:0; left:var(--split); z-index:3;
  width:var(--handle-hit); margin-left:calc(var(--handle-hit) / -2);
  cursor:ew-resize; touch-action:none;   /* only the handle grabs a touch, so
                                            dragging the card still scrolls   */
  display:grid; place-items:center;
}
.tm-compare-handle::before{         /* the line down the join */
  content:""; position:absolute; top:0; bottom:0; left:50%;
  width:var(--handle-line); margin-left:calc(var(--handle-line) / -2);
  background:var(--handle-colour); box-shadow:0 0 10px rgba(0,0,0,.5);
}
.tm-compare-handle span{            /* the grab circle */
  position:relative; display:grid; place-items:center;
  width:var(--handle-grip); height:var(--handle-grip); border-radius:50%;
  background:var(--handle-colour); color:#14181c;
  font:400 13px/1 var(--font-body); letter-spacing:-1px;
  box-shadow:0 2px 10px rgba(0,0,0,.5);
  transition:transform var(--button-fade);
}
.tm-compare-handle:hover span, .tm-compare-handle:focus-visible span{ transform:scale(1.12); }
.tm-compare-handle:focus-visible{ outline:none; }
.tm-compare-handle:focus-visible span{ outline:2px solid var(--accent-soft); outline-offset:3px; }

/* ── carousel arrows and dots ─────────────────────────────────────────── */
.tm-media-arrow{
  position:absolute; top:50%; transform:translateY(-50%);
  width:var(--arrow-size); height:var(--arrow-size); border-radius:50%;
  display:grid; place-items:center; cursor:pointer;
  border:1px solid var(--panel-edge); background:var(--arrow-bg); color:#fff;
  font:400 17px/1 var(--font-body); backdrop-filter:blur(6px);
  transition:background var(--button-fade), color var(--button-fade);
}
.tm-media-arrow:hover:not([disabled]){ background:var(--arrow-bg-hover); color:#12161a; }
.tm-media-arrow.is-prev{ left:9px; }
.tm-media-arrow.is-next{ right:9px; }
.tm-media-arrow[disabled]{ opacity:.3; cursor:default; }

.tm-dots{
  position:absolute; left:0; right:0; bottom:9px;
  display:flex; gap:6px; justify-content:center;
}
.tm-dot{
  width:var(--dot-size); height:var(--dot-size); padding:0; border:0; border-radius:50%;
  background:var(--dot-off); cursor:pointer;
  transition:background var(--button-fade), transform var(--button-fade);
}
.tm-dot.is-on{ background:var(--dot-on); transform:scale(1.25); }

.tm-card .tm-inner{ padding:14px 20px 15px; }
/* The waypoint number on the left, the current picture's caption on the right.
   baseline alignment keeps the two lines of type sitting on the same line even
   though they are different sizes; the caption is allowed to wrap under itself
   rather than push the number about. */
/* ── THE STAMP ON THE PICTURE ─────────────────────────────────────────────
   The waypoint number and the current picture's caption, over the top-left of
   the photograph. They were a row between the picture and the title, which
   cost 21 pixels and put two small grey things in the way of a heading. Here
   they cost nothing and the title starts where the picture stops.

   Over a photograph nothing can be relied on for contrast, so both carry a
   shadow and the whole corner is darkened a little underneath them — enough
   to read against a bright sky, not enough to look like a box. */
.tm-stamp{
  position:absolute; left:0; top:0; right:0;
  padding:9px 12px 22px;
  display:flex; flex-direction:column; gap:4px;
  pointer-events:none;
  background:linear-gradient(to bottom, rgba(8,10,12,.55), rgba(8,10,12,0));
}
.tm-card .tm-count{
  flex:0 0 auto;
  font:700 10px/1 var(--font-body); letter-spacing:.2em; text-transform:uppercase;
  color:#f0c246;
  text-shadow:0 1px 5px rgba(0,0,0,.9);
}
/* the caption for whichever picture is showing. It is emptied and refilled by
   the engine; .tm-fading is on while the words are being changed, which is
   what turns the swap into a fade rather than a jump. Empty means no caption
   for that picture, and it simply takes no room. */
.tm-card .tm-slideCaption{
  max-width:min(62%, 260px);
  font:400 var(--caption-size)/1.35 var(--font-body);
  color:rgba(255,255,255,.82); font-style:italic;
  text-shadow:0 1px 5px rgba(0,0,0,.85);
  transition:opacity var(--caption-fade) ease;
}
.tm-card .tm-slideCaption.tm-fading{ opacity:0; }
.tm-card.tm-wishful .tm-count{ color:#f2a8ff; }
.tm-card .tm-count span{ color:rgba(255,255,255,.7); letter-spacing:.1em; font-weight:500; }
/* ── A LINK INSIDE A CARD'S TEXT ─────────────────────────────────────────
   The only running text on the site that can carry links, so this is the only
   place they need a look. Underlined rather than coloured alone: over a
   photograph the card's background is not reliably dark, and an underline
   survives that where a colour does not. It thickens under the pointer instead
   of changing colour, which is a steadier cue and one that does not depend on
   being able to tell the two colours apart.

   A link leaving the site gets a small outward arrow after it, drawn in the
   text rather than added as an image — so it prints, it scales with the type,
   and it costs no request. Anything pointing at another page of this site is
   left plain, which is what the rule below keys on. */
.tm-textpages a{
  color:var(--accent-soft);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  transition:color var(--button-fade), text-decoration-thickness var(--button-fade);
}
.tm-textpages a:hover{
  color:var(--text);
  text-decoration-thickness:2px;
}
.tm-textpages a:focus-visible{
  outline:2px solid var(--accent-soft); outline-offset:2px; border-radius:2px;
}
.tm-textpages a[target="_blank"]::after{
  content:"\2197";              /* ↗ */
  font-size:.82em; margin-left:.15em; text-decoration:none;
  display:inline-block; vertical-align:.05em;
}

.tm-card h2{ margin:0 0 6px; font:600 var(--card-title)/1.2 var(--font-display); letter-spacing:-.01em; }
/* ── the body text, in pages ──────────────────────────────────────────────
   The window is a whole number of lines tall and hides everything past it;
   the block inside slides up one page at a time. No scrollbar, so nothing in
   the card can ever swallow a scroll meant for the map.                    */
.tm-textwindow{ position:relative; overflow:hidden; }
.tm-textpages{ transition:transform var(--text-turn) var(--media-ease); }
.tm-card p{ margin:0; font:400 var(--card-body)/var(--card-line) var(--font-body); color:var(--text-quiet); }
/* The gap between paragraphs is exactly one line, which keeps every line of
   the card on the same grid — so a page break always lands between lines and
   never slices one in half. */
.tm-card p + p{ margin-top:calc(var(--card-body) * var(--card-line)); }

.tm-pager{ display:none; align-items:center; gap:10px; margin-top:8px; }
.tm-pager.is-on{ display:flex; }
.tm-pager button{
  width:26px; height:26px; border-radius:50%; cursor:pointer;
  display:grid; place-items:center;
  border:1px solid var(--panel-edge); background:transparent; color:var(--text);
  font:400 15px/1 var(--font-body);
  transition:background var(--button-fade), color var(--button-fade);
}
.tm-pager button:hover:not([disabled]){ background:var(--accent); color:#12161a; border-color:transparent; }
.tm-pager button[disabled]{ opacity:.28; cursor:default; }
.tm-pager .tm-pagecount{
  font:600 10px/1 var(--font-body); letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-faint); font-variant-numeric:tabular-nums;
}
/* ══ WHAT IT WOULD COST, AND HOW BADLY IT IS WANTED ═══════════════════════
   Two facts that only a wishful stop has, sitting between its title and its
   text — above the words rather than below them, because they are the first
   thing anyone comparing one proposal with another wants to know, and because
   the card's text scrolls in pages while this does not.

   Each is a picture and a word: a Canadian coin for the cost and a dial for
   the priority, with the value spelled out beside it. The picture is what you
   read at a glance across twelve cards; the word is what makes it certain, and
   is all a screen reader has. Neither is left to colour alone — the coins
   differ in size and in edge, and the dial's needle differs in ANGLE. */
/* WHAT IT WOULD COST, AND HOW BADLY IT IS WANTED — in the row of figures.
   They had a panel of their own beside the title, which made them the loudest
   thing on the card. They belong here: this is the row of things that are true
   about this stop, and they are the third and fourth of them, after Elevation
   and From start. No panel, no border — the row already has a rule above it,
   and a box inside a box is one box too many. */
.tm-judgement{
  display:flex; gap:14px; flex-wrap:wrap; flex:0 0 auto;
  margin:0; padding:0; border:0; background:none;
}
.tm-judge{ display:flex; align-items:center; gap:7px; }
.tm-judge img{
  width:21px; height:21px; display:block; flex:0 0 auto;
  /* the dial and the coins both carry a soft shadow so they sit ON the panel
     rather than looking pasted onto it */
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45));
  transition:transform var(--button-fade);
}
.tm-judge:hover img{ transform:scale(1.12) rotate(-4deg); }
.tm-judgeText{ display:flex; flex-direction:column; gap:2px; }
.tm-judgeText small{
  font:600 7.5px/1 var(--font-body); letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-quiet);
}
.tm-judgeText b{ font:600 10.5px/1 var(--font-body); color:var(--text); }

.tm-card .tm-facts{
  margin-top:11px; padding-top:10px; border-top:1px solid var(--panel-edge);
  /* flex-end so the link button sits on the same baseline as the numbers
     beside it rather than stretching to the full height of the row */
  display:flex; gap:20px; align-items:flex-end;
}
/* the link button at the end of the facts row. It reads as a button rather
   than a fact, but it is the same size and sits on the same line, so the row
   still scans as one thing. margin-left:auto pushes it to the far end. */
.tm-card .tm-mapLink{
  margin-left:auto; flex:0 0 auto; align-self:center;
  font:600 var(--maplink-size)/1 var(--font-body);
  letter-spacing:.11em; text-transform:uppercase; text-decoration:none;
  white-space:nowrap; color:var(--text);
  background:rgba(255,255,255,.10); border:1px solid var(--panel-edge);
  padding:7px 11px; border-radius:999px;
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}
.tm-card .tm-mapLink:hover{
  color:#fff; background:var(--accent); border-color:transparent;
}
.tm-card.tm-wishful .tm-mapLink:hover{ background:var(--wishful); }
.tm-card .tm-mapLink:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:2px; }
.tm-card .tm-facts div{ font:600 12px/1.2 var(--font-body); }
.tm-card .tm-facts small{
  display:block; font:500 9.5px/1 var(--font-body); letter-spacing:.14em;
  text-transform:uppercase; color:var(--text-faint); margin-bottom:5px;
}

/* ── readouts and elevation profile along the bottom ─────────────────────
   This is the bottom band. Its three parts — the row of numbers, the gap, the
   graph — plus the drop below it are the same values --band-bottom is built
   from at the top of the file, so the card column always stops exactly where
   this begins. Restyle the graph and the cards move up out of its way.     */
#tm-readouts{
  position:absolute; left:0; right:0; bottom:0;
  display:flex; flex-direction:column; gap:var(--readout-gap);
  padding:0 var(--edge-gap) var(--readout-drop);
}
#tm-numbers{
  display:flex; gap:clamp(16px,3vw,34px); align-items:flex-end;
  min-height:var(--readout-row);
}
#tm-numbers .tm-gap{ flex:1; }
.tm-readout small{
  display:block; font:500 9.5px/1 var(--font-body); letter-spacing:.16em;
  text-transform:uppercase; color:var(--text-faint); margin-bottom:6px;
}
.tm-readout b{
  font:700 var(--readout-size)/1 var(--font-body);
  letter-spacing:-.02em; font-variant-numeric:tabular-nums;
}
.tm-readout b i{ font:500 11px/1 var(--font-body); font-style:normal; color:var(--text-quiet); margin-left:2px; }

#tm-profile{ position:relative; height:var(--profile-height); }
#tm-profile svg{ width:100%; height:100%; display:block; overflow:visible; }
#tm-profile .tm-under{ fill:rgba(255,255,255,.10); }
#tm-profile .tm-whole{ fill:none; stroke:var(--profile-line); stroke-width:1.5; vector-effect:non-scaling-stroke; }
/* The walked part of the elevation graph is the same colour as the trail on
   the map — the two are the same fact drawn twice, so they should not be two
   different colours. --route-glow is the halo under it, kept as its own
   variable because a drop-shadow cannot take a bare colour variable and an
   alpha in one go. */
#tm-profile .tm-walked{
  fill:none; stroke:var(--route-line); stroke-width:2.5; vector-effect:non-scaling-stroke;
  filter:drop-shadow(0 0 5px var(--route-glow));
}
#tm-profile .tm-cursor{ stroke:rgba(255,255,255,.5); stroke-width:1; vector-effect:non-scaling-stroke; stroke-dasharray:2 3; }
/* The dot marking where you are on the graph.
   It is a plain element rather than a circle inside the SVG on purpose. The
   graph is drawn in a square 1000×100 box and then stretched to whatever
   width and height it is given — roughly 1372×58 on a desktop — so a circle
   drawn inside it comes out as a wide, flat oval. Sitting outside the SVG and
   positioned in percentages, this stays perfectly round at any size. */
/* A dot for each waypoint, so you can see at a glance where the stops fall
   against the climb. Placed from the same waypoint list as everything else —
   see the profile block in the HTML. Round for the same reason the knob is. */
#tm-profile .tm-wpdot{
  position:absolute; width:var(--wpdot-size); height:var(--wpdot-size);
  border-radius:50%; background:var(--wpdot-colour);
  border:1px solid var(--wpdot-ring);
  transform:translate(-50%, -50%); pointer-events:none;
}
#tm-profile .tm-knob{
  position:absolute; width:var(--knob-size); height:var(--knob-size);
  border-radius:50%; background:var(--knob-colour);
  transform:translate(-50%, -50%); pointer-events:none;
  box-shadow:0 0 5px rgba(0,0,0,.9);
}

/* ── opening and closing screens ─────────────────────────────────────── */
/* The darkening behind the opening and closing text. It is gentle: the text
   sits in its own box now, which is what carries the contrast, so this only
   has to settle the map down a little around it. There is no blur behind
   either screen any more — see blurAtStart / blurAtEnd in the page. */
#tm-opening, #tm-closing{
  position:absolute; inset:0; display:grid; place-items:center; text-align:center; padding:6vw;
  /* above the left-hand rail (z-index 5), so on a narrow screen the box is
     never sliced through by the legend and layers buttons */
  z-index:6;
  background:radial-gradient(60% 60% at 50% 50%,
    rgba(6,8,10,var(--screen-veil-centre)), rgba(6,8,10,var(--screen-veil-edge)));
}
/* The opening screen is the one that MOVES, so it needs a bottom that is
   already nothing by the time you can see it. Two gradients, not a mask: the
   radial does the darkening as before, the linear underneath it thins that
   darkening away to clear before the element's own edge. A mask would do the
   same job and cost a compositing pass on a layer that is being moved every
   frame; this costs nothing. */
#tm-opening{
  /* the engine moves this up and off the top as you scroll, so it is given its
     own compositing layer — and the engine hands the layer back (will-change:
     auto) the moment it has gone, so a full-screen layer is not held for the
     rest of the visit. The closing screen never moves and never needs one. */
  will-change:transform, opacity;
  background:
    /* Lighter at the very top than in the middle. The corner title sits up
       there in dark ink chosen for pale paper, and a veil at full strength
       under it left the trail's name barely readable — the panel's own
       darkening was fighting the page's own heading. */
    linear-gradient(to bottom,
      rgba(6,8,10,var(--screen-veil-corner)) 0%,
      rgba(6,8,10,var(--screen-veil-edge)) 34%,
      rgba(6,8,10,var(--screen-veil-edge)) 55%,
      rgba(6,8,10,0) var(--screen-veil-ends)),
    radial-gradient(70% 55% at 50% 42%,
      rgba(6,8,10,0) 0%, rgba(6,8,10,0) 100%);
}
#tm-closing{ opacity:0; }
#tm-opening .tm-kicker{
  font:600 11px/1 var(--font-body); letter-spacing:.28em; text-transform:uppercase; color:var(--accent-soft);
}
#tm-opening h2{
  /* it is inside a box now, not floating on the whole screen, so it wants to
     be a size that sits in that box rather than one that fills the window */
  margin:16px 0 14px; font:600 clamp(26px,4.6vw,48px)/1.08 var(--font-display);
  letter-spacing:-.02em; text-wrap:balance;
}
#tm-opening p, #tm-closing p{
  margin:0 auto; max-width:50ch;
  font:400 clamp(14px,1.5vw,16.5px)/1.65 var(--font-body); color:var(--text-quiet);
}
#tm-hint{
  margin-top:34px; font:600 10.5px/1 var(--font-body); letter-spacing:.22em; text-transform:uppercase;
  color:var(--text-quiet); display:flex; flex-direction:column; align-items:center; gap:12px;
}
#tm-hint svg{ animation:bob var(--hint-bob-speed) ease-in-out infinite; }
@keyframes bob{ 0%,100%{ transform:translateY(0); opacity:.5 } 50%{ transform:translateY(7px); opacity:1 } }
/* The panel both ends of the page sit in. It was the closing screen's; the
   opening screen now uses the same one, which is why the two ends read as the
   same object rather than two unrelated title cards. */
#tm-opening .tm-box, #tm-closing .tm-box{
  background:var(--panel); border:1px solid var(--panel-edge); border-radius:22px;
  padding:clamp(24px,4vw,40px); box-shadow:var(--shadow);
  backdrop-filter:blur(var(--panel-blur)); max-width:540px;
}
/* The opening box holds a heading rather than a line of totals, so it needs
   more room across and a little less air inside than the closing one did. */
/* A trail's own picture behind its opening panel. The veil is a gradient
   rather than a flat wash — lighter at the top where the kicker sits, heavier
   lower down where the paragraph is — so the picture is most visible exactly
   where there is least text over it. */
#tm-opening .tm-box.tm-hasImage{
  background-image:
    linear-gradient(to bottom,
      rgba(10,12,14,var(--opening-veil-top)),
      rgba(10,12,14,var(--opening-veil))),
    var(--opening-image);
  background-size:cover, cover;
  background-position:center, center;
}
/* THE PICTURE NEEDS ROOM OF ITS OWN.
   The trail's photograph is this panel's background, so every part of it that
   is not behind a word is the only part you actually look at. The panel is
   therefore wider than the words need and padded top and bottom by more than
   they need, which buys a clear band of picture above the kicker and below the
   scroll hint. The text block itself stays the same width it was — it is
   capped at 50ch — so widening the panel widens the picture, not the line
   length, which would have made it harder to read rather than easier. */
#tm-opening .tm-box{
  max-width:680px;
  padding:calc(clamp(26px,4.4vw,44px) + var(--opening-picture))
          clamp(24px,4vw,46px)
          calc(clamp(26px,4.4vw,44px) + var(--opening-picture));
}
#tm-closing h2{ margin:0 0 10px; font:600 clamp(22px,3.4vw,34px)/1.15 var(--font-display); }
#tm-closing .tm-row{ display:flex; gap:28px; justify-content:center; margin-top:22px; }

/* the little glyph on a corner link — what the button DOES, not where it goes */
.tm-linkIcon{ width:1.15em; height:1.15em; flex:none; opacity:.75; }





/* ── the corner title, over the new top veil ──────────────────────────────
   The veil at the top of a trail page sits UNDER the interface (shade is
   z-index 1, the interface 3) — that part was always right. What was wrong is
   that the title and kicker are dark ink, chosen back when there was nothing
   but pale paper behind them. Dark ink on a darkened band reads as the veil
   being ON TOP of the text, which is what it looked like.

   So over a veil they go light. The map page has no veil there and keeps its
   dark ink.

   NO DROP SHADOW. These carried one for a while — a tight dark halo, the trick
   every map uses on a label it cannot choose the background for. It did make
   the words hold up over pale artwork, and it looked like a compromise: soft
   edges on type this size read as a smudge rather than as depth. They are set
   in flat colour now. If a particular trail's artwork ever swallows the title,
   the fix is to darken the veil under it (--screen-veil-corner) rather than to
   put the shadow back — the background is the thing that is wrong in that
   case, not the letters. */
body.page-trail #tm-brand h1{
  color:var(--over-veil-ink);
}
body.page-trail #tm-brand .tm-kicker{
  color:var(--over-veil-kicker);
}
body.page-trail #tm-links a{
  color:var(--over-veil-ink);
  background:rgba(20,24,28,.42); border-color:rgba(255,255,255,.22);
}
body.page-trail #tm-links a:hover{ background:rgba(20,24,28,.62); }
body.page-trail.trail-wishful #tm-brand .tm-kicker{ color:var(--wishful-kicker-ink); }

/* ══ BUY ME A COFFEE ══════════════════════════════════════════════════════
   WHY THIS IS A LINK AND NOT THEIR WIDGET.

   Buy Me a Coffee offer a drop-in script that floats a button over the page.
   It is not used here, deliberately:

     · it is a third-party script on all sixteen pages, and this site currently
       loads NO external code at all — that is why it holds 55fps on a phone
     · it floats a fixed button over the bottom-left corner, which on a trail
       page is exactly where the readouts, the elevation graph and the new
       waypoint arrows already are
     · it loads their fonts and images, and sets cookies, on every visit from
       everyone, whether or not anybody ever clicks it

   A plain link costs nothing, cannot slow anything down, needs no cookie
   notice, and lands on the same page their button would have opened. If the
   widget is ever wanted instead, it is one <script> tag on each page — but
   check what it does to the corner controls first.

   The address lives in three places, all of them data rather than markup:
   WORDS.bar.links in trail-engine.js, WORDS.nav in index.html, and the three
   reading pages' own <nav>. Search for "buymeacoffee" to change it. */

/* The item in the navigation bar. NOT the yellow used on the button below:
   the bar is white, and Buy Me a Coffee's yellow on white is close to
   unreadable. It takes the site's own orange instead — the same one the
   current page's link uses — so it stays legible and stays in the family.
   The button in the support block keeps the yellow, because there it sits on
   a dark panel where the yellow is both legible and recognisably theirs. */
.tm-coffee, .ht-coffee{
  color:var(--coffee-nav) !important;
}
.tm-coffee:hover, .ht-coffee:hover{ color:var(--coffee-nav-hover) !important; }

/* THE LONG NAME AND THE SHORT ONE. "Buy me a coffee" is five words in a bar
   that already holds four links, and on a 420px phone the last of them ran off
   the right-hand edge — the bar does not wrap, and it should not: a navigation
   bar that becomes two lines pushes the whole page down.

   So the link is written twice and one of them is always hidden. Above 700px
   the full name shows; below it, just "Coffee", which says the same thing in a
   fifth of the room. Any link given a `short` in its settings gets the same
   treatment — nothing here names the coffee link in particular. */
.nav-short{ display:none; }
@media (max-width: 700px){
  .nav-full{ display:none; }
  .nav-short{ display:inline; }
}

/* the block at the foot of the About and Contact pages */
.pt-support{
  display:flex; gap:20px; align-items:flex-start;
  margin:var(--read-gap) 0 0; padding:22px 24px;
  border-radius:var(--panel-radius);
  background:var(--coffee-bg); border:1px solid var(--coffee-edge);
}
.pt-support h2{
  margin:0 0 7px; font:700 16px/1.25 var(--font-body); color:var(--text);
}
.pt-support p{
  margin:0 0 15px; max-width:56ch;
  font:400 13.5px/1.65 var(--font-body); color:var(--text-quiet);
}
.pt-cup{ width:34px; height:34px; flex:none; color:var(--coffee-ink); margin-top:2px; }
.pt-coffee{
  display:inline-flex; align-items:center; gap:8px;
  padding:10px 17px; border-radius:999px; text-decoration:none;
  font:700 11.5px/1 var(--font-body); letter-spacing:.1em; text-transform:uppercase;
  color:#221a06; background:var(--coffee-ink);
  transition:background var(--button-fade), transform var(--button-fade);
}
.pt-coffee:hover{ background:#fff; transform:translateY(-1px); }
@media (max-width: 700px){
  .pt-support{ flex-direction:column; gap:12px; padding:18px; }
}

/* ── the picture on a trail card ──────────────────────────────────────────
   A crop of that trail's own map — the same picture its page opens with, so
   arriving there looks like the thing you clicked. It is a background rather
   than an <img> because it is decoration, not content: the card already says
   in words what trail this is. */
.pt-shot{
  height:var(--shot-height); margin:-18px -18px 14px;
  border-radius:var(--panel-radius) var(--panel-radius) 0 0;
  background-size:cover; background-position:center;
  background-color:rgba(255,255,255,.04);
}

/* ── a wishful trail on the trails page ──────────────────────────────────
   Purple where the others are amber, so the two kinds are told apart before
   the words are read. */
.pt-card.is-wishful .pt-meta{ color:var(--wishful-kicker); }
.pt-card.is-wishful .pt-go{ background:var(--route-line-wish); color:#1a0c1f; }
.pt-card.is-wishful:hover .pt-go{ background:#fff; }
.pt-groupNote{
  margin:-4px 0 14px; max-width:60ch;
  font:400 13.5px/1.6 var(--font-body); color:var(--text-quiet);
}
/* A link inside that note. Nothing else on the site is a link in running text,
   so without this it came out in the browser's own blue with the browser's own
   underline — the one piece of the page that looked like it belonged to a
   different website. */
.pt-groupNote a{
  color:var(--accent); text-decoration:none;
  border-bottom:1px solid currentColor; padding-bottom:1px;
  transition:color var(--button-fade);
}
.pt-groupNote a:hover{ color:var(--text); }

/* ── WHERE ONE TRAIL MEETS ANOTHER ────────────────────────────────────────
   A button on the map at each junction, so you can follow the network rather
   than having to go back to the main map between trails. Blue, so it is
   plainly neither a waypoint (which is the accent colour) nor a wishful
   section (purple) — a third kind of thing, which is what it is.

   The circles these hang off are drawn BESIDE the route in the artwork, not
   on it, so a crossing button can never end up under a waypoint button. */
.tm-crossing .tm-cross{
  display:inline-flex; align-items:center; gap:6px;
  padding:5px 11px 5px 8px; border-radius:999px;
  text-decoration:none; white-space:nowrap;
  font:600 10px/1 var(--font-body); letter-spacing:.1em; text-transform:uppercase;
  color:#eaf2fb; background:var(--cross-bg); border:1px solid var(--cross-edge);
  box-shadow:var(--button-shadow);
  transition:background var(--button-fade), color var(--button-fade);
}
.tm-crossing .tm-cross svg{ width:14px; height:14px; opacity:.9; }
.tm-crossing .tm-cross:hover{ background:var(--cross-bg-hover); color:#fff; }

/* ── A WISHFUL TRAIL ──────────────────────────────────────────────────────
   A trail that does not exist yet is a KIND, not a variant: purple where a
   built trail is green, and consistently so — the route on the map, the line
   on the elevation graph, the kicker over the title, the walking point. One
   class does all of it, put on <body> by the engine when a page sets
   SETTINGS.trailKind = "wishful". Everything below is a colour swap and
   nothing else, which is what keeps the two kinds behaving identically. */
body.trail-wishful{
  --route-line:  var(--route-line-wish);
  --route-glow:  var(--route-glow-wish);
  --trail-walked: var(--route-line-wish);
  --accent-soft: var(--wishful-kicker);
}
body.trail-wishful #tm-walker .tm-dot{ background:var(--route-line-wish); }
body.trail-wishful #tm-walker .tm-ring{ border-color:var(--route-line-wish); }
/* (the kicker's colour is set with the rest of the over-the-veil ink above —
   it was set twice, and the weaker of the two never applied) */

/* ── the waypoint stepper ─────────────────────────────────────────────────
   Two arrows just above the readouts that step from one waypoint to the next.
   Grey rather than accent-coloured, and smaller than the rail buttons, on
   purpose: the rail buttons open panels, these only move you along, and the
   map is the thing meant to hold your attention. An arrow with nowhere to go
   is disabled rather than hidden, so the pair keeps its shape and the state
   reads as "you are at the end" rather than as something breaking. */
#tm-stepper{
  position:absolute; z-index:4;
  /* it belongs to the walk: the engine fades it with the readouts, so it is
     not sitting there offering to step through a trail you have not started */
  transition:opacity var(--button-fade);
  left:var(--edge-gap);
  bottom:calc(var(--band-bottom) + var(--stepper-drop));
  display:flex; gap:var(--stepper-gap);
}
.tm-step{
  width:var(--stepper-size); height:var(--stepper-size);
  display:grid; place-items:center; padding:0; cursor:pointer;
  border-radius:50%; color:var(--stepper-ink);
  background:var(--stepper-bg); border:1px solid var(--stepper-edge);
  transition:background var(--button-fade), color var(--button-fade),
             opacity var(--button-fade);
}
.tm-step svg{ width:56%; height:56%; }
.tm-step:hover:not(:disabled){ background:var(--stepper-bg-hover); color:#fff; }
.tm-step:disabled{ opacity:var(--stepper-off); cursor:default; }
.tm-step:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }

/* ── the invisible column you actually scroll ────────────────────────── */
#tm-scroller{ position:relative; z-index:2; height:var(--scroll-length); pointer-events:none; }

/* ── "turn your phone upright" ────────────────────────────────────────────
   Hidden always, except in the one media query that asks for it: a short
   window in landscape. Nothing in the page switches this on or off, so there
   is no state to keep in step — turn the phone back and it is simply gone. */
#tm-turn{ display:none; }
/* Phones only. Without the width and pointer tests this would also fire on a
   laptop whose window happens to be short and wide, which is a window someone
   chose and can resize — not a device that cannot be turned. `pointer:coarse`
   is the honest question here: is this a finger on a screen? */
@media (orientation: landscape) and (max-height: 520px)
   and (max-width: 950px) and (pointer: coarse){
  body.page-trail #tm-turn{
    display:grid; place-items:center; text-align:center;
    position:fixed; inset:0; z-index:80; padding:24px;
    background:var(--turn-veil);
  }
  body.page-trail #tm-turn .tm-box{
    background:var(--panel); border:1px solid var(--panel-edge); border-radius:20px;
    padding:24px 30px; box-shadow:var(--shadow); max-width:420px;
  }
  body.page-trail #tm-turn h2{
    margin:14px 0 8px; font:600 20px/1.2 var(--font-display);
  }
  body.page-trail #tm-turn p{
    margin:0; font:400 13px/1.55 var(--font-body); color:var(--text-quiet);
  }
  body.page-trail #tm-turn svg{ color:var(--accent); }
}

/* ── the coordinate reader (press E) ─────────────────────────────────── */
#tm-reader{ position:absolute; inset:0; z-index:5; display:none; pointer-events:auto; cursor:crosshair; }
#tm-reader.tm-open{ display:block; }
/* while reading coordinates, clear the interface but keep the trail visible */
body.tm-reading #tm-ui, body.tm-reading #tm-shade, body.tm-reading #tm-labels{
  opacity:0; transition:opacity var(--reader-fade);
}
#tm-readerPanel{
  position:absolute; right:var(--gutter); top:var(--gutter);
  width:min(420px,42vw); max-height:calc(100vh - var(--gutter) * 2);
  display:flex; flex-direction:column; gap:10px; padding:16px;
  background:var(--panel); border:1px solid var(--panel-edge); border-radius:16px;
  backdrop-filter:blur(var(--panel-blur));
}
#tm-readerPanel h3{
  margin:0; font:700 11px/1 var(--font-body); letter-spacing:.18em;
  text-transform:uppercase; color:var(--accent-soft);
}
#tm-readerPanel p{ margin:0; font:400 12px/1.55 var(--font-body); color:var(--text-quiet); }
#tm-readerPanel kbd{
  font:600 10.5px/1 var(--font-body); background:rgba(255,255,255,.1);
  border:1px solid var(--panel-edge); border-radius:5px; padding:3px 5px; color:var(--text);
}
#tm-readerOut{
  flex:1; min-height:150px; resize:vertical; width:100%;
  font:500 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; color:var(--text);
  background:rgba(0,0,0,.45); border:1px solid var(--panel-edge); border-radius:10px; padding:10px;
}
#tm-readerButtons{ display:flex; gap:8px; }
#tm-coords{
  position:absolute; left:var(--gutter); bottom:var(--gutter);
  padding:8px 12px; border-radius:10px;
  background:var(--panel); border:1px solid var(--panel-edge); backdrop-filter:blur(10px);
  font:600 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── the "something went wrong" screen ───────────────────────────────── */
#tm-problem{
  position:fixed; inset:0; z-index:9; display:none; place-items:center;
  padding:8vw; text-align:center; background:var(--backdrop);
}
#tm-problem.tm-open{ display:grid; }
#tm-problem p{ max-width:56ch; font:400 15px/1.75 var(--font-body); color:var(--text-quiet); }code,
code{ font:500 12.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color:var(--accent-soft); }

/* ── phones and small windows ────────────────────────────────────────── */
/* Only the regions change here. No element repeats its position on a phone —
   they all still read the same variables, so this block is the whole of the
   difference between the two layouts. */


/* ── the satellite view ───────────────────────────────────────────────────
   The photograph sits underneath the artwork at exactly the artwork's size.
   When the layer is on, the page puts .tm-satellite on <body> and a few things
   that were drawn for pale paper switch to their dark-ground versions.     */
#tm-satellite{
  position:absolute; top:0; left:0; display:none;
  user-select:none; -webkit-user-drag:none;
}
/* The flat picture of the artwork that phones walk on instead of the drawing
   itself — see flattenArtwork() in the page. It is laid over the drawing at
   exactly the drawing's size, so the two are interchangeable and everything
   that sits above them (the route, the waypoints, the chips) is unaffected. */
#tm-flatMap{
  position:absolute; top:0; left:0;
  user-select:none; -webkit-user-drag:none; pointer-events:none;
}
body.tm-satellite{
  /* the ground around the artwork, so panning past its edge is not a jolt */
  --backdrop: #23282b;
  /* The corner title, its kicker and the version are dark ink chosen for pale
     paper, and disappear against a photograph. Over the satellite they become
     their light-ground versions. This is the whole reason those three colours
     are named separately from the rest. */
  --over-map-ink:    #f4f2ee;
  --over-map-quiet:  #b9b2a4;
  --over-map-kicker: #e8b657;
  /* the not-yet-walked line was a dark brown for a cream map, and vanishes on
     a dark photograph — so it turns pale instead */
  --trail-ahead: rgba(255,255,255,.72);
  /* the photograph is already dark; less shading is needed over it */
  --shade-edges: .10;
  --shade-bottom: .42;
}
/* the name chips gain a touch more weight over busy imagery */
body.tm-satellite .tm-label .tm-tag{ background:rgba(10,12,14,.82); }

/* ── short windows ────────────────────────────────────────────────────────
   A laptop in a small window, or any screen turned on its side. There is not
   enough height for the bands to be generous, so they tighten and hand the
   room to the card column. Variables only again — nothing is repositioned. */


/* ── for people who ask their system to reduce motion ────────────────── */


/* ── the main map's own pieces ─────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   HAPPY TRAILS — stylesheet
   version 4.1

   Built to match the scrolling trail map, so the two pages read as one site.
   The variables below are deliberately named the same as that page's, and the
   shared pieces — the navigation bar, the left rail, the panel, the layer
   switches, the legend — are the same values in both files. Change one and
   change the other.

   Everything you are likely to want to change lives in the :root block. Below
   it is plain layout, grouped and labelled.
   ═══════════════════════════════════════════════════════════════════════════ */



/* the main map: it fills the window and nothing scrolls. Nothing on it is
   meant to be selected either — a drag is a pan, and a double-click on a route
   button should not leave a blue highlight behind. The one exception is the
   coordinate readout, which turns selection back on for itself. */
body.page-map{
  background:var(--map-backdrop);
  overflow:hidden;
  user-select:none; -webkit-user-select:none;
  -webkit-tap-highlight-color:transparent;
}
img{ -webkit-user-drag:none; user-drag:none; }
#ht-brand{
  font:700 var(--bar-brand-size)/1 var(--font-body); letter-spacing:.01em;
  color:var(--bar-brand); text-decoration:none; white-space:nowrap;
}
#ht-nav{ display:flex; gap:var(--bar-link-gap); }
#ht-nav a{
  font:500 var(--bar-link-size)/1 var(--font-body);
  letter-spacing:.09em; text-transform:uppercase; white-space:nowrap;
  color:var(--bar-text); text-decoration:none;
  transition:color var(--button-fade);
}
#ht-nav a:hover{ color:var(--bar-here); }
/* the page you are on. The class name matches what writeWords() writes —
   these two drifted apart in 2.0 and the marker quietly stopped appearing. */
#ht-nav a.is-here{
  color:var(--bar-here); text-decoration:underline; text-underline-offset:4px;
}

/* ── the corner title, over the map ──────────────────────────────────────
   The top band. Its height is --band-top, which is what the rail below it
   measures down from — so restyling the title carries the rail with it. */
#ht-topbar{
  position:fixed; top:var(--bar-height); left:0; right:0; z-index:30;
  min-height:var(--band-top);
  display:flex; gap:16px; align-items:flex-start; justify-content:space-between;
  padding:var(--title-pad) var(--edge-gap);
  pointer-events:none;                 /* the map underneath stays draggable */
}
#ht-brandline{ max-width:52ch; }
#ht-brandline .ht-kicker{
  font:600 10.5px/1 var(--font-body); letter-spacing:.22em; text-transform:uppercase;
  color:var(--over-map-kicker); margin-bottom:8px;
  text-shadow:0 1px 6px rgba(0,0,0,.7);
}
#ht-brandline h1{
  margin:0; font:700 clamp(15px,2.1vw,21px)/1.25 var(--font-body); letter-spacing:-.01em;
  color:var(--over-map-ink); text-shadow:0 1px 8px rgba(0,0,0,.75);
}
#ht-version{
  font:500 10px/1 var(--font-body); letter-spacing:.14em;
  color:var(--over-map-quiet); text-shadow:0 1px 6px rgba(0,0,0,.7);
}
#ht-links a{
  pointer-events:auto; cursor:pointer;
  font:600 var(--trail-link-size)/1 var(--font-body);
  letter-spacing:.11em; text-transform:uppercase; text-decoration:none;
  color:var(--text);
  background:rgba(18,20,23,.62); border:1px solid var(--panel-edge);
  padding:6px 10px; border-radius:999px; backdrop-filter:blur(6px);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}

/* ── the map stage: everything below the bar ─────────────────────────────── */
#ht-stage{
  position:fixed; top:var(--bar-height); left:0; right:0; bottom:0; z-index:0;
  overflow:hidden; background:var(--map-backdrop);
  cursor:grab; touch-action:none;
}
#ht-stage.is-dragging{ cursor:grabbing; }
#ht-world svg{ display:block; }

/* ── the trail pins ──────────────────────────────────────────────────────── */
#ht-pins{ position:absolute; inset:0; }
/* Centred on the point given, in both directions. No stem: the button sits ON
   its route, so there is nothing to line up and nothing pointing at empty
   ground. The engine writes --pin-counter each frame (1/zoom, so the button
   holds its size on screen); the hover lift multiplies that rather than
   replacing it, which is why both can happen at once. */
.ht-pin{
  position:absolute; z-index:5; text-decoration:none;
  transform-origin:50% 50%;
  transform:translate(-50%, -50%) scale(var(--pin-counter, 1));
  padding:5px 11px; border-radius:var(--pin-radius);
  background:var(--pin-green); color:var(--pin-text);
  font:700 var(--pin-size)/1 var(--font-body); letter-spacing:.02em;
  white-space:nowrap; box-shadow:0 3px 10px rgba(0,0,0,.45);
  transition:filter var(--button-fade), box-shadow var(--button-fade);
}
.ht-pin[hidden]{ display:none; }
.ht-pin.is-purple{ background:var(--pin-purple); color:var(--pin-text-purple); }
.ht-pin:hover, .ht-pin:focus-visible{
  transform:translate(-50%, -50%)
            scale(calc(var(--pin-counter, 1) * var(--pin-lift)));
  filter:brightness(1.08);
  box-shadow:0 5px 16px rgba(0,0,0,.55);
}
.ht-pin:focus-visible{ outline:2px solid #fff; outline-offset:2px; }

/* ── THE LEFT RAIL ────────────────────────────────────────────────────────
   The compass and the two panel buttons in one fixed column. Nothing in here
   ever moves, which is what keeps the buttons attached to the panel they
   open. Same construction as the trail map's rail. */
#ht-rail{
  position:fixed; z-index:35;
  left:var(--edge-gap);
  top:calc(var(--bar-height) + var(--band-top) + var(--rail-top));
  display:flex; flex-direction:column; gap:var(--rail-gap);
}

/* the north badge. The map is drawn north-up, so the needle never turns. */
#ht-compass{
  width:var(--compass-size); height:var(--compass-size); border-radius:50%;
  display:grid; place-items:center;
  background:var(--panel); border:1px solid var(--panel-edge);
  backdrop-filter:blur(var(--panel-blur)); box-shadow:var(--button-shadow);
}

.ht-railBtn{
  cursor:pointer; padding:0;
  width:var(--compass-size); height:var(--compass-size); border-radius:50%;
  display:grid; place-items:center;
  background:var(--panel); border:1px solid var(--panel-edge);
  color:var(--text-quiet);
  backdrop-filter:blur(var(--panel-blur)); box-shadow:var(--button-shadow);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}

/* ── the one panel both buttons open ─────────────────────────────────────── */
#ht-panel{
  position:fixed; z-index:35;
  left:calc(var(--edge-gap) + var(--compass-size) + var(--panel-gap));
  top:calc(var(--bar-height) + var(--band-top) + var(--rail-top));
  width:var(--panel-width);
  max-height:calc(100vh - var(--bar-height) - var(--band-top)
                        - var(--rail-top) - var(--gutter));
  display:flex; flex-direction:column;
  background:var(--panel-bg); border:1px solid var(--panel-edge);
  border-radius:var(--panel-radius); box-shadow:var(--shadow);
  backdrop-filter:blur(var(--panel-bg-blur));
  overflow:hidden;
  transform-origin:0 0;

  /* THE CLOSED STATE. All three of these matter:
       opacity        makes it fade rather than vanish
       visibility     takes it out of the accessibility tree, and — with the
                      0s delay below — waits until the fade has finished
       pointer-events stops it catching clicks and drags while it is invisible

     That last one was the bug: a panel at opacity 0 is still a solid pane as
     far as the pointer is concerned, so a closed panel sat over the map
     swallowing clicks and swallowing drags across a third of the window. The
     `hidden` attribute alone does NOT fix it — an element with a display of
     its own overrides what [hidden] would do — which is why the rule below
     spells that out too. */
  opacity:0; transform:translateX(-10px) scale(.98);
  visibility:hidden; pointer-events:none;
  transition:opacity var(--panel-slide) var(--panel-ease),
             transform var(--panel-slide) var(--panel-ease),
             width var(--panel-slide) var(--panel-ease),
             visibility 0s linear var(--panel-slide);
}
#ht-panel.is-open{
  opacity:1; transform:none;
  visibility:visible; pointer-events:auto;
  transition:opacity var(--panel-slide) var(--panel-ease),
             transform var(--panel-slide) var(--panel-ease),
             width var(--panel-slide) var(--panel-ease),
             visibility 0s;
}
#ht-panel.is-layers{ width:var(--panel-width-wide); }
.ht-close{
  width:24px; height:24px; padding:0; border-radius:50%;
  display:grid; place-items:center; cursor:pointer;
  font:400 16px/1 var(--font-body); color:var(--text);
  background:rgba(8,10,12,.55); border:1px solid var(--panel-edge);
  transition:background var(--button-fade), transform var(--button-fade);
}
#ht-panelBody{ overflow:auto; overscroll-behavior:contain; padding:0 16px 16px; }

/* ── the layer switches ──────────────────────────────────────────────────
   The same sliding switches as the trail map's Layers panel. */
.ht-groupTitle{
  margin:18px 0 9px; font:700 9.5px/1 var(--font-body);
  letter-spacing:.16em; text-transform:uppercase; color:var(--text-faint);
}
.ht-groupTitle:first-child{ margin-top:0; }
/* two columns, so the whole set is visible without a scroll bar. The count is
   --switch-columns; nothing in the HTML knows about it. */
.ht-switches{
  display:grid; gap:var(--switch-gap);
  grid-template-columns:repeat(var(--switch-columns), minmax(0, 1fr));
}
.ht-switch{
  display:flex; align-items:flex-start; gap:9px; width:100%; text-align:left;
  padding:9px 10px; border-radius:11px; cursor:pointer;
  background:rgba(255,255,255,.045); border:1px solid var(--panel-edge);
  transition:background var(--button-fade), border-color var(--button-fade);
}
.ht-switchText{ min-width:0; }
.ht-switchText b{ display:block; font:600 12px/1.25 var(--font-body); color:var(--text); }
.ht-switchText small{
  display:block; margin-top:3px;
  font:400 10.5px/1.35 var(--font-body); color:var(--text-quiet);
}

/* ── the reset button, at the foot of the Layers panel ───────────────────── */
.ht-reset{
  margin-top:14px; width:100%; cursor:pointer;
  padding:9px 12px; border-radius:11px;
  background:rgba(255,255,255,.06); border:1px solid var(--panel-edge);
  color:var(--text-quiet);
  font:600 10px/1 var(--font-body); letter-spacing:.16em; text-transform:uppercase;
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}
.ht-reset:hover{ color:#fff; background:var(--accent); border-color:transparent; }
.ht-reset:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:2px; }

/* ── the round zoom controls ─────────────────────────────────────────────
   Bottom right, so they sit opposite the rail rather than competing with it.
   Same round dark-glass button as the rail uses. */
#ht-controls{
  position:fixed; right:var(--edge-gap); bottom:var(--edge-gap); z-index:35;
  display:flex; flex-direction:column; gap:var(--control-gap);
}
.ht-control{
  width:var(--control-size); height:var(--control-size); border-radius:50%;
  border:1px solid var(--panel-edge); cursor:pointer;
  background:var(--panel); color:var(--text-quiet);
  display:grid; place-items:center;
  backdrop-filter:blur(var(--panel-blur)); box-shadow:var(--button-shadow);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}
.ht-control:hover{ color:#fff; background:var(--accent); border-color:transparent; }
/* the small press when one is clicked. The map's own easing does the rest —
   see SETTINGS.buttonGlide. */
.ht-control.is-pressed{
  transform:scale(.88);
  transition:transform .1s var(--panel-ease);
}
.ht-control{ transition:color var(--button-fade), background var(--button-fade),
                        border-color var(--button-fade), transform .22s var(--panel-ease); }
.ht-control:disabled{ opacity:.4; cursor:default; background:var(--panel); color:var(--text-quiet); }
.ht-control:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:3px; }
.ht-control svg{ width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.7; }
.ht-control .ht-11{ font:700 10px/1 var(--font-body); letter-spacing:.08em; }

/* ── the footnotes along the bottom ──────────────────────────────────────── */
.ht-note{
  position:fixed; bottom:var(--edge-gap); z-index:20;
  font:500 var(--note-size)/1.4 var(--font-body); color:var(--text);
  text-shadow:0 1px 6px rgba(0,0,0,.85);
  pointer-events:none;
}
#ht-hint{ left:var(--edge-gap); max-width:44vw; opacity:.85; }

/* ── the coordinate readout (press C) ────────────────────────────────────── */
#ht-coords{
  /* the one thing you are meant to be able to select and copy */
  user-select:text; -webkit-user-select:text;
  position:fixed; left:var(--edge-gap); bottom:calc(var(--edge-gap) + 30px); z-index:36;
  display:none; padding:8px 12px; border-radius:10px;
  background:var(--panel); border:1px solid var(--panel-edge);
  backdrop-filter:blur(var(--panel-blur));
  font:600 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color:var(--text);
}
#ht-coords.is-on{ display:block; }

/* ── the "something went wrong" screen ───────────────────────────────────── */
#ht-problem{
  position:fixed; inset:0; z-index:60; display:none; place-items:center;
  padding:8vw; text-align:center; background:var(--map-backdrop); color:var(--text-quiet);
}
#ht-problem.is-on{ display:grid; }
#ht-problem p{ max-width:56ch; font:400 15px/1.75 var(--font-body); }

/* ── phones and small windows ────────────────────────────────────────────
   Region variables only, the way the trail map does it — no element repeats
   its position here. */


/* ── short windows ────────────────────────────────────────────────────────
   A laptop in a small window. The top band gives up some air and the switches
   tighten, which buys the panel enough height to show the whole set without a
   scroll bar for a good deal further down. Below about 700px tall it scrolls
   anyway, which is the right answer at that size. */



/* ═══ ④  THE READING PAGES ═════════════════════════════════════════════════
   Trails, About and Contact. They share the navigation bar with the two map
   pages and nothing else: these scroll, hold long text, and want a comfortable
   measure rather than a full-bleed drawing. The palette is the same one, so
   they read as the same site.
   ═══════════════════════════════════════════════════════════════════════════ */

body.page-text{
  overflow:auto; overscroll-behavior:auto;
  background:var(--map-backdrop); color:var(--text);
  user-select:text; -webkit-user-select:text;
}
body.page-text main{
  max-width:var(--read-width);
  margin:0 auto;
  padding:calc(var(--bar-height) + var(--read-top)) var(--edge-gap) 96px;
}

/* the page's own title block, matching the corner title on the map pages */
.pt-head{ margin:0 0 var(--read-gap); }
.pt-kicker{
  font:600 10.5px/1 var(--font-body); letter-spacing:.22em; text-transform:uppercase;
  color:var(--over-map-kicker); margin-bottom:10px;
}
.pt-head h1{
  margin:0; font:700 clamp(26px, 4.6vw, 40px)/1.15 var(--font-body);
  letter-spacing:-.02em; color:var(--text);
}
.pt-lede{
  margin:14px 0 0; max-width:62ch;
  font:400 clamp(15px, 1.6vw, 17px)/1.7 var(--font-body); color:var(--text-quiet);
}

/* a section of prose */
.pt-section{ margin-top:var(--read-gap); }
.pt-section h2{
  margin:0 0 14px; font:700 clamp(18px, 2.4vw, 23px)/1.25 var(--font-body);
  letter-spacing:-.01em; color:var(--text);
}
.pt-section h3{
  margin:26px 0 10px; font:700 11px/1 var(--font-body);
  letter-spacing:.16em; text-transform:uppercase; color:var(--accent-soft);
}
.pt-section p{
  margin:0 0 15px; max-width:68ch;
  font:400 15px/1.75 var(--font-body); color:var(--text-quiet);
}
.pt-section p strong{ color:var(--text); font-weight:600; }
.pt-section a{ color:var(--bar-here); text-decoration:underline; text-underline-offset:3px; }

/* a picture inside the prose */
.pt-figure{ margin:22px 0 6px; }
.pt-figure img, .pt-figure video{
  display:block; width:100%; height:auto; border-radius:var(--panel-radius);
  background:#111; border:1px solid var(--panel-edge);
}
.pt-figure figcaption{
  margin-top:9px; font:400 12.5px/1.6 var(--font-body); color:var(--text-faint);
}

/* ── the list of trails ────────────────────────────────────────────────────
   One card per trail, in a grid that becomes a single column when there is no
   room for two. The whole card is the link to that trail's page. */
.pt-group{ margin-top:var(--read-gap); }
.pt-groupTitle{
  margin:0 0 14px; font:700 10.5px/1 var(--font-body);
  letter-spacing:.18em; text-transform:uppercase; color:var(--accent-soft);
}
/* ── HOW MANY COLUMNS ─────────────────────────────────────────────────────
   Two at most, ever — three made the cards too small to read and the pictures
   too small to be worth having. But a group holding ONE trail gives that trail
   the full width, because a lone card in a two-column grid leaves an obvious
   hole beside it.

   The count is asked of the DOM rather than written down per section, so
   adding trails later needs no CSS: `:has(> :nth-child(2))` is true only when
   a second card exists. One rule covers every group, now and later. */
.pt-cards{
  display:grid; gap:14px;
  grid-template-columns:1fr;                    /* one trail: full width */
}
.pt-cards:has(> :nth-child(2)){
  grid-template-columns:repeat(2, minmax(0, 1fr));   /* two or more: two columns */
}

/* On a phone, two of anything is one too many. Two columns of a 420px screen
   leaves each card about 180px wide — narrower than the picture inside it
   wants to be, and the trail names start breaking mid-word. "Two columns
   maximum" is a ceiling, not a floor, so below 700px the ceiling comes down
   to one and the rule above stops applying. */
@media (max-width: 700px){
  .pt-cards, .pt-cards:has(> :nth-child(2)){ grid-template-columns:1fr; }
}
.pt-card{
  display:flex; flex-direction:column;
  padding:18px 18px 16px; border-radius:var(--panel-radius);
  background:var(--panel-bg); border:1px solid var(--panel-edge);
  text-decoration:none; color:inherit;
  transition:border-color var(--button-fade), background var(--button-fade),
             transform var(--button-fade);
}
.pt-card:hover{
  border-color:var(--bar-here); background:rgba(255,255,255,.05);
  transform:translateY(-2px);
}
.pt-card:focus-visible{ outline:2px solid var(--accent-soft); outline-offset:3px; }
.pt-card{ position:relative; }
.pt-card h3{
  margin:0 0 6px; font:700 17px/1.2 var(--font-body); color:var(--text);
  letter-spacing:-.01em;
}
/* The trail's name is the link, and this stretches it across the whole card so
   the card feels clickable — without putting one <a> inside another, which is
   invalid and which browsers pull apart. The small buttons sit above it. */
.pt-card h3 a{ color:inherit; text-decoration:none; }
.pt-open::after{ content:""; position:absolute; inset:0; border-radius:inherit; }
.pt-links{ position:relative; z-index:1; }
.pt-card .pt-meta{
  font:600 9.5px/1 var(--font-body); letter-spacing:.15em; text-transform:uppercase;
  color:var(--over-map-kicker); margin-bottom:9px;
}
.pt-card p{ margin:0; font:400 13.5px/1.65 var(--font-body); color:var(--text-quiet); }
/* ── OPEN THE TRAIL ───────────────────────────────────────────────────────
   The one thing a card is for. It was a line of small caps that read as a
   caption; it is now a filled button, because the reference links beside it
   are secondary and the card should say which of the three matters. It is
   NOT an <a> — the whole card is already the link (see the stretched overlay
   above) — so it is a button-shaped label that the card's own link activates,
   which is what keeps one anchor inside another from happening. */
/* pointer-events:none is not decoration — it is the FIX for a real bug.
   The whole card is the link (a stretched overlay on .pt-open). This button is
   a LABEL for that link, not a control of its own. Without this it swallowed
   the click: it carries a hover transform, a transform makes a new stacking
   context, and a new stacking context lifted it above the overlay — but only
   while the pointer was on it. So the card worked everywhere except on the one
   part of it that said "Open the trail", and any static inspection of the
   stacking showed nothing wrong, because the transform is not applied until
   the cursor arrives. */
.pt-card .pt-go{
  pointer-events:none;
  margin-top:15px; align-self:flex-start;
  display:inline-flex; align-items:center; gap:7px;
  padding:9px 15px; border-radius:999px;
  font:700 11px/1 var(--font-body); letter-spacing:.12em; text-transform:uppercase;
  color:#12161a; background:var(--accent-soft);
  border:1px solid transparent;
  transition:background var(--button-fade), transform var(--button-fade);
}
.pt-card:hover .pt-go{ background:#fff; transform:translateX(2px); }

/* The reference links are deliberately quieter than that button: they are
   somewhere else to go, not the thing this card is offering. */
.pt-links{
  margin-top:11px; display:flex; flex-wrap:wrap; gap:14px;
  font:500 11px/1 var(--font-body);
}
.pt-links a{
  color:var(--text-faint); text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.16); padding-bottom:2px;
}
.pt-links a:hover{ color:var(--text); border-bottom-color:currentColor; }
/* a trail with no page of its own yet: still listed, but plainly not a link */
.pt-card.is-soon{ opacity:.62; }
/* a trail with no page yet keeps the shape but not the invitation */
.pt-card.is-soon .pt-go{
  color:var(--text-faint); background:transparent;
  border-color:var(--panel-edge);
}

/* the small link buttons under a trail's name, matching the map pages' */
.pt-links{ display:flex; flex-wrap:wrap; gap:var(--trail-link-gap); margin-top:13px; }
.pt-links a{
  font:600 var(--trail-link-size)/1 var(--font-body);
  letter-spacing:.11em; text-transform:uppercase; text-decoration:none;
  color:var(--text); background:rgba(255,255,255,.07);
  border:1px solid var(--panel-edge); padding:6px 10px; border-radius:999px;
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade);
}
.pt-links a:hover{ color:#fff; background:var(--accent); border-color:transparent; }

/* ── the contact page ──────────────────────────────────────────────────── */
.pt-contact{
  margin-top:var(--read-gap); padding:26px;
  border-radius:var(--panel-radius);
  background:var(--panel-bg); border:1px solid var(--panel-edge);
  max-width:520px;
}
.pt-contact label{
  display:block; margin-bottom:6px;
  font:600 9.5px/1 var(--font-body); letter-spacing:.15em; text-transform:uppercase;
  color:var(--text-faint);
}
.pt-field{ margin-bottom:16px; }
.pt-contact input, .pt-contact textarea{
  width:100%; padding:11px 13px; border-radius:11px;
  background:rgba(0,0,0,.35); border:1px solid var(--panel-edge);
  color:var(--text); font:400 14px/1.5 var(--font-body);
  transition:border-color var(--button-fade);
}
.pt-contact input:focus, .pt-contact textarea:focus{
  outline:none; border-color:var(--bar-here);
}
.pt-contact textarea{ min-height:132px; resize:vertical; }
.pt-send{
  cursor:pointer; padding:12px 22px; border-radius:999px;
  background:var(--accent); border:1px solid transparent; color:#fff;
  font:700 10.5px/1 var(--font-body); letter-spacing:.16em; text-transform:uppercase;
  transition:filter var(--button-fade);
}
.pt-send:hover{ filter:brightness(1.1); }
.pt-mail{
  margin-top:20px; font:400 14px/1.7 var(--font-body); color:var(--text-quiet);
}
.pt-mail a{ color:var(--bar-here); }

/* the footer every reading page ends with */
.pt-foot{
  margin-top:60px; padding-top:22px; border-top:1px solid var(--panel-edge);
  font:400 12px/1.7 var(--font-body); color:var(--text-faint);
  display:flex; flex-wrap:wrap; gap:16px; justify-content:space-between;
}
.pt-foot a{ color:var(--text-quiet); text-decoration:none; }
.pt-foot a:hover{ color:var(--bar-here); }


/* ═══════════════════════════════════════════════════════════════════════════
   THE WISHFUL THINKING PAGE — body.page-wishful
   ═══════════════════════════════════════════════════════════════════════════
   A reading page with a control panel on top of it. It borrows the reading
   pages' head, footer and card shape, and adds the only thing it really needs
   of its own: two sliders and a sort, and cards that rearrange under them.

   THE NUMBERS FOR THIS PAGE, in one block as everywhere else. */
body.page-wishful{
  --wt-card-min:       300px;  /* narrower than this and a card gets two columns
                                  of nothing; wider and three never fit         */
  --wt-gap:            16px;
  --wt-shot-height:    150px;  /* the picture at the top of a card              */
  --wt-radius:         14px;
  --wt-in:             300ms;  /* how long a card takes to arrive               */
  --wt-out:            150ms;  /* and to shrink away. Shorter, on purpose: you
                                  are waiting for what is left, not watching
                                  what has gone.                                */
  --wt-ease:           cubic-bezier(.22,.9,.28,1);   /* quick out, soft landing */
  --wt-track:          6px;    /* the thickness of a slider's groove            */
  --wt-thumb:          22px;
  --wt-panel:          rgba(255,255,255,.035);

  /* the three levels, wherever they are shown as colour. The cost colours are
     the coins' own metals so the slider and the icons agree; the priority
     colours are the gauge's three zones, for the same reason. */
  --wt-low:            #c8804a;
  --wt-medium:         #c9ccd2;
  --wt-high:           #d9ab48;
  --wt-pri-low:        #4ecf4e;
  --wt-pri-medium:     #e6e2d8;
  --wt-pri-high:       #e8503a;
}

/* ── THE CONTROLS ──────────────────────────────────────────────────────── */
.wt-controls{
  margin:26px 0 24px; padding:20px 22px 16px;
  border:1px solid var(--panel-edge); border-radius:var(--panel-radius);
  background:var(--wt-panel);
}
.wt-sliders{
  display:grid; gap:26px 40px;
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr));
}
.wt-slider label{
  display:flex; align-items:baseline; gap:10px;
  font:600 10px/1 var(--font-body); letter-spacing:.2em; text-transform:uppercase;
  color:var(--text-quiet);
}
/* the value the slider is currently at, said in words beside its name. A
   slider with no readout is a slider you have to guess at. */
.wt-slider label b{
  font:600 13px/1 var(--font-body); letter-spacing:0; text-transform:none;
  color:var(--text);
}

/* THE SLIDER ITSELF.
   Ranges are one of the few controls browsers will not style consistently, so
   the track and the thumb are written out for both engines. The thumb takes
   the colour of the level it is sitting on — which is the same colour as the
   coin or the gauge zone that level uses on the cards, so moving the slider to
   "high" turns it the colour of the things it is about to show. */
.wt-slider input[type=range]{
  -webkit-appearance:none; appearance:none;
  width:100%; margin:12px 0 6px; background:transparent; cursor:pointer;
}
.wt-slider input[type=range]:focus{ outline:none; }
.wt-slider input[type=range]:focus-visible{
  outline:2px solid var(--accent-soft); outline-offset:6px; border-radius:4px;
}
.wt-slider input[type=range]::-webkit-slider-runnable-track{
  height:var(--wt-track); border-radius:999px;
  background:linear-gradient(to right, rgba(255,255,255,.10), rgba(255,255,255,.22));
}
.wt-slider input[type=range]::-moz-range-track{
  height:var(--wt-track); border-radius:999px;
  background:linear-gradient(to right, rgba(255,255,255,.10), rgba(255,255,255,.22));
}
.wt-slider input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none;
  width:var(--wt-thumb); height:var(--wt-thumb); border-radius:50%;
  margin-top:calc((var(--wt-track) - var(--wt-thumb)) / 2);
  background:var(--text); border:2px solid rgba(0,0,0,.45);
  box-shadow:0 2px 6px rgba(0,0,0,.5);
  transition:background var(--button-fade), transform var(--button-fade);
}
.wt-slider input[type=range]::-moz-range-thumb{
  width:var(--wt-thumb); height:var(--wt-thumb); border-radius:50%;
  background:var(--text); border:2px solid rgba(0,0,0,.45);
  box-shadow:0 2px 6px rgba(0,0,0,.5);
  transition:background var(--button-fade), transform var(--button-fade);
}
.wt-slider input[type=range]:hover::-webkit-slider-thumb{ transform:scale(1.14); }
.wt-slider input[type=range]:hover::-moz-range-thumb{ transform:scale(1.14); }
.wt-slider input[type=range]:active::-webkit-slider-thumb{ transform:scale(1.22); }

/* the thumb wears the level it is on — written twice because neither engine
   will accept the other's selector in the same rule */
#wt-cost[data-level=low]::-webkit-slider-thumb{ background:var(--wt-low); }
#wt-cost[data-level=medium]::-webkit-slider-thumb{ background:var(--wt-medium); }
#wt-cost[data-level=high]::-webkit-slider-thumb{ background:var(--wt-high); }
#wt-cost[data-level=low]::-moz-range-thumb{ background:var(--wt-low); }
#wt-cost[data-level=medium]::-moz-range-thumb{ background:var(--wt-medium); }
#wt-cost[data-level=high]::-moz-range-thumb{ background:var(--wt-high); }
#wt-priority[data-level=low]::-webkit-slider-thumb{ background:var(--wt-pri-low); }
#wt-priority[data-level=medium]::-webkit-slider-thumb{ background:var(--wt-pri-medium); }
#wt-priority[data-level=high]::-webkit-slider-thumb{ background:var(--wt-pri-high); }
#wt-priority[data-level=low]::-moz-range-thumb{ background:var(--wt-pri-low); }
#wt-priority[data-level=medium]::-moz-range-thumb{ background:var(--wt-pri-medium); }
#wt-priority[data-level=high]::-moz-range-thumb{ background:var(--wt-pri-high); }

/* THE FOUR STOPS ARE BUTTONS.
   They began as labels — the slider said what its positions meant, and people
   clicked them anyway, because a word under a slider that names a value looks
   like a thing you can pick. So they are what they look like. Clicking one
   sends the thumb to it, travelling rather than jumping, so the connection
   between the word and the control is visible.

   They sit lower than the labels did, which is the room the hover state needs
   to land in without touching the groove above it. */
.wt-ticks{
  display:flex; justify-content:space-between;
  margin-top:8px;
}
.wt-ticks button{
  font:600 9.5px/1 var(--font-body); letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-faint); background:transparent; border:1px solid transparent;
  padding:6px 9px; margin:0 -9px; border-radius:999px; cursor:pointer;
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade), transform var(--button-fade);
}
.wt-ticks button:hover{
  color:var(--text); background:rgba(255,255,255,.08);
  border-color:var(--panel-edge); transform:translateY(-1px);
}
.wt-ticks button:active{ transform:translateY(0); }
.wt-ticks button:focus-visible{
  outline:2px solid var(--accent-soft); outline-offset:1px;
}
/* the stop the slider is currently on */
.wt-ticks button.is-on{ color:var(--text); }

/* ── SORT, AND RESET ───────────────────────────────────────────────────── */
.wt-sortRow{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  margin-top:20px; padding-top:16px; border-top:1px solid var(--panel-edge);
}
.wt-sortLabel{
  font:600 10px/1 var(--font-body); letter-spacing:.2em; text-transform:uppercase;
  color:var(--text-quiet);
}
.wt-sort{ display:flex; gap:6px; flex-wrap:wrap; }
.wt-sort button, .wt-reset{
  font:600 11px/1 var(--font-body); letter-spacing:.06em;
  padding:8px 13px; border-radius:999px; cursor:pointer;
  color:var(--text-quiet); background:transparent;
  border:1px solid var(--panel-edge);
  transition:color var(--button-fade), background var(--button-fade),
             border-color var(--button-fade), transform var(--button-fade);
}
.wt-sort button:hover, .wt-reset:hover{
  color:var(--text); border-color:var(--accent-soft); transform:translateY(-1px);
}
.wt-sort button:active, .wt-reset:active{ transform:translateY(0); }
/* A shortcut lights up when the sliders are where it would put them, however
   they got there — dragged, typed or clicked. It is a reading of the state,
   not a record of what was pressed, so it can never disagree with the sliders
   the way a remembered "current tab" can. */
.wt-sort button.is-on{
  color:#1d2124; background:var(--accent); border-color:transparent;
}
.wt-reset{ margin-left:auto; }
.wt-count{
  margin:14px 0 0; font:500 12px/1 var(--font-body); color:var(--text-faint);
}

/* ── THE LIST ──────────────────────────────────────────────────────────── */
/* A grid rather than a flow, and the cards are re-ORDERED rather than moved:
   the script writes a CSS `order` on each one. Nothing is destroyed and
   rebuilt, so pictures stay loaded, focus stays where it was, and a card can
   fade rather than blink. */
.wt-list{
  display:grid; gap:var(--wt-gap);
  grid-template-columns:repeat(auto-fill, minmax(var(--wt-card-min), 1fr));
}
/* A CARD HAS THREE STATES, and the middle one is why it can be animated away.
     resting (no class)  it is in the layout, not yet arrived
     .is-in              arrived: full size, full opacity
     .is-leaving         still in the layout, shrinking and fading
     .is-out             gone from the layout entirely
   Leaving is a state rather than a removal because a card taken out of a grid
   the instant it stops matching simply blinks out, and everything after it
   jumps into the hole. It shrinks first, and the hole closes afterwards. */
.wt-card{
  display:flex; flex-direction:column; position:relative;
  border:1px solid var(--panel-edge); border-radius:var(--wt-radius);
  background:var(--panel-bg); overflow:hidden;
  opacity:0; transform:translateY(10px) scale(.97);
  transition:opacity var(--wt-in) var(--wt-ease),
             transform var(--wt-in) var(--wt-ease),
             border-color var(--button-fade);
}
.wt-card.is-in{ opacity:1; transform:none; }
.wt-card.is-leaving{
  opacity:0; transform:scale(.9);
  /* out faster than in, and from wherever it is rather than after a queue —
     leaving should feel like a dismissal, arriving like an arrival */
  transition-duration:var(--wt-out); transition-delay:0ms !important;
  pointer-events:none;
}
/* A CARD THAT IS FILTERED OUT LEAVES THE LAYOUT.
   This rule is the fix for the holes in the grid. The script also sets the
   `hidden` attribute, and `hidden` alone did nothing here: the browser's own
   [hidden]{display:none} is a single attribute selector, and .wt-card above
   sets display:flex with a class — which wins. So every filtered-out card kept
   its cell in the grid, invisible and one column wide, and the ones still
   showing were pushed into whatever spaces were left. */
.wt-card.is-out, .wt-card[hidden]{ display:none !important; }
.wt-card:hover{ border-color:var(--accent-soft); }
.wt-shot{
  height:var(--wt-shot-height); background-size:cover; background-position:center;
  border-bottom:1px solid var(--panel-edge);
  transition:transform 520ms var(--panel-ease);
}
/* the picture leans in a little when the card is pointed at. Small on purpose:
   it should register as the card noticing you, not as an animation. */
.wt-card:hover .wt-shot{ transform:scale(1.04); }
.wt-body{ padding:15px 16px 16px; display:flex; flex-direction:column; flex:1; }

/* WHICH TRAIL THIS IS ON. The first thing on the card, because a proposal
   means nothing until you know where it is. */
.wt-on{
  font:600 9.5px/1 var(--font-body); letter-spacing:.18em; text-transform:uppercase;
  color:var(--wishful-kicker); margin-bottom:7px;
}
.wt-card h3{ margin:0 0 7px; font:600 17px/1.25 var(--font-display); }
.wt-card h3 a{ color:var(--text); text-decoration:none; }
/* the whole card is the link. The <a> is the only thing that carries the
   address; this overlay is what makes the rest of the card clickable, which
   is why nothing else inside may sit above it — see .wt-go below. */
.wt-card h3 a::after{ content:""; position:absolute; inset:0; }
.wt-card h3 a:hover{ color:var(--accent); }
.wt-card p{
  margin:0 0 14px; font:400 13px/1.6 var(--font-body); color:var(--text-quiet);
}

/* ── THE COIN AND THE DIAL ─────────────────────────────────────────────── */
.wt-marks{
  display:flex; gap:16px; flex-wrap:wrap; margin:auto 0 12px;
  padding-top:12px; border-top:1px solid var(--panel-edge);
}
.wt-mark{ display:flex; align-items:center; gap:8px; }
.wt-mark img{
  width:28px; height:28px; display:block;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45));
  transition:transform 420ms var(--panel-ease);
}
/* the coin turns and the dial leans when the card is pointed at — one gesture
   each, and they are staggered so it reads as a response rather than a twitch */
.wt-card:hover .wt-mark.is-cost img{ transform:rotate(-12deg) scale(1.12); }
.wt-card:hover .wt-mark.is-priority img{ transform:scale(1.12); transition-delay:70ms; }
.wt-mark span{ display:flex; flex-direction:column; gap:2px; }
.wt-mark small{
  font:600 8.5px/1 var(--font-body); letter-spacing:.16em; text-transform:uppercase;
  color:var(--text-faint);
}
.wt-mark b{ font:600 12px/1 var(--font-body); color:var(--text); }

/* ── THE BUTTON ────────────────────────────────────────────────────────── */
/* A LABEL, NOT A CONTROL — pointer-events:none for the same reason as .pt-go
   on the trails page: it carries a transform on hover, a transform makes a new
   stacking context, and that context would lift it above the card's own link
   overlay and swallow the click on the one part of the card that says
   "click me". */
.wt-go{
  pointer-events:none; align-self:flex-start;
  display:inline-flex; align-items:center; gap:8px;
  font:600 11px/1 var(--font-body); letter-spacing:.06em;
  padding:9px 14px; border-radius:999px;
  color:var(--wishful-kicker); background:var(--wishful-panel);
  border:1px solid var(--wishful-edge);
  transition:background var(--button-fade), color var(--button-fade),
             border-color var(--button-fade);
}
.wt-go span{ transition:transform var(--button-fade); }
.wt-card:hover .wt-go{
  color:#1d0f24; background:var(--route-line-wish); border-color:transparent;
}
.wt-card:hover .wt-go span{ transform:translateX(4px); }

/* ── WHEN NOTHING MATCHES ──────────────────────────────────────────────── */
.wt-empty{
  margin:30px 0; padding:26px; text-align:center;
  border:1px dashed var(--panel-edge); border-radius:var(--panel-radius);
  font:400 14px/1.7 var(--font-body); color:var(--text-quiet);
}
.wt-linkish{
  font:inherit; color:var(--accent); background:none; border:0; padding:0;
  cursor:pointer; text-decoration:underline; text-underline-offset:3px;
}
.wt-linkish:hover{ color:var(--text); }

/* Somebody who has asked not to be moved about gets the filtering without the
   choreography — the cards still appear and disappear, they simply do it at
   once. */
@media (prefers-reduced-motion: reduce){
  .wt-card, .wt-shot, .wt-mark img, .wt-go, .wt-go span,
  .wt-ticks button, .wt-sort button, .wt-reset{
    transition-duration:1ms !important; transition-delay:0ms !important;
  }
}

/* ── WHERE THE CARD MAY START, ON A WIDE SCREEN ──────────────────────────
   The card column normally begins below the corner title, because on a narrow
   screen the card is full width and would cover it. Past 1000px it cannot: the
   title ends around x=330 and the card is capped at 540px against the right
   edge, so there is always clear space between them. Reserving the title's
   full height there cost the card about 80 pixels — and a card that is
   80 pixels shorter is three fewer lines of text.

   Kept as a variable rather than a different `top` so that the height the
   engine measures for fitting the text agrees with where the card actually
   is. Two places disagreeing about that is how a card ends up overhanging the
   readouts. */
@media (min-width: 1000px){
  body.page-trail{ --card-top: calc(var(--title-pad) + 10px); }
}

/* ═══ ⑤  SMALL SCREENS ═════════════════════════════════════════════════════
   Last in the file so these win. The page-specific blocks that follow were
   each written for one page and are scoped to it, so the two map pages cannot
   rewrite one another's variables at odd widths.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the layers panel on a phone ───────────────────────────────────────────
   The panel used to be one tall column of switches, each with a line of
   explanation under its name, and on a short phone the bottom of the list was
   simply cut off — there was no way to reach the last switch at all.

   Two changes fix it, and both are variables rather than new rules:
     * two columns instead of one, which halves the height
     * the explanations are dropped. They are a nicety on a desktop and the
       reason the list was twice as tall as it needed to be. The switch's name
       is what identifies it; the note only ever expanded on that.
   Between them the whole set fits on a phone screen without scrolling.      */
@media (max-width: 700px){
  /* the main map's panel only — a trail page's switches are one per row at
     every size, see .tm-switches */
  :root{ --switch-columns: 2; --switch-gap: 6px; }
  /* THE NOTES GO ON THE MAIN MAP AND STAY ON A TRAIL PAGE.
     Dropping them was the price of fitting a dozen switches into two columns
     on a phone. A trail page has two or three, one per row, and there is room
     — so it keeps them, and it needs them: "Tap a waypoint to open it" is the
     only place that says what Waypoint auto-load does. */
  .ht-switchText small{ display:none; }
  .ht-switch, .tm-switch{ padding:9px 10px; gap:8px; }
  .ht-switchText b, .tm-switchText b{ font-size:11.5px; line-height:1.2; }
  /* the switch itself shrinks a little so two fit side by side */
  :root{ --switch-width: 28px; --switch-height: 17px; }
  .ht-reset{ margin-top:10px; }

  /* The panel's opening line of explanation goes too. On a desktop it says
     what the switches do; on a phone it costs three lines of a screen that has
     none to spare, and the switches explain themselves. */
  #ht-panelNote, #tm-panelNote{ display:none; }
  .ht-groupTitle{ margin:10px 0 6px; }
  /* the corner title tucks in, which raises the panel's ceiling */
  :root{ --title-pad: 14px; }
}

/* the same again for a short, wide window — a phone on its side, mostly */
@media (max-height: 560px){
  :root{ --switch-columns: 2; }
  /* a phone on its side has almost no height, so here even a trail page's
     notes go — the panel would not fit otherwise */
  .ht-switchText small, .tm-switchText small{ display:none; }
}

/* ── the reading pages ─────────────────────────────────────────────────── */
@media (max-width: 700px){
  :root{ --read-top: 26px; --read-gap: 34px; }
  .pt-foot{ flex-direction:column; gap:8px; }
}


/* the page-specific responsive rules, scoped so neither page can rewrite the
   other's variables at an awkward width */
@media (max-width:860px){
  body.page-trail{
    --edge-gap:    12px;    /* less air to spare, so tighter margins           */
    --bar-height:  44px;    /* a touch deeper: thumbs need more than pointers  */
    --bar-brand-size: 15px;
    --bar-link-size:  10px;
    --title-pad:   16px;    /* and the corner title tucks in tighter           */
    --trail-link-size: 9px;
    --band-bottom: 144px;   /* a little more than the derived stack above, so a
                               thumb on the card never brushes the numbers     */
    --card-width:  none;    /* the column spans the full width instead         */
    --card-sit:    0%;      /* and the card drops to the bottom of it,         */
    --card-lift:   0%;      /*   rather than being centred                     */
    --card-lean:   0;       /* no extra rise: it has nowhere to rise from      */

    /* THE CAP ON A PHONE. It was 4, from when the card's chrome took 100
       pixels more than it does — the count row, the scroll hint, the wider
       paddings. With those gone the card was finishing 52 pixels short of the
       readouts with the text still cut into four pages, because the cap, not
       the room, was the limit. The engine still shows fewer than this on a
       short phone; it is a ceiling, not a promise. */
    --card-text-lines:7;
    --arrow-size:28px;
  }
  /* ── frosted glass, and why a phone does not get it ──────────────────
     backdrop-filter means "blur everything behind this box, every frame".
     Behind the waypoint card is the moving map, so on a phone that is a full
     blur of a moving picture on every frame of the walk — measured at around
     eleven frames a second of the budget, which is most of the difference
     between a walk that flows and one that stutters. The blur goes, and the
     panels behind it become solid enough to read against a busy map instead.
     Raise the alpha in these two if you ever want them denser still. */
  body.page-trail{
    --card-panel:    rgba(18,20,23,.90);
    --wishful-panel: rgba(31,22,44,.90);
    --panel:         rgba(18,20,23,.93);
  }
  /* Setting the blur radius to zero is NOT enough — blur(0) is still a filter,
     and the browser still does the pass. It has to be switched off outright. */
  body.page-trail .tm-card,
  body.page-trail #tm-panel,
  body.page-trail .tm-railBtn,
  body.page-trail #tm-opening .tm-box,
  body.page-trail #tm-closing .tm-box,
  body.page-trail .tm-caption,
  body.page-trail .tm-slideCaption,
  body.page-trail .tm-compare-label,
  body.page-trail #tm-numbers,
  body.page-trail #tm-coords{
    backdrop-filter:none; -webkit-backdrop-filter:none;
  }
  /* ── who is in front of whom, on a phone ────────────────────────────
     The card is full width here and fills nearly the whole column, so it and
     the rail of buttons cannot both have the space. The card takes it: it is
     laid OVER the rail, the way a sheet is laid over what is under it. Nothing
     fades and nothing blinks — for the two thirds of the walk with no card up
     the buttons are exactly where they always were, and when a card rises it
     simply covers them. The page lowers the rail far enough that a card can
     never cross one halfway down; see placeRail().

     The panel keeps the top layer, so a panel you have deliberately opened is
     never buried by a card arriving underneath it. */
  body.page-trail #tm-cards{ z-index:6; }
  body.page-trail #tm-panel{ z-index:7; }
  /* THE STEPPER IS THE ONE THING THE CARD MAY NOT COVER.
     Everything else on the rail opens a panel, and a panel is no use while a
     card fills the screen. The stepper is the opposite: it is how you get from
     this card to the next one, so it is needed exactly when a card is up — and
     it was underneath, greyed and unreachable, for the whole of the walk.

     It goes over the card rather than beside it because there is nowhere
     beside it: the card is full width here. It lands on the card's bottom-left
     corner, where the only thing under it is the centred scroll hint's empty
     left end, and it carries its own background so it reads as sitting on top
     rather than as part of the card. */
  body.page-trail #tm-stepper{ z-index:8; }
  /* THE ARROWS LINE UP WITH THE CARD'S OWN LEFT EDGE, not with the screen's.
     They are positioned from the window, so without this they sat against the
     very edge of the card and hung over its rounded corner — beside the card's
     content rather than in line with it. --edge-gap is where the card starts,
     16px is its inner padding, and the sum is where every line of text in it
     begins. */
  body.page-trail #tm-stepper{ left:calc(var(--edge-gap) + 16px); }
  /* THE BOTTOM PADDING HOLDS A STRIP CLEAR FOR THE STEPPER ARROWS, which
     sit over the card on a phone. The scroll hint used to be that strip;
     with it gone the card has to keep the space itself, or the arrows land
     on the figures above them.
     Written into the shorthand rather than as its own padding-bottom below
     it: this shorthand resets all four sides, so a separate rule for one of
     them is silently overwritten if it comes first — which it did. */
  .tm-card .tm-inner{ padding:14px 16px calc(var(--stepper-size) + 14px); }
  .tm-close{ width:34px; height:34px; font-size:20px; }   /* easier to hit with a thumb */
  .tm-card h2{ font-size:19px; }
  .tm-card p{ font-size:13px; }
  /* the version is hidden here, so the title has the row to itself and the
     link buttons get the full width before they start wrapping */
  #tm-brand{ max-width:100%; }
  #tm-brand h1{ font-size:14px; }
  #tm-version{ display:none; }
  #tm-numbers .tm-optional{ display:none; }
  #tm-readerPanel{ width:auto; left:var(--edge-gap); right:var(--edge-gap); }
}
@media (max-height:720px){
  body.page-trail{
    --title-pad:      12px;   /* the corner title stops taking so much air    */
    --title-links:    30px;
    --readout-drop:   14px;   /* and the numbers sit closer to the edge       */
    --profile-height: 40px;   /* a shallower elevation graph                  */
    /* on a phone the card also holds a clear strip at the bottom for the
       stepper arrows, which is why the stepper's own size is in here */
    --card-chrome:   calc(272px + var(--stepper-size));  /* tighter padding, but
                                 the hint still has to be paid for            */
    --card-media-min: 116px;  /* and the picture may go a little smaller here
                                 before the card is allowed to overhang       */
  }
  /* NOT the shorthand: on a small phone this block applies as well as the
     narrow-screen one above, comes later, and a shorthand here would reset
     the bottom padding that is holding a strip clear for the stepper. */
  .tm-card .tm-inner{ padding-top:14px; padding-left:18px; padding-right:18px; }
  .tm-card .tm-facts{ margin-top:10px; padding-top:9px; }
}
@media (prefers-reduced-motion:reduce){
  #tm-hint svg, #tm-walker .tm-ring{ animation:none; }
}
@media (max-width: 700px){
  body.page-map{
    --edge-gap:      12px;
    --bar-height:    44px;
    --bar-brand-size:15px;
    --bar-link-size: 10px;
    --compass-size:  46px;
    --compass-arrow: 20px;
    --control-size:  40px;
    --rail-top:      6px;
    --title-pad:     14px;
    --trail-link-size: 9px;
    --note-size:     11px;
    /* Both panels take exactly the room left beside the rail, so neither can
       run off the right-hand edge. Worked out rather than guessed, because a
       fixed width that suits a 390px phone is wrong on a 430px one. */
    --panel-width:      calc(100vw - var(--edge-gap) * 2
                                   - var(--compass-size) - var(--panel-gap));
    --panel-width-wide: var(--panel-width);
    /* --switch-columns stays at 2 here. It used to drop to 1 on a phone, which
       made the list twice as tall as the screen and cut the last switches off
       entirely. Two columns with the explanations hidden — see the small-screen
       block above — is what makes the whole set reachable. */
  }
  /* On a narrow screen the panel reaches nearly to the right-hand edge, where
     the zoom controls are. Rather than squeeze the panel, the controls step
     aside while it is open — on a phone you are reading the panel, not
     zooming, and they come straight back when it closes. */
  body.ht-panel-open #ht-controls{
    opacity:0; pointer-events:none;
    transition:opacity var(--panel-slide) var(--panel-ease);
  }
  /* the same trade as the trail page above: no frosted glass on a phone,
     denser panels instead, so dragging the map stays smooth */
  body.page-map{ --panel: rgba(18,20,23,.93); }
  body.page-map #ht-panel,
  body.page-map .ht-railBtn,
  body.page-map .ht-control,
  body.page-map .ht-pin,
  body.page-map #ht-brandline{
    backdrop-filter:none; -webkit-backdrop-filter:none;
  }
  #ht-brandline{ max-width:100%; }
  #ht-brandline h1{ font-size:14px; }
  #ht-version{ display:none; }
  /* THE HOW-TO LINE GOES, on a phone.
     "Drag to move the map. Use the mouse wheel to zoom. Click to zoom out."
     is written for a mouse, and there is no mouse here — two of its three
     sentences describe something the reader does not have. What they do have
     is touch, which they already know how to use: everyone who has opened a
     map on a phone has dragged and pinched one. So it is instruction nobody
     needs, sitting across the bottom-left corner of a screen that has less
     room than any other. It stays on the desktop, where the wheel and the
     click-to-zoom-out genuinely are worth saying. */
  #ht-hint{ display:none; }
}
@media (max-height: 860px){
  body.page-map{
    --title-pad:    12px;
    --rail-top:      6px;
    --switch-gap:    6px;
  }
  .ht-switch{ padding:6px 9px; }
  .ht-switchText small{ margin-top:2px; font-size:10px; line-height:1.3; }
  .ht-groupTitle{ margin:11px 0 6px; }
  .ht-legend{ gap:8px; }
  .ht-reset{ margin-top:9px; padding:7px 12px; }
}
@media (prefers-reduced-motion: reduce){
  #ht-panel, .ht-switch, .ht-control, .ht-pin, .ht-railBtn{ transition-duration:.01ms; }
}


/* Below 480px, and LAST in the file on purpose: the 700px
   block above also sets these variables, and between two :root rules of equal
   weight the later one wins. Below 480px the short name alone is not enough — five links, a brand and the
   page's own margins still add up to more than the window, and the bar spills
   off the right-hand edge. So at that size the bar gives up the last of its
   comfort: tighter letter-spacing, smaller type, narrower gaps and less padding
   at the ends. Nothing is dropped — every section stays reachable, which is the
   point of the bar; it just stops being spacious. */
@media (max-width: 480px){
  :root{
    --bar-pad:        10px;
    --bar-brand-size: 14px;
    --bar-link-size:  9.5px;
    --bar-link-gap:   9px;
  }
  #ht-nav a, #tm-barNav a{ letter-spacing:.05em; }
}
