/* Passage, the look of a book's inside cover: manila endpaper, library ink,
 date-due slips, customs stamps.

 Logical properties throughout, because this has to hold up in Arabic
 as well as English. */

:root {
 --paper: #E4E0D5;
 --paper-hi: #EFEDE6;
 --card: #F3F1EA;
 --ink: #191C24;
 --ink-2: #4A4F5C; /* 7.4:1 on paper */
 --ink-3: #5F5C4E; /* 5.9:1, the smallest text we set */
 --ink-4: #8B8878; /* rules and dividers only, never text */
 --rule: #C6C1B1;
 --violet: #55338A; /* 7.1:1 on paper */
 --violet-2: #6E4BA8;
 --red: #9A3325;
 --green: #2F5D3F;
 --blue: #2A5A85;
 --rust: #9C4A1E;
 --mustard: #7D6412;
 --teal: #1C6A5E;

 --display: 'Archivo', system-ui, sans-serif;
 --body: 'Newsreader', Georgia, serif;
 --stamp: 'Courier Prime', 'Courier New', monospace;

 --gap: clamp(1.25rem, 4vw, 2.5rem);
 --tap: 44px;
 --blend: multiply;
 color-scheme: light;
}

/* Dark comes from the OS unless the reader has chosen otherwise, and from the
 attribute whenever they have. Both paths set the same variables. */
@media (prefers-color-scheme: dark) {
 :root:not([data-theme="light"]) {
 --paper: #16181D;
 --paper-hi: #1E2128;
 --card: #22262E;
 --ink: #E6E3D9;
 --ink-2: #ADA99B;
 --ink-3: #97927F;
 --ink-4: #5A5749;
 --rule: #3A3E48;
 --violet: #B79CE8;
 --violet-2: #CBB6F5;
 --red: #E58A78;
 --green: #86C79B;
 --blue: #9DC3EA;
 --rust: #E7A97D;
 --mustard: #D6BE6E;
 --teal: #89D2C2;
 --blend: screen; /* multiply is invisible on a dark ground */
 color-scheme: dark;
 }
}
:root[data-theme="dark"] {
 --paper: #16181D;
 --paper-hi: #1E2128;
 --card: #22262E;
 --ink: #E6E3D9;
 --ink-2: #ADA99B;
 --ink-3: #97927F;
 --ink-4: #5A5749;
 --rule: #3A3E48;
 --violet: #B79CE8;
 --violet-2: #CBB6F5;
 --red: #E58A78;
 --green: #86C79B;
 --blue: #9DC3EA;
 --rust: #E7A97D;
 --mustard: #D6BE6E;
 --teal: #89D2C2;
 --blend: screen; /* multiply is invisible on a dark ground */
 color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }

html {
 -webkit-text-size-adjust: 100%;
 scroll-behavior: smooth;
 overflow-x: hidden; /* rotated stamps must never scroll the page sideways */
}

body {
 margin: 0;
 min-height: 100vh;
 background: var(--paper);
 /* Paper grain (fine lines) plus a faint dot grid underneath, the same
    graph-paper-under-the-endpaper feel, sized to line up under both
    light and dark ink so it never fights the text sitting on top. */
 background-image:
 repeating-linear-gradient(0deg, rgba(128,128,128,.045) 0 1px, transparent 1px 3px),
 radial-gradient(circle, color-mix(in srgb, var(--ink-4) 55%, transparent) 1px, transparent 1.4px);
 background-size: auto, 24px 24px;
 background-position: 0 0, 0 0;
 color: var(--ink);
 font-family: var(--body);
 font-size: 18px;
 line-height: 1.62;
 overflow-x: hidden;
 -webkit-font-smoothing: antialiased;
}

a { color: var(--violet); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }

:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; border-radius: 2px; }

img { max-width: 100%; display: block; }

.skip-link {
 position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
 background: var(--ink); color: var(--paper); padding: .8rem 1.2rem;
 font-family: var(--display); font-size: .8rem;
}
.skip-link:focus { inset-inline-start: 0; }

.visually-hidden {
 position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
 overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---- type ---- */
.label, .eyebrow {
 font-family: var(--display); font-size: .7rem; font-weight: 600;
 letter-spacing: .16em; text-transform: uppercase; color: var(--ink-3);
}

/* A quiet glow on the one phrase we want a first-time visitor's eye to
 land on. Kept subtle, this is a label, not a neon sign, and switched off
 entirely for anyone who asked for less motion. */
.glow-text {
 color: var(--violet);
 text-shadow: 0 0 6px color-mix(in srgb, var(--violet) 45%, transparent);
}
[data-motion="on"] .glow-text { animation: glowPulse 3.4s ease-in-out infinite; }
@keyframes glowPulse {
 0%, 100% { text-shadow: 0 0 5px color-mix(in srgb, var(--violet) 35%, transparent); }
 50% { text-shadow: 0 0 12px color-mix(in srgb, var(--violet) 70%, transparent),
 0 0 3px color-mix(in srgb, var(--violet) 85%, transparent); }
}

h1, h2, h3 {
 font-family: var(--display); font-weight: 700; letter-spacing: -.02em;
 line-height: 1.1; margin: 0 0 .5em; text-wrap: balance;
}
h1 { font-size: clamp(2rem, 5.5vw, 3.5rem); }
h2 { font-size: clamp(1.35rem, 3vw, 2rem); }
h3 { font-size: 1.1rem; letter-spacing: 0; }

p { margin: 0 0 1em; text-wrap: pretty; }

/* ---- masthead ----
 * The header sticks and sits above the hero globe. Without a z-index and a
 * background the hero-globe (which is position:absolute inside .hero-stage)
 * paints over the top of it on tall viewports. Fixed by giving the masthead
 * its own stacking context. */
.masthead {
 position: sticky;
 inset-block-start: 0;
 z-index: 50;
 display: flex; align-items: center; justify-content: space-between;
 gap: 1rem 1.5rem;
 padding: .85rem var(--gap);
 background: var(--paper);
 border-block-end: 1px solid var(--ink);
}
.wordmark { text-decoration: none; color: inherit; display: flex; align-items: center; gap: .7rem; }
.wordmark-name {
 font-family: var(--display); font-weight: 700; font-size: 1.3rem;
 letter-spacing: .04em; text-transform: uppercase;
}
.wordmark-tag { font-family: var(--stamp); font-size: .72rem; color: var(--ink-3); }

.masthead-nav { display: flex; gap: .35rem 1rem; align-items: center; flex-wrap: wrap; }
.masthead-nav a {
 font-family: var(--display); font-size: .72rem; font-weight: 600;
 letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
 color: var(--ink-2); padding: .55rem 0; min-height: var(--tap);
 display: inline-flex; align-items: center;
}
.masthead-nav a:hover { color: var(--ink); }
.masthead-nav .nav-cta { color: var(--violet); box-shadow: inset 0 -2px 0 var(--violet); }

/* ---- mobile menu ----
 * Hamburger sits between the wordmark and the nav on narrow screens. Nav
 * becomes a dropdown pinned under the header. On desktop the button is hidden
 * and the nav lays out inline as before. */
.nav-toggle {
 display: none;
 border: 1px solid var(--rule); background: transparent;
 inline-size: 44px; block-size: 44px;
 padding: 0; cursor: pointer; color: var(--ink);
 border-radius: 2px;
 align-items: center; justify-content: center;
}
.nav-toggle-bars { display: inline-flex; flex-direction: column; gap: 4px; }
.nav-toggle-bars span {
 display: block; inline-size: 20px; block-size: 2px; background: currentColor;
 transition: transform .2s ease, opacity .2s ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 720px) {
 .masthead { padding: .7rem var(--gap); flex-wrap: nowrap; }
 .wordmark-tag { display: none; }
 .wordmark-name { font-size: 1.1rem; }
 .nav-toggle { display: inline-flex; }

 .masthead-nav {
 position: absolute;
 inset-block-start: 100%;
 inset-inline: 0;
 background: var(--paper);
 border-block-end: 1px solid var(--ink);
 padding: .5rem var(--gap) 1rem;
 flex-direction: column;
 align-items: stretch;
 gap: 0;
 max-block-size: 0;
 overflow: hidden;
 transition: max-block-size .28s ease, padding .28s ease;
 padding-block: 0;
 }
 .masthead[data-nav-open="true"] .masthead-nav {
 max-block-size: 60vh;
 padding-block-start: .5rem;
 padding-block-end: 1rem;
 }
 .masthead-nav a {
 padding: .9rem 0;
 border-block-end: 1px solid var(--rule);
 font-size: .82rem;
 }
 .masthead-nav .nav-cta { box-shadow: none; }
 .masthead-nav .theme-toggle { align-self: flex-start; margin-block-start: .8rem; }
}

/* ---- shells ---- */
.wrap { max-width: 1080px; margin-inline: auto; padding: var(--gap); }
.wrap-sm { max-width: 660px; margin-inline: auto; padding: var(--gap); }

/* ---- hero ---- */
.hero { padding: clamp(2.25rem, 6vw, 4.5rem) var(--gap) 2rem; max-width: 1080px; margin-inline: auto; }
.hero-lede { font-size: clamp(1.05rem, 2.2vw, 1.28rem); max-width: 34em; color: var(--ink-2); font-weight: 300; }
.hero h1 em { font-style: italic; font-family: var(--body); font-weight: 400; }

.stamp-row {
 display: flex; flex-wrap: wrap; align-items: flex-start;
 gap: .55rem .9rem; padding: .6rem 0; overflow: hidden;
}
.hero-stamps { margin: 2rem 0 0; padding-block-start: 1.6rem; border-block-start: 1px solid var(--rule); }

/* ---- the stamp: signature element ---- */
.stamp {
 --angle: 0deg;
 --ink-density: .85;
 --stamp-c: var(--violet); /* the place's ink; a colour class below overrides it */
 display: inline-flex; flex-direction: column; align-items: flex-start; gap: 1px;
 inline-size: 10.5rem; /* fixed, so a row of stamps lines up */
 min-block-size: 4.6rem;
 padding: .5rem .65rem .45rem;
 border: 2px solid var(--stamp-c);
 border-radius: 2px;
 box-shadow: inset 0 0 0 1px var(--paper), inset 0 0 0 3px var(--stamp-c);
 color: var(--stamp-c);
 font-family: var(--stamp);
 opacity: var(--ink-density);
 transform: rotate(var(--angle));
 mix-blend-mode: var(--blend);
 background: transparent;
 flex: 0 0 auto;
 text-decoration: none;
}
/* Real stamps (as opposed to the decorative ghost ones) are links straight
 to that hop on the journey, so they behave like something you can pick up. */
a.stamp {
 cursor: pointer;
 transition: transform .2s cubic-bezier(.2,.8,.3,1), box-shadow .2s ease, opacity .2s ease;
}
a.stamp:hover, a.stamp:focus-visible {
 transform: rotate(calc(var(--angle) - 5deg)) translateY(-3px) scale(1.06);
 opacity: 1;
 box-shadow: inset 0 0 0 1px var(--paper), inset 0 0 0 3px var(--stamp-c), 0 10px 16px -8px rgba(0,0,0,.4);
 z-index: 2;
}
a.stamp--release:hover, a.stamp--release:focus-visible,
a.stamp--home:hover, a.stamp--home:focus-visible { box-shadow: 0 10px 16px -8px rgba(0,0,0,.4); }
a.stamp:focus-visible { outline: 2px solid var(--stamp-c); outline-offset: 4px; }
.stamp-kind { font-size: .55rem; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; }
.stamp-where {
 font-size: .92rem; font-weight: 700; letter-spacing: .03em; line-height: 1.12;
 inline-size: 100%; overflow-wrap: anywhere; hyphens: auto;
}
.stamp-when { font-size: .66rem; letter-spacing: .04em; }
.stamp-country {
 font-size: .56rem; letter-spacing: .1em; text-transform: uppercase; opacity: .8;
 inline-size: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Kind still reads at a glance from the border, independent of the place's
 own ink colour: solid for a hand-to-hand hop, dashed for a sighting,
 double for home. Release keeps a solid border, its label carries it. */
.stamp--sighting { border-style: dashed; box-shadow: none; }
.stamp--home { border-width: 4px; border-style: double; box-shadow: none; }

/* ---- ink: which place-coloured pen stamped this one ---- */
.stamp--ink-violet  { --stamp-c: var(--violet); }
.stamp--ink-ink     { --stamp-c: var(--ink); }
.stamp--ink-red     { --stamp-c: var(--red); }
.stamp--ink-green   { --stamp-c: var(--green); }
.stamp--ink-blue    { --stamp-c: var(--blue); }
.stamp--ink-rust    { --stamp-c: var(--rust); }
.stamp--ink-mustard { --stamp-c: var(--mustard); }
.stamp--ink-teal    { --stamp-c: var(--teal); }

/* ---- shape: which outline this place's stamp takes ----
 Selector is doubled up (.stamp.stamp--shape-oval) to outrank the responsive
 .stamp { inline-size: … } rules further down the sheet, which would
 otherwise win the cascade on source order alone and flatten it back to a
 rectangle on narrower screens. Circle, hex and diamond were tried and
 dropped -- see the comment on STAMP_SHAPES in lib/emblems.php for why. */
.stamp.stamp--shape-oval { border-radius: 999px; padding-inline: 1.1rem; }

@keyframes press {
 0% { transform: rotate(var(--angle)) scale(1.45); opacity: 0; }
 55% { transform: rotate(var(--angle)) scale(.96); opacity: 1; }
 100% { transform: rotate(var(--angle)) scale(1); opacity: var(--ink-density); }
}
.stamp--fresh { animation: press .5s cubic-bezier(.2,.8,.3,1) both; }

/* ---- buttons ---- */
.btn {
 display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
 min-height: var(--tap);
 font-family: var(--display); font-size: .78rem; font-weight: 600;
 letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
 padding: .8rem 1.4rem;
 border: 2px solid var(--ink); background: var(--ink); color: var(--paper-hi);
 border-radius: 2px; cursor: pointer;
 transition: background .14s ease, border-color .14s ease, transform .1s ease;
 -webkit-tap-highlight-color: transparent;
}
.btn:hover { background: var(--violet); border-color: var(--violet); color: var(--paper-hi); }
.btn:active { transform: translateY(1px); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper-hi); border-color: var(--ink); }
.btn--big { font-size: .92rem; padding: 1.05rem 2rem; inline-size: 100%; }
.btn--small { font-size: .65rem; padding: .5rem .85rem; min-height: 38px; }
.btn[disabled], .btn.is-busy { opacity: .55; cursor: progress; pointer-events: none; }

.btn-row { display: flex; gap: .7rem; flex-wrap: wrap; margin: 1.4rem 0; }

/* ---- styled file input: a real <input type=file>, visually hidden behind
 its own <label>, so it reads as one of the site's own buttons rather than
 whatever the browser draws by default. Still fully keyboard/AT operable --
 this hides it from sight only, not from focus. ---- */
.file-field { display: inline-flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-block-start: .3rem; }
.file-field .file-input {
 position: absolute; inline-size: 1px; block-size: 1px; padding: 0; margin: -1px;
 overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.file-field .file-input:focus-visible + .file-btn { outline: 2px solid var(--violet); outline-offset: 2px; }
.file-field .file-btn { cursor: pointer; }
.file-field .file-name { font-family: var(--stamp); font-size: .78rem; color: var(--ink-3); overflow-wrap: anywhere; }
.file-field .file-name.has-file { color: var(--ink); }

.btn-link-danger {
 background: none; border: 0; padding: 0; font: inherit; font-size: .82rem;
 color: var(--red); text-decoration: underline; cursor: pointer;
}

.spinner {
 inline-size: 1em; block-size: 1em;
 border: 2px solid currentColor; border-top-color: transparent;
 border-radius: 50%; animation: spin .7s linear infinite; display: none;
}
.is-busy .spinner { display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- forms ---- */
.field { margin: 0 0 1.35rem; }
.field label {
 display: block; font-family: var(--display); font-size: .7rem; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2); margin-block-end: .4rem;
}
.field .hint { font-size: .84rem; color: var(--ink-3); margin: .35rem 0 0; font-family: var(--body); }

.label {
 display: block; font-family: var(--display); font-size: .7rem; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2); margin: 0 0 .4rem;
}

input[type=text], input[type=email], input[type=password], input[type=datetime-local],
input[type=number], input[type=search], textarea, select {
 inline-size: 100%;
 font-family: var(--body);
 font-size: 16px; /* anything smaller makes iOS zoom the page */
 min-height: var(--tap);
 padding: .7rem .8rem;
 background: var(--card);
 border: 1px solid var(--rule);
 border-block-end: 2px solid var(--ink-2);
 border-radius: 2px;
 color: var(--ink);
}
textarea { min-height: 7rem; resize: vertical; line-height: 1.55; }
input:focus, textarea:focus, select:focus {
 border-block-end-color: var(--violet); outline: 2px solid var(--violet); outline-offset: 1px;
}
input[type=file] { font-family: var(--stamp); font-size: .8rem; padding: .6rem; }
.field.has-error input, .field.has-error textarea { border-color: var(--red); border-block-end-color: var(--red); }
.field-error { color: var(--red); font-size: .85rem; margin: .35rem 0 0; font-family: var(--body); }

.check { display: flex; gap: .7rem; align-items: flex-start; margin: 0 0 1rem; }
.check input { margin-block-start: .4rem; inline-size: 20px; block-size: 20px; flex: 0 0 auto; accent-color: var(--violet); }
.check label {
 font-family: var(--body); text-transform: none; letter-spacing: 0;
 font-size: .95rem; color: var(--ink); font-weight: 400; margin: 0; cursor: pointer;
}

/* ---- kind picker: found / releasing / sighting, as cards not a dropdown ---- */
.kind-picker { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); }
/* Specificity note: plain .field label is a class+type selector, which beats
 a single class. .field .kind-card (two classes) is what actually wins so
 this renders as a card and not a block-stacked native label. */
.field .kind-card {
 position: relative; display: flex; flex-direction: column; gap: .2rem;
 border: 1px solid var(--rule); border-radius: 2px; background: var(--paper-hi);
 padding: .85rem .9rem; cursor: pointer; text-transform: none; letter-spacing: normal;
 transition: border-color .15s ease, background .15s ease;
}
.kind-card input { position: absolute; inset-block-start: .8rem; inset-inline-end: .8rem; accent-color: var(--violet); }
.kind-card:hover { border-color: var(--ink-2); }
.kind-card:has(input:checked) { border-color: var(--violet); background: var(--card); }
.kind-card:has(input:focus-visible) { outline: 2px solid var(--violet); outline-offset: 2px; }
.kind-card-title {
 font-family: var(--display); font-weight: 700; font-size: .92rem; color: var(--ink);
 padding-inline-end: 1.6rem;
}
.kind-card:has(input:checked) .kind-card-title { color: var(--violet); }
.kind-card-sub { font-family: var(--body); font-size: .8rem; color: var(--ink-2); line-height: 1.3; }

fieldset { border: 0; padding: 0; margin: 0; }
[hidden] { display: none !important; }

.notice {
 border-inline-start: 3px solid var(--violet);
 background: var(--card); padding: .9rem 1.1rem; margin: 0 0 1.5rem; font-size: .95rem;
}
.notice--bad { border-inline-start-color: var(--red); }
.notice--good { border-inline-start-color: var(--green); }
.notice p:last-child { margin-bottom: 0; }

/* ---- book journey page ---- */
.book-head { border-block-end: 1px solid var(--ink); padding-block-end: 1.5rem; margin-block-end: 2rem; }
.book-title { margin-block-end: .12em; }
.book-author { font-size: 1.12rem; font-style: italic; color: var(--ink-2); margin: 0 0 1rem; }

.ledger {
 display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
 gap: 1px; background: var(--rule); border: 1px solid var(--rule); margin: 1.5rem 0;
}
.ledger > div { background: var(--paper); padding: .85rem 1rem; }
.ledger dt {
 font-family: var(--display); font-size: .62rem; font-weight: 600;
 letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 .25rem;
}
.ledger dd { margin: 0; font-family: var(--stamp); font-size: clamp(1.05rem, 3.2vw, 1.35rem); font-weight: 700; }

.milestone {
 font-family: var(--stamp); font-size: .78rem; letter-spacing: .04em; color: var(--red);
 border-block: 1px solid var(--red); padding: .5rem 0; margin: 1.5rem 0; text-transform: uppercase;
}

/* ---- maps ---- */
.map-frame { border: 1px solid var(--ink); background: var(--paper-hi); position: relative; }
#map { height: clamp(300px, 52vh, 520px); }
.leaflet-container { background: #DAD6CA; font-family: var(--body); }
@media (prefers-color-scheme: dark) {
 :root:not([data-theme="light"]) .leaflet-container { background: #22262E; }
 :root:not([data-theme="light"]) .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(.92) contrast(.9); }
}
:root[data-theme="dark"] .leaflet-container { background: #22262E; }
:root[data-theme="dark"] .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(.92) contrast(.9); }

/* Leaflet's default popup is a white pill and looks pasted on. Make it ours. */
.leaflet-popup-content-wrapper {
 background: var(--paper-hi); color: var(--ink);
 border: 1px solid var(--ink); border-radius: 2px;
 box-shadow: 3px 3px 0 rgba(0,0,0,.12);
}
.leaflet-popup-content { margin: .7rem .9rem; font-size: .9rem; line-height: 1.45; }
.leaflet-popup-tip { background: var(--paper-hi); }
.leaflet-popup-content-wrapper a { color: var(--violet); }
.leaflet-container a.leaflet-popup-close-button { color: var(--ink-2); }
.leaflet-bar a { background: var(--paper-hi); color: var(--ink); border-color: var(--rule); }
.leaflet-bar a:hover { background: var(--card); color: var(--ink); }
.leaflet-control-attribution { background: rgba(244,241,234,.82) !important; font-size: 10px; }
@media (prefers-color-scheme: dark) {
 :root:not([data-theme="light"]) .leaflet-control-attribution { background: rgba(22,24,29,.86) !important; color: var(--ink-2); }
}
:root[data-theme="dark"] .leaflet-control-attribution { background: rgba(22,24,29,.86) !important; color: var(--ink-2); }
.leaflet-control-attribution a { color: var(--ink-2); }

/* the "use two fingers" veil, so a full-width map never traps the page scroll */
.map-veil {
 position: absolute; inset: 0; z-index: 500;
 display: flex; align-items: center; justify-content: center;
 background: rgba(25,28,36,.42); color: #fff;
 font-family: var(--display); font-size: .8rem; font-weight: 600;
 letter-spacing: .08em; text-transform: uppercase; text-align: center;
 padding: 1rem; opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.map-veil.is-on { opacity: 1; }

/* ---- the date-due slip ---- */
.slip { margin: 3rem 0 0; }
.slip-hop {
 display: grid;
 grid-template-columns: minmax(0, 12.5rem) minmax(0, 1fr);
 gap: var(--gap);
 padding: 1.7rem 0;
 border-block-start: 1px solid var(--rule);
}
.slip-hop:first-of-type { border-block-start: 1px solid var(--ink); }
.slip-mark { min-inline-size: 0; }
.slip-seq {
 font-family: var(--stamp); font-size: .7rem; color: var(--ink-3);
 letter-spacing: .1em; display: block; margin-block-end: .6rem;
}
.slip-body { min-inline-size: 0; }
.slip-body p:last-child { margin-bottom: 0; }
.slip-place { font-family: var(--display); font-weight: 600; font-size: 1.05rem; margin: 0 0 .1rem; overflow-wrap: anywhere; }
.slip-holder { font-family: var(--stamp); font-size: .78rem; color: var(--ink-3); margin: 0 0 .9rem; letter-spacing: .03em; }
.slip-note { font-size: 1.04rem; overflow-wrap: anywhere; }
.slip-photo { margin: 1rem 0; border: 1px solid var(--rule); padding: 6px; background: var(--card); max-inline-size: 420px; }
.slip-photo img { inline-size: 100%; height: auto; }
.slip-forward {
 border-inline-start: 2px solid var(--violet);
 padding-block: .3rem; padding-inline-start: 1rem;
 margin: 1rem 0 0; font-style: italic; color: var(--ink-2); overflow-wrap: anywhere;
}
.slip-forward .label { display: block; font-style: normal; margin-block-end: .2rem; }
/* Feedback about Relay itself, not about the book or its next reader: same
 shape, a quieter border so it doesn't read as part of the journey record. */
.slip-forward--project { border-inline-start-color: var(--ink-4); }
/* The one thing on the owner dashboard that never appears anywhere public:
 a background tint so it reads as different in kind, not just in content. */
.slip-forward--private {
 border-inline-start-color: var(--red);
 background: color-mix(in srgb, var(--red) 7%, transparent);
 padding: .6rem .8rem;
}
.slip-leg { font-family: var(--stamp); font-size: .72rem; color: var(--ink-3); margin-block-start: .8rem; letter-spacing: .04em; }

/* ---- atlas ---- */
.atlas-grid {
 display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
 gap: 1px; background: var(--rule); border: 1px solid var(--rule); margin-block-start: 2rem;
}
.atlas-card {
 background: var(--paper); padding: 1.35rem; text-decoration: none; color: inherit;
 display: block; transition: background .15s ease;
}
.atlas-card:hover, .atlas-card:focus-visible { background: var(--card); color: inherit; }
.atlas-card h3 { margin-block-end: .1rem; overflow-wrap: anywhere; }
.atlas-card .by { font-style: italic; color: var(--ink-2); font-size: .9rem; margin: 0 0 .8rem; }
.atlas-meta { font-family: var(--stamp); font-size: .74rem; color: var(--ink-3); letter-spacing: .03em; }
.atlas-card.is-quiet { opacity: .68; }
.atlas-card.is-quiet .atlas-meta { color: var(--red); }

/* ---- empty states: an invitation, not an apology ---- */
.empty {
 border: 1px dashed var(--rule);
 padding: clamp(1.75rem, 5vw, 3rem);
 text-align: center; margin: 2rem 0;
}
.empty h2 { margin-block-end: .4rem; }
.empty p { max-inline-size: 32em; margin-inline: auto; color: var(--ink-2); }
.empty .stamp-row { justify-content: center; margin-block-start: 1.5rem; opacity: .4; }
.empty .btn-row { justify-content: center; }

/* ---- check-in ---- */
.scan { max-width: 560px; margin-inline: auto; padding: var(--gap); }
.scan-hello { text-align: center; padding: 1.25rem 0 .5rem; }
.scan-hello h1 { font-size: clamp(1.7rem, 6.5vw, 2.5rem); }
.scan-hello .book-author { text-align: center; }

.progress { display: flex; gap: 4px; margin: 0 0 1.2rem; list-style: none; padding: 0; }
.progress li { flex: 1; height: 3px; background: var(--rule); transition: background .25s ease; }
.progress li.is-done { background: var(--violet); }

.js-steps .step { display: none; }
.js-steps .step.is-on { display: block; animation: stepIn .28s ease both; }
@keyframes stepIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.step-count { font-family: var(--stamp); font-size: .72rem; color: var(--ink-3); letter-spacing: .1em; margin-block-end: .8rem; }
.pick-wrap { position: relative; margin-block-end: .7rem; }
#pickmap { height: min(320px, 45vh); border: 1px solid var(--ink); }
.pick-state {
 font-family: var(--stamp); font-size: .78rem; text-align: center;
 margin: 0 0 1rem; padding: .55rem; border: 1px dashed var(--rule); color: var(--ink-3);
}
.pick-state.is-set { border-style: solid; border-color: var(--green); color: var(--green); }

.photo-preview { margin: .7rem 0 0; border: 1px solid var(--rule); padding: 5px; background: var(--card); max-inline-size: 220px; }

/* ---- language switcher ---- */
.lang-bar { display: flex; flex-wrap: wrap; gap: .3rem; justify-content: center; margin: 0 0 1.5rem; }
.lang-bar a {
 font-family: var(--display); font-size: .66rem; font-weight: 600;
 letter-spacing: .08em; text-transform: uppercase; text-decoration: none;
 color: var(--ink-3); border: 1px solid var(--rule);
 padding: .45rem .6rem; min-height: 34px; display: inline-flex; align-items: center; border-radius: 2px;
}
.lang-bar a:hover { color: var(--ink); border-color: var(--ink-2); }
.lang-bar a[aria-current="true"] { color: var(--paper); background: var(--ink); border-color: var(--ink); }

/* ---- offline + install ---- */
.bar-offline {
 position: fixed; inset-inline: 0; bottom: 0; z-index: 900;
 background: var(--ink); color: var(--paper-hi);
 font-family: var(--display); font-size: .74rem; letter-spacing: .05em;
 padding: .8rem 1rem; text-align: center;
 transform: translateY(110%); transition: transform .28s ease;
}
.bar-offline.is-on { transform: none; }

.install-prompt {
 display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; justify-content: space-between;
 border: 1px solid var(--rule); background: var(--card);
 padding: 1rem 1.2rem; margin: 2rem 0;
}
.install-prompt p { margin: 0; font-size: .92rem; }

/* ---- guide ---- */
.guide-body { max-width: 46em; }
.guide-body h2 {
 margin-block-start: 2.6rem; padding-block-start: 1.2rem; border-block-start: 1px solid var(--rule);
 scroll-margin-block-start: 5.5rem; /* clears the sticky masthead when a quick-link jumps here */
}
.guide-body ul, .guide-body ol { padding-inline-start: 1.25rem; }
.guide-body li { margin-block-end: .5rem; }
.guide-body blockquote {
 margin: 1.5rem 0; padding-inline-start: 1.2rem;
 border-inline-start: 2px solid var(--violet); font-style: italic; color: var(--ink-2);
}
.guide-nav { margin-block: 1.6rem 0; }
.template {
 font-family: var(--stamp); font-size: .86rem; line-height: 1.7;
 background: var(--card); border: 1px solid var(--rule);
 padding: 1.1rem; white-space: pre-wrap; margin: 1rem 0 1.5rem; overflow-wrap: anywhere;
}

/* ---- setup tiers: bare minimum to rich ---- */
.tier-grid {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
 gap: 1rem;
 margin: 1.4rem 0 1rem;
}
.tier-card {
 border: 1px solid var(--rule); background: var(--card);
 padding: 1.2rem 1.3rem;
}
.tier-kicker {
 font-family: var(--display); font-size: .64rem; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: var(--violet); margin: 0 0 .4rem;
}
.tier-card h3 { margin: 0 0 .5rem; font-size: 1.05rem; }
.tier-card p:last-child { margin: 0; font-size: .88rem; color: var(--ink-2); line-height: 1.6; }
.tier-card code {
 font-family: var(--stamp); font-size: .82em; background: var(--paper-hi);
 padding: .1em .3em; border-radius: 2px; overflow-wrap: anywhere;
}

/* ---- notes wall: quote cards pulled live from public hop notes ---- */
.notes-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.note-card { display: flex; flex-direction: column; }
.note-quote {
 font-style: italic; color: var(--ink-2); line-height: 1.6; margin: 0 0 .8rem;
 overflow-wrap: anywhere;
}
.note-meta { font-size: .8rem; color: var(--ink-3); margin: auto 0 0; }
.note-meta a { color: var(--violet); }

/* ---- guide: downloadable extras (blank plates, bookmarks) ---- */
.download-grid {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
 gap: .8rem;
 margin: 0 0 1.6rem;
}
.download-card {
 display: flex; flex-direction: column; gap: .3rem;
 border: 1px solid var(--rule); background: var(--card);
 padding: 1rem 1.1rem; text-decoration: none; color: inherit;
 transition: border-color .15s, background .15s;
}
.download-card:hover { border-color: var(--violet); background: var(--paper-hi); }
.download-title { font-family: var(--display); font-weight: 600; font-size: .92rem; color: var(--ink); }
.download-desc { font-size: .82rem; color: var(--ink-2); line-height: 1.5; }
.download-cta {
 font-family: var(--display); font-size: .68rem; font-weight: 600; letter-spacing: .1em;
 text-transform: uppercase; color: var(--violet); margin-top: .3rem;
}

/* ---- found a book: the landing page for someone with zero context ---- */
.find-ways {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
 gap: .8rem;
 margin: 1.8rem 0 2rem;
}
.find-way {
 display: flex; gap: .7rem; align-items: flex-start;
 border: 1px solid var(--rule); background: var(--card);
 padding: .9rem 1rem;
}
.find-way-icon {
 flex: none; display: grid; place-items: center;
 inline-size: 34px; block-size: 34px; color: var(--violet);
 border: 1px solid var(--rule); border-radius: 2px; background: var(--paper);
}
.find-way p { margin: 0; font-size: .84rem; line-height: 1.5; color: var(--ink-2); }
.find-way p strong { color: var(--ink); }
.find-form { margin-top: .4rem; }
.find-after { font-size: .9rem; color: var(--ink-2); margin: 1.4rem 0 0; max-width: 34em; }
.find-alt { margin-top: 1.2rem; }

/* ---- plate design picker (screen only) ---- */
.plate-controls {
 display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center;
 border: 1px solid var(--rule); background: var(--card); padding: 1rem 1.2rem; margin: 1.4rem 0;
}
.control-group { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; }
.control-label { font-family: var(--display); font-size: .68rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.control-group label { display: inline-flex; align-items: center; gap: .35rem; font-size: .84rem; }
.plate-controls .hint { flex-basis: 100%; margin: 0; }

/* ---- printable plate ----
   One content set, shown or trimmed per shape by CSS alone, so switching
   the radio buttons above re-flows instantly without touching the DOM.
   Base styles are already the black & white look; .plate--color layers
   the violet accents on top, so nothing needs a separate .plate--bw rule
   unless it's undoing something color added. */
.plate {
 width: 92mm; border: 2px solid #000; border-radius: 3mm; padding: 8mm 7mm;
 background: #fff; color: #191C24; margin: 0 auto 8mm; break-inside: avoid;
 font-family: var(--body);
}
.plate--color { border-color: #55338A; }

.plate-head { display: flex; align-items: baseline; justify-content: space-between; gap: 3mm; margin: 0 0 1.5mm; }
.plate-brand { display: flex; align-items: center; gap: 1.6mm; min-width: 0; }
.plate-logo { flex: none; display: block; color: #000; }
.plate-word-name { font-family: var(--display); font-weight: 700; font-size: 12pt; letter-spacing: .02em; white-space: nowrap; }
.plate--color .plate-logo, .plate--color .plate-word-name { color: #55338A; }
.plate-eyebrow {
 flex: none; font-family: var(--display); font-size: 6pt; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: #7a7a72;
}

.plate-tagline { font-style: italic; font-size: 9pt; color: #444; margin: 0; }

.plate-rule { border: 0; border-block-start: 1px solid #000; margin: 3mm 0; }
.plate--color .plate-rule { border-color: #D8CFEA; }

.plate-code {
 display: block; width: fit-content; max-width: 100%; margin: 0 auto 4mm;
 font-family: var(--stamp); font-weight: 700; font-size: 19pt; letter-spacing: .07em;
 text-align: center; padding: 2.2mm 5mm; border-radius: 2mm; border: 1.5px solid #000;
 background: #fff; color: #191C24; white-space: nowrap;
}
.plate--color .plate-code { background: #55338A; border-color: #55338A; color: #fff; }

.qr { display: block; width: 40mm; height: 40mm; margin: 0 auto 2mm; background: #f3f1ea; border: 1px solid #e2dcc8; }
.qr canvas, .qr img { display: block; width: 100%; height: 100%; }

.plate-url { font-family: var(--stamp); font-size: 7.5pt; text-align: center; margin: 0; color: #555; word-break: break-all; }
.plate-nfc {
 display: flex; align-items: center; justify-content: center; gap: 1mm;
 font-family: var(--stamp); font-size: 6.8pt; color: #555; margin: 1.5mm 0 0;
}
.plate-nfc svg { flex: none; }

.plate-steps {
 display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap;
 margin: 0; padding: 2.4mm 3mm; list-style: none; background: #F2EEE3; border-radius: 2mm;
}
.plate-step {
 display: flex; align-items: center; gap: 1mm; font-size: 6.6pt;
 font-family: var(--display); font-weight: 600; letter-spacing: .01em; white-space: nowrap;
}
.plate-step svg { flex: none; }

.plate-body p { font-size: 7.8pt; line-height: 1.55; color: #333; margin: 0 0 2mm; }
.plate-body p:last-child { margin-block-end: 0; }

.plate-owner { font-size: 6.5pt; font-style: italic; color: #666; margin: 0 0 1mm; }
.plate-lang { font-family: var(--stamp); font-size: 6.5pt; line-height: 1.45; color: #666; margin: 0; }

.plate-cta { font-size: 6.8pt; font-style: italic; color: #555; text-align: center; margin: 0; }
.plate--color .plate-cta { color: #55338A; }

.plate-track-label {
 font-family: var(--display); font-size: 6pt; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: #7a7a72;
 text-align: center; margin: 0 0 1.5mm;
}

.plate-footer {
 display: flex; justify-content: center; align-items: center; flex-wrap: wrap; gap: 0 1.5mm;
 font-family: var(--display); font-size: 6.6pt; font-weight: 600; letter-spacing: .02em; color: #7a7a72;
}
.plate-footer span { display: inline-flex; align-items: center; gap: .8mm; white-space: nowrap; }
.plate-footer svg { flex: none; }
.plate-footer span:not(:last-child)::after { content: '\00b7'; margin-inline-start: 1.5mm; color: #b3ab97; }

/* square and circle are quick stickers: header, code, QR, footer, nothing
   else this content set carries for the full plate */
.plate--square, .plate--circle { width: 76mm; text-align: center; }
.plate--square .plate-eyebrow, .plate--circle .plate-eyebrow,
.plate--square .plate-tagline, .plate--circle .plate-tagline,
.plate--square .plate-steps, .plate--circle .plate-steps,
.plate--square .plate-body, .plate--circle .plate-body,
.plate--square .plate-owner, .plate--circle .plate-owner,
.plate--square .plate-lang, .plate--circle .plate-lang,
.plate--square .plate-track-label, .plate--circle .plate-track-label,
.plate--square .plate-cta, .plate--circle .plate-cta { display: none; }
.plate--square .plate-head, .plate--circle .plate-head { justify-content: center; }
.plate--square .plate-rule:not(:first-of-type) { display: none; }
.plate--circle .plate-rule,
.plate--circle .plate-url,
.plate--circle .plate-nfc { display: none; }
.plate--square .qr { width: 36mm; height: 36mm; }
.plate--circle .qr { width: 28mm; height: 28mm; }
.plate--circle .plate-code { font-size: 13pt; }
.plate--circle .plate-footer { margin-block-start: 1.5mm; }

.plate--circle {
 height: 76mm; border-radius: 50%;
 display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 8mm;
}

/* Horizontal: two columns via CSS Grid straight on .plate--horizontal's
   flat children, no wrapper divs, so the shape-switcher's live className
   swap doesn't need to touch the DOM. Rules are dividers between stacked
   sections in the portrait shapes; a two-column layout gets its separation
   from the columns themselves, so they're simply hidden here. Owner credit
   and the extra language line are dropped in this shape to keep a wide,
   busy layout from getting busier; they still show on every other shape. */
.plate--horizontal {
 width: 136mm; display: grid; align-items: start;
 grid-template-columns: 50mm 1fr; column-gap: 6mm;
 grid-template-areas:
  "head head"
  "tag  tag"
  "code steps"
  "qr   steps"
  "url  body"
  "nfc  body"
  "foot foot";
}
.plate--horizontal .plate-rule,
.plate--horizontal .plate-owner,
.plate--horizontal .plate-lang,
.plate--horizontal .plate-track-label,
.plate--horizontal .plate-cta { display: none; }
.plate--horizontal .plate-head { grid-area: head; }
.plate--horizontal .plate-tagline { grid-area: tag; margin-block-end: 2.5mm; padding-block-end: 2.5mm; border-block-end: 1px solid #ddd; }
.plate--horizontal .plate-code { grid-area: code; margin: 0 0 2.5mm; justify-self: start; }
.plate--horizontal .qr { grid-area: qr; margin: 0 0 2mm; justify-self: start; }
.plate--horizontal .plate-url { grid-area: url; }
.plate--horizontal .plate-nfc { grid-area: nfc; justify-content: flex-start; }
.plate--horizontal .plate-steps {
 grid-area: steps; flex-direction: column; align-items: flex-start; justify-content: flex-start;
 gap: 2.2mm; background: none; border-radius: 0; padding: 0; align-self: start;
}
.plate--horizontal .plate-body { grid-area: body; align-self: start; }
.plate--horizontal .plate-footer { grid-area: foot; margin-block-start: 2.5mm; padding-block-start: 2.5mm; border-block-start: 1px solid #ddd; }

/* ---- the designed plate: art background, three live things on top ----
 A real <img>, not a CSS background-image, on purpose: background-images
 need "print backgrounds" enabled in the browser's print dialog or they
 silently vanish on paper, an <img> always prints. Everything positioned
 on top of it is real content for the same reason. */
.plate-art {
 position: relative; margin: 0 auto 4mm; break-inside: avoid; overflow: hidden;
}
.plate-art-bg { display: block; width: 100%; height: 100%; }
.plate-art-qr, .plate-art-code, .plate-art-url { position: absolute; }
.plate-art-qr img { display: block; width: 100%; height: 100%; }
.plate-art-code, .plate-art-url {
 display: flex; align-items: center; justify-content: center;
 font-family: var(--stamp); text-align: center; white-space: nowrap;
}
.plate-art-code { font-weight: 700; letter-spacing: .05em; color: #191C24; }
.plate-art-url { color: #555; }

/* Only the selected design's block actually takes up space or prints;
 display:contents on the active one so its plates lay out exactly as if
 the wrapper weren't there. */
.plate-design-block { display: none; }
.plate-design-block.is-active { display: contents; }

@media print {
 .masthead, .colophon, .noprint, .bar-offline { display: none !important; }
 body { background: #fff; color: #000; font-size: 12pt; background-image: none; }
 .plate, .plate-art { break-inside: avoid; }
}

/* ---- footer ---- */
.colophon {
 border-block-start: 1px solid var(--ink); margin-block-start: 4rem;
 padding: 2rem var(--gap) 3rem; max-width: 1080px; margin-inline: auto;
}
.colophon-line { font-family: var(--display); font-weight: 600; font-size: .95rem; }
.colophon nav { display: flex; gap: .3rem 1.2rem; flex-wrap: wrap; margin: .8rem 0; }
.colophon nav a {
 font-family: var(--display); font-size: .7rem; font-weight: 600;
 letter-spacing: .1em; text-transform: uppercase; text-decoration: none; color: var(--ink-2);
 min-height: var(--tap); display: inline-flex; align-items: center;
}
.colophon-fine { font-size: .8rem; color: var(--ink-3); max-inline-size: 46em; margin: 1rem 0 0; }
.colophon-fine a { color: var(--violet); text-decoration: underline; text-underline-offset: 2px; }

/* ---- responsive ---- */
@media (max-width: 760px) {
 .slip-hop { grid-template-columns: 1fr; gap: 1rem; }
 .stamp { inline-size: 9.5rem; }
}
@media (max-width: 400px) {
 body { font-size: 17px; }
 .stamp { inline-size: calc(50% - .5rem); min-inline-size: 8.5rem; }
 .btn-row .btn { inline-size: 100%; }
}

@media (prefers-reduced-motion: reduce) {
 html { scroll-behavior: auto; }
 *, *::before, *::after {
 animation-duration: .001ms !important;
 animation-iteration-count: 1 !important;
 transition-duration: .001ms !important;
 }
}

/* ============================================================
 Immersive layer. Everything here is additive: with JS off, or
 on the plain tier, the page keeps its original static form.
 ============================================================ */

/* ---- scroll reveals ---- */
[data-reveal] {
 opacity: 0;
 transform: translateY(14px);
 transition: opacity .7s cubic-bezier(.2,.7,.3,1), transform .7s cubic-bezier(.2,.7,.3,1);
 will-change: opacity, transform;
}
[data-reveal].is-in { opacity: 1; transform: none; }
[data-motion="off"] [data-reveal] { opacity: 1; transform: none; transition: none; }
/* Never let a reveal hide content if the script fails to run. */
.no-js [data-reveal] { opacity: 1; transform: none; }

/* ---- the pinned journey ---- */
.journey-stage { margin: 2.5rem 0 0; }

.journey-stage.is-cinematic {
 display: grid;
 grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
 gap: clamp(1.5rem, 4vw, 3rem);
 align-items: start;
}
.journey-stage.is-cinematic .journey-pin {
 position: sticky;
 top: clamp(1rem, 6vh, 4rem);
 align-self: start;
}
.journey-stage.is-cinematic .slip { margin-top: 0; }
.journey-stage.is-cinematic .slip-hop { grid-template-columns: 1fr; gap: .9rem; }

/* the map itself */
.journey-pin { position: relative; }
#journey-map {
 height: clamp(320px, 62vh, 560px);
 border: 1px solid var(--ink);
 background: var(--paper-hi);
}
.journey-stage.is-static #journey-map { height: clamp(300px, 52vh, 520px); }
#journey-map .leaflet-control-zoom { display: none; }

/* the caption sits on the map like a slug line */
.journey-caption {
 position: absolute;
 inset-inline-start: 0;
 bottom: 0;
 z-index: 500;
 display: flex;
 flex-direction: column;
 gap: 1px;
 background: var(--paper);
 border: 1px solid var(--ink);
 border-inline-start: 3px solid var(--violet);
 padding: .6rem .85rem;
 margin: 0 0 0 -1px;
 font-family: var(--stamp);
 opacity: 0;
 transform: translateY(6px);
 transition: opacity .35s ease, transform .35s ease;
 max-inline-size: 78%;
}
.journey-caption.is-in { opacity: 1; transform: none; }
.journey-caption .jc-seq { font-size: .62rem; letter-spacing: .16em; color: var(--ink-3); }
.journey-caption .jc-where { font-size: 1rem; font-weight: 700; letter-spacing: .03em; overflow-wrap: anywhere; }
.journey-caption .jc-when { font-size: .7rem; color: var(--ink-3); }
.journey-stage.is-static .journey-caption { display: none; }

/* the hop being read is lit; the rest recede */
.journey-stage.is-cinematic .slip-hop {
 opacity: .4;
 transition: opacity .45s ease;
}
.journey-stage.is-cinematic .slip-hop.is-current { opacity: 1; }
[data-motion="off"] .journey-stage.is-cinematic .slip-hop { opacity: 1; }

@media (max-width: 899px) {
 .journey-stage.is-cinematic { grid-template-columns: 1fr; }
 .journey-stage.is-cinematic .journey-pin { position: static; }
 .journey-stage.is-cinematic .slip-hop { opacity: 1; }
}

/* ---- hero sequence on the home page ---- */
[data-motion="on"] .hero-title-line {
 display: block;
 opacity: 0;
 transform: translateY(18px);
 animation: riseIn .9s cubic-bezier(.2,.75,.25,1) forwards;
}
[data-motion="on"] .hero-title-line:nth-child(2) { animation-delay: .12s; }
@keyframes riseIn { to { opacity: 1; transform: none; } }

/* ---- page transitions, where the browser supports them ---- */
@media (prefers-reduced-motion: no-preference) {
 @view-transition { navigation: auto; }
}
::view-transition-old(root) { animation: vtOut .18s ease both; }
::view-transition-new(root) { animation: vtIn .28s ease both; }
@keyframes vtOut { to { opacity: 0; } }
@keyframes vtIn { from { opacity: 0; } }

/* ============================================================
 Emblems, the device inside a stamp, like a passport mark
 ============================================================ */
.stamp { position: relative; }
.stamp-emblem {
 position: absolute;
 inset-block-start: .35rem;
 inset-inline-end: .4rem;
 opacity: .28;
 pointer-events: none;
 line-height: 0;
}
.stamp.has-emblem .stamp-where { padding-inline-end: 1.6rem; }
.stamp-emblem--br {
 inset-block-start: auto; inset-block-end: .35rem; inset-inline-end: .4rem;
}
.stamp.has-emblem:has(.stamp-emblem--br) .stamp-where { padding-inline-end: 0; }
.stamp.has-emblem:has(.stamp-emblem--br) .stamp-country { padding-inline-end: 1.8rem; }
.emblem { display: block; }
.emblem--img { object-fit: contain; filter: grayscale(1) contrast(1.4); }

/* ============================================================
 Status bar, the register of a parcel service
 ============================================================ */
.status-bar {
 display: flex;
 flex-wrap: wrap;
 align-items: baseline;
 gap: .45rem .9rem;
 padding: .7rem .95rem;
 border: 1px solid var(--rule);
 border-inline-start: 3px solid var(--violet);
 background: var(--card);
 margin-block-start: 1.1rem;
}
.status-dot {
 inline-size: 9px; block-size: 9px; border-radius: 50%;
 background: var(--violet); align-self: center; flex: 0 0 auto;
}
.status-bar.is-moving .status-dot { animation: livePulse 2s ease-in-out infinite; }
@keyframes livePulse {
 0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--violet) 55%, transparent); }
 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--violet) 0%, transparent); }
}
.status-what {
 font-family: var(--display); font-weight: 700; font-size: .74rem;
 letter-spacing: .12em; text-transform: uppercase;
}
.status-where { font-family: var(--body); font-size: 1rem; }
.status-when { font-family: var(--stamp); font-size: .72rem; color: var(--ink-3); }

.status-bar.is-quiet { border-inline-start-color: var(--red); }
.status-bar.is-quiet .status-dot { background: var(--red); }
.status-bar.is-home { border-inline-start-color: var(--red); }
.status-bar.is-home .status-dot { background: var(--red); }
.status-bar.is-done { border-inline-start-color: var(--ink-4); }
.status-bar.is-done .status-dot { background: var(--ink-4); }

.scale-note {
 font-size: .95rem; color: var(--ink-2);
 border-inline-start: 2px solid var(--rule);
 padding-inline-start: 1rem; margin: 1.5rem 0;
}
.book-story { margin: 2.5rem 0; max-width: 44em; }
.watch-block { margin-block-start: 3.5rem; max-width: 34em; }
.watch-count {
 display: flex; align-items: center; gap: .5rem;
 font-family: var(--display); font-size: .82rem; font-weight: 600; color: var(--violet);
 margin: .6rem 0 1.2rem;
}
.watch-count-dot {
 inline-size: 8px; block-size: 8px; border-radius: 50%; flex: 0 0 auto;
 background: var(--violet); animation: livePulse 2s ease-in-out infinite;
}

/* ============================================================
 The tracker
 ============================================================ */
.tracker { margin-block-start: 2.5rem; }
.tracker-head {
 display: flex; align-items: baseline; justify-content: space-between;
 gap: 1rem; border-block-end: 1px solid var(--ink); padding-block-end: .6rem;
}
.tracker-toggle {
 background: none; border: 0; cursor: pointer; padding: .4rem 0;
 font-family: var(--display); font-size: .66rem; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: var(--violet);
}
.tracker-toggle:hover { color: var(--ink); }

.track { list-style: none; margin: 0; padding: 0; }

.track-node {
 position: relative;
 padding-inline-start: 2.6rem;
 padding-block: .35rem;
}
/* the line the nodes hang from */
.track-node::before {
 content: "";
 position: absolute;
 inset-inline-start: .78rem;
 inset-block: 0;
 inline-size: 2px;
 background: var(--rule);
}
.track-node:first-child::before { inset-block-start: 1.4rem; }
.track-node:last-child::before { inset-block-end: calc(100% - 1.4rem); }

.track-marker { position: absolute; inset-inline-start: 0; inset-block-start: .9rem; z-index: 1; }
.track-pip {
 display: grid; place-items: center;
 inline-size: 1.65rem; block-size: 1.65rem;
 border: 2px solid var(--violet);
 border-radius: 50%;
 background: var(--paper);
 color: var(--violet);
}
.track-node--release .track-pip { border-color: var(--ink); color: var(--ink); }
.track-node--sighting .track-pip { border-style: dashed; }
.track-node--home .track-pip { border-color: var(--red); color: var(--red); }

.track-node.is-latest .track-pip {
 background: var(--violet);
 color: var(--paper);
 box-shadow: 0 0 0 4px color-mix(in srgb, var(--violet) 18%, transparent);
}
[data-motion="on"] .track-node.is-latest .track-pip { animation: pipPulse 2.4s ease-in-out infinite; }
@keyframes pipPulse {
 0%,100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--violet) 22%, transparent); }
 50% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--violet) 0%, transparent); }
}

.track-leg {
 display: flex; gap: .9rem; flex-wrap: wrap;
 font-family: var(--stamp); font-size: .68rem; color: var(--ink-3);
 letter-spacing: .04em; margin: 0 0 .1rem; padding-block: .5rem;
}
.track-leg span { position: relative; }
.track-leg span + span::before {
 content: "·"; position: absolute; inset-inline-start: -.55rem; color: var(--ink-4);
}

.track-card {
 border: 1px solid var(--rule);
 background: var(--paper-hi);
 margin-block-end: .5rem;
 transition: border-color .18s ease, background .18s ease;
}
.track-card[open] { border-color: var(--ink-2); background: var(--card); }
.track-card:hover { border-color: var(--ink-2); }
.track-node.is-latest > .track-card { border-color: var(--violet); }

/* Landed here from a stamp: a brief flash so the jump reads as arrival,
 not a silent scroll. */
.track-node--jumped > .track-card { animation: hopFlash 1.6s ease; }
@keyframes hopFlash {
 0% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--violet) 35%, transparent); }
 100% { box-shadow: 0 0 0 0 transparent; }
}

.track-card > summary,
.track-summary-inner {
 display: flex; align-items: flex-start; gap: .75rem;
 padding: .8rem .95rem;
 cursor: pointer;
 list-style: none;
}
.track-card--flat > .track-summary-inner { cursor: default; }
.track-card > summary::-webkit-details-marker { display: none; }
.track-card > summary:focus-visible { outline: 2px solid var(--violet); outline-offset: -2px; }

.track-seq {
 font-family: var(--stamp); font-size: .68rem; font-weight: 700;
 color: var(--ink-4); padding-block-start: .18rem; flex: 0 0 auto;
}
.track-main { display: flex; flex-direction: column; gap: .1rem; min-inline-size: 0; flex: 1 1 auto; }
.track-where {
 font-family: var(--display); font-weight: 600; font-size: 1rem;
 line-height: 1.2; overflow-wrap: anywhere;
}
.track-sub { font-family: var(--body); font-style: italic; font-size: .85rem; color: var(--ink-2); }
.track-when { font-family: var(--stamp); font-size: .7rem; color: var(--ink-3); letter-spacing: .03em; }

.track-chevron {
 flex: 0 0 auto; align-self: center;
 inline-size: .55rem; block-size: .55rem;
 border-inline-end: 2px solid var(--ink-3);
 border-block-end: 2px solid var(--ink-3);
 transform: rotate(45deg);
 transition: transform .22s ease;
}
.track-card[open] .track-chevron { transform: rotate(-135deg); }

.track-detail {
 padding: 0 .95rem 1rem;
 border-block-start: 1px dashed var(--rule);
 margin-block-start: -.2rem;
 padding-block-start: .9rem;
}
[data-motion="on"] .track-card[open] .track-detail { animation: openIn .3s ease both; }
@keyframes openIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }

.track-place { font-family: var(--display); font-weight: 600; font-size: .92rem; margin: 0 0 .5rem; }
.track-note { font-size: 1.02rem; margin: 0 0 .6rem; overflow-wrap: anywhere; }
.track-photo { margin: 0 0 .8rem; border: 1px solid var(--rule); padding: 6px; background: var(--paper-hi); max-inline-size: 380px; }
.track-photo img { inline-size: 100%; height: auto; }

.track-open-end {
 display: flex; align-items: center; gap: .95rem;
 font-family: var(--stamp); font-size: .74rem; color: var(--ink-3);
 margin: .6rem 0 0; padding-inline-start: 0;
}
.track-pip--empty {
 inline-size: 1.65rem; block-size: 1.65rem;
 border: 2px dashed var(--rule); border-radius: 50%;
 display: inline-block; flex: 0 0 auto;
}

/* ============================================================
 The map, made to look considered rather than default Leaflet
 ============================================================ */
.map-shell {
 position: relative;
 border: 1px solid var(--ink);
 background: var(--paper-hi);
 overflow: hidden;
}
.map-grain {
 position: absolute; inset: 0; z-index: 400; pointer-events: none;
 background:
 repeating-linear-gradient(0deg, rgba(128,128,128,.05) 0 1px, transparent 1px 3px),
 radial-gradient(ellipse at center, transparent 52%, color-mix(in srgb, var(--ink) 22%, transparent) 100%);
 mix-blend-mode: multiply;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .map-grain { mix-blend-mode: screen; opacity: .5; } }
:root[data-theme="dark"] .map-grain { mix-blend-mode: screen; opacity: .5; }

/* route styling that survives Leaflet's own defaults */
.route-leg { filter: drop-shadow(0 0 3px color-mix(in srgb, var(--violet) 45%, transparent)); }
.route-dot { filter: drop-shadow(0 0 2px color-mix(in srgb, var(--violet) 35%, transparent)); }

.map-switch {
 position: absolute; z-index: 450;
 inset-block-start: .6rem; inset-inline-end: .6rem;
 display: flex; border: 1px solid var(--ink); background: var(--paper); border-radius: 2px;
 overflow: hidden;
}
.ms-btn {
 border: 0; background: none; cursor: pointer;
 padding: .5rem .75rem; min-height: 36px;
 font-family: var(--display); font-size: .62rem; font-weight: 600;
 letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2);
}
.ms-btn + .ms-btn { border-inline-start: 1px solid var(--rule); }
.ms-btn.is-on { background: var(--ink); color: var(--paper); }

#mini-globe { height: clamp(300px, 52vh, 520px); touch-action: pan-y; cursor: grab; }
#mini-globe canvas { display: block; inline-size: 100%; block-size: 100%; }
#mini-globe.is-loading::after {
 content: "Loading the globe…";
 position: absolute; inset: 0; display: grid; place-items: center;
 font-family: var(--stamp); font-size: .8rem; color: var(--ink-3);
}
.globe-fail { padding: 2rem 1rem; text-align: center; font-family: var(--stamp); font-size: .8rem; color: var(--ink-3); }

/* Leaflet zoom control, restyled to match */
.leaflet-touch .leaflet-bar a { inline-size: 34px; block-size: 34px; line-height: 34px; }

@media (max-width: 760px) {
 .track-node { padding-inline-start: 2.35rem; }
 .track-where { font-size: .95rem; }
 .status-bar { flex-direction: column; align-items: flex-start; gap: .3rem; }
 #journey-map { height: clamp(260px, 44vh, 380px); }
}

/* ---- admin: shared tab bar across admin-*.php ---- */
.admin-nav {
 display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1.1rem;
 margin: 0 0 1.6rem; padding-block-end: .9rem; border-block-end: 1px solid var(--rule);
 font-family: var(--display); font-size: .78rem; font-weight: 600;
 letter-spacing: .03em;
}
.admin-nav a { color: var(--ink-2); text-decoration: none; padding: .15rem 0; }
.admin-nav a:hover { color: var(--ink); }
.admin-nav a[aria-current] { color: var(--violet); border-block-end: 2px solid var(--violet); }
.admin-nav-out { margin-inline-start: auto; color: var(--ink-3) !important; font-weight: 500 !important; }

/* ---- admin: plain data table, used by books/hops/analytics ---- */
.admin-table-wrap { overflow-x: auto; margin-block-end: 2rem; }
.admin-table { width: 100%; border-collapse: collapse; font-size: .84rem; }
.admin-table th, .admin-table td {
 padding: .55rem .7rem; border-block-end: 1px solid var(--rule); text-align: start;
 vertical-align: top;
}
.admin-table th { font-family: var(--display); font-size: .68rem; text-transform: uppercase;
 letter-spacing: .07em; color: var(--ink-3); font-weight: 600; }
.admin-table tr:hover td { background: var(--card); }
.admin-table .num { text-align: end; font-family: var(--stamp); }

/* ---- admin: kpi summary cards, used by analytics ---- */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1px;
 background: var(--rule); border: 1px solid var(--rule); margin-block-end: 2rem; }
.kpi-card { background: var(--paper); padding: 1rem 1.1rem; }
.kpi-card .kpi-num { font-family: var(--display); font-size: 1.7rem; font-weight: 700; line-height: 1.1; }
.kpi-card .kpi-label { font-size: .72rem; color: var(--ink-3); margin-block-start: .2rem; }

/* ---- admin: simple two-column form grid, used by books/hops/content editors ---- */
.admin-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 1.2rem; }
.admin-form-grid .field { margin-block-end: 1rem; }

/* ---- admin: emblem picker ---- */
.emblem-form { max-width: 52em; margin-block-start: 1.5rem; }
.emblem-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 1rem; }
.emblem-picker {
 display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
 gap: 1px; background: var(--rule); border: 1px solid var(--rule);
}
.emblem-choice { margin: 0; cursor: pointer; }
.emblem-choice input { position: absolute; opacity: 0; pointer-events: none; }
.emblem-swatch {
 display: flex; flex-direction: column; align-items: center; gap: .35rem;
 padding: .8rem .4rem; background: var(--paper); color: var(--ink-2);
 text-align: center; min-block-size: 100%;
 transition: background .15s ease, color .15s ease;
}
.emblem-swatch span {
 font-family: var(--stamp); font-size: .62rem; line-height: 1.25; color: var(--ink-3);
}
.emblem-choice:hover .emblem-swatch { background: var(--card); color: var(--ink); }
.emblem-choice input:checked + .emblem-swatch { background: var(--violet); color: var(--paper); }
.emblem-choice input:checked + .emblem-swatch span { color: var(--paper); }
.emblem-choice input:focus-visible + .emblem-swatch { outline: 2px solid var(--violet); outline-offset: -2px; }

/* ============================================================
 Hero, the globe sits behind and beyond the words, cropped by
 the viewport rather than boxed. Interactive where it shows.
 ============================================================ */
.hero-stage {
 position: relative;
 padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(2rem, 5vw, 4rem);
 min-block-size: clamp(520px, 82vh, 820px);
 display: flex;
 align-items: center;
 /* Clip the globe to the hero rectangle so it stays strictly below the sticky
  header. Prevents the globe overlapping the header on scroll and keeps the
  header's own buttons clickable. Horizontal bleeds still work; only the top
  and bottom edges are clipped by this. */
 overflow: hidden;
 isolation: isolate;
}
.hero-stage.is-bare { min-block-size: auto; }

/* The words stay within the reading column; only the globe bleeds wide. */
.hero-words {
 position: relative;
 z-index: 3;
 max-width: 34rem;
 margin-inline: auto;
 inline-size: 100%;
 padding-inline: var(--gap);
 box-sizing: content-box;
 /* pin the column to the same left edge as the rest of the page */
 margin-inline-start: max(var(--gap), calc((100vw - 1400px) / 2 + var(--gap)));
 margin-inline-end: auto;
}
.hero-hint {
 font-family: var(--stamp); font-size: .74rem; color: var(--ink-3);
 margin-block-start: 1.2rem; letter-spacing: .03em;
}
[data-rich="off"] .hero-hint { display: none; }

.hero-globe {
 position: absolute;
 z-index: 1;
 inset-block: 0;
 inset-inline-end: 0; /* anchored to the real screen edge */
 inline-size: min(60vw, 880px);
 pointer-events: none; /* only the globe itself takes the pointer */
}
.hero-globe .globe-stage { position: relative; block-size: 100%; }
.hero-globe #globe { pointer-events: auto; }

@media (max-width: 1100px) {
 .hero-globe { inline-size: min(66vw, 720px); opacity: .92; }
}
@media (max-width: 860px) {
 .hero-stage { flex-direction: column; align-items: stretch; min-block-size: auto; }
 .hero-globe { position: static; inline-size: 100%; margin-block-start: 2rem; order: 2; opacity: 1; }
 .hero-words { order: 1; max-width: none; margin-inline: 0; box-sizing: border-box; }
}

#globe {
 display: none;
 block-size: 0;
 overflow: hidden;
 cursor: grab;
 touch-action: pan-y;
 transition: block-size .7s cubic-bezier(.2,.7,.3,1);
}
[data-rich="on"] #globe { display: block; }
#globe.is-live { block-size: clamp(460px, 86vh, 860px); }
@media (max-width: 860px) { #globe.is-live { block-size: clamp(340px, 52vh, 460px); } }
#globe.is-grabbing { cursor: grabbing; }
#globe.is-pointing { cursor: pointer; }
#globe canvas { display: block; inline-size: 100%; block-size: 100%; }

body.has-globe .globe-fallback { display: none; }
.globe-fallback { pointer-events: auto; }

/* On the book page, the globe sits inside the map-shell next to the record. It
 needs to be sized to the shell, not to the viewport, or it takes over the page. */
.map-shell #globe.is-live { block-size: clamp(320px, 52vh, 520px); }

/* The books page reuses the homepage hero (left text, right globe) but at a
 shorter scale, it's a section header, not the front door. */
.hero-stage--books { min-block-size: clamp(400px, 58vh, 600px); }
.hero-stage--books .hero-globe { inline-size: min(52vw, 640px); }
.hero-stage--books #globe.is-live { block-size: clamp(300px, 46vh, 480px); }
@media (max-width: 860px) {
 .hero-stage--books #globe.is-live { block-size: clamp(260px, 40vh, 360px); }
}

/* ---- tooltip ---- */
.globe-tip {
 position: absolute; z-index: 20; pointer-events: none;
 display: flex; flex-direction: column; gap: 1px;
 max-inline-size: 17rem;
 padding: .6rem .8rem;
 background: var(--paper);
 border: 1px solid var(--ink);
 border-inline-start: 3px solid var(--violet);
 box-shadow: 4px 4px 0 rgba(0,0,0,.14);
 opacity: 0;
 transform: translate(14px, -50%) scale(.97);
 transition: opacity .14s ease, transform .14s ease;
}
.globe-tip.is-on { opacity: 1; transform: translate(14px, -50%) scale(1); }
.gt-title { font-family: var(--display); font-weight: 700; font-size: .95rem; line-height: 1.2; }
.gt-author { font-family: var(--body); font-style: italic; font-size: .85rem; color: var(--ink-2); }
.gt-meta { font-family: var(--stamp); font-size: .7rem; color: var(--ink-3); margin-block-start: .25rem; }
.gt-go { font-family: var(--display); font-size: .62rem; font-weight: 600; letter-spacing: .12em;
 text-transform: uppercase; color: var(--violet); margin-block-start: .4rem; }

/* ============================================================
 Bands and section headers
 ============================================================ */
.band { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.band--stamps { border-block: 1px solid var(--rule); background: color-mix(in srgb, var(--card) 55%, transparent); }
.band-head { max-width: 40em; margin-block-end: 2rem; }
.band-head h2 { margin-block-end: .3rem; }
.band-head p { color: var(--ink-2); margin: 0; }

.ledger--wide { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }

/* ---- symmetric grid of stamps ---- */
.stamp-grid {
 display: grid;
 grid-template-columns: repeat(6, minmax(0, 1fr));
 gap: 1.1rem .8rem;
 justify-items: center;
}
.stamp-grid .stamp { inline-size: 100%; max-inline-size: 11rem; }
@media (max-width: 1100px) { .stamp-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 760px) { .stamp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 460px) { .stamp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem .6rem; } }

/* ---- photographs from readers ---- */
.sight-grid {
 display: grid;
 grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
 gap: 1px;
 background: var(--rule);
 border: 1px solid var(--rule);
}
.sight {
 position: relative; display: block; background: var(--paper);
 text-decoration: none; color: inherit; overflow: hidden;
 aspect-ratio: 4 / 5;
}
.sight img {
 inline-size: 100%; block-size: 100%; object-fit: cover;
 filter: saturate(.88) contrast(1.03);
 transition: transform .7s cubic-bezier(.2,.7,.3,1), filter .4s ease;
}
.sight:hover img, .sight:focus-visible img { transform: scale(1.045); filter: saturate(1) contrast(1.05); }
.sight-cap {
 position: absolute; inset-inline: 0; inset-block-end: 0;
 display: flex; flex-direction: column; gap: .1rem;
 padding: 1.6rem .85rem .8rem;
 background: linear-gradient(to top, rgba(15,16,20,.82), rgba(15,16,20,0));
 color: #F3F1EA;
}
.sight-where { font-family: var(--display); font-weight: 600; font-size: .88rem; }
.sight-title { font-family: var(--stamp); font-size: .68rem; opacity: .82; }

/* On narrow screens a long stacked grid is a lot of scrolling for photos
   that are meant to be browsed quickly, side to side, like a strip of
   prints, instead. */
@media (max-width: 640px) {
 .sight-grid {
 display: flex;
 grid-template-columns: none;
 overflow-x: auto;
 overscroll-behavior-x: contain;
 scroll-snap-type: x proximity;
 -webkit-overflow-scrolling: touch;
 gap: .6rem;
 background: none;
 border: none;
 padding-block-end: .5rem;
 margin-inline: calc(var(--gap) * -1);
 padding-inline: var(--gap);
 scroll-padding-inline: var(--gap);
 scrollbar-width: none;
 }
 .sight-grid::-webkit-scrollbar { display: none; }
 .sight-grid .sight {
 flex: 0 0 auto;
 inline-size: min(68vw, 280px);
 scroll-snap-align: start;
 border: 1px solid var(--rule);
 }
}

/* ---- the social experiment ---- */
.band--experiment { border-block-start: 1px solid var(--rule); }
.experiment-wrap { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 860px) { .experiment-wrap { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); } }
.experiment-copy h2 { max-inline-size: 17em; }
.experiment-copy p {
 color: var(--ink-2);
 max-inline-size: 36em;
 margin: 0 0 1.3em;
 font-size: 1.08rem;
 line-height: 1.75;
 letter-spacing: .003em;
}
.experiment-copy p:last-child { margin-block-end: 0; }
/* The opening line carries the argument, set a shade larger and darker so
   the eye lands there first, the way a good lede works in print. */
.experiment-copy p:first-of-type { font-size: 1.2rem; color: var(--ink); }
.experiment-art { order: -1; }
.experiment-art img { inline-size: 100%; block-size: auto; max-block-size: 22rem; object-fit: contain; }
@media (min-width: 860px) { .experiment-art { order: 1; } }

/* Two renders of the same artwork (one per theme), only one shown at a
   time. Same explicit-override + prefers-color-scheme-fallback pattern
   used everywhere else theme-swapped assets appear on this site. */
.experiment-art .map-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .experiment-art .map-light { display: none; }
  :root:not([data-theme="light"]) .experiment-art .map-dark { display: block; }
}
:root[data-theme="dark"] .experiment-art .map-light { display: none; }
:root[data-theme="dark"] .experiment-art .map-dark { display: block; }

/* ---- how it works ---- */
.band--how { border-block-start: 1px solid var(--rule); }
.how-wrap { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 900px) { .how-wrap { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); } }
.how-art { color: var(--violet); }
.how-art img { inline-size: 100%; block-size: auto; max-block-size: 30rem; object-fit: contain; }

.how-art .map-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .how-art .map-light { display: none; }
  :root:not([data-theme="light"]) .how-art .map-dark { display: block; }
}
:root[data-theme="dark"] .how-art .map-light { display: none; }
:root[data-theme="dark"] .how-art .map-dark { display: block; }

.steps { list-style: none; margin: 1.5rem 0; padding: 0; }
.steps li {
 display: grid; grid-template-columns: 3rem minmax(0, 1fr); gap: .3rem 1rem;
 padding-block: 1rem; border-block-start: 1px solid var(--rule);
}
.steps li:last-child { border-block-end: 1px solid var(--rule); }
.step-n { font-family: var(--stamp); font-size: .95rem; font-weight: 700; color: var(--violet); }
.step-body { display: flex; flex-direction: column; gap: .2rem; }
.step-body strong { font-family: var(--display); font-size: 1.02rem; font-weight: 600; }
.step-body { color: var(--ink-2); }
.step-body strong { color: var(--ink); }

/* ============================================================
 Books gallery
 ============================================================ */
.filter-bar { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1.8rem 0 0; }
.filter-bar a {
 font-family: var(--display); font-size: .68rem; font-weight: 600;
 letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
 color: var(--ink-2); border: 1px solid var(--rule);
 padding: .5rem .8rem; min-height: 38px; display: inline-flex; align-items: center; gap: .45rem;
 border-radius: 2px;
}
.filter-bar a span { font-family: var(--stamp); color: var(--ink-3); }
.filter-bar a:hover { border-color: var(--ink-2); color: var(--ink); }
.filter-bar a[aria-current="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.filter-bar a[aria-current="true"] span { color: var(--paper); opacity: .7; }

.shelf {
 display: grid;
 grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
 gap: 1.5rem;
 margin-block-start: 2rem;
}
.vol {
 display: flex; flex-direction: column;
 text-decoration: none; color: inherit;
 border: 1px solid var(--rule); background: var(--paper-hi);
 transition: border-color .2s ease, transform .2s ease, background .2s ease;
}
.vol:hover, .vol:focus-visible {
 border-color: var(--ink); transform: translateY(-3px); background: var(--card); color: inherit;
}
.vol-cover { position: relative; display: block; aspect-ratio: 3 / 4; overflow: hidden; background: var(--card); }
.vol-cover img { inline-size: 100%; block-size: 100%; object-fit: cover; filter: saturate(.9); }
.vol-blank {
 display: grid; place-items: center; block-size: 100%; padding: 1.5rem;
 background:
 repeating-linear-gradient(90deg, transparent 0 14px, color-mix(in srgb, var(--ink) 5%, transparent) 14px 15px),
 var(--card);
}
.vol-blank-title {
 font-family: var(--display); font-weight: 700; font-size: 1.05rem; line-height: 1.2;
 text-align: center; color: var(--ink-3);
}
.vol-flag {
 position: absolute; inset-block-start: .6rem; inset-inline-start: .6rem;
 font-family: var(--display); font-size: .58rem; font-weight: 600;
 letter-spacing: .14em; text-transform: uppercase;
 padding: .3rem .5rem; background: var(--violet); color: var(--paper-hi);
}
.vol--quiet .vol-flag { background: var(--ink-4); }
.vol--home .vol-flag { background: var(--red); }
.vol--quiet .vol-cover img { filter: saturate(.35) contrast(.95); }

.vol-body { display: flex; flex-direction: column; gap: .25rem; padding: 1rem 1.1rem 1.2rem; }
.vol-title { font-family: var(--display); font-weight: 700; font-size: 1.05rem; line-height: 1.2; }
.vol-by { font-style: italic; font-size: .88rem; color: var(--ink-2); }
.vol-blurb { font-size: .9rem; color: var(--ink-2); margin-block-start: .3rem; }
.vol-meta { font-family: var(--stamp); font-size: .7rem; color: var(--ink-3); margin-block-start: .5rem; line-height: 1.5; }

/* ============================================================
 Masthead: logo and theme switch
 ============================================================ */
.wordmark { gap: .65rem; align-items: center; }
.wordmark-logo { color: var(--violet); display: block; line-height: 0; }
.wordmark-text { display: flex; flex-direction: column; gap: 1px; }
.wordmark-tag { font-size: .66rem; }

.theme-toggle {
 display: inline-grid; place-items: center;
 inline-size: 38px; block-size: 38px;
 border: 1px solid var(--rule); background: transparent; color: var(--ink-2);
 border-radius: 2px; cursor: pointer; padding: 0;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink-2); }
.theme-toggle .t-moon { opacity: 0; transform-origin: center; transition: opacity .2s ease; }
.theme-toggle .t-sun, .theme-toggle .t-rays { opacity: 1; transition: opacity .2s ease; }
.theme-toggle.is-dark .t-moon { opacity: 1; }
.theme-toggle.is-dark .t-sun,
.theme-toggle.is-dark .t-rays { opacity: 0; }

.holding-note {
 font-size: .92rem; color: var(--ink-2);
 border: 1px dashed var(--rule); padding: .9rem 1.1rem; margin: 0 0 1.5rem;
}

/* ============================================================
 The floating "go immersive" button on the hero globe
 ============================================================ */
.globe-immersive {
 position: absolute;
 z-index: 25;
 inset-block-start: 1rem;
 inset-inline-end: 1rem;
 display: inline-grid;
 place-items: center;
 inline-size: 40px;
 block-size: 40px;
 color: var(--ink-2);
 background: color-mix(in srgb, var(--paper) 78%, transparent);
 border: 1px solid var(--rule);
 border-radius: 2px;
 text-decoration: none;
 backdrop-filter: blur(4px);
 -webkit-backdrop-filter: blur(4px);
 opacity: 0;
 transform: translate(4px, -4px);
 transition: opacity .18s ease, transform .18s ease, color .18s ease, background .18s ease, border-color .18s ease;
 pointer-events: none;
}
/* Reveal on hover of the globe stage, or when the button itself has keyboard
 focus. Once revealed, the button takes clicks. */
.globe-stage:hover .globe-immersive,
.globe-immersive:focus-visible,
.globe-immersive:hover {
 opacity: 1;
 transform: none;
 pointer-events: auto;
}
.globe-immersive:hover,
.globe-immersive:focus-visible {
 color: var(--violet);
 border-color: var(--ink);
 background: var(--paper);
}
/* Touch devices don't have hover; keep the button always visible there. */
@media (hover: none) {
 .globe-immersive { opacity: 1; transform: none; pointer-events: auto; }
}
[data-rich="off"] .globe-immersive { display: none; }

/* ============================================================
 The immersive page
 ============================================================ */
body.is-immersive {
 min-block-size: 100vh;
 overflow: hidden;
 background: var(--paper);
}
.is-immersive .skip-link { display: none; }

.immersive-stage {
 position: fixed;
 inset: 0;
 z-index: 0;
}
.is-immersive #globe {
 display: block;
 block-size: 100vh;
 inline-size: 100vw;
 cursor: grab;
 touch-action: none; /* pinch is ours, not the browser's */
}
.is-immersive #globe.is-grabbing { cursor: grabbing; }
.is-immersive #globe.is-pointing { cursor: pointer; }
.is-immersive #globe canvas { display: block; inline-size: 100%; block-size: 100%; }
.is-immersive .globe-fallback {
 position: absolute; inset: 0; z-index: 0;
}
.is-immersive #map { block-size: 100vh; }
body.has-globe.is-immersive .globe-fallback { display: none; }

/* corner tiles */
.im-corner, .im-panel {
 position: fixed;
 z-index: 10;
 padding: .85rem 1rem;
 background: color-mix(in srgb, var(--paper) 82%, transparent);
 border: 1px solid var(--rule);
 border-radius: 3px;
 backdrop-filter: blur(6px);
 -webkit-backdrop-filter: blur(6px);
}
.im-corner--tl { inset-block-start: 1.1rem; inset-inline-start: 1.1rem;
 display: flex; align-items: center; gap: .7rem;
 text-decoration: none; color: var(--ink); }
.im-corner--tl:hover { color: var(--violet); border-color: var(--ink); }
.im-corner-text {
 display: flex; align-items: center; gap: .45rem;
 font-family: var(--display); font-weight: 700; font-size: .95rem;
 color: var(--violet);
}
.im-corner-text svg { color: var(--violet); display: block; line-height: 0; }

/* The theme toggle lives with the zoom controls, bottom-right, see
 .im-controls-row below, rather than crowding the back link up top. */
.im-theme-toggle {
 background: color-mix(in srgb, var(--paper) 82%, transparent);
 backdrop-filter: blur(6px);
 -webkit-backdrop-filter: blur(6px);
 flex: none;
}

/* counters */
.im-panel--tr { inset-block-start: 1.1rem; inset-inline-end: 1.1rem; }
.im-stats {
 display: grid;
 grid-template-columns: repeat(6, minmax(0, 1fr));
 gap: 0 1.2rem;
 margin: 0; padding: 0;
}
.im-stats div { text-align: start; }
.im-stats dt {
 font-family: var(--display); font-size: .58rem; font-weight: 600;
 letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
 margin: 0;
}
.im-stats dd {
 margin: .15rem 0 0;
 font-family: var(--stamp); font-weight: 700; font-size: 1.4rem; line-height: 1;
 color: var(--ink);
}
@media (max-width: 900px) {
 .im-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .8rem 1.2rem; }
}
@media (max-width: 520px) {
 /* Small screens get a compact strip, not a scaled-down desktop panel:
 fewer columns, tighter type, less padding, dropped below the back
 link so the two never overlap regardless of title length. */
 .im-corner, .im-panel { padding: .55rem .7rem; }
 .im-corner--tl { gap: .5rem; }
 .im-corner-text { font-size: .8rem; }
 .im-panel--tr {
 inset-block-start: 4rem; inset-inline-end: .7rem; inset-inline-start: .7rem;
 padding: .5rem .65rem;
 }
 .im-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .4rem .6rem; }
 .im-stats dt { font-size: .48rem; letter-spacing: .06em; }
 .im-stats dd { font-size: .88rem; margin-block-start: .1rem; }
}

/* caption */
.im-caption {
 position: fixed; z-index: 10;
 inset-block-end: 1.4rem; inset-inline-start: 1.4rem;
 max-inline-size: 22rem;
 display: flex; flex-direction: column; gap: .15rem;
 padding: 1rem 1.15rem;
 background: color-mix(in srgb, var(--paper) 85%, transparent);
 border: 1px solid var(--rule);
 border-inline-start: 3px solid var(--violet);
 border-radius: 2px;
 text-decoration: none; color: var(--ink);
 backdrop-filter: blur(6px);
 -webkit-backdrop-filter: blur(6px);
 opacity: 0;
 transform: translateY(10px);
 transition: opacity .35s ease, transform .35s ease;
}
.im-caption.is-in { opacity: 1; transform: none; }
.im-caption:hover { border-inline-start-color: var(--ink); }
.ic-eyebrow {
 font-family: var(--display); font-size: .58rem; font-weight: 600;
 letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
}
.ic-title { font-family: var(--display); font-weight: 700; font-size: 1.15rem; line-height: 1.2; }
.ic-author { font-style: italic; font-size: .9rem; color: var(--ink-2); }
.ic-meta { font-family: var(--stamp); font-size: .72rem; color: var(--ink-3); margin-block-start: .25rem; }
.ic-go { font-family: var(--display); font-size: .62rem; font-weight: 600;
 letter-spacing: .12em; text-transform: uppercase; color: var(--violet);
 margin-block-start: .5rem; }

/* theme toggle + zoom, side by side, hint tile below */
.im-panel--br { inset-block-end: 1.4rem; inset-inline-end: 1.4rem;
 display: flex; flex-direction: column; gap: .55rem; align-items: flex-end; }
.im-controls-row { display: flex; align-items: center; gap: .5rem; }
.im-zoom { display: inline-flex; border: 1px solid var(--ink); background: var(--paper); overflow: hidden; }
.im-zoom button {
 border: 0; background: none; cursor: pointer;
 inline-size: 38px; block-size: 38px;
 display: grid; place-items: center; color: var(--ink);
}
.im-zoom button + button { border-inline-start: 1px solid var(--rule); }
.im-zoom button:hover { background: var(--card); color: var(--violet); }
.im-hint { margin: 0; font-family: var(--stamp); font-size: .68rem; color: var(--ink-3); text-align: end; max-inline-size: 15rem; }

@media (max-width: 520px) {
 /* No inset-inline-start here on purpose: with the hint hidden, this tile
 is just the toggle and two zoom buttons and should stay compact in its
 corner rather than stretch the width of the screen. Everything in it
 shrinks a size, this is a phone, not a desk. */
 .im-panel--br { inset-block-end: 1rem; inset-inline-end: .7rem; gap: .4rem; }
 .im-hint { display: none; }
 .im-controls-row { gap: .4rem; }
 .im-theme-toggle,
 .im-zoom button { inline-size: 32px; block-size: 32px; }
 .im-theme-toggle svg, .im-zoom button svg { width: 14px; height: 14px; }
 /* Stacked above the controls row rather than squeezed beside it: trying to
 share a row on a ~360-400px screen left no safe width for either. */
 .im-caption {
 inset-inline-start: .7rem; inset-inline-end: .7rem; inset-block-end: 4.4rem;
 max-inline-size: none;
 padding: .65rem .75rem;
 gap: .05rem;
 }
 .ic-eyebrow { font-size: .52rem; }
 .ic-title { font-size: .96rem; }
 .ic-author { font-size: .78rem; }
 .ic-meta { font-size: .64rem; margin-block-start: .15rem; }
 .ic-go { font-size: .56rem; margin-block-start: .35rem; }
}

/* empty state */
.immersive-empty {
 position: fixed; inset: 0;
 display: grid; place-items: center; padding: 2rem;
 text-align: center;
}
.immersive-empty > * { max-inline-size: 34em; }
