/* ============================================================
   Reading Room — a calm, bookish, editorial reading queue.
   Warm paper, serif headlines, a single deep-green accent, and
   sharp modern corners.

   This stylesheet is the design system. It is organised in layers,
   top to bottom, and every rule is keyed to a semantic class that
   matches a hiccup primitive in reader.ui.components — there are no
   utility classes. To add UI, reuse a primitive; to restyle, edit
   the one rule here. See docs/design-system.md.

     1. Base        — reset, elements (headings, links, buttons)
     2. App shell   — .topbar, .brand, .topnav, <main>
     3. Primitives  — .btn, .chip, .card, .page-head, .field, .backnav
     4. Views       — .readables, .reader, .login, .settings, .eval

   Design tokens (colour, type, spacing, radii) live in tokens.css.
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-ui);
  background: var(--paper);
  color: var(--ink);
  line-height: 1.55;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 {
  font-family: var(--font-prose);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.15;
  margin: 0 0 var(--s-4);
  color: var(--ink);
}
h1 { font-size: clamp(1.8rem, 1.3rem + 1.8vw, 2.4rem); }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.1rem; }
p { margin: 0 0 var(--s-4); }

a { color: inherit; text-decoration: none; transition: color .15s; }
a:hover { color: var(--accent); }

hr { border: 0; border-top: 1px solid var(--rule); margin: var(--s-6) 0; }

/* A single, consistent keyboard-focus ring everywhere. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

.muted { color: var(--muted); }

/* ---- Buttons (primitive: components/button) ------------------
   A bare <button> is the quiet secondary control. Variants add a
   modifier class: .btn--primary (accent fill), .btn--icon (a quiet
   glyph button), .btn--link (reads as inline text). */
button {
  font: inherit;
  font-weight: 500;
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--rule-2);
  border-radius: var(--r-sm);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: border-color .15s, background .15s, color .15s, box-shadow .15s, transform .05s;
}
button:hover { border-color: var(--ink-soft); }
button:active { transform: translateY(0.5px); }

.btn--primary {
  border-color: var(--accent);
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
.btn--primary:hover { border-color: var(--accent); filter: brightness(1.07); }
@media (prefers-color-scheme: dark) { .btn--primary { color: #10201b; } }

.btn--icon {
  display: inline-flex;
  padding: var(--s-2);
  border: 0;
  background: transparent;
  color: var(--muted);
}
.btn--icon:hover { background: var(--rule); color: var(--gold); border-color: transparent; }
.btn--icon svg { display: block; width: 1.1rem; height: 1.1rem; }

.btn--link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font-weight: 500;
}
.btn--link:hover { color: var(--accent); border-color: transparent; }

/* ---- Chips (primitive: components/chip) ----------------------
   A small status pill. The default is an accent chip; modifiers
   recolour it for queue states. */
.chip {
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.625rem;
  font-weight: 700;
  padding: 0.22em 0.5em;
  border-radius: var(--r-sm);
  background: var(--accent-tint);
  color: var(--accent);
  line-height: 1.5;
}
.chip--read { background: transparent; color: var(--muted); border: 1px solid var(--rule-2); }
.chip--reading { background: color-mix(in srgb, var(--gold) 14%, transparent); color: var(--gold); }

/* Tag chips read as content (sentence case, not the uppercase status pills) and
   double as filter links: a clear pill affordance, no underline, accent fill when
   active (= currently filtering). */
.chip--tag {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  text-decoration: none;
  background: var(--paper-2);
  color: var(--ink-soft);
  border: 1px solid var(--rule-2);
  transition: background .15s, color .15s, border-color .15s;
}
.chip--tag:hover { color: var(--accent); border-color: var(--accent); }
.chip--active, .chip--active:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (prefers-color-scheme: dark) { .chip--active, .chip--active:hover { color: #10201b; } }

/* The tag filter bar above the reading list, and the per-row tag strip. */
.tag-filter   { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: var(--s-4) 0; }
.readable-tags { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-2); }

/* Reader-view tag editor: each tag is a chip with a quiet × remove, plus an
   inline add field. */
.reader-tags { margin: var(--s-6) 0; padding-top: var(--s-4); border-top: 1px solid var(--rule); }
.reader-tag-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3);
}
.reader-tag { display: inline-flex; align-items: center; gap: var(--s-2); }
.reader-tag form { display: inline; }
.tag-remove {
  border: none; background: none; cursor: pointer; padding: 0 0.1em;
  color: var(--muted); font-size: 1.05rem; line-height: 1;
}
.tag-remove:hover { color: var(--gold); }
.reader-tag-add form { display: flex; gap: var(--s-2); align-items: center; }
.reader-tag-add input {
  font-size: 0.875rem; padding: var(--s-2) var(--s-3);
  border: 1px solid var(--rule-2); border-radius: var(--r-sm); background: var(--paper);
}

/* ---- Top bar / app shell ------------------------------------
   A sticky, translucent masthead with the wordmark and the primary
   nav. Shared across every signed-in page (reader.ui.layout/app-page). */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--rule);
}
.topbar-inner {
  max-width: var(--feed);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s-3) var(--s-5);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-prose);
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.brand:hover { color: var(--ink); }
.brand-mark { display: inline-flex; color: var(--accent); }
.brand-mark svg { width: 1.25rem; height: 1.25rem; }
.topnav { display: flex; align-items: center; gap: var(--s-5); font-size: 0.9rem; font-weight: 500; }
.topnav a { color: var(--muted); padding: 0.2rem 0; border-bottom: 2px solid transparent; }
.topnav a:hover { color: var(--ink); }
.topnav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }
/* Sign-out is a POST, so a real <button> with the .btn--link variant. */
.logout { display: inline-flex; }

main {
  max-width: var(--feed);
  margin-inline: auto;
  padding: var(--s-6) var(--s-5) var(--s-7);
}

/* ---- Page head ---------------------------------------------- */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-5);
}
.page-head h1 { margin: 0; }
.page-sub { margin: var(--s-2) 0 0; font-size: 0.9rem; }

/* ---- Back nav (reader, sub-pages) --------------------------- */
.backnav { margin-bottom: var(--s-5); font-size: 0.875rem; }
.backnav a { display: inline-flex; align-items: center; gap: var(--s-1); color: var(--muted); font-weight: 500; }
.backnav a:hover { color: var(--accent); }
.backnav svg { width: 1rem; height: 1rem; }

/* ---- Add-by-URL bar ----------------------------------------- */
.add-url {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-6);
  padding: var(--s-2) var(--s-2) var(--s-2) var(--s-4);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.add-url-icon { color: var(--muted); font-size: 1.2rem; font-weight: 300; line-height: 1; }
.add-url input[type="url"] {
  font: inherit;
  flex: 1;
  min-width: 0;
  padding: var(--s-3) var(--s-2);
  border: 0;
  background: transparent;
  color: inherit;
}
.add-url input::placeholder { color: var(--muted); }
.add-url input:focus { outline: none; }
/* The submit is a .btn--primary; the bar only sets its size. */
.add-url .btn--primary { padding: var(--s-3) var(--s-5); }

/* ---- The reading list --------------------------------------- */
.readables, .entities { list-style: none; padding: 0; margin: 0; }

.readable {
  display: flex;
  align-items: flex-start;
  gap: var(--s-4);
  padding: var(--s-5) var(--s-4);
  margin-inline: calc(-1 * var(--s-4));
  border-radius: var(--r-md);
  border: 1px solid transparent;
  position: relative;
  transition: background .15s, box-shadow .15s;
}
/* A hairline between rows, drawn as an inset pseudo-element so it can
   vanish cleanly around the hovered (raised) row. */
.readable::after {
  content: "";
  position: absolute;
  left: var(--s-4); right: var(--s-4); bottom: 0;
  border-bottom: 1px solid var(--rule);
}
.readable:last-child::after { display: none; }
.readable:hover { background: var(--paper-2); box-shadow: var(--shadow-sm); }
.readable:hover::after, .readable:hover + .readable::after { border-color: transparent; }

.readable-text { flex: 1; min-width: 0; }
.readable-title {
  font-family: var(--font-prose);
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
}
.readable-title a { color: inherit; }
.readable:hover .readable-title a { color: var(--accent); }

.readable-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  font-size: 0.8125rem;
  margin-top: var(--s-2);
  color: var(--muted);
}
/* CSS owns the separators, so the markup stays clean (no literal dots). */
.meta-item + .meta-item::before { content: "·"; margin-right: var(--s-3); color: var(--rule-2); }
.meta-source { color: var(--ink-soft); font-weight: 500; }
.readable-meta a { color: var(--ink-soft); }
.readable-meta a:hover { color: var(--accent); }

/* The row action (.btn--icon) is hidden until the row is hovered. */
.readable-actions { flex-shrink: 0; }
.readable-actions .btn--icon { opacity: 0; transition: opacity .15s, background .15s, color .15s; }
.readable:hover .readable-actions .btn--icon { opacity: 1; }

/* Importing / failed states */
.readable.importing .readable-title {
  color: var(--muted);
  font-family: var(--font-ui);
  font-size: 1.05rem;
  font-weight: 500;
}
.readable.failed .readable-title { color: var(--gold); }
.import-url { overflow-wrap: anywhere; font-family: var(--font-ui); }

.spinner {
  display: inline-block;
  width: 0.85em; height: 0.85em;
  border: 2px solid var(--accent);
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -0.1em;
  margin-right: 0.35em;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Entity indexes (authors, sources) ---------------------- */
.entities li {
  padding: var(--s-4) var(--s-2);
  border-top: 1px solid var(--rule);
  font-family: var(--font-prose);
  font-size: 1.15rem;
}
.entities li:first-child { border-top: 0; }
.entities li a { color: var(--ink); }
.entities li a:hover { color: var(--accent); }
.entities .entity-type { font-family: var(--font-ui); font-size: 0.8125rem; color: var(--muted); }

/* ---- Entity show pages (author / source: lead + sections) --- */
.entity-section { margin-top: var(--s-6); }
.entity-lead { color: var(--ink-soft); max-width: 42rem; }
.entity-meta { color: var(--muted); font-size: 0.9rem; display: flex; gap: var(--s-2); flex-wrap: wrap; }

/* ---- Forms -------------------------------------------------- */
.form { max-width: 32rem; }
.form label { display: block; margin-bottom: var(--s-5); }
.form .label-text { display: block; margin-bottom: var(--s-2); font-size: 0.8125rem; font-weight: 600; color: var(--ink-soft); }
.form input {
  font: inherit;
  width: 100%;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--rule-2);
  border-radius: var(--r-sm);
  background: var(--paper);
  color: inherit;
  transition: border-color .15s, box-shadow .15s;
}
.form input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.form input:focus:not(:focus-visible) { outline: none; }
.form .error { color: var(--gold); font-size: 0.8125rem; margin-top: var(--s-1); }
.form .btn--primary { padding-inline: var(--s-5); }

/* ---- Reader view -------------------------------------------- */
.reader { max-width: var(--measure); margin-inline: auto; }
.reader-head { margin-bottom: var(--s-6); padding-bottom: var(--s-5); border-bottom: 1px solid var(--rule); }
.kicker {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--s-3);
}
.reader-head h1 { margin: 0 0 var(--s-4); font-size: clamp(2rem, 1.4rem + 2.4vw, 2.9rem); line-height: 1.1; }
.reader-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  font-size: 0.875rem;
  color: var(--muted);
}
.reader-meta .meta-item + .meta-item::before { content: "·"; margin-right: var(--s-3); color: var(--rule-2); }
.reader-meta a { color: var(--ink-soft); }
.reader-meta a:hover { color: var(--accent); }

.reader .prose { font-family: var(--font-prose); font-size: 1.2rem; line-height: 1.75; color: var(--ink-soft); }
.reader .prose > * + * { margin-top: var(--s-5); }
.reader .prose h2, .reader .prose h3 { color: var(--ink); margin-top: var(--s-6); margin-bottom: var(--s-3); }
.reader .prose blockquote {
  margin: var(--s-5) 0;
  padding: var(--s-1) 0 var(--s-1) var(--s-5);
  border-left: 3px solid var(--accent-2);
  color: var(--ink);
  font-style: italic;
  font-size: 1.25rem;
}
.reader .prose .lead { font-size: 1.35rem; line-height: 1.6; color: var(--ink); }
/* A drop cap opens the piece — the editorial flourish that sets the tone. */
.reader .prose .lead::first-letter {
  initial-letter: 3;
  -webkit-initial-letter: 3;
  font-weight: 700;
  margin-right: 0.6rem;
  color: var(--accent);
}
.reader .prose .placeholder { font-style: italic; }

/* External links (DOI, arXiv, the original) get a trailing ↗. */
.reader-links { display: flex; flex-wrap: wrap; gap: var(--s-4); font-size: 0.9375rem; margin-top: var(--s-6); }
.reader-links a { color: var(--accent); font-weight: 500; }
.external::after { content: " ↗"; opacity: 0.6; }
.reader-unsubscribe { font-size: 0.875rem; margin-top: var(--s-3); }

.reader-actions {
  display: flex;
  gap: var(--s-3);
  margin-top: var(--s-7);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
}
.reader-actions button { font-weight: 500; }

/* ---- Login -------------------------------------------------- */
.login-main { display: flex; min-height: 100vh; align-items: center; justify-content: center; max-width: none; padding: var(--s-5); }
.login-card { width: 100%; max-width: 24rem; text-align: center; }
.brand-lg { font-size: 1.6rem; justify-content: center; margin-bottom: var(--s-6); }
.brand-lg .brand-mark svg { width: 1.7rem; height: 1.7rem; }
.login-card h1 { font-size: 2rem; margin-bottom: var(--s-2); }
.login-tag { margin-bottom: var(--s-6); }
/* Hanko renders the actual auth flow inside a shadow root, so we theme it the
   two supported ways (see docs.hanko.io/guides/hanko-elements/customize-appearance):
   its CSS custom properties (which pierce the shadow boundary) map the widget
   onto our tokens, and a few ::part() rules sharpen the controls to match. We
   frame the host element itself as the card and hide its built-in headline,
   since the page already provides one. */
.login-card hanko-auth {
  display: block;
  text-align: left;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);

  --color: var(--ink);
  --color-shade-1: var(--muted);
  --color-shade-2: var(--rule-2);
  --brand-color: var(--accent);
  --brand-color-shade-1: var(--accent);
  --brand-contrast-color: #fff;
  --background-color: var(--paper-2);
  --error-color: var(--gold);
  --link-color: var(--accent);
  --font-family: var(--font-ui);
  --font-size: 1rem;
  --font-weight: 400;
  --border-radius: var(--r-sm);
  --border-style: solid;
  --border-width: 1px;
  --item-height: 2.85rem;
  --item-margin: 0.6rem 0;
  --container-padding: var(--s-6);
  --container-max-width: 100%;
  --headline2-font-size: 0.8125rem;
  --headline2-font-weight: 600;
  --link-text-decoration: none;
  --link-text-decoration-hover: underline;
}
@media (prefers-color-scheme: dark) {
  .login-card hanko-auth { --brand-contrast-color: #10201b; }
}
/* The page renders its own "Welcome back" headline above the card. */
.login-card hanko-auth::part(headline1) { display: none; }
.login-card hanko-auth::part(primary-button) { font-weight: 600; }
.login-card hanko-auth::part(input),
.login-card hanko-auth::part(button) { border-radius: var(--r-sm); }

/* ---- Card (primitive: components/card) ---------------------- */
.card { padding: var(--s-5); background: var(--paper-2); border: 1px solid var(--rule); border-radius: var(--r-md); }
.card h2 { margin-bottom: var(--s-3); }
.card > :last-child { margin-bottom: 0; }
main section + section { margin-top: var(--s-5); }

/* ---- Settings ----------------------------------------------- */
.inbox-alias { margin: var(--s-4) 0; }
/* user-select:all lets one click select the whole address to copy it. */
.inbox-alias code {
  display: inline-block;
  font-size: 1.0625rem;
  padding: var(--s-3) var(--s-4);
  border: 1px dashed var(--rule-2);
  border-radius: var(--r-sm);
  background: var(--paper);
  user-select: all;
}
.inbox-pending { font-size: 0.875rem; }
/* The rotate-alias form sits beneath the address, set off by a hairline. */
.rotate-alias { margin-top: var(--s-5); padding-top: var(--s-5); border-top: 1px solid var(--rule); }
.rotate-alias > p { margin-top: 0; margin-bottom: var(--s-4); }

/* ---- Extraction eval dashboard ------------------------------ */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s-4); margin: 0; }
.stats dt { font-size: 0.8125rem; color: var(--muted); }
.stats dd { margin: 0; font-family: var(--font-prose); font-size: 1.6rem; }
table.eval { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
table.eval th, table.eval td {
  text-align: left;
  padding: var(--s-3) var(--s-4) var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
  font-weight: 400;
}
table.eval thead th { color: var(--muted); }
.sources { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.sources .source { font-size: 0.8125rem; color: var(--muted); }

/* ---- Responsive --------------------------------------------- */
@media (max-width: 560px) {
  .topbar-inner { padding: var(--s-3) var(--s-4); }
  .topnav { gap: var(--s-4); font-size: 0.85rem; }
  .brand-word { display: none; }
  main { padding: var(--s-5) var(--s-4); }
  .page-head { flex-direction: column; align-items: flex-start; gap: var(--s-3); }
  .readable-actions button { opacity: 1; }
}
