/* The route map, shared with the admin so the editor and the page cannot drift.
   Inlined by App\Site\AssetPublisher when the site is built. */
/*
 * The route map.
 *
 * Shared deliberately: imported by BOTH the published site's stylesheet and the
 * admin's, because the editor shows the same SVG the build publishes. Keeping two
 * copies in step by hand is exactly the drift that stops an editor preview being a
 * preview — and the first symptom here was worse than drift, because the admin had
 * no copy at all and every map rendered as unstyled black shapes.
 *
 * It asks for its colours through --map-* tokens rather than reaching for either
 * palette directly, because the two hosts name their colours differently. Each one
 * assigns these from its own palette; the fallbacks mean a map still renders
 * legibly if a host forgets.
 */

.route-map {
    --map-context: var(--vine-pale, #9aa88a);
    --map-route: var(--vine, #6d7f4e);
    --map-here: var(--bark, #7c5c3b);
    --map-paper: var(--paper, #f6f3ea);
    --map-ink: var(--ink-soft, #5b564b);
    --map-font: var(--sans, system-ui, sans-serif);
    --map-water: #6f8fa8;

    margin: 2rem 0;
}

.route-map svg {
    display: block;
    width: 100%;
    height: auto;
    /* Reserves the space before the SVG lays out, so the page does not jump. */
    aspect-ratio: 720 / 460;
}

.route-map path { fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* Context. Deliberately faint — it is there so the route has somewhere to be, and
   the moment it competes with the route it has stopped doing its job.

   The weights are the whole legibility of a city map: a motorway and a side street
   drawn identically is worse than no streets at all, because it reads as noise
   rather than as a place. */
.route-map__grid { stroke: var(--map-context); stroke-width: 0.5; opacity: 0.4; }
.route-map__coastline { stroke: var(--map-context); stroke-width: 1; }
.route-map__borders { stroke: var(--map-context); stroke-width: 0.75; stroke-dasharray: 4 3; opacity: 0.7; }

/* Streets, from OpenStreetMap. */
.route-map__road-major { stroke: var(--map-context); stroke-width: 1.1; opacity: 0.85; }
.route-map__road-minor { stroke: var(--map-context); stroke-width: 0.55; opacity: 0.5; }
.route-map__rail { stroke: var(--map-context); stroke-width: 0.6; stroke-dasharray: 5 4; opacity: 0.45; }
/* Water gets its own colour rather than another grey — a river is the one piece of
   context that tells you which way a city faces. */
.route-map__water { stroke: var(--map-water, #6f8fa8); stroke-width: 1.1; opacity: 0.6; }

/* The whole journey. */
.route-map__track { stroke: var(--map-route); stroke-width: 1.75; opacity: 0.55; }

/* This post's share of it, over the top. */
.route-map__walked { stroke: var(--map-here); stroke-width: 2.75; }

.route-map__stop { stroke: var(--map-paper); stroke-width: 1.5; }

/* Three states, and the point of them is that a post about day three shows days
   one and two behind it and days four onward still waiting. */
.route-map__stop--past { fill: var(--map-route); opacity: 0.45; }
.route-map__stop--ahead { fill: var(--map-context); opacity: 0.35; }
.route-map__stop--here { fill: var(--map-here); }

.route-map__scale path { stroke: var(--map-ink); stroke-width: 1; }
.route-map__scale text { fill: var(--map-ink); font-family: var(--map-font); font-size: 11px; }

/* The stops as text. Not decoration: an SVG <title> needs a hover, which a phone
   does not have, so this is where the information actually lives. */
.route-map__stops { margin-top: 1rem; font-family: var(--map-font); font-size: 0.875rem; }
.route-map__stops ol { margin: 0; padding-left: 1.4rem; }
.route-map__stop-name { margin-bottom: 0.35rem; }
.route-map__stop-name--past, .route-map__stop-name--ahead { color: var(--map-ink); }
.route-map__stop-note { color: var(--map-ink); }

.route-map__credit {
    margin-top: 0.75rem;
    font-family: var(--map-font);
    font-size: 0.75rem;
    color: var(--map-ink);
}


/*
 * The published site.
 *
 * Hand-written and copied verbatim into each build by App\Site\AssetPublisher —
 * this file never goes through AssetMapper, and readers never download a
 * framework to read a poem.
 *
 * This is the baseline: type, colour and the layout scaffolding the wander and
 * the vines hang off. The organic treatment builds on top of it.
 */

:root {
    --paper: #f6f3ea;
    --paper-deep: #ece7da;
    --ink: #211f1a;
    --ink-soft: #5b564b;
    --vine: #6d7f4e;
    --vine-pale: #b3bf96;
    --bark: #7c5c3b;

    --measure: 34rem;
    --rhythm: 1.6rem;

    --serif: Iowan Old Style, Palatino, "Palatino Linotype", Georgia, serif;
    --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
}

@media (prefers-color-scheme: dark) {
    :root {
        --paper: #14150f;
        --paper-deep: #1b1d15;
        --ink: #e9e5d8;
        --ink-soft: #a29c8b;
        --vine: #8ba063;
        /* Lighter than you would expect from a name like "pale". This is a thin
           stroke on a near-black page: the value that reads as a faint pencil line
           on paper disappears completely here. */
        --vine-pale: #6b7d47;
        --bark: #a57c50;
    }
}

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

body {
    margin: 0;
    /* The growth layers are absolutely positioned against the page, so this is what
       they anchor to. Without it they would anchor to the viewport and the margin
       vine would scroll with the reader instead of running the length of the page. */
    position: relative;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--serif);
    font-size: clamp(1.0625rem, 0.95rem + 0.4vw, 1.1875rem);
    line-height: 1.65;
    /* The vines are absolutely positioned relative to the page and can extend past
       the text column; without this they add horizontal scroll on a phone. */
    overflow-x: hidden;
}

/* ---- masthead and footer ---- */

.masthead {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    max-width: var(--measure);
    margin: 0 auto;
    padding: 2rem 1.25rem 0;
}

.masthead__home {
    font-family: var(--sans);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: lowercase;
    color: var(--vine);
    text-decoration: none;
}

.masthead__nav { display: flex; gap: 1rem; font-family: var(--sans); font-size: 0.8125rem; }
.masthead__nav a { color: var(--ink-soft); }

.footer {
    /* Anchors the root system to the footer rather than to the page. */
    position: relative;
    max-width: var(--measure);
    margin: 6rem auto 0;
    padding: 0 1.25rem 4rem;
    font-family: var(--sans);
    font-size: 0.8125rem;
    color: var(--ink-soft);
}

/* ---- the wander ----
 *
 * Content blocks drift sideways and tilt very slightly, each by an amount seeded
 * from the post's slug so a page looks the same on every build. Three rules keep
 * it from becoming unreadable:
 *
 *   1. The drift moves the block, never the measure — line length is untouched.
 *   2. Rotation is capped at well under a degree of visible slope at reading size.
 *   3. Below the breakpoint, and for anyone who asked for reduced motion, the
 *      whole thing collapses to a straight column.
 */

.wander {
    max-width: var(--measure);
    margin: 0 auto;
    padding: 0 1.25rem;
}

.wander__block {
    --wander-x: 0rem;
    --wander-rot: 0deg;
    margin-block: var(--rhythm);
}

@media (min-width: 52rem) {
    .wander__block {
        transform: translateX(var(--wander-x)) rotate(var(--wander-rot));
        transform-origin: left center;
    }

    /* Never tilt something with its own internal geometry: a rotated map is a
       wrong map, rotated code is unreadable, and a rotated poem fights the
       spacing that IS the poem. */
    .wander__block:has(.route-map),
    .wander__block:has(pre),
    .wander__block:has(.poem) {
        transform: translateX(var(--wander-x));
    }

    /* Inside prose, paragraphs drift a little too — otherwise a long entry is a
       rigid column sitting inside a page that sways, which reads as a mistake.
       Done with nth-child rather than generated per element: the amounts are tiny
       and repeating on a four-paragraph cycle is invisible, where marking up every
       paragraph would not be.

       These are a quarter the size of the block-level drift and carry no rotation
       at all. A paragraph is where the reading happens. */
    .prose > * { transition: transform 0.3s ease-out; }
    .prose > :nth-child(4n+1) { transform: translateX(0.45rem); }
    .prose > :nth-child(4n+2) { transform: translateX(-0.3rem); }
    .prose > :nth-child(4n+3) { transform: translateX(0.6rem); }
    .prose > :nth-child(4n+4) { transform: translateX(-0.15rem); }

    /* Anything with its own alignment stays put. */
    .prose > pre,
    .prose > table,
    .prose > figure { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .wander__block { transform: none; }
}

/* ---- growth (vines and roots) ----
 *
 * Generated in PHP from the page's slug (App\Botany), so a page's vine is the same
 * on every build. Purely decorative and marked aria-hidden in the markup — there is
 * nothing useful to announce about it.
 */

.growth {
    position: absolute;
    pointer-events: none;
    color: var(--vine-pale);
    z-index: -1;
}

.growth--margin {
    top: 0;
    left: 0;
    width: min(16vw, 8rem);
    height: 100%;
}

.growth--roots {
    inset: auto 0 0 0;
    height: 10rem;
    overflow: hidden;
}

.growth svg { width: 100%; height: 100%; display: block; }

.growth path {
    fill: none;
    stroke: currentColor;
    /* No stroke-width here: each path carries its own as a presentation
       attribute, so that roots can taper from trunk to tip. A CSS declaration
       would beat the attribute and flatten every branch to one weight. */
    stroke-linecap: round;
}

.growth .leaf { fill: currentColor; stroke: none; opacity: 0.85; }
.growth .node { fill: currentColor; stroke: none; opacity: 0.6; }

@media (max-width: 51.999rem) {
    /* No room beside the text on a phone; the roots in the footer stay. */
    .growth--margin { display: none; }
}

/* ---- typography ---- */

.page-title {
    font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
    line-height: 1.1;
    font-weight: 400;
    letter-spacing: -0.01em;
    margin-block: 2.5rem 1.5rem;
}

.post__title {
    font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
    line-height: 1.15;
    font-weight: 400;
    margin: 0;
}

.post__meta, .card-post__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: 0.5rem 0 0;
    font-family: var(--sans);
    font-size: 0.8125rem;
    letter-spacing: 0.04em;
    color: var(--ink-soft);
}

.prose > :first-child { margin-top: 0; }
.prose p { margin-block: var(--rhythm); }
.prose h2, .prose h3 { font-weight: 400; line-height: 1.25; margin-block: 2.5rem 0.75rem; }
.prose blockquote {
    margin-inline: 0;
    padding-left: 1.25rem;
    border-left: 2px solid var(--vine-pale);
    color: var(--ink-soft);
}
.prose img { max-width: 100%; height: auto; }
.prose pre { overflow-x: auto; padding: 1rem; background: var(--paper-deep); border-radius: 4px; }
.prose code { font-family: ui-monospace, Menlo, monospace; font-size: 0.9em; }

a { color: var(--bark); text-underline-offset: 0.15em; }
a:hover { color: var(--vine); }

/* ---- cards and navigation ---- */

.card-post { margin-block: 2.75rem; }
.card-post__title { font-size: 1.375rem; font-weight: 400; line-height: 1.25; margin: 0; }
.card-post__title a { color: inherit; text-decoration: none; }
.card-post__title a:hover { text-decoration: underline; }
.card-post__excerpt { margin: 0.5rem 0 0; color: var(--ink-soft); }
.card-post__kind { text-transform: lowercase; }

.year-nav, .post__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 3rem;
    padding-top: 1rem;
    border-top: 1px solid var(--vine-pale);
    font-family: var(--sans);
    font-size: 0.8125rem;
}

.tag-cloud { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 1rem; }
.tag-cloud__count { color: var(--ink-soft); font-size: 0.8125rem; }


/* ---- room for the vine ----
 *
 * At wide sizes the text column shifts right so the margin vine has somewhere to
 * live. Applied to the column rather than the body so the vine can still run the
 * full width of the page behind the footer.
 */
@media (min-width: 52rem) {
    .masthead, .wander, .footer {
        /* The extra left padding is the vine's strip plus a gutter. */
        padding-left: calc(min(16vw, 8rem) + 2rem);
        margin-left: 0;
        margin-right: auto;
        max-width: calc(var(--measure) + min(16vw, 8rem) + 4rem);
    }
}

/* ---- footer ---- */

.footer__note {
    position: relative;
    margin: 0;
}

/* ---- poem ----
 *
 * Note there is no white-space: pre here, and that is deliberate. The parser has
 * already turned every run of two or more spaces into a measured .poem__gap and
 * every leading indent into a --indent, both in `ch`. That reproduces the geometry
 * the poem was written with in a monospace textarea, in whatever font it is read
 * in — where pre-wrap would hand the alignment over to the serif's space width and
 * lose it.
 */

.poem {
    --poem-line: 1.9em;
    margin-block: 2.5rem;
    line-height: 1.9;
    /* Lining figures, so a poem with a date or a number in it keeps its columns. */
    font-variant-numeric: tabular-nums lining-nums;
}

.poem__line {
    margin: 0;
    padding-left: var(--indent, 0);
    /* The line is the unit of this format, so it never rewraps into another one.
       A poem that reflows on a narrow screen is a different poem.

       white-space rather than the newer text-wrap: nowrap. text-wrap: nowrap here,
       with these inline-blocks of exact ch widths inside a transformed ancestor,
       sends Chrome's layout into a loop and hangs the renderer on the whole page.
       Collapsing whitespace is not a side effect worth worrying about: the parser
       has already turned every run of two or more spaces into a .poem__gap element,
       so there are no runs left to collapse. */
    white-space: nowrap;
    transform: translateX(var(--drift, 0));
}

.poem__line--blank { height: var(--poem-line); }

.poem__space { width: 100%; }

/* An empty inline-block of an exact width. The alternative — non-breaking spaces —
   would be at the mercy of the font's space width, which is the problem this
   template exists to solve. */
.poem__gap {
    display: inline-block;
    width: calc(var(--columns) * 1ch);
}

/* Rotation and scale need a block box to transform, and inline-block is the
   smallest one that does not disturb the line around it. */
.poem__rot,
.poem__scale {
    display: inline-block;
}

.poem__rot { transform: rotate(var(--rot)); }
.poem__scale { transform: scale(var(--scale)); }

/* Both at once: one transform, or the second declaration wins and the first
   silently does nothing. */
.poem__rot.poem__scale { transform: rotate(var(--rot)) scale(var(--scale)); }

.poem__fade { opacity: 0.55; }

.poem__figure { margin: 2rem 0; }
.poem__figure img { display: block; max-width: 100%; height: auto; }
.poem__figure figcaption { margin-top: 0.5rem; font-family: var(--sans); font-size: 0.8125rem; color: var(--ink-soft); }

.poem__figure--left { float: left; margin-right: 1.5rem; width: var(--img-width, 45%); }
.poem__figure--right { float: right; margin-left: 1.5rem; width: var(--img-width, 45%); }
.poem__figure--centre { margin-inline: auto; width: var(--img-width, 70%); }
.poem__figure--full { width: var(--img-width, 100%); }

/* Floated images pushing into the next stanza is charming until it is not; a
   phone has no room for it either way. */
@media (max-width: 40rem) {
    .poem__figure--left,
    .poem__figure--right {
        float: none;
        margin-inline: 0;
        width: var(--img-width, 100%);
    }
}

/* A long line on a narrow screen scrolls sideways rather than being rewrapped or
   shrunk, because both of those change the shape of the poem. */
@media (max-width: 40rem) {
    .poem { overflow-x: auto; }
}

/* ---- photographs ---- */

.photo { margin: 2rem 0; }
.photo img { display: block; width: 100%; height: auto; }
.photo figcaption {
    margin-top: 0.5rem;
    font-family: var(--sans);
    font-size: 0.8125rem;
    color: var(--ink-soft);
}

.gallery { margin-top: 2rem; }

/* ---- playing lately ----
 *
 * Ambient: a fact about this week rather than a piece of writing, so it is quieter
 * than everything around it and never competes with a post for attention.
 */

.playing {
    margin-top: 3.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--vine-pale);
    font-family: var(--sans);
    font-size: 0.875rem;
    color: var(--ink-soft);
}

.playing__title {
    margin: 0 0 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.playing__list { margin: 0; padding: 0; list-style: none; }
.playing__list li { margin-bottom: 0.25rem; }
.playing__time { color: var(--vine); font-variant-numeric: tabular-nums; }
