@import "shared-vars.css";
@import "banner.css";

/* ── Eval mailing index — page-specific styles ───────────── */

/* ── Eval variables ──────────────────────────────────────── */

:root {
  --bar-passed: var(--accent, #0050e0);
  --bar-bg: var(--border-default, #e1e4ea);
  /* Opaque equivalent of --bg-card layered over --bg-body over --bg-canvas;
     used as the sticky-header background so rows don't ghost through. */
  --bg-sticky: var(--bg-canvas, var(--ink, #0f1419));
  /* Single source of truth for the sticky filter bar's height: also drives
     the thead `top` offset so the two pinned bands abut without overlap. */
  --filter-bar-h: 60px;
  /* Height of the condensed mobile header (breadcrumb + compact Submit Issue
     button; the title block is hidden). Drives the filter bar's `top` offset.
     4px pad-top + 26px button + 0 pad-bottom = 30px. */
  --mailing-header-h: 30px;
}

/* Centralized focus-visible outline. It matches the
   pattern already used in paper-updates.css/about.css/landing.css/etc. Covers
   every real <a>/<button>/<summary> added across this file, including the
   audience/author badge buttons and the sidebar year-disclosure -- their two
   previous one-off rules are folded into this shared one. */
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── Container ───────────────────────────────────────────── */

.subreddit,
.mailing-page {
  position: relative;
  z-index: 1;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 0.75rem 2.5rem;
}

/* Mailing pages use the wide landing/About shell (--wrap / --pad-x from
   shell.css) instead of the default --page-max, so the slim banner, navbar,
   ISO row, and content table all align at 1760px like the rest of the site. */
.mailing-page { max-width: var(--wrap); padding-inline: var(--pad-x); }
.navbar-inner,
.iso-bar-inner { max-width: var(--wrap); }
.navbar-inner,
.iso-bar-inner { padding-inline: var(--pad-x); }

.mailing-page .breadcrumb-bar,
.mailing-page .page-title {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

/* Breadcrumb and Submit Issue share one row at every breakpoint, so the button
   reads as a header action rather than a CTA above the search. */
.mailing-header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
/* Match the breadcrumb text size so the button sits level with the trail. */
.mailing-header-top .submit-issue-btn { font-size: 0.85rem; }

/* shared-vars.css's .breadcrumb-sep (var(--text-muted) at 0.5 opacity, making
   it difficlt to see on a white background. It is scoped here to match
   .mailing-list-subtitle's color/opacity, instead of leaving it near-invisible. */
.mailing-page .breadcrumb-sep {
  color: var(--text-secondary);
  opacity: 1;
}
.mailing-section-header {
  /* Matches .about-head in foundation.css so the mailings-area pages open at
     the same height as About/Books/Community. */
  padding-top: 56px;
  margin-bottom: 1.5rem;
}

@media (max-width: 720px) {
  .mailing-section-header { padding-top: 36px; }
}

.mailing-section-eyebrow {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 0 0 12px;
}

/* --accent (#007AFF) and --text-muted (#8b95a6) both fail WCAG AA against the
   white page background (~4.0:1 and ~3.0:1); --accent-blue-higher-contrast
   clears it at ~5.6:1. */
.mailing-section-eyebrow .slash { color: var(--accent-blue-higher-contrast); }
.mailing-section-eyebrow .dot { color: var(--accent-blue-higher-contrast); }

.page-count-line {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin: -0.15rem 0 0.5rem;
}

/* ── Filter bar ──────────────────────────────────────────── */

.filter-bar {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: nowrap;
  margin-bottom: 1rem;
  position: sticky;
  top: 0;
  z-index: var(--z-filter-bar);
  background: var(--bg-canvas);
  padding-block: 8px;
  box-sizing: border-box;
  min-height: var(--filter-bar-h);
}

/* ── Audience filter chip bar ── */

.audience-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 1rem;
}

.filter-audience-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: inherit;
  font-family: var(--badge-font);
  font-size: var(--badge-size);
  font-weight: var(--badge-weight);
  line-height: 1.4;
  padding: 4px 12px;
  border-radius: var(--badge-radius);
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-soft, #f6f7f9);
  color: var(--text-secondary);
  cursor: pointer;
  appearance: none;
}

.filter-audience-chip:hover {
  color: var(--text-primary);
  border-color: var(--text-muted, #9aa0aa);
}

.filter-audience-chip.is-active {
  background: var(--accent-blue-higher-contrast);
  border-color: var(--accent-blue-higher-contrast);
  color: #fff;
  font-weight: 600;
}

.filter-audience-caret {
  display: inline-block;
  transition: transform 0.15s;
}

.filter-audience-rollup[aria-expanded="true"] .filter-audience-caret {
  transform: rotate(90deg);
}

.audience-subrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin: -2px 0 8px;
  padding: 7px 12px;
  border-radius: 8px;
  background: var(--bg-soft, #f6f7f9);
}

/* An author-stylesheet `display` rule overrides the browser's default
   `[hidden] { display: none }` (author styles beat the user-agent
   stylesheet), so the class rule above needs this explicit override to
   respect the `hidden` attribute the JS toggles -- otherwise every subrow
   renders open at once regardless of which rollup is expanded. */
.audience-subrow[hidden] {
  display: none;
}

.filter-audience-subchip {
  padding: 3px 10px;
  font-size: 11px;
}

.search-wrap {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 4px;
  padding: 4px 8px;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 8px;
  transition: border-color 0.2s, box-shadow 0.2s;
  cursor: text;
}

.search-wrap:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--border-default, #e1e4ea);
}

.filter-search {
  flex: 1 1 60px;
  min-width: 40px;
  padding: 0.4rem 0.5rem;
  background: transparent;
  border: none;
  color: var(--ink, #0f1419);
  font-family: inherit;
  font-size: 1rem;
  outline: none;
}
/* Shrink input to content width when it has text */
.filter-search.has-text {
  flex: 0 0 auto;
  min-width: 0;
  padding-left: 0.2rem;
  padding-right: 0;
}

.filter-search::placeholder {
  color: var(--ink-faint, #8b95a6);
}

.search-clear {
  /* Reset native <button> chrome, so it keeps its plain-glyph look. */
  appearance: none;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-secondary);
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 4px;
  transition: color 0.15s;
  flex: 0 0 auto;
  order: 0;
}

.search-clear:hover {
  color: var(--text-primary);
}

/* Below the table (not a .filter-bar flex item) so the filter-status sentence
   (e.g. "Showing 12 of 165 papers in EWG or LEWG, by Nina Ranns") has room to
   wrap instead of being squeezed into a fixed-width slot pinned beside the
   search box. The open-std credit sits alongside it, not inside it -- #row-count's
   text is fully owned/overwritten by eval-table.js on every filter change. */
.row-count-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 1rem;
}

.row-count {
  font-size: 13px;
  color: var(--text-secondary);
}

.row-count-credit {
  font-size: 13px;
  color: var(--text-secondary);
}

/* ── Table ────────────────────────────────────────────────── */

.eval-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  /* Opaque fill (matches --bg-sticky / thead) so the rounded top
     corners read as a continuous extension of the header band.
     A translucent fill let the page grid show through the corner
     cutouts as a visible "ghost" against the thead's opaque bg. */
  background: var(--bg-sticky);
  border: 1px solid var(--border-default);
  /* Top edge lives on `thead th` so it travels with the sticky header
     and traces the rounded top corners while pinned. */
  border-top: none;
  border-radius: 12px;
}

/* The visually-last paper card's td border-bottom would stack with the
   table's outer border-bottom for a 2px double line. Drop it. Uses
   .is-card-bottom (JS-applied) instead of :last-child because the true
   DOM last-child is the trailing row-details (always present, often
   hidden) — :last-child would target the wrong element. */
.eval-table tbody tr.is-card-bottom td {
  border-bottom: none;
}

.eval-table thead th:first-child { border-radius: 12px 0 0 0; }
.eval-table thead th:last-child { border-radius: 0 12px 0 0; }
/* Rounded bottom corners on the visually-last card. JS tags
   .is-card-bottom on the parent row when collapsed and on the
   row-details panel when the last paper is expanded, so the radius
   tracks the actual visual bottom across filter/sort/expand. CSS
   :last-child is always the trailing DOM row-details (often hidden),
   so it would target the wrong element here. Applied on the td so
   the curve renders on desktop/tablet (TR border-radius doesn't
   render in table-row layout); mobile's TR-level radius lives inside
   the 768px media query at the smaller 8px value. */
.eval-table tbody tr.is-card-bottom td:first-child {
  border-bottom-left-radius: 12px;
}
.eval-table tbody tr.is-card-bottom td:last-child {
  border-bottom-right-radius: 12px;
}

/* When the thead is pinned, drop the top corners so it reads as a flat
   banner abutting the filter bar. JS toggles `.is-pinned` via an
   IntersectionObserver on a sentinel inserted before the table. */
.eval-table.is-pinned { border-top-left-radius: 0; border-top-right-radius: 0; }
.eval-table.is-pinned thead th:first-child { border-top-left-radius: 0; }
.eval-table.is-pinned thead th:last-child { border-top-right-radius: 0; }

.eval-table-sentinel {
  height: 1px;
  margin-bottom: -1px;
}

/* Column widths per case (with/without the findings col). col-paper and
   col-prev are fixed px widths, not percentages: both hold fixed-format
   paper ids that must never break mid-token (col-paper also carries the
   row-expand caret), so they need the same room at any table width, and a
   percentage share collapses into the title column on narrow layouts
   (issue #61). Same rationale as .search-col-paper below. px rather than em
   because em on a <col> resolves against the col's own inherited font-size
   (the 15.5px body font), not the td's 14px, and .row-detail-grid's indent
   must reuse col-paper's exact number (keep them in sync). The percentage
   columns must still sum to 100% between themselves, or table-layout:fixed
   stretches them unevenly. Cells wrap instead of ellipsis-truncating (see
   the tbody td rule), so the shares below are floored by the narrowest
   layout (a ~700px table at 1025-1200px viewports, where the sidebar still
   sits alongside): the date columns keep at least ~5 characters per line
   there so values break at their hyphens, never one character per line.
   Title takes the remaining slack since it wraps most gracefully. No
   `min-width` on <col>: Firefox ignores it while WebKit/Blink honor it, so a
   px floor would desync the engines. */
.eval-table:has(col.col-findings) col.col-paper    { width: 105px; }
.eval-table:has(col.col-findings) col.col-title    { width: 34%; }
.eval-table:has(col.col-findings) col.col-authors  { width: 13%; }
.eval-table:has(col.col-findings) col.col-date     { width: 11%; }
.eval-table:has(col.col-findings) col.col-mdate    { width: 10%; }
.eval-table:has(col.col-findings) col.col-audience { width: 12%; }
.eval-table:has(col.col-findings) col.col-prev     { width: 90px; }
.eval-table:has(col.col-findings) col.col-status   { width: 9%; }
.eval-table:has(col.col-findings) col.col-findings { width: 11%; }
.eval-table:not(:has(col.col-findings)) col.col-paper    { width: 105px; }
.eval-table:not(:has(col.col-findings)) col.col-title    { width: 39%; }
.eval-table:not(:has(col.col-findings)) col.col-authors  { width: 15%; }
.eval-table:not(:has(col.col-findings)) col.col-date     { width: 12%; }
.eval-table:not(:has(col.col-findings)) col.col-mdate    { width: 11%; }
.eval-table:not(:has(col.col-findings)) col.col-audience { width: 13%; }
.eval-table:not(:has(col.col-findings)) col.col-prev     { width: 90px; }
.eval-table:not(:has(col.col-findings)) col.col-status   { width: 10%; }

.eval-table thead th {
  background: var(--bg-sticky);
  color: var(--text-secondary);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 10px 12px;
  text-align: left;
  vertical-align: middle;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  /* Pin directly under the sticky filter bar; both share --filter-bar-h. */
  position: sticky;
  top: var(--filter-bar-h);
  z-index: 10;
}

/* Multi-word headers ("Previous Version", "Mailing Date", "Document Date")
   are too long for their narrow columns; let them wrap to two lines instead
   of clipping. "Disposition" is a single long word, so wrapping alone can't
   help it: the template marks it with a soft hyphen (Dispo&shy;sition) that
   only breaks when the column is too narrow. Other headers stay single-line
   (nowrap above) and vertically center in the taller header row. */
.eval-table thead th.col-prev,
.eval-table thead th.col-mdate,
.eval-table thead th.col-date,
.eval-table thead th.col-status { white-space: normal; line-height: 1.2; }

.sort-btn {
  appearance: none;
  background: none;
  border: 0;
  margin: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.eval-table thead th::after {
  content: "";
  display: inline-block;
  margin-left: 4px;
  font-size: 10px;
  color: var(--text-muted);
}

.eval-table thead th.sort-asc::after {
  content: " \25B2";
  color: var(--ink, #0f1419);
}

.eval-table thead th.sort-desc::after {
  content: " \25BC";
  color: var(--ink, #0f1419);
}

.eval-table tbody tr {
  transition: background 0.15s;
}
.eval-table tbody td {
  border-bottom: 1px solid var(--bg-soft, #f6f7f9);
}

.eval-table tbody tr:hover {
  background: var(--bg-hover);
}

/* ── Row audience stripe (primary visual signal) ──
   Default stripe is --clr-direction so Direction-only papers and any
   row whose audience didn't map to a known group still get a colored
   left edge (matches the mobile default). The per-group rules below
   override for mapped audiences. */
.eval-table tbody tr td:first-child { border-left: 3px solid var(--stripe-direction); }
.eval-table tbody tr[data-audience-group="ewg"]  td:first-child { border-left: 3px solid var(--stripe-ewg); }
.eval-table tbody tr[data-audience-group="lewg"] td:first-child { border-left: 3px solid var(--stripe-lewg); }
.eval-table tbody tr[data-audience-group="cwg"]  td:first-child { border-left: 3px solid var(--stripe-cwg); }
.eval-table tbody tr[data-audience-group="lwg"]  td:first-child { border-left: 3px solid var(--stripe-lwg); }
.eval-table tbody tr[data-audience-group="sg"]   td:first-child { border-left: 3px solid var(--stripe-sg); }
.eval-table tbody tr[data-audience-group="wg21"] td:first-child { border-left: 3px solid var(--stripe-wg21); }

/* The search results table never sets data-audience-group on its rows, so
   every row would otherwise fall through to the default stripe above.
   Nothing here calls for per-row audience coloring, so drop the stripe
   outright instead of wiring up that attribute. */
.eval-table.search-results-table tbody tr td:first-child {
  border-left: none;
}

.eval-table tbody td {
  padding: 8px 12px;
  font-size: 14px;
  color: var(--text-primary);
  vertical-align: top;
  /* Wrap-not-truncate (issue #61): long content breaks onto extra lines
     instead of ellipsis-clipping. overflow-wrap gives unbroken tokens
     (paper ids, long words) a break point of last resort so nothing
     spills into the neighboring column. */
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Paper ids (Paper and Previous Version columns) stay on one line, always:
   an id must never break mid-token. The fixed px col-paper/col-prev widths
   (above) guarantee the room at every table width. */
.eval-table tbody td:first-child,
.eval-table tbody td.col-prev {
  white-space: nowrap;
}

/* The row itself is a tap target for expand/collapse, so a clickable
   title link would steal the click and navigate away mid-row. Mute the
   anchor across every viewport: keep it in markup for screen readers,
   but visually it's plain text and clicks fall through to the row's
   expand handler. The paper-id link in the first column stays
   clickable (it's a separate target, narrow, and intentional). */
.eval-table tbody td[data-label="Title"] a {
  pointer-events: none;
  color: inherit;
  text-decoration: none;
}

/* Date column: tabular ISO dates (YYYY-MM-DD). Matches the authors
   column color; tabular-nums so digits align across rows. */
.eval-table tbody td.col-date,
.eval-table tbody td.col-mdate {
  font-size: 12.5px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

@media (min-width: 1025px) {
  .eval-table tbody td.col-date,
  .eval-table tbody td.col-mdate { font-size: 14px; }
  .findings-text { font-size: 14px; }
}

/* Status (disposition) cell: tiny column with a single text-style icon.
   Hover shows the raw open-std disposition string via the <span title="">
   tag. Em-dash placeholder when the paper has no disposition (most
   in-flight papers); rendered muted so the column reads as "nothing yet". */
.eval-table tbody td.col-status {
  text-align: center;
  white-space: nowrap;
  padding: 8px 4px;
}
.status-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  cursor: default;
}
.status-svg { display: block; }
/* Per-kind colors — reuses #22c55e from the existing zero-findings green
   so accepted papers read consistently across the table. */
.status-accepted    { color: #22c55e; }
.status-rejected    { color: var(--accent-bright); }
.status-in-progress { color: var(--amber, #b07a1b); }
.status-new         { color: var(--clr-lewg); }
.status-unknown     { color: var(--text-muted); }
.status-empty       { display: none; }
/* Audit column (search.html.j2) verdict dot colors. Own --audit-* tokens
   rather than the --green/--amber/--red Disposition uses just above: the two
   palettes sit in one table and have to be able to move independently.
   The same tokens carry the expanded panel's dot and verdict text further
   down, so one verdict reads as one color everywhere. */
.status-sound        { color: var(--audit-sound); }
.status-weakened     { color: var(--audit-weakened); }
.status-undermined   { color: var(--audit-undermined); }
.status-insufficient { color: var(--audit-insufficient); }
/* Verdict dot that sits beside the paper id. Off by default: above 1024px the
   Audit column renders its own labelled dot, and showing both would announce
   the verdict twice. The ≤1024px block near the end of this file turns it on
   as that column collapses. */
.paper-audit-dot { display: none; }

/* GitHub tracking-issue link inside the expanded row-details panel.
   Reuses the muted/hover treatment from the icon-only column it
   replaced; pairs the Octocat SVG with a short text label. */
.github-issue-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--text-secondary);
  text-decoration: none;
}
.github-issue-link:hover { color: var(--text-primary); }

.eval-table tbody td.col-authors,
.eval-table tbody td.col-audience {
  overflow: visible;
  position: relative;
}

.eval-table td.col-authors {
  color: var(--text-secondary);
}

.eval-table td a {
  color: #16202e;
  text-decoration: none;
  font-weight: 400;
  transition: color 0.2s;
}

/* Scoped :not([colspan]) so the paper-column color doesn't leak into the
   expanded row-details panel (whose single `<td colspan>` is also td:first-child). */
.eval-table td:first-child:not([colspan]) a {
  color: var(--text-primary);
}

.eval-table td:first-child:not([colspan]) a:not(.rev-chip):visited {
  color: var(--text-muted);
}

/* Give administrative (N-numbered) papers a real link target that is large
   enough. */
.eval-table td:first-child a:not(.rev-chip) {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

/* Multi-revision rows: a parent (latest revision) with .is-expandable is
   clickable to reveal a single sub-row of square `[Rn]` chips for the
   older revisions. Hover hints at the affordance; expanded state visually
   ties the parent to its chain row beneath. */
.eval-table tbody tr.is-expandable {
  cursor: pointer;
  /* Stop the parent row's text (paper id, title, date, etc.) from being
     highlighted when the user clicks twice to toggle expand/collapse.
     The expanded .row-details panel is a sibling, not a child, so its
     prose (abstract, authors) stays selectable. */
  user-select: none;
  /* When auto-scrolling an expanded row into view, park it just below
     the sticky filter-bar + thead stack with a small breathing gap.
     `--sticky-stack-h` is set by JS at load + on resize and tracks the
     deepest pinned element across breakpoints (filter-bar everywhere,
     thead on desktop/tablet, mailing-page-header on mobile). The calc()
     fallback covers the brief moment before JS runs. */
  scroll-margin-top: var(--sticky-stack-h, calc(var(--filter-bar-h) + 65px));
}
.eval-table tbody tr.is-expandable:hover {
  background: rgba(255, 255, 255, 0.03);
}
.eval-table tbody tr.is-expandable {
  /* Match the panel's open/close timing so the parent's highlight + bottom
     border fade in/out instead of snapping when a row toggles. */
  transition: background 140ms ease-out;
}
.eval-table tbody tr.is-expandable td {
  transition: border-bottom-color 140ms ease-out;
}
.eval-table tbody tr.is-expandable.is-expanded {
  background: rgba(15, 20, 25, 0.07);
}

/* A visible disclosure triangle, leading the paper id, providing the same
   toggle that the whole row already provides on click/tap. */
.row-expand-toggle {
  appearance: none;
  background: none;
  border: 0;
  padding: 2px;
  margin: 0 6px 0 0;
  display: inline-flex;
  align-items: center;
  border-radius: 4px;
  vertical-align: middle;
  cursor: pointer;
}
.row-expand-caret {
  display: inline-block;
  font-size: 13px;
  line-height: 1;
  color: var(--text-secondary);
  transition: transform 0.15s;
}
.row-expand-toggle[aria-expanded="true"] .row-expand-caret {
  transform: rotate(90deg);
}
.eval-table tbody tr.is-expandable.is-expanded td {
  /* Fade the border to transparent (instead of border-bottom: 0) so the
     1px line transitions out smoothly and reappears symmetrically on
     close. The 1px reserved space avoids any layout shift either way. */
  border-bottom-color: transparent;
}

/* Note expanded rows don't unfurl audience badges inline — the +N pill +
   popup is kept on both desktop and tablet so the row height stays compact
   when expanded. Authors stay collapsed for the same reason; the full author
   list is rendered as a labeled line inside the row-details panel. */
/* The row-details <tr> is always in the DOM as display: table-row; the
   inner .row-detail-grid-wrap/.row-detail-grid pair (below) carries the
   open/close transition. This gives us symmetric open + close (vs. the
   previous keyframe animation that only ran on open and snapped instantly
   on close). */
.eval-table tbody tr.row-details {
  background: #fbfcfe;
}
.eval-table tbody tr.row-details td {
  padding: 0;
  font-size: 12px;
  color: var(--text-secondary);
  border-bottom: 0;
  /* Override the table's default nowrap so summaries and other prose wrap
     within the cell instead of running off into adjacent columns. */
  white-space: normal;
}
/* Expanded row-details: restore the 1px separator below the panel so it
   reads as the bottom edge of the paper, with a clean break before the
   next paper's row. Matches the desktop visual that existed before PR #102
   silently dropped this border as a side effect of the row-details staying
   in the DOM. (Mobile already has its own bottom separator on every
   visible row via `box-shadow: inset 0 -1px 0` on `tbody tr`.) */
.eval-table tbody tr.is-expandable.is-expanded + tr.row-details td {
  border-bottom: 1px solid #e4e9f0;
}
/* Metadata fields render as a definition list: labels share one
   auto-sized column on the left, values share a flexible column on
   the right. Achieved by promoting each .row-detail-line's spans to
   direct grid items via `display: contents` (see rule below), so
   every label across the panel participates in the same max-content
   column — they align vertically without per-line width math. */
/* Auto-height disclosure wrapper: animates from 0 to the panel's own
   natural content height via the CSS grid-template-rows 0fr -> 1fr
   technique, rather than a fixed max-height cap. A cap has to guess a
   number that fits "typical" content; Audit findings are unbounded and
   the Abstract can run to 400 characters, so any fixed cap eventually
   clips real content with no scrollbar or indication anything's missing
   (a real bug this replaces). This wrapper is purely a sizing shell:
   .row-detail-grid inside it (unchanged) still owns the actual column
   layout. */
.row-detail-grid-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 140ms ease-out;
}
.row-detail-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1rem;
  row-gap: 8px;
  /* Center labels with taller values (pills, phase badge); wide prose rows
     (Abstract/Findings) opt back out below. */
  align-items: center;
  /* Indent panel content just past the Paper column so it starts where
     the Title column's text does: col-paper's fixed 105px (keep in sync
     with the col.col-paper width rules) plus a 15px inset. px rather
     than em: this panel's 12px font differs from the col's em base, so
     em math here can't track the column width. */
  padding-left: calc(105px + 15px);
  max-width: calc(105px + 15px + 65ch);
  /* padding-block must still animate to 0 alongside the wrapper's 0fr row:
     padding is added on top of content height (content-box, this file's
     default), so the wrapper forcing its row track toward 0 can shrink
     this element's own *content* to nothing but can never shrink away its
     padding: a fixed non-zero padding-block would leave a permanent
     ~10px sliver on every collapsed row regardless of the row-track's
     size (harmless alone, but 10px x hundreds of rows on a large mailing
     is not). */
  padding-block: 0;
  opacity: 0;
  overflow: hidden;
  /* min-height: 0 overrides grid items' default min-height: auto, which
     would otherwise stop the wrapper's 0fr row from actually reaching
     zero height (a well-known gotcha of this technique). overflow: hidden
     is what actually clips this element's own content while the wrapper's
     row track is animating between 0fr and 1fr. */
  min-height: 0;
  /* opacity is purely visual (a fade, layered on top of the height
     animation above); none of opacity/overflow/the wrapper's 0fr sizing
     remove a collapsed panel's links/chips/icons from the tab order or
     the a11y tree, so every collapsed row would otherwise leave its
     content focusable and screen-reader-announced. visibility does both,
     with a transition delay so it only takes effect once the close
     animation finishes (and takes effect immediately on open, so content
     is reachable as soon as it starts appearing). */
  visibility: hidden;
  transition: padding-block 140ms ease-out, opacity 140ms ease-out,
    visibility 0s linear 140ms;
}
.eval-table tbody tr.is-expandable.is-expanded + tr.row-details .row-detail-grid-wrap {
  grid-template-rows: 1fr;
}
.eval-table tbody tr.is-expandable.is-expanded + tr.row-details .row-detail-grid {
  padding-block: 20px;
  opacity: 1;
  visibility: visible;
  transition: padding-block 140ms ease-out, opacity 140ms ease-out;
}
/* Promote each line's label + value spans to direct grid items of
   .row-detail-grid so every label shares the one max-content column.
   Without this, each .row-detail-line would be a single grid cell and
   labels couldn't align across rows. The wrapper div itself
   contributes nothing to layout. */
.row-detail-line {
  display: contents;
  font-size: 12px;
  white-space: normal;
}
.row-detail-label {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-secondary);
}
/* Wide prose rows keep their label at the top (the grid uses align-items: center). */
.row-detail-line-wide .row-detail-label {
  align-self: start;
}
.row-detail-value {
  color: #16202e;
  min-width: 0;
}
/* Target Audience row: badges render back-to-back, so give it the same 4px gap
   as the table's audience column (.col-audience-badges). */
.row-detail-value:has(> .search-badge) {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}
/* Mailing Date value: date link + phase badge on one centered row (the badge's
   own margin-top, for wrapped table layouts, is reset below). */
.row-detail-value:has(> .phase-badge) {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.row-detail-value .phase-badge {
  margin-top: 0;
}
.row-detail-summary {
  line-height: 1.5;
  max-width: 65ch;
}
/* Reset native <button> chrome so it keeps reading as plain inline text, not a UI button. */
.audience-link {
  appearance: none;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: color 0.15s;
}
.audience-link:hover {
  color: var(--text-primary);
  text-decoration: underline;
}
.eval-table td:first-child .rev-chip {
  position: relative;
  display: inline-block;
  min-width: 28px;
  border: 1px solid var(--bg-soft, #f6f7f9);
  border-radius: 3px;
  font-size: 11px;
  text-align: center;
  color: var(--text-secondary);
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s;
}
.eval-table td:first-child .rev-chip:hover {
  color: var(--text-primary);
  border-color: var(--text-primary);
  background: rgba(255, 255, 255, 0.04);
  text-decoration: none;
}
/* Custom styled tooltip on hover: pulled from data-tooltip so we control
   the visual instead of relying on the unstyled, delayed native title= popup.
   aria-label on the chip preserves screen-reader access to the same text. */
.eval-table td:first-child .rev-chip[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 6px);
  transform: translateX(-50%);
  padding: 4px 8px;
  background: var(--bg-canvas, #ffffff);
  border: 1px solid var(--border-default, #e1e4ea);
  border-radius: 2px;
  box-shadow: 0 4px 16px rgba(15, 20, 25, 0.15);
  color: var(--ink, #0f1419);
  font-size: 12px;
  font-family: var(--font-mono, monospace);
  font-weight: 400;
  white-space: nowrap;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s;
}
@media (hover: hover) {
  .eval-table td:first-child .rev-chip[data-tooltip]:hover::after {
    opacity: 1;
  }
}
/* Keyboard-focus equivalent of the hover reveal above. */
.eval-table td:first-child .rev-chip[data-tooltip]:focus-visible::after {
  opacity: 1;
}
/* The revisions chip strip wraps onto multiple lines for papers with many
   revisions. flex + gap gives consistent horizontal spacing between chips
   and vertical breathing room between wrapped lines. */
.row-detail-value:has(> .rev-chip) {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 6px;
  row-gap: 4px;
}
/* Expanded-panel revisions are plain dark-text links (per Figma), not boxed
   chips; scoped to beat the boxed `.eval-table td:first-child .rev-chip` that
   leaks in through the panel's colspan td. */
.search-results-table .row-detail-grid .row-detail-value .rev-chip {
  border: none;
  min-width: 0;
  border-radius: 0;
  color: #16202e;
  font-weight: 600;
  font-family: var(--badge-font);
}
.search-results-table .row-detail-grid .row-detail-value .rev-chip:hover {
  border: none;
  background: none;
  color: #16202e;
  text-decoration: underline;
}

/* Reset native <button> chrome -- see .audience-link above for why. */
.author-link {
  appearance: none;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: color 0.15s;
  display: inline-flex;
  align-items: center;
  /* use min-height here, not padding, to ensure a large-enough height, since
     this renders in several font-size contexts (.col-authors,
     .row-detail-value, .badge-overflow-popup). */
  min-height: 24px;
}

.author-link:hover {
  color: var(--text-primary);
  text-decoration: underline;
}

/* Author filter affordances render as real <a> (hover URL, keyboard focus,
   open-in-new-tab), but should keep the plain author-text look rather than
   inherit the table's link color/weight. Higher specificity than
   `.eval-table td a` so it wins. */
.eval-table td a.author-link {
  color: inherit;
  font-weight: inherit;
  text-decoration: none;
}
.eval-table td a.author-link:hover {
  color: var(--text-primary);
  text-decoration: underline;
}

.col-authors .badge-overflow-wrap { margin-left: 4px; }
.col-authors .badge-overflow-popup {
  flex-direction: column;
  white-space: normal;
  width: max-content;
  max-width: 220px;
  gap: 2px;
  font-size: 13px;
  line-height: 1.5;
  top: 0;
  left: 0;
  transform: none;
}


.eval-table td a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* ── Audience column layout ──────────────────────────────── */

/* Badges wrap onto extra lines when the column is too narrow for them
   (each .badge is atomic via its own white-space: nowrap); overflow must
   stay visible so the +N hover popup can escape the cell. */
td.col-audience {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  overflow: visible;
}

/* Audience overflow indicator + floating popup */
.badge-overflow-wrap { position: relative; display: inline-flex; align-items: stretch; }
/* we use var(--text-secondary) here, rather than var(--text-muted), to make the
   text easier to read, due to higher color contrast. */
.badge-overflow { background: var(--bg-soft, #f6f7f9); color: var(--text-secondary); border: 1px solid var(--border-default, #e1e4ea); cursor: default; padding: 4px 5px; font-size: 11px; font-weight: 500; letter-spacing: 0.02em; }
.badge-overflow-popup {
  display: inline-flex;
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  padding: 5px 8px;
  background: var(--bg-canvas, #ffffff);
  border: 1px solid var(--border-default, #e1e4ea);
  border-radius: 2px;
  box-shadow: 0 4px 16px rgba(15, 20, 25, 0.15);
  white-space: nowrap;
  z-index: 100;
  gap: 5px;
  opacity: 0;
  pointer-events: none;
  /* No opacity transition — when a row collapses, the popup's position
     snaps from static back to absolute instantly while opacity would
     otherwise fade over 120ms, creating a flicker overlap. */
}
/* Desktop (>1024px + hover-capable): hover opens the popup. */
@media (hover: hover) and (min-width: 1025px) {
  .badge-overflow-wrap:hover .badge-overflow-popup { opacity: 1; pointer-events: auto; }
  .badge-overflow-wrap:hover .badge-overflow { visibility: hidden; }
}

/* All viewports: click-to-toggle via JS `.is-open` class.
   On desktop this supplements hover; on tablet/mobile it's the only method. */
.badge-overflow { cursor: pointer; }
.badge-overflow-wrap.is-open .badge-overflow-popup {
  opacity: 1;
  pointer-events: auto;
}
.badge-overflow-wrap.is-open .badge-overflow {
  visibility: hidden;
}

/* Audience badge interaction. Shape, per-group color, and hover live on
   `.search-badge` (below); only the column-only dimming (JS toggles
   `.badge-dimmed`/`.badge-active` on sibling pills) stays scoped here. */
.col-audience .badge.badge-dimmed {
  background: transparent;
  border-color: transparent;
  color: var(--text-secondary);
}
.col-audience .badge.badge-active { filter: brightness(1.2); }

/* ── Filter chip ─────────────────────────────────────────── */

.filter-chip-area {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  flex-shrink: 0;
}

/* appearance/font-family/margin reset native <button> chrome. */
.filter-chip {
  appearance: none;
  margin: 0;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border: 1px solid;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 500;
  background: rgba(255,255,255,0.04);
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s;
}

.filter-chip:hover {
  background: rgba(255,255,255,0.08);
}

.filter-chip-x {
  font-size: 13px;
  line-height: 1;
  opacity: 0.6;
}

.filter-chip:hover .filter-chip-x {
  opacity: 1;
}

/* Inline suggestion chips shown while typing */
.filter-suggest-area {
  display: flex;
  flex-wrap: nowrap;
  gap: 3px;
  flex-shrink: 0;
}
.filter-suggest-area:empty {
  display: none;
}
/* appearance/font-family/margin reset native <button> chrome. */
.filter-suggest-chip {
  appearance: none;
  margin: 0;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border: 1px dashed;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 500;
  background: rgba(255,255,255,0.02);
  white-space: nowrap;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.12s, background 0.12s;
}
.filter-suggest-chip:hover,
.filter-suggest-chip.filter-suggest-active {
  opacity: 1;
  background: rgba(255,255,255,0.08);
}

/* ── Findings ────────────────────────────────────────────── */

.findings-text {
  /* Base = tablet/phone size. The desktop bump to 14px is in the
     @media (min-width: 1025px) block earlier. Setting font-size on the
     <a> directly rather than the td because the link has its own
     size rule and wouldn't otherwise inherit the cell's breakpoint
     size. */
  font-size: 13px;
  white-space: nowrap;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent);
}

@media (hover: hover) {
  .findings-text {
    text-decoration-color: rgba(244, 113, 113, 0.4);
    transition: text-decoration-color 0.15s;
  }
  .findings-text:hover {
    text-decoration-color: var(--accent);
  }
}

.eval-table td a.findings-zero {
  color: #22c55e;
}

.findings-pending {
  font-size: 13px;
  white-space: nowrap;
  color: var(--muted);
  font-style: italic;
}

/* Terminal state (convert permanently skipped the source, e.g. the Working
   Draft): upright and dimmer than the in-flight italic labels. */
.findings-skipped {
  font-style: normal;
  opacity: 0.7;
}

/* ── Mailing list (root index) ───────────────────────────── */

/* Sticky footer: pin the navy footer to the bottom of the viewport on short
   pages (mailing list / detail). The content area grows to fill the gap. */
body.eval-index {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* width:100% so the auto side-margins center it at max-width instead of
   shrink-to-fit (flex items with auto cross-axis margins size to content). */
body.eval-index .mailing-list,
body.eval-index .mailing-page { flex: 1 0 auto; width: 100%; }
/* Sticky-column layout: don't shrink the shared footer band. */
body.eval-index .footer { flex-shrink: 0; }

.mailing-list {
  position: relative;
  z-index: 1;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 1rem var(--pad-x);
}

.mailing-list-eyebrow {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-secondary, #57606a);
}
.mailing-list-eyebrow .slash { color: var(--accent-blue, #007aff); }
.mailing-list-eyebrow .dot { color: var(--ink-faint, #8b95a6); }

.mailing-list h1,
.mailing-section-title {
  font-size: 1.875rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  margin-bottom: 0.25rem;
}

.mailing-list-subtitle {
  color: var(--text-secondary);
  font-size: 0.9375rem;
  margin-bottom: 1.5rem;
}

.mailing-messages {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
}

.mailing-message {
  background: var(--accent-dim);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 0.75rem 1rem;
  font-size: 0.85rem;
  color: var(--accent-bright);
  margin-bottom: 0.5rem;
}

.mailing-list-disclaimer {
  color: var(--text-muted);
  font-size: 0.8rem;
  margin-bottom: 1.5rem;
}

.mailing-badge-latest {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--green-bg);
  color: var(--green);
  border: 1px solid var(--green-border);
  vertical-align: middle;
  margin-left: 6px;
}

/* Plain colored text, not a boxed pill like .mailing-badge-latest. This
   marks the whole page as a work-in-progress feature, not a per-item status,
   so it reads as a label on the title rather than a badge on a result. */
.beta-badge {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--orange);
  vertical-align: baseline;
  margin-left: 6px;
}

/* Puts the title, its Beta label, and the "not affiliated" disclaimer on one
   row -- the disclaimer's own margin-bottom (meant for when it stacks below
   a title on its own line) would otherwise add unwanted vertical gap here. */
.mailing-section-title-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 12px;
}

.mailing-section-title-row .mailing-list-disclaimer {
  margin-bottom: 0;
}

/* Puts the "visit open-std.org" link on the same line as the h1, pinned to
   the right edge -- a generic "visit the source site" link, distinct from
   the per-mailing attribution in .row-count-credit below the table. */
.page-title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.open-std-link {
  flex: 0 0 auto;
  font-size: 0.8rem;
  color: var(--text-secondary);
  white-space: nowrap;
}

.open-std-link:hover {
  color: var(--accent);
}

/* Plain inline link pair above the search toolbar, same tone/size as
   .open-std-link above rather than the boxed .submit-issue-btn treatment
   used for the sitewide Submit Issue action elsewhere. */
.search-quick-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin: 0 0 1rem;
}
.search-quick-links a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--accent-blue-higher-contrast);
  text-decoration: none;
}

.search-quick-links a:hover {
  text-decoration: underline;
}

.disposition-updated-caption {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  font-size: 13px;
  color: var(--text-secondary);
  margin: 0 0 0.75rem;
}

/* ── Mailing index list (quiet editorial) ────────────────── */

.mailing-index-list {
  display: flex;
  flex-direction: column;
}

.mailing-index-year {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.5rem 0 0.25rem;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}

.mailing-index-year:first-child {
  margin-top: 0;
}

.mailing-index-year::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border-default);
}

.mailing-index-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 0.5rem;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid var(--bg-soft, #f6f7f9);
  transition: background 0.15s;
}

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

.mailing-index-item:hover {
  background: var(--bg-hover);
  /* The row is one link; keep the global a:hover underline off the badge and
     arrow by re-adding it only to the text labels below. */
  text-decoration: none;
}

.mailing-index-item:hover .mailing-index-item-id,
.mailing-index-item:hover .mailing-index-item-count {
  text-decoration: underline;
}

.mailing-index-item-id {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  transition: color 0.15s;
}

.mailing-index-item:hover .mailing-index-item-id {
  color: var(--accent);
}

.mailing-index-item-count {
  margin-left: auto;
  font-size: 0.85rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.mailing-index-item-arrow {
  font-size: 1.1rem;
  color: var(--text-muted);
  transition: color 0.15s, transform 0.15s;
}

.mailing-index-item:hover .mailing-index-item-arrow {
  color: var(--text-primary);
  transform: translateX(2px);
}

/* ── Report buttons (stub) ───────────────────────────────── */

.report-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: 6px;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.15s, color 0.15s, background 0.15s, border-radius 0.15s;
  cursor: pointer;
}

.report-btn:hover {
  border-color: var(--text-secondary);
  color: var(--text-primary);
  background: var(--bg-soft, #f6f7f9);
}

.report-btn-block {
  display: flex;
  width: 100%;
  padding: 0.55rem 0.9rem;
  font-size: 0.8rem;
  margin-bottom: 0.5rem;
}

.report-btn-block:last-child {
  margin-bottom: 0;
}

.report-btn-icon {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: color 0.15s;
}

.report-btn:hover .report-btn-icon {
  color: var(--text-primary);
}

/* ── Report row (inline label + format icons) ────────────── */

.report-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.report-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.report-row-label {
  flex: 1;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-primary);
}

/* Per-committee label color. Reuses the same --clr-* tokens the audience
   badges use. */
.report-row-label-lewg { color: var(--clr-lewg); }
.report-row-label-lwg  { color: var(--clr-lwg); }
.report-row-label-ewg  { color: var(--clr-ewg); }
.report-row-label-cwg  { color: var(--clr-cwg); }
.report-row-label-sg   { color: var(--clr-sg); }

.report-row-count {
  color: var(--text-secondary);
  font-size: 12px;
  font-weight: 400;
}

.report-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  background: var(--bg-canvas, #ffffff);
  border: 1px solid var(--border-default);
  color: var(--ink, #0f1419);
  text-decoration: none;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
  cursor: pointer;
}
.report-icon-btn img { width: 13px; height: 16px; }

.report-icon-btn:hover {
  border-color: var(--text-secondary);
  color: var(--ink, #0f1419);
  background: var(--bg-soft, #f6f7f9);
}

.report-icon-btn[aria-disabled="true"] {
  opacity: 0.7;
  cursor: not-allowed;
}

/* Brand-colored icon button (Acrobat PDF) — same hover bg, keeps its own icon color */
.report-icon-btn-brand:hover {
  border-color: var(--text-secondary);
  background: var(--bg-soft, #f6f7f9);
}

/* ── Content layout with sidebar ─────────────────────────── */

.mailing-list .content-layout,
.mailing-page .content-layout {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.mailing-list .post-list,
.mailing-page .post-list {
  flex: 1;
  min-width: 0;
}

.mailing-list .sidebar,
.mailing-page .sidebar {
  width: 260px;
  min-width: 260px;
  flex-shrink: 0;
}

.sidebar-heading {
  margin: 0 0 0.75rem;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}

.mailing-list .sidebar-card,
.mailing-page .sidebar-card {
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  margin-bottom: 1rem;
}

.mailing-list .sidebar-card-header,
.mailing-page .sidebar-card-header {
  margin: 0;
  background: var(--bg-card);
  padding: 10px 20px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border-default);
  border-radius: 12px 12px 0 0;
}

.mailing-list .sidebar-card-body,
.mailing-page .sidebar-card-body {
  padding: 0.9rem 1rem 1rem;
}

.mailing-list .sidebar-card-desc,
.mailing-page .sidebar-card-desc {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 0.75rem;
}

/* Stack the sidebar below the table at tablet too, not just phone: with the
   260px sidebar beside it, a 769-1024px viewport leaves the 8-9 column
   papers table only ~420-690px, too narrow for every column to wrap
   readably (issue #61 removed the ellipsis clipping that used to paper
   over this). */
@media (max-width: 1024px) {
  .mailing-list .content-layout,
  .mailing-page .content-layout {
    flex-direction: column;
    align-items: stretch;
  }
  .mailing-list .sidebar,
  .mailing-page .sidebar {
    width: 100%;
    min-width: 0;
  }
}

/* ── "Reports by Year" collapsible tree  ──────
   Native <details>/<summary> for keyboard/AT-correct disclosure without
   custom ARIA. Each year group is independently collapsible,
   which satisfies the "mobile collapse" requirement. */

.sidebar-card-body-tree { padding-top: 0.4rem; }

.mailing-year-group {
  border-bottom: 1px solid var(--bg-soft, #f6f7f9);
}

.mailing-year-group:last-child { border-bottom: none; }

.mailing-year-summary {
  cursor: pointer;
  padding: 0.6rem 0.25rem;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-secondary);
  list-style: none;
}

.mailing-year-summary::-webkit-details-marker { display: none; }

.mailing-year-summary::before {
  content: "\25B8";
  display: inline-block;
  margin-right: 0.4rem;
  color: var(--text-muted);
  transition: transform 0.15s;
}

.mailing-year-group[open] > .mailing-year-summary::before {
  transform: rotate(90deg);
}

.mailing-year-list {
  display: flex;
  flex-direction: column;
  padding-bottom: 0.35rem;
}

.mailing-year-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.5rem 0.45rem 1.4rem;
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
  transition: background 0.15s;
}

.mailing-year-item:hover { background: var(--bg-hover); }

.mailing-year-item.is-active {
  background: var(--bg-hover);
  box-shadow: inset 2px 0 0 var(--accent);
}

.mailing-year-item-id {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.mailing-year-item-count {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* ── Tablet breakpoint ─────────────────────────────────── */
/* Typography steps down one size; cells wrap (base rule) so
   nothing clips or spills into the next column. */

@media (max-width: 1024px) {
  /* Tablet typography — one step down from desktop's 14px/12px so the
     denser column layout reads cleanly. .col-date and .findings-text
     already have their own tablet sizes (12.5px / 13px) above and aren't
     touched here. */
  .eval-table tbody td { font-size: 13px; }
  .eval-table thead th { font-size: 11px; }

  /* No tablet col-width overrides: the sidebar stacks below the table at
     ≤1024px (see .content-layout), so the table gets the full container
     width here and the desktop shares (with their smaller tablet fonts)
     have more room than they do at small-desktop widths. */

  /* Top-align so badges sit on the same line as title/authors/date
     text instead of flex-centering when the badge is shorter than the
     row content. (Audience-badge padding is set site-wide via the
     .badge-{audience} class rules in shared-vars.css.) */
  td.col-audience { align-items: flex-start; }

  /* Drop the bottom separator on expanded parent rows so the parent
     visually merges into its row-details panel below. Fade rather than
     snap, mirroring the desktop transition so close+open feel symmetric. */
  .eval-table tbody tr.is-expandable {
    transition: box-shadow 140ms ease-out, background 140ms ease-out;
  }
  .eval-table tbody tr.is-expandable.is-expanded {
    box-shadow: none;
  }
  .eval-table tbody tr.is-expandable.is-expanded td {
    border-bottom-color: transparent;
  }


  /* Hide the authors overflow indicator (+N pill / "…" / popup) at
     tablet and below — the row-details panel surfaces the full author
     list on expand, so the cell only shows the first two authors
     (wrapping as needed). data-search still includes every author
     name, so search/filter is unaffected. */
  .col-authors .badge-overflow-wrap { display: none; }
}

/* ── Mobile card breakpoint ──────────────────────────────── */

@media (max-width: 768px) {
  /* Condensed sticky page header: breadcrumb only. The page-title block is
     hidden because the breadcrumb already names the mailing.
     --mailing-header-h is the expected pinned height; the filter bar's `top`
     references it so the two pinned bands stack flush. The new
     .mailing-section-header block sits *above* this sticky header (normal,
     non-sticky flow) and simply scrolls away, unaffected. */
  .mailing-page-header {
    position: sticky;
    top: 0;
    z-index: var(--z-filter-bar);
    background: var(--bg-canvas);
    /* Extend bg to the container edges so cards scrolling under the
       pinned header don't show a vertical strip on either side. */
    margin: 0 -0.75rem;
    /* Drop the bottom pad so the filter bar pins flush right below. */
    padding: 4px 0.75rem 0;
  }
  /* Zero out the breadcrumb's own 1rem vertical padding so the header's
     own padding is the only contributor to the pinned strip's height —
     keeps --mailing-header-h predictable. */
  .mailing-page-header .breadcrumb-bar {
    margin: 0;
    padding: 0;
    font-size: 0.8rem;
  }
  .mailing-page-header .page-title { display: none; }

  .filter-bar {
    flex-wrap: nowrap;
    gap: 0.5rem;
    padding-block: 6px;
    margin-bottom: 0.5rem;
    top: var(--mailing-header-h);
    /* Shorter floor on mobile; the search input alone drives the rest. */
    min-height: 0;
  }
  /* Pinned filter bar gets a soft depth shadow + faint highlight at its
     bottom edge so the cards scrolling beneath read as below the bar
     without a hard 1px rail. Only while pinned: at rest at the page top
     there's no content scrolling under it, so the shadow would be
     gratuitous. JS toggles `.is-pinned` via an IntersectionObserver on
     a sentinel inserted before the filter bar. */
  .filter-bar.is-pinned {
    box-shadow:
      0 1px 0 rgba(255, 255, 255, 0.04),
      0 8px 12px -6px rgba(0, 0, 0, 0.55);
  }
  .filter-bar-sentinel {
    height: 1px;
    margin-bottom: -1px;
  }

  /* Let the search-wrap wrap its own children (clear, chips, input) so
     a long filter-chip list breaks to a new line inside the wrap instead
     of pushing the bar past 100% width. */
  .search-wrap {
    flex-wrap: wrap;
  }
  /* Allow the chip area to shrink and let chips wrap when many SG
     audiences are filtered at once. Without `min-width: 0` the chip
     area's contents would otherwise dictate a minimum width that
     pushes search-wrap past the viewport. */
  .filter-chip-area {
    flex-shrink: 1;
    min-width: 0;
  }
  /* Same overflow class as filter-chip-area: typing "sg" surfaces 9+
     suggestion chips (SG1, SG6, SG7, …). The desktop nowrap default
     pushes them off-canvas on mobile; let them wrap internally and
     shrink within the search-wrap. */
  .filter-suggest-area {
    flex-wrap: wrap;
    flex-shrink: 1;
    min-width: 0;
  }

  /* Mobile keeps the compact `X / Y` counter (set in JS); just tighten
     its type to match the rest of the mobile filter controls. The credit
     text is dropped here -- it would clash with the terse "X / Y" format. */
  .row-count {
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
  }
  .row-count-credit {
    display: none;
  }
  .filter-search {
    padding: 0.3rem 0.5rem;
  }

  /* .search-results-table opts out of the card look entirely (see the
     "search results table stays a genuine table on mobile" section at the
     end of this file): it keeps its own always-on .eval-table box
     (border/background/radius, eval-index.css:285-300) instead of picking
     up this flattened per-row-card chrome. */
  .eval-table:not(.search-results-table) {
    background: none;
    border: 1px solid var(--bg-soft, #f6f7f9);
    border-left: none;
    border-radius: 0 8px 8px 0;
    overflow: hidden;
  }

  .eval-table thead {
    display: none;
  }

  .eval-table,
  .eval-table tbody {
    display: block;
  }

  /* Mobile list layout — each row is a grid:
     Paper id, optional GitHub-issue icon, and Notes share the top line;
     title, authors, and audience each take their own wrapping line below. */
  .eval-table tbody tr {
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    grid-template-areas:
      "paper    status    mdate     notes"
      "title    title     title     title"
      "authors  authors   authors   authors"
      "audience audience  audience  date";
    row-gap: 4px;
    column-gap: 8px;
    background: var(--bg-sticky);
    border: none;
    /* Default left stripe for rows whose audience didn't map to a known
       group (audience_row_group → "unknown"). Uses --clr-direction so
       unmapped rows visually belong to the Direction track. The
       data-audience-group rules below override per-group; without this
       default the row had no left edge and the rounded corner on the
       first/last card had nothing to render against. */
    border-left: 3px solid var(--stripe-direction);
    box-shadow: inset 0 -1px 0 var(--bg-soft, #f6f7f9);
    border-radius: 0;
    margin: 0;
    padding: 8px 8px 8px 12px;
  }

  /* Drop the bottom row-separator shadow on the visually-last card
     (parent row when collapsed, row-details panel when expanded).
     Uses .is-card-bottom because :last-child of tbody is always the
     trailing row-details, often hidden, so the rule would target the
     wrong element. */
  .eval-table tbody tr.is-card-bottom {
    box-shadow: none;
  }

  /* Round the open left edge of the card stack to match the table's
     existing 8px right-side radius. Lives on the rows (not the table)
     because the colored audience stripe on each row is what visually
     closes the left edge, so the curve has to follow the stripe.
     `.is-card-top` / `.is-card-bottom` are JS-applied by updateCardEdges
     to the *visible* first/last paper rows — CSS-only selectors can't
     follow filter hides, sort reorders, or expansion (the row-details
     becomes the visual bottom when the last paper is expanded). */
  .eval-table tbody tr.is-card-top {
    border-top-left-radius: 8px;
  }
  .eval-table tbody tr.is-card-bottom {
    border-bottom-left-radius: 8px;
  }

  /* Row audience stripe — thin accent on the left edge of each list item */
  .eval-table tbody tr[data-audience-group="ewg"]  { border-left: 3px solid var(--stripe-ewg); }
  .eval-table tbody tr[data-audience-group="lewg"] { border-left: 3px solid var(--stripe-lewg); }
  .eval-table tbody tr[data-audience-group="cwg"]  { border-left: 3px solid var(--stripe-cwg); }
  .eval-table tbody tr[data-audience-group="lwg"]  { border-left: 3px solid var(--stripe-lwg); }
  .eval-table tbody tr[data-audience-group="sg"]   { border-left: 3px solid var(--stripe-sg); }
  .eval-table tbody tr[data-audience-group="wg21"] { border-left: 3px solid var(--stripe-wg21); }

  .eval-table tbody td {
    padding: 0;
    border: none;
    /* The `border` shorthand above resets border-color to `currentColor`,
       which is text-light on the dark theme. At the mobile→tablet
       breakpoint the base rule's `border-bottom: 1px solid var(--bg-soft, #f6f7f9)`
       suddenly applies, and the unconditional `transition: border-bottom-color
       140ms` (PR #102, for symmetric row expand/collapse) animates the
       color from currentColor (light) to the dark blue, producing a 140ms
       "white" pulse across every row separator. Park the color at the
       target value so the transition has nothing to animate. */
    border-bottom-color: var(--bg-soft, #f6f7f9);
    display: block;
  }

  .eval-table tbody td::before {
    display: none;
  }

  /* Remove desktop row border on mobile, plus the padding-left
     it's paired with — on mobile the colored stripe lives on the
     tr, and the first cell's content should sit flush against
     the tr's own 12px padding-left, not an extra td gutter. */
  .eval-table tbody tr[data-audience-group] td:first-child {
    border-left: none;
    padding-left: 0;
  }

  .eval-table tbody td[data-label="Paper"]    { grid-area: paper; font-weight: 600; }
  /* align-self: center on row 1 — the visible glyph is centered inside
     each SVG, so centering the SVG element vertically lines the two
     visible icons up regardless of their differing sizes / viewBox
     internal padding. Row 1 only holds paper + icons + notes, so its
     height stays at one line of text even when the card is expanded. */
  .eval-table tbody td[data-label="Status"]   { grid-area: status; align-self: center; padding: 0; }
  .eval-table tbody td.col-status svg { width: 16px; height: 16px; }
  .eval-table tbody td[data-label="Document Date"] { grid-area: date; align-self: center; justify-self: end; font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }
  /* Mailing date rides the top line next to the status icon — compact,
     numeric (YYYY-MM), right-aligned toward the Notes link. */
  .eval-table tbody td[data-label="Mailing Date"] { grid-area: mdate; align-self: center; justify-self: end; font-size: 12px; color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }
  /* Previous Version stays on the wider tablet/desktop table; the narrow
     mobile card would only show it as an unlabeled stray id, so drop it
     here. */
  .eval-table tbody td[data-label="Previous Version"] { display: none; }
  .eval-table tbody td[data-label="Title"]    { grid-area: title; font-size: 13px; color: var(--text-secondary); white-space: normal; overflow: visible; text-overflow: clip; }
  .eval-table tbody td[data-label="Authors"]  { grid-area: authors; font-size: 13px; color: var(--text-secondary); }
  .eval-table tbody td[data-label="Audience"] { grid-area: audience; }
  .eval-table tbody td[data-label="Notes"]    { grid-area: notes; text-align: right; font-size: 13px; }

  .eval-table tbody td.col-audience {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
  }
  /* On phone the audience cell has its own row in the card grid, so
     there's room for all badges — unfurl the popup inline and hide
     the +N pill instead of forcing a tap to reveal extras. */
  .eval-table tbody td.col-audience .badge-overflow-wrap { display: contents; }
  .eval-table tbody td.col-audience .badge-overflow { display: none; }
  .eval-table tbody td.col-audience .badge-overflow-popup {
    position: static;
    transform: none;
    opacity: 1;
    pointer-events: auto;
    display: inline-flex;
    flex-wrap: wrap;
    flex-direction: row;
    gap: 8px;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
    width: auto;
    max-width: none;
    white-space: normal;
  }
  .col-authors {
    display: block;
  }
  /* Authors on phone follow the tablet rule: +N popup hidden, first 2
     authors visible (wrapping as needed). Full author list is available
     by expanding the row. */

  /* On desktop the row-details <tr> stays in the DOM (display: table-row)
     so the inner .row-detail-grid can carry a symmetric open/close
     transition. On mobile that same approach turns every collapsed
     row-details into a ghost card — the default mobile `tbody tr` rule
     above applies grid layout + 8px padding + audience-stripe + shadow
     whether or not the panel is open. Cheaper to drop the symmetric
     animation here and hide the row-details outright; tap-based
     interaction makes the snap read fine. */
  .eval-table tbody tr.row-details {
    display: none;
  }
  /* Mobile chain row: read as a small block under the parent card.
     Keeps the parent's audience-group border-left color (no override)
     so the colored stripe runs continuously down the card. The desktop
     `display: table-row` rule wins by specificity, but a table-row
     inside a `display: block` tbody doesn't render its border-left in
     most browsers — force `display: block` so the stripe shows. */
  .eval-table tbody tr.is-expandable.is-expanded + tr.row-details {
    display: block;
  }
  /* Vertical padding now lives on .row-detail-grid (so it can transition
     in/out with the rest of the panel), and the parent `tbody tr` rule
     above already gives the row 12px of left padding (8px right) — no
     td padding needed. Avoids doubling the top/bottom gap on expanded
     mobile panels. */
  .eval-table tbody tr.row-details td {
    padding: 0;
  }
  /* Mobile already has a card-bottom separator via `box-shadow: inset 0
     -1px 0` on `tbody tr`, so the desktop expanded-panel `border-bottom`
     rule would stack a second line below it. Reset it here. */
  .eval-table tbody tr.is-expandable.is-expanded + tr.row-details td {
    border-bottom: 0;
  }
  .row-detail-summary {
    max-width: none;
  }
  .row-detail-grid {
    grid-template-columns: 1fr;
    gap: 8px;
    padding-left: 0;
  }
  /* Rev chips sit on their own line under the REVISIONS label in the
     stacked layout — flush them to the left edge and add a small
     top margin so they breathe under the label. */
  .rev-chip {
    margin-left: 0;
    margin-top: 4px;
  }
  .eval-table tr.row-details .row-detail-line-hide-mobile {
    display: none;
  }
  /* This table has no per-row data-audience-group, so its rows would
     otherwise fall through to the generic tr border-left default set
     above. Nothing here calls for per-row audience coloring, so drop the
     stripe outright instead of wiring up that attribute. */
  .search-results-table tbody tr {
    border-left: none;
  }
}

/* ── Cross-mailing search ─────────────────────────────────────── */

.search-form {
  display: flex;
  gap: 0.75rem;
  align-items: center;
}

.mailing-search-form {
  margin-bottom: 1.5rem;
}

.search-submit {
  flex: 0 0 auto;
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--accent-blue-higher-contrast);
  border-radius: 8px;
  background: var(--accent-blue-higher-contrast);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s;
}

.search-submit:hover {
  filter: brightness(1.08);
}

.search-empty {
  color: var(--text-secondary);
  margin-top: 1rem;
}

.search-active-filter {
  font-size: 13px;
  color: var(--text-secondary);
  margin: 0 0 0.75rem;
}

.search-revisions {
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Unlike the per-mailing index, the search page has no persistent sticky filter
   bar above the table (the search form scrolls away with the page), so pin the
   sticky header at the very top of the viewport instead of the index's
   filter-bar-height offset — otherwise it floats ~one row below the top. */
.eval-table.search-results-table thead th {
  top: 0;
}

/* The index uses JS to add `.is-pinned` (flattening the header's rounded top
   corners) while the header is stuck; the search page has no JS, so the rounded
   corners would stay and reveal the row scrolling behind through the cutout.
   The search header is effectively always pinned, so flatten its top corners
   permanently — mirrors the `.is-pinned` rules above. */
.eval-table.search-results-table {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
.eval-table.search-results-table thead th:first-child {
  border-top-left-radius: 0;
}
.eval-table.search-results-table thead th:last-child {
  border-top-right-radius: 0;
}

/* Results table is a borderless, unrounded list, not a boxed card: keep only
   horizontal rules between rows (drop box border/radius and the header top border). */
.eval-table.search-results-table {
  border-left: none;
  border-right: none;
  border-bottom: none;
  border-radius: 0;
}
.eval-table.search-results-table thead th {
  border-top: none;
}

/* The whole result row toggles its details (paper-search.js). Hover feedback
   only under (hover: hover) so touch devices don't hold a stuck hover after a tap. */
.eval-table.search-results-table tbody tr:not(.row-details) {
  cursor: pointer;
}
@media (hover: hover) {
  .eval-table.search-results-table tbody tr:not(.row-details):hover {
    background: var(--bg-hover, #f1f3f6);
  }
}

.search-results-table tbody tr.row-zebra {
  background: #f7f9fc;
}

/* Column widths. Search-specific col classes (not the shared `col-*` ones) so
   these don't collide with the global `.eval-table … col.col-*` width rules and
   no specificity fight / inline styles are needed. search-col-audit carries
   only a colored dot, so it needs little width; search-col-docdate is a plain
   YYYY-MM-DD string, similarly compact; search-col-select is a single
   checkbox and hidden outside select mode (see below), so it needs the least
   width of all. These, plus Authors/Audience, come out of Title, which has
   the most slack, keeping these six percentage-based columns summing to
   100%. Paper is a fixed `em` width, not a percentage, since its content
   (caret + ~7-8 char id) needs the same room at any table width. A percentage
   share is either too cramped just above the mobile card breakpoint or (to
   avoid that) wastefully wide on desktop, where the freed space is better
   spent on Title. This is a different case from `min-width` (elsewhere
   avoided because Firefox ignores it on `<col>`); plain `width` on one
   fixed-unit `<col>` alongside percentage siblings is standard
   `table-layout:fixed` behavior. */
.search-results-table col.search-col-select    { width: 3%; }
.search-results-table col.search-col-paper     { width: 8.5em; }
.search-results-table col.search-col-title     { width: 44%; }
.search-results-table col.search-col-authors   { width: 23%; }
.search-results-table col.search-col-audience  { width: 14%; }
.search-results-table col.search-col-docdate   { width: 10%; }
.search-results-table col.search-col-audit     { width: 6%; }

/* Select column: collapsed until "Select" is clicked (data-selection-mode="on"
   on the table, set by paper-search.js). This does NOT put `display: none` on
   the `<th>`/`<td>` cells themselves, since a `display: none` table cell is
   removed from the row's cell grid entirely, and with a fixed 7-`<col>`
   colgroup that shifts every later column's width assignment left by one
   (the "Paper" column would render under search-col-select's 3% width
   instead of its own, looking squeezed/missing). Collapsing the `<col>`'s
   own width to 0 instead keeps the cell grid at a constant 7 real cells per
   row regardless of mode, so no column ever shifts. Hidden checkboxes must
   drop out of the tab order/AT tree, not just go invisible, which is
   handled below by `display: none` on the checkbox `<input>` itself:
   hiding a cell's child doesn't affect the table's column count, only
   hiding the cell/column does. */
.search-results-table:not([data-selection-mode="on"]) col.search-col-select {
  width: 0;
}
.search-results-table:not([data-selection-mode="on"]) .col-select {
  padding: 0;
  border: none;
}
.search-results-table:not([data-selection-mode="on"]) .col-select input {
  display: none;
}

/* Sits inline with the Select/Export buttons in .search-select-toolbar
   (see search.html.j2), sharing that container's own `gap`, same tone/size
   as .row-count. */
#selection-count {
  display: block;
  font-size: 13px;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Same pill shape as .mailing-preset above (rounded-full, outlined default /
   filled-blue "pressed" state), reused here so the two toolbars read as one
   visual language rather than two different button styles. */
#select-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--font-size-sm, 14px);
  line-height: 1;
  font-weight: 600;
  padding: 6px 16px;
  border-radius: var(--radius-lg, 10px);
  border: 1.5px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  color: var(--text-secondary);
  cursor: pointer;
}

#select-toggle:hover {
  background: var(--bg-hover, #f1f3f6);
}

#select-toggle .status-svg {
  width: 16px;
  height: 16px;
}

#select-toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

#export-selected {
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--font-size-sm, 14px);
  line-height: 1;
  font-weight: 700;
  padding: 6px 16px;
  border-radius: var(--radius-lg, 10px);
  border: 1.5px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

#export-selected:hover {
  filter: brightness(1.08);
}

#export-selected:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  filter: none;
}

/* "Select" is JS-only: without JS there's no way to toggle
   data-selection-mode, so the button would do nothing at all. Hidden by
   default, same as `.no-js .mailing-presets` above. */
.no-js #select-toggle {
  display: none;
}

.export-status-main {
  max-width: 640px;
  margin: 2rem auto;
  padding: 0 1rem;
}

.export-status-card {
  border: 1px solid var(--border-default, #e1e4ea);
  border-radius: 8px;
  padding: 1.5rem;
}

.export-status-heading {
  margin-top: 0;
}

.export-status-notice {
  color: var(--text-secondary);
  margin-bottom: 1rem;
}

.export-status-actions {
  margin-top: 1.5rem;
}

.export-status-button {
  font: inherit;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  padding: 8px 20px;
  border-radius: 999px;
  border: 1px solid var(--accent-blue-higher-contrast);
  background: var(--accent-blue-higher-contrast);
  color: #fff;
  cursor: pointer;
}

.export-status-button:hover {
  filter: brightness(1.08);
  color: #fff;
  text-decoration: none;
}

/* Larger dot for the Audit column specifically — the shared status_svg
   macro's default 16px (set via width/height attributes on the <svg> itself,
   in eval/_table_macros.html.j2) reads too small as a plain colored dot.
   Scoped to this column only so mailing_index.html.j2's Disposition column
   (same macro, same default size) is unaffected. */
.search-results-table td.col-audit .status-svg {
  width: 2.5rem;
  height: 2.5rem;
}

/* Marks a row whose disposition carries a recorded plenary date, per the
   design mockup: a distinct square-outline-plus-inner-square glyph
   (recorded_icon in _table_macros.html.j2), in the same green already used
   for "positive/confirmed" states elsewhere (.status-accepted,
   .status-sound). The design pairs this with the Audit column's own green
   "Sound" dot in the very next cell without treating that as a conflict. */
.disposition-date-icon {
  display: inline-flex;
  align-items: center;
  vertical-align: -3px;
  margin-left: 4px;
  color: var(--green);
}
.disposition-date-icon svg {
  width: 14px;
  height: 14px;
}

/* At 2.5rem, the Audit dot is taller than every other cell's ordinary
   single-line text, so it alone forces each row to grow taller than a text
   line. `.eval-table tbody td`'s shared `vertical-align: top` (tuned for
   mailing_index.html.j2's row-details grid) then reads as "top of a
   dot-sized row" for every cell. Centering every cell (not just Audit) within
   the row is what actually lines the dot up with the rest of the row's content,
   rather than fighting it with a per-column offset that would only hold for
   this exact icon size / text size pair. */
/* Shorter header row for the search table (the per-mailing table keeps the
   taller `.eval-table thead th` padding). */
.eval-table.search-results-table thead th {
  padding-top: 6px;
  padding-bottom: 6px;
}

.search-results-table tbody td {
  vertical-align: middle;
}

.search-results-table tbody tr:not(.row-details, .search-group-header-row) td {
  border-bottom: 1px solid #e4e9f0;
  height: 48px;
}

/* Row caret. The header's own copy stays purely decorative (see its
   aria-hidden span, visibility: hidden rule below); the per-row copy is
   the visible glyph inside a real `.row-expand-toggle` button. Both share
   font-size/color here (no ancestor `.search-chip`/`.search-rollup` context to
   inherit from) so they stay the same size; the same size keeps "Paper"
   visually aligned with the paper id text underneath it. */
.search-results-table th.col-paper .search-caret,
.search-results-table td[data-label="Paper"] .search-caret {
  display: inline-block;
  margin-right: 6px;
  font-size: 21px;
  font-weight: 400;
}

@media (min-width: 1025px) {
  .search-results-table th.col-paper .search-caret,
  .search-results-table td[data-label="Paper"] .search-caret {
    margin-right: 20px;
  }
}

.search-results-table td[data-label="Paper"] .search-caret {
  color: #8b95a4;
}

/* Not a visible header glyph — just reserves the same leading width the
   data rows' caret occupies, so the "Paper" label lines up with the paper
   id text below it rather than sitting above the caret instead. */
.search-results-table th.col-paper .search-caret {
  visibility: hidden;
}

/* Real button now: reuses mailing_index.html.j2's own `.row-expand-toggle`
   reset (appearance: none, no border/background, cursor: pointer) so the
   two pages' toggle controls behave identically, but overrides its
   margin-right to 0. The wrapped `.search-caret` above already carries
   the margin that keeps it aligned with the header's copy, and the
   button's own margin would otherwise double that gap. */
.search-results-table td[data-label="Paper"] {
  white-space: nowrap;
}
.search-results-table td[data-label="Paper"] a {
  /* Keep the paper id a blue link (generic `.eval-table td a` is now dark). */
  color: #2563eb;
  font-weight: 600;
  vertical-align: middle;
}
.search-results-table td[data-label="Paper"] .row-expand-toggle {
  margin-right: 0;
  vertical-align: middle;
}
.search-results-table td[data-label="Paper"] .row-expand-toggle .search-caret {
  transition: transform 0.15s;
}
.search-results-table td[data-label="Paper"] .row-expand-toggle[aria-expanded="true"] .search-caret {
  transform: rotate(90deg);
}

/* Reveal the row-detail panel. Unlike mailing_index.html.j2's accordion
   (a `.is-expandable.is-expanded` class toggled on the whole row, since
   clicking anywhere on that page's row opens it), this page's rows are
   only interactive via the toggle button itself. Clicking the Title or
   an author link must not also expand the panel. `:has()` keys the reveal
   off the button's own `aria-expanded` state instead of a row-level class,
   so there's no need to mark the whole row "expandable" (and no risk of
   the shared `.eval-table tbody tr.is-expandable { cursor: pointer }` rule
   implying the whole row is clickable when it isn't). */
.search-results-table tbody tr:has(> td .row-expand-toggle[aria-expanded="true"]) + tr.row-details td {
  border-bottom: 1px solid #e4e9f0;
}
.search-results-table tbody tr:has(> td .row-expand-toggle[aria-expanded="true"]) + tr.row-details .row-detail-grid-wrap {
  grid-template-rows: 1fr;
}
.search-results-table tbody tr:has(> td .row-expand-toggle[aria-expanded="true"]) + tr.row-details .row-detail-grid {
  padding-block: 20px;
  opacity: 1;
  /* See .row-detail-grid's own base rule: visibility is what actually keeps
     collapsed content out of the tab order/a11y tree; this page's reveal
     selector is its own rule (`:has()`, not the shared `.is-expandable.
     is-expanded` class), so it needs its own un-delayed flip back too. */
  visibility: visible;
  transition: padding-block 140ms ease-out, opacity 140ms ease-out;
}

/* Shallower left indent than mailing_index.html.j2's shared default
   (`calc(105px + 15px)`, which indents panel content past the entire
   Paper column): the design shows this page's panel starting
   much closer to the row's own left edge, near the toggle button rather
   than the paper id. Scoped to this table only. mailing_index's own
   layout isn't part of this change. */
.search-results-table .row-detail-grid {
  padding-left: 32px;
  max-width: calc(32px + 65ch);
}

/* Matches the design's uppercase treatment. Transform only. The
   underlying text stays "Sound"/"Weakened"/etc. (get_audit_label_kind's own
   label), same value the collapsed row's dot uses for its title/aria-label,
   so nothing downstream that reads the label text needs to change. Laid
   out like .github-issue-link (icon + short text label), pairing the same
   colored dot the collapsed Audit column shows via .status-icon/.status-{kind},
   but as a plain CSS circle, not `_status_svg`'s icon. That macro's dot is
   a small circle inside a much bigger 24x24 viewBox (mostly invisible
   padding, built for a standalone icon-only cell), which read as "too much
   space around it" / not left-aligned once placed next to text here.
   The dot is aria-hidden here (unlike the collapsed column's role="img"
   copy) since the adjacent visible text already carries the same meaning
   ("Sound" etc.). With both present, a screen reader would otherwise
   announce it twice. */
.audit-verdict-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  text-transform: uppercase;
  text-decoration: none;
}
.audit-verdict-link:hover {
  text-decoration: underline;
}
/* Text/icon color follows the verdict (.status-sound/.status-weakened/etc.,
   already defined above for the dot), via currentColor -- not the default
   link color. */
.audit-verdict-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
/* Shared by every .external-link-icon usage (Audit, Tracking issue)
   currentColor already gives it the right color from its own link; this
   just stops it from being squished if the link text wraps. */
.external-link-icon {
  flex-shrink: 0;
}
/* The .status-{kind} color rules above (0,1,0 specificity) lose to
   `.eval-table td a`'s own color (0,1,2).
   Re-declared here, scoped under `.search-results-table tbody td`, so the
   verdict color actually wins and the text/arrow (via currentColor) match
   the dot instead of sitting in the default link color.

   Same --audit-* tokens the column and mobile dots use: one verdict is one
   color everywhere it appears, text included. That is a deliberate call
   against contrast -- --audit-weakened is 1.43:1 on white and
   --audit-insufficient 2.57:1, so "Partial" and "Insufficient" do not meet
   WCAG AA as text. Darkening either one here would reintroduce the mismatch
   this is here to remove; fixing it properly means the design picking
   text-safe values for those two verdicts. */
/* Weight has to be re-declared at this same scoped specificity for the reason
   directly above: `.eval-table td a` pins font-weight to 400 and outranks the
   bare `.audit-verdict-link` block. Heavier strokes lay down more pixels of the
   hue, which buys back some of the legibility the verdict colors cost. It does
   not make them compliant -- the large-text 3:1 allowance wants 18.66px bold
   and this is smaller -- but it is a real gain at no cost elsewhere. */
.search-results-table tbody td .audit-verdict-link {
  font-weight: 600;
}
.search-results-table tbody td .audit-verdict-link.status-sound        { color: var(--audit-sound); }
.search-results-table tbody td .audit-verdict-link.status-weakened     { color: var(--audit-weakened); }
.search-results-table tbody td .audit-verdict-link.status-undermined   { color: var(--audit-undermined); }
.search-results-table tbody td .audit-verdict-link.status-insufficient { color: var(--audit-insufficient); }

/* "Click for more information" question-mark next to the Audit label. Native
   `title` shows on hover, and (since it's focusable) on keyboard focus too.
   Grey/muted, distinct from the verdict-colored value below it. This is generic
   help, not itself part of the verdict. */
.audit-info-icon {
  display: inline-flex;
  align-items: center;
  color: var(--text-muted);
  margin-left: 0.25rem;
  vertical-align: -2px;
  cursor: default;
}
.audit-info-icon:hover,
.audit-info-icon:focus-visible {
  color: var(--text-secondary);
}

/* Long Title/Authors/Paper/Doc Date content wraps inside its own column via
   the base .eval-table tbody td rule (white-space: normal + overflow-wrap:
   anywhere); no per-column overrides needed here. */

/* Title links sit at their cell's normal text color at rest (the mailing
   index mutes it and makes the row the tap target instead) and turn
   accent-blue only on hover. `color: inherit` overrides the mailing index's
   muted `color: inherit` rule on Title. */
.search-results-table tbody td[data-label="Title"] a {
  pointer-events: auto;
  color: #16202e;
  font-family: "Inter", "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  font-weight: 500;
}

.search-results-table tbody td[data-label="Title"] a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* ── Phase badge (pre-/post-meeting label) ────────────────── */

.phase-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  /* Status-tag family: mono + shared radius/size/weight tokens so the phase
     badge matches the audience tags. */
  font-family: var(--badge-font);
  border-radius: var(--badge-radius);
  font-size: var(--badge-size);
  font-weight: var(--badge-weight);
  border: 1px solid;
  white-space: nowrap;
  vertical-align: middle;
  margin-top: 4px;
}
.phase-badge--pre  { background: #e8f0fb; color: #1252a3; border-color: #adcaed; }
.phase-badge--post { background: #e5f2eb; color: #196840; border-color: #a0d4b8; }
.phase-badge--unassigned { background: #eceef2; color: #5b6675; border-color: #d7dbe3; }
.search-results-table .phase-badge { background: #eceef2; color: #5b6675; border-color: #d7dbe3; }

/* ── Group header row ("Group by date?" checked) ────────────────── */

/* One header row per mailing cluster, holding the mailing's date and label.
   A <th scope="rowgroup">, not a <td>, so assistive tech announces it as a
   heading for the rows that follow, which means none of the table's td
   scoped rules (padding, font size, the row-details cell reset) apply to it
   automatically; every visual property here is stated explicitly rather than
   assumed to be inherited. The row itself needs no display override at any
   width: it already qualifies for the search table's own
   `.eval-table.search-results-table tbody tr { display: table-row }` rule,
   the same one every paper row relies on. */
.search-results-table tbody tr.search-group-header-row {
  background: var(--ink-soft, #5b6675);
}
.search-results-table tbody tr.search-group-header-row th {
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  color: #fff;
  border-bottom: none;
}

/* One row: Audience dropdown, the search box (grows to fill the middle), Mailings
   dropdown — Audience filter is a batch-select dropdown (native <details>/<summary>)
   over the group taxonomy. Checking boxes stages a pending selection; only Apply
   commits and navigates. Each dropdown's panel is positioned absolutely (relative to
   its own `.audience-dropdown`/`.mailings-dropdown`) so opening it overlays the
   results table instead of pushing the row down. The result-row audience badges
   below keep the shared `.badge-*` colors (see `.search-badge`), matching the
   Audience dropdown chips and the FILTERS-row chips. */
.search-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0;
}

.search-toolbar .search-form {
  flex: 1 1 260px;
  min-width: 200px;
}

/* .filter-bar's own margin-bottom (elsewhere, spacing below it and a results
   table on the per-mailing index page) has nothing below it to space out
   here. Left in place, that trailing margin makes .search-form's box taller
   on its bottom edge only, which skews this row's own vertical centering
   and pushes the visible search box above the Audience/Mailings buttons.
   .search-toolbar already carries the row's own bottom margin. */
.search-toolbar .filter-bar {
  margin-bottom: 0;
  /* .filter-bar has no flex-grow of its own, so without this it just sits at
     its content width inside .search-form's already-wide box, leaving empty
     space between it and the Mailings button. .search-wrap (the visible
     pill) already has flex:1 1 auto, so growing filter-bar itself is the
     only piece needed for the pill to stretch the rest of the way. */
  flex: 1 1 auto;
}

/* Scoped to this toolbar only. .search-wrap/.filter-search are shared with
   mailing_index.html.j2's and eval/index.html.j2's own search boxes, so the
   rounder pill shape here must not leak into those. */
.search-toolbar .search-wrap {
  border-radius: var(--radius-lg, 10px);
  padding-top: 7px;
  padding-bottom: 7px;
}

.search-toolbar .filter-search {
  font-size: 14px;
  line-height: 1.4;
  padding-top: 0;
  padding-bottom: 0;
}

/* The magnifying-glass icon doubles as the submit control (a real button,
   not decorative-only markup, so it's a discoverable click target even for
   anyone who doesn't already expect Enter-to-submit on a lone text field). */
.search-icon-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  background: none;
  border: none;
  padding: 0 2px;
  color: var(--text-secondary);
  cursor: pointer;
}

.search-icon-btn:hover,
.search-icon-btn:focus-visible {
  color: var(--text-primary);
}

.audience-dropdown,
.mailings-dropdown {
  position: relative;
  flex: 0 0 auto;
}

/* Padding, border-width, and font-size match .mailings-dropdown-summary's
   own box exactly, so the two buttons sitting side by side in the toolbar
   are the same height -- only the border/background/text colors stay
   neutral instead of that button's blue accent. */
.audience-dropdown-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.4;
  padding: 7px 16px;
  border-radius: var(--radius-lg, 10px);
  border: 1.5px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  color: var(--text-primary);
  cursor: pointer;
  list-style: none;
}

.audience-dropdown-summary::-webkit-details-marker {
  display: none;
}

/* Same solid-triangle caret as .mailings-dropdown-summary::after, so the two
   buttons that sit side by side in the toolbar share one caret language. */
.audience-dropdown-summary::after {
  content: "";
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  margin-top: 2px;
  transition: transform 0.15s;
}

.audience-dropdown[open] .audience-dropdown-summary {
  border-color: var(--text-muted, #9aa0aa);
}

.audience-dropdown[open] .audience-dropdown-summary::after {
  transform: rotate(180deg);
  margin-top: -2px;
}

.audience-dropdown-form {
  position: absolute;
  /* Extra offset so the panel clears the search box (taller than this trigger
     button); a smaller offset left its outline looking clipped. */
  top: calc(100% + 14px);
  left: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 300px;
  padding: 16px;
  border-radius: 12px;
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  box-shadow: 0 12px 32px rgba(15, 20, 25, 0.14);
}

.audience-filter-input-wrap {
  position: relative;
}

.audience-filter-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted, #9aa0aa);
  pointer-events: none;
}

.audience-filter-input {
  width: 100%;
  padding: 7px 10px 7px 32px;
  border-radius: 8px;
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  color: var(--text-primary);
  font-size: 13px;
}

.audience-filter-input:focus {
  outline: none;
  border-color: var(--accent-blue-higher-contrast);
}

.audience-dropdown-sections {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-height: 340px;
  overflow-y: auto;
}

.audience-section {
  border: none;
  padding: 0;
  margin: 0;
}

.audience-section legend {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #9aa0aa);
  padding: 0 0 6px;
}

.audience-checkbox-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  cursor: pointer;
}

.audience-checkbox-row input[type="checkbox"] {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--accent-blue-higher-contrast);
}

.audience-checkbox-row[hidden] {
  display: none;
}

.audience-checkbox-row .badge {
  font-size: 12px;
  font-weight: 600;
  padding: 2px 10px;
  border-radius: 6px;
}

.audience-dropdown-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 12px;
  border-top: 1px solid var(--border-default, #e1e4ea);
}

.audience-clear {
  border: none;
  background: none;
  padding: 4px 2px;
  font-size: 13px;
  font-weight: 500;
  color: var(--accent-blue-higher-contrast);
  cursor: pointer;
}

.audience-clear:hover {
  text-decoration: underline;
}

.audience-apply {
  border: none;
  padding: 7px 20px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  background: var(--accent-blue-higher-contrast);
  color: #fff;
  cursor: pointer;
}

.audience-apply:hover {
  filter: brightness(1.08);
}

/* Wraps .search-pills (left) and .search-select-toolbar (right) on one line;
   either can be absent (no active filters / no results) without breaking the
   other's position, since margin-left: auto on the toolbar (not
   justify-content: space-between, which only pushes a lone child to the
   start) keeps it pinned to the right edge regardless of whether its
   sibling pills div is present. */
.search-filter-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 10px;
  /* Breathing room below the toolbar so Select/Export don't crowd the table.
     On the wrapper so one gap holds however many lines the FILTERS chips wrap onto. */
  margin-bottom: 1.5rem;
}

.search-select-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

/* Select/Export as their own flex row, nested inside .search-select-toolbar
   alongside #selection-count: keeps the two buttons together as a single
   unit if the toolbar ever needs to wrap (see the mobile override), rather
   than each button being its own flex item that could wrap independently. */
.search-select-buttons {
  display: flex;
  align-items: center;
  gap: 12px;
}

.search-pills {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.search-pills-label {
  font-family: var(--font-body);
  font-size: var(--font-size-xs, 12px);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted, #8b95a6);
}

.search-pills-sep {
  flex: none;
  width: 1.5px;
  height: 22px;
  background: var(--border-default, #e1e4ea);
}

.search-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--font-size-sm, 14px);
  line-height: 1;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: var(--radius-pill, 999px);
  border: 1.5px solid var(--border-default, #e1e4ea);
  background: var(--bg-soft, #f6f7f9);
  color: var(--ink-soft, #5b6675);
  text-decoration: none;
  transition: border-color 0.15s, color 0.15s;
}

.search-pill:hover {
  border-color: var(--text-muted, #9aa0aa);
  text-decoration: none;
}

/* Per-audience-group tint, so an applied audience filter chip visually
   matches the same group's color in the Audience dropdown checklist and the
   results-table Audience column above. Declared after .search-pill:hover so
   these win the tie on equal specificity (one class + :hover each). */
.search-pill--ewg       { background: var(--chip-ewg-bg);       color: var(--chip-ewg-text);       border-color: var(--chip-ewg-border); }
.search-pill--lewg      { background: var(--chip-lewg-bg);      color: var(--chip-lewg-text);      border-color: var(--chip-lewg-border); }
.search-pill--cwg       { background: var(--chip-cwg-bg);       color: var(--chip-cwg-text);       border-color: var(--chip-cwg-border); }
.search-pill--lwg       { background: var(--chip-lwg-bg);       color: var(--chip-lwg-text);       border-color: var(--chip-lwg-border); }
.search-pill--sg        { background: var(--chip-sg-bg);        color: var(--chip-sg-text);        border-color: var(--chip-sg-border); }
.search-pill--wg21      { background: var(--chip-wg21-bg);      color: var(--chip-wg21-text);      border-color: var(--chip-wg21-border); }
.search-pill--direction { background: var(--chip-direction-bg); color: var(--chip-direction-text); border-color: var(--chip-direction-border); }
.search-pill--unknown   { background: var(--chip-unknown-bg);   color: var(--chip-unknown-text);   border-color: var(--chip-unknown-border); }
.search-pill--author    { background: var(--chip-author-bg);    color: var(--chip-author-text);    border-color: var(--chip-author-border); }

.search-pill--ewg:hover       { border-color: var(--chip-ewg-text);       color: var(--chip-ewg-text); }
.search-pill--lewg:hover      { border-color: var(--chip-lewg-text);      color: var(--chip-lewg-text); }
.search-pill--cwg:hover       { border-color: var(--chip-cwg-text);       color: var(--chip-cwg-text); }
.search-pill--lwg:hover       { border-color: var(--chip-lwg-text);       color: var(--chip-lwg-text); }
.search-pill--sg:hover        { border-color: var(--chip-sg-text);        color: var(--chip-sg-text); }
.search-pill--wg21:hover      { border-color: var(--chip-wg21-text);      color: var(--chip-wg21-text); }
.search-pill--direction:hover { border-color: var(--chip-direction-text); color: var(--chip-direction-text); }
.search-pill--unknown:hover   { border-color: var(--text-muted, #9aa0aa); color: var(--text-primary); }
.search-pill--author:hover    { border-color: var(--text-muted, #9aa0aa); color: var(--text-primary); }

/* The Mailings summary chip opens the Mailings panel rather than removing
   anything directly, so it reads visually as a mini dropdown trigger
   (filled pill + its own caret) instead of a removable ×-chip. */
.search-mailings-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: var(--font-size-sm, 14px);
  line-height: 1;
  font-weight: 600;
  /* Match the audience .search-pill box so the two chips line up on the FILTERS row. */
  padding: 6px 12px;
  border-radius: 999px;
  border: 1.5px solid var(--chip-mailings-border);
  background: var(--chip-mailings-bg);
  color: var(--chip-mailings-text);
  appearance: none;
  cursor: pointer;
}

.search-mailings-chip:hover {
  border-color: var(--chip-mailings-text);
}

.search-mailings-chip-caret {
  width: 0;
  height: 0;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 4px solid currentColor;
}

.search-clear-all {
  font-size: var(--font-size-sm, 14px);
  font-weight: 600;
  color: var(--accent-royal, #2563eb);
  text-decoration: none;
}

.search-clear-all:hover {
  text-decoration: underline;
}

/* Rendered on the default scope, where clearing is a no-op. Muted rather than
   hidden so the row's shape doesn't shift as filters come and go. */
.search-clear-all[aria-disabled="true"] {
  color: var(--ink-soft, #5b6675);
  cursor: default;
}

.search-clear-all[aria-disabled="true"]:hover {
  text-decoration: none;
}

/* Result-row audience badges: colored `.badge-*`, clickable. Shared by the
   table Audience column and the expanded detail rows, so all the pill styling
   lives here; shape mirrors the Audience dropdown chips. */
.search-badge {
  cursor: pointer;
  text-decoration: none;
  font-size: 12px;
  /* Explicit line-height so the pill's box is identical in the table column and
     the expanded detail rows (instead of inheriting each context's body line-height). */
  line-height: 1.4;
  padding: 2px 10px;
  border-radius: 6px;
  transition: filter 0.15s, background 0.15s, color 0.15s, border-color 0.15s;
}
/* Two classes so the pill weight beats `.eval-table td a` (font-weight:400). */
.badge.search-badge { font-weight: 600; }

/* Three classes so per-group color beats the Paper-column rule, which otherwise
   leaks into the expanded panel's colspan td and darkens the pills. */
.badge.search-badge.badge-direction { color: var(--clr-direction); }
.badge.search-badge.badge-ewg       { color: var(--clr-ewg); }
.badge.search-badge.badge-lewg      { color: var(--clr-lewg); }
.badge.search-badge.badge-cwg       { color: var(--clr-cwg); }
.badge.search-badge.badge-lwg       { color: var(--clr-lwg); }
.badge.search-badge.badge-sg        { color: var(--clr-sg); }
.badge.search-badge.badge-wg21      { color: var(--clr-wg21); }
.badge.search-badge.badge-unknown   { color: var(--text-secondary); }

/* Hover deepens border + text to the group's full color, keeping the pastel
   fill; scoped no-underline beats the generic `.eval-table td a:hover`. */
.eval-table td a.search-badge:hover { text-decoration: none; }
.search-badge.badge-direction:hover { border-color: var(--clr-direction); color: var(--clr-direction); }
.search-badge.badge-ewg:hover       { border-color: var(--clr-ewg);       color: var(--clr-ewg); }
.search-badge.badge-lewg:hover      { border-color: var(--clr-lewg);      color: var(--clr-lewg); }
.search-badge.badge-cwg:hover       { border-color: var(--clr-cwg);       color: var(--clr-cwg); }
.search-badge.badge-lwg:hover       { border-color: var(--clr-lwg);       color: var(--clr-lwg); }
.search-badge.badge-sg:hover        { border-color: var(--clr-sg);        color: var(--clr-sg); }
.search-badge.badge-wg21:hover      { border-color: var(--clr-wg21);      color: var(--clr-wg21); }
.search-badge.badge-unknown:hover   { border-color: var(--text-muted, #9aa0aa); color: var(--text-primary); }

/* Audience cell holds one or more badge links; keep them on a tidy wrapped row. */
.eval-table.search-results-table tbody td.col-audience {
  display: table-cell;
}
.search-results-table tbody td.col-audience .col-audience-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-content: flex-start;
}

/* Author names are click-to-filter links. Styled like the per-mailing `.author-link`:
   regular cell text at rest (not the default `td a` link blue), underlined in primary
   text color on hover; the active author (currently filtered on) is bold + underlined.
   Scoped under `.search-results-table tbody td` to outrank `.eval-table td a`. */
.search-results-table tbody td .search-author-link {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s;
}

.search-results-table tbody td .search-author-link:hover {
  color: var(--text-primary);
  text-decoration: underline;
}

.search-results-table tbody td .search-author-link.is-active {
  font-weight: 600;
  text-decoration: underline;
}

/* Mailings filter is a second batch-select dropdown that has its own independent
  <form>, same interaction model as .audience-dropdown above (native <details>/<summary>,
   checkboxes stage a pending selection, only Apply commits/navigates). Year rows
   are themselves nested <details>, one level deeper, for the per-year month picker. */
.mailings-dropdown-summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  padding: 7px 16px;
  border-radius: var(--radius-lg, 10px);
  border: 1.5px solid var(--accent-blue-higher-contrast);
  background: var(--bg-card, #fff);
  color: var(--accent-blue-higher-contrast);
  cursor: pointer;
  list-style: none;
  transition: background-color 0.15s;
}

.mailings-dropdown-summary:hover {
  background: var(--accent-bg, #edf2fe);
}

.mailings-dropdown-summary::-webkit-details-marker {
  display: none;
}

.mailings-dropdown-summary::after {
  content: "";
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  margin-top: 2px;
  transition: transform 0.15s;
}

.mailings-dropdown[open] .mailings-dropdown-summary::after {
  transform: rotate(180deg);
  margin-top: -2px;
}

.mailings-dropdown-panel {
  position: absolute;
  /* Same clearance as the Audience panel so it clears the taller search box. */
  top: calc(100% + 14px);
  /* Right-aligned to the button, not left-aligned like Audience's. The
     Mailings button sits at the right edge of the toolbar row, so opening
     the panel leftward keeps it on-screen instead of overflowing past the
     right edge of the page. */
  right: 0;
  z-index: 20;
  width: 320px;
  max-width: calc(100vw - 32px);
  padding: 16px;
  border-radius: 12px;
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  box-shadow: 0 12px 32px rgba(15, 20, 25, 0.14);
}

/* Non-interactive summary of the currently checked selection: grey, not
   clickable, purely informational (unlike the preset buttons below). The
   leading rule fills the space to the left of the badges rather than
   leaving it blank. */
.mailing-selection-summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-bottom: 10px;
}

.mailing-selection-summary::before {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border-default, #e1e4ea);
}

.mailing-selection-badge {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--bg-hover, #f1f3f6);
  color: var(--text-secondary);
}

.mailing-instructions {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 0 0 10px;
}

/* JS-only: these buttons only stage checkboxes, they never navigate or submit
   on their own, so without JS to act on them they'd do nothing at all: they
   would be hidden, rather than shown-but-dead. See the `no-js` class removal
   script at the top of this page's <head>. */
.no-js .mailing-presets {
  display: none;
}

.mailing-presets {
  display: flex;
  gap: 8px;
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-default, #e1e4ea);
}

.mailing-preset {
  display: inline-flex;
  align-items: center;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 6px 16px;
  border-radius: 999px;
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  color: var(--text-secondary);
  text-decoration: none;
  cursor: pointer;
}

.mailing-preset:hover {
  background: var(--bg-hover, #f1f3f6);
  text-decoration: none;
}

.mailing-preset.is-active {
  background: var(--accent-blue-higher-contrast);
  border-color: var(--accent-blue-higher-contrast);
  color: #fff;
  font-weight: 600;
}

.mailing-preset.is-active:hover {
  background: var(--accent-blue-higher-contrast);
  filter: brightness(1.08);
}

.mailings-dropdown-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.mailing-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.mailing-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 6px 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--text-link);
  background: var(--bg-card, #fff);
  color: var(--text-link);
}

.mailing-chip-remove {
  border: none;
  background: none;
  padding: 2px;
  line-height: 1;
  color: var(--text-link);
  cursor: pointer;
}

.mailing-chip-remove:hover {
  color: var(--accent-bright);
}

.mailing-year-list {
  display: flex;
  flex-direction: column;
  max-height: 300px;
  overflow-y: auto;
}

.mailing-year-row {
  border-bottom: 1px solid var(--bg-soft, #f6f7f9);
}

.mailing-year-row:last-child {
  border-bottom: none;
}

.mailing-year-row[hidden] {
  display: none;
}

.mailing-year-row-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 2px;
  cursor: pointer;
  list-style: none;
}

.mailing-year-row-summary::-webkit-details-marker {
  display: none;
}

/* Same corner-chevron rotate-on-open convention as elsewhere, drawn from two
   borders rather than the solid triangle used for .mailings-dropdown-summary,
   since here it points sideways (collapsed) rather than up/down. */
.mailing-year-row-summary::after {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--text-muted, #9aa0aa);
  border-bottom: 1.5px solid var(--text-muted, #9aa0aa);
  transform: rotate(-45deg);
  transition: transform 0.15s;
}

.mailing-year-row[open] > .mailing-year-row-summary::after {
  transform: rotate(45deg);
}

.mailing-year-checkbox {
  appearance: none;
  width: 15px;
  height: 15px;
  margin: 0;
  flex-shrink: 0;
  border-radius: 4px;
  border: 1.5px solid var(--border-default, #e1e4ea);
  background-color: var(--bg-card, #fff);
  background-position: center;
  background-repeat: no-repeat;
  background-size: 10px 10px;
  cursor: pointer;
}

.mailing-year-checkbox:checked,
.mailing-year-checkbox:indeterminate {
  background-color: var(--accent-blue-higher-contrast);
  border-color: var(--accent-blue-higher-contrast);
}

.mailing-year-checkbox:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.3L5 8.8L9.5 3.3' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.mailing-year-checkbox:indeterminate {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cline x1='3' y1='6' x2='9' y2='6' stroke='white' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

.mailing-year-label {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.mailing-year-summary-text {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-secondary);
}

.mailing-year-summary-text.is-active {
  color: var(--indigo);
}

.mailing-month-panel {
  background: var(--bg-soft, #f6f7f9);
  border-top: 1px solid var(--border-default, #e1e4ea);
  border-bottom: 1px solid var(--border-default, #e1e4ea);
  padding: 10px 12px 10px 23px;
}

.mailing-month-panel-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #9aa0aa);
  margin: 0 0 8px;
}

.mailing-month-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* The month toggle is a real checkbox underneath (native keyboard/screen-reader
   semantics, and the existing Apply/Clear/sync logic in paper-search.js keys off
   its name/value/checked state) with the box itself visually hidden below, so
   the label alone renders as the pill button the design calls for. */
.mailing-month-row {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  cursor: pointer;
}

.mailing-month-row:hover {
  background: var(--bg-hover, #f1f3f6);
}

.mailing-month-row input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.mailing-month-row:has(input:focus-visible) {
  outline: 2px solid var(--accent-blue-higher-contrast);
  outline-offset: 2px;
}

.mailing-month-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
}

.mailing-month-count {
  font-size: 12px;
  color: var(--text-secondary);
}

.mailing-month-row:has(input:checked) {
  background: var(--accent-dim);
  border-color: var(--indigo-border);
}

.mailing-month-row:has(input:checked):hover {
  background: var(--indigo-bg-hover);
  border-color: var(--indigo-border-hover);
}

.mailing-month-row:has(input:checked) .mailing-month-label,
.mailing-month-row:has(input:checked) .mailing-month-count {
  color: var(--indigo);
  font-weight: 700;
}

/* Add Year + and Group by date? sit on one row, per the mockup; the row (not
   `.mailing-add-year` itself) owns the separator above it now that it has a
   sibling to share the line with. The toggle is absolutely positioned in the
   row's top-right corner (rather than a flex sibling) so the <details> and
   its open panel can span the full dropdown width; only the
   summary pill itself is content-sized. */
.mailing-add-year-row {
  position: relative;
  border-top: 1px solid var(--border-default, #e1e4ea);
  padding-top: 10px;
}

.mailing-add-year-summary {
  display: inline-flex;
  align-items: center;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--bg-card, #fff);
  border: 1px solid var(--border-default, #e1e4ea);
  border-radius: 999px;
  padding: 6px 16px;
  cursor: pointer;
  list-style: none;
}

.mailing-add-year-summary:hover {
  background: var(--bg-hover, #f1f3f6);
}

.mailing-add-year[open] > .mailing-add-year-summary {
  background: var(--accent-dim);
  border-color: var(--indigo-border);
  color: var(--indigo);
}

.mailing-add-year-summary::-webkit-details-marker {
  display: none;
}

.mailing-add-year-panel {
  padding-top: 10px;
}

.mailing-add-year-label {
  font-size: 14px;
  font-weight: 400;
  color: var(--text-secondary);
  margin: 10px 0 6px;
}

.mailing-add-year-label:first-child {
  margin-top: 0;
}

.mailing-add-year-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.mailing-add-year-option {
  border: 1px solid var(--border-default, #e1e4ea);
  background: var(--bg-card, #fff);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-secondary);
  cursor: pointer;
}

.mailing-add-year-option:hover {
  background: var(--bg-hover, #f1f3f6);
}

.mailing-add-year-empty {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 0;
}

.mailing-add-year-actions {
  padding-top: 6px;
}

.mailing-add-year-clear {
  border: none;
  background: none;
  padding: 4px 2px;
  font-size: 13px;
  font-weight: 500;
  color: var(--accent-blue-higher-contrast);
  cursor: pointer;
}

.mailing-add-year-clear:hover {
  text-decoration: underline;
}

.mailing-group-by-toggle {
  /* Pinned to the row's top-right, beside the Add Year + pill. 10px matches
     the row's padding-top; the 6px vertical padding mirrors the pill's, so
     the toggle centers against the pill's height. */
  position: absolute;
  top: 10px;
  right: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 0;
  white-space: nowrap;
  font-size: 13px;
  color: var(--text-primary);
  cursor: pointer;
}

.mailings-dropdown-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 12px;
  border-top: 1px solid var(--border-default, #e1e4ea);
}

.mailings-clear {
  border: none;
  background: none;
  padding: 4px 2px;
  font-size: 13px;
  font-weight: 500;
  color: var(--accent-blue-higher-contrast);
  cursor: pointer;
}

.mailings-clear:hover {
  text-decoration: underline;
}

/* Inert once the selection is already the default there'd be nothing to reset. */
.mailings-clear:disabled {
  color: var(--text-muted, #9aa0aa);
  cursor: not-allowed;
}

.mailings-clear:disabled:hover {
  text-decoration: none;
}

.mailings-apply {
  border: none;
  padding: 7px 20px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  background: var(--accent-blue-higher-contrast);
  color: #fff;
  cursor: pointer;
}

.mailings-apply:hover {
  filter: brightness(1.08);
}

.mailings-apply:disabled {
  background: var(--bg-hover, #f1f3f6);
  color: var(--text-muted, #9aa0aa);
  cursor: not-allowed;
  filter: none;
}

.mailings-apply-warning {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 6px 0 0;
  text-align: right;
}

/* ── search results table stays a genuine table on mobile ─────────
   The "Mobile card breakpoint" block above (@media max-width:768px)
   converts .eval-table into mailing_index.html.j2's stacked-card layout
   (display: block/grid, headers hidden). The mobile design for
   .search-results-table calls for a genuine, narrower table instead:
   visible Paper/Title/Author headers, not a second stacked-card variant
   with a different grid-area set. So this opts the whole table out of
   that conversion rather than fighting it selector-by-selector. */
@media (max-width: 768px) {
  /* Force every part of this table back to its native table role,
     regardless of the generic block's overrides above (including the
     table element itself: that block sets `.eval-table, .eval-table
     tbody { display: block }`, not just tbody; leaving the table element
     blockified would keep table-layout:fixed/colgroup widths inert even
     with tbody/tr/td individually fixed). No `!important` needed: the
     table carries both `eval-table` and `search-results-table` classes at
     once, so qualifying it with both here (rather than just the one class
     the generic rules use) outweighs every rule it needs to beat on
     specificity alone, regardless of where either rule sits in the file. */
  .eval-table.search-results-table       { display: table; }
  .eval-table.search-results-table thead { display: table-header-group; }
  .eval-table.search-results-table tbody { display: table-row-group; }
  .eval-table.search-results-table tbody tr { display: table-row; }
  .eval-table.search-results-table thead th,
  .eval-table.search-results-table tbody td { display: table-cell; }
  /* `tr.row-details` needs one class more than the plain `tbody tr` rule
     above to outweigh the generic block's own `tr.row-details { display:
     none }` (that rule already has two classes' worth of specificity,
     same as the plain rule above, so it would otherwise still win the
     tie by sitting earlier in this same generic block). */
  .eval-table.search-results-table tbody tr.row-details { display: table-row; }
  /* Likewise, `td.col-audience` carries its own always-on `display: flex`
     rule (for wrapping multiple badges on desktop) at the same
     specificity as the plain `tbody td` rule above: one class more
     settles it in this rule's favor at every width. */
  .eval-table.search-results-table tbody td.col-audience { display: table-cell; }

  /* The generic block also zeroes every `.eval-table tbody td`'s padding/
     border (cell spacing lives on the tr/grid in the stacked-card layout
     instead) and sets a tr-level box-shadow as the card's row separator.
     Restore real per-cell padding and a border-bottom row separator now
     that these are genuine table cells again, excluding: the row-details
     panel cell (`[colspan]`: its padding intentionally lives on
     `.row-detail-grid`, not the td), the Select column (its own
     `:not([data-selection-mode="on"]) .col-select` rule already manages
     its padding at every width), and the four columns hidden below (they
     get their own explicit zero). The `:not()` exclusion list already
     gives this selector enough specificity to win outright. */
  .search-results-table tbody td:not([colspan], .col-select, .col-audience, .col-docdate, .col-audit) {
    padding: 6px 10px;
    border: none;
    border-bottom: 1px solid var(--bg-soft, #f6f7f9);
  }
  .search-results-table tbody tr:not(.row-details, .search-group-header-row) td {
    height: auto;
  }
  .eval-table.search-results-table tbody tr {
    box-shadow: none;
  }

  /* Hide Audience/Doc Date/Audit the same way the Select column is already
     hidden outside select mode: collapse the <col> width to 0 rather than
     `display: none` on the cells, so the row's 7-cell grid stays intact and
     later columns don't shift left. Padding must go to 0 too: a fixed-layout
     cell's padding can force a visible sliver even at width:0, the same
     reasoning the Select column's own collapse already relies on. Qualifying
     the table with both classes again (`.eval-table.search-results-table`,
     not just the one class the always-on desktop width rules use) is what
     wins this outright. */
  .eval-table.search-results-table col.search-col-audience,
  .eval-table.search-results-table col.search-col-docdate,
  .eval-table.search-results-table col.search-col-audit {
    width: 0;
  }
  .eval-table.search-results-table th.col-audience,
  .eval-table.search-results-table th.col-docdate,
  .eval-table.search-results-table th.col-audit,
  .eval-table.search-results-table td.col-audience,
  .eval-table.search-results-table td.col-docdate,
  .eval-table.search-results-table td.col-audit {
    padding: 0;
    border: none;
    overflow: hidden;
  }
  /* The cell itself collapses via the rules above, but its children
     (badge links, the audit status icon's fixed-size SVG) don't shrink to
     fit a zero-width column: they wrap onto their own lines or keep their
     own intrinsic size instead, and since the cell's own height is auto
     (unconstrained), that growth still inflates the row's height even
     though the content is invisible width-wise. Drop the children entirely
     so there's nothing left to size against. `!important` is kept here
     specifically: a universal child selector (`> *`) can't be given enough
     specificity to reliably outweigh every possible descendant rule these
     cells' contents might carry (for example the badge overflow popup's own
     three-class rule), since some of those may be more deeply nested than
     this selector can match without becoming unreadable. This is the one
     deliberate, narrow use of `!important` left in this block: "nothing
     inside these three cells ever renders," enforced regardless of what
     else might target their children. */
  .search-results-table td.col-audience > *,
  .search-results-table td.col-docdate > *,
  .search-results-table td.col-audit > * {
    display: none !important;
  }
  /* Paper/Title/Authors absorb the freed width. Select stays 0% outside
     select mode (existing rule above, every width) but falls back to its
     base, non-media-gated 3% once selection mode turns on: these three
     percentages are sized for the 0%-Select case; the second block
     accounts for the 3%-Select case so the row never exceeds 100% in
     either state. Starting point, not load-bearing (tune by eye once
     this is viewable at real phone width). */
  .eval-table.search-results-table col.search-col-paper   { width: 6em; }
  .eval-table.search-results-table col.search-col-title   { width: auto; }
  .eval-table.search-results-table col.search-col-authors { width: auto; }

  /* Select's own 3% desktop width (eval-index.css:~2201) is wide enough for
     a checkbox + padding on a ~1000px+ desktop table, but 3% of a
     ~360-414px phone screen is only ~11-12px: not enough room for even a
     bare checkbox (~13px square), let alone padding, so it renders clipped
     (row checkboxes) or pushed outside the cell entirely (the header's
     select-all checkbox). Give Select a fixed, phone-sized width once
     selection mode turns on instead of a percentage (the same "needs the
     same room regardless of table width" reasoning search-col-paper's own
     fixed `em` width already relies on), and restore real padding around
     the checkbox to match. Qualified with both classes plus the
     `[data-selection-mode="on"]` attribute, so these four rules
     consistently outweigh both the always-on desktop widths above and
     this same block's own non-selection-mode percentages just above. */
  .eval-table.search-results-table[data-selection-mode="on"] col.search-col-select {
    width: 36px;
  }
  .eval-table.search-results-table[data-selection-mode="on"] .col-select {
    padding: 8px;
    border: none;
  }
  .eval-table.search-results-table[data-selection-mode="on"] col.search-col-paper   { width: 6em; }
  .eval-table.search-results-table[data-selection-mode="on"] col.search-col-title   { width: auto; }
  .eval-table.search-results-table[data-selection-mode="on"] col.search-col-authors { width: auto; }

  /* No `top: var(--mailing-header-h)` offset for the pinned thead here: the
     sticky breadcrumb it used to clear (`.mailing-page-header`) only exists on
     the per-mailing index; this page's `.mailing-section-header` scrolls away
     with the content. Offsetting anyway left an empty 30px band above the
     pinned header that rows scrolled up through, so the base top:0 stands at
     every width. */

  /* No ">" caret on mobile: the whole row is the tap target instead
     (see paper-search.js). Collapse the toggle to zero width so it adds no
     left gutter, but keep it in the DOM and focusable (not display: none)
     so keyboard/AT users can still expand a row via its own button. */
  .search-results-table td[data-label="Paper"] .row-expand-toggle {
    width: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  .search-results-table td[data-label="Paper"] .row-expand-toggle .search-caret {
    visibility: hidden;
  }
  .search-results-table th.col-paper .search-caret {
    display: none;
  }
  .search-results-table tbody tr:not(.row-details, .search-group-header-row) {
    cursor: pointer;
  }

  /* The search box takes the full toolbar width on its own row, ahead of
     Audience/Mailings: only the *visual* row order changes (`order`),
     the underlying DOM/tab order stays Audience, search form, Mailings. */
  .search-toolbar .search-form {
    flex: 1 1 100%;
    order: -1;
  }

  /* Once the search box claims its own row above, Audience and Mailings
     share the next line. With no `justify-content` on `.search-toolbar`,
     they'd sit left-aligned back to back, leaving Mailings stranded near
     the left edge instead of the row's right edge its dropdown panel
     assumes (`.mailings-dropdown-panel`'s `right: 0`): without this, the
     panel opens off the left edge of the screen on a phone. Pushing
     Mailings back to the row's right edge restores that assumption
     instead of touching the panel's own positioning. */
  .search-toolbar .mailings-dropdown {
    margin-left: auto;
  }

  /* Select/Export's desktop padding and gap (eval-index.css:~2255-2296)
     leave little room on a phone for "N out of N papers selected for
     export" to sit alongside them. Tighten both, scoped to this toolbar
     specifically so desktop is untouched: `.search-select-toolbar
     #select-toggle` (an ID nested under a class) already outweighs the
     bare `#select-toggle` ID rule on specificity alone, same idea as the
     `.eval-table.search-results-table` qualifying used throughout this
     file, so none of this needs `!important`. Even tightened, the count
     text alone can run to 40+ characters at a four-digit result count, so
     `flex-wrap` on the outer toolbar lets the count drop to its own line
     above the Select/Export pair rather than push them off the right edge
     of the screen: the pair itself is one flex item (.search-select-
     buttons), not two, so it moves as a unit instead of splitting apart
     mid-wrap. `justify-content: flex-end` keeps whichever line each item
     lands on right-aligned. */
  .search-filter-row .search-select-toolbar {
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  .search-filter-row .search-select-buttons {
    gap: 8px;
  }
  .search-select-toolbar #select-toggle,
  .search-select-toolbar #export-selected {
    padding: 8px 12px;
  }
  /* "Export Selected" only fits this row unabbreviated on a wide desktop
     table; the design's own mobile copy just says "Export" once Select/
     Export share the row with the selection count. Screen readers and
     desktop still get the full label: only the suffix's rendering is
     hidden here, the text itself stays in the DOM. */
  .export-full-label-suffix {
    display: none;
  }
}

/* ── Narrow-width row height: keep the collapsed columns out of layout ─────
   The block above collapses Audience/Doc Date/Audit to `width: 0` rather than
   `display: none` (so the row's 7-cell grid stays intact) and hides their
   element children, because those children keep their intrinsic size and
   inflate the row. A *text node* has no element to hide, though, and Doc Date
   renders its value as bare text: `<td class="col-docdate"> 2026-06-01</td>`.
   At width 0 that text still lays out, breaks at the hyphens, and stacks into
   a ~200px column that sets the whole row's height. `white-space: nowrap`
   keeps it on one line, where the existing `overflow: hidden` clips it.

   The collapse now starts at 1024px instead of 768px, the width at which the
   "All Mailings" sidebar stacks below the table. Between 769px and 1024px the
   full column set had nowhere to go, so the table overflowed horizontally
   (Audit clipped at the right edge, Doc Date wrapping) with rows around 67px.

   Measured on /mailing/ with 146 rows: median row height 201px -> 37px at
   725px, 67px -> 48px at 900px, and the horizontal overflow at 900px is gone.
   The bug is latent rather than visible on stage and production only because
   their Doc Date values are currently empty, so there is no hyphenated string
   to wrap. cppalliance/wg21-website-issues#73 */
@media (max-width: 1024px) {
  .eval-table.search-results-table col.search-col-audience,
  .eval-table.search-results-table col.search-col-docdate,
  .eval-table.search-results-table col.search-col-audit {
    width: 0;
  }
  /* Hand the freed 30% to Title and Authors, or `table-layout: fixed` spreads
     the slack over every column including Paper's fixed 8.5em. Authors takes
     the fixed share so Title absorbs the rest: two `auto` columns split
     evenly, flattening desktop's 1.9:1 Title:Authors ratio. */
  .eval-table.search-results-table col.search-col-authors {
    width: 30%;
  }
  .eval-table.search-results-table col.search-col-title {
    width: auto;
  }
  .eval-table.search-results-table th.col-audience,
  .eval-table.search-results-table th.col-docdate,
  .eval-table.search-results-table th.col-audit,
  .eval-table.search-results-table td.col-audience,
  .eval-table.search-results-table td.col-docdate,
  .eval-table.search-results-table td.col-audit {
    padding: 0;
    border: none;
    overflow: hidden;
    white-space: nowrap;
  }
  .search-results-table td.col-audience > *,
  .search-results-table td.col-docdate > *,
  .search-results-table td.col-audit > * {
    display: none !important;
  }
}


/* ── Tablet and below: full-bleed table, verdict dot ──────────────────────
   Both apply only once the Audit column has collapsed.

   Full bleed cancels `--pad-x` instead of the usual `100vw` +
   `calc(50% - 50vw)`, which counts the classic scrollbar gutter and so
   overhangs the viewport by half a scrollbar on each side.

   The dot stands in for the collapsed Audit column. It trails the id because
   most rows have no verdict and a leading dot would leave the id column
   ragged; it sits outside the <a> to stay clear of the link's hit area. */
@media (max-width: 1024px) {
  .eval-table.search-results-table {
    width: calc(100% + 2 * var(--pad-x));
    margin-inline: calc(-1 * var(--pad-x));
  }

  /* search.html.j2 emits this span already carrying .status-{kind}, so the
     --audit-* color arrives through the same rules the Audit column uses and
     currentColor fills the circle. Nothing per-kind is needed here. */
  .paper-audit-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-left: 6px;
    border-radius: 50%;
    background: currentColor;
    vertical-align: middle;
  }
}
