/* ===========================================================================
 * portal.css -- the quarantine portal's whole visual system.
 *
 * Deployed by scripts/deploy.sh to /var/www/portal-static/portal.css and
 * served by nginx directly. Do not edit in /var/www.
 * ===========================================================================
 *
 * THE PALETTE IS CKT'S OWN, TAKEN FROM crawkan.net'S OWN STYLESHEET
 * (operator-instructed 2026-09-08). The names below are the names CKT uses --
 * "gorilla gold", "Pitt red", "KS sun orange" -- and they are local: the
 * Gorillas are Pittsburg State, in Pittsburg, Crawford County. Keeping the
 * vendor's names means a future designer can diff this against crawkan.net
 * and see immediately whether it has drifted.
 *
 * Source of truth: --base-color-brand--* in
 * cdn.prod.website-files.com/.../crawkan.shared.*.min.css
 *
 * LAYOUT IS THE INCUMBENT'S, deliberately (operator decision 2026-09-08).
 * Subscribers are moving off a portal they already know, so the tab strip
 * (Messages / Settings / Policies), the actions ABOVE the list, and the word
 * ranges are carried across rather than redesigned. What is NOT carried is
 * the blue gradient chrome, the glossy icons, the 11px type and the
 * horizontal scroll. See docs/design/ for the artboards this implements.
 *
 * 🔴 NO EXTERNAL REQUESTS FROM THIS STYLESHEET. EVER.
 *
 * crawkan.net sets its type in Montserrat, served from Google Fonts. This
 * portal does NOT fetch it, and the reason is the same one that makes remote
 * images opt-in on a quarantined message: a third-party request tells that
 * third party when a subscriber opened their quarantine. A web font is
 * exactly that request, on every page load, for every subscriber, to Google.
 *
 * So the stack below asks for Montserrat and falls back to the platform's
 * own UI font. Subscribers who have Montserrat installed get the brand face;
 * nobody's reading habits leave this host either way. If exact brand
 * typography matters more than that, the answer is to SELF-HOST the woff2
 * from this origin -- a deliberate change, not a @import somebody adds later.
 *
 * The same rule bans a CDN for anything else: no icon fonts, no CSS
 * frameworks, no analytics. Everything this page needs is on this host.
 * The one icon in the interface -- the refresh arrow -- is inline SVG in the
 * markup for exactly that reason.
 *
 * 🔴 AND NO JAVASCRIPT ANYWHERE. nginx serves `script-src 'none'`, so every
 * control below is a link, a form, or CSS. That constraint is what shapes
 * three things a reviewer might otherwise read as omissions, all of them
 * marked where they occur: the message pop-up is a server-rendered page and
 * not a client-side dialog; and Refresh is a link, with the periodic reload
 * delivered as an HTTP `Refresh:` header rather than a meta tag.
 */

:root {
    /* ---- CKT brand, verbatim from crawkan.net ---- */
    --ck-black:         #231f20;   /* brand black, not #000 */
    --ck-white:         #ffffff;
    --ck-gorilla-gold:  #febb1c;
    --ck-sun-orange:    #f04b25;
    --ck-pitt-red:      #cf2027;

    /* ---- neutrals, also theirs ---- */
    --ck-n-lightest:    #eeeeee;
    --ck-n-lighter:     #cccccc;
    --ck-n-light:       #aaaaaa;
    --ck-n:             #666666;
    --ck-n-dark:        #444444;
    --ck-n-darker:      #222222;

    /* ---- system colours, also theirs, so success/error match the main site
     *      rather than being invented here ---- */
    --ck-error:         #b42318;
    --ck-error-bg:      #fef3f2;
    --ck-success:       #027a48;
    --ck-success-bg:    #ecfdf3;

    /* ---- roles. Components reference THESE, never the raw brand colours,
     *      so a rebrand is a change to this block and nothing else. ---- */
    --bg:               var(--ck-white);
    --bg-alt:           var(--ck-n-lightest);
    --bg-bar:           #fafafa;      /* toolbar ground: lighter than bg-alt so
                                         the table head still reads as a head */
    --fg:               var(--ck-black);
    --fg-muted:         var(--ck-n);
    --rule:             var(--ck-n-lighter);
    --header-bg:        var(--ck-black);
    --header-fg:        var(--ck-white);
    --accent:           var(--ck-gorilla-gold);
    --link:             #0b5cab;      /* not a brand colour: see note below */
    --danger:           var(--ck-pitt-red);

    --font: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto,
            "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
            "Liberation Mono", monospace;

    --radius: 4px;
    --pad: 1rem;

    /* THE TOUCH TARGET. 0.75rem/1.125rem on a 16px root computes to a 46px
     * control. The previous 0.5rem/1rem gave 40px, under the 44px minimum
     * both platform guidelines use -- a real defect on a page whose two most
     * consequential controls are "release" and "delete" sitting side by side. */
    --btn-pad-y: 0.75rem;
    --btn-pad-x: 1.125rem;

    color-scheme: light;   /* no dark theme here; say so, so a browser does
                              not invent one for the form controls */
}

/* WHY --link IS NOT A BRAND COLOUR. Contrast ratios MEASURED against white,
 * not assumed -- WCAG AA wants 4.5:1 for body text and 3:1 for large text and
 * UI components:
 *
 *     gorilla gold #febb1c    1.70:1   fails both. A fill colour, never a
 *                                      text colour. On brand black it is
 *                                      9.58:1, which is why the header rule
 *                                      is the right place for it.
 *     sun orange   #f04b25    3.66:1   fails body text, passes large/UI
 *     pitt red     #cf2027    5.40:1   PASSES body text
 *     brand black  #231f20   16.30:1   passes comfortably
 *     chosen link  #0b5cab    6.70:1   passes
 *
 * So the honest reason is NOT that the brand colours are illegible -- Pitt
 * red is perfectly legible. It is that RED IS RESERVED. --danger is Pitt red
 * and is used ONLY for destructive controls and hostile-content warnings, so
 * that red on this page always means "be careful". Using the same red for
 * every ordinary link would spend that meaning on navigation, on a page whose
 * entire job is telling a subscriber which mail is dangerous. Gold and orange
 * are unusable for link text on their own numbers.
 *
 * Brand colour is therefore carried by the header, the logo and the accent
 * rule -- which is how crawkan.net itself uses them.
 */

*, *::before, *::after { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--font);
    font-size: 16px;              /* absolute, so a subscriber's browser zoom
                                     and OS text scaling both still work */
    line-height: 1.5;
    color: var(--fg);
    background: var(--bg);
}

/* ===========================================================================
 * HEADER AND TABS
 * ======================================================================== */

.ck-header {
    background: var(--header-bg);
    color: var(--header-fg);
    padding: 0.75rem var(--pad) 0;
    display: flex;
    align-items: center;
    gap: var(--pad);
    flex-wrap: wrap;
}
.ck-header img.ck-logo { height: 36px; width: auto; display: block; }
.ck-header .ck-spacer  { flex: 1 1 auto; }

/* THE LOGO AS A HOME LINK (staff view; the subscriber portal still passes no
 * `home` and keeps a plain <img>). `display: block` on the anchor so it wraps
 * the image tightly -- an inline anchor adds a baseline gap under the image
 * and the black band grows a few pixels taller on exactly the pages that link
 * it, which reads as the header shifting as you navigate. */
.ck-logo-link { display: block; border-radius: var(--radius); }
.ck-logo-link:focus-visible { outline: 2px solid var(--ck-white);
                              outline-offset: 3px; }

/* The identity as a link to /staff/profile. It sits on the black band, so it
 * takes the band's own light text colour rather than --link, which is tuned
 * for the white sheet below and fails contrast up here. Underlined on
 * hover/focus rather than always, so it does not read as a second button
 * sitting next to Sign out -- which is the neighbouring control and the one
 * with consequences. */
.ck-who-link { color: inherit; text-decoration: none; }
.ck-who-link:hover, .ck-who-link:focus-visible { text-decoration: underline; }
.ck-who-link:focus-visible { outline: 2px solid var(--ck-white);
                             outline-offset: 2px; }

/* CKT'S OWN SUPPORT NUMBERS, carried from the old portal. A subscriber who
 * cannot get into a quarantine is a subscriber who is about to phone
 * somebody; the number belongs on the page, not in a help article. */
.ck-support { font-size: 0.8125rem; line-height: 1.35; text-align: right; }
.ck-support strong { color: var(--accent); font-weight: 600; display: block; }

/* 🔴 LAID OUT, NOT text-align:right. This block held the address and the
 * Sign-out button divided by a <br>, with `text-align: right` to push them to
 * the page edge. That works only while `.ck-spacer` keeps this element at the
 * right of a single-line header. The moment the header wrapped -- which it
 * does on any phone -- this became the only item on its own line, placed at
 * flex-start, and `text-align: right` then aligned its contents against the
 * right edge of its own ~155px shrink-to-fit box. The result was a Sign-out
 * button floating at an arbitrary interior position with 640px of empty black
 * to its right, aligned to neither page edge nor to the label above it.
 * A flex row aligns to whatever box it is given, at any width. */
.ck-ident { display: flex; align-items: center; gap: 0.75rem;
            font-size: 0.8125rem; color: var(--ck-n-light); }
.ck-ident a { color: var(--ck-n-lighter); }
.ck-who { white-space: nowrap; }

/* Support numbers must never break mid-number: this is the one element whose
 * whole justification is that a locked-out subscriber can read it and dial
 * it. The wrap now falls on the middot between them. */
.ck-tel { white-space: nowrap; color: inherit; }
.ck-nowrap { white-space: nowrap; }

/* The tab strip sits INSIDE the black band and the gold rule closes it, so
 * the active tab reads as a sheet of paper in front of the header rather
 * than a button on top of it. */
.ck-tabs {
    background: var(--header-bg);
    padding: 0.5rem var(--pad) 0;
    display: flex; gap: 0.25rem; align-items: flex-end;
}
.ck-tab {
    display: block;
    padding: 0.6875rem 1.375rem;
    border-radius: 5px 5px 0 0;
    font-size: 0.9375rem;
    color: var(--ck-n-lighter);
    text-decoration: none;
}
.ck-tab:hover { color: var(--ck-white); background: #383334; }
.ck-tab[aria-current="page"] {
    background: var(--bg); color: var(--fg); font-weight: 700;
}
.ck-tab[aria-current="page"]:hover { background: var(--bg); }
.ck-rule { height: 4px; background: var(--accent); }   /* CKT's own gold rule */

/* ---------------------------------------------------------------------------
 * THE PER-MAILBOX STRIP -- the same construction as .ck-tabs above, smaller.
 *
 * Staff only, on the pages that act on ONE subscriber: Held mail, Policies.
 * It is deliberately the SAME shape as the page-level strip -- tabs sitting on
 * a black band, closed by the gold rule, so the current one reads as a sheet
 * of paper in front of it -- because it does the same job one level down. A
 * reader who has learnt the top strip already knows what this is.
 *
 * 🔴 AND IT IS DELIBERATELY *NOT* .ck-chip, which is what it was built from
 * first. Chips are FILTERS -- the range, state, audit and rates pickers are
 * all .ck-chip -- and on the Held mail page the mailbox tabs sit directly
 * above two rows of them. Three rows of identical pills meaning three
 * different things is not a layout, it is a puzzle. Navigation and filtering
 * have to look different, and the app already had a vocabulary for each.
 *
 * SMALLER ON EVERY AXIS, so it reads as subordinate to the page strip rather
 * than competing with it: 2px of gold instead of 4, ~0.72x the tab padding,
 * and a slightly smaller face.
 * ------------------------------------------------------------------------ */
.ck-subtabs {
    background: var(--header-bg);
    padding: 0.375rem var(--pad) 0;
    display: flex; gap: 0.25rem; align-items: flex-end;
    margin: 0;
}
.ck-subtab {
    display: block;
    padding: 0.4375rem 1rem;
    border-radius: 4px 4px 0 0;
    font-size: 0.875rem;
    color: var(--ck-n-lighter);
    text-decoration: none;
}
.ck-subtab:hover { color: var(--ck-white); background: #383334; }
.ck-subtab[aria-current="page"] {
    background: var(--bg); color: var(--fg); font-weight: 700;
}
.ck-subtab[aria-current="page"]:hover { background: var(--bg); }
.ck-subrule { height: 2px; background: var(--accent); margin: 0 0 var(--pad); }

main { max-width: 90rem; margin: 0 auto; }
/* Pages that are prose rather than a table get the narrower measure. */
main.ck-narrow { max-width: 60rem; padding: 1.25rem var(--pad) 2rem; }
main.ck-wide   { padding: 0; }
main.ck-wide > h1 { margin: 1.25rem var(--pad) 0.5rem; font-size: 1.375rem; }
/* A wide page has no padding so its TABLES can run edge to edge. Everything
 * else that sits directly in it must bring the gutter itself. The heading
 * and the notices did; the search bars (`form.ck-searchbar`) and the chip
 * rows (bare <p>) did not, and sat flush against the viewport while the
 * heading and notes beside them did not -- seen in the first headless
 * screenshots, 2026-10-01, on Find mail and the staff mailbox page. */
main.ck-wide > :is(form, h2, h3, p, ul, ol, pre, details,
                   table.ck-msgmeta, .ck-msg-plain, .ck-acct-actions) {
    margin-left: var(--pad); margin-right: var(--pad);
}
/* Deliberately NOT in that list, because they are meant to run edge to
 * edge: table.ck-list and .ck-scroll (the data tables), nav.ck-subtabs and
 * .ck-subrule (the mailbox tab strip), .ck-toolbar (the subscriber action
 * bar, which carries its own padding), and iframe.ck-reports-frame. */

/* ===========================================================================
 * NOTICES
 * ======================================================================== */

.ck-note, .ck-error, .ck-ok {
    padding: 0.75rem var(--pad);
    border-radius: var(--radius);
    border: 1px solid var(--rule);
    background: var(--bg-alt);
    margin: var(--pad) 0;
}
.ck-error { border-color: var(--ck-error);   background: var(--ck-error-bg);   color: var(--ck-error); }
.ck-ok    { border-color: var(--ck-success); background: var(--ck-success-bg); color: var(--ck-success); }
main.ck-wide > .ck-note,
main.ck-wide > .ck-error,
main.ck-wide > .ck-ok { margin: var(--pad); }

/* ===========================================================================
 * FORMS AND BUTTONS
 * ======================================================================== */

label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
input[type="email"], input[type="text"], input[type="password"], select {
    font: inherit; padding: 0.75rem; width: 100%;
    border: 1px solid var(--ck-n-light); border-radius: var(--radius);
    background: var(--bg); color: var(--fg);
}
button, .ck-btn {
    font: inherit; font-size: 0.9375rem; font-weight: 600; cursor: pointer;
    padding: var(--btn-pad-y) var(--btn-pad-x); border-radius: var(--radius);
    border: 1px solid var(--ck-black);
    background: var(--ck-black); color: var(--ck-white);
    text-decoration: none; display: inline-flex; align-items: center;
    gap: 0.4375rem; white-space: nowrap;
}
button.ck-secondary, .ck-btn.ck-secondary {
    background: var(--bg); color: var(--fg); border-color: var(--ck-n-light);
}
button.ck-secondary:hover, .ck-btn.ck-secondary:hover { background: var(--bg-alt); }
/* Destructive only. See the RED IS RESERVED note. */
button.ck-danger, .ck-btn.ck-danger {
    background: var(--danger); border-color: var(--danger); color: var(--ck-white);
}
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible {
    outline: 3px solid var(--accent); outline-offset: 2px;
}
/* The refresh glyph. Inline SVG, per the no-external-requests rule. */
.ck-btn svg, button svg { flex: none; }

a { color: var(--link); }

/* ===========================================================================
 * THE ACTION TOOLBAR -- ABOVE THE LIST
 * ======================================================================== */
/* Operator decision 2026-09-08, carried from the incumbent. Actions above the
 * list means a subscriber who has just ticked three rows does not have to
 * scroll past the rest of the page to act on them. */

.ck-toolbar {
    display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;
    padding: 0.875rem var(--pad) 0.75rem;
    background: var(--bg-bar);
    border-bottom: 1px solid var(--rule);
}
.ck-toolbar .ck-sep {
    width: 1px; align-self: stretch; background: var(--rule); margin: 0 0.25rem;
}
.ck-toolbar .ck-spacer { flex: 1 1 auto; }
/* The auto-reload notice. Quiet -- it is a statement of fact sitting beside
 * the Refresh button, not a control competing with it. */
.ck-auto { font-size: 0.8125rem; color: var(--fg-muted); line-height: 1.25;
           max-width: 11rem; }
/* flex, not a fixed 250px: on the narrowest screen the field wrapped onto a
 * row of its own and then used 250 of 358 available px, leaving 100px unused
 * on the form factor where a long subject query is hardest to type.
 * `min-width: 0` is what lets it actually shrink inside a flex line. */
.ck-toolbar input[type="text"] { flex: 1 1 12rem; width: auto; min-width: 0;
    /* Exactly the buttons' height. `font: inherit` gave the box the 16px body
     * size while `button` is 0.9375rem; at line-height 1.5 that is 24px
     * against 22.5px of text inside the same 0.75rem padding, so the box
     * stood 1.5px taller than Release/Delete/Search beside it (reported
     * 2026-10-01). Same font size, same height. */
    font-size: 0.9375rem; }
.ck-toolbar form { display: contents; }   /* so the search form's controls sit
                                             on the toolbar's own flex line */

/* THE SELECTION BAR: Select all / Select none and a LIVE count of the ticked
 * boxes, with no script (operator 2026-10-22). The count is a CSS counter:
 * reset on the wrapper, incremented by every checked row box, printed by
 * ::before. Counters run in DOCUMENT order, so the bar is the LAST child of
 * .ck-selwrap in the markup (after the table, where every box has already
 * been counted) and `order` lifts it to just under the toolbar. Moving it up
 * in the HTML would make it count only the boxes above it: none. See
 * app.selbar(). */
.ck-selwrap { display: flex; flex-direction: column; counter-reset: ck-sel; }
.ck-selwrap > .ck-toolbar { order: -2; }
.ck-selwrap > .ck-selbar  { order: -1; }
.ck-selwrap input[type="checkbox"][name="id"]:checked { counter-increment: ck-sel; }
.ck-selbar {
    display: flex; align-items: center; flex-wrap: wrap;
    padding: 0.4rem var(--pad);
    border-bottom: 1px solid var(--rule);
    font-size: 0.9375rem;
}
.ck-selbar .ck-dot { color: var(--ck-n-light); margin: 0 0.5rem; }
.ck-selcount { color: var(--fg-muted); }
.ck-selcount::before { content: counter(ck-sel); font-weight: 600; color: var(--fg); }

/* Ranges and counters, on their own line so the actions above stay on one row
 * when the window is narrow. */
.ck-meta {
    display: flex; gap: var(--pad); align-items: center; flex-wrap: wrap;
    padding: 0.5rem var(--pad);
    border-bottom: 1px solid var(--rule);
    font-size: 0.9375rem;
}
.ck-meta .ck-spacer { flex: 1 1 auto; }
.ck-meta .ck-count  { color: var(--fg-muted); }
/* ONE flex item holding the whole counts group. As bare siblings of a
 * wrapping flex container each pipe was its own item with 1rem of gap on both
 * sides, and a wrap could strand one at the end of a line with nothing after
 * it -- which read as damage, not punctuation. */
.ck-counts { display: inline; }
/* Was var(--rule) = #cccccc, 1.7:1 on white -- barely visible, which is why a
 * stranded one looked like a glitch rather than a separator. */
.ck-counts .ck-dot { color: var(--ck-n-light); margin: 0 0.5rem; }
/* 🔴 flex-wrap AND nowrap, and the pair of them is a bug fix not a polish.
 *
 * With no `flex-wrap` these six chips needed ~513px of a 358px content box.
 * As a flex item they compressed to min-content -- which, without
 * `white-space: nowrap`, is the longest WORD of each chip -- so every label
 * broke at its space ("2 / days", "All 60 / days") and the row STILL
 * overflowed by ~62px. `.ck-meta` sets no overflow, so that escaped and gave
 * the BODY a horizontal scrollbar: the exact thing `.ck-scroll` exists to
 * prevent, happening one element above it.
 *
 * `align-items: center` then centred one-, two- and three-line chips against
 * each other, so the row read as a paragraph of loose words rather than a
 * scale. */
.ck-ranges { display: flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; }
.ck-ranges a, .ck-ranges strong {
    padding: 0.4375rem 0.875rem; border-radius: var(--radius);
    text-decoration: none; display: block; white-space: nowrap;
    /* An inactive chip had no border or background until :hover, and :hover
     * never fires on touch -- so five of the six did not read as controls at
     * all. Only the active one looked like anything. */
    border: 1px solid var(--rule);
}
.ck-ranges strong { background: var(--ck-black); color: var(--ck-white);
                    font-weight: 600; border-color: var(--ck-black); }
.ck-ranges a:hover { background: var(--bg-alt); border-color: var(--ck-n-light); }

/* ===========================================================================
 * THE HELD-MAIL TABLE
 * ======================================================================== */

table.ck-list { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
table.ck-list th, table.ck-list td {
    text-align: left; padding: 0.6875rem 0.5rem;
    border-bottom: 1px solid var(--ck-n-lightest);
    vertical-align: top;
}
table.ck-list thead th {
    background: var(--bg-alt); font-weight: 600; white-space: nowrap;
    border-bottom: 1px solid var(--rule);
}
table.ck-list thead th a { color: var(--fg); text-decoration: none; }
table.ck-list thead th a:hover { text-decoration: underline; }
table.ck-list td.ck-when { white-space: nowrap; }
table.ck-list td.ck-score { font-family: var(--mono); text-align: right; white-space: nowrap; }
table.ck-list tbody tr:hover td { background: #fbfbfb; }
/* The row whose message is open in the pop-up. */
table.ck-list tbody tr.ck-open td { background: #fff8e6; }
table.ck-list .ck-pickbox { width: 2.25rem; }
table.ck-list input[type="checkbox"] { width: 1.125rem; height: 1.125rem; }
/* 🔴 THE 18px CONTROL. A bare <input> cannot be padded, so the primary
 * per-message control was an 18x18 hit area -- a quarter of the 44px this
 * stylesheet argues for at the --btn-pad-y note and calls "a real defect"
 * when violated. The negative margin reclaims the cell padding so the row
 * does not grow taller than it already is. */
.ck-pick {
    display: flex; align-items: center; justify-content: center;
    min-width: 2.75rem; min-height: 2.75rem;
    margin: -0.6875rem -0.5rem; cursor: pointer;
}
/* An e-mail address is one unbreakable token, so this cell set a ~250px
 * min-content floor and squeezed Subject -- the only column that answers "is
 * this mine?" -- down to about 80px. */
table.ck-list td.ck-from { word-break: break-word; overflow-wrap: anywhere; }

/* "released" beside a subject. Quiet on purpose: the row's state is already
 * carried by the absence of bold, and this only answers the one question that
 * bold cannot -- "have I already sent this to myself" -- now that releasing
 * twice is allowed. It must not compete with the risk pill next to it. */
.ck-tag {
    display: inline-block; margin-left: 0.5rem; padding: 0 0.375rem;
    font-size: 0.75rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--fg-muted);
    border: 1px solid var(--rule); border-radius: 3px; vertical-align: 1px;
    white-space: nowrap;
}

/* Risk, as a word rather than a number. The score stays available as a column
 * for support; the pill is what a subscriber actually reads. */
.ck-pill {
    display: inline-block; border-radius: 999px; padding: 0.125rem 0.6875rem;
    font-size: 0.8125rem; font-weight: 700; white-space: nowrap;
    background: var(--bg-alt); color: var(--ck-n-dark);
    border: 1px solid var(--ck-n-light);
}
.ck-pill-danger {
    background: var(--ck-error-bg); color: var(--ck-error);
    border-color: var(--ck-error);
}

/* Wide content must scroll in its own box, never make the page scroll
 * sideways -- subject lines off the internet are arbitrarily long. */
.ck-scroll { overflow-x: auto; }

.ck-pager { display: flex; gap: var(--pad); align-items: center;
            flex-wrap: wrap; justify-content: center;
            padding: var(--pad); color: var(--fg-muted); }
.ck-pageno { color: var(--fg-muted); white-space: nowrap; }

/* ===========================================================================
 * THE MESSAGE POP-UP
 * ======================================================================== */
/* 🔴 THIS IS A SERVER-RENDERED PAGE, NOT A CLIENT-SIDE DIALOG. There is no
 * JavaScript on this origin (`script-src 'none'`), so /message/<id> renders
 * the list AND the dialog, and closing it is a link back to the list.
 *
 * Two consequences, both handled here and neither hidden:
 *   * the list behind carries `inert` in the markup, so it is out of the tab
 *     order and cannot be clicked through the backdrop;
 *   * Escape does NOT close it. The Close control is first in the dialog and
 *     carries autofocus, and the backdrop is a link, so pointer and keyboard
 *     both have a one-action exit. Escape would need script.
 */
.ck-backdrop {
    position: fixed; inset: 0; background: rgba(35, 31, 32, 0.55);
    z-index: 10; display: block;
}
.ck-modal {
    position: fixed; z-index: 11;
    left: 50%; transform: translateX(-50%);
    top: 1.5rem; bottom: 1.5rem;
    width: min(60rem, calc(100% - 2rem));
    background: var(--bg); border: 1px solid var(--ck-black);
    border-radius: 6px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
    display: flex; flex-direction: column; overflow: hidden;
}
.ck-modal-head {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.75rem var(--pad);
    border-bottom: 1px solid var(--rule); background: var(--bg-bar);
}
.ck-modal-head h2 {
    margin: 0; font-size: 1.0625rem; flex: 1 1 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ck-modal-sub {
    display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap;
    background: var(--bg-alt); border-bottom: 1px solid var(--rule);
    padding: 0.5625rem var(--pad); font-size: 0.9375rem;
}
.ck-modal-sub .ck-spacer { flex: 1 1 auto; }
/* `.ck-modal` sets `overflow: hidden`, so a long sender address -- one
 * unbreakable token with no word-break anywhere on this row -- was silently
 * CLIPPED mid-domain rather than wrapped or scrolled, on the exact surface
 * where "who really sent this" is the decision being made. */
.ck-modal-sub > span { min-width: 0; overflow-wrap: anywhere; }
.ck-modal-body { overflow-y: auto; padding: var(--pad); flex: 1 1 auto; }
.ck-modal-foot {
    display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;
    padding: 0.75rem var(--pad);
    border-top: 1px solid var(--rule); background: var(--bg-bar);
}
.ck-modal-foot .ck-spacer { flex: 1 1 auto; }

/* The "delete these?" list inside the confirmation dialog. A plain <ul> put
 * the subject and the sender on one run-on line at bullet indent, which is
 * the wrong shape for the thing somebody is checking before destroying it --
 * they are scanning for "is one of these the message I actually wanted".
 * Bordered rows, no bullets, and a scroll cap so a 200-message selection
 * cannot push the buttons off the bottom of the viewport. */
.ck-msglist {
    list-style: none; margin: 0 0 var(--pad); padding: 0;
    max-height: 18rem; overflow-y: auto;
    border: 1px solid var(--rule); border-radius: var(--radius);
}
.ck-msglist li {
    padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--rule);
}
.ck-msglist li:last-child { border-bottom: 0; }
.ck-msglist small { color: var(--ck-n); }

/* Band separator rows inside the Metrics tab's score distribution. The table
 * is one continuous run of integer scores and the bands are the only thing
 * that gives it meaning, so the boundary has to be visible as a boundary
 * rather than inferred by reading the numbers against actions.conf. */
.ck-bandhead {
    text-align: left; font-size: 0.875rem; font-weight: 600;
    background: var(--bg-alt); border-top: 2px solid var(--accent);
    padding: 0.4rem var(--pad);
}
.ck-modal-foot form { display: contents; }
/* The list behind an open dialog. `inert` is an HTML attribute and needs no
 * script; this only removes the pointer affordance. */
[inert] { user-select: none; }

/* ===========================================================================
 * MESSAGE RENDERING. The riskiest surface in the system.
 * ======================================================================== */

.ck-msg-plain {
    font-family: var(--mono); font-size: 0.875rem;
    white-space: pre-wrap; word-break: break-word;
    background: var(--bg-alt); padding: var(--pad);
    border: 1px solid var(--rule); border-radius: var(--radius);
}
/* The sandboxed iframe an opted-in HTML part renders in. Bordered and
 * labelled so it never reads as part of the portal's own chrome -- a
 * quarantined message must not be able to look like this page. */
iframe.ck-msg-html {
    width: 100%; min-height: 24rem;
    border: 2px dashed var(--danger); border-radius: var(--radius);
    background: var(--ck-white);
}
.ck-hostile-banner {
    background: var(--ck-error-bg); color: var(--ck-error);
    border: 1px solid var(--ck-error); border-left-width: 4px;
    padding: 0.5rem var(--pad); font-weight: 600; font-size: 0.9375rem;
    margin: 0 0 var(--pad);
}

/* ===========================================================================
 * SETTINGS AND POLICIES
 * ======================================================================== */

.ck-section { margin-bottom: 2.125rem; }
.ck-section > .ck-section-head {
    border-bottom: 2px solid var(--ck-black); padding-bottom: 0.5rem;
}
.ck-section h2 { margin: 0; font-size: 1.1875rem; font-weight: 700; }
.ck-section-head p { margin: 0.25rem 0 0; font-size: 0.9375rem; color: var(--fg-muted); }

.ck-field {
    display: grid; grid-template-columns: 13.75rem 1fr; gap: 1.5rem;
    align-items: start; padding: 1.125rem 0;
    border-bottom: 1px solid var(--ck-n-lightest);
}
.ck-field > label { padding-top: 0.625rem; margin: 0; font-size: 0.9375rem; }
/* Secondary explanatory text. Used inside a field, and on its own under the
 * policy lists and the digest block, so it is NOT scoped to .ck-field. */
.ck-hint { font-size: 0.875rem; color: var(--fg-muted); margin: 0.375rem 0 0; }
@media (max-width: 40rem) { .ck-field { grid-template-columns: 1fr; gap: 0.25rem; } }

/* A segmented control built from radios, so it works with no script and stays
 * a real fieldset for a screen reader. The input is visually hidden but still
 * focusable -- :focus-within is what draws the ring on the label. */
.ck-seg { display: inline-flex; border-radius: var(--radius); overflow: hidden;
          border: 1px solid var(--ck-n-light); }
.ck-seg label {
    margin: 0; font-weight: 400; font-size: 0.9375rem;
    padding: 0.625rem 1.25rem; cursor: pointer; background: var(--bg);
    border-right: 1px solid var(--ck-n-light);
}
.ck-seg label:last-child { border-right: 0; }
.ck-seg input { position: absolute; opacity: 0; pointer-events: none; }
.ck-seg input:checked + span { font-weight: 600; }

/* 🔴 THE SELECTED SEGMENT IS GOLD, NOT BLACK, AND THAT IS TO STOP IT LOOKING
 * LIKE A BUTTON. Reported 2026-09-24, on both Settings pages.
 *
 * Black fill was carrying two meanings at once in this stylesheet: "this is
 * the action" (every primary button -- Release, Sign in, Filter, Save) and
 * "this one is selected". On the Settings pages those sit one under the other,
 * so `Save` read as a third chosen option rather than as the thing that
 * commits the other two. A reader cannot tell state from action when both are
 * the same swatch, and the action is the one that must not be mistaken.
 *
 * The BUTTON keeps black, because that convention is everywhere and is the
 * stronger claim on the colour; the STATE moves. Gold is the right home for it
 * -- the palette note above records gold as a fill colour and never a text
 * colour (1.70:1 on white), and this is a fill. Brand black on gorilla gold
 * measures 9.58:1, well past AA for the 15px face this control uses.
 *
 * Deliberately NOT applied to .ck-chip-on, which is still black and has the
 * same collision next to the Filter button. That is a wider change across five
 * pages and is the operator's call, not a tidy-up to slip in here. */
.ck-seg label:has(input:checked) {
    background: var(--accent); color: var(--ck-black);
}
.ck-seg label:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: -3px; }
/* Fallback for engines without :has() -- the checked state is also written
 * into a class server-side, so the control is never ambiguous.
 *
 * 🔴 AND IT IS SCOPED TO THOSE ENGINES, WHICH IT WAS NOT. Reported from the
 * staff Settings tab 2026-09-24, and it affected the subscriber's own Settings
 * tab identically, since both draw this control from app._segmented().
 *
 * `ck-on` is written by the SERVER, at render time, onto whichever option was
 * saved. `:has(input:checked)` is evaluated by the BROWSER and follows the
 * pointer. On any engine that has both -- which is every current one -- the
 * moment somebody clicks the other option there are two black segments: the
 * live one, and the stale class the page was built with. The fallback was
 * defeating the rule it exists to back up, and the control answered "which one
 * am I on" with "both", which is the exact failure its own comment says it is
 * there to prevent.
 *
 * @supports NOT selector(:has(*)) confines it to engines that genuinely cannot
 * do the live version. Where :has() works the class is inert and the highlight
 * follows the click; where it does not, the server-rendered state is still
 * drawn and the control still reads correctly on load. */
@supports not selector(:has(*)) {
    .ck-seg label.ck-on { background: var(--accent); color: var(--ck-black); }
}

.ck-lists { display: grid; grid-template-columns: 1fr 1fr; gap: 1.625rem;
            align-items: start; }
@media (max-width: 56rem) { .ck-lists { grid-template-columns: 1fr; } }
/* One list. Kept to a single column's width rather than stretched across the
 * grid: a lone full-width card reads as a page that lost something. */
.ck-lists-one { grid-template-columns: minmax(0, 30rem); }
.ck-listbox { border: 1px solid var(--rule); border-radius: 5px; overflow: hidden; }
.ck-listbox > header {
    padding: 0.8125rem 0.875rem; border-bottom: 1px solid var(--rule);
    border-left: 5px solid var(--ck-n-light); background: var(--bg);
}
.ck-listbox.ck-allow > header { border-left-color: var(--ck-success); }
.ck-listbox.ck-hold  > header { border-left-color: var(--danger); }
.ck-listbox header strong { font-size: 1.0625rem; }
.ck-listbox header p { margin: 0.1875rem 0 0; font-size: 0.875rem; color: var(--fg-muted); }
.ck-listbox ul { list-style: none; margin: 0; padding: 0; }
.ck-listbox li {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.625rem 0.75rem; border-bottom: 1px solid var(--ck-n-lightest);
}
.ck-listbox li .ck-entry { font-family: var(--mono); font-size: 0.9375rem;
                           word-break: break-all; }
.ck-listbox li .ck-spacer { flex: 1 1 auto; }
.ck-listbox li form { display: contents; }
.ck-listbox li button {
    font-size: 0.875rem; padding: 0.4375rem 0.875rem;
    background: var(--bg); color: var(--danger); border-color: var(--danger);
}
.ck-listbox .ck-adder {
    display: flex; gap: 0.5rem; padding: 0.875rem 0.75rem;
    background: var(--bg-bar); border-top: 1px solid var(--rule);
}
.ck-listbox .ck-adder form { display: contents; }
.ck-listbox .ck-empty { padding: 1rem 0.875rem; color: var(--fg-muted);
                        font-size: 0.9375rem; }

/* The "your administrator also maintains a list" notice. Gold, because it is
 * information rather than a warning -- red is reserved. */
.ck-admin-note {
    margin-top: 1.625rem; border: 1px solid var(--ck-n-light);
    border-left: 5px solid var(--accent); border-radius: 5px;
    padding: var(--pad) 1.125rem; background: #fffdf5;
}
.ck-admin-note p { margin: 0.375rem 0 0; font-size: 0.9375rem;
                   color: var(--ck-n-dark); max-width: 68ch; }

/* Accepted languages (2026-10-19): one checklist shared by the subscriber's
 * Policies tab and both staff Policies tabs (app.lang_checklist). One
 * alphabetical list in balanced columns, English first (operator, 16:55). */
.ck-langs { margin-top: 0.75rem; }
.ck-lang-mode label { display: block; margin: 0.375rem 0; }
.ck-lang-list {
    columns: 4 11rem; column-gap: 1.25rem; margin: 0.5rem 0 1rem;
    border: 1px solid var(--rule); border-radius: 5px; padding: 0.625rem 0.875rem;
}
.ck-lang-list label {
    display: flex; align-items: center; gap: 0.375rem; break-inside: avoid;
    padding: 0.1875rem 0; font-size: 0.9375rem;
}
.ck-lang-list .ck-lang-always { font-weight: 600; }
.ck-lang-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

footer {
    margin-top: 2rem; padding: var(--pad);
    border-top: 1px solid var(--rule);
    color: var(--fg-muted); font-size: 0.875rem;
}

/* ===========================================================================
 * NARROW VIEWPORTS
 * ======================================================================== */
/* 🔴 THERE WAS NONE OF THIS. Before 2026-09-10 the only media queries in this
 * file were `.ck-field` at 40rem, `.ck-lists` at 56rem and
 * prefers-reduced-motion -- nothing in the header, the tab strip, the toolbar,
 * the meta line or the held-mail table had ANY narrow-viewport handling.
 * Everything phone-shaped on the Messages tab was accidental flex wrapping,
 * and a real phone screenshot showed what that produced: 82% of the usable
 * screen spent on chrome, one message row visible out of six held, the Risk
 * pill scrolled off the right edge with no scroll cue, and two stranded
 * separators that read as rendering damage.
 *
 * Two breakpoints, both max-width so the approved desktop design is untouched:
 *   48rem  the toolbar stops pretending to be one row
 *   40rem  the phone layout proper -- the list becomes cards
 * Plus a pointer:coarse block for touch targets, which is orthogonal to width:
 * a 13px text link is too small on a 1024px tablet too.
 */

@media (max-width: 48rem) {
    /* Both of these are decorations for a single-row toolbar that no longer
     * exists. `.ck-sep` was the visible one: a 1px, full-height hairline left
     * as the LAST item of a wrapped line, separating nothing, which reads as a
     * text cursor or a glitch. `.ck-spacer` was invisible but worse -- it
     * grows into all remaining space on whatever line it lands on, so the
     * toolbar's intended left/right split silently evaporated. */
    .ck-toolbar .ck-sep,
    .ck-toolbar .ck-spacer { display: none; }
    .ck-toolbar { row-gap: 0.5rem; }

    /* An 11rem cap that existed to stop this note competing with Refresh on a
     * wide toolbar. On its own wrapped row it only forced "Reloads every
     * 3 min · stop" onto three lines, with `stop` -- the WCAG 2.2.1 off
     * switch -- stranded as a 13px link. */
    .ck-auto { max-width: none; }

    .ck-meta .ck-spacer { display: none; }
    .ck-meta { gap: 0.5rem; }
}

@media (max-width: 40rem) {
    /* ---- header: stack it, and stop aligning against invisible boxes ---- */
    .ck-header { row-gap: 0.5rem; padding-bottom: 0.5rem; }
    .ck-header .ck-spacer { display: none; }
    .ck-support, .ck-ident { text-align: left; flex: 1 1 100%; }
    .ck-support { font-size: 0.8125rem; }
    .ck-support strong { display: inline; }          /* one line, not two */
    /* Address left, Sign out hard right -- the alignment the desktop gets
     * from `.ck-spacer`, done with a property that works on one line too. */
    .ck-ident { justify-content: space-between; }
    .ck-who { overflow: hidden; text-overflow: ellipsis; }

    /* Three tabs at 22px of side padding needed ~364px, so at 360px -- iPhone
     * SE, Galaxy S8/S9/S10e -- the strip overflowed and took the whole page
     * sideways with it. Shrinking the padding keeps all three visible;
     * `overflow-x` here would clip the tabs' top radius against the gold rule
     * and break the sheet-of-paper effect that rule exists for. */
    .ck-tab { padding-left: 0.875rem; padding-right: 0.875rem; }
    .ck-subtab { padding-left: 0.625rem; padding-right: 0.625rem; }

    /* The address is already in the header; this repeated it 60px later. */
    main.ck-wide > h1 { font-size: 1.125rem; margin: 0.75rem var(--pad) 0.5rem; }
    .ck-toolbar { padding: 0.625rem var(--pad); gap: 0.375rem; }

    /* ---- the held-mail list becomes CARDS ----
     *
     * Five columns needed ~580px of min-content against a 358px box, so the
     * table overflowed into `.ck-scroll` and took Subject and Risk with it --
     * and Android Chrome's overlay scrollbar does not show at rest, so the
     * columns were undiscoverable. `.ck-pickbox` is not sticky either, so
     * scrolling right to read a subject scrolled its checkbox out of view:
     * you could not see what you were ticking.
     *
     * `display: grid` on the <tr> rather than plain `display: block` is what
     * keeps the checkbox in a left gutter spanning the stacked lines, so
     * "tick rows, then use the actions above" still works. Cells are placed by
     * CLASS, not nth-child, so moving a column cannot silently rearrange this.
     *
     * ⚠️ HIDING <thead> REMOVES THE FOUR SORT LINKS. Sorting is unavailable on
     * a phone. That is a real loss, accepted for now: the day-range chips
     * still filter, the default is newest-first, and a subscriber holding a
     * page of 25 is usually looking for something they can see. If sort must
     * survive, emit the same four links again as a chip row styled like
     * `.ck-ranges` and show it only under this breakpoint. */
    .ck-scroll { overflow-x: visible; }
    table.ck-list thead { display: none; }
    table.ck-list,
    table.ck-list tbody,
    table.ck-list tr,
    table.ck-list td { display: block; }
    table.ck-list tr {
        display: grid;
        grid-template-columns: 2.75rem minmax(0, 1fr) auto;
        grid-template-areas:
            "pick subj risk"
            "pick from from"
            "pick when when";
        align-items: start;
        column-gap: 0.25rem;
        padding: 0.5rem 0.5rem 0.625rem;
        border-bottom: 1px solid var(--rule);
    }
    table.ck-list td { border: 0; padding: 0; }
    table.ck-list tbody tr:hover td { background: transparent; }
    table.ck-list tr.ck-open { background: #fff8e6; }
    /* `align-self: center` centred the checkbox in a three-line card, which
     * put it level with the SENDER line -- so it read as belonging to the
     * sender rather than to the row. Aligned to the start it sits beside the
     * subject, which is what ticking it acts on. */
    table.ck-list td.ck-pickbox { grid-area: pick; width: auto; align-self: start; }
    table.ck-list .ck-pick { margin: 0; }
    table.ck-list td.ck-subj  { grid-area: subj; font-size: 1rem; line-height: 1.35; }
    table.ck-list td.ck-risk  { grid-area: risk; justify-self: end; padding-left: 0.5rem; }
    table.ck-list td.ck-from  { grid-area: from; font-size: 0.9375rem;
                                color: var(--ck-n-dark); margin-top: 0.1875rem; }
    table.ck-list td.ck-when  { grid-area: when; font-size: 0.8125rem;
                                color: var(--fg-muted); margin-top: 0.125rem; }

    /* ---- the message pop-up: full bleed ----
     * `top/bottom: 1.5rem` spent 48px on a decorative gutter that only makes
     * sense over a desktop backdrop -- and `position: fixed` with `bottom` on
     * iOS resolves against a viewport that changes as the browser toolbar
     * collapses, so the footer carrying Release and Delete could end up under
     * it. `100dvh` tracks the visual viewport instead. */
    .ck-modal {
        left: 0; right: 0; top: 0; bottom: 0; transform: none;
        width: 100%; height: 100dvh; border: 0; border-radius: 0;
    }

    /* `.ck-entry` has word-break: break-all, so with no wrap on the row the
     * address absorbed the whole shortfall and rendered as a two-character
     * column broken every few glyphs -- the one piece of information on the
     * row was the one destroyed. */
    .ck-listbox li { flex-wrap: wrap; }
    .ck-listbox li .ck-entry,
    .ck-listbox li .ck-hint { flex: 1 1 100%; }
    .ck-listbox li .ck-spacer { display: none; }
}

/* ---- touch targets, independent of width ----
 * `--btn-pad-y`/`--btn-pad-x` buy 46px for `button` and `.ck-btn` only.
 * Everything that sets its own padding, or is a bare anchor, bypassed them:
 * the range chips (36px), the segmented labels (42.5px), the Policies Remove
 * button (35px -- and it is destructive), the pager links (~24px), the
 * auto-reload off switch (~19px) and "Show details" (~22px). */
@media (pointer: coarse) {
    .ck-ranges a, .ck-ranges strong,
    .ck-pager a,
    .ck-auto a,
    .ck-modal-sub a,
    .ck-listbox li button,
    .ck-seg label {
        min-height: 2.75rem; display: inline-flex; align-items: center;
    }
    .ck-seg label { justify-content: center; }
    /* A fingertip is wider than the 8px that sat between "send me this mail"
     * and "destroy this mail", with no disabled state on either. */
    .ck-toolbar { gap: 0.625rem; }
}

/* ===========================================================================
 * PRINT
 * ======================================================================== */
/* THERE IS NO PRINT BUTTON. It was removed 2026-09-10: without script it could
 * only render a chrome-free page and then ask the subscriber to use their own
 * browser's Print command -- which is what that command already does. These
 * rules are kept anyway, because they are the reason Ctrl-P on any page here
 * comes out as the list or the message rather than the list plus a black
 * header, a tab strip, a toolbar and a footer. */
@media print {
    .ck-header, .ck-tabs, .ck-rule, .ck-subtabs, .ck-subrule,
    .ck-toolbar, .ck-meta, .ck-selbar,
    .ck-pager, footer, .ck-backdrop, .ck-pickbox { display: none !important; }
    .ck-modal { position: static; transform: none; width: auto;
                border: 0; box-shadow: none; }
    [inert] { display: none !important; }
    a { color: #000; text-decoration: none; }
    body { font-size: 11pt; }
    table.ck-list { font-size: 10pt; }
    table.ck-list thead th { background: #eee !important;
                             -webkit-print-color-adjust: exact;
                             print-color-adjust: exact; }
}

/* Respect the subscriber's own preferences. */
@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

/* ===========================================================================
 * THE STAFF VIEW (/staff) -- phase 3b step 10, 2026-09-11.
 *
 * Same visual system, same palette, no new colours and no new fonts. It is
 * deliberately NOT styled to look like a different product: a staff member
 * looking at a held message must see it laid out the way the subscriber does,
 * because the support call is "what does MY page say", and two layouts would
 * make that conversation harder for no benefit.
 *
 * One visual difference is intentional -- the score bars on the release-rate
 * page, which exist because there is no script and a column of numbers hides
 * the shape of a distribution, which is the entire reason for looking at it.
 * ======================================================================== */

.ck-stack { display: flex; flex-direction: column; gap: .5rem;
            max-width: 26rem; margin: var(--pad) 0; }
.ck-stack label { font-weight: 600; font-size: .9rem; }
.ck-stack input, .ck-stack select { padding: .5rem; font: inherit;
            border: 1px solid var(--rule); border-radius: var(--radius);
            background: var(--bg); color: var(--fg); }
.ck-stack button { align-self: flex-start; margin-top: .25rem; }

.ck-searchbar { display: flex; flex-wrap: wrap; gap: .5rem;
            align-items: center; margin: var(--pad) 0; }
/* Every visible text box in a search bar, not only the one named `q`.
 * Reported 2026-10-01 on Find mail: its box is `<input name="account">`
 * with no type attribute, so the site-wide input[type="text"] rule never
 * matched it and it drew at the browser's default height beside a 46px
 * button; the policy-add box (`pattern`) had the same gap, and `q` sat at
 * .5rem, a size between the two. 0.75rem is the padding every other text
 * input on the site uses, so the box and the button come out the same
 * height. :not([type="hidden"]) because these forms carry hidden fields. */
.ck-searchbar input:not([type="hidden"]) { flex: 1 1 22rem; min-width: 12rem;
            padding: 0.75rem; font: inherit; font-size: 0.9375rem;
            border: 1px solid var(--rule);
            border-radius: var(--radius); background: var(--bg);
            color: var(--fg); }
/* font-size 0.9375rem above: the buttons' size, so box and button are the
 * SAME height, not 1.5px apart -- see the .ck-toolbar input note. */
/* The two boxes that hold ONE ADDRESS (Find mail's `account`, the policy
 * list's `pattern`) do not grow with the row: on the 90rem staff page the
 * shared flex rule above made the lookup box most of the screen wide for a
 * 30-character value (reported 2026-10-01). 28rem fits the longest address
 * in the directory with room; they still shrink on a narrow screen. The
 * filter box `q` keeps growing, which is right for a search field. */
.ck-searchbar input[name="account"],
.ck-searchbar input[name="pattern"] { flex: 0 1 28rem; }
.ck-searchbar select { padding: .45rem; font: inherit;
            border: 1px solid var(--rule); border-radius: var(--radius);
            background: var(--bg); color: var(--fg); }

/* The filter chips on the audit and release-rate pages. Links, not buttons --
 * they change what is displayed, they change nothing on the server, and a GET
 * is the correct method for that. */
.ck-chip { display: inline-block; padding: .3rem .7rem; margin: 0 .25rem .35rem 0;
           border: 1px solid var(--rule); border-radius: 999px;
           text-decoration: none; color: var(--fg); font-size: .9rem;
           background: var(--bg); }
.ck-chip:hover { background: var(--bg-alt); }
.ck-chip-on { background: var(--ck-black); color: var(--ck-white);
              border-color: var(--ck-black); }

/* The message metadata table. NOT .ck-meta -- that name is already the
 * Messages toolbar and reusing it would inherit a flex layout. */
.ck-msgmeta { border-collapse: collapse; margin: var(--pad) 0;
              max-width: 60rem; width: 100%; }
.ck-msgmeta th { text-align: left; vertical-align: top; padding: .35rem .75rem .35rem 0;
                 color: var(--fg-muted); font-weight: 600; white-space: nowrap;
                 width: 9rem; }
.ck-msgmeta td { padding: .35rem 0; vertical-align: top;
                 overflow-wrap: anywhere; }
.ck-msgmeta code { font-family: var(--mono); font-size: .9em; }

.ck-num { text-align: right; font-variant-numeric: tabular-nums;
          white-space: nowrap; }
.ck-detail { color: var(--fg-muted); font-size: .9rem;
             overflow-wrap: anywhere; }
.ck-symbols { font-family: var(--mono); font-size: .8rem; white-space: pre-wrap;
              overflow-wrap: anywhere; background: var(--bg-alt);
              padding: .75rem; border-radius: var(--radius); }

/* Release rate by score. The bar is a plain element sized with an inline
 * width -- the one place this stylesheet accepts an inline style, because the
 * value is data and there is no script to set it from a data- attribute. */
.ck-rates .ck-barcell { width: 45%; padding-right: .75rem; }
.ck-bar { display: block; height: .8rem; border-radius: 2px;
          background: var(--ck-n-light); min-width: 2px; }
/* Gold, not red: a high release rate is a FINDING, not a fault. It means the
 * threshold is in the wrong place, which is exactly what this page is for. */
.ck-bar-hot { background: var(--accent); }
.ck-rates tfoot th { border-top: 2px solid var(--rule); padding-top: .5rem; }

/* Metrics sections collapse (operator, 2026-10-07). <details>, no script.
 * The panel itself takes NO gutter -- the wide-page rule above would give it
 * one, and its tables are meant to run edge to edge -- so the summary and
 * the notes inside bring the gutter themselves, as they did when they sat
 * directly in <main>. The heading keeps its size; the marker is a plain
 * triangle that turns (no transition: nothing here animates), so "this
 * opens" is visible without hovering. */
main.ck-wide > details.ck-metric { margin: 0 0 1.5rem; }
.ck-metric > summary { cursor: pointer; list-style: none;
                       margin: 0 var(--pad); display: flex;
                       align-items: baseline; gap: .5rem; }
.ck-metric > summary::-webkit-details-marker { display: none; }
.ck-metric > summary::before { content: "\25B8"; color: var(--fg-muted);
                               display: inline-block; }
.ck-metric[open] > summary::before { transform: rotate(90deg); }
.ck-metric > summary h2 { display: inline; }
.ck-metric > :is(p, pre) { margin-left: var(--pad); margin-right: var(--pad); }

.ck-audit td { vertical-align: top; }
.ck-audit code { font-family: var(--mono); font-size: .85em; }

.ck-users .ck-controls { white-space: normal; }

/* ===========================================================================
 * STAFF ACCOUNTS -- a disclosure panel per account (2026-09-21)
 * ========================================================================
 * Replaced a six-column table whose last cell held four forms. The summary
 * keeps the scannability a table gave; the open panel gives the controls the
 * width a table cell never had. <details> does it with no script, which is
 * not a preference here -- script-src is 'none'.
 *
 * ONE GRID, DECLARED TWICE: the header strip and every summary share these
 * track sizes, which is what makes the collapsed rows line up like a table.
 * Change one and change the other, or the columns drift apart. */
.ck-acct-head, .ck-acct-sum {
    display: grid;
    grid-template-columns:
        minmax(9rem, 1.4fr)    /* person   */
        minmax(7rem, 1fr)      /* username */
        minmax(11rem, 1.8fr)   /* e-mail   */
        6.5rem                 /* role     */
        6.5rem                 /* state    */
        minmax(8rem, .9fr);    /* last seen*/
    gap: .75rem; align-items: center;
}
.ck-acct-head {
    padding: .4rem .75rem .4rem 2rem;   /* 2rem left clears the marker column */
    font-size: .75rem; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--fg-muted);
    border-bottom: 2px solid var(--ck-black);
}

.ck-acct { border-bottom: 1px solid var(--ck-n-lightest); }
.ck-acct-sum {
    padding: .6rem .75rem .6rem 2rem; cursor: pointer; position: relative;
    font-size: .9375rem; list-style: none;
}
/* The default triangle is replaced by one we can place, because the marker
 * has to sit in that 2rem gutter for the grid tracks to start at the same x
 * on the header and on every row. ::-webkit-details-marker is still needed
 * for Safari, which ignores `list-style` on <summary>. */
.ck-acct-sum::-webkit-details-marker { display: none; }
.ck-acct-sum::before {
    content: "\25B8"; position: absolute; left: .85rem; top: 50%;
    transform: translateY(-50%); color: var(--fg-muted);
    transition: transform .12s ease;
}
.ck-acct[open] > .ck-acct-sum::before { transform: translateY(-50%) rotate(90deg); }
.ck-acct-sum:hover { background: var(--bg-alt); }
.ck-acct-sum:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
.ck-acct[open] > .ck-acct-sum { background: var(--bg-alt); }

.ck-acct-user, .ck-acct-mail, .ck-acct-seen {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ck-acct-mail { font-size: .875rem; }
.ck-acct-seen { font-size: .875rem; color: var(--fg-muted); }

.ck-acct-body { padding: .25rem 1rem 1.25rem 2rem; }
.ck-acct-body h3 {
    font-size: .8125rem; text-transform: uppercase; letter-spacing: .04em;
    color: var(--fg-muted); margin: 1.25rem 0 .5rem;
}
.ck-acct-body .ck-msgmeta { margin-top: .5rem; }
.ck-acct-actions { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }

/* One action row: labelled fields that grow, button that does not. */
.ck-acct-row { display: flex; flex-wrap: wrap; gap: .75rem; align-items: flex-end; }
.ck-acct-lbl {
    display: flex; flex-direction: column; gap: .2rem;
    font-size: .8125rem; color: var(--fg-muted);
}
.ck-acct-lbl.ck-grow { flex: 1 1 18rem; }

/* The one-time password in the create confirmation. Big, monospaced and
 * selectable, because its whole job is to be read off the screen accurately
 * and typed somewhere else -- often read aloud. Letter-spacing so the groups
 * separate; the generator already drops i/l/1/o/0 for the same reason. */
.ck-onetime {
    display: inline-block; margin-top: .35rem;
    font-family: var(--mono); font-size: 1.125rem; font-weight: 700;
    letter-spacing: .08em; user-select: all;
    padding: .4rem .7rem; border-radius: var(--radius);
    background: var(--bg); border: 1px solid var(--rule); color: var(--fg);
}
.ck-acct-lbl input {
    font: inherit; padding: .35rem .5rem; border: 1px solid var(--rule);
    border-radius: var(--radius); background: var(--bg); color: var(--fg);
}

/* Narrow: the grid stops being a table and becomes a stack, because six
 * tracks in 360px is six unreadable columns. The header strip goes with it --
 * labels for columns that no longer exist are worse than no labels, so each
 * cell carries its own instead. */
@media (max-width: 52rem) {
    .ck-acct-head { display: none; }
    .ck-acct-sum { grid-template-columns: 1fr auto; gap: .25rem .5rem; }
    .ck-acct-who { grid-column: 1; font-size: 1rem; }
    .ck-acct-role, .ck-acct-state { grid-column: 2; justify-self: end; }
    .ck-acct-user::before { content: "user "; color: var(--fg-muted); }
    .ck-acct-mail::before { content: "e-mail "; color: var(--fg-muted); }
    .ck-acct-seen::before { content: "last seen "; }
    .ck-acct-user, .ck-acct-mail, .ck-acct-seen {
        grid-column: 1 / -1; white-space: normal; font-size: .8125rem;
    }
    .ck-acct-body { padding-left: 1rem; }
}
.ck-inline { display: inline-flex; gap: .25rem; align-items: center;
             margin: 0 .3rem .3rem 0; }
.ck-inline input[type="password"] { width: 9rem; padding: .3rem; font: inherit;
             border: 1px solid var(--rule); border-radius: var(--radius); }
.ck-actions { margin: var(--pad) 0; }

/* .ck-primary is the default button; the class exists so a template can say
 * which one it means rather than relying on the absence of a class. */
button.ck-primary, .ck-btn.ck-primary { /* inherits the base button rules */ }

@media (max-width: 40rem) {
    .ck-searchbar input:not([type="hidden"]) { flex: 1 1 100%; }
    .ck-msgmeta th { width: auto; }
}

/* --- The staff Status tab (2026-09-11) ---------------------------------- */

/* One vocabulary for every state on that page. Shape as well as colour: the
 * pill is legible in print, and to a reader who cannot distinguish the
 * green from the red. */
.ck-pill { display: inline-block; min-width: 3.2rem; text-align: center;
           padding: .1rem .45rem; border-radius: 3px; font-size: .75rem;
           font-weight: 700; letter-spacing: .03em; border: 1px solid; }
.ck-pill-ok      { color: var(--ck-success); border-color: var(--ck-success);
                   background: var(--ck-success-bg); }
.ck-pill-warn    { color: #7a4b02; border-color: var(--accent);
                   background: #fff8e6; }
.ck-pill-crit    { color: var(--ck-error); border-color: var(--ck-error);
                   background: var(--ck-error-bg); }
.ck-pill-unknown { color: var(--fg-muted); border-color: var(--rule);
                   background: var(--bg-alt); }

.ck-status td { vertical-align: top; }
.ck-status td:first-child { width: 4.5rem; }
.ck-status .ck-detail { font-family: var(--mono); font-size: .78rem;
                        line-height: 1.45; }
.ck-vols .ck-barcell { width: 35%; }
.ck-vols td { vertical-align: middle; }

/* The "Needs attention" block is a .ck-error carrying a list, so the list
 * needs its margins back inside that box. */
.ck-error ul, .ck-note ul, .ck-ok ul { margin: .4rem 0 0 1.1rem; padding: 0; }
.ck-error li, .ck-note li, .ck-ok li { margin: .15rem 0; }

@media (max-width: 40rem) {
    .ck-status .ck-detail { font-size: .72rem; }
    .ck-vols .ck-barcell { display: none; }
}

/* --- 404 (2026-09-11) ---------------------------------------------------
 * Operator instruction: a 404 must be recognisable as one by a human. The
 * code is set large because that is the whole point -- somebody who mistyped
 * an address should know it at a glance, without reading. */
.ck-404 { text-align: center; padding: 2.5rem 1rem 3rem; }
.ck-404-code { font-size: clamp(3.5rem, 14vw, 6rem); line-height: 1;
               font-weight: 800; letter-spacing: -.02em; margin: 0 0 .25rem;
               color: var(--ck-n-lighter); }
.ck-404 h1 { font-size: 1.25rem; margin: 0 0 .75rem; }
.ck-404 .ck-note { display: inline-block; text-align: left; max-width: 30rem; }

/* --- The staff mailbox view (2026-09-11) -------------------------------- */
.ck-mailbox td { vertical-align: top; }
.ck-mailbox .ck-controls { white-space: nowrap; }
.ck-mailbox .ck-controls .ck-inline { margin: 0 .2rem .2rem 0; }
/* The Clear link beside the filter box once sat at .45rem/.8rem to match a
 * .5rem input; the inputs are now button-height, so it takes the base
 * .ck-btn padding and lines up with the button and the box alike. */

/* --- Controls that live INSIDE a .ck-stack form (2026-10-01) ---------------
 * .ck-stack styles every descendant `label` (bold, .9rem) and `input`
 * (padding, border) as a field heading and a text box, because that is what
 * its forms held until now. The staff profile's density control and the
 * sign-in checkbox are neither, and inherited both by accident: the
 * segmented control's labels went bold -- which is its "checked" cue -- and
 * the whole control stretched to the stack's width as a flex item; the
 * checkbox grew a padded border. Found by reading the rules after shipping,
 * not by looking at the page -- the Settings pages avoid all of this by
 * wrapping the same control in a .ck-field grid instead. */
.ck-seg-row { align-self: flex-start; }
.ck-stack .ck-seg label { font-weight: 400; font-size: 0.9375rem; }
.ck-stack .ck-seg input:checked + span { font-weight: 600; }
.ck-check { display: flex; align-items: center; gap: 0.5rem; cursor: pointer;
            font-weight: 400; font-size: 0.9375rem; }
.ck-stack .ck-check input,
.ck-check input { width: 1.125rem; height: 1.125rem; margin: 0; flex: none;
                  padding: 0; border: 0; border-radius: 0; background: none; }

/* --- Compact staff lists, per account (2026-10-01, sql/019) --------------
 * Set from /staff/profile; the body carries `ck-compact` when the signed-in
 * staff account chose it. SCOPED TWICE, on purpose: under the body class so
 * nobody who has not chosen it sees a change, and under `table.ck-mailbox`
 * so even for those who have, only the staff mailbox list changes. The
 * subscriber portal never renders either class, so its 46px Release/Delete
 * targets (the --btn-pad-y note above) and the .ck-pick negative-margin
 * trick, which assumes the default cell padding, are untouched. A tester
 * arrived at these numbers by removing the button padding entirely and
 * taking cells to 0.25rem; this keeps a 32px control, enough for a mouse,
 * and about 60% of the row height. */
body.ck-compact table.ck-mailbox th,
body.ck-compact table.ck-mailbox td { padding-top: 0.3rem; padding-bottom: 0.3rem; }
body.ck-compact table.ck-mailbox .ck-controls button {
  padding: 0.3rem 0.65rem; font-size: 0.875rem;
}
body.ck-compact table.ck-mailbox .ck-controls .ck-inline { margin-bottom: 0.1rem; }

/* --- The staff Reports tab (2026-09-29): mail.ckt.net/reports in a frame --- */
/* Fills the wide main below its heading and note; the height is the viewport
   less the chrome above it, so the framed site scrolls inside the tab rather
   than the tab scrolling the page. The inline `style` attribute is not an
   option here: style-src 'self' blocks it, which is why this is a class. */
iframe.ck-reports-frame {
  display: block;
  width: 100%;
  height: calc(100vh - 14rem);
  min-height: 30rem;
  border: 0;
  border-top: 1px solid var(--line, #ccc);
  background: #fff;
}
