:root {
  --ink: oklch(22% 0.012 260);
  --ink-soft: oklch(47% 0.012 260);
  --paper: oklch(97% 0.004 90);
  --panel: oklch(99% 0.002 90);
  --line: oklch(90% 0.005 90);
  --navy: oklch(24% 0.02 260);
  --navy-dark: oklch(18% 0.018 260);
  --accent: oklch(50% 0.11 250);
  --accent-dark: oklch(42% 0.11 250);
  --brass: oklch(42% 0.1 80);
  --brass-soft: oklch(93% 0.06 80);
  --red: oklch(43% 0.13 25);
  --red-soft: oklch(93% 0.05 25);
  --red-solid-bg: oklch(43% 0.13 25);
  --red-solid-fg: oklch(98% 0.005 25);
  --green: oklch(38% 0.09 155);
  --green-soft: oklch(93% 0.055 155);
  --info: oklch(42% 0.1 250);
  --info-soft: oklch(93% 0.035 250);
  --teal: oklch(40% 0.09 200);
  --teal-soft: oklch(92% 0.05 200);
  --purple: oklch(43% 0.11 305);
  --purple-soft: oklch(93% 0.045 305);
  --gray-fg: oklch(45% 0.012 260);
  --gray-soft: oklch(93% 0.006 260);
  /* House identity colours for the bill progress track only (see
     lw_bill_stage_track()) -- deliberately distinct from --green/--red,
     which mean "first/second House" (by order) on the existing stage
     badge and "success/error" everywhere else. Commons/Lords here mean
     the House itself, regardless of which one a bill started in. */
  --commons: oklch(42% 0.12 145);
  --commons-soft: oklch(92% 0.05 145);
  --lords: oklch(40% 0.15 8);
  --lords-soft: oklch(92% 0.05 8);
  --radius: 10px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: "Inter", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.5;
}

h1, h2 {
  font-family: inherit;
  color: var(--ink);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 4px;
}

h1 { font-size: 1.7rem; }
h2 { font-size: 1.15rem; margin-top: 0; font-weight: 700; }

a { color: var(--accent); }
a:hover { color: var(--accent-dark); }

.shell { min-height: 100vh; display: flex; flex-direction: column; }

.topbar {
  background: var(--navy);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 60px;
}

.brand { display: flex; align-items: center; gap: 10px; color: #fff; text-decoration: none; }
.brand:hover { color: #fff; opacity: 0.85; }
.brand-mark {
  width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.brand-mark svg { display: block; }
.brand-text { font-weight: 700; letter-spacing: -0.01em; font-size: 1.02rem; }

.topnav { display: flex; align-items: center; gap: 4px; font-size: 0.88rem; }
.topnav a { color: oklch(78% 0.012 260); text-decoration: none; padding: 8px 12px; border-radius: 7px; font-weight: 500; }
.topnav a:hover { color: #fff; background: oklch(32% 0.02 260); }
.topnav-user { color: oklch(65% 0.012 260); margin-left: 8px; }
.logout-link { border-left: 1px solid oklch(38% 0.02 260); padding-left: 16px; margin-left: 8px; border-radius: 0; }
.logout-link:hover { background: transparent; color: #fff; }

.content { flex: 1; max-width: 980px; width: 100%; margin: 0 auto; padding: 32px 24px 64px; }

.page-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
/* The 70ch cap here was a readability default, but it left every
   explanatory paragraph visibly narrower than the cards directly beneath
   it, which reads as a layout fault rather than a typographic choice. The
   content column is already capped at 980px, so lines never run away. */
.page-intro { color: var(--ink-soft); line-height: 1.6; }

.alert { padding: 10px 14px; border-radius: var(--radius); font-size: 0.92rem; margin-bottom: 16px; border: 1px solid transparent; }
.alert-ok { background: var(--green-soft); color: var(--green); }
.alert-error { background: var(--red-soft); color: var(--red); }

.stat-row { display: flex; gap: 12px; margin: 20px 0; flex-wrap: wrap; align-items: stretch; }
/* Each card is wrapped in a link, so the link is the flex item and the
   card inside it is not. Without these two rules the card kept its own
   content height, so a row where one label wrapped to a second line left
   the shorter cards visibly out of alignment. */
.stat-row > a { display: flex; }
.stat-row > a > .stat-card { flex: 1; }
.stat-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px 14px;
  min-width: 120px;
  position: relative;
  overflow: hidden;
}
.stat-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--brass); }
.stat-card-muted::before { background: var(--line); }
.stat-num { display: block; font-size: 1.6rem; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.stat-label { font-size: 0.75rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 600; }

.filter-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.tab { padding: 8px 14px; text-decoration: none; color: var(--ink-soft); font-size: 0.9rem; border-bottom: 2px solid transparent; }
.tab-active { color: var(--ink); border-bottom-color: var(--brass); font-weight: 600; }

/*
 * Stat-tabs: the stat-card look, but the card itself is the tab —
 * built after real user feedback that separate number cards and filter
 * tabs directly underneath them, both doing the same job, invited
 * clicking the numbers and getting nothing. Each one keeps a resting
 * grey top edge and picks up its own colour, set per-tab via an inline
 * custom property so the same CSS serves every colour rather than
 * needing a class per status, only when it's the selected one — an
 * outline, not a fill, so the row still reads calmly when nothing
 * especially urgent is selected.
 */
.stat-tabs { display: flex; gap: 10px; margin: 20px 0 18px; flex-wrap: wrap; }
.stat-tab {
  display: block;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 18px 12px;
  min-width: 120px;
  text-decoration: none;
  position: relative;
  overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.stat-tab::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--line); transition: background 0.15s ease; }
.stat-tab:hover::before { background: var(--stat-tab-color, var(--brass)); }
.stat-tab-active { border-color: var(--stat-tab-color, var(--brass)); box-shadow: 0 0 0 1px var(--stat-tab-color, var(--brass)); }
.stat-tab-active::before { background: var(--stat-tab-color, var(--brass)); }
.stat-tab .stat-num { display: block; font-size: 1.5rem; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.stat-tab .stat-label { font-size: 0.75rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 600; }

/* The Upcoming/Made stage toggle sits a size class up from the status
   stat-tabs below it — same interaction, but visually its own level of
   the hierarchy rather than a seventh status tab. */
.stage-tabs { display: flex; gap: 10px; margin: 20px 0 0; }
.stage-tab {
  display: block;
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 3px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 22px;
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.stage-tab:hover { border-top-color: var(--stat-tab-color, var(--navy)); }
.stage-tab-active {
  border-color: var(--stat-tab-color, var(--navy));
  border-top-color: var(--stat-tab-color, var(--navy));
  box-shadow: 0 0 0 1px var(--stat-tab-color, var(--navy));
}
.stage-tab .stat-num { display: block; font-size: 1.3rem; font-weight: 800; color: var(--ink); }
/* Both of these need display:block. Left inline, the label and the
   caption below it ran together on one line as a single run of text
   ("UpcomingDrafts & awaiting commencement") with nothing separating
   them, on the SIs stage toggle and the Publications stream toggle
   alike. */
.stage-tab .stat-label { display: block; font-size: 0.85rem; color: var(--ink); font-weight: 600; }
.stage-tab .stage-tab-sub { display: block; margin-top: 3px; font-size: 0.78rem; color: var(--ink-soft); line-height: 1.35; }

.item-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.item-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.item-main { flex: 1; min-width: 240px; }
.item-type {
  display: inline-block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--brass);
  font-weight: 700;
  margin-bottom: 4px;
}
.item-title { display: block; font-weight: 700; color: var(--ink); text-decoration: none; margin-bottom: 4px; }
.item-title:hover { color: var(--accent); text-decoration: none; }
.item-meta { font-size: 0.82rem; color: var(--ink-soft); display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.item-matches { color: var(--brass); }

/* Matched keyword groups, as a chip rather than another line of brass
   text.

   .item-matches was doing two unrelated jobs in the same colour: naming
   which subject areas an item touches, and carrying factual scheduling
   detail like "In force: 1 Oct 2026". Sitting side by side in identical
   brass, they read as one run of text. The chip keeps brass for the
   subject-area meaning it has everywhere else in the app and gives it a
   shape; .item-detail takes the scheduling job in a quieter slate. */
.lw-chip {
  display: inline-block;
  background: var(--brass-soft);
  color: var(--brass);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.5;
  padding: 2px 9px;
  border-radius: 11px;
}

.item-detail { color: var(--ink-soft); font-size: 0.82rem; }
.item-actions { display: flex; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }
/* A <form> is a block box by default; as a direct flex child alongside
   plain <a class="btn"> links, that box (not the button inside it)
   takes part in the flex row, which is what actually made the
   Prioritise rescan / Mark relevant / Mark not relevant buttons render
   thinner than their neighbours despite sharing the exact same .btn
   classes. display:contents removes the form's own box from layout
   entirely, so its button behaves exactly like the anchors beside it —
   confirmed via a screenshot showing the mismatch. */
.item-actions form { display: contents; }

.empty-state {
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 28px;
  text-align: center;
}

.bill-summary { font-size: 0.86rem; color: var(--ink-soft); background: var(--paper); border-left: 3px solid var(--brass); padding: 8px 12px; margin: 8px 0; border-radius: 0 6px 6px 0; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 24px;
  margin-bottom: 20px;
}

.data-table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.data-table th, .data-table td { text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line); font-size: 0.9rem; }
.data-table th { background: var(--paper); color: var(--ink-soft); font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.data-table tr:last-child td { border-bottom: none; }
.url-cell a { word-break: break-all; font-size: 0.85rem; }

/* The force list. The address field was inheriting a narrow default, so
   every row showed "https://ww" and you had to click into the box and
   scroll to find out which site a force was actually pointed at --
   awkward for a column whose whole job is to be checked by eye. It now
   fills its cell, and the column is given room to be filled.

   Monospace because these are addresses being compared character by
   character, where a proportional font hides the difference between
   northyorkshire and north-yorkshire. */
.lw-force-table { table-layout: fixed; width: 100%; }
.lw-force-table td { vertical-align: middle; padding-top: 8px; padding-bottom: 8px; }
.lw-force-table th:nth-child(1), .lw-force-table td:nth-child(1) { width: 17%; }
.lw-force-table th:nth-child(2), .lw-force-table td:nth-child(2) { width: 26%; }
.lw-force-table th:nth-child(3), .lw-force-table td:nth-child(3) { width: 27%; }
.lw-force-table th:nth-child(4), .lw-force-table td:nth-child(4) { width: 30%; }
.lw-force-table .url-cell input { width: 100%; box-sizing: border-box;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.82rem; }

/* The failure messages carry a full URL, and a URL has no spaces in it to
   break at, so under table-layout:fixed it ran straight over the column
   to its right and sat on top of the switches. */
.lw-force-table .sitemap-cell { overflow-wrap: anywhere; word-break: break-word; }

/* Switches and Save on one line rather than stacked. Stacking squeezed
   each label into two or three wrapped lines and made every row three
   times taller than it needed to be, on a page that is already long.
   Wrapping is still allowed, so a narrow window degrades to stacked
   rather than overflowing. */
.force-toggles { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; }
.force-toggles .checkbox-label { margin: 0; white-space: nowrap; }
.force-toggles .btn { margin-left: auto; }

@media (max-width: 900px) {
  /* Fixed percentages stop making sense once the table is narrower than
     the addresses in it; let it size to content instead of squeezing
     every column equally badly. */
  .lw-force-table { table-layout: auto; }
  .lw-force-table th, .lw-force-table td { width: auto !important; }
}
.table-actions { display: flex; gap: 8px; }

.pill { display: inline-block; padding: 3px 10px; border-radius: 6px; font-size: 0.74rem; font-weight: 600; background: var(--gray-soft); color: var(--gray-fg); }
.pill-active { background: var(--green-soft); color: var(--green); }

label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); margin: 12px 0 4px; }
input[type="text"], input[type="email"], input[type="password"] {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: 7px;
  font-size: 0.95rem;
  background: #fff;
  font-family: inherit;
}
.checkbox-label { display: flex; align-items: center; gap: 8px; font-weight: 500; color: var(--ink); margin-top: 14px; }
.checkbox-label input { width: auto; }

.btn {
  display: inline-block;
  border: none;
  border-radius: 7px;
  padding: 9px 16px;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  font-family: inherit;
}
.btn-primary { background: var(--navy); color: #fff; }
.btn-primary:hover { background: var(--navy-dark); }
.btn-small { padding: 6px 12px; font-size: 0.8rem; background: var(--gray-soft); color: var(--ink); }
.btn-small:hover { background: var(--line); }
.btn-ghost { background: transparent; border: 1px solid var(--line); color: var(--ink-soft); }
.btn-ghost:hover { background: var(--gray-soft); border-color: var(--gray-soft); }
.btn-danger { background: var(--red-soft); color: var(--red); }
.btn-danger:hover { background: oklch(88% 0.06 25); }

.inline-form { display: flex; gap: 10px; margin: 16px 0 20px; flex-wrap: wrap; }
.inline-form input[type="text"] { width: auto; flex: 1; min-width: 220px; }
.inline-form-wide input[type="text"] { flex: 1; min-width: 180px; }
.inline-form-tight { margin: 14px 0 0; }
.inline-form-tight input[type="text"] { min-width: 160px; }

.group-list { display: flex; flex-direction: column; gap: 12px; }
.group-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px;
  position: relative;
  overflow: hidden;
}
.group-card::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 4px; background: var(--brass); }
.group-card-inactive::before { background: var(--line); }
.group-card-inactive { opacity: 0.7; }
.group-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.group-card-head h2 { display: flex; align-items: center; gap: 8px; font-size: 1.05rem; }

.group-empty { color: var(--ink-soft); font-size: 0.88rem; margin: 6px 0; }

.term-pills { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.term-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--brass-soft);
  color: var(--brass);
  border-radius: 99px;
  padding: 4px 6px 4px 12px;
  font-size: 0.85rem;
  font-weight: 500;
}
.term-pill-inactive { background: var(--gray-soft); color: var(--ink-soft); text-decoration: line-through; }
.term-pill-actions { display: inline; }
.term-pill-actions button {
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;
  font-size: 0.8rem;
  padding: 2px 4px;
  border-radius: 99px;
}
.term-pill-actions button:hover { background: rgba(0,0,0,0.08); }

.auth-wrap { display: flex; justify-content: center; padding-top: 40px; }
.auth-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 30px 32px; width: 340px; }
.auth-card button { width: 100%; margin-top: 18px; }

.code-block { background: var(--paper); border: 1px solid var(--line); border-radius: 7px; padding: 12px 14px; font-family: "SFMono-Regular", Consolas, monospace; font-size: 0.85rem; overflow-x: auto; word-break: break-all; white-space: pre-wrap; }

code { background: var(--paper); padding: 1px 5px; border-radius: 4px; font-size: 0.88em; }

/* ─────────────────────────────────────────────────────────────────────
   Grouped navigation.

   The flat nav reached ten items, at which point scanning it cost more
   than it saved. Items are now grouped behind two dropdowns, which
   creates one problem worth solving deliberately: you can no longer see
   where you are. Hence .navgroup-btn.is-current, which marks the group
   containing the current page so orientation survives the collapse.
   ───────────────────────────────────────────────────────────────────── */

.navgroup { position: relative; display: flex; align-items: center; }

.navgroup-btn {
  display: flex; align-items: center; gap: 6px;
  background: none; border: 0; cursor: pointer;
  color: oklch(78% 0.012 260);
  font: inherit; font-weight: 500;
  padding: 8px 12px; border-radius: 7px;
}
.navgroup-btn:hover { color: #fff; background: oklch(32% 0.02 260); }

/* The current group stays visibly marked whether or not it's open. */
.navgroup-btn.is-current { color: #fff; background: oklch(32% 0.02 260); }

.navgroup-caret { font-size: 0.7em; opacity: 0.7; }

.navgroup-menu {
  display: none;
  position: absolute;
  top: 100%; left: 0;
  min-width: 190px;
  background: var(--navy-dark);
  border: 1px solid oklch(38% 0.02 260);
  border-radius: 9px;
  padding: 6px;
  box-shadow: 0 10px 28px oklch(20% 0.02 260 / 0.45);
  z-index: 60;
}

/* Hover for mice, focus-within for keyboards, and .navgroup-open for
   touch — where hover never fires and a tap must do the work. */
.navgroup:hover .navgroup-menu,
.navgroup:focus-within .navgroup-menu,
.navgroup.navgroup-open .navgroup-menu { display: block; }

.navgroup-menu a {
  display: block;
  white-space: nowrap;
  padding: 8px 12px;
  border-radius: 6px;
}
.navgroup-menu a.is-current { color: #fff; background: oklch(32% 0.02 260); }

.hamburger-btn {
  display: none;
  background: none; border: 0; cursor: pointer;
  color: #fff; font-size: 1.4rem; line-height: 1;
  padding: 6px 10px; border-radius: 7px;
}
.hamburger-btn:hover { background: oklch(32% 0.02 260); }

@media (max-width: 640px) {
  .topbar { position: relative; flex-wrap: wrap; }
  .hamburger-btn { display: block; }

  /* Previously .topnav was simply hidden here and the hamburger had no
     styles at all, so the toggle did nothing. The nav now drops below
     the bar when opened. */
  .topnav { display: none; }
  .topnav.topnav-open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: absolute;
    top: 60px; left: 0; right: 0;
    background: var(--navy-dark);
    border-top: 1px solid oklch(38% 0.02 260);
    padding: 8px;
    gap: 2px;
    z-index: 60;
  }

  /* Groups expand inline rather than as floating menus — a dropdown
     inside a dropdown is a poor tap target, and there is room here. */
  .topnav-open .navgroup { display: block; }
  .topnav-open .navgroup-btn { width: 100%; justify-content: space-between; }
  .topnav-open .navgroup-menu {
    display: block;
    position: static;
    border: 0; box-shadow: none; padding: 0 0 0 12px;
    background: transparent;
    min-width: 0;
  }
  .topnav-open .navgroup-caret { display: none; }

  .topnav-open .logout-link {
    border-left: 0; border-top: 1px solid oklch(38% 0.02 260);
    padding-left: 12px; margin-left: 0; margin-top: 4px; padding-top: 12px;
  }
  .topnav-open .topnav-user { margin-left: 0; }

  .content { padding: 20px 14px 48px; }
}

/* ─────────────────────────────────────────────────────────────────────
   Site review, item pages, and the slimmed listing cards.

   The amber left-rule means one thing throughout: Claude wrote this.
   Published text — a long title, Parliament's own description — uses a
   plain grey rule instead, and .bill-summary is no longer used for
   anything that isn't AI-written. A source label always accompanies it;
   the rule is a second signal, never the only one.
   ───────────────────────────────────────────────────────────────────── */

/* Listing card: stacks, with the keywords line doubling as the action
   row. The old side column cost about a third of the card's width once
   there were three buttons in it, which squeezed the summary badly. */
.lw-card { flex-direction: column; gap: 0; align-items: stretch; padding: 16px 18px; }
.lw-card .item-title { margin-bottom: 5px; font-size: 1.02rem; }
.lw-card-foot { display: flex; justify-content: space-between; align-items: center;
  gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.lw-card-foot .item-meta { flex: 1; min-width: 0; }
.lw-card-actions { display: flex; gap: 8px; flex-shrink: 0; align-items: center; }
.lw-card-actions form { display: inline; }

/* One-line summary, source named inline. */
.lw-summary { font-size: 0.88rem; color: var(--ink-soft); margin: 10px 0 0; line-height: 1.55; }
.lw-summary-claude { background: var(--paper); border-left: 3px solid var(--brass);
  padding: 8px 12px; border-radius: 0 6px 6px 0; }
.lw-summary-parliament { padding: 0; }
.lw-summary-label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
  font-weight: 700; color: var(--ink-soft); margin-right: 5px; }
.lw-summary-claude .lw-summary-label, .lw-label-claude { color: var(--brass); }
.lw-label-source { color: var(--ink-soft); }
/* On an item page the label sits on its own line above the text instead. */
p.lw-summary-label { display: block; margin: 0 0 4px; }

/* Published text. Deliberately not .bill-summary. */
.lw-quote { font-size: 0.9rem; color: var(--ink-soft); background: var(--paper);
  border-left: 3px solid var(--line); padding: 8px 12px; margin: 0; border-radius: 0 6px 6px 0; }

/* Claude's statutory citation under a finding — AI-written, so amber. */
.lw-cite { font-size: 0.82rem; color: var(--ink-soft); background: var(--paper);
  border-left: 3px solid var(--brass); padding: 8px 12px; margin: 12px 0 0; border-radius: 0 6px 6px 0; }

/* Deliberately not .page-intro: that class caps prose at 70ch, which is
   right for the explanatory hint text it's used for elsewhere, but this
   is the panel's actual content — Claude's full assessment — sitting
   inside a box that's already a sensible reading width. Capping it again
   left a visible gap on the right of the panel. */
.lw-assessment-text { color: var(--ink-soft); line-height: 1.65; }

/* A saved note that shaped a finding: the user's words, not Claude's. */
.lw-note-applied { font-size: 0.82rem; color: var(--ink-soft); background: var(--green-soft);
  border-left: 3px solid var(--green); padding: 8px 12px; margin: 12px 0 0; border-radius: 0 6px 6px 0; }

/* The site review caption sits on its own row under the stage dates,
   always, rather than only when the stage line runs long enough to push
   it there -- a card that reflows depending on how wordy Parliament was
   about a date looked broken rather than responsive. .item-meta is a
   wrapping flexbox, so a full-width basis is all that takes.

   Only the label is brass. Colouring the whole line made the date and
   the finding count shout as loudly as the words naming them. */
.lw-review-flag { flex-basis: 100%; color: var(--ink-soft); }
.lw-review-flag-label { color: var(--brass); font-weight: 600; }
.lw-mono { font-family: "SFMono-Regular", Consolas, monospace; font-size: 0.85rem; }
.lw-crumb { font-size: 0.85rem; margin: 0 0 10px; font-weight: 600; }
.lw-provenance { font-size: 0.78rem; color: var(--ink-soft); margin: 12px 0 0;
  padding-top: 10px; border-top: 1px solid var(--line); }
.lw-hint { font-size: 0.8rem; color: var(--ink-soft); margin: 5px 0 0; }
.lw-hint-inline { font-size: 0.8rem; color: var(--ink-soft); font-weight: 400; }
/* A page whose findings run to several parts: the intro count, and the
   label separating one affected passage from the next inside one card. */
.lw-parts-intro { margin: 10px 14px 0; font-size: 0.85rem; color: var(--ink-soft); }
.lw-part-label { margin: 14px 14px 0; font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.08em; font-weight: 700; color: var(--brass); }
.lw-finding-body + .lw-part-label { border-top: 1px solid var(--line); padding-top: 12px; }

/* The section list and page limit belong to the "Also search the site"
   checkbox above them -- they do nothing at all when it is unticked. The
   indent and rule make that ownership visible, and the dimming makes an
   unticked search obviously inert instead of leaving a live-looking grid
   of checkboxes that no longer affects anything. */
.lw-suggest-opts { margin: 10px 0 0 10px; padding-left: 14px;
  border-left: 2px solid var(--line); }
.lw-suggest-opts.lw-inactive { opacity: 0.45; }

/* The section header, with its select-all controls sitting opposite the
   label rather than stacked above the list. */
.lw-sections-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.lw-sections-bulk { display: flex; gap: 6px; }

/* "Coming up" on the Dashboard: a calendar tile beside each entry.
   Built from the existing tokens rather than new colours, so it reads as
   part of the same page -- the tile is a paper-coloured card with the
   same border and radius as every other card, not a skeuomorphic
   desk calendar. */
.lw-upcoming { display: flex; gap: 14px; align-items: center; padding: 10px 0; }
.lw-upcoming + .lw-upcoming { border-top: 1px solid var(--line); }
.lw-upcoming-main { min-width: 0; flex: 1; }
.lw-upcoming .item-title { margin-bottom: 6px; }

.lw-cal {
  flex: 0 0 auto;
  width: 58px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 0 7px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  border-top: 3px solid var(--brass);
  line-height: 1.1;
}
.lw-cal-dow { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.08em;
  font-weight: 700; color: var(--ink-soft); }
.lw-cal-day { font-size: 1.45rem; font-weight: 700; color: var(--ink); margin: 1px 0; }
.lw-cal-mon { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em;
  font-weight: 600; color: var(--ink-soft); }

/* The same calendar tile inside a card, rather than in a borderless
   list. Two differences from .lw-upcoming above: no padding or dividing
   rule, because the card already provides both, and the tile aligns to
   the top rather than the middle -- a publication card can carry a
   several-line assessment underneath, and a tile floating in the
   vertical centre of that looks unmoored from the title it dates. */
.lw-cal-row { display: flex; gap: 14px; align-items: flex-start; }
.lw-cal-main { min-width: 0; flex: 1; }

/* The stage badge, matching the one the Bills page builds inline. */
.lw-stage-badge { padding: 2px 8px; border-radius: 4px; font-weight: 600; }

@media (max-width: 560px) {
  .lw-upcoming { gap: 10px; }
  .lw-cal { width: 48px; }
  .lw-cal-day { font-size: 1.2rem; }
}

.lw-h3 { font-family: inherit; color: var(--ink);
  font-size: 1rem; font-weight: 700; margin: 22px 0 10px; }

.lw-alert-amber { background: var(--brass-soft); color: var(--brass); border: none;
  border-radius: var(--radius); padding: 10px 14px; font-size: 0.88rem; margin: 0 0 14px; }
.lw-alert-red { background: var(--red-soft); color: var(--red); border: none;
  border-radius: var(--radius); padding: 10px 14px; font-size: 0.88rem; margin: 0; }

/* The base stylesheet styles text/email/password inputs only. */
.lw-select, .lw-textarea { width: 100%; padding: 9px 11px; border: 1px solid var(--line);
  border-radius: 7px; font-size: 0.95rem; background: #fff; color: var(--ink);
  font-family: inherit; }
.lw-textarea { font-family: "SFMono-Regular", Consolas, monospace; font-size: 0.85rem; resize: vertical; }

.lw-sections { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 20px;
  border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 14px; background: #fff; }
.lw-sections .checkbox-label { margin-top: 6px; font-size: 0.88rem; }
.lw-sections .lw-off { color: var(--ink-soft); }
.lw-count { margin-left: auto; font-family: "SFMono-Regular", Consolas, monospace;
  font-size: 0.78rem; color: var(--ink-soft); }

.lw-subform { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px;
  padding-top: 14px; border-top: 1px solid var(--line); }

.lw-finding { border: 1px solid var(--line); border-left: 4px solid var(--brass);
  border-radius: var(--radius); margin: 0 0 12px; background: #fff; overflow: hidden; }
.lw-finding-clear { border-left-color: var(--green); }
.lw-finding-fail { border-left-color: var(--line); }
.lw-finding-flagged { border-left-color: var(--red); }
.lw-finding-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  align-items: center; padding: 10px 14px; background: var(--paper); border-bottom: 1px solid var(--line); }
.lw-finding-body { padding: 14px; }
.lw-finding-body p { margin: 0; font-size: 0.9rem; }
.lw-finding-foot { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 9px 14px; border-top: 1px solid var(--line); }
.lw-finding-foot form { display: inline; }
.lw-url { font-family: "SFMono-Regular", Consolas, monospace; font-size: 0.82rem; word-break: break-all; }

.lw-feedback { padding: 12px 14px; border-top: 1px solid var(--line); background: var(--red-soft); }
.lw-feedback label { margin-top: 10px; color: var(--red); }
.lw-feedback label:first-child { margin-top: 0; }
.lw-feedback-foot { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 12px; }

.lw-rerun { border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); padding: 14px 16px; margin-top: 18px; }
.lw-rerun p { margin: 0; font-size: 0.9rem; color: var(--ink-soft); }

.lw-diff { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; margin: 11px 0 0; }
.lw-diff > div { padding: 10px 12px; }
.lw-was { background: var(--red-soft); border-right: 1px solid var(--line); }
.lw-now { background: var(--green-soft); }
.lw-diff-tag { display: block; margin: 0 0 6px; font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.04em; font-weight: 700; }
.lw-was .lw-diff-tag { color: var(--red); }
.lw-now .lw-diff-tag { color: var(--green); }
.lw-diff p { font-size: 0.88rem; }

.lw-bar { height: 6px; background: var(--gray-soft); border-radius: 99px; overflow: hidden; }
.lw-bar i { display: block; height: 100%; background: var(--accent); }

@media (max-width: 640px) {
  .lw-sections { grid-template-columns: 1fr; }
  .lw-diff { grid-template-columns: 1fr; }
  .lw-was { border-right: 0; border-bottom: 1px solid var(--line); }
  .lw-card-foot { flex-direction: column; align-items: flex-start; }
}

/* "Last stage change" is worth noticing at a glance among the other meta
   text on a card or in the dates table -- bold + ink rather than brass,
   since brass specifically means "Claude wrote this" throughout this app
   and a stage-change date is a plain fact, not AI content. */
.lw-stage-date-label { font-weight: 700; color: var(--ink); }

/* Placeholder text in the site-review "specific pages" box was reading as
   real, already-typed URLs rather than illustrative examples -- lighter
   and semi-transparent so it reads as a hint, not content. */
.lw-textarea::placeholder { color: var(--ink-soft); opacity: 0.6; }

/* Site-review diff columns.
   pre-wrap preserves the page's own line breaks and "- " bullet prefixes
   exactly as they were extracted, so a content editor can match the block
   against the live page line for line. Without it, HTML collapses every
   newline to a space and a bulleted list arrives as one run-on sentence. */
.lw-diff p { white-space: pre-wrap; }

/* Inline change markers. Deliberately distinct from the panel background
   tints, which only say which SIDE you're on -- these say which WORDS
   actually differ. */
.lw-del { color: var(--red); text-decoration: line-through;
  text-decoration-thickness: 2px; background: oklch(88% 0.06 25); border-radius: 3px; padding: 0 2px; }
.lw-ins { color: var(--green); font-weight: 600; background: oklch(88% 0.07 155); border-radius: 3px; padding: 0 2px; }

/* Welsh Checker: English/Welsh side by side, reusing .lw-diff's grid
   layout and mobile collapse (both classes sit on the same element) but
   with its own colour language. Site Review's red/was and green/now
   pairing means "before vs after" -- here the two columns are supposed
   to say the SAME thing, so a mismatch is a property of the PAIR, not of
   one side being the problem and the other the fix. Green on both sides
   when a section matches; red on BOTH when it doesn't. */
.lw-wc-pair .lw-wc-en,
.lw-wc-pair .lw-wc-cy { background: var(--green-soft); }
.lw-wc-pair.lw-wc-gap .lw-wc-en,
.lw-wc-pair.lw-wc-gap .lw-wc-cy { background: var(--red-soft); }
.lw-wc-en { border-right: 1px solid var(--line); }
.lw-wc-pair .lw-diff-tag { color: var(--ink-soft); }
.lw-wc-pair.lw-wc-gap .lw-diff-tag { color: var(--red); }

/* The specific missing phrase within a Welsh Checker section. Deeper and
   more saturated than the section's own light red/green tint, on
   purpose, so the exact gap stands out from "this whole section has a
   problem" rather than blending into it -- the same relationship
   .lw-del/.lw-ins have to .lw-was/.lw-now. */
.lw-missing { font-weight: 700; background: oklch(80% 0.09 25); border-radius: 3px; padding: 0 2px; }

.lw-wc-section { margin-top: 18px; }
.lw-wc-section:first-child { margin-top: 0; }
.lw-wc-heading { font-size: 0.95rem; font-weight: 700; margin: 0 0 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

@media (max-width: 640px) {
  .lw-wc-en { border-right: 0; border-bottom: 1px solid var(--line); }
}

/* Bill progress track: a line of dots per House (Commons/Lords, by
   identity) plus a final Royal Assent dot -- see lw_bill_stage_track().
   Colour is set inline per dot from PHP, same convention as .pill +
   inline background/color; these rules are layout only. */
.lw-stage-track { display: flex; align-items: center; gap: 10px; margin: 8px 0 6px; max-width: 480px; }
.lw-stage-group { display: flex; align-items: center; }
.lw-stage-dots { display: flex; align-items: center; width: 100%; }
.lw-stage-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.lw-stage-line { flex: 1; height: 2px; }

/* Dot states. Until these existed every dot was an identical 8px circle
   and only the tooltip distinguished them -- so 'done' and 'current'
   looked the same, and 'upcoming', 'skipped' and 'stopped' were all
   simply grey. The track could compute where a bill was and then not
   show it.

   Shape carries the meaning rather than colour alone, so the states stay
   legible for anyone who can't easily separate the House colours, and at
   the 8px size where a colour shift is nearly invisible anyway. */

/* Where the bill is now: larger, with a halo, so the eye lands on it. */
.lw-stage-dot-current {
  width: 12px; height: 12px;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dot-color) 22%, transparent);
}

/* A stage that never happened -- the National Security Act took no report
   stage at all. Hollow, because filling it would invent a sitting, but
   ringed in the House colour at full weight: a grey ring read as just
   another upcoming dot at this size, which defeated the point. */
.lw-stage-dot-skipped {
  background: transparent !important;
  box-shadow: inset 0 0 0 2.5px var(--dot-color);
  width: 10px; height: 10px;
}

/* Where a withdrawn, defeated or fallen bill stopped. Square, because a
   journey that ended is not the same as one still to come. */
.lw-stage-dot-stopped {
  border-radius: 2px;
  background: var(--ink-soft) !important;
  width: 10px; height: 10px;
}
.lw-stage-legend { display: flex; align-items: center; gap: 12px; margin: 0 0 10px; }
.lw-stage-legend-item { display: flex; align-items: center; gap: 4px; font-size: 0.7rem; color: var(--ink-soft); }
.lw-stage-legend-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }

/* Detail-page variant: bigger dots, a House name under each group instead
   of a separate legend row. */
.lw-stage-track-lg { max-width: 600px; align-items: flex-start; gap: 16px; margin: 0; }
.lw-stage-track-lg .lw-stage-group { flex-direction: column; }
.lw-stage-track-lg .lw-stage-dot { width: 11px; height: 11px; }
.lw-stage-group-label { font-size: 0.72rem; font-weight: 600; margin-top: 8px; letter-spacing: 0.01em; }

@media (max-width: 640px) {
  .lw-stage-track, .lw-stage-track-lg { max-width: none; }
}

/* Paste-the-sitemap fallback. Collapsed by default so it stays out of the
   way in the normal case, and only rendered at all once the automatic
   route has actually failed for the selected force. */
.lw-paste-fallback { margin-top: 14px; padding: 12px 14px; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius); }
.lw-paste-fallback summary { cursor: pointer; font-weight: 600; font-size: 0.88rem; color: var(--ink); }

/* APP change cards (apps.php). One card per APP per day; each distinct
   change note once, with the pages it touched beneath it. */
.lw-app-trail { margin-bottom: 2px; }
.lw-app-trail a { color: inherit; text-decoration: none; }
.lw-app-trail a:hover { text-decoration: underline; }
.lw-app-note { margin-top: 10px; }
.lw-app-note + .lw-app-note { padding-top: 10px; border-top: 1px solid var(--line); }
.lw-app-note-text { line-height: 1.55; }
.lw-app-note-line { display: block; }
.lw-app-note-list { margin: 4px 0 4px 18px; padding: 0; }
.lw-app-more { margin-top: 4px; }
.lw-app-more summary, details.lw-app-pages summary { cursor: pointer; }
.lw-app-pages { font-size: 0.8rem; color: var(--ink-soft); margin: 4px 0 0; }
.lw-app-pages-label { font-weight: 600; }
.lw-app-pages ul { margin: 4px 0 0 18px; padding: 0; columns: 2 16rem; }
.lw-app-reason { margin-top: 6px; }
.lw-app-provisional { margin: 4px 0 0; opacity: 0.75; font-size: 0.78rem; }
.lw-app-import { margin-top: 18px; }