@font-face{font-family:'Bodoni Moda';font-style:normal;font-weight:400 700;font-display:swap;src:url('/media/bodoni-moda.e3d1b6d7.woff2') format('woff2-variations')}
@font-face{font-family:'Bodoni Moda';font-style:italic;font-weight:400 700;font-display:swap;src:url('/media/bodoni-moda-italic.07fcb751.woff2') format('woff2-variations')}
@font-face{font-family:'Chivo';font-style:normal;font-weight:300 900;font-display:swap;src:url('/media/chivo.a3ed33fd.woff2') format('woff2-variations')}
:root {
    /* The page's own left and right margin, and where the wordmark sits on
       every page. Matches the homepage's clamp(16px, 3cqw, 44px). */
    --edge: clamp(16px, 3vw, 44px);
    --paper: #F4F1E8;
    --ink: #0C0C0B; --body: #3A3833; --muted: #5A574F;
    --red: #C4271E; --rule-red: #E63329; --hairline: rgba(12,12,11,.14);
    --display: "Bodoni Moda", Didot, "Bodoni 72", serif;
    --text: Chivo, system-ui, -apple-system, sans-serif;
  }
  html { -webkit-text-size-adjust: 100%; }
  body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--text); }
  /* House style: no orphaned text. Individual selectors below already set this
     where it matters most; this is the safety net so a lone word is never left
     on the last line of any flowing text. */
  h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
  /* A hyphen in a name set in the display face: Bodoni Moda's is a hairline at size, so
     it carries the cards' stroke (51-20; cover_block.HYPHEN_STROKE, 50-34). */
  .cb-hy { -webkit-text-stroke: .03em currentColor; }
  p, li, figcaption, blockquote, dd, dt { text-wrap: pretty; }
  a { color: inherit; }
  /* --gut is the column's side padding. The sticky masthead spans past it so
     nothing scrolls through the gutters beside it, on this page as on a guide. */
  main { --gut: var(--edge); max-width: 680px; margin: 0 auto; padding: 0 var(--gut) 120px; }

  /* Eyebrow is structure, not a control: ink text over the one red accent rule. */
  /* The publisher's mark, top left of every guide. Display face so it reads as
     an imprint rather than a nav item, and the same on each guide so the second
     and third one feel like the same place. */
  .wordmark { display: block; font-family: var(--display); font-weight: 400;
    font-size: 20px; line-height: 1; letter-spacing: -.005em; color: var(--ink);
    text-decoration: none; margin: 0 0 18px; }
  @media (hover: hover) { .wordmark:hover {color: var(--red);} }
  .wordmark:focus-visible { color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }

  /* The two actions. Uppercase with a red underline, which is the guide's one
     action style, so nothing new looks pressable. */
  .acts { margin: 26px 0 0; display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: baseline; }
  .act { background: none; border: 0; padding: 0; cursor: pointer; color: var(--ink);
    font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase;
    text-decoration: none; border-bottom: 2px solid var(--rule-red); }
  @media (hover: hover) { .act:hover { color: var(--red); } }
  .act:focus-visible { color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }

  /* The contents row: the page's sections in reading order, plain anchors.
     Muted so it never competes with the two real actions above it; the red
     underline arrives on hover, in the house action grammar. */
  .secnav, .ptoc { margin: 24px 0 0; display: flex; flex-wrap: wrap; gap: 8px 16px; }
  /* The practical contents follows the reader: sticky beneath the filter bar
     (the script measures the real offset into --ptoctop), and the group in
     view holds the underline. Without JavaScript it is simply a row of links. */
  .ptoc { margin-top: 16px; position: sticky; top: var(--ptoctop, 56px);
    z-index: 3; background: var(--paper); padding: 8px 0 0;
    border-bottom: 1px solid var(--hairline); }
  /* The group's mark sits ON the rule, as in the app (53-42, 53-21): no room under the
     row, and each link steps down a pixel so its 2px red covers the 1px hairline, the
     two bottom edges together. A row that wraps puts the last line's marks there. */
  .ptoc a { position: relative; margin-bottom: -1px; }
  .ptoc a.on { color: var(--ink); border-bottom-color: var(--red); }
  .secnav a, .ptoc a { font: 700 10px/1.4 var(--text); letter-spacing: .12em;
    text-transform: uppercase; color: var(--muted); text-decoration: none;
    border-bottom: 2px solid transparent; }
  .secnav a:focus-visible, .ptoc a:focus-visible {
    color: var(--ink); border-bottom-color: var(--red); outline: none; }
  @media (hover: hover) { .secnav a:hover, .ptoc a:hover {color: var(--ink); border-bottom-color: var(--red); outline: none;} }

  .eyebrow { display: inline-block; border-top: 2px solid var(--rule-red); padding-top: 7px;
    font: 700 10px/1 var(--text); letter-spacing: .24em; text-transform: uppercase; color: var(--muted); }
  .eyebrow a { color: var(--red); text-decoration: none; border-bottom: 2px solid transparent; }
  @media (hover: hover) { .eyebrow a:hover {border-bottom-color: var(--red);} }
  .eyebrow a:focus-visible { border-bottom-color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }
  h1 { font-family: var(--display); font-weight: 400; font-size: clamp(44px, 9vw, 64px);
    line-height: .98; letter-spacing: -.015em; margin: 20px 0 0; text-wrap: balance; }
  .byline { font: 400 12px/1.6 var(--text); color: var(--muted); margin: 14px 0 0; }
  /* A Preview whose map files are still being cut says so and fills in when they exist (OCT8-4). */
  .kymap-wait { position: absolute; inset: 0; z-index: 1200; display: grid; place-items: center;
    background: var(--paper); color: var(--muted); font: 400 15px/1.4 var(--text);
    text-align: center; padding: 0 24px; text-wrap: balance; }
  /* The byline carries the author's face. It is the first thing under the
     title on a page a reader usually arrives at from somebody else's share,
     and it is the only portrait on the page: the footer no longer repeats it. */
  .byauthor { margin: 14px 0 0; display: flex; align-items: center; gap: 10px;
    font: 400 14px/1.4 var(--text); color: var(--muted); }
  .byauthor .mugshot { flex: none; width: 34px; height: 34px; border-radius: 50%;
    object-fit: cover; background: rgba(12,12,11,.08); }
  .byauthor a { color: var(--ink); text-decoration: none;
    border-bottom: 2px solid var(--rule-red); }
  @media (hover: hover) { .byauthor a:hover {color: var(--red);} }
  .byauthor a:focus-visible { color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }
  .bybio { margin: 8px 0 0; font: 400 14px/1.45 var(--text); color: var(--body);
    max-width: 40ch; text-wrap: pretty; }
  .bylink { margin: 6px 0 0; font: 400 14px/1.4 var(--text); }
  /* The creator's site takes the page's link style, the same as the name above it:
     sentence case, ink, the 2px red underline. It leaves the guide, so it carries the
     red arrow every link out carries (56-36). */
  .bylink a { color: var(--ink); text-decoration: none;
    border-bottom: 2px solid var(--rule-red); }
  .bylink a::after { content: "\00A0\2197\FE0E"; color: var(--red); font-size: .9em; }
  @media (hover: hover) { .bylink a:hover {color: var(--red);} }
  .bylink a:focus-visible { color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }
  footer .legal a { color: var(--muted); }
  footer .legal a:focus-visible { color: var(--red); }
  @media (hover: hover) { footer .legal a:hover {color: var(--red);} }
  .dek { font-family: var(--display); font-style: italic; font-size: clamp(18px, 3.4vw, 22px);
    line-height: 1.35; color: var(--body); margin: 26px 0 0; max-width: 30ch; text-wrap: pretty; }

  /* Interactive text is red and carries an affordance. Nothing else is red. */
  .share { display: none; margin-top: 20px; background: none; border: none; padding: 0;
    font: 700 10px/1.5 var(--text); letter-spacing: .08em; text-transform: uppercase;
    color: var(--red); cursor: pointer; }
  .share.on { display: inline-flex; align-items: center; gap: 6px; }
  .share::after { content: "\2197\FE0E"; font-size: .9em; }
  .share:focus-visible { border-bottom: 2px solid var(--red); outline: none; }
  @media (hover: hover) { .share:hover { border-bottom: 2px solid var(--red); } }

  .toc { display: flex; flex-wrap: wrap; gap: 6px 20px; margin-top: 30px;
    border-top: 1px solid var(--hairline); padding-top: 16px; }
  .toc a { font: 700 10px/1.6 var(--text); letter-spacing: .12em; text-transform: uppercase;
    color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; }
  .toc a:focus-visible { color: var(--red); border-bottom-color: var(--red); outline: none; }
  @media (hover: hover) { .toc a:hover {color: var(--red); border-bottom-color: var(--red); outline: none;} }

  /* #2 hierarchy: the category name is a Bodoni display in ink, over the red
     accent rule, with real air above each section. Red stays the accent line,
     never the heading text (which isn't a control). */

  /* Guide hero: a full-bleed image or looping video under the header. */
  .hero { margin: 40px 0 0; position: relative; }
  .hero img, .hero video { display: block; width: 100%; height: min(60vw, 460px); object-fit: cover; background: var(--hairline); }
  /* The cover clip's own pause button (47-34): one control, clear of the caption, in
     place of the iPhone's player overlay. 36 drawn, 44 to tap. */
  .hero .clipbtn { position: absolute; right: 12px; bottom: 12px; width: 36px; height: 36px; border-radius: 50%; border: 0; padding: 0; background: rgba(12,12,11,.55); color: #F4F1E8; display: grid; place-items: center; cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
  .hero .clipbtn::after { content: ""; position: absolute; inset: -4px; }
  .hero .clipbtn svg { fill: currentColor; }
  .hero .clipbtn:focus-visible { outline: 2px solid #F4F1E8; outline-offset: 2px; }
  .hero .clipbtn.is-paused svg { display: none; }
  .hero .clipbtn.is-paused::before { content: ""; margin-left: 3px; border-style: solid; border-width: 7px 0 7px 11px; border-color: transparent transparent transparent #F4F1E8; }
  .hero figcaption { position: absolute; left: 10px; bottom: 10px; background: rgba(12,12,11,.55);
    color: var(--paper); font: 500 10px/1 var(--text); padding: 4px 8px; }

  /* The old guide's eight pages now 301 to these sections, so arriving by
     hash has to clear the sticky filter bar rather than land behind it. */
  section { margin-top: 76px; scroll-margin-top: 136px; }
  .cat { border-top: 2px solid var(--rule-red); padding-top: 14px; margin-bottom: 8px; }
  .cat h2 { margin: 0; font-family: var(--display); font-weight: 400; font-size: 30px;
    line-height: 1; color: var(--ink); }

  .entry { margin: 30px 0 0; padding-top: 30px; border-top: 1px solid var(--hairline); }
  .entry:first-of-type { border-top: none; padding-top: 4px; }
  figure { margin: 0; position: relative; }
  /* A place that leads with a photo sits the same 48px below the entry's top line as
     a text-led place does (its title carries 18px on top of the 30px padding). Without
     this the photo sat 18px higher and the section read as uneven. */
  .entry > figure { margin-top: 18px; }
  figure img { display: block; width: 100%; height: min(52vw, 340px); object-fit: cover; background: var(--hairline); }
  figcaption { position: absolute; left: 8px; bottom: 8px; background: rgba(12,12,11,.55);
    color: var(--paper); font: 500 10px/1 var(--text); padding: 4px 7px;
    /* A caption is a label, not a control. Inside a listing, which is itself a
       pin selector, clicking one used to jump the map. */
    pointer-events: none; }
  /* The licence links are the exception, so they get their clicks back. */
  figcaption a { pointer-events: auto; }
  /* Passage credits carry the photographer's and Unsplash's links, which the
     licence asks for. They sit on the scrim, so they take its colour. */
  figcaption a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
  /* Labelled facts on the headline picks: Closed, Give it, Worth knowing. */
  .entry .note { margin: 6px 0 0; font: 400 14px/1.5 var(--text); color: var(--ink); }
  .entry .note span { display: inline-block; min-width: 92px; color: var(--muted);
    font: 500 10px/1.5 var(--text); text-transform: uppercase; letter-spacing: .06em; }

  .entry h3 { margin: 18px 0 0; font-family: var(--display); font-weight: 400;
    font-size: clamp(22px, 4.4vw, 27px); line-height: 1.08; text-wrap: balance; }
  .place { color: var(--ink); text-decoration: none; }
  a.place { color: var(--ink); }
  a.place .mark { color: var(--red); font: 500 .46em var(--text); margin-left: .32em; vertical-align: .5em; }
  @media (hover: hover) { a.place:hover {color: var(--red);} }
  @media (hover: hover) { a.place:hover .mark {color: var(--red);} }
  .practical { margin: 11px 0 0; font: 700 10px/1.4 var(--text); letter-spacing: .08em;
    text-transform: uppercase; color: var(--muted); font-variant-numeric: tabular-nums; }
  .said { margin: 12px 0 0; font: 400 16px/1.62 var(--text); color: var(--body); max-width: 60ch; text-wrap: pretty; }
  .addr { margin: 14px 0 0; }
  .addr a { font: 700 10px/1.5 var(--text); letter-spacing: .08em; text-transform: uppercase;
    color: var(--red); text-decoration: none; border-bottom: 2px solid transparent; }
  .addr a::after { content: "  \2197\FE0E"; }
  @media (hover: hover) { .addr a:hover {border-bottom-color: var(--red);} }
  /* A link the creator kept in their note (a booking, tickets, their own site),
     shown by its host. Red like the guide's other actions, quiet until hovered. */
  .said .notelink { color: var(--red); text-decoration: none; white-space: nowrap;
    border-bottom: 2px solid transparent; }
  @media (hover: hover) { .said .notelink:hover {border-bottom-color: var(--red);} }
  .said .notelink .mark { font: 500 .7em var(--text); margin-left: .18em; vertical-align: .2em; }

  /* Pass on one place. Quiet like the contents row rather than red like the
     address above it: two red uppercase lines under every listing read as two
     addresses. The red underline arrives on hover, which is the house action
     grammar for something that does not need to announce itself. */
  /* The listing's action row: the two things a reader can DO with this place, on one
     line, with a hierarchy (Tomáš, 22 Sep 2026: "book tickets being primary makes
     sense. we should have primary and secondary links to show hierarchy").
       · PRIMARY, the booking: red, and carrying the page's own action mark, the 2px
         red underline. The arrow says it leaves. It is the only line under a listing
         that is both red and underlined, so it cannot be read as a second address.
       · SECONDARY, passing it on: the same uppercase, muted, the rule arriving on
         hover, which is the house grammar for something that does not announce itself.
     They used to stack as two paragraphs in two different voices, and the booking one
     had no style at all: `.plink` is scoped to `.passage`, so in a listing it fell
     through to the browser's default link. */
  .actline { margin: 14px 0 0; display: flex; flex-wrap: wrap; align-items: baseline;
    gap: 4px 18px; }
  .actline .plink.book { font: 700 10px/1.4 var(--text); letter-spacing: .12em;
    text-transform: uppercase; color: var(--red); text-decoration: none;
    border-bottom: 2px solid var(--rule-red); }
  .actline .plink.book span { font-weight: 500; margin-left: .18em; }
  .actline .plink.book:focus-visible {
    color: var(--ink); border-bottom-color: var(--ink); outline: none; }
  @media (hover: hover) { .actline .plink.book:hover {color: var(--ink); border-bottom-color: var(--ink); outline: none;} }
  .actline .fnmark { margin-left: 1px; }
  .pshareline { margin: 12px 0 0; }
  .pshare { background: none; border: 0; padding: 0; cursor: pointer; display: inline-block;
    font: 700 10px/1.4 var(--text); letter-spacing: .12em; text-transform: uppercase;
    color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; }
  .pshare:focus-visible {
    color: var(--ink); border-bottom-color: var(--red); outline: none; }
  @media (hover: hover) { .pshare:hover { color: var(--ink); border-bottom-color: var(--red); } }
  /* `hidden` has to win over the display above, or a reader without JavaScript is
     shown a Share that cannot work (the rule the markup's `hidden` was there for). */
  .pshare[hidden] { display: none; }

  /* Directions (Tomáš, 29 Sep 2026, option A). The summary is an action in the
     line, dressed exactly like Share; open, it carries the house action's 2px red
     underline and the mark turns up. The list is the line's next sibling and CSS
     opens it, so no script is involved. A browser without :has() shows it open. */
  .dirs { display: inline-block; }
  .dirs > summary { list-style: none; cursor: pointer; display: inline-block;
    font: 700 10px/1.4 var(--text); letter-spacing: .12em; text-transform: uppercase;
    color: var(--muted); border-bottom: 2px solid transparent; }
  .dirs > summary::-webkit-details-marker { display: none; }
  .dirs > summary::after { content: "\00A0\25BE\FE0E"; }
  .dirs[open] > summary { border-bottom-color: var(--red); }
  .dirs[open] > summary::after { content: "\00A0\25B4\FE0E"; }
  @media (hover: hover) { .dirs > summary:hover {color: var(--ink); border-bottom-color: var(--red);} }
  .dirs > summary:focus-visible { color: var(--ink); border-bottom-color: var(--red);
    outline: 2px solid var(--red); outline-offset: 2px; }
  .dirlist { margin: 12px 0 0; border-top: 1px solid var(--hairline); max-width: 60ch; }
  @supports selector(:has(a)) {
    .dirlist { display: none; }
    .actline:has(> .dirs[open]) + .dirlist { display: block; }
  }
  .dirlist .dir { display: flex; align-items: center; justify-content: space-between;
    box-sizing: border-box; width: 100%; min-height: 44px; margin: 0; padding: 0;
    background: none; border: 0; border-bottom: 1px solid var(--hairline);
    font: 700 10px/1.4 var(--text); letter-spacing: .12em; text-transform: uppercase;
    color: var(--red); text-decoration: none; text-align: left; cursor: pointer; }
  .dirlist .dir[hidden] { display: none; }
  .dirlist .dir .mark { font-weight: 500; }
  .dirlist .dircopy { color: var(--muted); }
  @media (hover: hover) { .dirlist .dir:hover {color: var(--ink);} }
  .dirlist .dir:focus-visible { color: var(--ink); outline: 2px solid var(--red);
    outline-offset: -2px; }

  /* The commission footnote. A dagger on the link that earns, and one line at the
     foot of the section that carries it. Quieter than the address above it and
     quieter than the note: it is a fact a reader is owed, not a thing to read. The
     disclosure at the end of Practical still says the whole of it; this says the
     part that matters where the reader is actually deciding. */
  .fnmark { font: 700 10px/1 var(--text); color: var(--muted); vertical-align: super;
    margin-left: 3px; }
  .fnote { margin: 22px 0 0; font: 400 12px/1.5 var(--text); color: var(--muted);
    max-width: 52ch; text-wrap: pretty; }
  .fnote .fnmark { vertical-align: baseline; margin: 0 4px 0 0; }

  /* Profile: portrait, name, and each guide as a covered card. */
  /* Clear of the masthead rule: the portrait was sitting straight on it. */
  header.profile { text-align: left; margin-top: 40px; }
  header.profile .avatar { margin-bottom: 22px; }
  .handle { margin: 12px 0 0; font: 400 12px/1.6 var(--text); letter-spacing: .02em; color: var(--red); }
  .bio { margin: 14px 0 0; font-family: var(--display); font-style: italic;
    font-size: clamp(17px, 3.2vw, 20px); line-height: 1.4; color: var(--body); max-width: 34ch; text-wrap: pretty; }

  .guides-sec { margin-top: 60px; }
  .guides-sec .cat { border-top: 2px solid var(--rule-red); padding-top: 14px; margin-bottom: 4px; }
  .guides-sec .cat h2 { margin: 0; font-family: var(--display); font-weight: 400; font-size: 26px; line-height: 1; color: var(--ink); }
  .guides-sec .count { font: 400 12px/1 var(--text); color: var(--muted); margin-left: 10px; }

  .guides { display: grid; grid-template-columns: 1fr; gap: 40px; margin-top: 34px; }
  @media (min-width: 620px) { .guides { grid-template-columns: 1fr 1fr; gap: 32px 28px; } }
  .gcard { display: block; text-decoration: none; color: inherit; }
  .gcard figure { margin: 0; aspect-ratio: 3 / 2; overflow: hidden; background: var(--hairline); }
  .gcard figure.empty { background: var(--hairline); }
  .gcard img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .5s ease; }
  @media (hover: hover) { .gcard:hover img {transform: scale(1.035);} }
  .gcard h2 { margin: 16px 0 0; font-family: var(--display); font-weight: 400;
    font-size: clamp(26px, 4.6vw, 30px); line-height: 1.04; color: var(--ink); }
  @media (hover: hover) { .gcard:hover h2 {color: var(--red);} }
  .gcard .meta { margin: 5px 0 0; font: 400 12px/1.5 var(--text); color: var(--muted); letter-spacing: .02em; }

  .avatar { width: 92px; height: 92px; border-radius: 50%; object-fit: cover; background: var(--ink);
    color: var(--paper); display: flex; align-items: center; justify-content: center;
    font-family: var(--display); font-size: 40px; }

  footer { margin-top: 90px; border-top: 1px solid var(--hairline); padding: 26px 0 12px; }
  footer .who { display: flex; align-items: center; gap: 16px; }
  footer .who img { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; display: block; }
  footer .who a { display: block; line-height: 0; }
  footer .sign { font-family: var(--display); font-style: italic; font-size: 20px; color: var(--body); margin: 0; }
  footer .colophon { font: 400 12px/1.8 var(--text); color: var(--muted); margin: 12px 0 0; }
  footer .colophon a { color: var(--red); text-decoration: none; border-bottom: 1px solid var(--red); }

  /* The share sheet. Sharing is the whole hypothesis of this release, and a
     link on its own is not shareable on the one surface where a guide would
     travel furthest: Instagram takes a picture or it takes nothing. So the
     sheet leads with the link, which is what most people want, and then offers
     the three things a reader can actually post. */
  /* Sized to the viewport as it is on screen (53-29): in an in-app browser (Google,
     Instagram) vh is the viewport with its bars put away, taller than what shows, and
     the sheet ran under the bottom bar. dvh after the vh fallback. The bottom space is
     on the step, not here: WebKit leaves a scrolling box's own bottom padding out of
     what scrolls, so a long sheet ended flush on its last line. */
  .sheet { box-sizing: border-box; width: min(440px, calc(100vw - 32px));
    max-height: min(86vh, 760px); max-height: min(86dvh, 760px);
    padding: 28px 26px 0; border: 1px solid var(--hairline); background: var(--paper);
    color: var(--ink); box-shadow: 0 24px 60px rgba(12,12,11,.22); overflow: auto;
    overscroll-behavior: contain; }
  .sheet::backdrop { background: rgba(12,12,11,.5); }
  .sheet h2 { font-family: var(--display); font-weight: 400; font-size: 30px; line-height: 1.04;
    letter-spacing: -.015em; margin: 16px 0 0; }
  .sheet .say { margin: 10px 0 0; font: 400 14px/1.5 var(--text); color: var(--muted); }
  .sheet .x { position: absolute; top: 12px; right: 12px; margin: 0; }
  .sheet .x button { background: none; border: 0; padding: 6px; cursor: pointer;
    color: var(--muted); font: 400 20px/1 var(--text); }
  .sheet .x button:focus-visible { color: var(--red); outline: none; }
  @media (hover: hover) { .sheet .x button:hover {color: var(--red); outline: none;} }

  /* The link, shown in full and copied in one tap. A monospaced face because
     this is the one place on the page where a reader reads a URL as a string. */
  .linkrow { display: flex; align-items: center; gap: 10px; margin: 18px 0 0;
    border: 1px solid var(--hairline); background: rgba(12,12,11,.03); padding: 11px 12px; }
  .linkrow code { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font: 400 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--body); }
  .linkrow .act { flex: none; }

  /* What a reader pays through a link that earns us something, and the date
     somebody checked. Small and factual: it is evidence, not a boast. */
  .pchecked { margin: 4px 0 0; font: 400 10px/1.5 var(--text); color: var(--muted); }

  .sheet .lab { margin: 26px 0 6px; font: 700 10px/1 var(--text); letter-spacing: .22em;
    text-transform: uppercase; color: var(--muted); }

  /* One question, then one screen for the answer. Back returns to the question;
     the cross in the corner leaves altogether. They do different things, so
     Back is text on the left and the cross stays furniture in the corner. */
  .sheet .back { display: block; margin: 0 0 20px; padding: 0;
    background: none; border: 0; cursor: pointer; color: var(--muted);
    font: 700 10px/1 var(--text); letter-spacing: .18em; text-transform: uppercase; }
  .sheet .back:focus-visible { color: var(--red); outline: none; }
  @media (hover: hover) { .sheet .back:hover {color: var(--red); outline: none;} }
  /* Each card whole, scaled to fit, never cropped (50-33): the guest card's code was
     cut off at the bottom and the Story showed only its top. The box keeps the card's
     own shape (width and height on the img) and the height is capped so the button
     stays in view; a card taller than that is drawn smaller, centered, whole. */
  /* The card's own edge (53-26). The guest card's paper band sat on the sheet's same
     paper, so its 2:3 shape, the point of it, could not be seen; a Story or Post with a
     pale sky lost its top edge the same way. A hairline, the sheet's own, drawn on the
     card rather than on the box: each shape is sized from the height cap by its own
     ratio, so the box never letterboxes and the line sits on the card's edges. */
  .sheet .preview { display: block; box-sizing: border-box; height: auto;
    width: min(100%, calc(min(56vh, 440px) * 4 / 5)); max-height: min(56vh, 440px);
    width: min(100%, calc(min(56dvh, 440px) * 4 / 5)); max-height: min(56dvh, 440px);
    object-fit: contain; margin: 16px auto 0; border: 1px solid var(--hairline); }
  .sheet .preview.tall { width: min(100%, calc(min(56vh, 440px) * 9 / 16));
    width: min(100%, calc(min(56dvh, 440px) * 9 / 16)); }
  .sheet [data-step="guest"] .preview { width: min(100%, calc(min(56vh, 440px) * 2 / 3));
    width: min(100%, calc(min(56dvh, 440px) * 2 / 3)); }
  .sheet .step { padding-bottom: calc(26px + env(safe-area-inset-bottom, 0px)); }
  /* The one button on a step. It is the whole point of the screen, so unlike
     everything else in the guide it is allowed to look like a button. */
  .sheet .cta { display: block; margin: 18px 0 0; padding: 13px 16px; text-align: center;
    background: var(--red); color: var(--paper); text-decoration: none;
    font: 700 10px/1.4 var(--text); letter-spacing: .16em; text-transform: uppercase; }
  /* The one button is the action red, at rest, in every language (54-04, his "they
     should be red"; tokens.json: red is "the one button"). Pressed is red held down,
     on :active, which a phone does not keep after the finger lifts; no :hover colour,
     because a phone keeps :hover on the last thing touched (53-32). */
  .sheet .cta:active { background: #A81F18; }
  .sheet .cta:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
  .sheet .step .hint { margin: 14px 0 0; }
  .sheet .step .linkrow { margin-top: 14px; }
  .rows .sw-send { background: var(--ink); font-size: 14px; }
  .rows .sw-link { background: rgba(12,12,11,.55); font-size: 14px; }
  /* Why saving a picture is the whole route, said once, above the rows that do
     it. A control that quietly does less than it looks like it should is worse
     than one that explains itself. */
  .sheet .hint { margin: 0 0 10px; font: 400 12px/1.5 var(--text); color: var(--muted);
    max-width: 46ch; }
  /* What the row will do on this device. The house action style, so it reads as
     pressable and nothing new is invented for it. */
  .rows .do { margin-left: auto; flex: none; align-self: center;
    font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase;
    color: var(--ink); border-bottom: 2px solid var(--rule-red); }
  .rows a:focus-visible .do { color: var(--red); }
  @media (hover: hover) { .rows a:hover .do {color: var(--red);} }
  .rows { display: block; }
  .rows a { display: flex; align-items: center; gap: 12px; padding: 11px 0;
    border-top: 1px solid var(--hairline); text-decoration: none; color: var(--ink); }
  .rows a:last-child { border-bottom: 1px solid var(--hairline); }
  /* A row this page does not offer (54-19: a reel cut in another language). */
  .rows a[hidden] { display: none; }
  .rows a:focus-visible { background: rgba(12,12,11,.03); outline: none; }
  @media (hover: hover) { .rows a:hover {background: rgba(12,12,11,.03); outline: none;} }
  .rows a:focus-visible { box-shadow: inset 3px 0 0 var(--red); }
  .rows .t { font: 400 14px/1.2 var(--text); }
  .rows .t em { display: block; margin-top: 3px; font: 400 10px/1.3 var(--text);
    font-style: normal; color: var(--muted); }
  /* What just happened, in place of the file size, for a few seconds. */
  .rows .t em.said { color: var(--red); font-weight: 700; }
  /* The card rows show the card. A swatch would be quicker to build and would
     tell a reader nothing about what they are about to post. */
  .rows img { flex: none; width: 34px; height: 34px; object-fit: cover; border-radius: 4px;
    background: rgba(12,12,11,.08); }
  .rows img.tall { height: 56px; width: 32px; }
  /* The messaging rows have no picture, so they carry the app's own colour. */
  .rows .sw { flex: none; width: 34px; height: 34px; border-radius: 8px;
    display: flex; align-items: center; justify-content: center; color: var(--paper);
    font: 700 12px/1 var(--text); font-style: normal; letter-spacing: .01em; }
  .rows .sw-whatsapp { background: #25D366; }
  .rows .sw-messages { background: #1F8FFF; }
  .rows .sw-email    { background: #5A574F; }
  .rows .sw-threads  { background: #0C0C0B; }
  .rows .sw-x        { background: #14171A; }
  .rows .sw-linkedin { background: #0A66C2; }
  .rows .sw-facebook { background: #1877F2; }
  .rows .sw-reddit   { background: #FF4500; }
  /* Not a brand: the phone's own sheet, which knows the apps we do not. */
  .rows .sw-more     { background: rgba(12,12,11,.55); font-size: 10px; letter-spacing: .06em; }
  /* One flat list, like the app's share step (49-27, decided 4A): a bare mark, one
     line of name, the arrow. The brand marks are the app's own vectors, drawn inline;
     our own rows are ink glyphs at one stroke weight. */
  .rows.flat { margin-top: 18px; }
  .rows.flat a { padding: 12px 0; }
  .rows .ic { flex: none; width: 26px; height: 26px; display: flex; align-items: center;
    justify-content: center; }
  .rows .bm { display: block; width: 22px; height: 22px; }
  .rows .bm.glyph { fill: none; stroke: var(--ink); stroke-width: 1.7;
    stroke-linecap: round; stroke-linejoin: round; }
  .rows .bm.glyph .dot { fill: var(--ink); stroke: none; }
  /* What just happened, on the row's own name, for a moment. */
  .rows a.said .t { color: var(--red); font-weight: 700; }

    /* Below the split: Practical, About, feedback and the footer carry no pins,
     so the map column has ended and the page returns to a single measure. */
  .tail { max-width: 720px; margin: 0 auto; padding: 0 var(--edge); }
  /* A chapter break, not a reflow: the split ends, air, then the manual
     begins on its own measure. */
  .tail > section:first-child { margin-top: 120px; }
  /* Practical images are illustrations, not photography: sized to inform,
     never wider than their pixels can honestly fill. */
  .tail .pfig { max-width: 440px; }

    /* Rich media in a creator's practical note (R3-68, tools/media_links.py). A YouTube, Instagram or
     Google Drive link plays in the page; the provider's frame loads on the reader's tap, so the page
     itself calls no one. A video keeps its true shape (--ratio): a phone video is not boxed in 16:9. */
  .pembed { margin: 16px 0 24px; }
  .pembed .pframe { position: relative; aspect-ratio: var(--ratio, 16 / 9); background: var(--hairline);
    overflow: hidden; width: 100%; }
  .pembed.vertical .pframe { max-width: 340px; }
  .pembed-instagram .pframe { max-width: 400px; }
  .pembed .pframe iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
  .pembed .pthumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .pembed .pwhat { position: absolute; left: 0; right: 0; top: 38%; text-align: center;
    font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
  .pembed .pplay { display: none; position: absolute; left: 50%; top: 50%; translate: -50% -50%;
    width: 64px; height: 64px; border: 0; border-radius: 50%; background: var(--paper); cursor: pointer;
    place-items: center; padding: 0; }
  .pe-js .pembed .pplay { display: grid; }
  .pembed .pplay:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
  .pembed .ptri { margin-left: 4px; border-style: solid; border-width: 11px 0 11px 18px;
    border-color: transparent transparent transparent var(--ink); }
  .pembed .plabel2 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .pembed figcaption { position: static; background: none; padding: 0; pointer-events: auto; margin: 8px 0 0;
    font: 400 14px/1.4 var(--text); color: var(--muted); }
  .pembed .psrc { font: 700 10px/1.4 var(--text); letter-spacing: .12em; text-transform: uppercase; margin-right: 8px; }
  .pembed .pfallback { color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--rule-red); font-size: 14px; }
  .pembed .pfallback:focus-visible { color: var(--red); outline: none; }
  @media (hover: hover) { .pembed .pfallback:hover {color: var(--red); outline: none;} }
  .pembed .pfallback .mark, .pprose .notelink .mark, .pprose .pmention .mark { color: var(--red); margin-left: .3em; font-size: .9em; }
  .pprose .pmention { display: block; font: 700 10px/1.6 var(--text); letter-spacing: .1em; text-transform: uppercase;
    color: var(--muted); text-decoration: none; }
  .pprose .pmention:focus-visible { color: var(--red); outline: none; }
  @media (hover: hover) { .pprose .pmention:hover {color: var(--red); outline: none;} }

  /* A discreet legal line, set apart from the brand colophon. */
  footer .legal { margin: 20px 0 0; font: 400 10px/1.5 var(--text); letter-spacing: .04em; }
  footer .legal a { color: var(--muted); text-decoration: none; border-bottom: 1px solid var(--hairline); }
  @media (hover: hover) { footer .legal a:hover { color: var(--red); border-bottom-color: var(--red); } }

  /* Editorial extras that make a generated guide read hand-made:
     a short section intro, and a per-place callout label. */
  .sectionintro { margin: 8px 0 0; font-family: var(--display); font-style: italic; font-size: clamp(16px, 2.6vw, 19px); line-height: 1.4; color: var(--body); max-width: 46ch; text-wrap: pretty; }
  .entry .label { margin: 0 0 -4px; font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
  .entry figure + .label { margin-top: 14px; }
  /* Walk-section directions link: an action, so the guide's action dress */
  /* (uppercase, 2px red underline), never a box. */
  .walklink { margin: 12px 0 4px; }
  .walklink a { font: 700 10px/1.4 var(--text); letter-spacing: .12em; text-transform: uppercase; color: var(--red); text-decoration: none; border-bottom: 2px solid var(--red); padding-bottom: 1px; }
  @media (hover: hover) { .walklink a:hover { color: var(--ink); border-bottom-color: var(--ink); } }
  /* Neighbourhood label (orientation), muted so it never reads as a control. */
  .entry .locality { margin: 7px 0 0; font: 400 12px/1.4 var(--text); letter-spacing: .02em; color: var(--muted); }
  /* A place clip renders exactly like its photo would. */
  .entry figure video { display: block; width: 100%; height: min(52vw, 340px); object-fit: cover; background: var(--hairline); }
  @media (prefers-reduced-motion: reduce) { .hero video, .entry figure video { animation: none; } }

  /* Skeleton: a soft shimmer fills the frame until the lazy-loaded photo
     paints over it, so the column never shows a blank grey box. It lives on
     the box the photo actually covers, never on a figure whose caption strip
     sits below the image, where it would keep flashing behind the words. */
  .entry figure, .gcard figure, .passage .pfig { position: relative; overflow: hidden; }
  .entry figure .pmedia, .gcard figure, .passage .pfig .pmedia {
    background: linear-gradient(100deg, #E9E5DC 25%, #f4f1e8 45%, #E9E5DC 65%);
    background-size: 220% 100%; animation: kyshimmer 1.2s linear infinite; }
  .entry figure img, .entry figure video, .gcard figure img { background: transparent; }
  @keyframes kyshimmer { 0% { background-position: 180% 0; } 100% { background-position: -80% 0; } }
  @media (prefers-reduced-motion: reduce) { .entry figure .pmedia, .gcard figure, .passage .pfig .pmedia { animation: none; background: var(--hairline); } }

  /* Editorial passages (Wander / Weekend / Day trips): a narrative column
     of prose, sub-heads, images and clips. */
  .eyebrow .shape { margin-left: 10px; padding-left: 10px; border-left: 1px solid var(--hairline); color: var(--muted); }
  .standfirst { margin: 18px 0 0; font: 400 16px/1.55 var(--text); color: var(--ink); max-width: 60ch; text-wrap: pretty; }
  .guidecol .subhead { margin: 10px 0 0; font-family: var(--display); font-weight: 400; font-size: 20px; line-height: 1.1; color: var(--ink); }
  .guidecol .outro { margin-top: 26px; padding-top: 16px; border-top: 1px solid var(--hairline); }
  .guidecol .subsec { margin: 34px 0 -6px; font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--red); }
  .pheading { margin: 6px 0 4px; font-family: var(--display); font-style: italic; font-size: clamp(19px, 3vw, 23px); line-height: 1.3; color: var(--body); max-width: 34ch; }
  .passage .psub { margin: 32px 0 0; font-family: var(--display); font-weight: 400; font-size: clamp(19px, 3.4vw, 23px); line-height: 1.15; color: var(--ink); }
  .passage .pprose { margin: 16px 0 0; font: 400 16px/1.62 var(--text); color: var(--body); max-width: 62ch; text-wrap: pretty; }
  /* One link style for the whole passage: the writer's own inline links
     dress exactly like the named .plink ones, hover included. */
  .passage .plink, .passage .pprose a { color: var(--red); text-decoration: none; border-bottom: 1px solid rgba(196,39,30,.4); }
  .passage .plink { white-space: nowrap; }
  .passage .plink:focus-visible, .passage .pprose a:focus-visible { border-bottom-color: var(--red); }
  @media (hover: hover) { .passage .plink:hover, .passage .pprose a:hover { border-bottom-color: var(--red); } }
  /* Who is speaking in Practical: one quiet line, said once. */
  .passage .pboth { margin: 8px 0 0; font: 400 12px/1.6 var(--text); color: var(--muted); max-width: 62ch; }
  .passage .pdisclose { margin: 24px 0 0; padding-top: 16px; border-top: 1px solid var(--hairline); font: 400 12px/1.6 var(--text); color: var(--muted); max-width: 62ch; text-wrap: pretty; }

  /* Small fact tables: airport fares, ticket prices, the phrasebook.
     Wide ones scroll inside their own box rather than pushing the page. */
  .passage .ptablewrap { margin: 16px 0 0; overflow-x: auto; }
  .passage .ptable { border-collapse: collapse; font: 400 14px/1.5 var(--text); }
  .passage .ptable th, .passage .ptable td { text-align: left; padding: 8px 16px 8px 0; border-bottom: 1px solid var(--hairline); vertical-align: top; }
  .passage .ptable thead th { font: 500 10px/1.5 var(--text); color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
  .passage .ptable tbody th { font-weight: 500; padding-right: 24px; }
  .passage .ptable tr:last-child th, .passage .ptable tr:last-child td { border-bottom: none; }

  /* A numbered walk. The number is a marker, not a control. */
  .passage .pgroup { margin: 48px 0 0; padding-top: 8px; scroll-margin-top: 128px; border-top: 2px solid var(--rule-red); font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--red); }
  /* Action links a passage ends on. Uppercase like every other action. */
  .passage .plinks { margin: 16px 0 0; display: flex; flex-wrap: wrap; gap: 6px 20px; align-items: baseline; }
  .passage .plinks .plink { font: 700 10px/1.6 var(--text); letter-spacing: .12em; text-transform: uppercase; }
  .passage .plinks .lnote { font: 400 14px/1.6 var(--text); color: var(--muted); flex-basis: 100%; }
  .passage .plist { margin: 8px 0 0; padding-left: 16px; font: 400 16px/1.6 var(--text); }
  .passage .plist li { margin: 4px 0; }
  .passage .psteps { margin: 16px 0 0; padding: 0; list-style: none; }
  .passage .psteps li { display: flex; gap: 16px; padding: 8px 0; border-top: 1px solid var(--hairline); }
  .passage .psteps li:first-child { border-top: none; }
  .passage .psteps .sn { flex: none; font: 700 10px/1.9 var(--text); letter-spacing: .1em; color: var(--red); }
  .passage .psteps .sbody { display: block; font: 400 16px/1.5 var(--text); }
  .passage .psteps .snote { display: block; margin-top: 4px; font: 400 14px/1.55 var(--text); color: var(--muted); }
  .passage .psteps .plink { display: inline-block; margin-top: 8px; font: 700 10px/1 var(--text); letter-spacing: .12em; text-transform: uppercase; }
  .passage .plabel { margin: 24px 0 0; font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
  .passage .plabel + .psub, .passage .plabel + .pprose { margin-top: 4px; }
  .passage .plabel.take { color: var(--red); margin-top: 16px; }
  .passage .pprose .pick { font: 700 10px/1.4 var(--text); letter-spacing: .14em; text-transform: uppercase; color: var(--red); margin: 0 4px 0 8px; white-space: nowrap; }
  .passage .pfig { margin: 24px 0 0; }
  .pmedia { position: relative; overflow: hidden; border-radius: 4px; background: var(--hairline); }
  .passage .pfig img, .passage .pfig video { display: block; width: 100%; height: auto; max-height: 460px; object-fit: cover; }
  /* The credit sits on the picture, the caption under it: a licence line
     and the writer's own words are not the same kind of thing. */
  .pcredit { position: absolute; left: 8px; bottom: 8px; pointer-events: none; background: rgba(12,12,11,.55); color: var(--paper); font: 500 10px/1 var(--text); padding: 4px 7px; }
  .pcredit a { color: inherit; text-decoration: underline; pointer-events: auto; text-underline-offset: 2px; }
  /* The global figcaption is an overlay chip on a place photo. A passage
     caption is a line of text under the picture, so it opts out. */
  .passage .pfig figcaption, .entry figure figcaption { position: static; background: none; padding: 0; margin: 4px 0 0; font: 400 12px/1.5 var(--text); color: var(--muted); }

  /* Place gallery: 2+ of the creator's own photos, laid out in justified
     rows the way Google Photos or Flickr do, and crop-free. --ar (= width/
     height) is set inline per tile. .pgal is a vertical stack of .pgalr
     rows; inside a row, flex-grow of --ar over a 0 basis makes each width
     proportional to the ratio, and aspect-ratio then hands every tile in
     the row one shared height, so portraits stay narrow-tall and landscapes
     wide, edges align, nothing is cropped. Which photos share a row is
     chosen at build time by gallery_rows() so the row heights stay close.
     Even 8px gutters both ways. No JavaScript. The same composition serves a
     practical take's own photos, so a `.passage figure.pgal` shares it. */
  .entry figure.pgal, .passage figure.pgal { display: flex; flex-direction: column; gap: 8px; }
  .passage figure.pgal { margin: 24px 0 0; }
  .entry figure.pgal .pgalr, .passage figure.pgal .pgalr { display: flex; flex-wrap: nowrap; gap: 8px; }
  .entry figure.pgal .pmedia, .passage figure.pgal .pmedia { flex: var(--ar, 1.5) 1 0; aspect-ratio: var(--ar, 1.5); min-width: 0; }
  /* Beat figure img{height:min(52vw,340px)} so a tile keeps its own ratio. */
  .entry figure.pgal .pmedia img, .entry figure.pgal .pmedia video, .passage figure.pgal .pmedia img, .passage figure.pgal .pmedia video { width: 100%; height: 100%; object-fit: cover; }
  .entry figure.pgal figcaption, .passage figure.pgal figcaption { margin-top: 8px; }
  /* The tile shimmer, on a passage gallery too (the entry one is .entry-scoped). */
  .passage figure.pgal .pmedia { background: linear-gradient(100deg, #E9E5DC 25%, #f4f1e8 45%, #E9E5DC 65%); background-size: 220% 100%; animation: kyshimmer 1.2s linear infinite; }
  .passage figure.pgal .pmedia img, .passage figure.pgal .pmedia video { background: transparent; }
  @media (prefers-reduced-motion: reduce) { .passage figure.pgal .pmedia { animation: none; background: var(--hairline); } }

  /* Feedback: the one form on the page. The Send control is allowed to look
     pressable (house rule); nothing else here is. */
  .feedback { margin: 64px 0 0; border-top: 1px solid var(--hairline); padding-top: 30px; }
  .fbwho { margin: 0 0 16px; display: flex; flex-wrap: wrap; gap: 8px 24px; }
  .fbwho label { display: flex; align-items: center; gap: 8px; font: 400 12px/1.4 var(--text); color: var(--body); cursor: pointer; }
  .fbwho input { accent-color: var(--red); width: 15px; height: 15px; }
  .feedback h2 { margin: 0; font-family: var(--display); font-weight: 400; font-size: 20px; line-height: 1.1; color: var(--ink); }
  .feedback > p { margin: 8px 0 0; font: 400 14px/1.55 var(--text); color: var(--body); max-width: 46ch; }
  .fbform { margin: 16px 0 0; }
  .fbtext { width: 100%; box-sizing: border-box; resize: vertical; background: rgba(12,12,11,.02); border: 1px solid var(--hairline); border-radius: 8px; padding: 16px; font: 400 14px/1.5 var(--text); color: var(--ink); }
  .fbtext:focus { outline: 2px solid var(--red); outline-offset: 1px; border-color: var(--red); }
  .fbtrap { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
  .fbrow { display: flex; align-items: center; gap: 16px; margin-top: 16px; }
  .fbsend { background: none; border: none; cursor: pointer; padding: 2px 0; font: 700 10px/1.4 var(--text); letter-spacing: .1em; text-transform: uppercase; color: var(--ink); border-bottom: 2px solid var(--rule-red); }
  @media (hover: hover) { .fbsend:hover { color: var(--red); } }
  .fbsend[disabled] { color: var(--muted); border-bottom-color: var(--hairline); cursor: default; }
  @media (hover: hover) { .fbsend[disabled]:hover { color: var(--muted); } }
  .fbsend:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
  .fbstatus { margin: 0; font: 400 12px/1.4 var(--text); color: var(--muted); }
  .fbthanks { margin: 16px 0 0; font-family: var(--display); font-style: italic; font-size: 16px; color: var(--body); }

  /* Guide as a planning split view, one consistent block from top to bottom: a
     scrolling column (header, hero, places, footer) on the left, a sticky map on
     the right. The whole split is width-capped and centred, so the top no longer
     floats in a narrow band above a full-bleed map. */
  .guidepage { max-width: none; margin: 0; padding: 0; }
  .split { display: flex; align-items: flex-start; max-width: 1680px; margin: 0 auto; }
  .guidecol { --gut: var(--edge); width: 560px; flex: none; padding: 0 var(--gut) 40px; }
  .guidecol header { margin-top: 40px; }
  .guidecol .hero { margin: 30px 0 0; }
  .guidecol .hero img, .guidecol .hero video { height: 300px; }
  .mapcol { flex: 1; align-self: stretch; position: sticky; top: 56px;
    height: calc(100vh - 56px);
    border-left: 1px solid var(--hairline); }
  .kymap { width: 100%; height: 100%; background: #e9e5dc; position: relative; }
  /* A shimmer over the map panel only, while the tiles fetch and paint. The guide
     itself is already readable beside it; this says the map is loading rather than
     leaving a grey rectangle that reads as broken. It clears the moment the map is
     ready and never returns. */
  .kymap::after { content: ""; position: absolute; inset: 0; z-index: 800;
    pointer-events: none; opacity: 1; transition: opacity .5s ease-in-out;
    background: linear-gradient(100deg, #E9E5DC 30%, #f4f1e8 50%, #E9E5DC 70%);
    background-size: 200% 100%; animation: kymapShimmer 1.2s linear infinite; }
  .kymap.mapready::after { opacity: 0; animation: none; }
  @keyframes kymapShimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
  @media (prefers-reduced-motion: reduce) { .kymap::after { animation: none; } }
  .leaflet-container { background: #e9e5dc; font-family: var(--text); }
  .leaflet-control-attribution { font-size: 10px; }
  .ky-pin { background: none; border: none; }

  /* The masthead belongs to the page, not to the reading column. It used to
     sit inside the column, so the same mark landed at four different x
     positions across four pages and the bar ran full width on two of them and
     column width on the other two. One bar, edge to edge, with the wordmark at
     the inset the homepage already uses. */
  .idbar { position: sticky; top: 0; z-index: 40;
    padding: 0 var(--edge);
    /* 56px overall, the same as the homepage header, border included. */
    box-sizing: border-box; height: 56px;
    display: flex; align-items: center; gap: 12px;
    background: var(--paper); border-bottom: 2px solid var(--ink); }
  /* The same size as the homepage wordmark (20px), so the mark reads as one
     mark across the marketing page and every guide. */
  .idbar .wordmark { font-family: var(--display); font-weight: 400; font-size: 20px;
    letter-spacing: -.01em; line-height: 1; color: var(--ink);
    text-decoration: none; margin: 0; white-space: nowrap; }
  @media (hover: hover) { .idbar .wordmark:hover { color: var(--red); } }
  .idbar .wordmark:focus-visible { color: var(--red); outline: 2px solid var(--red); outline-offset: 2px; }
  /* The guide's name, pinned beside the wordmark once the title has scrolled away.
     The name alone (50-31): the byline is under the title and in the footer. One
     line always; a rare long name ends in an ellipsis rather than wrapping, and it
     never pushes the language link. */
  .idbar .idguide { font: 700 10px/1 var(--text); letter-spacing: .14em;
    text-transform: uppercase; color: var(--muted);
    flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap;
    text-overflow: ellipsis; padding: 2px 0;
    opacity: 0; transform: translateX(-4px); transition: opacity .15s ease, transform .15s ease; }
  .idbar.pinned .idguide { opacity: 1; transform: none; }
  /* FR on the English page, EN on the French one (50-31): the homepage's and
     /legal/'s switch, a plain link, in the guide's one action style, at the right
     end. It never shrinks and never moves. Added only once the other language's
     page exists (guide_i18n). */
  .idbar .idlang { flex: none; margin-left: auto; }
  /* On a phone the normal names fit whole: "Cape Cod National Seashore" needed 206px
     beside the mark and the link and had 189 at 375px wide, so the gaps close to 8px
     and the name's tracking to .1em (measured: 196 needed, 197 there). A longer name
     still ends in an ellipsis. */
  @media (max-width: 480px) {
    .idbar { gap: 8px; }
    .idbar .idguide { letter-spacing: .1em; }
  }
  @media (prefers-reduced-motion: reduce) { .idbar .idguide { transition: none; } }

  .stickybar { position: sticky; top: 56px; z-index: 6;
    margin: 30px calc(-1 * var(--gut)) 0; padding: 0 var(--gut);
    background: var(--paper); border-bottom: 1px solid var(--hairline); }
  .filterbar { background: var(--paper);
    display: flex; flex-wrap: wrap; gap: 5px; padding: 9px 0 9px; }
  /* The chip carries its category's pin colour as a dot. Without it the map is
     a colour code with no key, and a reader has to guess which red is which. */
  .chip .dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    margin-right: 6px; vertical-align: baseline; background: currentColor; }
  /* The dot stays on the chosen chip, in paper: the chip is that colour now, so the
     dot is no longer the key, but it keeps the row's rhythm and it still reads as the
     pin it stands for. Said once here; a second rule further down that hid it was
     dropped by the stylesheet pass, which is how two rules for one selector fail. */
  .chip.on .dot { background: var(--paper); }
  /* Each chip carries its category's pin colour twice: as the dot, and as --c, the
     colour it fills with when it is the chosen filter. */
  .chip.cat-eat { color: #C4271E; --c: #C4271E; }
  .chip.cat-drink { color: #6F3448; --c: #6F3448; }
  .chip.cat-nightlife { color: #63346F; --c: #63346F; }
  .chip.cat-art { color: #34526F; --c: #34526F; }
  .chip.cat-see { color: #34526F; --c: #34526F; }
  .chip.cat-walk { color: #346F4A; --c: #346F4A; }
  .chip.cat-wander { color: #346F4A; --c: #346F4A; }
  .chip.cat-shop { color: #6F5934; --c: #6F5934; }
  .chip.cat-stay { color: #346F6B; --c: #346F6B; }
  .chip.cat-day-trip { color: #344A6F; --c: #344A6F; }
  .chip.cat-weekend { color: #3A3833; --c: #3A3833; }
  .chip { background: none; border: 1px solid var(--hairline); cursor: pointer;
    padding: 5px 11px; border-radius: 100px; font: 700 10px/1 var(--text);
    letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
    transition: background .15s, color .15s, border-color .15s; }
  /* Hover is emphasis, not meaning: ink, not red. Red on a filter said "action",
     and hovering a filter is not one (Tomáš, 22 Sep 2026). */
  @media (hover: hover) { .chip:hover { border-color: var(--ink); color: var(--ink); } }
  .chip.now { border-color: var(--ink); color: var(--ink); }
  /* The chosen filter fills with ITS OWN category colour, the one its pins carry on
     the map, so the row is the map's key in both directions and the reader never has
     to learn which black means which. It was an ink pill, a colour that appears
     nowhere else in the guide and says nothing about Art. All and Practical have no
     pins, so they keep the ink. */
  .chip.on { background: var(--c, var(--ink)); border-color: var(--c, var(--ink));
    color: var(--paper); }
  @media (hover: hover) { .chip.on:hover { filter: brightness(1.12); } }
  .chip:focus-visible, .areabtn:focus-visible, .areaclear:focus-visible,
  .mapbtn:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

  .guidecol section[hidden], .guidecol .entry[hidden] { display: none; }
  .guidecol .entry { padding: 4px 14px 24px; margin-left: -14px;
    margin-right: -14px; border-radius: 8px; scroll-margin-top: 90px; }
  .guidecol .entry[data-i] { cursor: pointer; }
  /* The listing whose pin is active on the map. A 2px red rule across the top and
     nothing else (Tomáš, 22 Sep 2026): the mark this page already uses to open a
     category, so it is a word the page has said before. It was a 3px inset bar over a
     red wash, which the entry's own 6px radius rounded at both ends and the negative
     margin floated in the gutter with nothing to align to. */
  .guidecol .entry.on { border-top: 2px solid var(--rule-red); }

  /* Filter-by-area controls, floating over the map. */
  .areabtn, .areaclear { position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
    z-index: 800; display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
    background: var(--paper); color: var(--ink); border: 1px solid var(--hairline);
    padding: 9px 16px; border-radius: 100px; font: 700 10px/1 var(--text);
    letter-spacing: .1em; text-transform: uppercase; box-shadow: 0 4px 14px rgba(12,12,11,.18);
    transition: background .15s, color .15s, border-color .15s; }
  @media (hover: hover) { .areabtn:hover, .areaclear:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); } }
  .areaclear { border-color: var(--red); color: var(--red); }
  @media (hover: hover) { .areaclear:hover { background: var(--red); border-color: var(--red); color: var(--paper); } }
  .areabtn[hidden], .areaclear[hidden] { display: none; }

  /* Floating controls: only on mobile, where the map is an overlay. */
  .mapbtn { position: fixed; z-index: 70; display: none; align-items: center; gap: 8px;
    left: 50%; bottom: 22px; transform: translateX(-50%); border: none; cursor: pointer;
    background: var(--ink); color: var(--paper); padding: 13px 22px; border-radius: 100px;
    font: 700 10px/1 var(--text); letter-spacing: .12em; text-transform: uppercase;
    box-shadow: 0 6px 20px rgba(12,12,11,.28); transition: background .15s; }
  .mapbtn svg { width: 15px; height: 15px; }
  @media (hover: hover) { .mapbtn:hover { background: var(--red); } }
  .mapbtn:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
  .mapbtn.guide { z-index: 1300; }

  @media (max-width: 1039px) {
    .split { display: block; max-width: none; }
    .guidecol { --gut: var(--edge); width: auto; max-width: 680px; margin: 0 auto;
      padding: 0 var(--gut) 0; }
    /* On a phone the tail is the next section, not a chapter after a sticky map: the
       gap before Practical is the gap between two sections (53-30, it was ~200px). */
    .tail > section:first-child { margin-top: 76px; }
    /* Practical carries no pins, so past the last mapped section the button goes:
       resting at the bottom it covered Practical's contents row (53-30). */
    body.in-tail .mapbtn.open { display: none; }
    .guidecol .hero img, .guidecol .hero video { height: min(56vw, 340px); }
    .mapcol { position: fixed; inset: 0; height: 100%; width: auto; border-left: none;
      z-index: 60; transform: translateY(100%); transition: transform .35s ease; }
    .mapcol.on { transform: none; }
    .mapbtn.open { display: inline-flex; }
    body.map-open .mapbtn.open { display: none; }
    body.map-open .mapbtn.guide { display: inline-flex; }
  }

