        /* ── carried from css/06-legacy-map-stops.css on 2026-09-22, as that part was deleted.
           It is the record of how this room came to be dressed in one file, and its last
           sentence is an instruction addressed to this file. ── */
/* ══════════════════════════════════════════════════════════
           The stop detail sheet was dressed here too, and is not any more · 2026-09-12
           ══════════════════════════════════════════════════════════

           Five hundred and sixty-eight lines ended this file and every one of them dressed
           one overlay: the sheet's head, its two words, its section heads, the stay ticket
           in all its parts, the activity timeline with its rail and its dot, the day band,
           the notes aside, and a form that was rewritten in April and whose `.form-input`
           rules had had nothing to match ever since.

           It loads BEFORE css/17t-stop.css, so it did not win the properties that file
           names — it won the ones it does not. That is a quieter failure than the one in
           css/24-tail.css and it produced the same picture: a migrated room with
           `--accent` on its DAY 4–7, `--border` under its section heads, `--text-secondary`
           on its date range and a 1px `#C4CBC3` box still drawn round every category word.
           A rule that does not mention a property does not win it, and the room could not
           win a property nobody in it had mentioned.

           So the room is dressed in ONE file. If something here is wanted back, it goes to
           css/17t-stop.css — not to a second copy that loads at a different time. */

        /* ==========================================================================
           #AE  A stop — what is at one place, and the form that changes it
           ==========================================================================

           Migrated into the deck log on 2026-09-11, at the owner's word: "trip页面里的
           add a stop 页面 还是旧世界的 迁移至新世界，依旧需要加图片search 功能 unsplash",
           and then "stop detail sheet一起做" — so both modes, the reading one and the form.

           ⚠️ THIS ROOM COULD NOT BE MIGRATED BY CSS. Forty-one elements in the form carried
           a `style` attribute and twenty-four of them PAINTED — font, colour, border,
           background — and an inline style beats every stylesheet there is. The markup had
           to be rewritten before a single rule here could reach anything. The note that used
           to sit in it said why, honestly: "inline styles reproduce the 9a canvas sample
           verbatim". That is a reasonable way to land a design and a terrible way to keep
           one, and it is worth naming because this is the last room in the app that did it.

           ⚠️ AND #stopDetailSheet WAS THE EIGHTH SURFACE MISSING FROM THE TOKEN LIST at the
           head of css/02-auth.css. Checked before writing: getComputedStyle returned "" for
           both --log-ink and --log-stock. Eight is no longer a run of bad luck — every
           overlay in this app is on <body>, because .app-frame's desktop transform degrades
           position:fixed, so EVERY overlay needs that line.

           ⚠️ THE PHOTOGRAPH SEARCH IS THE TRIP FORM'S COMPONENT, NOT A COPY OF IT. The
           `.ucov-*` markup here is bound by bindCoverSearch (public/11a-cover-search.js),
           which was restructured the same day to take a scope and a callback precisely so
           this room would not get a second one. The dressing for it is shared too — see the
           note above the .ucov rules at the foot of this file. */

        /* ---- the sheet ---------------------------------------------------------- */

        #stopDetailSheet {
            background: var(--log-stock);
            border-radius: 0;
            box-shadow: none;
            /* ⚠️ BOUNDED, ALWAYS. The sheet is measured to a pixel height when it opens;
               this is what holds until it is, and `height: auto` is always wrong at this
               layer: the content decides the height, the top edge leaves the viewport so
               the head goes with it, and the body's overflow-y never triggers — so the
               sheet cannot be scrolled at all. Moved here from css/24-tail.css on
               2026-09-12 with the rest of that file's account of this room. */
            height: 80dvh;
        }

        /* One ruling tall, like every other head in this world — see --log-row. */
        #stopDetailSheet .trip-section-sheet-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-md);
            min-height: var(--log-row);
            padding: var(--sp-2xs) var(--sp-lg);
            padding-top: calc(var(--sp-2xs) + env(safe-area-inset-top, 0px));
            background: var(--log-stock-band);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        #stopDetailSheet .stop-view-heading {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            /* 8px here until today, from css/06-legacy-map-stops.css. A place and the days
               it covers are one thing said twice, not two things: they sit together, and
               the head comes in under one ruling because of it. */
            gap: 1px;
            min-width: 0;
        }

        /* ⚠️ ONE STEP DOWN, AND THE STEP WAS MEASURED AGAINST THE PAGE BEHIND IT. The
           owner, 2026-09-12: 「文字的字号有些大 再小些」. This head printed the stop's name at
           --fs-lg, 20px, while the journey's own name in the bar three rows above it is 12px
           print caps and the stop's row on the page you tapped to get here is 13.6px. A room
           one tap deeper was setting everything a step or two larger than the room it opens
           from. --fs-base is the scale's own "card titles", which is what this is. */
        #stopDetailSheet .trip-section-sheet-title {
            font-family: var(--log-print);
            font-size: var(--fs-base);
            font-weight: 600;
            letter-spacing: 0.02em;
            line-height: 1.15;
            color: var(--log-ink);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* Which nights, and how many. Printed: it is the app's arithmetic on the stop, not
           something the traveller wrote. */
        /* ⚠️ TWO PRINTED LINES, NOT ONE (2026-09-17). The stop's span became the stay's
           writing — THU 8 OCT TO TUE 13 OCT · FIVE NIGHTS — and that alone is about as wide as
           this column at 375. On one row with the day numbers it hid FIVE NIGHTS behind an
           ellipsis and broke DAY 8–13 over two lines. The day numbers take the first line, the
           owner's phrase the second, whole, and in the case the owner wrote it and a stay prints it
           (Thu 8 Oct to Tue 13 Oct · five nights): in caps it was still a pixel too wide at 375.
           It wraps rather than hides if a longer span needs to. */
        #stopDetailSheet .stop-view-meta {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            min-width: 0;
            margin: 0;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink-soft);
        }
        #stopDetailSheet .stop-view-meta:empty { display: none; }

        /* ⚠️ THESE THREE HAD NEVER BEEN DRESSED IN THIS WORLD AT ALL. DAY 4–7 came out in
           --accent, the range in --text-secondary and the dot in --border, from
           css/06-legacy-map-stops.css — which loads BEFORE this file and therefore lost
           every property this file names and won every one it does not. Dressing the
           parent is not dressing the children. */
        #stopDetailSheet .stop-meta-day { color: var(--log-ink); white-space: nowrap; }
        #stopDetailSheet .stop-meta-range { letter-spacing: 0.04em; text-transform: none; }

        #stopDetailSheet .trip-section-sheet-actions {
            display: flex;
            align-items: center;
            gap: var(--sp-lg);
            flex: none;
        }

        /* CHANGE and CLOSE: a pencil and a multiplication sign until 2026-09-11, and the
           pencil was the only way from the reading mode into the form. A way somewhere is
           a word. */
        #stopDetailSheet .stop-edit-toggle,
        #stopDetailSheet .stop-head-act,
        #stopDetailSheet .trip-section-sheet-btn {
            display: inline-flex;
            align-items: center;
            min-height: 44px;
            width: auto;
            height: auto;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
            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);
        }

        /* SAVE is the press that changes the record, so it takes the magenta here exactly
           as it did at the foot. CANCEL is a way out, and in this world ways out are ink. */
        #stopDetailSheet .stop-head-act.is-primary { color: var(--log-magenta); }
        #stopDetailSheet .stop-head-act.is-primary:active {
            box-shadow: inset 0 -2px 0 0 var(--log-magenta);
        }
        /* The head's words are shown and hidden by `hidden`, and this is what makes that
           stick: .stop-head-act is inline-flex, which beats the attribute's own display. */
        #stopDetailSheet .trip-section-sheet-actions [hidden] { display: none; }

        /* ⚠️ THE BODY IS FLUSH AND EVERY CHILD INSETS ITSELF. The plates' bands and the
           rows beneath them run to the sheet's edges the way a band does everywhere in this
           world, and a band cannot bleed out of a padded box without a negative margin that
           then has to be cancelled again. Writing a margin column here as well produced
           exactly that double-count on 2026-09-11 — the day band landed at -23px with 24px
           of padding, so DAY 4 sat 1px from the glass. */
        #stopDetailSheet .trip-section-sheet-body {
            display: flex;
            flex-direction: column;
            padding: 0 0 env(safe-area-inset-bottom, 0px);
            background: var(--log-stock);
            /* A flex child's default min-height is auto, so its content can push it past
               its parent and the scrollbar never appears. Every scrolling region in this
               app carries this line. */
            min-height: 0;
        }

        /* Which mode the sheet is in is a class on the sheet. It was display on the two
           children, written inline, which would have beaten the flex column below. */
        #stopDetailSheet #stopViewMode {
            display: flex;
            flex-direction: column;
            flex: 1 0 auto;
            min-height: 0;
        }
        #stopDetailSheet #stopEditMode { display: none; }
        #stopDetailSheet.is-editing #stopViewMode { display: none; }
        #stopDetailSheet.is-editing #stopEditMode { display: block; }

        /* ⚠️ THE SHEET IS RULED TO ITS FOOT. Its height is measured to the top of the
           journey's own sheet rather than taken from its contents — that is the
           composition, and it means a stop with one bed and one dinner ended in 390px of
           bare stock. The Ruled-To-The-Foot Rule answers exactly this: "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."

           Offset -1px so the first rule it draws lands ON the join with the last row's own
           border rather than a pixel below it, which is the same trick .log-fill uses on
           the sign-in sheet. It takes no height of its own when the contents already
           overflow, except one row, which is the bottom margin a scrolled sheet wants
           anyway. */
        #stopDetailSheet .stop-fill {
            flex: 1 1 auto;
            min-height: var(--log-row);
            background-color: var(--log-stock);
            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));
            background-position: 0 -1px;
        }

        /* ---- the reading mode --------------------------------------------------- */

        /* ⚠️ A SECTION OF DATA ON A RULED SHEET IS A PLATE, and DESIGN.md has said so since
           this world was written: "a full-width heading band on --log-stock-band with a
           firm rule under it, at most one action at the band's right end, and contents
           inset by --sp-lg. Plates are divided by the firm rule. Never by a tint, never by
           a card, never by a gap."

           This head was a word floating on bare stock with 24px of margin AND 24px of
           padding above it — 48 pixels of nothing over a 15px word — and it came out 73
           tall to say STAYS. Two of them ate 170px of a 688px sheet before a single bed was
           drawn. It is a band now, at the height of a thumb, and the gap it used to leave
           is the rule that divides one plate from the next. */
        #stopDetailSheet .stop-detail-section-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-sm);
            min-height: 44px;
            margin: 0;
            padding: 0 var(--sp-lg);
            background: var(--log-stock-band);
            border-top: 1px solid var(--log-rule-firm);
            border-bottom: 1px solid var(--log-rule-firm);
        }
        /* The first plate opens against the head's own rule; a second line there would read
           as a double rule rather than as a division. */
        #stopDetailSheet #stopViewMode > .stop-detail-section-head:first-child {
            border-top: none;
        }

        #stopDetailSheet .stop-detail-section-title {
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* Adding a stay or an activity changes the record, so it takes the magenta — the
           same ink SAVE takes, for the same reason. */
        #stopDetailSheet .stop-detail-add-link {
            display: inline-flex;
            align-items: center;
            min-height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
            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);
            white-space: nowrap;
        }

        /* The count of booked nights feeds the ghost row below and draws nothing itself. */
        #stopDetailSheet .stop-nights-booked:empty { display: none; }

        /* A plate with nothing on it still says so on a line, inset with everything else. */
        #stopDetailSheet .stop-quiet {
            margin: 0;
            padding: var(--sp-sm) var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            font-family: var(--log-write);
            font-size: var(--fs-small);
            line-height: 1.5;
            color: var(--log-ink-soft);
        }

        /* The aside's left rule went with the card. It marked a quiet passage back when the
           body was padded and the rule sat inside the margin column; with a flush body it
           landed against the glass and drew the notes as a box — which is the one thing the
           band above it already says, and the one shape the Ruled Plate Rule forbids. */
        #stopDetailSheet .stop-view-notes {
            margin: 0;
            padding: var(--sp-sm) var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            font-family: var(--log-write);
            font-size: var(--fs-body);
            font-style: normal;
            line-height: 1.5;
            white-space: pre-wrap;
            color: var(--log-ink);
        }

        /* ---- a bed, as a line in the register ----------------------------------- */

        /* ⚠️ THE STAY IS A TICKET AGAIN, AND THE MATERIAL IS NOT WRITTEN HERE.

           Its ground, its frame, its banded head, the kind printed in the band and the rule
           between the two dates are all named on the ticket's own rules in
           css/17k-ticket.css — beside the document this row opens into, so the two cannot
           drift. What belongs here is only what is different about a bed in a LIST: how far
           apart they sit, and what the panel holds.

           The old ticket is not what came back. That one was 186px and four boxes deep — a
           frame around a pad around a SHADED box around two padded cells — and the shading
           was the part the house law forbids: "do not tint a container to separate it from
           its neighbour. Separate it with a rule." The frame is the ticket; the tint was
           never doing the work it looked like it was doing. */
        #stopDetailSheet .stay-ticket {
            display: block;
            margin: var(--sp-sm) var(--sp-lg);
            padding: 0;
            border-radius: 0;
            cursor: pointer;
        }
        #stopDetailSheet .stay-ticket + .stay-ticket { margin-top: var(--sp-md); }
        #stopDetailSheet .stay-ticket:active {
            box-shadow: inset 0 -2px 0 0 var(--log-rule-firm);
        }

        /* ⚠️ BOOKED AND NOT BOOKED ARE THE TWO INKS THE DAYS VIEW USES, AND THEY ARE NOT
           THE SIGNAL COLOURS. This row printed NOT BOOKED in --log-port and BOOKED in
           --log-starboard, and DESIGN.md reserves both for something else: port red is
           "Refusal — the status text of a failed attempt"; starboard is "the reserved value
           for the first surface that genuinely needs confirmed, not an active token"; and
           the house law adds "do not colour a state that the layout already states".

           A bed nobody has booked yet is not a failure. It is the thing still outstanding —
           which is exactly what the Days view says about the same fact on the same journey,
           in ink, with BOOKED receding into the softer ink because it is settled. Two
           surfaces in one trip were printing one word in three colours, a year after the app
           was made to stop printing it in three WORDS. */
        #stopDetailSheet .stay-ticket-status,
        #stopDetailSheet .stop-tl-book {
            flex: none;
            justify-self: end;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            white-space: nowrap;
            color: var(--log-ink);
        }
        #stopDetailSheet .stay-ticket-status:not(.pending),
        #stopDetailSheet .stop-tl-book.is-booked { color: var(--log-ink-soft); }

        /* ⚠️ THE NAME IS WHAT THE BAND PRINTS, WHICH IS WHERE A CONFIRMATION PUTS IT.
           It was LODGING · 4 NIGHTS in the band and the name below — a category announced
           louder than the thing itself. A hotel's confirmation is headed by the hotel. The
           category is carried by the plate this ticket sits in, which says STAYS. */
        #stopDetailSheet .stay-ticket-name {
            font-family: var(--log-write);
            font-size: var(--fs-body);
            color: var(--log-ink);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* ⚠️ THE TWO ENDS, AND THE COUNT RIDING THE RULE BETWEEN THEM.

           The owner asked for something in the spirit of an app that draws a stay as a card
           with CHECK-IN and CHECK-OUT side by side, divided — 类似这样的效果 精致些 但不要照抄.
           What is worth taking from it is the PAIR: two labelled ends with something between
           them, which is a document's way of saying a span, and which this world already
           draws in css/17k-ticket.css as .tk-ends — "a rule between two marks is how a chart
           says from here to there".

           What is NOT taken is the notch bitten out of the card's edge, and the reason is
           already written down here. 2026-09-09, of this same ticket family: "a notch has to
           be cut out of whatever is BEHIND the sheet to read as a notch, and there is nothing
           behind this one." In that app there is — a photograph shows through the bite, which
           is what makes it read as paper. On a ruled sheet it would be two ornaments hung on
           an edge. DESIGN.md is equally plain that a stay has no tear at all: a confirmation
           has no counterfoil to give back.

           So the refinement is in what the ticket now SAYS rather than in what is cut out of
           it: the clock times, which were on the record and were being thrown away, and the
           nights, which stop being a word in a list of words and become the figure the span
           is measured by. Three columns, two rows, one grid. */
        #stopDetailSheet .stay-ticket-ends {
            display: grid;
            grid-template-columns: auto 1fr auto;
            align-items: center;
            /* Tight across, because everything the span is spent on comes out of the middle
               column and the rule is what says "from here to there" — at the widest labels
               and the longest dates there is barely a centimetre of line left for it. */
            gap: var(--sp-2xs) var(--sp-xs);
        }
        #stopDetailSheet .stay-ticket-label {
            grid-row: 1;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink-soft);
            white-space: nowrap;
        }
        #stopDetailSheet .stay-ticket-label { grid-column: 1; }
        #stopDetailSheet .stay-ticket-label.is-out { grid-column: 3; text-align: right; }

        #stopDetailSheet .stay-ticket-when {
            grid-row: 2;
            grid-column: 1;
            font-family: var(--log-print);
            font-size: var(--fs-body);
            font-weight: 600;
            font-variant-numeric: lining-nums tabular-nums;
            letter-spacing: 0.04em;
            color: var(--log-ink);
            white-space: nowrap;
        }
        #stopDetailSheet .stay-ticket-when.is-out { grid-column: 3; text-align: right; }

        /* ⚠️ THE SAME SIZE AS THE DATE IT SITS UNDER, WHICH IS WHAT WAS ASKED FOR, AND
           the softer ink, which was not. Two lines at one size and one weight would compete
           for the same glance; the date is the fact a reader is scanning for and the hour is
           the qualification on it. Size says they belong together — the Stamped-State Rule
           uses the same pair of inks for the same reason. */
        #stopDetailSheet .stay-ticket-clock {
            grid-row: 3;
            grid-column: 1;
            font-family: var(--log-print);
            font-size: var(--fs-body);
            font-variant-numeric: lining-nums tabular-nums;
            letter-spacing: 0.04em;
            color: var(--log-ink-soft);
            white-space: nowrap;
        }
        #stopDetailSheet .stay-ticket-clock.is-out { grid-column: 3; text-align: right; }

        /* The count sits ON the line, the way a figure is written on a measured span. */
        #stopDetailSheet .stay-ticket-count {
            grid-row: 2;
            grid-column: 2;
            display: grid;
            grid-template-columns: 1fr auto 1fr;
            align-items: center;
            gap: var(--sp-2xs);
            min-width: 0;
        }

        #stopDetailSheet .stay-ticket-sub {
            font-family: var(--log-write);
            font-size: var(--fs-small);
            color: var(--log-ink-soft);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* Nights with no bed under them. Dashed, because it is a place kept rather than a
           record made — the one dashed line in this room and it means exactly that. */
        #stopDetailSheet .stay-ticket-ghost {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-sm);
            min-height: 44px;
            margin: 0;
            padding: 0 var(--sp-lg);
            border: none;
            border-bottom: 1px dashed var(--log-rule-firm);
            background: var(--log-stock);
            cursor: pointer;
            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);
        }
        #stopDetailSheet .stay-ticket-ghost span:last-child {
            flex: none;
            color: var(--log-magenta);
            text-decoration: underline;
            text-underline-offset: 0.25em;
        }

        /* ---- what is planned, by day -------------------------------------------- */

        /* ⚠️ THE GROUND HAD TO BE SAID OUT LOUD. This band and the rows below it inherited
           --bg-primary and --surface-field from css/24-tail.css — the outgoing world's
           cream — because this file dressed their type and their rules and never named
           their background. A rule that does not mention a property does not win it. That
           file no longer dresses this room at all, and the lesson is why every ground in
           here is stated rather than left to the cascade. */
        #stopDetailSheet .stop-day-label {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: var(--sp-sm);
            /* A day divides rows WITHIN one plate, so it takes the hairline; the plate's
               own head takes the firm rule. Weight is what carries the hierarchy, because
               both bands stand on the same stock. */
            margin: 0;
            padding: var(--sp-2xs) var(--sp-lg);
            background: var(--log-stock-band);
            border-bottom: 1px solid var(--log-rule);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            font-variant-numeric: lining-nums tabular-nums;
        }
        #stopDetailSheet .stop-tl + .stop-day-label { border-top: 1px solid var(--log-rule); }
        #stopDetailSheet .stop-day-n { color: var(--log-ink); }
        #stopDetailSheet .stop-day-d { color: var(--log-ink-soft); }

        #stopDetailSheet .stop-tl-row {
            display: flex;
            align-items: stretch;
            gap: var(--sp-sm);
            min-height: 44px;
            padding: var(--sp-2xs) var(--sp-lg);
            background: var(--log-stock);
            border-bottom: 1px solid var(--log-rule);
            cursor: pointer;
        }
        #stopDetailSheet .stop-tl-row:active {
            box-shadow: inset 0 -2px 0 0 var(--log-rule-firm);
        }

        /* The category mark. Kept, and it is the same carve-out the journal's link picker
           has: a colour standing for a kind is not a picture of the kind. */
        /* ⚠️ `align-items: stretch` ON THE ROW, or this does nothing. align-self: stretch is
           a request the parent has to allow, and the row was `align-items: baseline` — which
           put a 3px bar on the text's baseline and drew it as a speck. */
        #stopDetailSheet .stop-tl-icon {
            flex: none;
            width: 3px;
            min-height: 100%;
            align-self: stretch;
            background: var(--c, var(--log-rule-firm));
        }
        /* The row stretches; the words inside it still sit on a baseline. */
        #stopDetailSheet .stop-tl-time,
        #stopDetailSheet .stop-tl-body { align-self: center; }

        #stopDetailSheet .stop-tl-time {
            flex: none;
            width: 44px;
            font-family: var(--log-print);
            font-size: var(--fs-small);
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink-soft);
        }

        #stopDetailSheet .stop-tl-body {
            flex: 1;
            min-width: 0;
            padding: 0;
        }

        #stopDetailSheet .stop-tl-head {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: var(--sp-sm);
        }

        #stopDetailSheet .stop-tl-name {
            margin: 0;
            font-family: var(--log-write);
            font-size: var(--fs-body);   /* with the bed above it — see .stay-ticket-name */
            color: var(--log-ink);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* ⚠️ AND THE CATEGORY WORD HAD A BOX AROUND IT — 1px of hand-typed #C4CBC3, from
           css/06-legacy-map-stops.css, which this file's rule could not take off because it
           never mentioned a border. In this world a box means "this encloses something" or
           "this can be pressed", and a category is neither: it is a word. */
        #stopDetailSheet .stop-tl-tag {
            display: inline;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            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 form ----------------------------------------------------------- */

        /* ⚠️ THE FORM IS THE SHEET'S RULED ENTRIES. Until 2026-09-12 every field in here
           was a caption stacked over its value — `.sed-label` above `.sed-input`, with a
           16px margin under each pair — and the Margin-Column Rule forbids exactly that:
           "Labels live in the margin column on their value's own baseline. Never stack a
           caption above a field in this world."

           The rows are `.log-entry` from css/02-auth.css, the component the sign-in sheet,
           the register, Edit profile and My friends already use. Nothing here redraws it;
           these rules are only the three things this form has that a plain entry does not —
           a stepper, a line the app writes rather than the reader, and a box that grows.

           The height is the other half of it. A caption, a gap, a 44px field and a 16px
           margin is 79px to ask one question. A ruled entry is 53, which is the pitch the
           whole world is ruled at, and the rules between the rows do the work the gaps were
           doing. */
        #stopDetailSheet .sed {
            /* Flush, like the reading mode: the entry rows and the photograph's band run to
               the sheet's edges, and everything that is not a row insets itself. */
            padding: 0;
        }

        #stopDetailSheet .sed-entries {
            border-top: 1px solid var(--log-rule-firm);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        /* ⚠️ THE TYPED VALUES COME DOWN A STEP TOO, AND THIS IS A DECISION WITH A COST.
           The owner, 2026-09-12, having already had the room's printed text reduced once:
           输入字体再小些. DESIGN.md's Body role asks for a full 16px here — "the only text a
           traveller authors here… anything smaller invites iOS zoom" — and the app's
           viewport carries no maximum-scale, so that is a live consequence and not a
           precaution: tapping into a 13.6px field on an iPhone will zoom the page.

           Taken anyway, because the owner has now asked twice and it is their form to read.
           SCOPED to this sheet rather than changed in css/02-auth.css, which would take the
           sign-in sheet, the register, Edit profile and My friends with it on a request made
           about one page. That leaves the shared component printing at two sizes, which is a
           split worth knowing about — it is on DEBTS.md with the two ways to close it. */
        #stopDetailSheet .log-entry-value { font-size: var(--fs-body); }

        /* Every row on the ruling, including the three whose value is not a field. The
           stepper and the two printed lines came out at 47 against a field's 53, which on a
           ruled sheet reads as a row that has slipped rather than as a row of its own kind. */
        #stopDetailSheet .log-entry { min-height: var(--log-row); }

        /* The list of places hangs from the row it belongs to, in the entry column rather
           than across the margin — the same geometry Edit profile's place row uses. */
        #stopDetailSheet .sed-entry-place { position: relative; }
        #stopDetailSheet .sed-entry-place .place-suggestions {
            left: 6.5rem;
            right: 0;
        }

        /* The place was resolved to real coordinates, not merely typed. It was a tick in
           the outgoing sage; then a word in --log-starboard, which DESIGN.md reserves —
           "the reserved value for the first surface that genuinely needs confirmed, not an
           active token" — and a resolved coordinate is a state of the record, not a signal
           that something went right. It is the ink, like every other stamped state in this
           app. --log-starboard now has no use anywhere in the app, which is what "reserved"
           was always supposed to mean. */
        #stopDetailSheet .sed-pinned {
            display: flex;
            align-items: center;
            padding-right: var(--sp-sm);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            color: var(--log-ink);
            white-space: nowrap;
        }

        /* ⚠️ − AND + WERE TWO GLYPHS AT 20px IN THE OUTGOING SAGE, and they are the one
           pair of controls in this app that change a NUMBER rather than open something.
           Words, like every other control in this world — and they had no names at all, so
           a reader without sight met two unlabelled buttons around a figure. */
        #stopDetailSheet .sed-step {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-sm);
            min-height: 44px;
            padding: 0 var(--sp-sm);
        }

        #stopDetailSheet .sed-stepper {
            flex: none;
            min-height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 1px;
            color: var(--log-ink);
        }

        /* ⚠️ THE FIGURE SITS WITH THE VALUES, NOT ABOVE THEM. It was --fs-lg, which the
           scale reserves for section headings, and in a 53px row it was the largest thing in
           the form — a number the reader sets, printed larger than the name of the place. */
        #stopDetailSheet .sed-count {
            font-family: var(--log-print);
            font-size: var(--fs-base);
            font-weight: 600;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink);
        }

        /* A value the app worked out rather than one the reader set: no field, no caret,
           and the softer ink says so without a word for it. */
        #stopDetailSheet .sed-read {
            display: flex;
            align-items: center;
            min-height: 44px;
            padding: var(--sp-sm);
            font-family: var(--log-print);
            font-size: var(--fs-small);
            letter-spacing: 0.06em;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink-soft);
        }

        /* When the answer is that these nights belong to another stop, the row takes the
           fault treatment the ruled entry already owns — the inset port baseline and the
           margin label in port. Written once, in css/02-auth.css, for the sign-in sheet's
           refusals. THIS is what port red is for in this world; the same red on a bed that
           simply has not been booked yet was the misuse this round removed upstairs. */
        #stopDetailSheet .sed-entry-derived[data-fault="true"] .sed-read {
            color: var(--log-port);
        }

        /* Notes grow, so the label sits at the top of the row rather than in its middle —
           the same exception Edit profile's About row takes. */
        #stopDetailSheet .sed-entry-notes .log-entry-label { align-items: flex-start; }

        /* The 72px of right padding went with TALLER, which used to sit in that corner. A
           box that grows on its own needs no room kept for a control that made it grow. */
        #stopDetailSheet .sed-notes {
            min-height: 74px;
            resize: none;
            overflow: hidden;
            display: block;
            line-height: 1.5;
        }

        /* ⚠️ A SOLID HAIRLINE, NOT A DOTTED ONE. The one field left that is not a ruled
           entry — the pasted link, which lives inside the photograph's plate rather than in
           the register — was `1px dotted`, the outgoing world's mark for "you may write
           here". This world rules its sheet, and a ruled line is solid. */
        #stopDetailSheet .sed-input,
        #stopDetailSheet .sed-line {
            width: 100%;
            box-sizing: border-box;
            min-height: 44px;
            padding: var(--sp-2xs) 0;
            border: none;
            border-bottom: 1px solid var(--log-rule-firm);
            border-radius: 0;
            background: none;
            outline: none;
            font-family: var(--log-write);
            font-size: var(--fs-base);
            color: var(--log-ink);
        }

        /* A row that holds a field carries the rule; the field inside it gives it up, or
           the line is drawn twice. */
        #stopDetailSheet .sed-line {
            display: flex;
            align-items: center;
            gap: var(--sp-sm);
            padding: 0;   /* the controls inside are 44; the row does not add to them */
        }
        /* ⚠️ 44, NOT 40. Setting these a little short kept the row from growing, which is a
           layout convenience paid for out of the one number that decides whether a thumb
           lands on the control. */
        #stopDetailSheet .sed-line .sed-input {
            flex: 1;
            min-width: 0;
            border-bottom: none;
            min-height: 44px;
        }

        #stopDetailSheet .sed-input::placeholder {
            color: var(--log-ink-soft);
            opacity: 1;
        }

        #stopDetailSheet .sed-input:focus,
        #stopDetailSheet .sed-line:focus-within {
            border-bottom-color: var(--log-ink);
            box-shadow: inset 0 -2px 0 0 var(--log-ink);
        }
        #stopDetailSheet .sed-line:focus-within .sed-input { box-shadow: none; }


        /* ---- the two ways to a photograph --------------------------------------- */

        /* The plate's contents, inset by the margin column like every other thing in this
           sheet that is not a full-width band. */
        #stopDetailSheet .sed-plate-block {
            padding: var(--sp-xs) var(--sp-lg) var(--sp-lg);
        }

        #stopDetailSheet .sed-ways {
            display: flex;
            align-items: stretch;
            gap: var(--sp-xl);
            min-height: 44px;
            margin-bottom: var(--sp-xs);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        #stopDetailSheet .sed-way {
            display: inline-flex;
            align-items: center;
            min-height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }
        #stopDetailSheet .sed-way.is-on {
            color: var(--log-ink);
            box-shadow: inset 0 -3px 0 0 var(--log-ink);
        }

        #stopDetailSheet .sed-way-body { display: none; }
        #stopDetailSheet .sed-way-body.is-on { display: block; }

        /* The photograph itself. It was bordered in --rule-soft with a 16:9 box; it keeps
           the proportion and takes this world's rule. */
        /* ⚠️ ABOVE THE WAYS, NOT UNDER THE GRID — see the note in the markup. The margin
           turned round with it: a plate that leads a section is spaced from what FOLLOWS. */
        #stopDetailSheet .sed-plate {
            position: relative;
            margin-bottom: var(--sp-md);
            border: 1px solid var(--log-rule-firm);
            border-radius: 0;
            aspect-ratio: 16 / 9;
            overflow: hidden;
            background: var(--log-stock-band);
        }
        #stopDetailSheet .sed-plate img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        /* Whoever took it, when it came from Unsplash. The same band, wash and reasoning as
           the search grid's own bylines — see .ucov-by. */
        #stopDetailSheet .sed-plate-by {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            padding: 2px var(--sp-xs);
            background: rgba(22, 25, 26, 0.70);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            letter-spacing: 0.08em;
            color: var(--log-on-oilskin);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        #stopDetailSheet .sed-plate-by a {
            color: var(--log-on-oilskin);
            text-decoration: underline;
            text-underline-offset: 0.15em;
        }

        /* ---- the acts ----------------------------------------------------------- */

        /* SAVE at the right, under the thumb; the ways out at the left, where this world
           puts BACK, PREVIOUS and CLOSE. The same arrangement the trip's own form took on
           the owner's word (cancel 左边 save 右边). */
        /* ⚠️ ONE ACT AT THE FOOT NOW, AND IT IS THE ONE THAT CANNOT BE UNDONE. Cancel and
           Save went to the head on 2026-09-12; Delete stayed. It is not a way out of the
           form and it is not a way to keep it, and a removal sitting under the thumb that
           reaches for Save is how a stop gets deleted by somebody who meant to keep it. */
        #stopDetailSheet .sed-acts {
            display: flex;
            align-items: center;
            gap: var(--sp-xl);
            min-height: var(--log-row);
            margin: 0;
            /* Flush body, so the row insets itself — and the rule above it is the plate
               divider, not a margin. */
            padding: var(--sp-2xs) var(--sp-lg);
            padding-bottom: calc(var(--sp-2xs) + env(safe-area-inset-bottom, 0px));
            border-top: 1px solid var(--log-rule-firm);
        }
        #stopDetailSheet .sed-acts[hidden] { display: none; }

        /* A companion may read a journey's stops and may not change them. Keeping and
           removing both disappear; the way out does not. */
        #stopDetailSheet.view-only .stop-head-act.is-primary,
        #stopDetailSheet.view-only .sed-acts { display: none; }

        #stopDetailSheet .sed-act {
            flex: none;
            min-height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
            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);
        }
        #stopDetailSheet .sed-act.is-remove { color: var(--log-magenta); }   /* was port red (owner, 2026-09-17: 打开表单算写记录，删除统一用品红) */
        #stopDetailSheet .sed-act.is-primary {
            color: var(--log-magenta);
            margin-left: auto;
        }
        #stopDetailSheet .sed-act.is-primary:active {
            box-shadow: inset 0 -2px 0 0 var(--log-magenta);
        }

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

        #stopDetailSheet button:focus-visible,
        #stopDetailSheet [tabindex]:focus-visible {
            outline: 2px solid var(--log-ink);
            outline-offset: 2px;
        }

        /* ==========================================================================
           A place, offered — in whichever room asks for one
           ==========================================================================

           ⚠️ FOUR ROOMS DRESSED THIS LIST SEPARATELY: Saved, the profile editor, the journal
           editor, and — as of today — the stop sheet. The journal editor's own note
           anticipated exactly this: "scoped to this form because .place-suggestions is
           shared with the stops picker, WHICH IS IN ANOTHER ROOM'S ROUND." This is that
           round, so the fourth copy is not written; the three become one.

           ⚠️ WHAT DIFFERS BETWEEN THE ROOMS IS GEOMETRY, AND THAT IS REAL. Saved floats the
           list over the sheet; the journal editor puts it in normal flow, because there it
           was absolutely positioned inside one half of a two-column row and opened 166px
           wide with its bottom clipped — laid out, opaque, invisible, and reported as "the
           field cannot be used". Those are different answers to different rooms. The INK is
           not: stock, one rule, 44px rows, the band on hover. That part lives here, and each
           room now says only where its list sits. */

        .place-suggestions {
            background: var(--log-stock);
            border: 1px solid var(--log-rule-firm);
            border-radius: 0;
            box-shadow: none;
            overflow-y: auto;
        }

        .place-suggestion {
            display: flex;
            align-items: center;
            min-height: 44px;
            padding: var(--sp-xs) var(--sp-md);
            font-family: var(--log-write);
            font-size: var(--fs-base);
            color: var(--log-ink);
            cursor: pointer;
        }
        .place-suggestion + .place-suggestion { border-top: 1px solid var(--log-rule); }
        /* Said above the list when it is the journey's stops rather than a search (01-core.js). */
        .place-suggestions-note {
            margin: 0;
            padding: var(--sp-xs) var(--sp-md);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            color: var(--log-ink);
        }
        #writeJournalModal .place-suggestions-note { padding-left: 0; padding-right: 0; }
        .place-suggestion:hover,
        .place-suggestion:active { background: var(--log-stock-band); }
        .place-suggestion:focus-visible {
            outline: none;
            box-shadow: inset 0 0 0 2px var(--log-ink);
        }

        /* The stop sheet's own geometry: under the field, over what follows. */
        #stopDetailSheet .place-suggestions {
            position: absolute;
            left: 0;
            right: 0;
            top: 100%;
            z-index: 3;
            max-height: 40vh;
            border-top: none;
        }

        /* ==========================================================================
           The photograph search, in whichever room asks for it
           ==========================================================================

           ⚠️ THESE RULES WERE SCOPED TO #planTripModal AND ARE NOT ANY MORE. The component
           became shared on 2026-09-11 (bindCoverSearch takes a scope and a callback), and a
           shared component dressed per-room is a copy waiting to happen — the same fault as
           the two pickers where one kept its magnifier, and the two calendars before them.

           So the dressing lives once, on `.ucov`, and each room only says where the panel
           sits. If a third room asks, it draws the markup and inherits all of this. */

        .ucov {
            padding: var(--sp-sm) 0 var(--sp-md);
            background: var(--log-stock);
        }

        .ucov-bar {
            display: flex;
            align-items: stretch;
            gap: var(--sp-md);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        .ucov-input {
            flex: 1;
            min-width: 0;
            min-height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            outline: none;
            font-family: var(--log-write);
            font-size: var(--fs-base);
            color: var(--log-ink);
        }
        .ucov-input::placeholder {
            color: var(--log-ink-soft);
            opacity: 1;   /* Firefox dims a placeholder by default; 0.54 of ink-soft is not legible */
        }

        .ucov-go {
            flex: none;
            min-height: 44px;
            padding: 0;
            border: none;
            background: none;
            cursor: pointer;
            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);
        }

        /* What the search has to say for itself — looking, nothing found, or why it could
           not ask. An empty grid and a grid that has not been asked for look identical,
           which is how the notifications page spent a week pretending it had no notices. */
        .ucov-said {
            padding-top: var(--sp-sm);
            font-family: var(--log-write);
            font-size: var(--fs-body);
            color: var(--log-ink-soft);
        }
        .ucov-said.is-wrong { color: var(--log-port); }

        .ucov-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 1px;
            margin-top: var(--sp-sm);
            background: var(--log-rule);
            border: 1px solid var(--log-rule);
        }
        .ucov-grid:empty { display: none; }

        /* A figure, not a button: the byline under each photograph has to be a LINK to the
           photographer's page, and a <button> may not contain one. So the picture is the
           button and the byline is its sibling. */
        .ucov-tile {
            position: relative;
            display: block;
            width: 100%;
            aspect-ratio: 16 / 10;
            margin: 0;
            padding: 0;
            border: none;
            border-radius: 0;
            background: var(--log-stock-band);
            overflow: hidden;
        }

        .ucov-take {
            display: block;
            width: 100%;
            height: 100%;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            cursor: pointer;
        }

        .ucov-tile img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        /* ⚠️ 0.70, AND THE NUMBER IS MEASURED. At 0.62 this band composites over a bright
           photograph to rgb(111,112,113), and --log-on-oilskin on that is 4.18:1 — under the
           4.5 that 11px text needs. Over the capture's stub it measured 5.25:1, which is
           exactly why the photograph of it looked fine; a real Bali search comes back full of
           white sky, which is what a landscape-only search returns. At 0.70 the worst case is
           5.51:1.

           Whoever took it, on every tile — not only on the one that gets chosen. That is what
           "wherever the photograph is shown" means, and twelve are shown at once. */
        .ucov-by {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            padding: 2px var(--sp-xs);
            background: rgba(22, 25, 26, 0.70);
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            letter-spacing: 0.08em;
            color: var(--log-on-oilskin);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            text-align: left;
        }
        .ucov-by a {
            color: var(--log-on-oilskin);
            text-decoration: underline;
            text-underline-offset: 0.15em;
        }

        /* Chosen. Stamped on the margin rather than tinted over the photograph — a wash over
           a picture is exactly the Ink-Not-Glow the rest of this world refuses, and it would
           also change the thing you are trying to judge. */
        .ucov-tile.is-on { box-shadow: inset 0 0 0 4px var(--log-ink); }
        .ucov-take:focus-visible {
            outline: none;
            box-shadow: inset 0 0 0 3px var(--log-magenta);
        }

        .ucov-source {
            padding-top: var(--sp-sm);
            font-family: var(--log-write);
            font-size: var(--fs-small);
            color: var(--log-ink-soft);
        }
        .ucov-source a {
            color: var(--log-ink);
            text-decoration: underline;
            text-underline-offset: 0.2em;
        }
