/* =========================================================================
   COMPONENTS
   The class names here are the contract between markup and design. A reskin
   changes tokens.css and, if it wants, the rules in this file — but keeping
   these class names means the templates need not change. See docs/DESIGN.md.
   ========================================================================= */

/* ---- banner and footer -------------------------------------------------- */

.banner {
  background: var(--surface-raised);
  border-bottom: var(--border-width) solid var(--border);
}
.banner-inner {
  max-width: var(--measure-narrow);
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  /* A long association name in German on a 360px phone must not push the
     language switch off the screen; the switch drops to its own line
     instead. The name block is the only bare div in here -- the switch is a
     <nav> or a <form>. */
  flex-wrap: wrap;
}
.banner-inner > div {
  flex: 1 1 12rem;
  min-width: 0;
}
.banner-inner > .lang-switch {
  flex: 0 0 auto;
}
.banner-inner--wide {
  max-width: var(--measure-wide);
}
/* The mark alone in the banner. The pack sets 140px as the floor for the
   horizontal lockup and says to use the mark below that; a header bar is
   below that. */
/* The pack's own horizontal lockup -- mark and wordmark drawn together, and
   drawn to sit together. Setting the name as text beside the mark was
   rebuilding it badly. 140px is the pack's stated floor for this lockup, so
   that is the size: any smaller and the rule says to use the mark alone. */
.banner-lockup {
  display: inline-block;
  line-height: 0;
}
.banner-lockup img {
  width: 8.75rem; /* 140px */
  height: auto;
}
.banner-mark {
  margin: 0;
  font-weight: var(--weight-semibold);
  font-size: var(--text-base);
  letter-spacing: var(--tracking-heading);
  color: var(--accent);
}
.banner-sub {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.page-footer {
  max-width: var(--measure-narrow);
  margin: 0 auto;
  padding: var(--space-5) var(--space-4) var(--space-7);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}
.page-footer--wide {
  max-width: var(--measure-wide);
}
.page-footer a {
  color: inherit;
  margin-right: var(--space-3);
}

/* The product mark sits in the footer, never the banner: the banner belongs
   to the association running the election. Clear space is a quarter of the
   mark width, per the brand pack, and the horizontal lockup is held at its
   140px minimum. */
.page-footer__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--border-width) solid var(--border);
}
.page-footer__brand picture,
.page-footer__brand img {
  display: block;
}
/* The pack's minimum for the horizontal lockup is 140px; below that it asks
   for the mark alone, so this never shrinks. */
.page-footer__brand img {
  width: 140px;
  height: auto;
}
.page-footer__tagline {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

/* ---- language switch ----------------------------------------------------
   A segmented control. Rendered as links on ordinary pages and as submit
   buttons where a form's state must survive the switch; both get this
   styling, so the control looks and behaves identically either way. */

.lang-switch {
  display: inline-flex;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--surface-page);
}
.lang-switch__option {
  appearance: none;
  border: 0;
  margin: 0;
  padding: var(--space-2) var(--space-3);
  min-height: var(--target-min);
  display: inline-flex;
  align-items: center;
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  cursor: pointer;
}
.lang-switch__option + .lang-switch__option {
  border-left: var(--border-width) solid var(--border);
}
.lang-switch__option {
  transition: var(--motion-hover);
}
.lang-switch__option:hover {
  background: var(--select-ground);
  color: var(--select-ink);
}
/* Current language is marked by weight and ground, not by colour alone, and
   carries aria-current for anyone not seeing either. */
.lang-switch__option[aria-current='true'] {
  background: var(--accent);
  color: var(--text-on-accent);
  font-weight: var(--weight-bold);
}

/* ---- card --------------------------------------------------------------- */

.card {
  background: var(--surface-raised);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-sm);
}
/* A feature panel: the one place the larger brand radius is used. */
.card--feature {
  border-radius: var(--radius-xl);
  padding: var(--space-6);
}
/* The single navy panel a screen is allowed. */
.card--inverse {
  background: var(--surface-inverse);
  border-color: var(--surface-inverse);
  color: var(--text-inverse);
}
.card--inverse .card__title,
.card--inverse h1,
.card--inverse h2,
.card--inverse h3 {
  color: var(--text-inverse);
}
.card--inverse .quiet {
  color: var(--navy-200);
}
.card + .card {
  margin-top: var(--space-4);
}
/* ...but not when the cards are grid items: the gap already spaces them, and
   a top margin on every card after the first drops each one below its
   neighbour and ruins the row. */
.grid-2 > .card + .card,
.feature-grid > .card + .card {
  margin-top: 0;
}
.card__title {
  margin-top: 0;
}

/* ---- buttons ------------------------------------------------------------ */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--target-min);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-md);
  border: var(--border-width) solid transparent;
  font: inherit;
  font-weight: var(--weight-semibold);
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  transition: var(--motion-hover),
    transform var(--duration-instant) var(--ease-standard);
}
/* Press is physical: the button depresses and loses its shadow. Nothing in
   this system scales or fades. */
.button:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: none;
}
.button:disabled,
.button[aria-disabled='true'] {
  background: var(--surface-sunken);
  color: var(--text-secondary);
  border-color: var(--border);
  box-shadow: none;
  cursor: not-allowed;
}

.button--primary {
  background: var(--accent);
  color: var(--text-on-accent);
  border-color: var(--accent);
  box-shadow: var(--shadow-sm);
}
.button--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}
.button--secondary {
  background: var(--surface-raised);
  color: var(--text-primary);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-xs);
}
.button--secondary:hover {
  background: var(--surface-page);
  border-color: var(--text-secondary);
}
.button--quiet {
  background: transparent;
  color: var(--select-ink);
  border-color: transparent;
  font-weight: var(--weight-medium);
}
.button--quiet:hover {
  background: var(--select-ground);
}
.button--block {
  width: 100%;
}
.button--large {
  font-size: var(--text-lg);
  padding: var(--space-4) var(--space-6);
}

/* ---- forms -------------------------------------------------------------- */

.field {
  margin-bottom: var(--space-4);
}
.field__label {
  display: block;
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-1);
}
.field__hint {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-2);
}

.input,
.textarea,
.select {
  width: 100%;
  padding: var(--space-3);
  min-height: var(--target-min);
  font: inherit;
  color: var(--text-primary);
  background: var(--surface-raised);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  transition: var(--motion-hover);
}
.input:hover,
.textarea:hover,
.select:hover {
  border-color: var(--accent);
}
.textarea {
  min-height: 12rem;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

.input--code {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  letter-spacing: 0.12em;
  text-align: center;
}

.fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-4);
}
.fieldset__legend {
  padding: 0;
  margin-bottom: var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-heading);
}

/* ---- candidate options -------------------------------------------------- */

.options {
  list-style: none;
  margin: 0;
  padding: 0;
}
.options > li + li {
  margin-top: var(--space-2);
}

.option {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  /* The brand pack asks for 64px on a ballot option — comfortably above the
     44px floor, because this is the one control everybody has to hit. */
  min-height: var(--target-option);
  padding: var(--space-4);
  /* The border width never changes between states: only its colour does, so
     selecting an option cannot shift the row below it. */
  border: var(--border-width-strong) solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  transition: var(--motion-hover);
}
.option:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-sm);
}
/* Selection is teal, per the brand pack — a chosen candidate must not look
   like a button. It is signalled by ground, border colour and the checkbox
   itself, never by colour alone. */
.option:has(input:checked) {
  border-color: var(--select);
  background: var(--select-ground);
  box-shadow: none;
}
.option__control {
  width: 1.4rem;
  height: 1.4rem;
  margin: 0.1rem 0 0;
  flex: none;
  accent-color: var(--select);
}
.option__body {
  display: flex;
  flex-direction: column;
}
.option__name {
  font-weight: var(--weight-semibold);
}
.option__detail {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  margin-top: var(--space-1);
}

/* ---- callouts ----------------------------------------------------------- */

/* A full hairline on a tinted ground. The brand pack rules out the
   coloured-left-border card, so the tone is carried all the way round and
   repeated in the title colour. */
.callout {
  border: var(--border-width) solid var(--info-line);
  background: var(--info-ground);
  color: var(--text-primary);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  margin: var(--space-4) 0;
}
.callout--warn {
  border-color: var(--warn-line);
  background: var(--warn-ground);
}
.callout--danger {
  border-color: var(--danger-line);
  background: var(--danger-ground);
}
.callout--ok {
  border-color: var(--ok-line);
  background: var(--ok-ground);
}
.callout__title {
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-1);
  color: var(--info);
}
.callout--warn .callout__title {
  color: var(--warn);
}
.callout--danger .callout__title {
  color: var(--danger);
}
.callout--ok .callout__title {
  color: var(--ok);
}

/* ---- receipt ------------------------------------------------------------ */

.receipt {
  background: var(--surface-sunken);
  border: var(--border-width-strong) dashed var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin: var(--space-4) 0;
  text-align: center;
}
.receipt__label {
  margin: 0 0 var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.receipt__code {
  margin: 0;
  font-family: var(--font-mono);
  /* Sized to fit a narrow phone rather than fixed, because this is the one
     string on the site a voter copies down by hand. */
  font-size: clamp(1rem, 5.4vw, var(--text-xl));
  font-weight: var(--weight-bold);
  letter-spacing: 0.06em;
  /* break-all used to drop a single character of the last group onto its own
     line, which is exactly how a reference gets written down wrong. If it has
     to wrap at all, it wraps after a hyphen, between whole groups. */
  word-break: normal;
  overflow-wrap: normal;
}

/* ---- status pill -------------------------------------------------------- */

.pill {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  border: var(--border-width) solid currentColor;
  white-space: nowrap;
}
/* In a table on a phone there is no room for "Tied for the last seat" on one
   line: the wrapper scrolls, but a member reading the published result should
   not have to discover that. Let the pill wrap instead. */
@media (max-width: 30rem) {
  .table .pill {
    white-space: normal;
  }
}
.pill--ok {
  color: var(--ok);
  background: var(--ok-ground);
}
.pill--warn {
  color: var(--warn);
  background: var(--warn-ground);
}
.pill--danger {
  color: var(--danger);
  background: var(--danger-ground);
}
.pill--info {
  color: var(--info);
  background: var(--info-ground);
}
.pill--quiet {
  color: var(--text-secondary);
  background: var(--surface-sunken);
}

/* ---- tables ------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  margin: var(--space-4) 0;
}
.table {
  width: 100%;
  border-collapse: collapse;
}
.table th,
.table td {
  text-align: left;
  padding: var(--space-3);
  border-bottom: var(--border-width) solid var(--border);
}
.table thead th {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-secondary);
}
.table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.table tbody tr:last-child td {
  border-bottom: 0;
}

/* ---- statistics --------------------------------------------------------- */

.stats {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  margin: var(--space-4) 0;
}
.stat {
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}
.stat__value {
  font-size: var(--text-2xl);
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-heading);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-tight);
}
.stat__label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin-top: var(--space-1);
}
.stat--accent .stat__value {
  color: var(--select-ink);
}

/* Turnout meter. Aggregate only — there is no per-voter equivalent. */
.meter {
  height: 0.75rem;
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin: var(--space-2) 0;
}
.meter__fill {
  height: 100%;
  background: var(--select);
  border-radius: var(--radius-pill);
  transition: width var(--duration-slow) var(--ease-out);
}

/* Turnout over time: a plain bar chart in inline SVG, no library. */
.chart {
  width: 100%;
  height: auto;
  overflow: visible;
}
.chart__bar {
  fill: var(--select);
}
.chart__axis {
  stroke: var(--border);
  stroke-width: 1;
}
.chart__label {
  fill: var(--text-secondary);
  font-size: 10px;
  font-family: var(--font-sans);
}

/* ---- administration ----------------------------------------------------- */

.admin-nav {
  background: var(--surface-inverse);
}
.admin-nav__inner {
  max-width: var(--measure-wide);
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
}
.admin-nav a {
  color: var(--text-inverse);
  text-decoration: none;
  font-weight: var(--weight-medium);
  font-size: var(--text-sm);
}
.admin-nav a:hover {
  text-decoration: underline;
}
.admin-nav__spacer {
  margin-left: auto;
}

.steps {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.step {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  background: var(--surface-raised);
}
.step--done {
  border-color: var(--ok);
  color: var(--ok);
  background: var(--ok-ground);
}
.step--current {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--text-on-accent);
  font-weight: var(--weight-semibold);
}

/* A vertical, numbered sequence rather than the wizard's horizontal pills.
   Used on the landing page, where the four steps are a narrative rather than
   a progress indicator. */
.steps--numbered {
  display: block;
  counter-reset: step;
  margin-bottom: 0;
}
.steps--numbered .step {
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text-primary);
  font-size: var(--text-base);
}
.steps--numbered .step::before {
  counter-increment: step;
  content: counter(step);
  flex: 0 0 auto;
  min-width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--accent-quiet);
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

.step__index {
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}

/* Per-language content inputs, side by side where there is room. */
.lang-fields {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.lang-fields__item {
  min-width: 0;
}
.lang-fields__tag {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-secondary);
  margin-bottom: var(--space-1);
}

/* ---- layout utilities ---------------------------------------------------
   Small, named adjustments that would otherwise be written as style="…" in a
   template. They are here because the Content-Security-Policy sets
   style-src 'self' with no 'unsafe-inline': an inline style attribute is not
   applied by the browser at all, so a layout written that way silently did
   not happen (review finding 10). Anything visual belongs in this file. */

.u-flush        { margin: 0; }
.u-flush-top    { margin-top: 0; }
.u-space-above  { margin-top: var(--space-3); }
.u-space-above-4 { margin-top: var(--space-4); }
.u-space-above-5 { margin-top: var(--space-5); }
.u-space-below  { margin-bottom: var(--space-3); }
.u-inline       { display: inline; }
.u-ok           { color: var(--ok); }

.row--split     { justify-content: space-between; }

/* A form people fill in once and carefully -- signup, sign-in, setup. Wider
   than .card--narrow, because those forms carry hint text under every label
   and 26rem wraps each hint onto three lines. */
/* A text input a thousand pixels wide is harder to read back than a short
   one, and looks unconsidered. Fields inside an admin form are held to a
   readable measure; a grid of two still splits the row. */
.card .field > .input,
.card .field > .textarea,
.card .field > .select {
  max-width: var(--measure-narrow);
}
.grid-2 .field > .input,
.grid-2 .field > .textarea,
.grid-2 .field > .select,
.field--wide > .input,
.field--wide > .textarea {
  max-width: none;
}

.card--form {
  max-width: 34rem;
  margin-inline: auto;
}

/* A note that is information rather than a warning. */
.callout--info {
  border-color: var(--info-line);
  background: var(--info-ground);
}
.callout--info .callout__title {
  color: var(--info);
}

.card--narrow {
  max-width: 26rem;
  margin-inline: auto;
}

.input--reason  { width: 10rem; }
.select--approval { width: 12rem; }
.select--wide   { max-width: 22rem; }

/* ---- turnout meter ------------------------------------------------------
   Drawn as an SVG rather than a div whose width is set inline, for the same
   reason: the width is data and cannot travel in a style attribute. An SVG
   presentation attribute is markup, not CSS, so it survives the policy. */

.meter-svg {
  display: block;
  width: 100%;
  height: 0.75rem;
  /* Its own space. At 100% the bar fills the full width and, sitting flush
     against the paragraph under it, read as a horizontal rule rather than a
     turnout figure. */
  margin: var(--space-4) 0 var(--space-3);
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--surface-sunken);
}
.meter-svg__track { fill: var(--surface-sunken); }
.meter-svg__fill  { fill: var(--select); }

/* ---- launch preview and logo ------------------------------------------- */

.preview {
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  white-space: pre-wrap;
  overflow-x: auto;
  font-size: var(--text-sm);
  line-height: 1.6;
}
.logo-preview { max-height: 4rem; width: auto; }
.banner-logo { max-height: 2.5rem; width: auto; display: block; }

/* ---- landing --------------------------------------------------------------
   The public front door. Everything here is a modifier on components that
   already exist -- the hero is the one navy panel a screen is allowed
   (.card--inverse) at the brand's large radius (.card--feature), and the
   display size is the type scale's top step rather than a new one. A visitor
   deciding whether to trust this should meet the brand, not an admin table. */

/* No mark in the hero: the footer already carries the lockup, and a large
   abstract shape beside the headline was decoration standing in for a
   picture of nothing. The panel itself is the brand statement. */
.hero__title,
.hero__lead {
  max-width: 34rem;
}
.hero__title {
  font-size: var(--text-3xl);
  line-height: 1.1;
  letter-spacing: var(--tracking-heading-tight);
  margin: 0 0 var(--space-3);
  /* Let the browser even out the lines rather than breaking after "a". */
  text-wrap: balance;
}
.hero__lead {
  font-size: var(--text-lg);
  line-height: 1.5;
  margin: 0 0 var(--space-5);
}
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin: 0;
}
/* On a phone the two actions stack, and two different widths read as a
   mistake rather than a hierarchy. */
@media (max-width: 30rem) {
  .hero__actions { display: grid; }
  .hero__actions .button { width: 100%; }
}
/* Reversed on the navy panel, so the primary action does not disappear. */
.card--inverse .button--primary {
  background: var(--surface-raised);
  color: var(--accent);
  border-color: var(--surface-raised);
}
.card--inverse .button--secondary {
  color: var(--text-inverse);
  border-color: var(--navy-200);
  background: transparent;
}

/* One rhythm for the whole page.
   Spacing used to come from `.card + .card`, which only ever spaces two cards
   that are siblings -- so a grid, a heading or a callout following a card
   touched it. Owning the gap here means every block on the page is spaced the
   same way, whatever it happens to be. */
/* Twice the gap inside a group. 24 against 16 was too close to read as
   deliberate -- it just looked like the boxes were randomly stuck together. */
.landing > * + * {
  margin-top: var(--space-6);
}
/* A heading belongs to what follows it, not to what came before. */
.landing > .section-title + * {
  margin-top: var(--space-3);
}
.landing > .section-title {
  margin-top: var(--space-6);
}

/* The two explanatory blocks, inside ONE card. Two cards side by side are
   never the same height, which leaves a hole under the shorter one. */
.landing-band {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}
@media (min-width: 56rem) {
  .landing-band {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
  }
}
.landing-band .card__title {
  margin-bottom: var(--space-3);
}

/* Two up, then three on a wide screen -- and never four, which is what
   .grid-2 does at this width and why these do not use it. A feature is a
   short paragraph and needs a readable measure, not a column of six words. */
.feature-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
  .feature-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 64rem) {
  .feature-grid { grid-template-columns: repeat(3, 1fr); }
}

/* A section heading above a group of cards, rather than inside one. */
.section-title {
  font-size: var(--text-xl);
  margin: 0;
}
/* A feature: its mark, then its claim, then the sentence.
   The rule down the side went because it was doing an icon's job badly. */
.feature__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-bottom: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--accent-quiet);
  color: var(--accent);
}
.feature__icon .icon {
  width: 1.5rem;
  height: 1.5rem;
}
.feature__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-base);
  line-height: 1.3;
}

/* The step marker: solid, not a tint, so a sequence reads as a sequence. */
.steps--numbered .step::before {
  background: var(--accent);
  color: var(--text-on-accent);
}

/* ---- print --------------------------------------------------------------
   Officers print the results page. base.css carries the rest of the print
   rules, but the card chrome has to be neutralised here: components.css loads
   after base.css, and at equal specificity the later rule wins, so a print
   block in base.css cannot switch off a border declared in this file. */
@media print {
  .card,
  .stat,
  .receipt,
  .callout {
    border: 0;
    box-shadow: none;
    background: #fff;
    padding-left: 0;
    padding-right: 0;
  }
  .card + .card {
    margin-top: var(--space-5);
  }
  .pill {
    border-color: #000;
    color: #000;
    background: #fff;
  }
  .table th,
  .table td {
    border-bottom-color: #999;
  }
}

/* ---- the separation diagram ---------------------------------------------
   Two stores side by side with nothing between them. The point being made is
   an absence, so it is drawn as one: a gap, a broken link, and a caption. It
   is HTML rather than a picture because it has to translate, reflow onto a
   phone and follow the viewer's theme. */

.split-store {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--space-4);
  align-items: stretch;
  margin: var(--space-5) 0;
}
/* Stacked on a phone, with the broken link between the two panels rather than
   beside them, so the reading order still carries the argument. */
@media (max-width: 46rem) {
  .split-store {
    grid-template-columns: 1fr;
  }
}

.store {
  border: var(--border-width-strong) solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  background: var(--surface-page);
}
.store--identity {
  border-color: var(--accent);
}
.store--ballots {
  border-color: var(--select);
}
.store__title {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.store--identity .store__title {
  color: var(--accent);
}
.store--ballots .store__title {
  color: var(--select-ink);
}
.store__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.store__list li {
  padding: var(--space-2) 0;
  border-top: var(--border-width) solid var(--border);
  font-size: var(--text-sm);
}
.store__list li:first-child {
  border-top: 0;
}
/* The row that names what is *not* in the table. Struck through, so the eye
   catches the absence before the sentence explains it. */
.store__absent {
  color: var(--text-secondary);
  text-decoration: line-through;
}
.store__foot {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.no-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
  color: var(--warn);
  text-align: center;
}
.no-link__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-pill);
  background: var(--warn-ground);
}
.no-link__glyph .icon {
  width: 1.75rem;
  height: 1.75rem;
}
.no-link__label {
  max-width: 9rem;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
}
@media (max-width: 46rem) {
  .no-link {
    flex-direction: row;
    gap: var(--space-3);
    text-align: left;
  }
  .no-link__label {
    max-width: none;
  }
}

/* An icon in a table's first column: sized to the row, not to a feature card. */
.cell-icon {
  width: 2.25rem;
  color: var(--accent);
}
.cell-icon .icon {
  width: 1.25rem;
  height: 1.25rem;
  display: block;
}
.feature__icon--inline {
  width: 1.75rem;
  height: 1.75rem;
  margin: 0 var(--space-2) 0 0;
  vertical-align: -0.35em;
}
.feature__icon--inline .icon {
  width: 1rem;
  height: 1rem;
}

/* A list of things this service does not do. Marked with a rule rather than a
   bullet: these are commitments, not features. */
.ticks {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}
.ticks li {
  position: relative;
  padding: var(--space-2) 0 var(--space-2) var(--space-6);
  border-top: var(--border-width) solid var(--border);
}
.ticks li:first-child {
  border-top: 0;
}
.ticks li::before {
  content: '';
  position: absolute;
  left: var(--space-2);
  top: 1.05em;
  width: 0.85rem;
  height: 0.45rem;
  border-left: 2px solid var(--select);
  border-bottom: 2px solid var(--select);
  transform: rotate(-45deg);
}

/* ---- question and answer ------------------------------------------------
   <details> rather than scripted accordions: it works with JavaScript off,
   the browser handles the keyboard, and each answer keeps its own anchor. */

.qa {
  border-top: var(--border-width) solid var(--border);
}
.qa:first-of-type {
  border-top: 0;
}
.qa__q {
  padding: var(--space-4) var(--space-2) var(--space-4) 0;
  font-weight: var(--weight-semibold);
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-height: var(--target-min);
}
.qa__q::-webkit-details-marker {
  display: none;
}
/* Our own marker, so it can be a token colour and rotate on open. */
.qa__q::before {
  content: '';
  flex: 0 0 auto;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--select);
  border-bottom: 2px solid var(--select);
  transform: rotate(-45deg);
  transition: transform var(--duration-instant) var(--ease-standard);
}
.qa[open] > .qa__q::before {
  transform: rotate(45deg);
}
.qa__q:hover {
  color: var(--select-ink);
}
.qa__a {
  padding: 0 0 var(--space-4) var(--space-5);
  color: var(--text-secondary);
  max-width: var(--measure-text, 42rem);
}

/* The one word a club puts in its minutes. Sized as a verdict, not as a
   heading: somebody scanning the page for "was it carried" should not have to
   read a sentence to find out. */
.verdict {
  margin: var(--space-3) 0;
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
}
.verdict--carried {
  color: var(--ok);
}
.verdict--not-carried {
  color: var(--text-secondary);
}

/* The election-or-motion chooser: the same option rows the ballot uses, as
   links rather than radios, because the choice loads a different form. */
.option--choice {
  text-decoration: none;
  color: inherit;
  display: block;
}
.option--chosen {
  border-color: var(--select);
  background: var(--select-ground);
}

/* A hash somebody is going to compare character by character against their own
   `shasum` output. Wraps rather than scrolls, because a hash cut off at the
   card edge cannot be compared at all. */
.verify-hash {
  font-size: var(--text-sm);
  word-break: break-all;
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
}

/* A filename in a table cell. "ballots.json" broken across two lines as
   "ballots.j / son" is not a filename anybody can copy. */
.table .mono {
  white-space: nowrap;
}
