        /* ==========================================================================
           #L  Notifications — what came in while you were away
           --------------------------------------------------------------------------
           Brought into the deck log on 2026-09-07, at the same time as it was wired to
           the server for the first time. Drawn by public/29-notifications.js.

           On the number: the deck-log band is 11–17 and every number in it is taken —
           14 went to the bottom bar the same day the Almanac freed it. A letter keeps
           this part inside the band, where the cascade wants it (after the tokens, before
           the outgoing world's overlays), without renumbering seven files and their links
           to make room. If the band is ever renumbered, this joins the sequence.

           It is a room off Home: sticky head with Back, no bottom bar.
           ========================================================================== */
        #notificationsPage {
            background: var(--log-stock);
        }

        #notificationsPage.active {
            display: flex;
            flex-direction: column;
        }

        /* The Rooms-off-Home head, the same measure and the same 1fr auto 1fr as the
           Shelf's and the Wall's. */
        /* The head, its title and Back are the room head (.room-bar, css/11-home.css, since
           2026-09-16). What is this room's own: the whole page scrolls, so the head holds its
           place by sticking rather than by sitting outside a scroller. */
        #notificationsPage .nt-bar {
            position: sticky;
            top: 0;
            z-index: 2;
        }

        /* The page's acts — Mark all read in the head, Try again below — in Back's word. */
        #notificationsPage .nt-act {
            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;
            background: none;
            border: none;
            padding: 0;
            cursor: pointer;
            min-height: 44px;
            display: inline-flex;
            align-items: center;
        }

        /* An act is an underlined word; whether it is magenta depends on what it does.
           Ink by default — Try again re-reads the page and changes nothing. */
        #notificationsPage .nt-act {
            color: var(--log-ink);
        }

        /* Magenta only in the head, where the act is Mark all read, which does change the
           record. It is the one magenta on this page: opening a notice marks it read too,
           but there the act is opening, and a row is not dressed as a control. */
        #notificationsPage .nt-bar .nt-act {
            justify-self: end;
            color: var(--log-magenta);
            text-align: right;
        }

        #notificationsPage .nt-sheet {
            flex: 1;
            min-height: 0;
            display: flex;
            flex-direction: column;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
        }

        /* One notice is one ruled row: the type in the margin column on the line's own
           baseline, the line in the entry cell, the time under it. The column rule between
           them is firm — it carries meaning — and the rule between rows is the hairline. */
        #notificationsPage .nt-row {
            display: grid;
            /* Both rows are declared so `grid-row: 1 / -1` on the label spans the whole
               row. Left implicit, `-1` is the explicit grid's last line — line two — and
               the label spans one row while the time falls into the margin column beneath
               it, which is the caption-above-a-field the Margin-Column Rule forbids, only
               upside down. */
            grid-template-columns: 6.5rem 1fr;
            /* Three declared rows: the line, the time, and the row's tail — its actions while
               it can be answered, its stamp once it has been. A row with no tail leaves the
               third at zero height. The row is a plain div, not a control: it holds buttons,
               and a button inside a button is not markup. The door out of it is the person's
               name. */
            grid-template-rows: auto auto auto;
            align-items: start;
            width: 100%;
            min-height: var(--log-row);
            padding: 0;
            text-align: left;
            border-bottom: 1px solid var(--log-rule);
        }

        #notificationsPage .nt-label {
            grid-column: 1;
            grid-row: 1 / -1;
            align-self: stretch;
            border-right: 1px solid var(--log-rule-firm);
            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);
            padding: var(--sp-sm) var(--sp-sm) var(--sp-sm) var(--sp-lg);
        }

        #notificationsPage .nt-line {
            grid-column: 2;
            grid-row: 1;
            font-family: var(--log-write);
            font-size: var(--fs-body);
            line-height: 1.4;
            color: var(--log-ink-soft);
            padding: var(--sp-sm) var(--sp-lg) 0 var(--sp-sm);
        }

        /* The name, inside the sentence, is the way to that person — an underlined word in
           the written voice, not the printed one: it is part of what was written, not a
           label the form stamped. */
        #notificationsPage .nt-who {
            font: inherit;
            color: inherit;
            background: none;
            border: none;
            padding: 0;
            cursor: pointer;
            text-decoration: underline;
            text-underline-offset: 0.2em;
            text-decoration-thickness: 1px;
        }

        #notificationsPage .nt-tail {
            grid-column: 2;
            grid-row: 3;
            display: flex;
            align-items: center;
            gap: var(--sp-md);
            padding: 0 var(--sp-lg) var(--sp-2xs) var(--sp-sm);
        }

        /* 44px, and the tightness comes out of the tail's padding instead.
           This overrode the floor at thirty-two — on Accept and Decline, the two most
           consequential targets on the page and the only two that change another person's
           record. The head's acts kept their forty-four; the row's, where it matters most,
           did not. Found by the finish review, 2026-09-08. */

        /* The stamp is content and takes no target size, but it can hold focus after an
           answer, so it has to be able to show that it does. */
        #notificationsPage .nt-stamp:focus-visible {
            outline: 2px solid var(--log-ink);
            outline-offset: 2px;
        }

        /* Accept changes the record — this one's and the other traveller's — so it is the
           magenta. Decline changes it too, but what it writes is a refusal, and refusal in
           this world is said quietly rather than in the annotation colour. */
        #notificationsPage .nt-row .nt-act.is-mark { color: var(--log-magenta); }

        /* The Stamped-State Rule: what became of the record is a word in a hairline box at
           the row's right, in print micro caps, and it is content — there is nothing left to
           press. */
        #notificationsPage .nt-stamp {
            margin-left: auto;
            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);
            border: 1px solid var(--log-rule);
            padding: 2px var(--sp-xs);
        }

        #notificationsPage .nt-when {
            grid-column: 2;
            grid-row: 2;
            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);
            padding: 2px var(--sp-lg) var(--sp-sm) var(--sp-sm);
        }

        /* Unread is the one ink at full pressure — the same device the bottom bar uses for
           the destination you are on. It is said twice, in colour and in weight, because a
           state carried by colour alone is a state some readers do not receive. */
        #notificationsPage .nt-row.is-unread .nt-label,
        #notificationsPage .nt-row.is-unread .nt-line {
            color: var(--log-ink);
        }
        #notificationsPage .nt-row.is-unread .nt-line { font-weight: 600; }

        /* The Ruled-To-The-Foot Rule: the rest of the sheet keeps the ruling at the pitch,
           and the margin column runs on through it. Two background layers, the horizontal
           rules and the one vertical, so the empty part of the sheet is the same instrument
           as the written part. */
        #notificationsPage .nt-rule-out {
            flex: 1;
            min-height: calc(var(--log-row) * 2);
            background-image:
                /* 6.5rem exactly: the row carries no padding of its own, so the column
                   rule stands at the margin column's own width. The label's --sp-lg is
                   inside that column, not before it. */
                linear-gradient(to right,
                    transparent 0,
                    transparent calc(6.5rem - 1px),
                    var(--log-rule-firm) calc(6.5rem - 1px),
                    var(--log-rule-firm) 6.5rem,
                    transparent 6.5rem),
                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));
        }

        /* Waiting, failed and empty all speak in the written voice above the ruling, the
           way the other surfaces' quiet lines do. */
        #notificationsPage .nt-quiet {
            margin: 0;
            padding: var(--sp-2xl) var(--sp-lg);
            font-family: var(--log-write);
            font-size: var(--fs-body);
            line-height: 1.5;
            color: var(--log-ink);
        }

        #notificationsPage .nt-quiet span {
            display: block;
            margin-top: var(--sp-sm);
            font-size: var(--fs-small);
            color: var(--log-ink-soft);
        }

        #notificationsPage .nt-quiet.is-reading { animation: wall-breathe 1.8s ease-in-out infinite; }

        #notificationsPage :focus-visible {
            outline: 2px solid var(--log-ink);
            outline-offset: 2px;
        }

        /* The bell, on Home's night plate, says whether anything is waiting — and it says it
           as a stamp: the chart magenta filled behind the bell, which is knocked out of it in
           the plate's own light ink.

           It began as a 2px rule in that light ink and was not loud enough (owner,
           2026-09-07), who asked for Plan a trip's colour. Drawn the same way — magenta as a
           line on the plate — it measures **2.74:1**, under the 3:1 a non-text mark has to
           clear: `--log-magenta` was darkened to pass on the pale stock and had never been
           measured on a dark ground, which is exactly the case the Two-Grounds Rule is
           written for. Filled instead, the reading is done by the bell at **5.77:1** against
           the magenta — `--log-on-oilskin`, this world's ink for a mark on a dark block,
           rather than the outgoing world's `--on-dark` the bell otherwise wears — and the
           colour is still the colour that was asked for.

           The shape is borrowed on purpose: the stamp is what Add a Trip is, so between them
           the two say the same thing in the two grounds — a block of colour with the mark
           knocked out. Not a dot, because a state here is not a glyph; not amber, which the
           Lantern Rule keeps for the plate's visited countries.

           It lives in this part rather than Home's because the state is this surface's: the
           class is set by markBellUnread() in 29-notifications.js. */
        #mainPage .hero-corner-right.has-notices {
            background: var(--log-magenta);
            color: var(--log-on-oilskin);
        }
