        /* ==========================================================================
           #Y  The journal — the list, and the calendar above it
           ==========================================================================

           A journey's journal: a month grid saying which days were written on, and the
           entries themselves underneath, newest first. Migrated into the deck log on
           2026-09-11, the second of the journal's three rounds (the reading page went on
           2026-09-10; the editor is the third).

           WHERE THE RULES CAME FROM. `.jrnl-*` was written in SIX files —
           09-modal, 19-legacy-media, 20-legacy-calendar, 22-diagnostics,
           24-tail and 06-pagestack — and `.jrnl-drafts-bar` was declared THREE
           separate times in two of them, each overriding the last. `.pcal-*` was in
           20-legacy-calendar with a second set of "final proportions" further down the
           same file overriding the first. That is what a room looks like after it has been
           adjusted from wherever was convenient. It is one file now, and the old rules were
           removed rather than left to be beaten by the cascade.

           ⚠️ THIS FILE LOADS BEFORE 18–24. It cannot win on order, so it must win on
           having no opponent: every `.jrnl-`/`.pcal-` rule in those files is gone. Where a
           rule here dresses something those files still own — the section sheet's own
           chrome — it is qualified with `#tripSectionSheet`, and an id beats a class
           whatever the order.

           ⚠️ AND THE SHEET HAD NO TOKENS. `#tripSectionSheet` is a sibling of the pages,
           not a child of one, so every var() written here resolved to nothing until it was
           named in css/02-auth.css on the same day. Same trap as the dialogs, the drawer
           and the page stack.

           ⚠️ THE CALENDAR IS SHARED, AND IS MIGRATED ONCE FOR BOTH ROOMS.
           `buildTripCalendar` draws this grid and the Calendar section's — photographs in
           the cells here, stay-and-travel lanes there. Scoping a second copy to the journal
           was the obvious way to keep this round small, and it is exactly what the file
           these rules came from had already warned against: "two versions that differ only
           in gutter would be the kind of drift that starts as a preference and ends as a
           second implementation."

           So the frame, the lattice, the day numbers, the weekday heads, the month bars and
           every cell state are here, once, and the Calendar section reads in this world too.
           WHAT IS NOT MIGRATED is marks mode's three coloured LANES — stay, travel, and the
           activity dashes (.pcal-lane / .pcal-dash, still in 22-diagnostics.css). Those
           are the Calendar's instrument, not its dressing: the colours carry the meaning,
           they are duplicated in CALENDAR_MARK_COLOURS in JS, and choosing what they become
           in a world whose whole colour vocabulary is port, starboard and magenta is a
           decision for that room's own round, with the owner looking at it. On DEBTS.md.
           The Calendar section is photographed alongside the journal so that seam is a
           picture rather than a claim. */

        /* ---- the sheet's own chrome, for this room ---------------------------------- */

        /* Five rooms share this header. The two glyphs in it became the words ADD and
           CLOSE for all five on 2026-09-11 — the same call the owner made for the page
           stack's nine back chevrons — and a word needs a box that fits it: the shared rule
           in 24-tail.css pins every close button to a 44px square.

           ⚠️ THE DECK-LOG CHROME BELOW IS KEYED ON `.is-log`, NOT ON `.is-journal`. Five
           rooms live on this sheet and they are migrating one at a time; openTripSectionSheet
           sets `is-log` for the ones that have moved (the Journal, and the Calendar from
           2026-09-11). Migrating the next one is a word in that toggle rather than a second
           copy of these six rules — which is exactly how `.jrnl-drafts-bar` came to be
           declared three times. */
        /* ⚠️ NO PADDING OF ITS OWN (owner, 2026-09-11: close 和下面 open 右对齐). The
           header already carries the room's 24px column, and twelve pixels inside the button
           on top of it put the word CLOSE twelve pixels left of every other word down the
           right-hand side — measured: CLOSE ended at 367 where OPEN and the day's OPEN DAY
           ended at 379.

           It reads as a misalignment and it is one, but the cause is worth naming: the
           padding was added to make a 44px-square glyph box hold a word, and the box it was
           padding away from is not the edge the word has to line up with. A word aligns to
           the column, not to its own button. */
        #tripSectionSheet .trip-section-sheet-btn {
            width: auto;
            min-width: 0;
            padding: 0;
            font-size: var(--fs-small);
        }

        /* The two words in the head keep their distance from each other rather than from
           the edge — the same gap the editor's DRAFT and SAVE take. */
        #tripSectionSheet.is-log .trip-section-sheet-actions { gap: var(--sp-lg); }

        #tripSectionSheet.is-log {
            background: var(--log-stock);
        }

        #tripSectionSheet.is-log .trip-section-sheet-header {
            background: var(--log-stock-band);
            border-bottom: 1px solid var(--log-rule-firm);
            padding: var(--sp-2xs) var(--sp-lg);
        }

        #tripSectionSheet.is-log .trip-section-sheet-title {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* The way out is a word and is underlined, like every other way out of a room
           here. It is not an act — leaving changes nothing — so it takes the ink. */
        #tripSectionSheet.is-log .trip-section-sheet-btn {
            min-height: 44px;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 1px;
            color: var(--log-ink);
            background: transparent;
        }
        /* ADD shares CLOSE's dress but not its ink: opening the way to add is the act that adds (owner, 2026-09-17: 打开表单算写记录，删除统一用品红). */
        #tripSectionSheet #tripSheetAddBtn { color: var(--log-magenta); }

        /* FULL HEIGHT. The other four rooms on this sheet are lists you glance at; the
           journal is one you stay in and read, and the calendar and the first entry have to
           be reachable together — that pairing is what the screen is for, and at 80dvh they
           are not. No rounded top and no shadow at full height either: both say "there is
           something behind this", and at full height there isn't. */
        .trip-section-sheet.is-journal {
            height: 100dvh;
            border-radius: 0;
            box-shadow: none;
        }

        /* THE BODY IS THE SCROLLER, AND THE ADD BAR SITS AT THE BOTTOM OF IT EITHER WAY.
           `position: sticky; bottom: 0` pins a thing only while there is something to
           scroll — on a journey with nothing written yet the calendar is short, so the bar
           stopped wherever the content stopped and left a field of blank stock under it.
           A column that fills the height, with the list taking the slack, puts it on the
           bottom edge when the page is short and keeps it stuck there when it is long.

           Four elements deep, and all four have to be in on it: the sheet body, then
           #sectionContent, .journal-section and #journalContent — three layers the journal
           does not own and shares with four other rooms, so each is qualified. */
        #tripSectionSheet.is-journal .trip-section-sheet-body {
            padding: 0;
            background: var(--log-stock);
            display: flex;
            flex-direction: column;
        }

        #tripSectionSheet.is-journal #sectionContent,
        #tripSectionSheet.is-journal .journal-section,
        #tripSectionSheet.is-journal #journalContent {
            display: flex;
            flex-direction: column;
            flex: 1 0 auto;
            min-height: 0;
        }

        /* The calendar's own top edge is the rule under the sheet header. Three layers each
           gave it a margin of their own: the sheet body's 0.5rem, .journal-section's 16px
           between #sectionContent and #journalContent — two layers nobody thought to look
           at, which is why that gap survived four rounds of chasing text nodes — and the
           calendar's own head padding. The BOTTOM sixteen of that same rule is why the add
           bar stopped sixteen pixels short of the sheet's own edge. */
        .trip-section-sheet.is-journal .journal-section { padding: 0; }

        /* ---- the calendar ---------------------------------------------------------- */

        .pcal {
            background: var(--log-stock);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        /* ONE PRINTED LINE, not a masthead. It used to be three: the journey's name in
           small sans, the date range in 20px serif with oldstyle figures, and the day count
           in caps beside it — a title block for a screen that is already inside the journey
           and already headed JOURNAL. The ledger's voice says all three facts on one line
           and gives the grid the room. */
        .pcal-head {
            display: flex;
            flex-wrap: wrap;
            align-items: baseline;
            gap: var(--sp-xs) var(--sp-sm);
            padding: var(--sp-xs) var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
        }

        .pcal-place {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
            margin: 0;
        }

        .pcal-range {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 400;
            letter-spacing: 0.12em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
            /* Lining figures. Oldstyle ripples, which is lovely in a heading and wrong in a
               column of dates you are meant to compare. */
            font-variant-numeric: lining-nums tabular-nums;
            line-height: 1.3;
        }

        .pcal-range span {
            font-family: inherit;
            font-size: inherit;
            letter-spacing: inherit;
            text-transform: inherit;
            color: var(--log-ink-soft);
            margin-left: var(--sp-xs);
            vertical-align: baseline;
        }

        .pcal-dow {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            padding: var(--sp-2xs) 0;
            background: var(--log-stock-band);
            border-bottom: 1px solid var(--log-rule);
        }

        .pcal-dow div {
            text-align: center;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }

        /* THE LATTICE IS THE GRID'S BACKGROUND, showing through 1px gaps; cells carry no
           borders at all. The mechanics are worth keeping whatever the palette: borders on
           cells need a rule about which cell owns which line, and every such rule has an
           edge case — the version before this one gave cells a right and bottom hairline
           and the grid a top and left, which worked until an `.is-empty` rule from an
           earlier design painted its own border in the card colour and erased them. A
           background showing through gaps cannot be overridden by a cell, and the outer
           edge comes free from the padding.

           ⚠️ `gap: 1px`, AND IT WAS 0 FOR A DAY (owner, 2026-09-11: 日历日期方格子还是要
           1px的边框分开). The rule this came from said `gap: 0` and a note underneath it
           said "1px gaps" — the two disagreed, and the file that actually made the lattice
           appear was 24-tail.css two hundred lines later, overriding the gap to 1. I moved
           the rule and its note and left the override behind, so the grid came out as one
           continuous field with the day numbers floating in it: two adjacent written days
           read as a single block, and telling days apart is the whole job of a calendar.

           The note is the lesson. A declaration and the comment beside it disagreeing is
           the loudest possible sign that the real value is somewhere else. */
        .pcal-grid {
            display: grid;
            /* ⚠️ `minmax(0, 1fr)`, NOT `1fr`. A grid item's automatic minimum size is its
               content, and `aspect-ratio: 1` on the cells made that minimum larger than a
               seventh of the row — so seven columns of "one fraction" came out at 58px each
               against a 402px sheet and the grid ran twelve pixels off the right-hand edge,
               taking the month bar with it. `1fr` is shorthand for `minmax(auto, 1fr)`; this
               is the same thing with the floor removed. */
            grid-template-columns: repeat(7, minmax(0, 1fr));
            gap: 1px;
            padding: 1px;
            background: var(--log-rule);
            /* A stay or travel run overhangs each cell by 1px so it joins across the
               lattice. In the first and last column there is nothing to join to, and that
               pixel lands outside the month — one pixel of horizontal scroll on the sheet.
               Clipped at the frame, which is where a month stops. */
            overflow: hidden;
        }

        .pcal-cell {
            position: relative;
            aspect-ratio: 1;
            /* ⚠️ WITHOUT THIS THE CELLS OVERLAP THEIR OWN LATTICE. A grid item's automatic
               minimum size is its content, and `aspect-ratio: 1` turns a minimum HEIGHT
               into a minimum WIDTH — marks mode gives every cell `min-height: 58px` so each
               one demanded 58px of width, against a seventh of a 402px sheet. Seven of them
               plus six gaps came to more than the row, so the items overflowed their tracks
               and sat ON the 1px gaps instead of beside them: the lattice was being drawn
               the whole time and painted over. Measured, not guessed — the gap between two
               adjacent cells came back as MINUS 0.72px. */
            min-width: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            background: var(--log-stock);
        }

        .pcal-cell img {
            position: absolute;
            inset: 0;
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        /* Outside the journey altogether — no number, nothing to look at. Filled rather
           than transparent: with the lattice coming from the grid's background, a
           transparent cell would show the rule colour as a solid block.

           THE JOURNEY'S DAYS TAKE THE STOCK AND THE DAYS EITHER SIDE TAKE THE BAND — the
           ruled sheet you write on, and the margin around it. Both were the band for an
           hour, which made a day of the journey and a day outside it identical unless you
           noticed that one had no number on it; and the other way round put a pale block in
           the bottom corner of the grid, drawing the eye to the one part of it that means
           nothing at all. */
        .pcal-cell.is-void { background: var(--log-stock-band); }

        .pcal-num {
            position: relative;
            z-index: 2;
            font-family: var(--log-print);
            font-size: var(--fs-small);
            font-weight: 600;
            font-variant-numeric: lining-nums tabular-nums;
            line-height: 1;
            color: var(--log-ink);
            background: transparent;
            padding: 0;
        }

        /* A DAY WITH A PHOTOGRAPH. The number sits on the image with a stock-coloured
           stroke rather than a plate behind it — a solid chip hides the very thing the cell
           is for, and a half-transparent one fails on a backlit photograph, where light and
           dark are both in the same frame. The stroke follows the glyph, so it holds on
           either. `paint-order` puts it under the fill; without that the stroke is drawn
           over the letter and thins it to nothing. */
        .pcal-cell.has-photo { cursor: pointer; }

        .pcal-cell.has-photo .pcal-num {
            color: var(--log-ink);
            -webkit-text-stroke: 2px var(--log-stock);
            paint-order: stroke fill;
        }

        /* WRITTEN ON, NO PHOTOGRAPH — A FILLED CELL (owner, 2026-09-11: 只有文字的用紫色
           背景铺满格子 文字icon 数字 浅色).

           Two drawings were wrong before this one, and both are worth keeping:

           1. THE OILSKIN. Near-black, and it made the weaker of the two marked states the
              loudest thing on a screen of photographs — a cell shouting over the cell beside
              it that says more.
           2. AN INK LINE ACROSS THE FOOT. Quiet enough, and too quiet: against a grid where
              the other marked state is a whole photograph, a 3px underline is not a peer. A
              day that was written about is one of the two things this calendar exists to
              show, and it has to hold the cell the way a photograph does.

           The ink at full pressure fills it. It is the SAME ink the numbers are written in
           everywhere else, so it reads as the day being inked in rather than as a colour
           being introduced — and it is not one of the three state colours, which is what a
           fill on this grid must never be mistaken for. The figures and the mark take the
           light ink, 14.9:1 on the oilskin and better than that here. */
        .pcal-cell.has-text {
            background: var(--log-ink);
            cursor: pointer;
        }

        .pcal-cell.has-text .pcal-num { color: var(--log-on-oilskin); }

        /* The mark that says what kind of something: three ruled lines, which is what
           writing looks like at 50px. Not a glyph standing for a thing — the actual shape
           of a written page, at the size the cell allows. */
        .pcal-mark {
            position: absolute;
            right: 4px;
            bottom: 7px;
            width: 12px;
            height: 9px;
            z-index: 2;
            stroke: var(--log-on-oilskin);
            stroke-width: 1;
        }

        /* IN RANGE AND EMPTY — most of a journey's calendar, and the thing this grid exists
           to show. It keeps the stock like every other day of the journey; what it does not
           have is the entry line across its foot. The number drops to the soft pressure, so
           the days with something on them read first. */
        .pcal-cell.is-empty .pcal-num { color: var(--log-ink-soft); }

        /* MARKS MODE — the Calendar section's cells. Outlined rather than filled: a grid
           of tinted blocks reads as a heat map, every cell competing, whereas a lattice of
           rules lets the only marked things on screen be the ones that mean something.
           Opaque, so the grid's ground shows only in the 1px gaps — any cell that goes
           transparent breaks the lane running across it. */
        .pcal-cell.pcal-mk,
        .pcal-cell.pcal-mk.is-void {
            background: var(--log-stock);
            /* ⚠️ NOT SQUARE. The journal's cells are `aspect-ratio: 1` because they hold a
               photograph; these hold a numeral and three registers of marks, and their
               height is `min-height` below. Leaving the ratio on made the cell 58 wide as
               well as 58 tall — WIDER THAN ITS OWN TRACK, which the grid had correctly sized
               at 56.28 — so seven cells overlapped the six 1px gaps between them and painted
               out the lattice. The gap measured MINUS 0.72px. */
            aspect-ratio: auto;
            /* Room for the numeral, two lanes and three rows of dashes. */
            min-height: 58px;
            flex-direction: column;
            justify-content: flex-start;
            padding: 4px 0;
            /* The stay lane overhangs into the gutter and must not be clipped. */
            overflow: visible;
        }

        /* An empty day there is a normal day that happens to have nothing on it, not a gap
           in a record, so it takes the plain stock rather than the journal's paler tint. */
        .pcal-cell.pcal-mk.is-empty { background: var(--log-stock); }
        .pcal-cell.pcal-mk.is-empty .pcal-num { color: var(--log-ink); }

        /* The selected day: an inset rule in the firm weight. Not a fill — a fill would sit
           under the lanes and hide which stay the day belongs to — and not a border change,
           which with shared hairlines would move the neighbour's line too. */
        .pcal-cell.pcal-mk.is-selected {
            outline: 1px solid var(--log-ink);
            outline-offset: -1px;
            z-index: 1;
        }

        .pcal-cell.pcal-mk.is-outside { opacity: 0.55; }

        /* Outside the journey's dates but carrying an entry — packing, the journey home, a
           note written a week later. Ruled with a broken line rather than dimmed: opacity
           took the number down with it, and a date you cannot read is not a date. */
        .pcal-cell.is-outside::before {
            content: '';
            position: absolute;
            inset: 2px;
            border: 1px dashed var(--log-rule-firm);
            z-index: 3;
            pointer-events: none;
        }

        /* A run of weeks with nothing in them, collapsed — which is why this calendar has
           no month arrows: nothing is off screen to page to. */
        .pcal-skip {
            grid-column: 1 / -1;
            margin: 0 -1px;
            padding: var(--sp-2xs) 0;
            text-align: center;
            background: var(--log-stock-band);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            letter-spacing: 0.4em;
            color: var(--log-ink-soft);
        }

        .pcal-month {
            grid-column: 1 / -1;
            margin: 0 -1px;
            padding: var(--sp-2xs) var(--sp-lg);
            background: var(--log-stock-band);
            border-top: 1px solid var(--log-rule);
            border-bottom: 1px solid var(--log-rule);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.2em;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* ---- what is unfinished ---------------------------------------------------- */

        /* A ruled row, directly under the calendar and above everything finished. It was a
           solid bar of colour — brick first, then the dark brown — and it was the loudest
           thing on a screen of somebody's writing. Position is what makes it findable. */
        #journalContent .jrnl-drafts {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-md);
            min-height: 44px;
            padding: 0 var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            background: var(--log-stock-band);
            cursor: pointer;
        }

        #journalContent .jrnl-drafts-count {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* ⚠️ MAGENTA (owner, 2026-09-11: Unfinished · 1 draft  Open 用品红). I had it in the
           ink on the argument that opening the drafts changes nothing — which is true of the
           press and false of the errand. Nobody opens their drafts to look at them: the row
           is the way back into writing, and what waits at the end of it is the one act this
           room is for. The same magenta as WRITE AN ENTRY at the foot, which is the other
           door to the same place. */
        #journalContent .jrnl-drafts-go {
            flex: none;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 1px;
            color: var(--log-magenta);
        }

        /* ---- the entries ----------------------------------------------------------- */

        /* RULED ROWS, NOT CARDS. Each entry was a bordered box on a tinted ground with a
           12px gutter between it and the next, so a screen of somebody's journal read as a
           stack of tiles. Here an entry is a block of the ruled sheet with a hairline above
           it — the sheet is continuous, and what separates one day from the next is a rule,
           the way it is everywhere else in this world. */
        /* ⚠️ RULED-TO-THE-FOOT (DESIGN.md:1416 — "Empty space inside the instrument is
           ruled, not blank. If a region of the sheet has nothing in it, it carries the
           ruling at --log-row pitch"). What was left of the sheet under the last entry was
           BLANK STOCK, here and in the day page and the Calendar's panel. The second home
           and Boswell both do it properly, and this list is the one a reader sees emptiest.

           ⚠️ ON A SPACER AFTER THE CONTENT, NEVER BEHIND IT. Boswell's day column once
           carried the ruling as a background on the column itself, and because entries are
           not --log-row tall it printed a line through the middle of them — both sets of
           border-bottom were removed twice, on the owner's word, and the lines were still
           there, because they had never been borders. The ruling rules what is EMPTY, which
           is what the rule actually asks for. */
        #journalContent .jrnl-list {
            flex: 0 0 auto;
            display: block;
            background: var(--log-stock);
            /* ⚠️ A ROTATED PRINT STICKS OUT FURTHER THAN ITS BOX. The band runs out to the
               sheet's edges, and `transform: rotate()` does not change layout width but
               DOES count towards scrollWidth — so the corners of the first and last print
               put two pixels of horizontal scroll on the sheet's scroller, which is a thing
               a reader finds by accident and cannot explain. Clipped at the edge of the
               paper, which is where a print lying on a page stops.

               `clip`, not `hidden`: hidden on one axis forces the other to scroll, and this
               block must stay part of the sheet's own scrolling. */
            overflow-x: clip;
        }

        .jrnl-list .jrnl-card {
            display: block;
            padding: var(--sp-sm) var(--sp-lg) var(--sp-md);
            border-bottom: 1px solid var(--log-rule);
            background: var(--log-stock);
            cursor: pointer;
        }

        .jrnl-list .jrnl-card:active { background: var(--log-stock-band); }

        /* THE DATELINE: the day, the month, and where it was written, on one printed line.
           The place used to be a second row with a map pin before it. */
        .jrnl-list .jrnl-card-date {
            display: flex;
            align-items: baseline;
            gap: var(--sp-xs);
            margin-bottom: var(--sp-2xs);
            font-family: var(--log-print);
            text-transform: uppercase;
        }

        .jrnl-list .jrnl-d {
            font-size: var(--fs-small);
            font-weight: 600;
            letter-spacing: 0.06em;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink);
            line-height: 1;
        }

        .jrnl-list .jrnl-m {
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            color: var(--log-ink);
        }

        /* Where, in the softer pressure — it is the same fact the day is, one step under
           it. `min-width: 0` so a long place name ellipses instead of pushing the date off
           its own line. */
        .jrnl-list .jrnl-card-loc {
            min-width: 0;
            flex: 1 1 auto;
            font-size: var(--fs-micro);
            font-weight: 400;
            letter-spacing: 0.12em;
            color: var(--log-ink-soft);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* The opening line, in the written voice and one step above the body — the same
           rule the entry's own page keeps, so the card and the entry read as one object. */
        .jrnl-list .jrnl-card-title {
            font-family: var(--log-write);
            font-size: var(--fs-base);
            font-weight: 500;
            line-height: 1.3;
            color: var(--log-ink);
            margin-bottom: 2px;
        }

        .jrnl-list .jrnl-card-excerpt {
            font-family: var(--log-write);
            font-size: var(--fs-body);
            line-height: 1.55;
            color: var(--log-ink-soft);
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        .jrnl-list .jrnl-card-excerpt.clamp2 { -webkit-line-clamp: 2; }

        /* ⚠️ THE DAY PAGE'S COPY IS NOT DRESSED HERE, and that is why every rule above
           is qualified with `#journalContent`.

           `renderJournalCard` draws the same card in two rooms — this list, and the day
           page on the page stack (`.jrnl-list.tday-entries`) — on the stated argument that
           a journal entry should look like the same object wherever it appears. It still
           is the same markup and the same function. But the day page is still in the
           outgoing world, and 06-pagestack.css and 24-tail.css already carry a
           dozen `.tday-entries .jrnl-card-*` rules of their own, so an unqualified rule
           here would have put deck-log ink on a cream page under outgoing overrides —
           half a card in each world.

           The id qualifier means the day page keeps exactly what it had, and the card
           moves when that room does. On DEBTS.md. */

        .jrnl-list .jrnl-card-more {
            margin-top: var(--sp-xs);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 1px;
            color: var(--log-ink);
        }

        .jrnl-list .jrnl-card-photocount {
            margin-top: var(--sp-xs);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            letter-spacing: 0.12em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }

        .jrnl-list .jrnl-card-tags {
            display: flex;
            flex-wrap: wrap;
            gap: var(--sp-xs) var(--sp-sm);
            margin-top: var(--sp-sm);
        }

        /* ⚠️ A TAG IS A TAG WHEREVER IT IS, so this is the only place one is dressed —
           deliberately unscoped, unlike every other rule in this block.

           It had two owners and lost half of itself between them. The `#` in front came
           from `.jrnl-tag::before` in 19-legacy-media.css; the entry's own page overrode
           the rest with `.pgstack-root .jp-tags .jrnl-tag` in 17m and relied on that file
           two rooms away for the character. Migrating the list cut 19's rule — and for one
           day the ENTRY page's tags had no `#` at all, which is the whole of what says they
           are tags. Found in a capture of a room I was not editing.

           They also disagreed about a rule under the word: the entry underlined them, the
           list did not. A tag is not a control here — nothing happens when you press one —
           and an underline in this world is what a way out and an act wear. No rule.

           The traveller's own words about the entry, in the printed voice because they are
           labels rather than writing. */
        .jrnl-tag {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.12em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }

        .jrnl-tag::before { content: '#'; }

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

        /* THE BAND STAYS (owner, 2026-09-10: 照片溢出边框 歪着放的效果 这部分想保留).
           A row of prints laid out flat, overlapping, running past both edges of the
           column. It is the one thing in this world that is an OBJECT rather than a ruling,
           and it earns that: photographs are the one thing in a journal that really were
           physical, and a deck log with a handful of prints laid loose across the page is a
           truer object than a deck log with a thumbnail grid in it.

           What changed is the material, not the gesture. The rotations are untouched.

           1. THE SHADOW IS A CONTACT SHADOW NOW, not a drop shadow. It was
              `0 1px 3px rgba(36,36,36,.10)` — a soft grey halo at a distance, which is how a
              card floats above a surface. A print lying on paper touches it: the shadow is
              tight, offset almost not at all, and in this world's ink rather than in a
              neutral grey that belongs to no palette here.
           2. THE WHITE BORDER IS A TRUE WHITE, and that is a deliberate exception. Every
              other surface in this room is stock or band; a photographic print's border is
              white paper, and making it #D9DFDD would be colouring the one genuinely
              physical thing in the app to match the sheet it is lying on. Named here so it
              is not "fixed" later by someone tidying up bare colours.
           3. THE COUNT LEFT THE PHOTOGRAPHS — see the note in renderJournalCard. */
        .jrnl-list .jrnl-band {
            position: relative;
            display: flex;
            align-items: flex-start;
            /* ⚠️ OUT TO THE EDGES OF THE SHEET, NOT PAST THEM. The rule it came from went
               24px negative against a 12px card inset — 12 of genuine overhang — and that
               worked because the card was a box floating on a tinted ground, so the
               overhang landed on the ground beside it. Here an entry is a full-bleed block
               of the ruled sheet: there is no ground beside it, so the same negative margin
               put the first and last print HALF OFF THE SCREEN with their white margins
               cut away.

               The gesture the owner asked to keep is the band being wider than the column
               of writing, and it still is — it cancels the column's own inset and keeps six
               pixels, which is what a print rotated five degrees needs so that its outer
               corner is not shaved off by the clip below. */
            margin: var(--sp-sm) calc(var(--sp-lg) * -1 + 6px) 0;
            padding-bottom: 6px;
        }

        .jrnl-list .jrnl-print {
            flex: 1 1 0;
            min-width: 0;
            height: 96px;
            box-sizing: border-box;
            /* 2 — the print's own white paper margin, deliberately not a token. */
            border: 3px solid #FFFFFF;
            outline: 1px solid var(--log-rule);
            background: var(--log-stock-band);
            /* 1 — a contact shadow: it is lying on the page, not hovering over it. */
            box-shadow: 0 1px 1px rgba(67, 39, 107, 0.22);
            overflow: hidden;
        }

        .jrnl-list .jrnl-print img,
        .jrnl-list .jrnl-print video {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        .jrnl-list .jrnl-print + .jrnl-print { margin-left: -16px; }

        /* Lightly askew, and the two at the ends turn inwards — a rotated corner must not
           reach the edge of the screen. Untouched from the outgoing world: the angles are
           the gesture the owner asked to keep. */
        .jrnl-list .jrnl-print:nth-child(1) { transform: rotate(-5deg); }
        .jrnl-list .jrnl-print:nth-child(2) { transform: rotate(3deg); }
        .jrnl-list .jrnl-print:nth-child(3) { transform: rotate(-3deg); }
        .jrnl-list .jrnl-print:nth-child(4) { transform: rotate(4deg); }
        .jrnl-list .jrnl-print:nth-child(5) { transform: rotate(-2deg); }

        /* Fewer prints, bigger prints — the band fills the column either way, rather than
           going half empty because there are only two. */
        .jrnl-list .jrnl-band[data-n="4"] .jrnl-print { height: 108px; }
        .jrnl-list .jrnl-band[data-n="3"] .jrnl-print { height: 118px; }
        .jrnl-list .jrnl-band[data-n="2"] .jrnl-print { height: 130px; }
        .jrnl-list .jrnl-band[data-n="2"] .jrnl-print + .jrnl-print { margin-left: -20px; }

        /* 3 — the count of what did not fit is GONE, not moved again (owner, 2026-09-11:
           +3 more 和分割线去掉吧 其实没有太大作用). See renderJournalCard: the sticker
           became a printed line and the printed line became a whole extra row under every
           card with more than five photographs, for a number nobody had asked for. */

        /* One photograph does not go in a band: it lies flat and square, not tilted, not
           overlapped, not running past the edge — there is nothing for it to overlap. The
           white margin stays, because it is still a print. */
        .jrnl-list .jrnl-solo {
            display: block;
            width: 100%;
            height: 170px;
            margin-top: var(--sp-sm);
            box-sizing: border-box;
            border: 3px solid #FFFFFF;
            outline: 1px solid var(--log-rule);
            background: var(--log-stock-band);
            box-shadow: 0 1px 1px rgba(67, 39, 107, 0.22);
            overflow: hidden;
        }

        /* A portrait is not stretched to landscape or cropped into one. Only the image
           knows its own proportion, so the shell is marked after it loads
           (`jrnlSoloFit`) — CSS cannot ask. */
        .jrnl-list .jrnl-solo.is-portrait { width: 165px; height: 220px; }

        .jrnl-list .jrnl-solo img,
        .jrnl-list .jrnl-solo video {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        /* ---- nothing written yet --------------------------------------------------- */

        /* THE STATE EVERY JOURNEY IS IN ON ITS FIRST DAY, and the list had no drawing for
           it at all: the calendar, and then the end of the screen. */
        #journalContent .jrnl-nothing {
            padding: var(--sp-xl) var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
        }

        #journalContent .jrnl-nothing-head {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            color: var(--log-ink);
            margin-bottom: var(--sp-2xs);
        }

        #journalContent .jrnl-nothing-note {
            font-family: var(--log-write);
            font-size: var(--fs-body);
            line-height: 1.55;
            color: var(--log-ink-soft);
        }

        /* What is left of the sheet, ruled. */
        #journalContent .jrnl-fill {
            flex: 1 1 auto;
            min-height: 0;
            background-image: repeating-linear-gradient(
                to bottom,
                transparent 0,
                transparent calc(var(--log-row) - 1px),
                var(--log-rule) calc(var(--log-row) - 1px),
                var(--log-rule) var(--log-row));
        }

        /* ---- the way to write ------------------------------------------------------ */

        /* Stuck to the foot of the scroller, not floating over it. Writing an entry is the
           act this room exists for, so it is magenta, and it is a rule across the page
           rather than a circle in a corner. */
        #journalContent .jrnl-foot {
            position: sticky;
            bottom: 0;
            z-index: 2;
            background: var(--log-stock-band);
            border-top: 1px solid var(--log-rule-firm);
        }

        #journalContent .jrnl-write {
            display: block;
            width: 100%;
            min-height: 48px;
            padding: 0 var(--sp-lg);
            border: none;
            background: none;
            cursor: pointer;
            /* ⚠️ ON THE RIGHT (owner, 2026-09-11: write an entry 放右下角). Every other act in
               this world sits at the right-hand end of its rule — SAVE, OPEN, OPEN DAY,
               EDIT — and this one was at the left, which put it under the entries' own
               column and read as one more line of the list rather than as the thing that
               adds to it. */
            text-align: right;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 1px;
            color: var(--log-magenta);
        }

        #journalContent .jrnl-write:active { box-shadow: inset 0 -2px 0 0 var(--log-magenta); }

        /* When a calendar cell scrolls its entry into view, the entry says so. A wash of
           the band rather than a coloured flash — this is "here it is", not an alarm. */
        .jrnl-list .jrnl-card.is-flash { animation: jrnlFlash 1.2s ease-out; }

        @keyframes jrnlFlash {
            0%, 100% { background: var(--log-stock); }
            25%      { background: var(--log-stock-band); }
        }

        @media (prefers-reduced-motion: reduce) {
            .jrnl-list .jrnl-card.is-flash { animation: none; }
        }

        /* ---- reachable without a pointer ---------------------------------------- */

        /* ⚠️ EVERY PRESSABLE THING THAT IS NOT A <button> got `role="button"`, a `tabindex`
           and a NAME on 2026-09-11 (see `pressable()` in 01-core.js) — the journal's cards,
           the calendar's cells, the day's rows, the photographs' tiles, the pickers' rows.
           A thing that can now be focused has to SHOW that it is focused, or the keyboard
           reader it was made reachable for is moving a cursor they cannot see.

           An inset rule rather than an outline: an outline on a grid cell draws outside its
           own box and over the lattice, and this world presses by thickening a baseline
           rather than by tinting a ground. `:focus-visible`, so a pointer press does not
           leave a mark behind it. */
        [role="button"]:focus-visible {
            /* Transparent, not none: forced colours removes the shadow and draws this instead (review, 2026-09-14). */
            outline: 2px solid transparent;
            outline-offset: -2px;
            box-shadow: inset 0 0 0 2px var(--log-ink);
        }

        .pcal-cell[role="button"]:focus-visible {
            box-shadow: inset 0 0 0 2px var(--log-ink);
            z-index: 2;
        }
        /* A day with writing is filled with ink, and an ink box on it is 1.0:1: the light ink (focus audit, 2026-09-14). */
        .pcal-cell.has-text[role="button"]:focus-visible {
            box-shadow: inset 0 0 0 2px var(--log-on-oilskin);
        }
        /* A day with a photograph is filled by it, and the inset box painted under the picture (review of the focus round,
           2026-09-15). The mark is a layer above it, paper outside ink. */
        .pcal-cell.has-photo[role="button"]:focus-visible { box-shadow: none; }
        .pcal-cell.has-photo[role="button"]:focus-visible::after {
            content: '';
            position: absolute;
            inset: 0;
            z-index: 3;
            pointer-events: none;
            border: 2px solid var(--log-stock);
            box-shadow: inset 0 0 0 2px var(--log-ink);
        }
