
        /* ══════════════════════════════════════════════════════════════
           MOVED OUT OF css/07-legacy-plan-trip.css · 2026-09-21  (prepended)
           36 rules. DESIGN.md: a surface's rules go in that surface's part, and the
           legacy parts only shrink.
           ⚠️ 07-legacy-plan-trip.css loaded BEFORE this file. This placement keeps
           their order against THIS PART’S OWN rules and nothing else: against the 33 part(s)
           between #7 and #41 the move reverses it. The banner used to claim they "keep that
           place" full stop, which was never true (review, 2026-09-22). Checked separately.
           ══════════════════════════════════════════════════════════════ */
        /* Pinned to the sheet body's box, not sized by a chain of flex parents.
           `height: 100%` needed every ancestor between here and the sheet to pass a
           definite height down — sheet → body → #sectionContent → wrap — and
           #sectionContent is moved into the sheet at runtime by JS, with no height rules
           of its own. One weak link and the wrap grows to fit its content instead, which
           pushed the bottom bar off the screen and left nothing with a bounded height to
           scroll. Absolute inset needs no cooperation from anything above it. */
        .mg2-wrap {
            position: absolute;
            inset: 0;
            display: flex;
            flex-direction: column;
            padding: 0;
        }


        .mg2-scroll {
            flex: 1;
            min-height: 0;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            padding: 8px 8px 16px;
        }

        /* ----- Toolbar ----- */
        .mg2-bar {
            flex: none;
            display: flex;
            align-items: center;
            gap: var(--sp-md);
            padding: var(--sp-sm) var(--sp-md);
            border-bottom: 1px solid var(--log-rule);
        }


        .mg2-filter {
            display: flex;
            align-items: center;
            gap: 4px;
            padding: 0;
            border: none;
            background: transparent;
            cursor: pointer;
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
            transition: color 0.3s;
        }

        /* Underlined rather than filled: the two filters are a place in a list, not two
           buttons, and an underline says which one you are on without adding a box. */
        .mg2-filter.is-on {
            color: var(--log-ink);
            /* 批次 07：这不是阴影，是用 inset shadow 画的下划线。改 border-bottom，视觉不变。 */
            border-bottom: 1px solid var(--log-ink);
        }


        .mg2-baraction {
            margin-left: auto;
            padding: 0;
            border: none;
            background: transparent;
            cursor: pointer;
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink);
        }


        .mg2-bar.is-selecting { background: var(--log-stock-band); }


        .mg2-selcount {
            font-family: var(--log-write);
            font-size: 13px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* ----- Bottom bar ----- */
        .mg2-foot {
            flex: none;
            display: flex;
            border-top: 1px solid var(--log-rule);
            background: var(--log-stock-band);
            padding-bottom: env(safe-area-inset-bottom, 0px);
        }


        .mg2-footbtn {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            padding: var(--sp-md) var(--sp-xs);
            border: none;
            background: transparent;
            cursor: pointer;
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink);
            transition: background 0.3s;
        }


        .mg2-footbtn + .mg2-footbtn { border-left: 1px solid var(--log-rule); }

        .mg2-footbtn:hover:not(:disabled) { background: var(--log-stock-band); }

        .mg2-footbtn.is-danger { color: var(--log-magenta); }

        .mg2-footbtn:disabled { color: var(--log-ink-soft); cursor: default; }

        /* ----- Selection ----- */
        .mg2-cols.is-selecting .mg2-tile::after {
            content: '';
            position: absolute;
            top: 6px;
            left: 6px;
            width: 18px;
            height: 18px;
            border-radius: 0;
            border: 1.5px solid var(--log-on-night-plate);
            background: rgba(22, 25, 26, 0.32);   /* the oilskin, not the outgoing #242424 (2026-09-17) */
            z-index: 2;
        }

        /* Mirrors the base selector's specificity on purpose. A shorter
           `.mg2-tile.is-picked::after` would score lower than the rule above and lose,
           which is exactly how the photo-picker's tick came to be invisible once already. */
        .mg2-cols.is-selecting .mg2-tile.is-picked::after {
            background: var(--log-ink);
            border-color: var(--log-ink);
        }

        /* The tick, positioned from the circle's centre rather than by eye.
           
           A CSS checkmark is a box showing only its right and bottom borders, rotated 45°.
           The visible ink is NOT centred in that box — it sits toward the bottom-right
           corner — and rotating moves that offset to roughly 1.75px below the box centre.
           So centring the box (which is what `top: 11px; left: 11px` was doing, and not
           even that accurately) leaves the tick visibly low and left inside its circle.
           
           The circle is `--tick-inset` from the corner and `--tick-dia` across (border-box,
           so the border is included). Everything below derives from those two, so moving
           or resizing the circle moves the tick with it. */
        .mg2-cols.is-selecting .mg2-tile.is-picked::before {
            --tick-inset: 6px;
            --tick-dia: 18px;
            --tick-w: 5px;
            --tick-h: 9px;
            /* ink offset after the 45° rotation: (-0.15px, +1.74px) */
            content: '';
            position: absolute;
            top: calc(var(--tick-inset) + var(--tick-dia) / 2 - var(--tick-h) / 2 - 1.74px);
            left: calc(var(--tick-inset) + var(--tick-dia) / 2 - var(--tick-w) / 2 + 0.15px);
            width: var(--tick-w);
            height: var(--tick-h);
            border: solid var(--log-on-night-plate);
            border-width: 0 1.5px 1.5px 0;
            transform: rotate(45deg);
            z-index: 3;
        }


        .mg2-cols.is-selecting .mg2-tile.is-picked img,
        .mg2-cols.is-selecting .mg2-tile.is-picked video { opacity: 0.6; }

        /* The heart is a second tap target on the same tile; in select mode the tile
           itself is the target, so the heart steps out of the way entirely. */
        .mg2-fav.is-hidden { display: none; }

        /* .mg2-count and the .mg2-daterow rules were here. The count moved into the
           toolbar's "All · 218", and the date separators were removed: they keyed on the
           full timestamp, so once taken_at was populated every photo became its own
           group. Sorting by capture time replaced them. */
        .mg2-empty { padding: 48px 12px; text-align: center; color: var(--log-ink-soft); font-size: 15px; }

        /* Two column containers side by side, each a plain vertical stack. The balancing
           happens in JS — see layoutMasonry — because neither CSS columns nor CSS grid can
           do "reading order *and* no gaps" on their own.
           
           flex rather than grid so the columns size themselves and nothing aligns to a
           row. */
        .mg2-cols {
            display: flex;
            align-items: flex-start;
            /* Tighter than the 8px it was: three columns in a 390px frame leaves each
               tile about 120px, and a wide gutter takes a noticeable bite out of that. */
            gap: 4px;
        }


        .mg2-col {
            flex: 1;
            min-width: 0;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .mg2-tile { break-inside: avoid; margin-bottom: 8px; border-radius: 0; overflow: hidden; position: relative; cursor: pointer; display: block; background: var(--log-stock-band); }

        .mg2-tile img, .mg2-tile video { width: 100%; height: auto; display: block; }

        /* A picture comes in rather than appears. The tile is already its final size —
           the width and height from upload, written on the <img>, size it (since 2026-09-14;
           before that nothing did, and a tile was 0px tall until its picture landed) — so the only thing that changes when the
           bytes land is the picture itself: held at 0 until decoded, then a short fade
           (02-state.js marks it on load). Per tile: a spinner over the whole grid would
           hide the pictures already here while waiting for the slowest one. */
        .mg2-tile img { opacity: 0; transition: opacity 0.18s ease; }

        .mg2-tile img.is-in { opacity: 1; }

        /* The gallery before the trip's media has arrived from the server: the grid's
           own shape — three columns of band at photograph-like ratios, breathing — and
           after a moment a line of words, so a slow answer does not look like an empty
           album or a broken app. Timed by the stylesheet, like the wall's. */
        .mg2-waiting { position: relative; }

        .mg2-waiting i {
            display: block;
            margin-bottom: 8px;
            background: var(--log-stock-band);
            animation: wall-breathe 1.8s ease-in-out infinite;
        }

        .mg2-waiting .mg2-col:nth-child(2) i { animation-delay: 0.3s; }

        .mg2-waiting .mg2-col:nth-child(3) i { animation-delay: 0.6s; }

        .mg2-waiting-word {
            position: absolute;
            left: 0; right: 0;
            top: 45%;
            margin: 0;
            padding: 0 var(--sp-lg);
            text-align: center;
            font-family: var(--log-write);
            font-size: 13px;
            line-height: 1.6;
            color: var(--log-ink-soft);
            opacity: 0;
        }

        .mg2-waiting-word.is-soon { animation: wall-word-soon 0.4s ease 1.5s forwards, wall-word-gone 0.2s ease 8s forwards; }

        .mg2-waiting-word.is-late { animation: wall-word-late 0.4s ease 8s forwards; }

        .mg2-waiting-word button {
            background: none; border: none; padding: 0; cursor: pointer;
            font: inherit; color: var(--log-ink-soft); text-decoration: underline; text-underline-offset: 0.2em;
        }

            .mg2-waiting i { animation: none; }

            .mg2-tile img { transition: none; }

        /* ==========================================================================
           #AI  The gallery — a journey's album, in the deck log
           ==========================================================================

           2026-09-13. The owner, after the tile's marks were settled: 整个页面没有迁移. The fifth room on the section
           sheet, and the fourth to move: openTripSectionSheet sets `is-log` for it now, so the head, the ground and the way
           out are the Journal's, the Calendar's and the Expenses' (css/17n-journal-list.css).

           ⚠️ EVERY RULE NAMES #tripSectionSheet.is-log. The gallery's legacy rules live in 07-legacy-plan-trip.css,
           19-legacy-media.css and 22-diagnostics.css, which load AFTER this file and name bare classes; the id and the
           class win on specificity whichever loads last.

           The photographs carry the colour. The room is ink on stock: words where the glyphs were — SEARCH, NEWEST FIRST,
           UPLOAD — the choices underlined, every control 44px. The heart and the pin stay marks on the photograph, which
           is the owner's call of the same day (css/19-legacy-media.css). */

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

        /* ---- the bar under the head: which of the album, and the two acts on it ------------ */
        /* Dressed as the Expenses' views are, which do the same job: words on the stock, the current one in full ink and
           underlined, and the acts to the right as words that are underlined because they act. */
        #tripSectionSheet.is-log .mg2-bar {
            gap: 0 var(--sp-lg);
            padding: 0 var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            background: var(--log-stock);
        }
        #tripSectionSheet.is-log .mg2-bar.is-selecting { background: var(--log-stock-band); }
        #tripSectionSheet.is-log .mg2-filter,
        #tripSectionSheet.is-log .mg2-baraction,
        #tripSectionSheet.is-log .mg2-selcount {
            display: inline-flex;
            align-items: center;
            min-height: 44px;
            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.16em;
            text-transform: uppercase;
            white-space: nowrap;
        }
        #tripSectionSheet.is-log .mg2-filter { color: var(--log-ink-soft); }
        #tripSectionSheet.is-log .mg2-filter.is-on,
        #tripSectionSheet.is-log .mg2-baraction {
            color: var(--log-ink);
            border-bottom: none;
            text-decoration: underline;
            text-underline-offset: 0.3em;
            text-decoration-thickness: 1px;
        }
        #tripSectionSheet.is-log .mg2-selcount { color: var(--log-ink); }
        /* SEARCH and SELECT sit together at the right; only the first is pushed there. */
        #tripSectionSheet.is-log .mg2-searchword { margin-left: auto; }
        #tripSectionSheet.is-log .mg2-searchword + .mg2-selectbtn { margin-left: 0; }

        /* ---- the album ----------------------------------------------------------- */
        #tripSectionSheet.is-log .mg2-scroll { padding: var(--sp-sm) var(--sp-md) var(--sp-lg); }
        /* ⚠️ WHERE THE PHOTOGRAPH WILL BE, DARKER THAN THE WORDS UNDER IT (owner, 2026-09-14: 占位区换深一点). Before its
           picture arrives a tile holds the photograph's shape, and that shape was the same band as the words under it, so
           nothing showed where the photograph would end. The darker ground is the tile's, because the img is held at
           opacity 0 until it arrives and opacity hides an img's own background with it; the words carry the band as
           theirs. #B9C3C0 is the log's band (#CFD7D5) and rule (#9FAAA7) mixed 55:45, written out rather than as
           color-mix() so the value a check reads back is the value on the page. */
        #tripSectionSheet.is-log .mg2-tile { background: #B9C3C0; }
        /* ⚠️ AND THE WORDS ON WHITE, AS A POLAROID'S ARE (owner, the same day: 下面注释 caption改成白色 像宝丽来照片的效果).
           Chosen over a white frame on all four sides, which would have shrunk every photograph and moved its marks: the
           photograph still runs to the tile's edges, and only the strip under it is white. The white is the log's paper,
           #E8EDEB, the ground a lit mark is drawn on. */
        #tripSectionSheet.is-log .mg2-state,
        #tripSectionSheet.is-log .mg2-cap { background: #E8EDEB; }
        #tripSectionSheet.is-log .mg2-state-words { font-family: var(--log-print); color: var(--log-ink-soft); }
        #tripSectionSheet.is-log .mg2-state-act { font-family: var(--log-write); color: var(--log-ink); }
        #tripSectionSheet.is-log .mg2-cap { font-family: var(--log-write); color: var(--log-ink-soft); }

        /* Selecting: the box is square and a picked one is the log's ink filled in, as a pinned photograph is. */
        #tripSectionSheet.is-log .mg2-cols.is-selecting .mg2-tile.is-picked::after {
            background: var(--log-ink);
            border-color: var(--log-ink);
        }

        /* Nothing in it, and not yet read. */
        #tripSectionSheet.is-log .mg2-empty {
            padding: var(--sp-2xl) var(--sp-sm);
            font-family: var(--log-write);
            font-size: var(--fs-small);
            line-height: 1.5;
            text-align: left;
            color: var(--log-ink-soft);
        }
        #tripSectionSheet.is-log .mg2-waiting i { background: var(--log-stock-band); }
        #tripSectionSheet.is-log .mg2-waiting-word {
            font-family: var(--log-write);
            font-size: var(--fs-small);
            color: var(--log-ink-soft);
        }
        #tripSectionSheet.is-log .mg2-waiting-word button { color: var(--log-ink); min-height: 44px; }

        /* ---- the foot: the order, and adding ----------------------------------------- */
        #tripSectionSheet.is-log .mg2-foot {
            border-top: 1px solid var(--log-rule-firm);
            background: var(--log-stock-band);
        }
        #tripSectionSheet.is-log .mg2-footbtn {
            min-height: 48px;
            gap: 0;
            background: none;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
            text-decoration: underline;
            text-underline-offset: 0.3em;
            text-decoration-thickness: 1px;
        }
        #tripSectionSheet.is-log .mg2-footbtn + .mg2-footbtn { border-left: 1px solid var(--log-rule); }
        #tripSectionSheet.is-log .mg2-footbtn:hover:not(:disabled) { background: none; }
        /* The one magenta in the room is spent on the act that adds to the record, as ADD A STOP and ADD TO THIS DAY. */
        #tripSectionSheet.is-log .mg2-footbtn.is-add { color: var(--log-magenta); }
        #tripSectionSheet.is-log .mg2-footbtn.is-danger { color: var(--log-magenta); }   /* was port red (owner, 2026-09-17: 打开表单算写记录，删除统一用品红) */
        #tripSectionSheet.is-log .mg2-footbtn:disabled { color: var(--log-ink-soft); text-decoration: none; }

        /* ---- searching the album ---------------------------------------------------- */
        #tripSectionSheet.is-log .mg2-searchbar {
            gap: var(--sp-sm);
            padding: 0 var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            background: var(--log-stock);
        }
        #tripSectionSheet.is-log .mg2-searchinput {
            min-height: 44px;
            font-family: var(--log-write);
            font-size: var(--fs-body);
            font-weight: 400;
            letter-spacing: 0;
            color: var(--log-ink);
            caret-color: var(--log-ink);
        }
        #tripSectionSheet.is-log .mg2-searchinput::placeholder { color: var(--log-ink-soft); opacity: 1; }
        /* The four ways to narrow it are words, like the album's own two, not boxes. */
        #tripSectionSheet.is-log .mg2-chips {
            gap: 0 var(--sp-lg);
            padding: 0 var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            background: var(--log-stock);
        }
        #tripSectionSheet.is-log .mg2-chip {
            min-height: 44px;
            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.16em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }
        #tripSectionSheet.is-log .mg2-chip.is-on {
            background: none;
            border: none;
            color: var(--log-ink);
            text-decoration: underline;
            text-underline-offset: 0.3em;
            text-decoration-thickness: 1px;
        }
        #tripSectionSheet.is-log #mg2SearchPanel { padding: 0 0 var(--sp-lg); }
        #tripSectionSheet.is-log #mg2SearchCols { padding: 0 var(--sp-md); }
        #tripSectionSheet.is-log .mg2-sugg-head,
        #tripSectionSheet.is-log .mg2-resulthead {
            padding: var(--sp-md) var(--sp-lg) var(--sp-xs);
            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);
        }
        #tripSectionSheet.is-log .mg2-sugg {
            min-height: 44px;
            padding: var(--sp-sm) var(--sp-lg);
            border-bottom: 1px solid var(--log-rule);
            background: none;
        }
        #tripSectionSheet.is-log .mg2-sugg:hover { background: var(--log-stock-band); }
        #tripSectionSheet.is-log .mg2-sugg-name { font-family: var(--log-write); font-size: var(--fs-body); color: var(--log-ink); }
        #tripSectionSheet.is-log .mg2-sugg-meta,
        #tripSectionSheet.is-log .mg2-sugg-n {
            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);
        }
        #tripSectionSheet.is-log .mg2-sugg-meta { margin-top: 2px; }
        #tripSectionSheet.is-log .mg2-clear {
            min-height: 44px;
            margin: var(--sp-sm) var(--sp-lg);
            padding: 0;
            border: none;
            background: none;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
            text-decoration: underline;
            text-underline-offset: 0.3em;
            text-decoration-thickness: 1px;
        }

        /* ⚠️ FOCUS ON A PHOTOGRAPH (finish review of the focus round, 2026-09-14). The app's role=button rule draws an inset
           box-shadow, which paints under the photograph that fills the tile: a keyboard moved through the album and nothing
           changed. An outline paints above it, and the album's gutters leave room for it outside. */
        #tripSectionSheet .mg2-tile:focus-visible {
            box-shadow: none;
            outline: 2px solid var(--log-ink);
            outline-offset: 2px;
        }
        /* The heart and the pin stand on the photograph itself, where ink can be 1:1. Focused, the chip is whole and ringed
           in paper and then ink, so one of the two reads on any picture. */
        #tripSectionSheet .mg2-fav:focus-visible,
        #tripSectionSheet .mg2-pin:focus-visible {
            opacity: 1;
            outline: 2px solid transparent;
            outline-offset: -2px;
        }
        #tripSectionSheet .mg2-fav:focus-visible::before,
        #tripSectionSheet .mg2-pin:focus-visible::before {
            box-shadow: 0 0 0 2px var(--log-stock), 0 0 0 4px var(--log-ink);
        }

        /* ══════════════════════════════════════════════════════════════
           MOVED OUT OF css/17zd-leftovers.css · 2026-09-21  (appended)
           2 rules. DESIGN.md: a surface's rules go in that surface's part, and the
           legacy parts only shrink.
           ⚠️ 17zd-leftovers.css loaded AFTER this file. This placement keeps
           their order against THIS PART’S OWN rules and nothing else: against the 5 part(s)
           between #41 and #47 the move reverses it. The banner used to claim they "keep that
           place" full stop, which was never true (review, 2026-09-22). Checked separately.
           ══════════════════════════════════════════════════════════════ */
        /* ---- a video with no still yet -----------------------------------------------------
           A marked tile, not a blank one — the word, where a play glyph on cream was. */
        #tripSectionSheet .mg2-vbare {
            display: flex;
            align-items: center;
            justify-content: center;
            aspect-ratio: 4 / 3;
            background: #B9C3C0;
        }

        #tripSectionSheet .mg2-vbare-word {
            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);
        }

        /* ══════════════════════════════════════════════════════════════
           MOVED OUT OF css/19-legacy-media.css · 2026-09-21  (appended)
           22 rules. DESIGN.md: a surface's rules go in that surface's part, and the
           legacy parts only shrink.
           ⚠️ 19-legacy-media.css loaded BEFORE this file. This placement keeps
           their order against THIS PART’S OWN rules and nothing else: against the 21 part(s)
           between #19 and #41 the move reverses it. The banner used to claim they "keep that
           place" full stop, which was never true (review, 2026-09-22). Checked separately.
           ══════════════════════════════════════════════════════════════ */
        /* ===== Media favourites & captions ===== */
        .mg2-tile { position: relative; }

        /* ⚠️ THE HEART IS THE ONE THING ON THE PHOTOGRAPH, AND IT CAN BE PRESSED (owner, 2026-09-13). It was a 24px button
           5px in from the corner; the mark still is, and the press is the whole 44px corner — the scrim is drawn
           behind the heart, not as the button's edge. */
        .mg2-fav {
            position: absolute;
            top: 0;
            right: 0;
            width: 44px;
            height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            color: var(--log-on-night-plate);
            cursor: pointer;
            opacity: 0.75;
        }

        .mg2-fav::before {
            content: '';
            position: absolute;
            top: 5px;
            right: 5px;
            width: 24px;
            height: 24px;
            background: rgba(22, 25, 26, 0.42);   /* the oilskin, not the outgoing #242424 (2026-09-17) */
        }

        .mg2-fav svg { position: absolute; top: 10.5px; right: 10.5px; }

        /* ⚠️ THE PIN, TOP LEFT (owner, 2026-09-13: pin看不出来 要不然把pin放左上角). Written under the photograph as ON YOUR WALL it
           could not be seen at a glance, and whether a photograph is on the wall is chosen while scanning, as a favourite is.
           The link mark that shared this corner and covered it is written under the photograph now, so the corner is the pin's
           alone. The same 24px mark and 44px press as the heart. */
        .mg2-pin {
            position: absolute;
            top: 0;
            left: 0;
            width: 44px;
            height: 44px;
            padding: 0;
            border: none;
            border-radius: 0;
            background: none;
            color: var(--log-on-night-plate);
            cursor: pointer;
            opacity: 0.75;
        }

        .mg2-pin::before {
            content: '';
            position: absolute;
            top: 5px;
            left: 5px;
            width: 24px;
            height: 24px;
            background: rgba(22, 25, 26, 0.42);   /* the oilskin, not the outgoing #242424 (2026-09-17) */
        }

        .mg2-pin svg { position: absolute; top: 10px; left: 10px; }

        .mg2-pin.is-pinned .mg2-pin-body { fill: currentColor; }

        .mg2-pin.is-hidden { display: none; }

        .mg2-pin:active { transform: scale(0.92); }

        /* .mg2-fav.is-fav's colour moved to the shared .fav-toggle rule at the end of
           this file — it was declared three times with the same value. */

        .mg2-fav:active { transform: scale(0.92); }

        /* ⚠️ LIT, A MARK IS A PAPER CHIP WITH ITS GLYPH IN COLOUR (owner, 2026-09-13: 我想要c 但是是品红magenta). Chosen from four
           drawn on a light sky, stone and dark foliage. Before, the two marks had two grammars: the pin a pale glyph on an
           ink square, the heart an ochre glyph on the same dark scrim as when off. Now both change the square itself, dark
           scrim to paper, so on and off differ in the largest thing about them. The pin is filled in the log's ink and the
           heart in its magenta. On a pale sky the paper is quieter than on stone or foliage; the filled glyph carries it.
           Three classes on the heart, because the shared .fav-toggle.is-fav ochre loads later, in 22. The full-screen
           viewer's heart is that shared rule and is still ochre. */
        .mg2-pin.is-pinned,
        .mg2-fav.fav-toggle.is-fav { opacity: 1; }

        .mg2-pin.is-pinned::before,
        .mg2-fav.fav-toggle.is-fav::before { background: #E8EDEB; }

        .mg2-pin.is-pinned { color: #43276B; }

        .mg2-fav.fav-toggle.is-fav { color: #A81E6E; }

        /* What is true of a photograph, under it, in two lines: a video and its length and whether it is on your wall in
           small capitals, then the activity it belongs to in the written hand. Each line is cut with an ellipsis rather
           than wrapped, so a long name does not make one tile taller than its neighbours for the sake of a label. It was
           one line on the first photograph of it, where the capitals came first and the activity was what got cut. */
        .mg2-state {
            padding: 6px 4px 0;
            line-height: 1.4;
        }

        .mg2-state[hidden] { display: none; }

        .mg2-state-words,
        .mg2-state-act {
            display: block;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .mg2-state-words {
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.12em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }

        .mg2-state-act { font-size: var(--fs-small); color: var(--log-ink-soft); }

        .mg2-state + .mg2-cap { padding-top: 2px; }


        .mg2-cap {
            /* 阶段三 ①（规格 04：「图注若有一律在图下」）：
               从绝对定位 + 渐变蒙版，改为图下的正常流。
               蒙版一并删除 —— 它的职能就是让压在图上的文字可读，文字走了它就没有职能（F2）。

               封顶两行：瀑布流的前提就是不等高，参差的底边是这种版面的正常样貌；
               但单格不该因为一条图注变成邻格的两倍高 —— 那时不等高就从节奏变成失衡。
               与规格给日记正文定「最大宽度约 34 个中文字符」同源：给文本一个上界，
               防它主导版面。两行在 12px 下约 24 个中文字。 */
            padding: 8px 4px 4px;
            font-size: var(--fs-small);
            color: var(--log-ink-soft);
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        /* ══════════════════════════════════════════════════════════════
           MOVED OUT OF css/20-legacy-calendar.css · 2026-09-21  (appended)
           1 rules. DESIGN.md: a surface's rules go in that surface's part, and the
           legacy parts only shrink.
           ⚠️ 20-legacy-calendar.css loaded AFTER this file. This placement keeps
           their order against THIS PART’S OWN rules and nothing else: against the 8 part(s)
           between #41 and #50 the move reverses it. The banner used to claim they "keep that
           place" full stop, which was never true (review, 2026-09-22). Checked separately.
           ══════════════════════════════════════════════════════════════ */
        /* Spacing is the column's `gap` now, so the tile's own margin would double it. */
        .mg2-tile {
            break-inside: auto;
            margin-bottom: 0;
        }

        /* ══════════════════════════════════════════════════════════════
           MOVED OUT OF css/22-diagnostics.css · 2026-09-21  (appended)
           17 rules. DESIGN.md: a surface's rules go in that surface's part, and the
           legacy parts only shrink.
           ⚠️ 22-diagnostics.css loaded AFTER this file. This placement keeps
           their order against THIS PART’S OWN rules and nothing else: against the 10 part(s)
           between #41 and #52 the move reverses it. The banner used to claim they "keep that
           place" full stop, which was never true (review, 2026-09-22). Checked separately.
           ══════════════════════════════════════════════════════════════ */
        /* ===== Gallery search ===== */
        .mg2-searchbar {
            flex: none;
            display: flex;
            align-items: center;
            gap: var(--sp-xs);
            padding: var(--sp-sm) var(--sp-md);
            border-bottom: 1px solid var(--log-rule);
            color: var(--log-ink-soft);
        }

        /* Underline-only, like every other field in this app — never a boxed input. */
        .mg2-searchinput {
            flex: 1;
            min-width: 0;
            padding: var(--sp-2xs) 0;
            border: none;
            background: transparent;
            font-family: var(--log-write);
            font-size: 15px;
            font-weight: var(--fw-light);
            letter-spacing: 0.05em;
            color: var(--log-ink);
        }


        .mg2-searchinput:focus { outline: none; }

        .mg2-searchinput::placeholder { color: var(--log-ink-soft); }

        /* The browser's own clear button on type=search is a blue circle on some
           platforms and cannot be restyled — it would be the one un-designed thing on
           the screen. Cancel already does the job. */
        .mg2-searchinput::-webkit-search-cancel-button { -webkit-appearance: none; }

        /* A magnifier and a Select label sit side by side; only the first of them should
           be pushed to the right. */

        .mg2-chips {
            flex: none;
            display: flex;
            gap: var(--sp-xs);
            padding: var(--sp-xs) var(--sp-md) var(--sp-sm);
            overflow-x: auto;
            border-bottom: 1px solid var(--log-rule);
        }


        .mg2-chip {
            flex: none;
            padding: 4px var(--sp-sm);
            border: 1px solid var(--log-rule-firm);
            background: transparent;
            cursor: pointer;
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
            transition: background 0.3s, color 0.3s, border-color 0.3s;
        }


        .mg2-chip.is-on {
            background: var(--log-ink);
            border-color: var(--log-ink);
            color: var(--log-on-oilskin);
        }


        .mg2-sugg-head {
            padding: var(--sp-md) var(--sp-md) var(--sp-xs);
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }


        .mg2-sugg {
            display: flex;
            align-items: baseline;
            gap: var(--sp-sm);
            width: 100%;
            padding: var(--sp-sm) var(--sp-md);
            border: none;
            border-bottom: 1px solid var(--log-rule);
            background: transparent;
            text-align: left;
            cursor: pointer;
            transition: background 0.3s;
        }


        .mg2-sugg:hover { background: var(--log-stock-band); }

        .mg2-sugg-main { flex: 1; min-width: 0; }


        .mg2-sugg-name {
            display: block;
            font-family: var(--log-write);
            font-size: 15px;
            color: var(--log-ink);
        }

        /* Dates get oldstyle figures, as dates do everywhere in this app. */

        .mg2-sugg-meta {
            display: block;
            margin-top: 0;
            font-family: var(--log-write);
            font-size: 13px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }


        .mg2-sugg-n {
            flex: none;
            font-family: var(--log-write);
            font-size: 13px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }


        .mg2-resulthead {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: var(--sp-md) var(--sp-md) var(--sp-xs);
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }


        .mg2-clear {
            margin: var(--sp-md);
            padding: var(--sp-xs) var(--sp-md);
            border: 1px solid var(--log-rule-firm);
            background: transparent;
            cursor: pointer;
            font-family: var(--log-write);
            font-size: 11px;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }
