/* =========================================================================
   Notifications — the settings-hub "Notifications" page (a reader's own
   alerts, then the organization's read-only half) and the "Slack channels"
   admin page, plus the header bell + unread badge.

   Twins the Profile/Locations/Skills pages: SAME tokens and fallbacks as
   profile.css (--color-action / --surface-raised / --bs-border-color /
   --text-muted, 0.75rem card / 0.5rem control radii, color-mix ink tints) so this page
   rhymes with every other page in the hub. Every rule is namespaced under
   .notifications-* so nothing here can cancel — or be cancelled by — the app's global
   .card / .form-control / .table styles.

   The header bell is the ONE exception: it lives on the dark brand bar, so it
   opts into the shared --header-control-* liquid-glass palette (main.css) the
   same way every other header control does.
   ========================================================================= */

/* The bell <button> also carries .global-header-btn.global-header-btn-icon, so the
   .global-app-header .global-header-btn rules paint it with the white-veil liquid-glass
   treatment (translucent fill, white glyph, hairline border, brightening on
   hover). Here we only add the badge anchor + the unread pill. */
.notifications-bell {
    display: inline-flex;
    align-items: center;
}

.notifications-bell-link {
    position: relative;          /* anchor for the absolutely-placed badge */
}

/* Unread dot — there is something, not how much. A red dot with a ring in
   the bar's own colour, hidden by Alpine (x-show) until a non-zero count
   arrives; the count itself only ever reaches the button's aria-label. */
.notifications-bell-badge {
    position: absolute;
    top: -2px;
    right: -2px;
    width: 9px;
    height: 9px;
    background: var(--color-error);
    border: 1.5px solid var(--color-action);
    border-radius: var(--radius-pill);
    pointer-events: none;
}

/* The outer box is now a Bootstrap offcanvas (.offcanvas.offcanvas-end
   .global-drawer-offcanvas, set in the template) — that shared skin owns position,
   width, height, and the below-the-header top offset, the same idiom every
   other offcanvas drawer in the app uses. .notifications-drawer itself carries no
   box CSS anymore; it stays as a plain, stable hook for the content rules
   below (list/item), all unchanged from the old dropdown box.

   The head row and its X are the shared .global-drawer-head / .global-drawer-head__title /
   .global-drawer-close (components/drawer.css); only the extra tools beside the X —
   mark-all-read and the settings gear — are this drawer's own. */

.notifications-drawer__tools {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.notifications-drawer__mark {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    color: var(--color-action);
    background: none;
    border: none;
    padding: var(--spacing-2xs) var(--spacing-xs);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.notifications-drawer__mark:hover {
    background: color-mix(in srgb, var(--color-action) 10%, transparent);
}

.notifications-drawer__gear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    color: var(--color-text-muted);
    border-radius: var(--radius-sm);
}

.notifications-drawer__gear:hover {
    color: var(--color-text);
    background: var(--color-surface-hover);
}

/* Fills the rest of the offcanvas panel below the head and scrolls on its
   own (the panel itself no longer scrolls — see .global-drawer-offcanvas). */
.notifications-drawer__list {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.notifications-drawer__state {
    padding: var(--spacing-xl) var(--spacing-md);
    text-align: center;
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    margin: 0;
}

/* One notification row — a full-width link so the whole strip is clickable
   and keyboard-reachable. A row that points somewhere is a real anchor; the
   rest still click to mark read. color/underline are reset so the anchor reads
   like the rest of the text. Unread rows carry a tinted wash and a dot. */
.notifications-item {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-sm);
    width: 100%;
    text-align: left;
    padding: var(--spacing-smd) var(--spacing-md);
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.12s ease;
}

.notifications-item:last-child {
    border-bottom: none;
}

.notifications-item:hover {
    background: var(--color-surface-hover);
}

.notifications-item.is-unread {
    background: color-mix(in srgb, var(--color-action) 5%, transparent);
}

.notifications-item__dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    margin-top: var(--spacing-xsm);
    border-radius: 50%;
    background: var(--color-action);
}

/* Reserve the dot's width on read rows so titles stay aligned. */
.notifications-item:not(.is-unread) .notifications-item__main {
    padding-left: calc(8px + 0.6rem);
}

.notifications-item__main {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
    min-width: 0;
}

.notifications-item__title {
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    line-height: 1.35;
}

.notifications-item__text {
    font-size: var(--font-size-sm);
    color: var(--color-grey-600);
    line-height: 1.35;
}

.notifications-item__time {
    font-size: var(--font-size-2xs);
    color: var(--color-text-muted);
    margin-top: var(--spacing-2xs);
}

/* A group row — one line standing in for a run of same-type notifications,
   e.g. "16 new bills". Reuses the .notifications-item frame, then adds a count pill
   and a chevron on the right. Clicking it expands the run in place. */
.notifications-group {
    align-items: center;
}

.notifications-group__badge {
    flex-shrink: 0;
    margin-left: auto;
    padding: 0.05rem var(--spacing-sm);
    font-size: var(--font-size-2xs);
    font-weight: 700;
    line-height: 1.4;
    color: var(--color-action);
    background: color-mix(in srgb, var(--color-action) 12%, transparent);
    border-radius: var(--radius-pill);
}

.notifications-group__chev {
    flex-shrink: 0;
    font-size: var(--font-size-2xs);
    color: var(--color-text-muted);
}

/* The individual rows revealed under an expanded group — a faint brand wash
   sets them apart from the top-level list, and each is indented under its
   heading. */
.notifications-group__members {
    background: color-mix(in srgb, var(--color-action) 2%, transparent);
}

.notifications-item--child {
    padding-left: var(--spacing-lg);
}

/* Full width: the wide shell modifier (settings-hub-content-inner--wide) sets
   the outer cap, so the page fills the room the alert rows and the channel
   tables need.

   It also carries the channel column's width. A card's header and its rows do
   share a container now, so the number could sit on .settings-permission-group — but it
   has to be the SAME number in every card or one card's ticks would sit under
   another card's word widths, and one declaration for the page is how that is
   guaranteed rather than reviewed. Read by .notifications-alert-channels below, which
   both the header's words and the rows' boxes wear. */
.notifications-settings {
    margin: 0 auto;
    --notif-channel-col: 3.25rem;
}

/* "This phone" — the card above the alert cards that signs this browser up for
   phone alerts. One row: the phone glyph in a tinted tile, the name over its
   one line and the iPhone note, the button at the right. Same gap below it as
   between the alert cards, so it reads as the first of them. */
.notifications-phone {
    display: flex;
    /* .global-card stacks its children; this one is a row. */
    flex-direction: row;
    align-items: center;
    gap: var(--spacing-smd);
    padding: var(--spacing-smd) var(--spacing-md);
    margin-bottom: var(--spacing-mdlg);
}

.notifications-phone__icon {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius-md);
    color: var(--color-action);
    background: color-mix(in srgb, var(--color-action) 10%, transparent);
    font-size: var(--font-size-lg);
}

.notifications-phone__text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
}

.notifications-phone__title {
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

.notifications-phone__line {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.notifications-phone__hint {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

.notifications-phone__hint[hidden],
.notifications-phone__button[hidden] {
    display: none;
}

.notifications-phone__button {
    flex: none;
}

/* The Slack channels page's title block, and only that page's: the
   notifications page itself draws no title of its own any more (it takes
   page_header.html's title_hidden, see app/notifications/settings.html). Kept
   because that page is still reached from Integrations rather than from a
   highlighted nav item, so its name is the only thing saying where you are. */
.notifications-page-title {
    margin-bottom: var(--spacing-md);
}

.notifications-page-h1 {
    font-size: 1.5rem;
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    margin: var(--spacing-xs) 0 var(--spacing-xsm);
}

.notifications-page-helper {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    margin: 0;
    max-width: 60ch;
}

/* Chrome (fill, hairline border, card radius, resting shadow) now comes from the
   canonical `.global-card` (components/card.css); the template carries both
   classes. This rule keeps only what the canonical card lacks: the section gap
   below each card and the corner clip that keeps the flush link-existing table
   inside the rounded corners. */
.notifications-card {
    margin-bottom: var(--spacing-lg);
    overflow: hidden;            /* clip a flush table to the rounded corners */
}

.notifications-card__header {
    display: flex;
    align-items: baseline;
    gap: var(--spacing-sm) var(--spacing-md);
    flex-wrap: wrap;
    padding: var(--spacing-md) var(--spacing-mdlg);
    border-bottom: 1px solid var(--color-border);
}

.notifications-card__title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    margin: 0;
}

.notifications-card__hint {
    flex-basis: 100%;            /* always drops to its own line under the title */
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0;
}

.notifications-card__body {
    padding: var(--spacing-mdlg) var(--spacing-lg);
}

.notifications-critical {
    display: inline-block;
    margin-left: var(--spacing-sm);
    padding: var(--spacing-2xs) var(--spacing-xsm);
    font-size: var(--font-size-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-warning-text);
    background: color-mix(in srgb, var(--color-warning) 18%, transparent);
    border-radius: var(--radius-pill);
    vertical-align: middle;
}

.notifications-cell {
    white-space: nowrap;
}

.notifications-audience-chip {
    padding: var(--spacing-2xs) var(--spacing-sm);
    font-size: var(--font-size-2xs);
    color: var(--color-grey-600);
    background: color-mix(in srgb, var(--color-text-muted) 14%, transparent);
    border-radius: var(--radius-pill);
}

/* Not a chip — the seam between two OR'd groups of them. Bare and lettered
   rather than filled, so it reads as punctuation between the conditions
   instead of as one more condition. */
.notifications-audience-or {
    font-size: var(--font-size-2xs);
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
}

.notifications-audience-form {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-smd);
}

/* The shared filter builder, under the hairline the drawer's other blocks
   use, so the conditions read as their own thing and not as more of the
   name field above them. */
.notifications-audience-conditions {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
    padding-top: var(--spacing-smd);
    border-top: 1px solid var(--color-border);
}

/* Destructive, so it is set like the other removes in this file — quiet
   until you look for it, never a filled button competing with Save. */
.notifications-audience-delete {
    align-self: flex-start;
    padding: 0;
    font-size: var(--font-size-sm);
    color: var(--color-error);
}

@media (max-width: 640px) {
    .notifications-card__header {
        padding: var(--spacing-md) var(--spacing-md);
    }

    .notifications-card__body {
        padding: var(--spacing-md);
    }
}

/* ========================= Review and link ========================= */
/* Not responsive rules — these sit after the Responsive block only because
   they shipped later. The small line under each row of the link-existing
   table saying why it reads the way it does, and the per-booking outcomes
   after a save. */
.notifications-backfill-reason {
    margin: var(--spacing-xsm) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-grey-600);
}

.notifications-backfill-results {
    margin: var(--spacing-sm) 0 0;
    padding: 0;
    list-style: none;
}

.notifications-backfill-result {
    display: flex;
    gap: var(--spacing-sm);
    justify-content: space-between;
    padding: var(--spacing-xs) 0;
    font-size: var(--font-size-md);
    border-bottom: 1px solid var(--color-border);
}

.notifications-backfill-result__text {
    color: var(--color-grey-600);
}

/* ── Your alerts: a card that names its own columns, then a box per column ──
   Nick, on the coloured pills the rows used to carry:

     "on the selection of the in app versus the email, can you please have
      those be stickey header kind of and then checkboxes? Chekcboxs are just
      more clear than the differnet colloered piull."

   and then, on where those words belong:

     "the in-app email shoudl acutally be sticky in each of the containers,
      like they should be at thet op fot he containers and then stickey as you
      scrol through that container."

   So the words come out of the rows and into the header of the card whose rows
   they name — one heading per card, not one strip above all of them — and the
   rows carry boxes under it. The row itself is still .settings-permission-row
   (settings-hub/permissions.css) on purpose — Nick asked for the Permissions
   page's look, and a second copy of that grid under a different name is how
   two surfaces start to drift. What follows is only what this variant adds.

   Alignment then has to be built rather than assumed, because a tick under
   the wrong word reads as a subscription the person did not choose. Half of
   it is by construction: both sides draw .notifications-alert-channels, a grid of
   FIXED-width columns, inside the same three-column layout, so neither needs
   the other's measurements to put a word over its own boxes. The other half
   is not — the header has to arrive at the same inner edge as a row by
   repeating .settings-permission-row's padding and .card-body's, below, and a repeated
   number is a number that can be wrong. It was, by 15px, until Chromium said
   so; tests/browser/test_notification_self_signup_proof.py now measures both
   centres off real boxes, which is the only thing standing behind this.

   A table would have carried the whole of it for free and is not available:
   the rows are cards in eight separate containers, and no table spans those. */

/* The card's header: the group's name and its rows' column headings on one
   row, sticky.

   Sticky INSIDE the card is the whole of "in each of the containers". A sticky
   box is pinned by the viewport but bounded by its containing block, which
   here is the .global-card — so it pins under the app header while its own
   list scrolls past and leaves with the card, rather than riding the page and
   outliving the rows it names. Two things have to hold for that:

     • .global-card carries no overflow (components/card.css), and a scrolling
       or clipping ancestor would break sticky outright;
     • the settings hub is deliberately not a scroll container either
       (overflow-x: clip, settings-hub.css), so this rides the page's own
       scroll and not a nested one.

   --drawer-top is the platform's single answer for "starts below the app
   header"; do not re-derive it here. The group's own name rides this header
   rather than a band above it precisely because this is the piece still on
   screen when the list is halfway past — a pinned strip reading only "In-app
   Email" would not say which card's.

   Chrome comes from the bare .card-header (main.css): hairline underline,
   medium weight. What is added is the grid, an opaque fill — .card-header is
   transparent, and a pinned transparent header shows the rows sliding under it
   — and the card's own top corners, so the fill does not square off the
   rounded card behind it.

   Written as a descendant of .global-card, and that is load-bearing rather
   than tidy. main.css is linked after every feature sheet (base/base.html), so
   .card-header and a bare .notifications-group-header tie on specificity and the later
   sheet takes it — which silently hands back .card-header's transparent fill
   and its padding. Both were lost exactly that way: the pinned header showed
   the rows through itself, and its words sat 15px off the boxes they name. The
   header only ever hangs inside a .global-card, so the extra class is the truth
   about where it lives and not a weight bolted on to win. */
.global-card .notifications-group-header {
    position: sticky;
    top: var(--drawer-top);
    z-index: var(--z-sticky);
    display: grid;
    /* .settings-permission-row's grid, so the middle column lands in the same place.
       The empty third cell is the row's 18px opener slot. */
    grid-template-columns: minmax(0, 1fr) auto 18px;
    align-items: center;
    gap: var(--spacing-md);
    /* What stands between the card's inner edge and a row's content, summed:
       .card-body's padding, .settings-permission-row's own, and the row's hairline. The
       card's own border is outside this box — the header is inside it, where
       the strip that preceded it was outside — so it is not in the sum.
       Indenting the group's name by the same amount is the other half of the
       point: it lands on the same left edge as the labels of the rows it
       heads. Every term here is repeated from somewhere else and the browser
       proof is what holds them together. */
    padding: var(--spacing-md) calc(var(--spacing-md) + var(--spacing-smd) + 1px);
    background: var(--color-card-bg);
    border-radius: var(--radius-card) var(--radius-card) var(--radius-none) var(--radius-none);
}

/* Icon over word, centred on the column its boxes sit in. */
.notifications-channel-head {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-2xs);
    font-size: var(--font-size-2xs);
    font-weight: var(--font-weight-medium);
    letter-spacing: 0.04em;
    line-height: 1.3;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

/* The row's boxes, and the header's headings, on one grid. Fixed columns
   rather than flex: a flex row sizes to its content, so "In-app" and "Email"
   would each pull their own column to a different width and the boxes below
   would sit under neither. */
.notifications-alert-channels {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: var(--notif-channel-col);
    justify-items: center;
    align-items: center;
}

/* The control is .global-checkbox (components/checkbox.css) — the platform's
   own box, ADR-131's singleton, already painting its tick in
   --color-neutral-ink-fg. Nothing here restyles it.

   Nick: "we need fo the checkboxes to be bigge rplease". Turned through the
   component's own documented size knob and nothing else. The tick is a
   full-bleed masked ::after sized at 75%, so it re-centres itself at whatever
   edge this says; a width/height pair written here would be the hand-rolled
   lookalike ADR-131's singleton gate exists to stop. 1.25rem is a deliberate
   step up from the component's 1rem default and still leaves room inside the
   3.25rem column, which is what keeps the boxes centred under their words. */
.notifications-alert-channel {
    --global-checkbox-size: 1.25rem;
}

/* In flight (hx-disabled-elt): the shared box goes to not-allowed, which reads
   as "you may not", and this one is only busy. It comes back the moment the
   row swaps in. */
.notifications-alert-channel:disabled {
    cursor: progress;
}

/* Only a row with a filter behind it is a click target. Every row used to wear
   .settings-permission-row's pointer and hover lift while only some had a drawer — Nick:
   "when I click some of the rows that look clickable nothign happens, others
   open the fitler drawer which is great." */
.settings-permission-row--alert {
    cursor: default;
}

.settings-permission-row--alert.is-openable {
    cursor: pointer;
}

/* Taken away, not merely left unset: the lift is .settings-permission-row's own, and a
   row that brightens under the cursor is the promise Nick clicked on. */
.settings-permission-row--alert:not(.is-openable):hover {
    border-color: color-mix(in srgb, currentColor 8%, transparent);
}

/* The funnel at the right. It carries .settings-permission-row__chevron, whose rule is
   to be invisible until the row is hovered — right there, where the row is a
   click target and the chevron only says which way it opens. Here it is the
   mark that the row opens at all, so it is visible at rest. */
.settings-permission-row--alert .notifications-alert-row__narrow {
    opacity: 1;
}

/* Lit once conditions are set, so a narrowed row says so from across the page. */
.notifications-alert-row__narrow.is-set {
    opacity: 1;
    color: var(--color-action);
}

/* The drawer's foot: Clear beside Save, Save primary and last. It reuses the
   drawer footer every saved-view panel uses (.global-drawer__footer, ghost/primary
   buttons — components/drawer-content.css) so both read as one panel language —
   the filter builder inside it is already drawing that button.

   Two departures from the pinned original, both forced. It sits INSIDE the
   panel rather than beside .global-drawer-body, because the panel is what re-renders
   on save (hx-swap="outerHTML" on #self-filter-body) and a footer outside it
   would keep offering Clear on a filter that no longer has one. And it is bled
   back out to the panel's edges — .global-drawer-body's own 1.25rem — so the hairline
   runs the full width the way a pinned footer's does.

   flex-end, not the original's space-between: with nothing saved there is no
   Clear, and space-between would walk Save over to the left on its own.

   Living inside the panel is also what made it float. Below, the panel is a
   full-height column so this can take the slack above it (margin-top: auto)
   and land on the drawer's floor; without that pair it stopped wherever the
   builder stopped, which on an empty filter is a fifth of the way down with
   a full-width hairline across it. Sticky for the other end of the range: a
   builder with a few conditions in it outgrows the drawer, and the way out of
   a question should not be the thing you scroll to find. The bottom offset is
   the bleed, so it comes to rest flush with .global-drawer-body's padding edge rather
   than 1.25rem above it. */
.notifications-self-filter-panel {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.notifications-self-filter-foot {
    justify-content: flex-end;
    margin: auto -1.25rem -1.25rem;
    position: sticky;
    bottom: -1.25rem;
}

/* Their own conditions, under the alert's name. One wrapping line: the lead-in
   word and the chips are a sentence and wrap together. */
.notifications-alert-row__narrowed {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-xs);
    margin-top: var(--spacing-2xs);
}

.notifications-alert-row__narrowed-lead {
    font-size: var(--font-size-2xs);
    color: var(--color-text-muted);
}

/* Why every button on this row is dark when somebody else put them on it.
   Without this the row is indistinguishable from one nobody ever touched. */
.notifications-alert-row__note {
    font-size: var(--font-size-2xs);
    color: var(--color-text-muted);
    margin-top: var(--spacing-2xs);
}

/* The Slack channels page stacks its six category groups inside one card,
   rather than the card-per-group the personal alerts page draws — twenty
   switches split six ways is six cards, two of which would hold a single row.

   That stacking is the whole reason this rule exists. On the alerts page the
   space above a group's name is the gap between two cards
   (.settings-permission-groups) and the space under it is .card-header's own padding;
   inside a single card there is neither. Every heading sat flush against
   whatever preceded it — the last row of the group before, or, for the first
   one, the intro line, which carries margin: 0 — and touched the first row of
   its own group. Scoped to this card's body because the alerts page draws the
   same element inside a .card-header, where both spacings are already right.  */
.notifications-card__body .settings-permission-group__header {
    margin-top: 1.25rem;
    margin-bottom: var(--spacing-sm);
}
