/* Page layout: containers, nav, hero, footer, and per-page section scaffolding. */

.container {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 32px;
}

/* Wider container for the homepage "What it looks like" demo, so its
   miniature toolbar (back / prev / next / timer / topic / difficulty) has
   room to lay out on one row without cramping or wrapping. */
.container--figure {
  max-width: 1160px;
}

/* Problem page toolbar: narrower than the demo's, since prev/next moved
   below the content — the top only carries Back, timer, and meta. */
.container--problem {
  max-width: 860px;
}

/* About page-only overrides of shared classes (container/page-header are
   also used by problems.html) — scoped via body.page-about so only
   about.html gets the wider layout. */
.page-about .container {
  max-width: 960px;
}

/* Problems page: the table has real content density (title, teaser,
   topic, difficulty) and looked starved of room at the shared 900px
   width — lots of dead margin on wider screens for what's meant to be a
   dense, scannable list. */
.page-problems .container {
  max-width: 1240px;
}

/* ---- Site nav ----
   The floating pill nav (.nav-floating and its scoped descendants) is
   defined in components.css and is now the one nav pattern for every page,
   including problem.html, which used to run its own sticky-bar variant. */

/* ---- Hero ----
   Full-viewport: the hero fills the screen (min-height:100vh) so it's the
   only thing visible on first load, with the floating nav overlapping on
   top (margin-top cancels the nav's own reserved padding on main, then the
   hero re-adds top padding so its content clears the nav pill). Content is
   a single centered column now that the side graphic is gone. */

/* Pinned scroll sequence: a tall track (height set in JS, 4.8x viewport)
   with the hero stuck via position:sticky inside it. Scroll position maps
   to a 0-1 progress value (hero-scroll-base.js) that drives everything
   here — nothing is a one-shot triggered animation, so scrolling back up
   reverses it exactly. Skips entirely under prefers-reduced-motion: the
   track collapses to a normal single-viewport hero and the reveal content
   renders as a plain section instead (see hero-scroll-base.js). */
.hero-scroll-track {
  position: relative;
}

.hero-scroll-track .hero {
  position: sticky;
  top: 0;
}

.hero {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  margin-top: -88px;
  padding: 90px 0 94px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

.vortex-canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  /* Opacity/transform are rewritten every scroll frame (hero-scroll-base.js);
     hinting up front avoids a layer promotion on the first scroll tick. */
  will-change: opacity, transform;
}

.vortex-reveal {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-3);
  padding: 0 32px;
  pointer-events: none;
  opacity: 0;
}

.vortex-wordmark {
  font-size: clamp(2.8rem, 8vw, 5.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  background: linear-gradient(
    90deg,
    var(--text-muted) 0%,
    var(--text-muted) 20%,
    var(--text-primary) 50%,
    var(--text-muted) 80%,
    var(--text-muted) 100%
  );
  background-size: 200% auto;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  animation: shimmer 7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .vortex-wordmark {
    animation: none;
    background-position: 0% center;
  }
}

.vortex-tagline {
  font-size: clamp(1rem, 2.4vw, 1.3rem);
  color: var(--text-secondary);
  max-width: 480px;
}

.vortex-free {
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--accent);
}

/* Ambient background: real math expressions type themselves out at
   randomized positions, pause, delete, and restart elsewhere. Positioned
   above the grid texture (no z-index / DOM order puts it later) and below
   .hero-content (explicit z-index:1) so it never competes with the actual
   headline. See assets/js/typing-equations.js. */
.eq-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.eq-slot {
  position: absolute;
  /* Deliberately not --font-display (now SF Pro sitewide) — these are
     equations, not headline text, and keep the old serif they were
     written in. */
  font-family: 'STIX Two Text', Georgia, 'Times New Roman', serif;
  font-style: italic;
  color: rgba(var(--accent-rgb), 0.15);
  white-space: nowrap;
  will-change: contents;
}

.eq-cursor {
  display: inline-block;
  color: rgba(var(--accent-rgb), 0.4);
  animation: eqCursorBlink 1s step-end infinite;
}

@keyframes eqCursorBlink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .eq-cursor {
    animation: none;
    opacity: 0;
  }
}

.hero-content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 640px;
  margin: 0 auto;
}

.hero-headline {
  margin-top: var(--space-4);
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6vw, 4rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  text-wrap: balance;
  /* Dimmer than --headline-accent (pure white) on purpose — emphasis on
     "twice" now comes from brightness contrast, not color, since the
     accent is monochrome. */
  color: var(--text-secondary);
}

@keyframes shimmer {
  0% {
    background-position: 200% center;
  }
  100% {
    background-position: -200% center;
  }
}

.headline-accent {
  color: var(--accent);
}

.hero-subhead {
  margin-top: var(--space-4);
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-secondary);
  max-width: 480px;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  margin-top: var(--space-8);
}

.hr {
  border: none;
  border-top: 1px solid var(--border-subtle);
  margin: 0;
}

/* ---- Featured problems ----
   Stats used to live in a separate big-number/small-label bar between the
   hero and this section — that's the "hero metric" pattern the redesign
   explicitly avoids (see DESIGN.md § Do's and Don'ts). The same information
   (count, topic count, cadence) now rides as a plain caption next to the
   section heading instead of its own bordered block. */

.section {
  padding: var(--space-16) 0;
}

.section-intro {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin-bottom: 32px;
}

/* Real headline, not a receding eyebrow label — the first thing the eye
   lands on when a section scrolls into view. Same display voice as the
   about page's h1 and the follow-strip heading, one step smaller. */
.section-heading {
  font-family: var(--font-display);
  font-size: clamp(24px, 3.2vw, 32px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--text-primary);
  text-wrap: balance;
  margin-bottom: var(--space-3);
}

.section-intro .section-heading {
  margin-bottom: var(--space-2);
}

.section-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}

/* ---- Page header (problems / about) ---- */

.page-header {
  padding: var(--space-16) 0 var(--space-8);
}

.page-title {
  font-size: 48px;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

.page-title--about {
  font-family: var(--font-display);
  font-size: clamp(44px, 7vw, 72px);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* The brand promise gets room to breathe: taller header block, larger
   lede. Scoped to the about page so the problems page header is
   unaffected. Padding tuned to match the current lede copy's length —
   only this section's own padding changes, so the divider below and
   every other section keep their original spacing. */
.page-about .page-header {
  padding: calc(var(--space-24) + var(--space-6)) 0 var(--space-12);
}

.page-about .page-header-lede {
  margin-top: var(--space-6);
  font-size: 17px;
  line-height: 1.75;
  max-width: 620px;
}

/* ---- Problems section (filter bar + table) ---- */

.problems-section {
  padding: 0 0 var(--space-16);
}

/* ---- Filter bar (problems page) ---- */

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  min-height: 48px;
  padding: var(--space-2) var(--space-4);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-6);
}

.filter-group {
  display: flex;
  align-items: center;
}

.filter-group--search {
  flex: 1 1 220px;
}

.filter-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}

.filter-bar .search-input,
.filter-bar .select-input {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  min-width: 0;
  height: 32px;
  width: 100%;
}

.filter-bar .search-input:focus-visible,
.filter-bar .select-input:focus-visible {
  outline-offset: -2px;
}

/* ---- Table wrapper ----
   No outer box — the "Luminous Ledger" table is hairlines and type only
   (see .problems-table in components.css). The filter bar above is its
   own standalone panel now, separated by margin instead of sharing a
   joined border. */
.table-wrapper {
  border: none;
}

/* ---- About page ---- */

.page-header-lede {
  margin-top: var(--space-4);
}

.about-section--criteria {
  padding-top: 0;
}

.about-section--topics {
  padding-top: 0;
}

/* Dividers between about-page sections: dead space on both sides instead
   of sitting flush against the content above/below. Scoped separately
   from the shared .hr (used elsewhere with margin: 0) so this doesn't
   affect index.html/problem.html's dividers. */
.about-hr {
  margin: var(--space-16) 0;
}

.about-lede {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-secondary);
  max-width: 680px;
}

.about-lede + .about-lede {
  margin-top: var(--space-4);
}

/* "Problems Sourced From Everywhere": plain mono list, dot-separated —
   reads as a quiet colophon line, not a badge row. */
.sources-list {
  list-style: none;
  margin: var(--space-6) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-muted);
}

.sources-list li:not(:last-child)::after {
  content: '·';
  margin-left: var(--space-4);
  color: var(--border-strong);
}

.criteria-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-6);
}

@media (max-width: 700px) {
  .criteria-grid {
    grid-template-columns: 1fr;
  }
}

/* ---- Follow Us strip (about page) ---- */

/* No top padding, exactly like every other about-page section: the
   .about-hr's own 64px bottom margin is what sets the gap from the rule to
   a section heading, so adding any here would break that shared rhythm.
   The bottom matches at 64px, which also leaves the content centered
   between the hr above and the footer's top border below. */
.follow-strip {
  padding: 0 0 var(--space-16);
  text-align: center;
}

.follow-strip-heading {
  font-family: var(--font-display);
  font-size: clamp(22px, 3vw, 30px);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

.follow-strip-text {
  margin-top: var(--space-3);
  font-size: 15px;
  color: var(--text-secondary);
}

.follow-actions {
  margin-top: var(--space-8);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* Platform-tinted buttons in the site's luminous language: the icon
   carries its platform's hue with a soft glow at rest, and hovering
   lights the whole button in that hue (tinted border, faint fill, outer
   glow) — the same treatment topic rows get, not a stock ghost button. */
.follow-btn {
  --social-color: var(--accent);
  gap: 10px;
  padding: 12px 26px;
  border-color: var(--border-default);
  color: var(--text-primary);
  transition: border-color var(--transition-fast), background var(--transition-fast), box-shadow var(--transition-fast), transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}

.follow-btn--instagram {
  --social-color: #e1306c;
}

.follow-btn--youtube {
  --social-color: #ff4444;
}

.follow-btn:hover {
  border-color: color-mix(in srgb, var(--social-color) 55%, transparent);
  background: color-mix(in srgb, var(--social-color) 8%, transparent);
  box-shadow: 0 0 20px -6px var(--social-color);
  transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
  .follow-btn:hover {
    transform: none;
  }
}

.follow-icon {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--social-color);
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--social-color) 55%, transparent));
}

/* ---- Footer ---- */

.site-footer {
  border-top: 1px solid var(--border-subtle);
  padding: var(--space-8) 0;
}

.footer-math {
  text-align: center;
  /* Deliberately not --font-mono (now Roboto Mono sitewide) — this is
     equation notation ("P(you enjoy this) → 1"), not a data numeral like
     the difficulty/index cells, and keeps the old mono it was written in. */
  font-family: 'IBM Plex Mono', 'SF Mono', Menlo, Consolas, monospace;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: var(--space-4);
}

.footer-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.footer-links {
  display: flex;
  gap: var(--space-6);
}

.footer-links a {
  font-size: 13px;
  color: var(--text-secondary);
  transition: color var(--transition-fast);
}

.footer-links a:hover {
  color: var(--text-primary);
}

.footer-copyright {
  font-size: 13px;
  color: var(--text-secondary);
}

.footer-note {
  margin-top: var(--space-4);
  font-size: 12px;
  color: var(--text-muted);
  max-width: 640px;
}

/* ---- Legal pages (terms / privacy) ----
   Narrower container than the default 900px — this is dense reading text,
   not a layout that benefits from extra width. */

.page-legal .container {
  max-width: 760px;
}

.page-legal .page-header {
  padding-bottom: var(--space-4);
}

.legal-updated {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  letter-spacing: 0.01em;
  margin-top: var(--space-3);
}

.legal-content {
  padding: var(--space-8) 0 var(--space-24);
}

.legal-section + .legal-section {
  margin-top: var(--space-12);
}

.legal-heading {
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: var(--space-3);
}

.legal-text {
  font-size: 14px;
  line-height: 1.75;
  color: var(--text-secondary);
  max-width: 680px;
}

.legal-text + .legal-text {
  margin-top: var(--space-4);
}

.legal-list {
  margin-top: var(--space-3);
  max-width: 680px;
}

.legal-list li {
  position: relative;
  padding-left: var(--space-4);
  font-size: 14px;
  line-height: 1.75;
  color: var(--text-secondary);
}

.legal-list li + li {
  margin-top: var(--space-2);
}

.legal-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 4px;
  height: 4px;
  border-radius: 999px;
  background: var(--accent);
}

.legal-text a,
.legal-list a {
  color: var(--accent-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-text a:hover,
.legal-list a:hover {
  color: var(--accent);
}

.legal-text code,
.legal-list code {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-primary);
  background: var(--bg-elevated);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
}

.legal-list strong {
  color: var(--text-primary);
  font-weight: 600;
}
