/* Global notification bell (in-app feed). Owned by mail-service, loaded on
   every page via global_assets. Kept out of the page-scoped mail-service.css
   so it never bleeds onto the mail admin pages and vice versa. Visual language
   is the ai-cloud theme; this is the former chat bell rebuilt under a neutral
   mp-notif-* namespace. */

:root {
    /* Global notification bell, owned by mail-service. Since core 1.12.30 the bell is a
       CHILD of the shell's sticky app bar (rendered into its appbar_right hook), so it no
       longer positions itself at all: the bar's tail slot places it, and the bar's own
       sticky/scroll/alignment rules apply to it for free. Everything that used to make
       that work by hand is gone — the viewport-corner inset (--mp-notif-edge), the
       .page-header-actions reservation (--mp-notif-slot) that kept a page's Add button
       from being covered, and the separate mobile pinning into the top app bar. The bell
       is now sized here and placed there. */
    --mp-notif-size: 32px;

    /* The unread chip, sized FROM the bell so the two cannot drift apart. It is a chip inside
       the button, not a badge hanging off its corner: --mp-notif-chip-inset is measured from
       the PADDING box, so the 1px border puts it 6px from the button's outer edge — the same
       6px the vertical centring gives it, which is what makes the corner well square. */
    --mp-notif-chip: 20px;
    --mp-notif-chip-inset: 5px;
    /* THE PANEL DOCKS ONTO THE BELL. Since v1.12.530 the flyout no longer hangs 12px under the
       bar; its head IS the row the bell sits in, and this is the margin between the bell and the
       panel's top-right corner. The head's height and its right-hand reservation are derived from
       it and --mp-notif-size, so the bell is centred in the row by construction, not by a number
       that has to be re-tuned when either changes. */
    --mp-notif-head-pad: 7px;
}

.mp-notifications {
    --mp-bell-icon: var(--mp-icon-bell-solid);
    /* THE TWO BELLS ARE NOT THE SAME SIZE, and one box cannot serve both. Measured at a 16px
       box: the outline paints 13.30 x 14.65 of ink, the solid 10.20 x 12.80 — 13% shorter and
       23% narrower, because 'bell-solid' is simply drawn smaller inside the same 0 0 24 24
       viewBox. `contain` fits the VIEWBOX, not the ink, so it cannot correct for that.

       Corrected here rather than in the icon registry on purpose: bell-solid has exactly one
       consumer in the tree — this mask — and the registry has no ink-extent convention to hold
       it to (its solid glyphs range from 14 to 20 units wide). Renormalising one glyph would be
       fixing a named instance inside the registry while changing what every future consumer
       gets. The defect is optical PARITY between the two glyphs this button swaps between, which
       is a property of the button, so it is answered beside the swap that causes it. */
    --mp-bell-glyph: 17.5px;
    --mp-notif-grad: linear-gradient(135deg, #00ea5e, #38bdf8);
    --mp-notif-glyph: #06111d;
    /* Relative, not absolute: the containing block for the flyout, nothing more. */
    position: relative;
    display: flex;
    align-items: center;
    z-index: 120;
}

.mp-notifications.is-open {
    z-index: 150;
}

/* Scheme-aware bell glyph: the filled 'bell-solid' reads bolder on the brand
   gradient in dark mode (the default); light mode uses the lighter outline 'bell'.
   Both keys ship in the icon registry (icons.css); mask swap only. */
html[data-mp-scheme="light"] .mp-notifications {
    --mp-bell-icon: var(--mp-icon-bell);
    --mp-bell-glyph: 16px;
}

.mp-notif-bell {
    /* ONE BOX. The containing block is for a chip that sits INSIDE this button — the previous
       count was absolutely positioned OUTSIDE it, at right:-4px/top:-4px, which is what made
       it need a ring punched around itself. Same property, opposite geometry. */
    position: relative;
    display: grid;
    place-items: center;
    width: var(--mp-notif-size);
    min-width: var(--mp-notif-size);
    height: var(--mp-notif-size);
    padding: 0px;
    border: 1px solid var(--mp-fill-18,rgba(255, 255, 255, 0.18));
    border-radius: var(--radius, 5px);
    background: var(--mp-notif-grad);
    color: var(--mp-notif-glyph);
    box-shadow: var(--mp-sh-34,rgba(0, 0, 0, 0.34)) 0px 18px 46px, var(--mp-sky-22,rgba(14, 165, 233, 0.22)) 0px 8px 22px -8px, var(--mp-fill-25,rgba(255, 255, 255, 0.25)) 0px 1px 0px inset;
    font: inherit;
    cursor: pointer;
    /* width is in the transition because the bell is in the app bar's right rail: when a
       notification lands, everything to its left moves 32px. Animated it reads as the bell
       opening; unanimated it is the rail jumping under a pointer already on its way to a
       control. The FIRST paint does not animate — the count is server-rendered, so a page
       with unread notifications loads wide rather than widening. */
    transition: width 0.18s ease, transform 0.16s, border-color 0.16s, box-shadow 0.16s, filter 0.16s;
}

/* UNREAD: the bell doubles and the count sits INSIDE it, on the same gradient.

   Selected off the count's own `hidden` attribute rather than a state class, because that
   attribute is already the one state token both writers share — views/notification-bell.php
   emits it from the server-rendered count and notifications.js toggles it on every poll. A
   second token would be a second thing to keep in step, and the failure mode of that is a
   bell that is twice as wide with nothing in it.

   The second column is minmax(0,1fr) so it can never claim more than the half it was given;
   the chip is justified to its end, which puts it in the corner well the inset defines. */
.mp-notif-bell:has(.mp-notif-bell-count:not([hidden])) {
    /* One box with room made on its right, and the chip sits in that room — not two cells.

       THE WIDTH FOLLOWS THE COMPOSITION, it is not a slogan. It was calc(--mp-notif-size * 2)
       for two releases because 'twice as wide' is how the change was described, and that extra
       width had nowhere to go: the interior read 7 | 18 | 13 | 20 | 6 — margin, glyph, GAP,
       chip, inset — so the space between the bell and the chip was nearly twice either outer
       margin. v1.12.385 tried to spend the slack on the left margin, which tightened the gap
       and pushed the glyph 3.25px off its resting centre. The slack should not have been spent;
       it should not have been there.

       60px removes it. Every outer space in the control is then the SAME 6px — glyph to the left
       edge, chip to the right edge, chip to top and bottom — and the interior reads
       6 | 18 | 10 | 20 | 6. The chip's 6px is not a choice: it is what centring a 20px chip in a
       32px button gives on the vertical, so matching it on the other three is what makes the
       control one rhythm instead of four values.

       This is also, to within half a pixel on every dimension, the mockup this was built from:
       it measured 59.96px wide, glyph centre 15.43, chip 34.26 to 53.49, right inset 6.30.
       Against 60 / 15 / 34 / 54 / 6 here. The mockup was right about the proportion and the
       phrase 'twice as wide' was the approximation.

       The padding is what carves the right half out; the glyph stays centred in the content box
       that is left (28px, so its centre sits at 15 rather than the resting 16 — one pixel, and
       the width transition carries it). Asserted as COMPOSITION in
       notification_bell_layout_test.js — outer spaces equal, gap in their rhythm, width equal to
       the sum of its parts — so none of these numbers is pinned in a test.

       ═══ AND THE PADDING SAID 25px WHILE EVERY LINE ABOVE SAID 30px ═══

       Everything written above is what this rule was designed to produce, and for three releases
       it produced something else. The 60px width landed; the padding that divides it did not
       follow. At 25px the content box is 33px rather than the 28px this comment describes, so
       centring the glyph in it puts the left space at 8.5px against 6px on the other three sides,
       and the bell-to-chip gap collapses to 7.5px — BELOW the outer space, at 0.88x. The paragraph
       above names 0.95x as the failure it was written to prevent. This was worse, and it was in
       the shipped bytes.

       It stayed there because the browser-real suites run under their own button: 44 of 46 green,
       and the two that were not never appeared in a PHP report. Measured after the correction:
       6.00 / 6.00 / 6.00 / 6.00 outer spaces and a 1.67x gap — the numbers this comment has
       claimed all along. The prose was right; the value drifted away from it. */
    width: 60px;
    min-width: 60px;
    padding-inline-end: 30px;
}

.mp-notif-bell:hover, .mp-notif-bell:focus-visible {
    outline: 0px;
    transform: translateY(-1px);
    border-color: var(--mp-fill-34,rgba(255, 255, 255, 0.34));
    filter: brightness(1.06) saturate(1.04);
    box-shadow: var(--mp-sh-38,rgba(0, 0, 0, 0.38)) 0px 22px 56px, var(--mp-accent-30,rgba(56, 189, 248, 0.30)) 0px 0px 0px 3px, var(--mp-fill-28,rgba(255, 255, 255, 0.28)) 0px 1px 0px inset;
}

/* OPEN IS FLAT, NOT LIFTED. The bell now sits inside the panel's head row, so the hover lift
   (translateY, brightness, the 46px drop shadow) that used to say 'this control is active' would
   say 'this control is floating off the row it belongs to' — measured: the shadow alone painted a
   dark smear across the head. Only the inset highlight survives; focus-visible keeps its ring,
   because that is a keyboard user's cursor and not decoration. */
.mp-notifications.is-open .mp-notif-bell,
.mp-notifications.is-open .mp-notif-bell:hover {
    z-index: 2;
    transform: none;
    filter: none;
    border-color: var(--mp-fill-18,rgba(255, 255, 255, 0.18));
    box-shadow: var(--mp-fill-25,rgba(255, 255, 255, 0.25)) 0px 1px 0px inset;
}

.mp-notif-bell-icon {
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    border-radius: 999px;
    background: transparent;
    color: var(--mp-notif-glyph);
}

.mp-notif-bell-icon::before {
    content: "";
    width: var(--mp-bell-glyph, 16px);
    height: var(--mp-bell-glyph, 16px);
    mask: var(--mp-bell-icon) center/contain no-repeat;
    -webkit-mask: var(--mp-bell-icon) center/contain no-repeat;
    background: currentColor;
}

/* The count. Was a pill hanging off the button's top-right corner with a 2px ring in
   rgb(7,16,29) — the dark scheme's surface colour, hardcoded, so the ring that punched the
   badge out of its background could only ever be right in one of the two schemes this
   platform ships. Inside the button there is nothing to punch out of: the ring is gone, and
   the fill is the --red token, which each scheme already answers for itself.

   A rounded square on the button's own radius, not a pill: it reads as part of the control
   rather than as something stuck to it. tabular-nums so 11 and 35 are the same width and the
   chip does not twitch between polls. */
.mp-notif-bell-count {
    /* Out of flow, so it occupies the room the padding made rather than competing with the
       glyph for the content box. inset-block:0 + margin-block:auto centres it against a known
       height — deliberately not translateY(-50%), because a transform on anything the flyout
       sits under establishes a containing block, and this platform has already paid for that
       once with a position:fixed panel that stopped being fixed. */
    position: absolute;
    inset-inline-end: var(--mp-notif-chip-inset);
    inset-block: 0px;
    display: grid;
    place-items: center;
    min-width: var(--mp-notif-chip);
    height: var(--mp-notif-chip);
    margin-block: auto;
    margin-inline: 0px;
    /* 3px, not 4: the widest label the cap can produce is '99+', and this is what keeps its
       left edge clear of the bell glyph inside a button whose width is fixed at twice the
       resting size. Measured, not chosen — see notification_bell_layout_test.js. */
    padding: 0px 3px;
    border: 0px;
    border-radius: var(--radius, 5px);
    background: var(--red, #f43f5e);
    color: #fff;
    font-size:var(--mp-fs-2xs,10px);
    font-weight:var(--mp-fw-black,900);
    line-height:var(--mp-lh-none,1);
    font-variant-numeric: tabular-nums;
}

/* [hidden] outranks the class rule above on its own — the !important that sat here beat nothing
   but our own earlier declaration. Removed at v1.12.530; the resting-bell width in both Chromium
   suites is the measurement that the count still does not paint. */
.mp-notif-bell-count[hidden] {
    display: none;
}

/* THE PANEL NO LONGER SCROLLS; ITS LIST DOES.

   It used to be one overflowing box, so everything in it scrolled together. That was harmless
   while the feed was capped at twenty rows and became the wrong shape the moment it paged
   indefinitely: a head carrying Read all and Clear all would leave the screen on the way down,
   and the bulk actions would be reachable only by scrolling back up through the list you had
   come down to get away from.

   So: flex column, head at flex:0, .mp-notif-scroll at flex:1 with the overflow. overflow:hidden
   here is not decoration either — without it the rounded corners and the border are drawn over by
   the scrolling child at the top and bottom edges. */
.mp-notif-panel {
    position: absolute;
    /* Docked: the panel's top-right corner sits one head-pad outside the bell on both axes, so
       the bell — which never moves — lands exactly centred in the head row. Under the bell, not
       over it: the bell is the row's one control and paints on top (z-index 2 in .is-open).
       PLUS THE BORDER. The head starts inside the panel's 1px border, so an offset of the bare pad
       put the bell one pixel high and one pixel tight to the right edge — measured in
       notification_panel_docked_test.js before this line grew the extra pixel. The offset is to
       the padding box, which is the box the head is laid out in. */
    right: calc(-1 * (var(--mp-notif-head-pad) + 1px));
    top: calc(-1 * (var(--mp-notif-head-pad) + 1px));
    z-index: 1;
    display: flex;
    flex-direction: column;
    /* 400: the head carries the title, the count and the bell's reservation; the actions sit in
       the foot, so the 440 that v1.12.530 needed to keep them clear of the bell is not needed.
       The viewport clamp keeps the gutter the bar itself uses. */
    /* The clamp subtracts the same overshoot on both sides: the head pad plus the 1px border the
       dock offset above adds, so the panel's OUTER edge is 1px + pad past the bell on the right
       and lands the same distance from the screen edge on the left. */
    width: min(400px, calc(100vw - 2 * (var(--mp-content-pad, 42px) - var(--mp-notif-head-pad) - 1px)));
    /* Two ceilings, not one. 430px is the design height; the viewport clamp is what keeps the
       panel on screen on a short window, where a fixed 430 would push its last rows — and the
       sentinel that loads the next page — below the fold with no way to reach them. */
    max-height: min(430px, calc(100vh - 132px));
    overflow: hidden;
    border: 1px solid var(--mp-fill-10,rgba(255, 255, 255, 0.1));
    border-radius: var(--radius, 5px);
    box-shadow: var(--mp-sh-45,rgba(0, 0, 0, 0.45)) 0px 24px 70px, var(--mp-fill-04,rgba(255, 255, 255, 0.04)) 0px 1px 0px inset;
}

/* The UA sheet expresses [hidden] as display:none, which any author `display` outranks — so the
   line above would have made the closed panel visible. It is the panel's own open/closed state,
   not a detail: notifications.js toggles nothing else. */
.mp-notif-panel[hidden] {
    display: none;
}

.mp-notif-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    /* The row the bell lives in: tall enough for the bell plus its margin, and padded on the
       right by the bell's width plus its margin on both sides, so nothing in the head can ever
       be laid out under it. Both values are derived; the unread variant below only widens the
       reservation to the wide bell's 60px. NO RULE UNDER IT since v1.12.531: the actions live in
       the foot now, so there is nothing here to fence off from the list, and a line cut the
       title from the rows it names. */
    min-height: calc(var(--mp-notif-size) + 2 * var(--mp-notif-head-pad));
    padding: var(--mp-notif-head-pad) calc(var(--mp-notif-size) + 2 * var(--mp-notif-head-pad)) var(--mp-notif-head-pad) 12px;
    /* OPAQUE, unlike the list. The panel overlaps the app bar now, and whatever sits beside the
       bell there — a page's Add button — bled through the frosted glass as a coloured smear.
       --panel-solid is foundation's token for exactly this surface. */
    background: var(--panel-solid, #101828);
}

/* Same state token the bell itself widens on: the count's own `hidden` attribute. */
.mp-notifications:has(.mp-notif-bell-count:not([hidden])) .mp-notif-head {
    padding-inline-end: calc(60px + 2 * var(--mp-notif-head-pad));
}

.mp-notif-head strong {
    font-size:var(--mp-fs-sm,12px);
    font-weight:var(--mp-fw-heavy,800);
}

/* The uncapped unread total. The chip inside the bell says '99+' because it has to fit inside a
   button; this has a panel's width and no reason to lose the number. */
.mp-notif-headcount {
    white-space: nowrap;
    color: var(--muted, #94a3b8);
    font-size:var(--mp-fs-2xs,10px);
    font-weight:var(--mp-fw-bold,700);
    letter-spacing:var(--mp-ls-wide,0.04em);
    text-transform: uppercase;
}

/* THE FOOT. Outside the scroller like the head, at the other end: the two bulk actions sit under
   the list where a reader who has scrolled into it is. No rule above them and no paint of its own:
   it is the tail of the same glass the rows sit on, and the buttons carry their own surfaces.
   Hidden by notifications.js while the list is empty. */
.mp-notif-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 0 0 auto;
    padding: 0 var(--mp-notif-head-pad) var(--mp-notif-head-pad);
}

.mp-notif-foot[hidden] {
    display: none;
}

/* Placement only. The two actions inside are registry buttons and bring their own paint. */
.mp-notif-foot-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* The one scrolling box in the panel. min-height:0 is load-bearing: a flex child defaults to
   min-height:auto, which refuses to shrink below its content, so without it this grows to the
   full list height and the panel's max-height is enforced by clipping instead of scrolling.
   overscroll-behavior keeps a flick at the end of the list from scrolling the page behind it. */
/* THE GLASS IS ON THE BODY, NOT THE PANEL. Docked, the panel's head lies over the app bar, and a
   backdrop-filter on the whole panel samples what is under the head too — the page's Add button,
   blurred 18px down into the first row as a coloured smear, with the opaque head hiding the
   button and not the blur. Measured in Chromium at v1.12.530. The body wraps the scroller AND the
   foot (v1.12.532) so both sit under one frosted layer: with the filter on the scroller alone the
   foot was the panel's bare translucent background, visibly more see-through than the rows above
   it, and a second filter on the foot would have met the first at a seam. */
.mp-notif-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    backdrop-filter: blur(18px);
}

.mp-notif-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    overscroll-behavior: contain;
}

.mp-notif-list {
    padding: 6px;
}

.mp-notif-row {
    position: relative;
    display: grid;
    /* auto, not a fixed 28px: buttons.css grows an xs icon button to a 40px square on coarse
       pointers, and a fixed column would have it overflow the row on every touch device. */
    grid-template-columns: minmax(0px, 1fr) auto;
    align-items: stretch;
    border-radius: var(--radius, 5px);
}

.mp-notif-row:hover, .mp-notif-row:focus-within {
    background: var(--mp-fill-055,rgba(255, 255, 255, 0.055));
}

.mp-notif-item {
    display: block;
    width: 100%;
    padding: 10px;
    border: 0px;
    border-radius: var(--radius, 5px);
    background: none;
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: 0.12s;
}

.mp-notif-row .mp-notif-item:hover, .mp-notif-row .mp-notif-item:focus-visible {
    outline: 0px;
    background: none;
}

.mp-notif-item strong {
    display: flex;
    align-items: center;
    gap: 7px;
    color: var(--text, #f8fafc);
    font-size:var(--mp-fs-sm,12px);
    font-weight:var(--mp-fw-heavy,800);
    line-height:var(--mp-lh-snug,1.25);
}

.mp-notif-item span {
    display: block;
    margin-top: 4px;
    color: var(--muted, #94a3b8);
    font-size:var(--mp-fs-xs,11px);
    line-height:var(--mp-lh-normal,1.4);
}

.mp-notif-row.is-unread .mp-notif-item strong::after {
    content: "";
    width: 7px;
    height: 7px;
    flex: 0 0 7px;
    border-radius: 50%;
    background: var(--green, #00EA5E);
    box-shadow: var(--mp-hl-12,rgba(0, 234, 94, 0.12)) 0px 0px 0px 3px;
}

/* THE DISMISS IS A REGISTRY BUTTON NOW — btn--tertiary + btn--icon + btn--xs, built by
   window.mpButton, the same shape attachments.js uses for its row actions. What it replaces was a
   bespoke 24px circle that drew a literal '\00d7' as text, which put one glyph of the icon
   vocabulary outside the icon registry and meant none of the registry's size or shape modifiers
   reached it (every rule in buttons.css is scoped .btn.btn--*, so btn--xs on a non-.btn element is
   a no-op).

   Everything below is PLACEMENT plus one thing the registry has no opinion about: a row action
   should be quiet until the row is under the pointer. opacity is not a property any button token
   declares, so this composes onto the variant rather than repainting it. */
.mp-notif-delete {
    place-self: start end;
    margin: 7px 6px 0px 0px;
    opacity: 0.5;
    transition: opacity 0.12s ease;
}

.mp-notif-row:hover .mp-notif-delete,
.mp-notif-row:focus-within .mp-notif-delete,
.mp-notif-delete:focus-visible {
    opacity: 1;
}

/* When it happened. Not decoration once the list pages backwards: without it everything past the
   first screen is undated, and a notification from March reads exactly like one from this
   morning. Quieter than the body it sits under, so it reads as metadata rather than content. */
.mp-notif-when {
    display: block;
    margin-top: 5px;
    color: var(--mp-ink-faint, #64748b);
    font-size:var(--mp-fs-2xs,10px);
    font-weight:var(--mp-fw-bold,700);
    letter-spacing:var(--mp-ls-wide,0.04em);
}

/* The paging sentinel, which doubles as its own status line. It needs real height for an
   IntersectionObserver to have anything to intersect, and it is hidden — not merely emptied —
   when no page is left, because a display:none target never intersects and that is precisely how
   the observer is told to stop asking. */
.mp-notif-more {
    min-height: 10px;
    padding: 8px 12px 12px;
    text-align: center;
    color: var(--muted, #94a3b8);
    font-size:var(--mp-fs-xs,11px);
}

.mp-notif-empty {
    padding: 12px;
    text-align: center;
    color: var(--muted, #94a3b8);
    font-size:var(--mp-fs-sm,12px);
}

@media (max-width: 1000px) {
    /* The bell rides the app bar on mobile exactly as it does on desktop — it is the same
       slot, in the same bar, which is itself sticky under the mobile top bar. Only the
       flyout changes: pinned to the viewport so it cannot overflow a narrow screen. */
    body.mobile-menu-open .mp-notifications {
        display: none;
    }

    /* Still docked, not pinned. Until v1.12.530 the flyout went position:fixed here so it could
       not overflow a narrow screen; the docked geometry needs no pin — the width clamp already
       reads the bar's own gutter (--mp-content-pad, 16px here), which puts the panel 9px off
       both screen edges with the bell 7px inside its corner. Only the ceiling changes: measured
       from the bar's top rather than a fixed pin. */
    .mp-notif-panel {
        max-height: calc(100vh - 96px);
    }
}
