/* ---------------------------------------------------------------------
   Vibecode Daily -- shared stylesheet
   Palette: warm cream page, near-black ink blocks, amber accent.
   Serif (Fraunces) for display/numbers, sans (Inter) for UI chrome.
--------------------------------------------------------------------- */

:root {
  --cream: #f3eee4;
  --cream-card: #ffffff;
  --ink: #17140f;
  --ink-soft: #1e1a14;
  --paper-text: #17140f;
  --paper-text-secondary: #5c5449;
  --paper-text-muted: #9a8f7f;
  --dark-text: #f5f0e8;
  --dark-text-secondary: #c9beb0;
  --dark-text-muted: #8a8078;
  --amber: #e8a86a;
  --amber-deep: #8a5a2e;
  --success: #6fb8a8;
  --success-deep: #1e5c48;
  --danger: #d99a9a;
  --border-soft: #e2dbcb;
  --font-display: "Fraunces", Georgia, serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --max-width: 1080px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--paper-text);
  font-family: var(--font-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

/* -------------------- nav -------------------- */

.site-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 0;
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}

.site-nav .links { display: flex; gap: 24px; color: var(--paper-text-secondary); }
.site-nav .links a.active { color: var(--paper-text); font-weight: 600; }
.site-nav .links a:hover { color: var(--paper-text); text-decoration: none; }

.masthead {
  text-align: center;
  padding: 4px 0 28px;
}

.masthead .wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(48px, 9vw, 92px);
  letter-spacing: -3px;
  line-height: 0.9;
}

.masthead .tagline {
  font-size: 11px;
  letter-spacing: 4px;
  color: var(--paper-text-muted);
  margin-top: 8px;
  text-transform: uppercase;
}

/* -------------------- hero -------------------- */

.hero {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  min-height: 340px;
  padding: 56px 40px 40px;
  margin-bottom: 4px;
  background: linear-gradient(200deg, #0a0a0a 0%, #1c1c1c 45%, #2e2e2e 100%);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 75% 30%, rgba(232, 168, 106, 0.18), transparent 55%);
}

.hero-graphic {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

.hero .eyebrow {
  position: absolute;
  z-index: 1;
  top: 28px;
  left: 40px;
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--amber);
  text-transform: uppercase;
}

.hero h1 {
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(28px, 4.5vw, 46px);
  line-height: 1.1;
  color: var(--dark-text);
  max-width: 640px;
  margin: 0 0 14px;
}

.hero p {
  position: relative;
  z-index: 1;
  color: var(--dark-text-secondary);
  font-size: 14px;
  max-width: 460px;
  margin: 0;
}

/* Puts hero-sub and hero-cta on the same line, CTA pinned to the right
   edge - a plain flex row nested inside .hero's own column layout, so
   .hero's flex-direction:column stacks (graphic/eyebrow/headline/this
   row) while this row itself lays its two children out horizontally. */
.hero-bottom-row {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.hero-bottom-row p { margin: 0; }

.hero-cta {
  display: inline-block;
  flex-shrink: 0;
  padding: 10px 18px;
  border: 1px solid var(--amber);
  border-radius: 3px;
  background: rgba(232, 168, 106, 0.16);
  color: var(--amber);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.hero-cta:hover {
  background: var(--amber);
  color: #17140f;
}

/* -------------------- stat band -------------------- */

.stat-band-heading {
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--paper-text-muted);
  text-transform: uppercase;
  margin: 20px 0 10px;
}

.stat-band {
  background: var(--ink);
  border-radius: 4px;
  padding: 28px 32px;
  margin: 4px 0 36px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 24px;
}

.stat-band .stat .value {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 34px;
  color: var(--dark-text);
  font-variant-numeric: tabular-nums;
}

.stat-band .stat .value.accent { color: var(--amber); }

.stat-band .stat .label {
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--dark-text-muted);
  text-transform: uppercase;
  margin-top: 4px;
}

/* -------------------- section headers -------------------- */

.section-label {
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--paper-text-muted);
  text-transform: uppercase;
  margin: 0 0 14px;
}

.section-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 500;
  margin: 0 0 6px;
}

.section-subtitle {
  font-size: 13px;
  color: var(--paper-text-secondary);
  max-width: 520px;
  margin: 0 0 20px;
}

.freshness-note {
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--paper-text-muted);
  margin: 4px 0 20px;
}

/* -------------------- weekly digest -------------------- */
/* Auto-written by scripts/generate_digest.py (Gemini) - an editorial
   pull-quote treatment (italic serif, amber rule) to read as a written
   aside rather than another data card. Hidden by default in the markup;
   JS only reveals it once data/digest.json actually loads. */

.digest-card {
  background: var(--cream-card);
  border-left: 3px solid var(--amber);
  border-radius: 4px;
  padding: 20px 24px;
  margin: 0 0 36px;
}

.digest-label {
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--amber-deep);
  text-transform: uppercase;
  margin-bottom: 8px;
}

.digest-text {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 17px;
  line-height: 1.5;
  color: var(--paper-text);
  margin: 0;
}

/* -------------------- filters -------------------- */
/* Editorial tab style, not buttons: letter-spaced uppercase labels
   sitting on a shared divider line, with the active tab picked out by
   its own underline - the same visual language as a magazine section
   nav rather than a row of filter chips. */

.filter-row {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  margin-bottom: 32px;
  border-bottom: 1px solid var(--border-soft);
}

.filter-pill {
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 0 0 12px;
  margin-bottom: -1px;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
  color: var(--paper-text-muted);
  transition: color 0.15s ease, border-color 0.15s ease;
}

.filter-pill:hover {
  color: var(--paper-text);
}

.filter-pill.active {
  background: transparent;
  color: var(--paper-text);
  border-bottom-color: var(--ink);
}

/* -------------------- story grid + video grid -------------------- */
/* True masonry, not a uniform grid: CSS multi-column layout, each card's
   image kept at its own natural aspect ratio (a real <img>, not a
   fixed-height background-div), so cards of different heights stagger
   the way the reference layout does - a CSS Grid row can't do this on
   its own, since every cell in a grid row is forced to the height of
   the tallest one. Shared between stories and videos, per request. */

.story-grid, .video-grid {
  column-count: 3;
  column-gap: 28px;
}

.story-grid {
  margin-bottom: 28px;
}

.story-card, .video-card {
  display: block;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  margin-bottom: 40px;
}

.story-card .thumb, .video-card .thumb {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  margin-bottom: 14px;
}

.thumb.thumb-placeholder {
  aspect-ratio: 4 / 3;
  background: linear-gradient(135deg, #2a3540, #42302a);
}

/* Videos need a positioning context for the play/views badges, which a
   plain <img> can't provide on its own (it can't contain children). */
.thumb-wrap {
  position: relative;
  margin-bottom: 10px;
}

.thumb-wrap .thumb {
  margin-bottom: 0;
}

.story-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.story-date {
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  white-space: nowrap;
}

.tag-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.tag-pill {
  font-size: 10px;
  letter-spacing: 0.5px;
  padding: 3px 9px;
  border-radius: 20px;
  text-transform: uppercase;
}

.tag-pill.tools { background: #e8a86a; color: #4a2e10; }
.tag-pill.industry { background: #d6c9ec; color: #3c2e5c; }
.tag-pill.risks { background: #f0b3b3; color: #5c1e1e; }
.tag-pill.research { background: #b3d9c0; color: #1e4a2c; }
.tag-pill.uncategorized { background: #d6d0c4; color: #4a4438; }

.tag-pill.relevant {
  position: static;
  display: inline-block;
  margin-right: 6px;
  background: #d6ece5;
  color: var(--success-deep);
}

.story-card .headline, .video-card .headline {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.3;
  margin: 0 0 8px;
  color: var(--paper-text);
}

.story-card .excerpt {
  font-size: 13px;
  line-height: 1.6;
  color: var(--paper-text-secondary);
  margin: 0 0 10px;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.story-card .byline, .video-card .byline {
  font-size: 12px;
  color: var(--paper-text-muted);
}

/* -------------------- Product Hunt launches -------------------- */
/* Styled like compare.html's .tool-card (dark ink, colored top border,
   italic tagline) rather than the light .story-card treatment used
   elsewhere on this page - this section is fundamentally about tools, the
   same subject as the dark .leaderboard/.tool-card blocks, not articles,
   so it reads as part of that system instead of a third, unrelated card
   style competing with both. */

#ph-section {
  margin-bottom: 44px;
}

.ph-subhead-block {
  border-left: 3px solid var(--amber);
  padding-left: 12px;
  margin-bottom: 16px;
}

.ph-subhead-block-spaced {
  margin-top: 36px;
}

.ph-subhead {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  color: var(--paper-text);
  margin: 0 0 4px;
}

.ph-subhead-note {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--paper-text-secondary);
  max-width: 560px;
  margin: 0;
}

.ph-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  margin-bottom: 8px;
}

/* Horizontal carousel, shared by all three Product Hunt lists - a single
   scrollable row reads better than a wrapping grid once there are enough
   items to need more than one row. */
.ph-grid-scroll {
  display: flex;
  grid-template-columns: none;
  overflow-x: auto;
  padding-bottom: 10px;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}

.ph-grid-scroll .ph-card {
  flex: 0 0 240px;
  scroll-snap-align: start;
}

.ph-grid-scroll .empty-state {
  flex: 1 0 100%;
}

/* Wraps a .ph-grid-scroll with prev/next buttons and edge fades - see
   initCarousel() in index.html. A button is fully hidden (opacity 0, via
   :disabled) at whichever end there's nothing further to scroll to,
   fading in only once scrolling away from that edge makes it usable -
   showing a dimmed-but-inert button before any scrolling has happened
   read as a permanently broken control, not an affordance. */
.ph-carousel {
  position: relative;
  margin-bottom: 8px;
}

.ph-carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--ink-soft);
  color: var(--dark-text);
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

.ph-carousel-scrollable .ph-carousel-arrow {
  opacity: 1;
  pointer-events: auto;
}

.ph-carousel-arrow:hover:not(:disabled) {
  background: var(--amber);
  color: var(--ink);
  transform: translateY(-50%) scale(1.08);
}

.ph-carousel-arrow:disabled {
  opacity: 0;
  cursor: default;
  pointer-events: none;
}

.ph-carousel-arrow-prev { left: -14px; }
.ph-carousel-arrow-next { right: -14px; }

/* Edge fades hint that a carousel continues past the visible cards -
   fade to the page's own cream background, since that's what's actually
   behind/around the dark cards. */
.ph-carousel::before,
.ph-carousel::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 10px; /* matches .ph-grid-scroll's padding-bottom */
  width: 40px;
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.ph-carousel::before {
  left: 0;
  background: linear-gradient(to right, var(--cream), transparent);
}

.ph-carousel::after {
  right: 0;
  background: linear-gradient(to left, var(--cream), transparent);
}

.ph-carousel-scrollable:not(.at-start)::before,
.ph-carousel-scrollable:not(.at-end)::after {
  opacity: 1;
}

.ph-card {
  background: var(--ink);
  border-radius: 4px;
  padding: 16px 18px 14px;
  border-top: 3px solid var(--tool-color, var(--amber));
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: transform 0.15s ease, filter 0.15s ease;
}

.ph-card:hover {
  transform: translateY(-3px);
  filter: brightness(1.12);
}

.ph-card-head {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

/* The color/gradient lives on this wrapper, never on the <img> itself -
   an <img> doesn't reliably composite a transparent source over its own
   CSS background in every rendering environment, so phCard() removes the
   <img> outright on a load failure (see its onerror handler) rather than
   swapping its src to a transparent placeholder image, which would only
   work if that compositing behaved as expected. */
.ph-card-icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: 8px;
  flex-shrink: 0;
  overflow: hidden;
  /* Matches the card background, not the tool's accent color: many
     Product Hunt thumbnails are themselves rounded-square icons with a
     transparent margin outside that shape, so whatever sits behind a
     real image shows through at its edges/corners. An accent-colored
     background there reads as a visible mismatched ring around the
     icon; the card's own --ink blends into it invisibly instead. The
     colorful accent still shows up correctly via .ph-card-icon-placeholder
     below, which only applies when there's no real image to show at all. */
  background: var(--ink);
}

.ph-card-icon-wrap.ph-card-icon-placeholder {
  background: linear-gradient(135deg, var(--tool-color, var(--amber)), var(--ink) 130%);
}

.ph-card-icon {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ph-card-head-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ph-card-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15.5px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ph-card-name a {
  color: var(--dark-text);
  text-decoration: none;
}

.ph-card-name a:hover { text-decoration: underline; }

.ph-card-tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dark-text-secondary);
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ph-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border-top: 1px dashed rgba(255, 255, 255, 0.12);
  padding-top: 8px;
  margin-top: auto;
}

.ph-card-votes {
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--dark-text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ph-card-votes-unit {
  font-weight: 400;
  color: var(--dark-text-muted);
}

.ph-card-meta {
  font-size: 11px;
  letter-spacing: 0.3px;
  color: var(--dark-text-muted);
  white-space: nowrap;
}

.empty-state {
  padding: 40px 20px;
  text-align: center;
  color: var(--paper-text-muted);
  font-size: 14px;
  border: 1px dashed var(--border-soft);
  border-radius: 8px;
  break-inside: avoid;
}

.video-card .play-badge {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(23, 20, 15, 0.55);
  color: var(--dark-text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
}

.video-card .views-badge {
  position: absolute;
  bottom: 8px;
  right: 8px;
  font-size: 10px;
  letter-spacing: 0.3px;
  padding: 3px 8px;
  border-radius: 20px;
  background: rgba(23, 20, 15, 0.65);
  color: var(--dark-text);
}

/* -------------------- leaderboard -------------------- */

.subsection-label {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  margin: 0 0 10px;
}

.leaderboard {
  background: var(--ink);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 16px;
}

.leaderboard .row {
  display: grid;
  grid-template-columns: 1fr 100px 90px;
  align-items: center;
  padding: 14px 20px;
  border-bottom: 0.5px solid #241f18;
}

.leaderboard .row:last-child { border-bottom: none; }
.leaderboard .row.head { color: var(--dark-text-muted); font-size: 11px; letter-spacing: 0.5px; text-transform: uppercase; }

.leaderboard .name { color: var(--dark-text); font-size: 14px; }
.leaderboard .score { text-align: right; font-family: var(--font-display); font-size: 16px; color: var(--dark-text); }
.leaderboard .delta { text-align: right; font-size: 13px; }
.leaderboard .delta.up { color: #85c99e; }
.leaderboard .delta.down { color: #d99a9a; }

.method-note {
  font-size: 12px;
  color: var(--paper-text-muted);
  line-height: 1.5;
  max-width: 560px;
  margin: 12px 0 40px;
}

/* -------------------- signals table -------------------- */
/* leaderboard.html's sortable table of raw per-tool signals - deliberately
   NOT a ranked leaderboard (no rank column, no blended score - see
   compute_signals.py's docstring for why that was retired). Fixed pixel
   column widths + flex-shrink:0, not minmax(_,1fr) + width:max-content -
   the latter combination was a confirmed bug in compare.html's table
   (each row resolved a different column width based on its own content). */

.signals-table {
  display: flex;
  flex-direction: column;
  background: var(--cream-card);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  overflow-x: auto;
  margin-bottom: 12px;
}

.signals-row {
  display: grid;
  grid-template-columns: 170px repeat(7, 130px);
  /* Without an explicit width, this row's own box (and therefore its
     background paint) is clamped to .signals-table's visible width -
     the grid's fixed-width columns still lay out correctly past that
     edge (grid content isn't clipped by default), so the text scrolls
     into view fine but the background stops at the old edge, visibly
     cutting off mid-row. max-content makes the row's own box match the
     true sum of its columns, so the background scrolls with the content
     instead of lagging behind it. */
  width: max-content;
  flex-shrink: 0;
}

.signals-row:not(:last-child) { border-bottom: 1px solid var(--border-soft); }
.signals-row:not(.signals-row-head):hover { background: rgba(0,0,0,0.02); }

.signals-row-head {
  background: var(--cream);
  border-bottom: 1px solid var(--border-soft);
}

.signals-head {
  background: none;
  border: none;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  text-align: left;
  padding: 12px 14px;
  cursor: pointer;
  white-space: nowrap;
}

.signals-head:hover { color: var(--paper-text-secondary); }
.signals-head-active { color: var(--amber-deep); font-weight: 600; }
.signals-head:not(:first-child) { text-align: right; }

.signals-name {
  padding: 12px 14px;
  font-size: 13.5px;
  color: var(--paper-text);
  border-left: 3px solid var(--tool-color, var(--amber));
  display: flex;
  align-items: center;
}

.signals-cell {
  padding: 12px 14px;
  font-size: 13px;
  color: var(--paper-text-secondary);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.signals-cell.delta.up { color: #4f9c7f; }
.signals-cell.delta.down { color: #c4655f; }

/* -------------------- charts -------------------- */

.chart-card {
  background: var(--ink);
  border-radius: 12px;
  padding: 24px;
  margin-bottom: 24px;
}

.chart-card .chart-label {
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--dark-text-muted);
  text-transform: uppercase;
  margin-bottom: 14px;
}

.chart-caption {
  font-size: 12px;
  line-height: 1.5;
  color: var(--dark-text-secondary);
  margin: 16px 0 0;
}

.chart-card svg text { font-family: var(--font-body); }

.chart-grid {
  display: grid;
  /* 480px min forces 2 per row at this site's ~1032px content width
     (3 * 480 > 1032) instead of 3 cramped ones, while still collapsing
     to 1 column on narrow viewports. */
  grid-template-columns: repeat(auto-fit, minmax(480px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.chart-grid .chart-card { margin-bottom: 0; }

/* -------------------- chart interactivity -------------------- */
/* Shared by the trend charts (assets/trend-chart.js) and the radar chart
   (assets/radar-chart.js): hover a line to dim the others, hover a dot to
   see it grow (the <title> child gives the native tooltip), click a
   line's label (or the radar's external legend) to isolate/restore it. */

.chart-card svg .trend-series,
.chart-card svg .radar-series {
  transition: opacity 0.2s ease;
}

.chart-card svg:has(.trend-series:hover) .trend-series:not(:hover),
.chart-card svg:has(.radar-series:hover) .radar-series:not(:hover) {
  opacity: 0.25;
}

.chart-card svg .trend-dot {
  cursor: pointer;
  transition: r 0.15s ease;
}

.chart-card svg .trend-dot:hover {
  r: 6;
}

.chart-card svg .trend-label {
  cursor: pointer;
}

.chart-card svg .trend-series-hidden,
.chart-card svg .radar-series-hidden {
  opacity: 0.08;
}

.chart-card svg .trend-series-hidden .trend-dot {
  pointer-events: none;
}

/* -------------------- footer -------------------- */

.site-footer {
  padding: 40px 0 60px;
  font-size: 12px;
  color: var(--paper-text-muted);
  border-top: 1px solid var(--border-soft);
  margin-top: 20px;
}

/* -------------------- disclaimer banner + footer disclosure -------------------- */

.disclaimer-banner {
  background: var(--ink);
  border-bottom: 1px solid var(--amber-deep);
}

.disclaimer-banner-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 8px 24px;
  font-size: 12px;
  color: var(--dark-text-secondary);
  text-align: center;
}

.disclaimer-banner-inner strong {
  color: var(--amber);
  letter-spacing: 0.5px;
}

.disclaimer-banner-inner a {
  color: var(--amber);
  text-decoration: underline;
}

.disclosure-block {
  margin-bottom: 24px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--border-soft);
}

/* Native <details>/<summary> - collapsed by default, no JS needed. The
   default disclosure triangle is replaced with a custom arrow so it
   matches the site's own type/color system instead of the browser
   default marker. */
.disclosure-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15px;
  color: var(--paper-text);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.disclosure-title::-webkit-details-marker { display: none; }

.disclosure-title::before {
  content: "▸";
  font-size: 11px;
  color: var(--paper-text-muted);
  transition: transform 0.15s ease;
}

.disclosure-block[open] .disclosure-title::before {
  transform: rotate(90deg);
}

.disclosure-list {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 12px 16px;
  margin: 14px 0 0;
}

.disclosure-list dt {
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  font-weight: 600;
}

.disclosure-list dd {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--paper-text-secondary);
}

.disclosure-list a { color: var(--amber-deep); }

@media (max-width: 600px) {
  .disclosure-list { grid-template-columns: 1fr; gap: 4px 0; }
  .disclosure-list dt { margin-top: 10px; }
}

/* -------------------- compare page -------------------- */

.tool-hero-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 16px;
  margin: 4px 0 44px;
}

.tool-card {
  background: var(--ink);
  border-radius: 4px;
  padding: 22px 22px 20px;
  border-top: 3px solid var(--tool-color, var(--amber));
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.tool-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.tool-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
  color: var(--dark-text);
}

.tool-tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 14px;
  color: var(--dark-text-secondary);
  margin: 0;
}

.tool-stats-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  row-gap: 14px;
  column-gap: 8px;
  padding: 12px 0;
  border-top: 1px solid rgba(255,255,255,0.08);
  border-bottom: 1px solid rgba(255,255,255,0.08);
}

/* min-width:0 overrides the grid-item default of min-width:auto, which
   refuses to shrink a track below its content's intrinsic width - that's
   what was pushing the last column (and the text in it) past the card's
   edge for long values like VS Code install counts. */
.tool-stat { text-align: center; min-width: 0; }

.tool-stat-value {
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--dark-text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tool-stat-value.up { color: #85c99e; }
.tool-stat-value.down { color: #d99a9a; }

.tool-stat-label {
  font-size: 9px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--dark-text-muted);
  margin-top: 2px;
}

/* Stands in for .tool-stats-row on cards with no comparable adoption
   numbers (see compare.html's TOOL_ICONS) - same padding/border rhythm
   as the stats row it replaces, so both card shapes still read as the
   same family despite one having no numbers to show. */
.tool-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--tool-color, var(--amber));
}

.tool-card-icon svg {
  width: 40px;
  height: 40px;
}

.tool-best-for {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dark-text-secondary);
  margin: 0;
}

.tool-best-for strong { color: var(--dark-text); }

.tool-latest {
  font-size: 11.5px;
  color: var(--tool-color, var(--amber));
  border-top: 1px dashed rgba(255,255,255,0.12);
  padding-top: 10px;
  margin-top: auto;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tool-latest:hover { text-decoration: underline; }

.radar-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.radar-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 18px;
  margin-top: 8px;
}

.radar-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  color: var(--dark-text-secondary);
  font-family: var(--font-body);
  font-size: 12px;
  cursor: pointer;
  padding: 4px 0;
  transition: opacity 0.2s ease;
}

.radar-legend-item.radar-legend-off { opacity: 0.4; }

.radar-legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--tool-color, var(--amber));
  display: inline-block;
}

.compare-table {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  margin-bottom: 12px;
  /* Always scrollable, not just below a breakpoint - the tool count is
     dynamic and can exceed what fits comfortably even on a wide desktop
     viewport once past ~5 tools. */
  overflow-x: auto;
}

/* grid-template-columns is set inline per row in JS (compare.html) with
   a FIXED pixel width per tool column, not minmax(_, 1fr) - a 1fr track
   inside a row sized by width:max-content used to resolve independently
   per row based on that row's own longest cell, which broke column
   alignment between rows (each row ended up a different total width).
   Fixed widths make every row's columns identical regardless of content
   length, which is what makes width:max-content safe again below - it's
   no longer paired with an ambiguous 1fr track. It's also required, not
   optional: without it, a row's own box (and its background) is clamped
   to .compare-table's visible width, while its fixed-width grid columns
   still lay out past that edge unclipped - so text scrolls into view
   correctly but the background stops short of it, visibly cutting off
   mid-row. flex-shrink:0 alongside
   it is what lets a row wider than its container overflow into the
   horizontal scrollbar on .compare-table, instead of being squeezed to
   fit. */
.compare-row {
  display: grid;
  width: max-content;
  flex-shrink: 0;
}

.compare-row:not(:last-child) { border-bottom: 1px solid var(--border-soft); }
.compare-row:not(.compare-row-head):hover { background: rgba(0,0,0,0.02); }

.compare-cell {
  padding: 14px 16px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--paper-text-secondary);
}

.compare-cell:not(:last-child) { border-right: 1px solid var(--border-soft); }

.compare-row-label {
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  display: flex;
  align-items: center;
  background: var(--cream);
}

.compare-row-head { background: var(--cream-card); }

.compare-head {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  color: var(--paper-text);
  border-bottom: 2px solid var(--tool-color, var(--amber));
}

.verified-note {
  font-size: 11px;
  color: var(--paper-text-muted);
  margin: 0 0 20px;
}

.compare-scroll-hint {
  font-size: 11px;
  color: var(--paper-text-muted);
  margin: 0 0 8px;
}

.compare-filter-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--paper-text-muted);
  margin: 0 0 8px;
}

.compare-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}

.compare-filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 10px;
  border-radius: 20px;
  border: 1px dashed var(--tool-color, var(--border-soft));
  background: transparent;
  color: var(--paper-text-secondary);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-style 0.15s;
}

.compare-filter-pill:hover { color: var(--paper-text); }

.compare-filter-pill-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid currentColor;
  font-size: 10px;
  line-height: 1;
}

.compare-filter-pill.active {
  border-style: solid;
  background: var(--tool-color, var(--amber));
  border-color: var(--tool-color, var(--amber));
  color: #17140f;
}

@media (max-width: 900px) {
  .story-grid, .video-grid { column-count: 2; }
}

@media (max-width: 640px) {
  .leaderboard .row { grid-template-columns: 1fr 80px 70px; }
  .story-grid, .video-grid { column-count: 1; }
}
