/* Said and Done — neutral, sober, self-hosted (CSP: style-src 'self').
   Colour lives in custom properties; @media (prefers-color-scheme: dark)
   re-declares them (D-040/A3). No JS, no cookies: the OS preference decides. */

/* Self-hosted heading serif (D-040/A2): Source Serif 4 SemiBold, OFL,
   subset to Latin + Irish diacritics (licence in fonts/OFL-source-serif-4.txt). */
@font-face {
  font-family: "Source Serif 4";
  src: url("fonts/source-serif-4-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Light is the primary design (D-054); dark is the option below. Every text
     token clears WCAG AA 4.5:1 on both --bg and --surface, measured, and
     --stroke-neutral clears 3:1 for non-text. */
  --ink: #15181c; --muted: #555d65; --line: #d7dbdf;
  --accent: #0a6a55; --accent-soft: #e4f0ec; --bg: #ffffff;
  --surface: #f6f4ef; --stroke-neutral: #7c858d;
  --ta: #0a6a55; --nil: #a02f2c; --staon: #79642c; --none: #b6bcc3;
  --lang-en: #4d6070; --lang-ga: #0a6a55;
  --hm-0: #eceae4; --hm-1: #c3ded4; --hm-2: #8ec2b2; --hm-3: #43917a; --hm-4: #0a6a55;
  /* One measure for the whole page (D-053): the header rule and footer rule
     span the viewport, but header, main and footer *contents* align to this
     column. --prose is the narrower cap for running text. */
  --measure: 72rem; --prose: 46rem; --prose-wide: 58rem; --gutter: 1.25rem;
  /* One body size everywhere (D-054). --text-chrome is the only smaller step,
     and only for labels that name a thing rather than say one: table headers,
     chart axes, the provenance line. Nothing on the site goes below it. */
  --text: 1.0625rem; --text-chrome: 0.9375rem;
}
/* Dark by OS preference, unless the reader has explicitly chosen light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink: #e8eaec; --muted: #a9b1b9; --line: #363d45;
    --accent: #5cc0a5; --accent-soft: #1b2f29; --bg: #14171b;
    --surface: #1c2026; --stroke-neutral: #6d777f;
    --ta: #5cc0a5; --nil: #e08b87; --staon: #c9b075; --none: #4b545c;
    --lang-en: #8fa3b4; --lang-ga: #5cc0a5;
    --hm-0: #22272d; --hm-1: #24413a; --hm-2: #2d6153; --hm-3: #3f8d76; --hm-4: #5cc0a5;
  }
}
/* Dark by explicit choice, whatever the OS says. */
:root[data-theme="dark"] {
    --ink: #e8eaec; --muted: #a9b1b9; --line: #363d45;
    --accent: #5cc0a5; --accent-soft: #1b2f29; --bg: #14171b;
    --surface: #1c2026; --stroke-neutral: #6d777f;
    --ta: #5cc0a5; --nil: #e08b87; --staon: #c9b075; --none: #4b545c;
    --lang-en: #8fa3b4; --lang-ga: #5cc0a5;
    --hm-0: #22272d; --hm-1: #24413a; --hm-2: #2d6153; --hm-3: #3f8d76; --hm-4: #5cc0a5;
}

* { box-sizing: border-box; }
body {
  margin: 0; color: var(--ink); background: var(--bg);
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: var(--text); line-height: 1.6;
}
/* Every full-width band puts its contents in .wrap so nothing is left flush
   to the viewport edge while the rest of the page is centred. */
.wrap { max-width: var(--measure); margin: 0 auto;
  padding-left: var(--gutter); padding-right: var(--gutter); }
main { padding-top: 1rem; padding-bottom: 3rem; }
/* Running text is capped well short of the table measure: a 72rem line of
   prose is unreadable, a 72rem table is the point. Only top-level text is
   capped; tables, charts, grids and anything nested keep the full measure. */
/* On a data page the paragraph sits under a heading rule drawn at the full
   measure, so a 46rem cap reads as text breaking for no reason; 58rem keeps
   the line length sane while closing most of that gap. A prose page narrows
   its whole column instead, below, and this cap never bites there. */
main > p, main > ul, main > ol, main > dl, main > blockquote {
  max-width: var(--prose-wide);
}
/* A page that is nothing but prose narrows its whole column to the reading
   measure instead (D-056). Otherwise every paragraph broke at 46rem under a
   heading rule drawn at 72rem, which reads as text wrapping for no reason. */
main.prose-page { --measure: var(--prose); }
.prose { max-width: var(--prose); }
/* Dates and other single tokens that must never break across lines. */
.nobr { white-space: nowrap; }
a { color: var(--accent); }

/* Skip link (D-040/C7): visually hidden until keyboard focus. */
.skip-link {
  position: absolute; left: -999rem; top: 0; z-index: 10;
  background: var(--accent); color: #fff; padding: 0.5rem 1rem;
  border-radius: 0 0 4px 0; text-decoration: none;
}
.skip-link:focus { left: 0; }
/* Present to a screen reader, absent on screen — for a column whose meaning is
   obvious visually but whose header still needs a name. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.site-header { border-bottom: 3px solid var(--accent); }
.header-inner {
  display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap;
  gap: 0.4rem 1.5rem; padding-top: 0.9rem; padding-bottom: 0.9rem;
}
.header-inner nav { flex: 1 1 auto; }
.brand {
  font-family: "Source Serif 4", Georgia, serif; font-weight: 600;
  font-size: 1.45rem; text-decoration: none; color: var(--ink);
}
.brand .amp { color: var(--accent); font-weight: 400; font-style: italic; }
.site-header nav {
  display: flex; flex-wrap: wrap; gap: 0.2rem 1.15rem; justify-content: flex-end;
}
.site-header nav a { text-decoration: none; color: var(--muted); }
.site-header nav a:hover { color: var(--accent); }
.site-header nav a[aria-current="page"] { color: var(--accent); font-weight: 600; }
/* Below the wrap point the nav is a left-aligned block under the brand
   rather than a ragged right-hand cluster. */
@media (max-width: 52rem) {
  .header-inner { gap: 0.35rem 1rem; }
  .site-header nav { justify-content: flex-start; }
}
.site-footer { border-top: 1px solid var(--line); color: var(--muted);
  font-size: var(--text-chrome); padding-top: 1rem; padding-bottom: 1rem; }

/* Colour-scheme control (D-056): a segmented set of submit buttons, sober
   enough to sit beside the nav and never competing with it. */
.theme { display: flex; align-items: baseline; gap: 0.45rem;
  font-size: var(--text-chrome); color: var(--muted); }
.theme-options { display: inline-flex; border: 1px solid var(--line);
  border-radius: 4px; overflow: hidden; }
.theme button {
  border: 0; border-left: 1px solid var(--line); background: var(--bg);
  color: var(--muted); font: inherit; padding: 0.15rem 0.55rem; cursor: pointer;
}
.theme button:first-child { border-left: 0; }
.theme button:hover { color: var(--accent); background: var(--accent-soft); }
.theme button[aria-current="true"] {
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
}

/* Typographic rhythm (D-040/A1): headings carry the serif voice; a spacing
   scale (0.5/1/1.5/2.5rem) separates sections instead of run-together text. */
h1, h2, h3 { font-family: "Source Serif 4", Georgia, serif; font-weight: 600;
  letter-spacing: -0.01em; }
h1 { font-size: 1.85rem; margin: 1.2rem 0 0.8rem; }
h2 { font-size: 1.3rem; margin: 2.5rem 0 0.6rem; padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--line); }
h1 + p, h2 + p { margin-top: 0.4rem; }

.muted { color: var(--muted); }
/* Retained so secondary copy can be marked without shrinking it: body text is
   one size. Genuine chrome uses .chrome / --text-chrome instead. */
.small { font-size: inherit; }
.chrome { font-size: var(--text-chrome); }
table { width: 100%; border-collapse: collapse; margin: 0.6rem 0; }
th, td { text-align: left; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--line);
  vertical-align: top; }
/* A date is one token: wrapping it across two lines makes a table unreadable. */
.col-date { white-space: nowrap; }
.tally { display: inline-block; white-space: nowrap; }
th { font-size: var(--text-chrome); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
/* On a phone the cell gutters are the difference between a table that fits and
   one that has to scroll inside its .scroll-x wrapper. */
@media (max-width: 30rem) { th, td { padding: 0.4rem 0.3rem; } }
.searchbox { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1rem 0; }
.searchbox input[type=search] { flex: 1 1 12rem; min-width: 0;
  padding: 0.6rem 0.85rem; font-size: var(--text);
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--bg); color: var(--ink); }
.searchbox button { padding: 0.6rem 1.2rem; border: 0; border-radius: 4px;
  background: var(--accent); color: #fff; font-size: var(--text); cursor: pointer; }
.hit { padding: 0.8rem 0; border-bottom: 1px solid var(--line); }
.hit blockquote { margin: 0.4rem 0 0; padding-left: 0.9rem; border-left: 3px solid var(--accent-soft); }
.vote-ta { color: var(--ta); font-weight: 600; }
.vote-nil { color: var(--nil); font-weight: 600; }
.vote-staon { color: var(--staon); font-weight: 600; }
.badge { display: inline-block; background: var(--accent-soft); color: var(--accent);
  border-radius: 3px; padding: 0.05rem 0.5rem; font-size: var(--text-chrome); }
.avatar { display: inline-flex; align-items: center; justify-content: center;
  width: 3.2rem; height: 3.2rem; border-radius: 50%; background: var(--accent-soft);
  color: var(--accent); font-weight: 700; font-size: 1.15rem; }
/* Official portrait (D-050). Sized to the source's own aspect; the record
   does not need a crop, and cropping a person's face is an editorial act. */
.avatar-photo { width: 4.8rem; height: auto; border-radius: 3px;
  border: 1px solid var(--line); background: var(--accent-soft); }
.portrait-credit { margin: 0.15rem 0 0; }
/* Index thumbnails: small, lazy-loaded, and the same footprint whether the
   member has a cleared portrait or the initials mark, so rows do not jump. */
.avatar-thumb { width: 34px; height: 40px; object-fit: cover; border-radius: 2px;
  border: 1px solid var(--line); display: block; }
.avatar-thumb-blank { width: 34px; height: 40px; border-radius: 2px;
  font-size: 0.8rem; }
.portrait-cell { width: 34px; padding-right: 0.2rem; }
.member-head { display: flex; gap: 1rem; align-items: center; }
.tabs a { display: inline-block; padding: 0.4rem 0.9rem; margin-right: 0.4rem;
  border: 1px solid var(--line); border-bottom: 0; border-radius: 4px 4px 0 0;
  text-decoration: none; color: var(--muted); }
.tabs a.active { color: var(--accent); font-weight: 600; border-color: var(--accent); }
.timeline li { margin-bottom: 0.25rem; }
.provenance { font-size: var(--text-chrome); color: var(--muted); margin-top: 0.3rem; }
/* A SHA-256 is 64 unbreakable characters — wider than a phone. Wrap it
   instead of letting it scroll the whole page sideways. */
code { overflow-wrap: anywhere; }
.pager { margin: 1.2rem 0; display: flex; gap: 1rem; align-items: baseline; }
.notice { background: var(--accent-soft); border-radius: 4px; padding: 0.7rem 1rem; }

/* Filters (data review 1.3 / 1.7 / 1.9) */
.filterbar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center;
  margin: 0.8rem 0; }
.filterbar label { display: flex; align-items: center; gap: 0.35rem; color: var(--muted); }
.filterbar input, .filterbar select { padding: 0.4rem 0.55rem; font-size: var(--text);
  border: 1px solid var(--line); border-radius: 4px; background: var(--bg); color: var(--ink);
  /* A <select> is as wide as its longest option unless told otherwise, and the
     party/constituency lists are long enough to overflow a phone. */
  max-width: 100%; min-width: 0; }
.filterbar input[type=search] { flex: 1 1 11rem; }
.filterbar button { padding: 0.45rem 1rem; border: 0; border-radius: 4px;
  background: var(--accent); color: #fff; font-size: var(--text); cursor: pointer; }

/* Charts (D-038): attribute-based SVG only — CSP forbids inline styles.
   Every chart is paired with a text/table equivalent (report 3.7). */
.votebar { display: block; width: 100%; max-width: 16rem; height: 0.55rem;
  border-radius: 2px; background: var(--accent-soft); }
.votebar-lg { max-width: 100%; height: 0.9rem; margin: 0.4rem 0 0.8rem; }
.seg-ta { fill: var(--ta); } .seg-nil { fill: var(--nil); } .seg-staon { fill: var(--staon); }
/* "No vote recorded" share (D-040/B2): a sized, neutral category — labelled
   exactly as the page labels it, never "absent". */
.seg-none { fill: var(--none); }
.seg-oral { fill: var(--staon); } .seg-written { fill: var(--lang-en); }
.act-bar { fill: var(--accent); }  /* in-table horizontal count bars */
.swatch { width: 0.7rem; height: 0.7rem; border-radius: 2px; flex: none; }
/* Non-text contrast (D-040/A5): fills alone fall below WCAG 1.4.11 for several
   party colours; a neutral stroke keeps swatches/map regions legible. */
.swatch rect { stroke: var(--stroke-neutral); stroke-width: 1; }
.party-group h3 { font-size: var(--text); margin: 0.9rem 0 0.15rem;
  display: flex; align-items: center; gap: 0.45rem; }
.party-group .member-list { margin: 0 0 0.3rem; line-height: 1.8; }

/* Member status header + neutral count chips (data review 1.4) */
.status-line { margin: 0.15rem 0 0.4rem; }
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.6rem 0 0.2rem;
  padding: 0; list-style: none; }
.chips li { background: var(--accent-soft); color: var(--accent); border-radius: 3px;
  padding: 0.2rem 0.65rem; }

/* Column bar charts with hover values (D-042): one flex column per month,
   the month's value revealed by a CSS :hover rule — no JS, no inline styles. */
.colbars { display: flex; align-items: stretch; height: 9rem; margin: 0.6rem 0;
  background: var(--surface); border: 1px solid var(--line); border-radius: 4px;
  padding: 0 2px; }
.colbar { flex: 1; position: relative; min-width: 0; }
.colbar svg { display: block; width: 100%; height: 100%; }
.colbar rect:not([fill]) { fill: var(--accent); }
.colbar rect[fill] { stroke: var(--stroke-neutral); stroke-width: 0.5; }
.colbar:hover rect { opacity: 0.75; }
.colbar-val { display: none; position: absolute; top: 0.15rem; left: 50%;
  font-size: var(--text-chrome);
  transform: translateX(-50%); white-space: nowrap; z-index: 3;
  background: var(--bg); border: 1px solid var(--line); border-radius: 3px;
  padding: 0 0.35rem; color: var(--ink); }
.colbar:hover .colbar-val { display: block; }
.colbar:first-child .colbar-val { left: 0; transform: none; }
.colbar:last-child .colbar-val { left: auto; right: 0; transform: none; }
.colbars-sm { height: 3.2rem; border-radius: 3px; }
.axis-labels { display: flex; justify-content: space-between;
  font-size: var(--text-chrome); color: var(--muted); }
.legend { list-style: none; padding: 0; margin: 0.5rem 0;
  display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; }
.legend li { display: flex; align-items: center; gap: 0.4rem; white-space: nowrap; }
details.data-table { margin: 0.6rem 0 1.2rem; }
details.data-table summary { cursor: pointer; color: var(--accent); }
.scroll-x { overflow-x: auto; }

/* Constituency map (data review 2.4): seats per constituency, nothing else. */
.map-details { margin: 0.8rem 0 1.2rem; }
.map-details summary { cursor: pointer; color: var(--accent); }
.map-wrap { display: flex; gap: 2rem; align-items: center; flex-wrap: wrap;
  justify-content: center; margin-top: 0.6rem; }
.map-svg { width: min(30rem, 100%); height: auto; flex: none; }
.map-svg path { stroke: var(--stroke-neutral); stroke-width: 0.6; }
.map-svg a:hover path, .map-svg a:focus path { fill: var(--accent); }
.map-svg path.map-active { stroke: var(--ink); stroke-width: 2; }
.seats-3 { fill: #bcd2cc; }
.seats-4 { fill: #7fa89f; }
.seats-5 { fill: #3d6b60; }
.legend-col { flex-direction: column; gap: 0.25rem; }

/* Hemicycle (D-040/B1): current composition in chamber-arc geometry — party
   identity and seat counts only, the same facts as the composition table. */
.hemi-svg { display: block; width: 100%; max-width: 34rem; height: auto;
  margin: 0.8rem auto; }
.hemi-svg circle { stroke: var(--bg); stroke-width: 0.8; }
.hemi-svg a:hover circle, .hemi-svg a:focus circle {
  stroke: var(--ink); stroke-width: 1.6; }

/* Sitting-day calendar heatmap (D-040/B3): institutional volume per day. */
.hm-svg { display: block; width: 100%; height: auto; margin: 0.6rem 0; }
.hm-0 { fill: var(--hm-0); } .hm-1 { fill: var(--hm-1); } .hm-2 { fill: var(--hm-2); }
.hm-3 { fill: var(--hm-3); } .hm-4 { fill: var(--hm-4); }
.hm-svg text { font-size: 11px; fill: var(--muted); }

/* Bill stage stepper (D-040/B4): fixed official sequence, current highlighted. */
.stepper { display: flex; flex-wrap: wrap; gap: 0.3rem 0; list-style: none;
  padding: 0; margin: 0.8rem 0; }
.stepper li { display: flex; align-items: center; color: var(--muted); }
.stepper li::after { content: "→"; margin: 0 0.5rem; color: var(--line); }
.stepper li:last-child::after { content: ""; margin: 0; }
.stepper .step-done { color: var(--accent); }
.stepper .step-current { color: var(--accent); font-weight: 700;
  border-bottom: 2px solid var(--accent); }

/* Ranked terms (D-040 novel formats): aggregate frequency bars. */
.term-row { display: flex; align-items: center; gap: 0.6rem; margin: 0.25rem 0; }
.term-label { width: min(14.5rem, 45%); flex: none; text-align: right; font-size: var(--text);
  overflow-wrap: break-word; }
.term-svg { flex: 1; height: 0.8rem; }
.term-svg rect { fill: var(--accent); }
.term-count { width: 3.5rem; flex: none; font-size: var(--text-chrome); color: var(--muted); }

/* Recorded activity by party (D-041): same-scale small multiples — one
   panel per party, alphabetical, seat count co-displayed. Never overlaid. */
.pp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.9rem 1.2rem; margin: 0.8rem 0; }
/* Name on one line, seat count on the next. Side by side in a 13rem column
   the two fought for width and both wrapped, which left every panel a
   different height (D-056). The count stays a separate fact either way. */
.pp-head { display: block; }
.pp-head .seats { display: block; color: var(--muted);
  font-size: var(--text-chrome); white-space: nowrap; }

/* Distinctive-terms panels (D-042): one column per window length. */
.term-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(23rem, 1fr));
  gap: 0.8rem 2rem; margin: 0.8rem 0; }
.term-grid h3 { margin: 0.9rem 0 0.4rem; }

/* On this day (D-040 novel formats): the record replayed for today's date. */
.onthisday { border: 1px solid var(--line); border-radius: 4px;
  padding: 0.8rem 1rem; margin: 1.5rem 0; background: var(--surface); }
.onthisday h2 { margin-top: 0; border-bottom: 0; padding-bottom: 0; }

/* Home search panel (D-054). The landing page's job is to invite a search,
   so the field gets real size and the archive states its own scale. Sober
   still: one ground, one rule, no gradient and no hero imagery. */
.search-panel {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 4px solid var(--accent); border-radius: 5px;
  padding: 1.4rem 1.5rem 1.5rem; margin: 1.2rem 0 1.5rem;
}
.search-panel h1 { margin: 0 0 0.35rem; }
.search-panel .lede { margin: 0 0 1rem; max-width: 58rem; color: var(--muted); }
.search-panel .searchbox { margin: 0 0 0.9rem; }
.search-panel input[type=search] { padding: 0.7rem 0.95rem; font-size: 1.15rem; }
.search-panel button { padding: 0.7rem 1.5rem; font-size: 1.05rem; font-weight: 600; }
/* Suggested searches: plain prefilled links, no JS. */
.examples { display: flex; flex-wrap: wrap; gap: 0.4rem 0.5rem; align-items: baseline;
  margin: 0; padding: 0; list-style: none; }
.examples .examples-label { color: var(--muted); }
.examples a { display: inline-block; background: var(--bg); color: var(--accent);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0.15rem 0.7rem; text-decoration: none; }
.examples a:hover, .examples a:focus { border-color: var(--accent);
  background: var(--accent-soft); }
.scale { margin: 1rem 0 0; color: var(--muted); }

/* Is the Dáil sitting (D-054). States only what the published schedule and
   the archive assert; never infers a recess end date. */
.sitting { border: 1px solid var(--line); border-left: 4px solid var(--stroke-neutral);
  border-radius: 5px; padding: 0.7rem 1rem; margin: 0 0 1.5rem; max-width: 58rem; }
.sitting-on { border-left-color: var(--accent); }
.sitting strong { color: var(--ink); }
.sitting .detail { color: var(--muted); }

/* Grouped search filters: a native disclosure, so the controls stop
   competing with the search field they refine. */
.filters { margin: 0 0 1.2rem; }
.filters > summary { cursor: pointer; color: var(--accent); }
.filters .filterbar { margin-top: 0.5rem; padding: 0.8rem 1rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 5px; }

/* Print (D-040/A4): pages are citable reference documents. */
@media print {
  .site-header nav, .searchbox, .filterbar, .pager, .skip-link, .theme,
  .examples, .filters { display: none; }
  .search-panel, .sitting { border: 0; background: none; padding: 0; }
  .wrap { max-width: none; padding: 0; }
  .site-header { border-bottom-color: #000; }
  body { font-size: 11pt; color: #000; background: #fff; }
  a { color: #000; text-decoration: none; }
  .provenance { display: block; }
  .colbars { border: 0; background: none; }
}
