/* Sector Info Engine — a daily press digest for the PPA.
 *
 * The design brief lives in .impeccable.md at the project root. The short
 * version: this is a press-cutting service for people who make magazines, so
 * it is set like one. Warm paper rather than clinical white, hairline rules
 * rather than cards, and the relevance score printed as a numeral in the
 * margin the way a digest numbers its entries.
 *
 * Mobile first throughout. Every rule below applies at phone width and is
 * widened later, because a colleague scanning between meetings is the normal
 * case, not the edge case.
 */

/* ------------------------------------------------------------------ *
 * Tokens
 * ------------------------------------------------------------------ */

:root {
  /* Colour. Derived from PPA's brand hexes, converted to OKLCH so that equal
   * steps in lightness actually look equal, then adjusted until every
   * text/background pair passes WCAG AA. Neutrals are tinted warm (hue ~55-70)
   * rather than PPA's cool greys, because ink on newsprint reads warm and it
   * ties the orange into the page. */
  --paper:        oklch(0.968 0.006 70);   /* page ground */
  --paper-raise:  oklch(0.992 0.003 70);   /* lifted surfaces */
  --ink:          oklch(0.255 0.013 55);   /* body text, 14.4:1 on paper */
  --ink-soft:     oklch(0.455 0.016 55);   /* meta text, 6.66:1 on paper */
  --rule:         oklch(0.885 0.008 70);   /* hairlines */

  /* Two accents, one per stream. Colour here means "which desk is this from",
   * never decoration. */
  --flag:         oklch(0.560 0.190 38.6); /* Industry, 4.62:1 — text safe */
  --civic:        oklch(0.470 0.250 280);  /* Public Affairs, 7.03:1 */

  /* PPA's actual brand orange. It is 2.75:1 on paper and fails even the
   * large-text threshold, so it MUST NOT carry text. Fills only. */
  --flag-bright:  oklch(0.690 0.205 38.6);

  /* Default accent; overridden per stream on the digest below. */
  --accent: var(--flag);

  /* Type. Lexend Deca is PPA's own display face, adopted at their request —
   * it was designed for reading proficiency, so it stays clear at the tight
   * leading headlines are set at. Archivo carries body and interface: a
   * grotesque built for periodical use that holds up at the small sizes the
   * credit lines run at.
   *
   * Both are sans-serifs, so the pairing leans on weight and size for
   * contrast rather than on letterform. That is why the headline scale steps
   * up sharply from body and the credit lines are set in caps — without
   * those, two grotesques this close together would read as one voice. */
  --font-display: "Lexend Deca", "Segoe UI", system-ui, sans-serif;
  --font-body: Archivo, "Segoe UI", system-ui, sans-serif;

  /* Fixed rem scale, not fluid. Fluid type belongs on marketing pages; in a
   * reading interface it makes line lengths unpredictable. The masthead is the
   * one exception. */
  --text-micro: 0.6875rem;   /* 11px — uppercase labels and credits */
  --text-meta: 0.8125rem;    /* 13px — dates, status */
  --text-body: 1rem;         /* 16px */
  --text-headline: 1.3125rem;/* 21px — story headlines */
  --text-section: 1.75rem;   /* 28px — page titles */

  /* 4pt spacing scale. 8pt is too coarse — 12px between two related lines is
   * a size you reach for constantly. */
  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 3rem;

  --measure: 68ch;  /* longest comfortable line for body copy */
}

/* ------------------------------------------------------------------ *
 * Base
 * ------------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--accent); }

/* One focus style everywhere, and it must be visible against warm paper. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 1px;
}

/* ------------------------------------------------------------------ *
 * Masthead
 *
 * The thick-rule-then-hairline under a masthead is a newspaper device, and
 * it is the single detail that sets the tone for everything below.
 * ------------------------------------------------------------------ */

.masthead {
  background: var(--paper-raise);
  border-bottom: 3px solid var(--ink);
  padding: var(--space-md) var(--space-md) var(--space-sm);
}

.masthead-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 800;
  /* The one place fluid sizing earns its keep — it has to hold the top of the
   * page at 360px and at 1600px without a breakpoint. */
  font-size: clamp(1.125rem, 5.5vw, 1.875rem);
  /* Slightly more tracking than a serif masthead would take. Lexend is drawn
   * with open sidebearings; set in caps it needs the extra room or the
   * letterforms crowd. */
  letter-spacing: 0.035em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
}

.dateline {
  font-size: var(--text-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 500;
  white-space: nowrap;
}

.site-nav {
  display: flex;
  gap: var(--space-md);
  padding: var(--space-xs) var(--space-md);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-raise);
  overflow-x: auto;
  scrollbar-width: none;
}
.site-nav::-webkit-scrollbar { display: none; }

.site-nav a {
  font-size: var(--text-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  padding: var(--space-2xs) 0;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.site-nav .voter-name {
  font-size: var(--text-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  padding: var(--space-2xs) 0;   /* match .site-nav a so the text lines up */
}

main {
  max-width: 46rem;
  margin: 0 auto;
  padding: var(--space-lg) var(--space-md) var(--space-2xl);
}

/* ------------------------------------------------------------------ *
 * Headings
 * ------------------------------------------------------------------ */

h1 {
  font-family: var(--font-display);
  font-size: var(--text-section);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-md);
}

h2 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  margin: var(--space-xl) 0 var(--space-sm);
}

.hint {
  color: var(--ink-soft);
  font-size: var(--text-meta);
  max-width: var(--measure);
  margin: 0 0 var(--space-md);
}

/* ------------------------------------------------------------------ *
 * Stream switcher
 * ------------------------------------------------------------------ */

.streams {
  display: flex;
  gap: var(--space-lg);
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--space-md);
  overflow-x: auto;
  scrollbar-width: none;
}
.streams::-webkit-scrollbar { display: none; }

.stream-tab {
  font-size: var(--text-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 0 0 var(--space-sm);
  margin-bottom: -1px;
  border-bottom: 3px solid transparent;
  white-space: nowrap;
}
.stream-tab:hover { color: var(--ink); }
.stream-tab.is-active {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* Each stream owns an accent, so the colour of the page tells you which desk
 * you are reading before you have read a word. */
.digest { --accent: var(--flag); }
.digest[data-stream="public_affairs"] { --accent: var(--civic); }

/* ------------------------------------------------------------------ *
 * Scan status — the dateline of the digest
 * ------------------------------------------------------------------ */

.scan-bar {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex-wrap: wrap;
  margin-bottom: var(--space-sm);
}

.scan-status {
  font-size: var(--text-meta);
  color: var(--ink-soft);
  margin: 0 0 var(--space-xl);
  max-width: var(--measure);
}
.scan-status a { color: var(--accent); }
.scan-failed, .scan-warning, .scan-warning-inline {
  color: var(--flag);
  font-weight: 600;
}

#scan-progress {
  font-size: var(--text-meta);
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------ *
 * The digest
 *
 * Rules, not cards. Stories are separated the way columns are. The score sits
 * in the margin as a printed numeral — it is the one piece of editorial
 * judgement the tool makes, so it gets the typographic weight.
 * ------------------------------------------------------------------ */

.story {
  display: grid;
  grid-template-columns: 2.25rem 1fr;
  column-gap: var(--space-sm);
  padding: var(--space-lg) 0;
  border-bottom: 1px solid var(--rule);
}
.story:first-child { padding-top: var(--space-xs); }

.story-rank {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.15;
  color: var(--accent);
  font-variant-numeric: tabular-nums lining-nums;
  text-align: right;
  padding-top: 0.06em;   /* optical: sit the figure on the headline baseline */
}

.story-body { min-width: 0; }   /* lets long URLs wrap instead of overflowing */

.story-headline {
  font-family: var(--font-display);
  font-size: var(--text-headline);
  font-weight: 700;
  /* A shade more leading than a serif headline wants. Lexend's open counters
   * make tightly-leaded lines look crowded at this size. */
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-xs);
}
.story-headline a {
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: break-word;
}
.story-headline a:hover {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 1px;
}

.story-credit {
  font-size: var(--text-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
  margin: 0 0 var(--space-xs);
}

.story-reason {
  margin: 0 0 var(--space-sm);
  color: var(--ink-soft);
  font-size: 0.9375rem;
  line-height: 1.6;
  max-width: var(--measure);
  overflow-wrap: break-word;
}

.empty {
  color: var(--ink-soft);
  font-size: var(--text-meta);
  padding: var(--space-xl) 0;
  border-top: 1px solid var(--rule);
  max-width: var(--measure);
}

/* ------------------------------------------------------------------ *
 * Buttons and forms
 * ------------------------------------------------------------------ */

button, .button {
  font-family: var(--font-body);
  font-size: var(--text-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  background: var(--ink);
  color: var(--paper-raise);
  border: 1px solid var(--ink);
  border-radius: 2px;
  padding: 0 var(--space-md);
  min-height: 2.5rem;
  cursor: pointer;
  transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1),
              color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}
button:hover { background: var(--accent); border-color: var(--accent); }
button:disabled {
  background: var(--rule);
  border-color: var(--rule);
  color: var(--ink-soft);
  cursor: not-allowed;
}

/* Not every action is primary. Ghost buttons for anything secondary. */
button.secondary {
  background: transparent;
  color: var(--ink-soft);
  border-color: var(--rule);
}
button.secondary:hover {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
}

.pick-name {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.vote {
  display: flex;
  gap: var(--space-xs);
}
.vote button {
  background: transparent;
  color: var(--ink-soft);
  border-color: var(--rule);
  padding: 0 var(--space-sm);
}
.vote button:hover {
  background: transparent;
  color: var(--accent);
  border-color: var(--accent);
}
.vote button.is-selected {
  color: var(--accent);
  border-color: var(--accent);
  background: color-mix(in oklch, var(--accent) 8%, transparent);
}

input[type="text"], input[type="password"], select, textarea {
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--ink);
  background: var(--paper-raise);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: var(--space-xs) var(--space-sm);
  min-height: 2.5rem;
}
input[type="text"]:focus, input[type="password"]:focus, textarea:focus {
  border-color: var(--accent);
}
textarea { min-height: 12rem; line-height: 1.6; resize: vertical; }

/* ------------------------------------------------------------------ *
 * Panels — suggest a source, pending approvals, criteria
 * ------------------------------------------------------------------ */

.panel {
  background: var(--paper-raise);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: var(--space-md);
  margin-bottom: var(--space-xl);
}
.panel > h2:first-child { margin-top: 0; }

.panel-form { display: flex; flex-direction: column; gap: var(--space-xs); }
.panel-form input[type="text"] { width: 100%; }

.suggestion {
  border-top: 1px solid var(--rule);
  padding-top: var(--space-md);
  margin-top: var(--space-md);
}
.suggestion label {
  display: block;
  margin: var(--space-xs) 0;
  font-size: var(--text-meta);
  color: var(--ink-soft);
}
.suggestion input[type="text"], .suggestion select {
  display: block;
  width: 100%;
  margin-top: var(--space-2xs);
}

.url {
  color: var(--ink-soft);
  font-size: var(--text-meta);
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------ *
 * Sources table
 *
 * Below 40rem the table becomes stacked blocks rather than a horizontally
 * scrolling grid. Adapt the interface for the context, don't amputate it —
 * every column is still there, it is just set as a list.
 * ------------------------------------------------------------------ */

table.sources {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--space-xl);
}
table.sources th {
  text-align: left;
  font-size: var(--text-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 600;
  padding: var(--space-xs) var(--space-sm) var(--space-xs) 0;
  border-bottom: 2px solid var(--ink);
}
table.sources td {
  padding: var(--space-sm) var(--space-sm) var(--space-sm) 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--text-meta);
  vertical-align: top;
}
table.sources .source-name {
  font-weight: 600;
  font-size: var(--text-body);
  color: var(--ink);
}
.status-cell { overflow-wrap: anywhere; }

/* Tint the row rather than stripe its edge. */
tr.failing td { background: color-mix(in oklch, var(--flag) 5%, transparent); }
tr.dead td { background: color-mix(in oklch, var(--flag) 10%, transparent); }

.badge-dead {
  display: inline-block;
  background: var(--flag);
  color: var(--paper-raise);
  padding: 0.1rem var(--space-xs);
  border-radius: 2px;
  font-size: var(--text-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

@media (max-width: 40rem) {
  table.sources, table.sources tbody, table.sources tr, table.sources td {
    display: block;
    width: 100%;
  }
  /* Visually hidden, still read by screen readers. */
  table.sources thead {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  table.sources tr {
    padding: var(--space-md) 0;
    border-bottom: 1px solid var(--rule);
  }
  table.sources td {
    border: 0;
    padding: 0 0 var(--space-2xs);
  }
  /* The column heading comes back as a label so nothing loses its meaning. */
  table.sources td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--text-micro);
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink-soft);
    font-weight: 600;
    margin-top: var(--space-xs);
  }
  table.sources td.source-cell::before { content: none; }
  tr.failing td, tr.dead td { background: transparent; }
  tr.failing { background: color-mix(in oklch, var(--flag) 5%, transparent); }
  tr.dead { background: color-mix(in oklch, var(--flag) 10%, transparent); }
}

/* ------------------------------------------------------------------ *
 * Criteria history
 * ------------------------------------------------------------------ */

.history { list-style: none; padding-left: 0; margin: var(--space-xs) 0 0; }
.history li {
  padding: var(--space-xs) 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--text-meta);
  color: var(--ink-soft);
}
details summary {
  cursor: pointer;
  color: var(--ink-soft);
  font-size: var(--text-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 600;
  margin-top: var(--space-md);
}
form.inline { display: inline; }

/* ------------------------------------------------------------------ *
 * Log in
 * ------------------------------------------------------------------ */

.login {
  max-width: 22rem;
  margin: var(--space-2xl) auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.login h1 { margin-bottom: var(--space-xs); }
.login label {
  font-size: var(--text-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
}
.login input, .login button { width: 100%; }
.error { color: var(--flag); font-weight: 600; font-size: var(--text-meta); }

/* ------------------------------------------------------------------ *
 * Flash messages
 *
 * A full hairline and a wash of the brand orange — deliberately NOT a
 * coloured stripe down one edge, which is the most over-used "design touch"
 * in internal tooling and never looks intentional.
 * ------------------------------------------------------------------ */

.flash {
  border: 1px solid color-mix(in oklch, var(--flag-bright) 35%, var(--rule));
  background: color-mix(in oklch, var(--flag-bright) 8%, var(--paper-raise));
  padding: var(--space-sm) var(--space-md);
  margin: 0 0 var(--space-md);
  font-size: var(--text-meta);
  border-radius: 2px;
}

/* ------------------------------------------------------------------ *
 * Motion
 *
 * One orchestrated moment — the digest settling in on load — rather than
 * micro-interactions scattered everywhere. Transform and opacity only, so it
 * never triggers layout. Exponential ease-out, because real objects
 * decelerate; they do not bounce.
 * ------------------------------------------------------------------ */

@keyframes settle {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}

.digest .story {
  animation: settle 480ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
.digest .story:nth-child(1) { animation-delay: 0ms; }
.digest .story:nth-child(2) { animation-delay: 40ms; }
.digest .story:nth-child(3) { animation-delay: 80ms; }
.digest .story:nth-child(4) { animation-delay: 120ms; }
.digest .story:nth-child(5) { animation-delay: 160ms; }
.digest .story:nth-child(6) { animation-delay: 200ms; }
.digest .story:nth-child(7) { animation-delay: 240ms; }
.digest .story:nth-child(n+8) { animation-delay: 280ms; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ------------------------------------------------------------------ *
 * Wider screens
 *
 * The layout is not rebuilt here, only loosened — the phone version is the
 * real design.
 * ------------------------------------------------------------------ */

@media (min-width: 40rem) {
  :root {
    --text-headline: 1.4375rem;
    --text-section: 2.125rem;
  }
  .masthead, .site-nav { padding-inline: var(--space-lg); }
  main { padding: var(--space-xl) var(--space-lg) var(--space-2xl); }
  .story { grid-template-columns: 3rem 1fr; column-gap: var(--space-md); }
  .story-rank { font-size: 1.75rem; }
  .panel { padding: var(--space-lg); }
  .panel-form { flex-direction: row; }
  .panel-form input[type="text"] { flex: 1; }
  .suggestion input[type="text"], .suggestion select {
    display: inline-block;
    width: auto;
    min-width: 16rem;
  }
}
