        /* ==========================================================================
           #AC  The date picker — a month, in the deck log
           ==========================================================================

           Written 2026-09-11 with the Add-a-trip room, and it replaces flatpickr
           outright. The argument for writing one rather than dressing the library is in
           the head of public/15b-datepicker-log.js; the short version is that this app
           already draws a month — `.pcal-grid`, in css/17n-journal-list.css — and a
           second calendar, imported, styled to look like the first, is the exact drift
           this repository keeps writing down.

           ⚠️ SO WHY IS THE GRID NOT SHARED WITH `.pcal-*`? It was the first thing tried.
           They are the same PICTURE and not the same INSTRUMENT: a `.pcal-cell` is a
           report — it carries marks for what is planned that day and is sized by them
           (58px, three rows of two) — and a `.dp-cell` is a control, sized by the ruling
           and by what a thumb needs. Sharing them would have meant a component with two
           sizing modes and two meanings for `.has-text`, which is worse than two files
           that look alike. What IS shared is the lattice idea: 1px of --log-rule showing
           through a gap, the same as the month above the journal.

           ⚠️ AND IT IS ALIGNED BY HAND. #datePickerRoot is on <body> — .app-frame's
           desktop transform would capture position:fixed — so it is named in the token
           list at the head of css/02-auth.css and pushed back over the frame by
           alignOverlaysToFrame() in 03-map-plan.js. Both were done when this was written;
           neither is optional, and the first is the trap that has now swallowed seven
           surfaces. */

        /* The root is the frame-shaped window; the scrim inside it is absolute. Copied in
           structure from #confirmDialogRoot (css/18-overlays.css) because that is
           the one overlay in this app that has been proved right on desktop. */
        #datePickerRoot {
            position: fixed;
            top: 0;
            height: 100dvh;
            z-index: 12000;
            pointer-events: none;
        }

        .dp-overlay {
            position: absolute;
            inset: 0;
            pointer-events: auto;
            /* The oilskin at low pressure — the same wash the drawer's scrim and the
               confirm dialog's use. */
            background: rgba(22, 25, 26, 0.42);
            display: flex;
            align-items: center;
            justify-content: center;
            padding: var(--sp-lg);
            box-sizing: border-box;
            animation: fadeIn 0.18s ease;
        }
        @media (prefers-reduced-motion: reduce) {
            .dp-overlay { animation: none; }
        }

        /* ⚠️ A SMALL CARD IN THE MIDDLE, NOT A SHEET ACROSS THE PHONE (owner, 2026-09-13: time picker 和
           date picker 打开的层都太大了 可以小一些吗 看着比较精致 现在傻大傻大的). It rose from the foot at the
           full width of the frame, on the argument that an instrument you work wants to be where the
           thumb is; beside the choice card — a small, edged card in the middle — it read as a second,
           heavier way of asking. It is that card's size and shape now: no wider than 344px, edged all
           round, in the middle. Its rows are the 44px a press needs rather than a full ruling. */
        .dp-sheet {
            width: 100%;
            max-width: 344px;
            max-height: 100%;
            display: flex;
            flex-direction: column;
            box-sizing: border-box;
            background: var(--log-stock);
            border: 1px solid var(--log-rule-firm);
            border-radius: 0;
            box-shadow: none;
            animation: dpRise 0.2s ease;
        }
        @keyframes dpRise {
            from { transform: translateY(12px); }
            to { transform: translateY(0); }
        }
        @media (prefers-reduced-motion: reduce) {
            .dp-sheet { animation: none; }
        }

        /* ---- the head ---------------------------------------------------------- */

        /* One ruling tall, like every other head in this world — see --log-row. */
        .dp-head {
            flex: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-sm);
            min-height: 44px;
            padding: 0 var(--sp-md);
            background: var(--log-stock-band);
            border-bottom: 1px solid var(--log-rule-firm);
        }

        .dp-head > span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.16em;
            text-transform: uppercase;
            color: var(--log-ink);
        }

        /* ---- the words that are controls --------------------------------------- */

        /* PREVIOUS, NEXT, CLOSE and DONE are one thing wearing three weights. The
           chevrons flatpickr drew went the way every glyph in this world goes: a way
           somewhere is a word (see .jp-nav-btn in css/17m-journal.css, which this
           deliberately matches — it is the same gesture on the same kind of band). */
        .dp-close,
        .dp-step,
        .dp-done {
            display: inline-flex;
            align-items: center;
            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);
            flex: none;
        }

        /* Quieted rather than hidden, for the same reason the journal's PREVIOUS is: a
           control that vanishes moves everything beside it, and the quiet state is itself
           the information — there is no month that way. */
        .dp-close:disabled,
        .dp-step:disabled,
        .dp-done:disabled {
            color: var(--log-ink-soft);
            text-decoration: none;
            cursor: default;
        }

        /* ---- which month ------------------------------------------------------- */

        .dp-nav {
            flex: none;
            display: grid;
            grid-template-columns: 1fr auto 1fr;
            align-items: baseline;
            gap: var(--sp-sm);
            padding: 0 var(--sp-md);
            background: var(--log-stock);
            border-bottom: 1px solid var(--log-rule);
        }

        .dp-step.right { justify-self: end; }

        /* The month printed, not written — it is the sheet's own stamp on the page, the
           same voice as .jp-date. The year steps back because you change months far more
           often than you change years, and because it repeats down the whole grid. */
        .dp-month {
            font-family: var(--log-print);
            font-size: var(--fs-small);
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            color: var(--log-ink);
            white-space: nowrap;
            text-align: center;
        }
        .dp-month span {
            margin-left: var(--sp-xs);
            font-weight: 400;
            letter-spacing: 0.06em;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink-soft);
        }

        /* ---- the lattice ------------------------------------------------------- */

        .dp-dow {
            flex: none;
            display: grid;
            grid-template-columns: repeat(7, minmax(0, 1fr));
            gap: 1px;
            padding: var(--sp-xs) var(--sp-md) var(--sp-2xs);
            background: var(--log-stock);
        }

        .dp-dow > div {
            min-width: 0;
            text-align: center;
            font-family: var(--log-print);
            font-size: var(--fs-micro);
            font-weight: 600;
            letter-spacing: 0.10em;
            text-transform: uppercase;
            color: var(--log-ink-soft);
        }

        /* 1px of --log-rule showing through the gaps, exactly as .pcal-grid does it: the
           rule is the background and the cells are laid over it, so every line is one
           device-pixel and no two adjacent borders ever double up. */
        .dp-grid {
            flex: 0 1 auto;
            min-height: 0;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            display: grid;
            grid-template-columns: repeat(7, minmax(0, 1fr));
            gap: 1px;
            padding: 1px;
            margin: 0 var(--sp-md) var(--sp-sm);
            background: var(--log-rule);
        }

        /* Sized by the ruling. A month drawn at --log-row pitch is the same sheet as
           everything else in this world, and at 430 it lands at 53.7 against a 53px
           ruling — the grid and the stock agree without being made to. */
        .dp-cell {
            min-width: 0;
            height: 44px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            border: none;
            border-radius: 0;
            cursor: pointer;
            background: var(--log-stock);
            font-family: var(--log-print);
            font-size: var(--fs-body);
            font-weight: 500;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink);
        }

        /* The days that belong to the months on either side. Kept rather than blanked —
           a week that stops in the middle reads as missing data, and this world rules
           empty space rather than leaving it (Ruled-To-The-Foot). They are legible and
           they are plainly not this month. */
        .dp-cell.is-outside { color: var(--log-rule-firm); }

        /* Struck off, not faded out. A day outside the journey's bounds is --log-rule-firm
           with a quiet line through it — the log's own way of closing a line it will not
           write on — and it is deliberately the same weight as a day from a neighbouring
           month, because the reader only ever needs one answer from a quieted cell.

           ⚠️ IT WAS --log-rule, WHICH IS 1.77:1 AGAINST THE STOCK. Measured, not judged.
           That is the same fault the finish review found on the editor's remove control
           four days ago: a state that exists in the stylesheet and not on the glass. At
           --log-rule-firm it is 3.30:1 — plainly quieted, still legible, which is what a
           day you cannot choose should be. */
        .dp-cell.is-disabled,
        .dp-cell:disabled {
            color: var(--log-rule-firm);
            text-decoration: line-through;
            text-decoration-color: var(--log-rule);
            cursor: default;
        }

        /* Today is marked on the FIGURE, not on the cell — an underline under the number
           itself, the way a date is underscored in a written log.

           ⚠️ IT HAD THE CELL'S BOTTOM EDGE FIRST, and that was wrong for a reason worth
           keeping: the range needs the cell's own surface, so a 3px rule at the foot of a
           cell was a second thing living where the range lives. Photographed at 430 it read
           as a stray ruling under the 11th with no way to tell it from the grid's own
           lattice. Two marks on one cell need two different PLACES, not two thicknesses. */
        .dp-cell.is-today {
            text-decoration: underline;
            text-underline-offset: 0.25em;
            text-decoration-thickness: 2px;
        }

        /* ⚠️ THE RANGE IS ONE HUE AT TWO PRESSURES, and the between days are FILLED.

           The first attempt gave them --log-stock-band, on the argument that a day you did
           not press should be quieter than one you did. Photographed, the band (#CFD7D5)
           against the stock (#D9DFDD) was very nearly nothing: the range — the entire
           subject of a range picker — was invisible, and the two ends read as two unrelated
           selected days. A distinction that exists in the token list and not on the glass is
           not a distinction.

           So: the ends take --log-ink and the days between take --log-ink-soft. One ink, two
           pressures, which is exactly what that pair of tokens is for (One-Ink), and the
           gradation says the right thing — the ends are the days you pressed, the middle is
           what pressing them meant. Both carry --log-on-oilskin figures, the same figure/
           ground flip `.pcal-cell.has-text` uses for a day that carries writing. */
        .dp-cell.is-between {
            background: var(--log-ink-soft);
            color: var(--log-on-oilskin);
        }

        .dp-cell.is-chosen {
            background: var(--log-ink);
            color: var(--log-on-oilskin);
            font-weight: 600;
        }

        /* An underline in the ink is unreadable once the cell is the ink. */
        .dp-cell.is-today.is-chosen,
        .dp-cell.is-today.is-between {
            text-decoration-color: var(--log-on-oilskin);
        }

        .dp-cell:focus-visible {
            outline: none;
            box-shadow: inset 0 0 0 2px var(--log-ink);
        }
        .dp-cell.is-chosen:focus-visible {
            box-shadow: inset 0 0 0 2px var(--log-on-oilskin);
        }

        /* ---- what you have chosen, and the way out ----------------------------- */

        /* The sentence is the instrument's own reading of the grid — "6 – 10 Sep · 4
           nights" — and it is the one place the count of nights is stated before the
           journey is made. It is written, not printed: it is what the app has understood
           from what you did, not a label it stamped in advance. */
        .dp-foot {
            flex: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-md);
            min-height: 44px;
            padding: 0 var(--sp-md);
            background: var(--log-stock-band);
            border-top: 1px solid var(--log-rule-firm);
        }

        .dp-said {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            font-family: var(--log-write);
            font-size: var(--fs-body);
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink);
        }

        /* DONE is the act — it is the press that puts a date on the record — so it takes
           the magenta and CLOSE does not. One ink for one act per surface. */
        .dp-done { color: var(--log-magenta); }
        .dp-done:active { box-shadow: inset 0 -2px 0 0 var(--log-magenta); }
        .dp-done:disabled { color: var(--log-ink-soft); }

        /* ---- the time: three columns of ruled figures ------------------------------ */
        /* The hour, the minute and the half of the day, in the grid's own printed figures and
           its own chosen state — the ink, with the figure turned out of it. Five rulings tall,
           each column scrolling inside itself. */
        /* The time card is narrower than the month's. It holds two columns of two-figure numbers (three on
           a 12-hour phone), and at the month's 344px each column was a 170px band around "05" — the same
           oversized look the owner asked to be rid of, on a smaller card. */
        .dp-sheet.tm-sheet { max-width: 260px; }
        .tm-cols {
            flex: 1 1 auto;
            min-height: 0;
            display: grid;
            grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
            background: var(--log-stock);
        }
        .tm-cols.is-twelve { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.8fr); }
        .tm-col {
            max-height: calc(5 * 44px);
            overflow-y: auto;
            overscroll-behavior: contain;
            border-right: 1px solid var(--log-rule);
        }
        .tm-col:last-child { border-right: none; }
        .tm-opt {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 44px;
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            border: none;
            border-bottom: 1px solid var(--log-rule);
            border-radius: 0;
            background: var(--log-stock);
            cursor: pointer;
            font-family: var(--log-print);
            font-size: var(--fs-body);
            font-weight: 500;
            letter-spacing: 0.04em;
            font-variant-numeric: lining-nums tabular-nums;
            color: var(--log-ink);
        }
        .tm-opt.is-chosen {
            background: var(--log-ink);
            color: var(--log-on-oilskin);
            font-weight: 600;
        }
        .tm-opt:focus-visible { outline: 2px solid transparent; outline-offset: -2px; box-shadow: inset 0 0 0 2px var(--log-ink); }
        .tm-opt.is-chosen:focus-visible { box-shadow: inset 0 0 0 2px var(--log-on-oilskin); }

        /* ---- the field that opens it ------------------------------------------- */

        /* Every date field in the app becomes this: a readonly line you press. Readonly
           and not disabled — it must stay focusable, be read out, and be reachable by
           keyboard — and the caret is suppressed because there is nothing to type.

           ⚠️ THE NATIVE PICKER HAS TO BE TAKEN OFF THE INPUT, not hidden. An
           `input[type="date"]` carries the operating system's own calendar and would open
           it alongside this one; 15b-datepicker-log.js sets `type="text"` for that reason,
           which is the one thing the flatpickr wiring it replaces also had to do. */
        .dp-field {
            caret-color: transparent;
            cursor: pointer;
        }
