/* WikiWatch 2026 design system (TFG refresh, July 2026).
   Color tokens sampled from the mock — confirm exact values with TFG. */
:root {
  --ww-purple: #4F6DA1;
  --ww-purple-dark: #415A86;
  --teal: #50C6BE;
  --teal-dark: #2e9c93;
  --teal-tint: #C0E9E6;
  --teal-text: #0F6A61;
  --talk-tint: #B9D5F4;
  --talk-text: #334D77;
  --ww-link: #0645AD;
  --ink: #1a2033;
  --muted: #6b7280;
  /* PLACEHOLDER pending TFG confirmation: fills the real gap between --muted
     (#6b7280 / gray-500) and --ink — gray-600, the next step on the same ramp.
     Used only for the traffic "back to normal" row, which needs to read a step
     stronger than muted timestamps without becoming full body text. */
  --muted-strong: #4b5563;
  --bg: #F9FBFC;
  --card: #ffffff;
  --line: #E1E6EE;
  --band: #EEF1F7;
  --th: #949AA7;
  --danger: #d64545;
  --alert: #ed5e42;
  --before-border: #e8c468;
  --after-border: #9cc3e5;
  /* Global corner radius (TFG July 20): one 5px value for every card, content
     box, stat callout, and section. Controls (buttons, inputs, pills) keep their
     own radii; inner table-cell corners stay at --radius minus the 1px border. */
  --radius: 5px;
  /* Single horizontal page gutter for the header, article hero, main and footer,
     so they stay flush with each other. Steps down at the mobile breakpoint (see
     the "Mobile" section at the foot of this file). */
  --gutter: 4rem;
}

/* Edit List toolbar: the "View" filter set on the left, "Mark all as viewed" on
   the right. The pills and the .el-filter-form dropdown are the same filter set
   at two breakpoints — the mobile section at the foot of this file swaps them. */
.el-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-bottom: 1rem; }
.el-filters { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.el-view-label { font-weight: 700; font-size: 0.88rem; }
.el-filter-form { display: none; margin: 0; gap: 0.5rem; align-items: center; }
.el-filter-select { height: 2.4rem; min-width: 7rem; }

/* Edit List: dedicated edit-kind icon column between Type and Summary. Larger,
   heavier read than the old inline icons (per the mockup), centered with room
   on both sides. Empty cell when the edit is unclassified (no guessed icons). */
.ev-icon-col, td.ev-icon { width: 3rem; text-align: center; padding-left: 0.4rem; padding-right: 0.4rem; }
td.ev-type { width: 5.5rem; }
td.ev-icon i { font-size: 1.35rem; color: #3a4252; vertical-align: middle; }
td.ev-icon i.ev-alert { color: var(--alert); }
/* Same edit-kind glyph in the Edit Detail / Event Detail header (shared partial
   article/_edit_kind_icon.html) — sized for the header line, list cell keeps its
   own size above. */
.edit-header .ev-icon-glyph { flex: none; font-size: 1.2rem; color: #3a4252; }
.ev-icon-glyph.ev-alert { color: var(--alert); }
/* traffic "back to normal" row: subordinate, but a step stronger than muted
   since it carries real numbers (--muted-strong is a TFG placeholder). */
.traffic-normal-text { color: var(--muted-strong); }

/* Non-edit events + deletion-class high-alert treatment (Phase 3) */
/* Event chips get a dedicated peach fill (#F7D2AF, per TFG July 20 mockup); the
   dark-warm text follows the same tint+dark-text pattern as the Article/Talk
   chips (she specified only the background). Traffic keeps the old neutral gray. */
.chip-event { background: #F7D2AF; color: #7a4a1f; }
.chip-traffic { background: #eceef3; color: #5b6270; }
.filter-pill.on-event { background: #F7D2AF; border-color: #F7D2AF; color: #7a4a1f; }
.alert-row > td, tr.alert-row > td { background: #fff6f4; }
.alert-text { color: var(--alert); font-weight: 700; }
.revdel-flag { color: var(--muted); font-size: 0.8rem; white-space: nowrap; }
.revdel-notice {
  background: #fff6f4; border: 1px solid #f6d9d2; border-radius: var(--radius);
  padding: 0.5rem 0.7rem; font-size: 0.82rem; color: #8a3b28; margin: 0 0 0.7rem;
}
.wl-deleted { color: var(--alert); font-weight: 600; white-space: nowrap; }
* { box-sizing: border-box; }
body {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  margin: 0; color: var(--ink); background: var(--bg);
  display: flex; flex-direction: column; min-height: 100vh;
  font-size: 14px;
}
a { color: var(--ww-link); text-decoration: underline; text-underline-offset: 2px; }
/* An icon inside a link doesn't take the link's underline (TFG Aug 1): the text
   stays underlined, the glyph doesn't. `text-decoration: none` on the <i> can't
   do this — a decoration propagated from an ancestor is not cancellable by a
   descendant — but propagation skips atomic inlines, so inline-block is what
   does the work. App-wide, so any new icon link picks it up for free. */
a .ph { display: inline-block; }

/* Headings (TFG Aug 1): one weight for every level and one size per level, set
   on the elements themselves so a heading can't drift by living in a different
   card. The per-selector `font-weight: 700` / `font-size` declarations these
   replace were removed below rather than left to be overridden. Heading-role
   CLASSES (.sr-title, .section-h, the .wl-section group band) restate the 600,
   since an element selector can't reach them. */
h1, h2, h3, h4, h5, h6 { font-weight: 600; }
h1 { font-size: 1.6rem; }
h3 { font-size: 1rem; }

/* header */
header.site {
  background: #fff; border-bottom: 1px solid var(--line);
  padding: 1.2rem var(--gutter); display: flex; align-items: center; gap: 2rem;
}
header.site .brand {
  font-weight: 800; letter-spacing: 0.02em; text-decoration: none; font-size: 1.05rem;
  color: var(--ww-purple); display: flex; align-items: center; gap: 0.3rem;
}
header.site .brand .mark { color: var(--teal); font-size: 1.3rem; }
header.site nav { display: flex; align-items: center; margin-left: auto; }
header.site nav a { color: var(--ink); text-decoration: none; font-size: 0.88rem; margin-left: 1.4rem; }
header.site nav a:hover { color: var(--ww-purple); }
/* Mobile ≡ menu. Hidden above the breakpoint, where the nav row carries the
   links; the mobile section at the foot of this file does the swap. Panel styling
   follows the ••• row menus (same border, radius, shadow, hover fill).
   NOTE (designer review): the mockups show the closed ≡ only, so this open
   treatment — a right-aligned dropdown panel under the header — is our
   convention pick, not TFG's. */
.nav-menu { display: none; position: relative; margin-left: auto; }
.nav-menu > summary {
  list-style: none; cursor: pointer; color: var(--ink);
  display: flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; margin-right: -0.6rem; border-radius: 6px;
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary .ph { font-size: 1.6rem; display: block; }
.nav-menu[open] > summary { background: var(--band); }
header.site nav.nav-menu-panel {
  position: absolute; right: 0; top: calc(100% + 0.35rem); z-index: 30; min-width: 190px;
  flex-direction: column; align-items: stretch; margin-left: 0;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(26, 32, 51, 0.12); padding: 0.35rem;
}
header.site nav.nav-menu-panel a {
  margin-left: 0; padding: 0.6rem 0.6rem; border-radius: 5px; font-size: 0.9rem;
}
header.site nav.nav-menu-panel a:hover { background: var(--bg); color: var(--ink); }

/* article hero + tabs (light) */
.article-hero { background: #fff; border-bottom: 1px solid var(--line); padding: 2rem var(--gutter) 0; }
.article-hero h1 { margin: 0 0 2rem; }
.tabs { display: flex; gap: 1.6rem; }
.tabs a {
  padding: 0 0 0.7rem; font-size: 0.88rem; color: var(--ink); text-decoration: none;
  border-bottom: 3px solid transparent; display: flex; align-items: center; gap: 0.4rem;
}
.tabs a.active { font-weight: 700; border-bottom-color: var(--teal); }
.tabs a:not(.active):hover { color: var(--ww-purple); }

main { flex: 1; width: 100%; padding: 1.5rem var(--gutter); }
main.full { max-width: none; padding: 0; }

/* cards, lists */
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1.25rem; }
.card h3 { margin: 0 0 0.75rem; }
/* Flat rows inside one container: no floating rounded per-row cards. Rows are
   separated by thin dividers; the enclosing .wl-section or .table-card draws
   the single border + rounded corners. */
table.list { width: 100%; border-collapse: collapse; }
table.list th {
  text-align: left; padding: 1rem 0.9rem; color: var(--th); font-weight: 500;
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em;
  border-bottom: 1px solid var(--line); background: var(--card);
}
table.list td {
  background: var(--card); padding: 0.85rem 0.9rem; font-size: 0.86rem; vertical-align: middle;
  border-bottom: 1px solid var(--line);
}
table.list tbody tr:last-child td { border-bottom: none; }
/* Edit List rows sit a touch taller than the shared row height (TFG July 20). */
table.list.edit-list td { padding-top: 1.3rem; padding-bottom: 1.3rem; }
/* Unread rows: teal left edge — a crisp square strip drawn as an absolutely
   positioned bar so it ignores the row's corner radius (no lozenge on the last
   row) and can't be out-specified by any border rule. */
table.list td:first-child { position: relative; }
table.list tr.unseen td:first-child::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--teal);
}

/* Standalone tables (Edit List, Top Editors, Search Results) get the single
   container the Watchlist gets from .wl-section. No overflow:hidden — that would
   clip the unread bar's ends at the rounded corners — so the corner *cells* are
   rounded instead, and the absolutely-positioned bar stays square on every row. */
.table-card {
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
  margin-bottom: 1.25rem;
}
.table-card table.list { margin: 0; }
.table-card table.list thead th:first-child { border-top-left-radius: 4px; }
.table-card table.list thead th:last-child { border-top-right-radius: 4px; }
/* search results have no thead: round the first row's top corners instead */
.table-card table.search-list tbody tr:first-child td:first-child { border-top-left-radius: 4px; }
.table-card table.search-list tbody tr:first-child td:last-child { border-top-right-radius: 4px; }
.table-card table.list tbody tr:last-child td:first-child { border-bottom-left-radius: 4px; }
.table-card table.list tbody tr:last-child td:last-child { border-bottom-right-radius: 4px; }

/* buttons */
.btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.5rem 1rem; border-radius: 7px; border: 1px solid var(--line);
  background: #fff; cursor: pointer; font-size: 0.85rem; text-decoration: none;
  color: var(--ink); font-family: inherit; font-weight: 500;
}
.btn-primary, .btn-dark {
  background: var(--ww-purple); border-color: var(--ww-purple); color: #fff; font-weight: 600;
}
.btn-primary:hover, .btn-dark:hover { background: var(--ww-purple-dark); }
.btn-icon { padding: 0.4rem 0.55rem; border: none; background: transparent; color: var(--muted); }
.btn-icon:hover { color: var(--danger); }
.btn-arrow {
  padding: 0.35rem 0.6rem; background: var(--ww-purple); color: #fff; border: none; border-radius: 6px;
  font-size: 0.95rem; text-decoration: none;
}
.btn-arrow.disabled { background: var(--line); color: var(--muted); pointer-events: none; }
input[type=text], input[type=search], input[type=email], input[type=password], select, textarea {
  padding: 0.45rem 0.6rem; border: 1px solid var(--line); border-radius: 6px;
  font-size: 0.86rem; font-family: inherit; background: #fff;
}

/* chips + pills */
.chip {
  display: inline-block; font-size: 0.72rem; font-weight: 600;
  border-radius: 999px; padding: 0.18rem 0.65rem;
}
.chip-article { background: var(--teal-tint); color: var(--teal-text); }
.chip-talk { background: var(--talk-tint); color: var(--talk-text); }
.count-pill {
  display: inline-block; background: var(--teal); color: #fff; font-size: 0.72rem;
  font-weight: 700; border-radius: 999px; padding: 0.12rem 0.6rem; margin-left: 0.35rem;
}
.badge {
  display: inline-block; font-size: 0.72rem; color: var(--muted);
  background: var(--bg); border: 1px solid var(--line); border-radius: 999px; padding: 0.15rem 0.6rem;
}
.filter-pill {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.35rem 0.9rem; border-radius: 999px; border: 1px solid var(--line);
  background: #fff; color: var(--ink); text-decoration: none; font-size: 0.83rem; font-weight: 600;
}
.filter-pill.on-article { background: var(--teal-tint); border-color: var(--teal-tint); color: var(--teal-text); }
.filter-pill.on-talk { background: var(--talk-tint); border-color: var(--talk-tint); color: var(--talk-text); }

/* toggle switch */
.toggle { position: relative; display: inline-block; width: 40px; height: 22px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle .slider {
  position: absolute; cursor: pointer; inset: 0; background: var(--line);
  border-radius: 999px; transition: 0.15s;
}
.toggle .slider:before {
  content: "\2715"; position: absolute; height: 16px; width: 16px; left: 3px; top: 3px;
  background: #fff; border-radius: 50%; transition: 0.15s;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; font-weight: 700; line-height: 1; color: var(--muted);
}
.toggle input:checked + .slider { background: var(--teal); }
.toggle input:checked + .slider:before { transform: translateX(18px); content: "\2713"; color: var(--teal-text); }

.messages { list-style: none; padding: 0; margin: 0 0 1rem; }
.messages li { padding: 0.5rem 0.75rem; border-radius: var(--radius); margin-bottom: 0.5rem; background: #ecfdf5; border: 1px solid #a7f3d0; font-size: 0.88rem; }
.messages li.error { background: #fef2f2; border-color: #fecaca; }
.muted { color: var(--muted); }

/* diff (Edit View) */
.diff-wrap { overflow-x: auto; }
.diff-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.diff-panel { border: 2px solid var(--line); border-radius: var(--radius); background: #fff; padding: 1rem; }
.diff-panel.before { border-color: var(--before-border); }
.diff-panel.after { border-color: var(--after-border); }
table.diff { width: 100%; border-collapse: collapse; font-family: ui-monospace, Menlo, monospace; font-size: 0.76rem; table-layout: fixed; }
table.diff td { padding: 0.15rem 0.4rem; vertical-align: top; word-wrap: break-word; }
td.diff-deletedline { background: #fdf3e0; border: 1px solid var(--before-border); width: 50%; }
td.diff-addedline { background: #eaf3fb; border: 1px solid var(--after-border); width: 50%; }
td.diff-context { background: #f8f9fa; width: 50%; }
td.diff-marker { width: 1.2rem; color: var(--muted); }
.diff-lineno { font-weight: 700; padding-top: 0.6rem; }
/* Before/After need a clear gutter between the two halves (TFG Aug 1) — the
   July 29 relayout dropped the old bordered .diff-panel boxes for a bare table,
   and with them the breathing room. The rows are Wikipedia's own markup, so
   there is no spacer cell to add: the After side's marker column doubles as the
   divider. These two lengths are the whole geometry — the <col> widths in
   article/revision_detail.html and the .diff-heads rules below are both
   expressed in terms of them, so the gutter moves from one place. */
.diff-card { --diff-marker: 1.2rem; --diff-gutter: 2.5rem; }
/* +/- pushed to the gutter's right edge, so it still reads as belonging to the
   After cell beside it rather than trailing the Before text. */
table.diff td.diff-marker:nth-child(3) { text-align: right; }
/* The "Line N:" rows are two colspan=2 cells, so the right-hand one starts at
   the gutter; indent it to overhang its column by the same 1.2rem the left one
   overhangs the Before column (gutter + the cell's 0.4rem padding - 1.2rem). */
table.diff td.diff-lineno + td.diff-lineno { padding-left: calc(var(--diff-gutter) - 0.8rem); }
/* Column headers on the same geometry as the colgroup, so each coloured rule
   spans exactly the half it labels. */
.diff-heads {
  display: grid; gap: var(--diff-gutter); margin-bottom: 0.9rem;
  grid-template-columns: calc(var(--diff-marker) + (100% - var(--diff-marker) - var(--diff-gutter)) / 2) 1fr;
}
.diff-heads h3 { margin: 0; padding-bottom: 0.5rem; }
.diff-heads .before { border-bottom: 3px solid var(--before-border); }
.diff-heads .after { border-bottom: 3px solid var(--after-border); }
del.diffchange { background: #f5d9a8; text-decoration: none; }
ins.diffchange { background: #c4ddf2; text-decoration: none; }

.embed-frame { width: 100%; height: calc(100vh - 220px); border: none; background: #fff; }

footer.site {
  background: #fff; border-top: 1px solid var(--line); padding: 1rem var(--gutter);
  font-size: 0.76rem; color: var(--muted); display: flex; justify-content: space-between; align-items: center;
}

.detail-cols { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1.25rem; }
/* Edit Detail (TFG July 29 relayout): two rows rather than one tall right-hand
   stack, so a short or long "What Happened" no longer strands whitespace beside
   it. Row 1 = What Happened (wide) + Wikipedia Summary; row 2 = Edit Details +
   Editor Summary. The two rows' column ratios are measured off her mockup and
   deliberately differ, so the dividers don't line up between rows. Row-mates
   share a height (default stretch) — that's what closes the whitespace gap. The
   row carries the vertical rhythm, so cards inside drop their own bottom margin.
   Line-height 1.4 on the body text. */
.ed-row { display: grid; gap: 1.25rem; margin-bottom: 1.25rem; line-height: 1.4; }
.ed-row > .card { margin-bottom: 0; }
.ed-row-primary { grid-template-columns: 3fr 1fr; }
.ed-row-secondary { grid-template-columns: 1fr 2fr; }
/* "Edit Detail" subheading + "Back to Edit List", above the header card. */
.ed-subhead { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin: 0 0 1.2rem; }
.ed-subhead h2 { font-size: 1rem; margin: 0; }
.ed-subhead a { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.85rem; }
/* Section links sit directly under their card title, one row, leading icons. */
.section-links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem; margin: 0.5rem 0 0.9rem; font-size: 0.85rem; }
.section-links a { display: inline-flex; align-items: center; gap: 0.3rem; }
/* Multi-column detail layouts collapse to one column on the shared mobile
   breakpoint. These were written at 800px before Stage A settled on 720px;
   folded onto the one value so there's a single place to move it. Collapsing
   .ed-row in DOM order gives the mobile deck's stack exactly: What Happened,
   Wikipedia Summary, Edit Details, Editor Summary, then Before/After. */
@media (max-width: 720px) {
  .ed-row, .detail-cols, .diff-panels { grid-template-columns: 1fr; }
}
.kv { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 1.5rem; font-size: 0.85rem; }
.kv .k { color: var(--muted); }
.kv .v { font-weight: 600; }

/* Watchlist two-section layout (Articles / Pages) */
.wl-section { margin-bottom: 1.1rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); }
/* Shaded header band spanning the section. Collapsed: all four corners rounded
   (it's the whole visible box). Open: only the top corners. */
.wl-section > summary {
  list-style: none; cursor: pointer; padding: 0.75rem 1rem; display: flex; align-items: center;
  gap: 0.55rem; font-weight: 600; color: var(--ink); user-select: none;
  background: var(--band); border-radius: 4px;
}
.wl-section[open] > summary { border-radius: 4px 4px 0 0; border-bottom: 1px solid var(--line); }
.wl-section > summary::-webkit-details-marker { display: none; }
/* CSS-drawn thin caret (no icon font): collapsed = caret-down (rotate 45deg),
   expanded = caret-up (rotate -135deg). */
.wl-caret {
  display: inline-block; width: 0.5rem; height: 0.5rem; flex: none;
  border-right: 1.5px solid var(--ink); border-bottom: 1.5px solid var(--ink);
  transform: rotate(45deg); transition: transform 0.15s; margin-bottom: 3px;
}
.wl-section[open] > summary .wl-caret { transform: rotate(-135deg); margin-bottom: 0; margin-top: 3px; }
.wl-section .sec-count { background: var(--card); color: var(--muted); border-radius: 999px; padding: 0.05rem 0.6rem; font-size: 0.78rem; font-weight: 700; }
/* Table flush to the container edges; round the last row so the white fill
   doesn't poke past the container's rounded bottom (no overflow:hidden here —
   the ••• row menu must be able to escape the container). */
/* Shared fixed column layout so PAGE / LATEST ACTIVITY / ALERTS / DIGEST / •••
   start at identical x-positions in every section, regardless of content. */
.wl-section table.list { width: 100%; table-layout: fixed; }
.wl-section table.list th:nth-child(1), .wl-section table.list td:nth-child(1) { width: 26%; }
.wl-section table.list th:nth-child(2), .wl-section table.list td:nth-child(2) { width: 42%; }
.wl-section table.list th:nth-child(3), .wl-section table.list td:nth-child(3) { width: 11%; }
.wl-section table.list th:nth-child(4), .wl-section table.list td:nth-child(4) { width: 15%; }
.wl-section table.list th:nth-child(5), .wl-section table.list td:nth-child(5) { width: 6%; }
/* PAGE cell: chip + truncating title + count pill on one line */
.wl-page-inner { display: flex; align-items: center; gap: 0.4rem; min-width: 0; }
.wl-page-inner .chip, .wl-page-inner .count-pill { flex: none; }
.wl-title { color: var(--ink); font-weight: 600; text-decoration: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* LATEST ACTIVITY: truncate the (single) link rather than wrap/push columns */
.wl-section td.wl-activity { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-section table.list tbody tr:last-child td:first-child { border-bottom-left-radius: 4px; }
.wl-section table.list tbody tr:last-child td:last-child { border-bottom-right-radius: 4px; }
.chip-page { background: #e8eaf4; color: var(--ww-purple); }

/* Non-mainspace page detail header (no article tabs) */
.page-kind { display: flex; align-items: center; gap: 0.6rem; padding-bottom: 1rem; color: var(--muted); font-size: 0.88rem; }

/* Right-aligned numeric table columns (Top Editors, etc.) */
th.num, td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Top Editors: the inline wording the mobile two-column condensation needs
   (see templates/article/top_editors.html). Off above the breakpoint, where the
   column headers already say it. */
.te-short, .te-suffix { display: none; }

/* Edit-detail header, boxed to match the row/card style */
.edit-header { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.edit-header .eh-main { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
.edit-header .eh-line { font-size: 0.95rem; }
.edit-header .eh-actions { display: flex; gap: 1rem; align-items: center; flex-shrink: 0; }
/* Share affordance: outlined box next to the prev/next arrows (per mockup) */
.btn-share {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; border-radius: 6px; cursor: pointer;
  background: #fff; border: 1px solid var(--line); color: var(--ww-purple); font-size: 1.05rem;
}
.btn-share:hover { background: var(--bg); }

/* Overview callout stat cards */
.stat-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.9rem; margin-bottom: 1.25rem; }
.stat-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 0.9rem; text-align: center; }
.stat-num { font-size: 1.7rem; font-weight: 600; color: var(--teal); line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-label { font-size: 0.74rem; color: var(--muted); margin-top: 0.3rem; }
/* 6 across → 3 on a tablet; the mobile section drops to 2 (and to 4 cards). */
@media (max-width: 900px) { .stat-grid { grid-template-columns: repeat(3, 1fr); } }

/* Overview enrichment (roadmap item 2) */
/* align-items:stretch so row-mates match heights (Activity == The Page), per
   TFG July 20 mockup. Columns stay 1/3 : 2/3. */
.ov-grid { display: grid; grid-template-columns: 1fr 2fr; gap: 1.25rem; align-items: stretch; margin-bottom: 1.25rem; }
/* The grid gap governs BOTH axes (TFG Aug 1): .card's own bottom margin stacked
   on top of the row gap, so the vertical space between cards read as twice the
   horizontal. Same fix as .ed-row > .card above. */
.ov-grid > .card { margin-bottom: 0; }
.ov-card h3 { display: flex; align-items: center; }
.ov-card .kv { grid-template-columns: auto 1fr; gap: 0.75rem 1rem; }
.ov-card .kv .v { text-align: left; word-break: break-word; }
@media (max-width: 900px) { .ov-grid { grid-template-columns: 1fr; } }

.year-chart { display: flex; align-items: flex-end; gap: 0.4rem; height: 180px; overflow-x: auto; padding-top: 1rem; }
/* The edit total rides on top of its own bar, the year stays below (TFG Aug 1).
   Stacked together under the bar, the two muted 0.68rem lines read as one label
   and the total was lost in the years. The total is absolutely positioned
   against the bar (bottom:100%) rather than laid out in a track of its own, so
   it tracks each bar's height instead of lining up across the chart, and the
   bars keep their proportions exactly — the chart's own padding-top is the room
   the tallest bar's total sits in. */
.yc-col { display: grid; grid-template-rows: 1fr auto; justify-items: center; align-items: end; min-width: 34px; flex: 1; height: 100%; }
.yc-bar { position: relative; width: 60%; min-height: 2px; background: var(--teal); border-radius: 3px 3px 0 0; transition: height 0.2s; }
.yc-col:hover .yc-bar { background: var(--ww-purple); }
.yc-val {
  position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  margin-bottom: 0.2rem; white-space: nowrap;
  font-size: 0.68rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.yc-label { font-size: 0.68rem; color: var(--muted); margin-top: 0.25rem; }

/* Watchlist add bar (consolidated search + URL add) */
/* One shared height for every add-bar control (field, attached ⊕, group
   dropdown, "Mark all as viewed") so the whole row is a single aligned line.
   Sized to the button's natural height — the field/⊕/dropdown shrink to match;
   the buttons don't grow. */
.add-bar { --addbar-h: 2.15rem; display: flex; align-items: center; gap: 0.75rem; padding-top: 1rem; padding-bottom: 1rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.add-form { display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 320px; }
.add-to { font-size: 0.82rem; white-space: nowrap; }
.add-form select { font-size: 0.82rem; height: var(--addbar-h); }
.add-bar .btn { height: var(--addbar-h); display: inline-flex; align-items: center; }
/* Field + submit form one continuous control: field rounded on the left, the
   button flush on its right with matching corners, no gap (per the mockup). */
.add-combo { display: flex; align-items: stretch; flex: 1; min-width: 0; }
/* .add-combo .add-field (0,2,0) must outrank the base input[type=search] rule
   (0,1,1), or the field keeps its all-round radius and right border. */
.add-combo .add-field { flex: 1; min-width: 0; height: var(--addbar-h); border-radius: 6px 0 0 6px; border-right: none; }
.mark-all { margin-left: auto; }

/* Group section header actions */
.sec-title { }
.sec-actions { margin-left: auto; display: inline-flex; gap: 0.1rem; }
.sec-actions .btn-icon { color: var(--muted); padding: 0.2rem 0.4rem; }
.sec-actions .btn-icon:hover { color: var(--ww-purple); }
/* Slightly larger group edit/trash glyphs (TFG July 20). */
.sec-actions .btn-icon .ph { font-size: 1.2rem; }

/* Search results block (rendered above the group sections) */
.search-results { margin-bottom: 1.5rem; }
.sr-title, .section-h { font-size: 1.25rem; font-weight: 600; margin: 0 0 1.2rem; }
table.search-list td { vertical-align: middle; }
.sr-name { font-weight: 700; color: var(--ww-link); }
.sr-snippet {
  font-size: 0.82rem; margin-top: 0.2rem; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
td.sr-action { width: 4rem; text-align: right; }
/* compact square "+" add button */
.btn-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: 7px; cursor: pointer;
  background: var(--ww-purple); color: #fff; border: 1px solid var(--ww-purple);
  font-size: 1.05rem;
}
.btn-add:hover { background: var(--ww-purple-dark); }
/* Add-time group popover (TFG July 29), anchored under a search result's ⊕.
   A <details> so open/close is native and needs no re-binding after an HTMX
   swap; the panel escapes .table-card, which deliberately has no overflow
   clipping. Sized to the mockup: stacked full-width group select + submit. */
.add-pop { position: relative; display: inline-block; }
.add-pop > summary { list-style: none; cursor: pointer; }
.add-pop > summary::-webkit-details-marker { display: none; }
.add-pop-panel {
  position: absolute; right: 0; top: calc(100% + 0.35rem); z-index: 20; width: 210px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(26, 32, 51, 0.12); padding: 0.6rem; text-align: left;
}
.add-pop-panel form { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; }
.add-pop-panel .add-pop-group { width: 100%; height: 2.2rem; }
.add-pop-panel .add-pop-new { width: 100%; }
.add-pop-panel .add-pop-submit { width: 100%; justify-content: center; }
/* Add-bar submit: purple button with a ⊕ (plus-circle) icon, attached flush to
   the right of the search field — rounded on the right only, matching height. */
.btn-round {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.4rem; height: var(--addbar-h); border-radius: 0 6px 6px 0; cursor: pointer; flex: none;
  background: var(--ww-purple); color: #fff; border: 1px solid var(--ww-purple);
  font-size: 1.3rem;
}
.btn-round:hover { background: var(--ww-purple-dark); }
/* Digest dropdown: comfortable padding with a custom caret so the text and
   chevron stay centered with clear separation (native caret spacing varies). */
/* Shared native-select treatment: a custom caret with comfortable padding so
   text and caret never crowd the right edge. Applied to every <select> in the
   app so all dropdowns match; per-select rules add only size (height/min-width). */
.ww-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  font-size: 0.82rem; padding: 0 2.1rem 0 0.75rem;
  border: 1px solid var(--line); border-radius: 6px;
  background-color: #fff; color: var(--ink); font-family: inherit; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.7rem center; background-size: 0.72rem;
}
.digest-select { min-width: 7.5rem; height: 2.2rem; }
/* "already watching" — inert outline checkmark, not a button */
/* "already watching" = a filled check-square (spec: check-square filled).
   Filled via CSS rather than the Phosphor fill weight, to avoid a font load. */
.added-check {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: 7px;
  background: var(--teal); color: #fff; font-size: 1rem;
}

/* Row ••• actions menu */
.row-actions { text-align: right; position: relative; }
.row-menu { display: inline-block; }
.row-menu > summary { list-style: none; cursor: pointer; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu > summary { padding: 0.3rem 0.5rem; color: var(--muted); }
.row-menu > summary:hover { color: var(--ink); }
/* Open menu: shade the ••• so it's clear which row's menu is active (TFG July 20). */
.row-menu[open] > summary { background: var(--band); border-radius: 6px; }
.row-menu > summary .ph { font-size: 1.5rem; display: block; }
.row-menu-panel {
  position: absolute; right: 0.5rem; top: 100%; z-index: 20; min-width: 180px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(26, 32, 51, 0.12); padding: 0.35rem; text-align: left;
}
.row-menu-panel form { margin: 0; }
.rm-head { font-size: 0.72rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; padding: 0.3rem 0.5rem 0.2rem; }
/* Menu items carry a leading icon in both decks, so they're flex rows rather
   than plain blocks; the icon-less group buttons in the submenu read the same. */
.rm-item {
  display: flex; align-items: center; gap: 0.55rem;
  width: 100%; text-align: left; background: none; border: none;
  padding: 0.4rem 0.5rem; border-radius: 5px; cursor: pointer; font-size: 0.85rem;
  color: var(--ink); font-family: inherit;
}
.rm-item:hover { background: var(--bg); }
.rm-item .ph { font-size: 1.1rem; flex: none; }
.rm-current { font-weight: 700; color: var(--ww-purple); }
.rm-current::after { content: " \2713"; }
.rm-sep { height: 1px; background: var(--line); margin: 0.35rem 0.25rem; }
.rm-danger { color: var(--danger); }
.rm-danger:hover { background: #fef2f2; }
/* "Change group": one menu row that reveals the group list (both decks). The
   revealed list is indented under it so it reads as a sub-level. */
.rm-sub > summary { list-style: none; }
.rm-sub > summary::-webkit-details-marker { display: none; }
.rm-sub-list { padding-left: 1.15rem; }
/* Alerts/Digest block at the top of the menu: mobile only (mobile deck note 2).
   Above the breakpoint the row's own Alerts and Digest columns carry these, and
   this copy — plus the separator that would follow it — stays out of the way. */
.rm-prefs, .rm-prefs-sep { display: none; }
.rm-prefs .rm-head { padding: 0 0 0.25rem; }
.rm-prefs .digest-select { min-width: 6.5rem; }
/* Bottom "Mark all as viewed": mobile only (see watchlist/_mark_all.html). */
.mark-all-bottom { display: none; }

/* --- Freemium gated sections (F2) -----------------------------------------
   Placeholder treatment pending TFG design review: blur the gated content and
   float a small upgrade card over it. Kept deliberately plain. */
.gate-wrap { position: relative; }
.gate-wrap .gate-blur { filter: blur(5px); opacity: 0.55; pointer-events: none; user-select: none; }
.gate-overlay {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 1rem;
}
.gate-overlay .gate-msg {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 0.6rem 1rem; font-size: 0.9rem; color: var(--ink);
  box-shadow: 0 2px 10px rgba(26, 32, 51, 0.12);
}
.gate-overlay .gate-msg i { color: var(--muted); margin-right: 0.3rem; }
.digest-locked { font-size: 0.85rem; white-space: nowrap; }
.digest-locked i { margin-right: 0.2rem; }
.history-locked td { background: var(--bg); }

/* --- Public auth pages (login / signup / password reset) --------------------
   Standalone full-bleed gradient screen with a centered white card. The
   designer's July 20 deck only covered Login; signup + reset reuse this shell
   and are pending her review. Gradient stops sampled from the Login mockup. */
.auth-body {
  min-height: 100vh; margin: 0; padding: 1.5rem;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(155deg, #4FC1BD 0%, #2F7D94 50%, #163256 100%);
}
.auth-card {
  /* flex:none resets the base `main { flex:1 }` rule (body is a column flexbox),
     so the card is content-height and centers instead of filling the viewport. */
  flex: none;
  background: var(--card); border-radius: var(--radius);
  box-shadow: 0 14px 44px rgba(16, 32, 60, 0.28);
  padding: 2.25rem 2.25rem 2rem; width: 100%; max-width: 380px; text-align: center;
}
.auth-logo { height: 40px; margin: 0 0 1.1rem; }
.auth-card h1 { margin: 0 0 1.5rem; }
.auth-sub { color: var(--muted); font-size: 0.88rem; margin: 0 0 1.25rem; }
.auth-card form { text-align: left; }
.auth-field { margin-bottom: 0.9rem; }
.auth-field label { display: block; font-size: 0.8rem; color: var(--muted-strong); margin-bottom: 0.25rem; }
.auth-card input[type=email], .auth-card input[type=password], .auth-card input[type=text] { width: 100%; }
.auth-card .btn-primary { width: 100%; justify-content: center; margin-top: 0.3rem; }
.auth-err { color: var(--danger); font-size: 0.85rem; margin: 0 0 0.8rem; }
.auth-field .auth-err { margin: 0.2rem 0 0; }
.auth-hint { display: block; color: var(--muted); font-size: 0.78rem; margin-top: 0.2rem; }
.auth-links { margin: 1.25rem 0 0; font-size: 0.85rem; color: var(--muted); }
.auth-links a { text-decoration: none; }
.auth-links a:hover { text-decoration: underline; }
.auth-body .messages { text-align: left; }

/* --- Account settings + contact (in-app, extend base.html) ------------------ */
.settings-page, .contact-page { max-width: 480px; margin: 0 auto; }
.settings-page h1, .contact-page h1 { text-align: center; margin: 0.5rem 0 1.5rem; }
.set-card h3 { display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.9rem; }
.set-lock { color: var(--muted); font-size: 0.9rem; }
.set-note { color: var(--muted); font-size: 0.8rem; margin: 0.8rem 0 0; }
.email-change > summary {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  cursor: pointer; list-style: none;
}
.email-change > summary::-webkit-details-marker { display: none; }
.email-change-link { color: var(--ww-link); font-size: 0.9rem; }
.email-change > summary:hover .email-change-link { text-decoration: underline; }
.email-change[open] > summary .email-change-link { color: var(--muted); }
.set-readonly { display: grid; grid-template-columns: 1fr 1fr; gap: 0.3rem 1rem; }
.set-readonly .k { font-weight: 600; font-size: 0.82rem; }
.set-readonly .v { color: var(--ink); }
.set-fields { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.9rem; }
.set-fields input { flex: 1; min-width: 8rem; }
.contact-page textarea { width: 100%; min-height: 8rem; resize: vertical; }
/* Reason dropdown: give the shared .ww-select a real input-height (it otherwise
   collapses to the bare native height) so it matches the message box's input
   styling, per the July 20 mockup. */
.contact-page .ww-select { height: 2.4rem; margin-top: 0.3rem; }
.contact-page textarea { margin-top: 0.3rem; }
.contact-readonly { display: grid; grid-template-columns: 1fr 1fr; gap: 0.3rem 1rem; margin-bottom: 1rem; }
.contact-readonly .k { font-weight: 600; font-size: 0.82rem; }
.field-label { display: block; font-weight: 600; font-size: 0.82rem; margin: 0.6rem 0 0.1rem; }

/* --- Help guide -------------------------------------------------------------
   Every <p> and <ul> on this page used to carry an inline font-size:0.9rem;
   that lives here now, so the page's body size moves from one place. The measure
   is capped because the page is one long read — at the full 1280px gutter width
   a 0.9rem line runs past 150 characters, which is why the pre-rewrite page was
   hard to scan. */
.help-page { max-width: 820px; }
.help-page p, .help-page li { font-size: 0.9rem; line-height: 1.55; }
.help-page li { margin-bottom: 0.3rem; }
.help-page .card > :last-child { margin-bottom: 0; }
.help-lede { font-size: 0.95rem; color: var(--muted-strong); margin: 0 0 1.25rem; }
/* A captured screenshot of a real WikiWatch surface. Images are 2x, so they are
   sized by the column and never by their intrinsic width. */
.help-figure { margin: 1.1rem 0; }
/* Each figure links to its own full-size file. These are desktop captures, so
   at the mobile width they render around a quarter size and their UI text is
   unreadable — tapping through is the only way to actually see the thing the
   caption describes. The anchor carries no underline: it wraps the image, and
   the caption below is the label. */
.help-figure a { display: block; text-decoration: none; }
.help-figure img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
}
.help-figure figcaption { font-size: 0.78rem; color: var(--muted); margin-top: 0.4rem; }
/* Badge reference: the app's table typography at reference-table density, and
   it scrolls rather than wraps its columns on a phone. */
.badge-table-wrap { overflow-x: auto; margin: 0.25rem 0 0; }
.badge-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.badge-table th {
  text-align: left; padding: 0.45rem 0.6rem; color: var(--th); font-weight: 500;
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
.badge-table td { padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
.badge-table tbody tr:last-child td { border-bottom: none; }
.badge-table td:first-child { font-weight: 600; }
.badge-note { font-size: 0.85rem; color: var(--muted); margin: 0.9rem 0 0; }
.badge-note .ph { color: var(--muted); }

/* Freemium alert-slot toggle cell (limit B): keep the toggle and its locked
   note aligned. Placeholder styling pending TFG. */
/* Toggle on top, the limit note stacked beneath it so the note stays inside the
   narrow Alerts column instead of overflowing into Digest. The note wraps at
   word/hyphen boundaries (never mid-word) on narrow widths; its full text is
   always in the tooltip. */
.alert-cell { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; min-width: 0; }
.alert-limit-note { font-size: 0.7rem; line-height: 1.2; display: flex; align-items: flex-start; gap: 0.2rem; max-width: 100%; }
.alert-limit-note i { flex: none; margin-top: 0.1em; }

/* Freemium F3: persistent unverified-email banner (quiet, above the app). */
.verify-banner {
  display: flex; align-items: center; justify-content: center; gap: 0.6rem;
  flex-wrap: wrap; padding: 0.5rem 1rem; font-size: 0.85rem;
  background: #fff8e6; color: #7a5b00; border-bottom: 1px solid #f0e2b8;
}
.verify-banner i { vertical-align: -0.1em; }
.verify-resend {
  background: none; border: none; padding: 0; font: inherit; cursor: pointer;
  color: var(--ww-link); text-decoration: underline;
}

/* --- Mobile (Stage A, mobile deck July 29) ---------------------------------
   One breakpoint for the whole mobile foundation: 720px. The header nav row's
   natural width (brand + six links + gutters) crowds just under ~700px, so the
   swap sits just above that; tablet portrait (768px) still fits the desktop
   layout comfortably and keeps it. Reuse this value for later mobile work
   rather than introducing a second near-identical breakpoint. */
@media (max-width: 720px) {
  /* 4rem gutters eat 128px of a 375px screen. 1.25rem matches the modest edge
     padding in the mobile mockups and keeps header/hero/main/footer flush. */
  :root { --gutter: 1.25rem; }

  /* Nav row out, ≡ menu in. Every mobile slide centers the logo with the ≡ at
     the right, so the brand is centered on the header rather than left-aligned
     (absolutely, so it centers on the header and not on the space left over
     beside the ≡). Scoped with :has() to headers that actually carry a ≡ — the
     client-report shell (templates/client/base.html) reuses header.site with its
     own two-link nav and no ≡, and must keep its left-aligned brand. */
  header.site nav.nav-row { display: none; }
  .nav-menu { display: block; }
  header.site:has(.nav-menu) { position: relative; }
  header.site:has(.nav-menu) .brand {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  }

  /* Six tabs overflow a phone; scroll them horizontally instead (mockup shows
     the row running off the right edge). Negative margin + matching padding
     lets the row scroll to the physical screen edge while the first tab stays
     on the gutter. The active underline is the tab's own border-bottom, so it
     rides along unchanged; the scrollbar is hidden so it can't sit on top of
     it or shift the row off the hero's bottom edge. */
  .tabs {
    overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
    margin: 0 calc(-1 * var(--gutter)); padding: 0 var(--gutter);
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs a { flex: none; white-space: nowrap; }

  /* --- Watchlist (Stage B, mobile deck Watchlist + Search Results slides) --- */

  /* Rows collapse to what the slide shows: title + unread badge on the left,
     ••• on the right. Latest Activity drops out (it's a tap away on the Edit
     List), Alerts and Digest move into the ••• menu, and the header row goes
     with them — a single content column needs no column labels. */
  .wl-section table.list thead { display: none; }
  .wl-section table.list td.wl-activity,
  .wl-section table.list td.wl-alerts,
  .wl-section table.list td.wl-digest { display: none; }
  /* table-layout stays fixed — it can't exceed the table's own width, so the
     title truncates instead of pushing the row wide — but the desktop column
     percentages have to be re-dealt between the two surviving cells, or the
     leftover 68% is split evenly and ••• gets a third of the row. */
  .wl-section table.list td:nth-child(1) { width: auto; }
  .wl-section table.list td:nth-child(5) { width: 3.25rem; }
  /* Group headers keep the caret and the rename/delete icons; the slide drops
     the article count at this width. */
  .wl-section .sec-count { display: none; }

  /* ••• menu: room for the alerts toggle and digest dropdown side by side, and
     still clear of both gutters at 375px (335px of content). */
  .row-menu-panel { min-width: 15rem; }
  .rm-prefs { display: flex; gap: 1.1rem; padding: 0.3rem 0.5rem 0.5rem; }
  .rm-prefs-sep { display: block; }

  /* "Mark all as viewed" leaves the add bar for the foot of the list, full
     width (deck note 3), so the articles start higher up the screen. */
  .add-bar .mark-all { display: none; }
  .mark-all-bottom { display: block; margin: 0 0 1.25rem; }
  .mark-all-bottom .btn { width: 100%; justify-content: center; height: 2.6rem; }

  /* Add bar: the field + ⊕ have the row to themselves and must be free to
     shrink below the desktop minimum. */
  .add-form { min-width: 0; }

  /* Search results: centered heading, and the ⊕ / ✓ aligned with the result
     title — desktop centers it against a one-line row, here the snippet wraps
     to two. Fixed layout + break-word keeps a long title inside the card. */
  .sr-title { text-align: center; }
  table.search-list { table-layout: fixed; }
  table.search-list td { vertical-align: top; }
  td.sr-action { width: 3.25rem; }
  .sr-name { overflow-wrap: break-word; }

  /* --- Article pages + account (Stage C, mobile deck slides 4-7) ------------ */

  /* Edit List toolbar: pills out, dropdown in (deck note 2), so the filter set
     and "Mark all as viewed" share one row. The dropdown carries its own label
     (aria-label="View"), so the standalone one goes with the pills. */
  .el-filters { display: none; }
  .el-filter-form { display: flex; }
  .el-filter-select { flex: 1; min-width: 0; }

  /* Edit List rows become stacked cards: chip + kind icon on the left of the
     first line with the date opposite, the linked summary on a second line
     spanning the card. The editor column drops out entirely (deck note 3) — that
     detail lives on the Edit Detail view. The table's parts are re-declared as
     blocks so each row can be its own two-row grid; `grid-area` does the
     reordering, since the date follows the summary in the DOM. */
  table.list.edit-list, .edit-list tbody, .edit-list td { display: block; }
  .edit-list thead { display: none; }
  .edit-list tr {
    display: grid; position: relative;
    grid-template-columns: auto auto 1fr;
    grid-template-areas: "chip icon date" "summary summary summary";
    align-items: center; gap: 0.55rem 0.6rem;
    padding: 0.85rem 0.9rem; border-bottom: 1px solid var(--line);
  }
  .edit-list tbody tr:last-child { border-bottom: none; }
  /* Selector matches table.list td / table.list.edit-list td, which set the
     cell padding and the row divider — the row itself carries both now. */
  table.list.edit-list td { width: auto; padding: 0; border-bottom: none; }
  .edit-list td.ev-type { grid-area: chip; }
  .edit-list td.ev-icon { grid-area: icon; width: auto; padding: 0; text-align: left; }
  .edit-list td:nth-child(3) { grid-area: summary; }
  .edit-list td:nth-child(4) { grid-area: date; justify-self: end; }
  .edit-list td:nth-child(5) { display: none; }
  /* A row that is one message rather than a record — the empty state here and
     on Top Editors — spans the whole card instead of landing in the first,
     narrow grid area. (The free plan's locked-history row needs no class: its
     message is already the cell the summary area picks up.) */
  .edit-list tr > td.row-wide { grid-area: auto; grid-column: 1 / -1; }
  /* The unread bar spans the whole card, so it moves off the first cell — now
     just the chip — onto the row itself. */
  .edit-list tr.unseen td:first-child::before { display: none; }
  .edit-list tr.unseen::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
    background: var(--teal);
  }

  /* Edit Detail / Event Detail header: chip + icon with the actions opposite,
     the edit's top line on a second row across the card (mockup). display:
     contents lifts .eh-main's children into the header's own grid so the top
     line can leave the chip's row. */
  .edit-header {
    display: grid; grid-template-columns: auto auto 1fr;
    grid-template-areas: "chip icon actions" "line line line";
    align-items: center; gap: 0.7rem 0.6rem;
  }
  .edit-header .eh-main { display: contents; }
  .edit-header .chip { grid-area: chip; }
  .edit-header .ev-icon-glyph { grid-area: icon; }
  .edit-header .eh-line { grid-area: line; }
  .edit-header .eh-actions { grid-area: actions; justify-self: end; }

  /* Overview callout stats: four on a phone (deck note 1) — "Edits (7 days)"
     and "Inbound links" drop out. Both numbers survive on the Activity and The
     Page cards below, so nothing is lost, only the row. */
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .stat-grid .stat-card:nth-child(1), .stat-grid .stat-card:nth-child(6) { display: none; }

  /* Overview cards are grid items, so their automatic minimum size is their
     min-content — and the edits-per-year chart's min-content (one 34px column
     per year) is wider than a phone. That stretched every card in the stacked
     column past the gutter, since they share one track. min-width:0 lets a card
     take the track's width and the chart scroll inside it, which is what its own
     overflow-x:auto is already there for. */
  .ov-grid > .card { min-width: 0; }

  /* Before/After gutter back to the marker's own width: 2.5rem out of a 335px
     card would cost the two monospace columns more than the separation is worth
     at this size. The .diff-heads grid and the <col> widths both follow it. */
  .diff-card { --diff-gutter: var(--diff-marker); }

  /* Key/value rows (Overview, Edit Details): the label column's `auto` track is
     sized to its longest label, which at this width leaves the value column
     narrower than its own content and pushes the card past the gutter. Let both
     tracks shrink, and break the long descriptions and language lists. */
  .kv { grid-template-columns: minmax(0, auto) minmax(0, 1fr); }
  .kv .v { overflow-wrap: anywhere; }

  /* Top Editors condenses to two columns: name over experience badge, edits to
     this article over total edits; the registered year drops out (deck note 1).
     Same block-plus-grid mechanism as the Edit List rows above. A fixed second
     track keeps the numbers on one x-position down the list — each row is its
     own grid, so an auto track would ragged-edge them. */
  table.list.top-editors, .top-editors thead, .top-editors tbody,
  .top-editors th, .top-editors td { display: block; }
  .top-editors tr {
    display: grid; grid-template-columns: minmax(0, 1fr) 8.5rem;
    grid-template-areas: "name edits" "badge total";
    gap: 0.3rem 0.6rem; padding: 0.85rem 0.9rem;
    border-bottom: 1px solid var(--line);
  }
  .top-editors tbody tr:last-child { border-bottom: none; }
  table.list.top-editors th, table.list.top-editors td { padding: 0; border-bottom: none; }
  .top-editors tr > :nth-child(1) { grid-area: name; overflow-wrap: anywhere; }
  .top-editors tr > :nth-child(2) { grid-area: edits; }
  .top-editors tr > :nth-child(3) { grid-area: badge; }
  .top-editors tr > :nth-child(4) { display: none; }
  .top-editors tr > :nth-child(5) { grid-area: total; font-weight: 700; }
  .top-editors tr > td.row-wide { grid-area: auto; grid-column: 1 / -1; }
  .top-editors thead th:nth-child(3), .top-editors thead th:nth-child(5) { display: none; }
  .top-editors th.num, .top-editors td.num { text-align: left; white-space: normal; }
  .te-short, .te-suffix { display: inline; }
  .te-long { display: none; }
  .te-suffix { font-weight: 400; }

  /* Badge reference: three nowrap columns need ~352px and the card offers 295,
     and a table that scrolls with no affordance just reads as clipped mid-word.
     Let the columns wrap instead — a reference table can take two-line cells. */
  .badge-table { font-size: 0.8rem; }
  .badge-table th, .badge-table td { padding: 0.45rem 0.4rem; white-space: normal; }

  /* Account Settings: the two password fields stack full-width (mockup) rather
     than sharing a row at a width where neither reads as a real field. */
  .set-fields { flex-direction: column; }
  .set-fields input { flex: none; width: 100%; }
}
