/*
 * FlickThreads design tokens.
 * Source of truth: the FlickThreads Design System (dark cinema UI, violet
 * accent, glass surfaces, poster-tinted blur). The brand default is dark;
 * a derived light variant keeps the theme preference (system/light/dark)
 * fully functional.
 */
:root {
  color-scheme: dark light;

  /* Typography — Outfit (display) + Instrument Sans (body). The next/font
   * variables are injected on <html>; the literal families cover tests and
   * fixtures rendered outside the app shell. */
  --font-display:
    var(--font-outfit, "Outfit"), system-ui, -apple-system, sans-serif;
  --font-body:
    var(--font-instrument-sans, "Instrument Sans"), system-ui, -apple-system,
    sans-serif;
  --font-sans: var(--font-body);
  --tracking-tight: -0.02em;
  --tracking-wide: 0.06em;
  /* Type scale. Body copy is --text-base; UI labels step down through
   * md/sm/xs; headings step up. Component styles reference these rather
   * than literal sizes so the scale can change in one place. */
  --text-2xs: 0.7rem;
  --text-xs: 0.75rem;
  --text-sm: 0.8rem;
  --text-md: 0.85rem;
  --text-base: 1rem;
  --text-lg: 1.15rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;

  /* Base neutrals — near-black cinema dark */
  --color-canvas: #0a0a0e;
  --color-canvas-raised: #101017;
  --color-surface: #16161f;
  --color-surface-strong: #1d1d28;
  --color-text: #f5f4f8;
  --color-text-muted: #b8b6c6;
  --color-text-faint: #7e7c90;
  --color-text-inverse: #ffffff;
  /* Text over posters, scrims, and tinted glass — theme-independent. */
  --color-on-media: #ffffff;
  --color-on-media-muted: rgb(255 255 255 / 78%);
  --color-border: rgb(255 255 255 / 12%);
  --color-border-subtle: rgb(255 255 255 / 7%);

  /* Glass surfaces (over imagery, pair with --blur-glass) */
  --glass-1: rgb(255 255 255 / 6%);
  --glass-2: rgb(255 255 255 / 10%);
  --glass-3: rgb(255 255 255 / 16%);
  --glass-border: rgb(255 255 255 / 10%);
  --glass-border-strong: rgb(255 255 255 / 18%);
  --scrim-1: rgb(10 10 14 / 55%);
  --scrim-2: rgb(10 10 14 / 80%);
  /* Dark-leaning glass for floating chrome that needs strong text contrast. */
  --glass-dim: rgb(16 14 22 / 62%);
  /* Floating sheets/dialogs: mostly-opaque fill so content stays legible
   * even where backdrop blur cannot apply. */
  --surface-sheet: rgb(18 16 24 / 84%);
  /* Near-opaque sheet fill for while the sheet is in motion — backdrop
   * blur is disabled during transforms (it re-blurs every frame), so the
   * fill compensates by covering what the blur would have obscured. */
  --surface-sheet-opaque: rgb(20 18 26 / 97%);
  /* Poster art tinting a sheet: the blurred-poster treatment and the wash
   * that keeps text readable over it. */
  --sheet-poster-filter: blur(56px) saturate(1.5) brightness(0.45);
  --sheet-poster-scrim: rgb(14 12 20 / 45%);

  /* Brand accent — FlickThreads violet */
  --color-accent: #9d5ce8;
  --color-accent-strong: #8a45dd;
  --color-accent-soft: rgb(157 92 232 / 16%);
  --color-accent-glow: rgb(157 92 232 / 45%);
  --color-on-accent: #ffffff;

  /* Quick-rate personality colors — Bad · Fine · Like · Love */
  --rate-bad: #ff5d5d;
  --rate-bad-soft: rgb(255 93 93 / 15%);
  --rate-fine: #ffc14d;
  --rate-fine-soft: rgb(255 193 77 / 15%);
  --rate-like: #4dd97e;
  --rate-like-soft: rgb(77 217 126 / 15%);
  --rate-love: #ff6ba9;
  --rate-love-soft: rgb(255 107 169 / 15%);

  /* Semantic */
  --color-success: #4dd97e;
  --color-warning: #ffc14d;
  --color-danger: #ff5d5d;
  --color-focus: #5da9ff;
  --color-download: #5da9ff;
  --color-backdrop: rgb(10 10 14 / 55%);

  /* Spacing (4px base) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  /* The page gutter: the one side margin every page edge aligns to. Framed
   * pages (.page-container, the details frames, Books' page frame, the
   * desktop topbar) pad by it directly. Full-bleed modules (Home shelves,
   * the Updates preview, the details hero) inset by --page-inset instead: the
   * gutter plus the centering slack once the viewport outgrows --content-max,
   * so their text lines up with framed pages while their scrollers still run
   * under the margin. `100%` resolves against the module's own containing
   * block, so a shelf inside a narrower frame simply insets by the gutter. */
  --page-pad: var(--space-5);
  --page-inset: calc(
    max(0px, (100% - var(--content-max)) / 2) + var(--page-pad)
  );
  --row-gap: 0.75rem;

  /* Radii — cards 16px, sheets 28px, buttons/chips pill */
  --radius-xs: 0.5rem;
  --radius-sm: 0.75rem;
  --radius-md: 1rem;
  --radius-lg: 1.25rem;
  --radius-xl: 1.75rem;
  --radius-card: var(--radius-md);
  --radius-sheet: var(--radius-xl);
  --radius-pill: 999px;

  /* Elevation — soft, large, black-only; glow reserved for accent moments */
  --shadow-card: 0 8px 24px rgb(0 0 0 / 45%);
  --shadow-card-hover: 0 16px 48px rgb(0 0 0 / 55%);
  --shadow-raised: 0 16px 48px rgb(0 0 0 / 55%);
  --shadow-sheet: 0 -12px 60px rgb(0 0 0 / 60%);
  --shadow-nav: 0 8px 24px rgb(0 0 0 / 45%);
  /* Small raised controls (segmented thumb) and the inset top highlight
   * that gives glass surfaces their edge. */
  --shadow-control: 0 2px 10px rgb(0 0 0 / 35%);
  --glass-highlight: rgb(255 255 255 / 12%);
  --glow-accent: 0 0 24px var(--color-accent-glow);

  /* Blur — the signature glass move */
  --blur-glass: blur(20px) saturate(1.6);
  --blur-heavy: blur(40px) saturate(1.8);

  /* Motion — springy and quick */
  --motion-fast: 150ms;
  --state-interacted-opacity: 0.68;
  --motion-standard: 280ms;
  --motion-slow: 450ms;
  --motion-download-pulse: 1600ms;
  --ease-standard: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-spring-soft: cubic-bezier(0.3, 1.11, 0.58, 1);
  /* Symmetric in-out for motion that must stay visible past the mobile
   * keyboard's render freeze. */
  --ease-gentle: cubic-bezier(0.4, 0, 0.2, 1);
  --loading-delay: 100ms;

  /* Layout */
  --poster-ratio: 2 / 3;
  --card-width-small: 9rem;
  --card-width-medium: 13.5rem;
  --card-width-large: 18rem;
  --card-panel-mix: 55%;
  --control-min: 2.75rem;
  /* Vertical rhythm between stacked page sections (home shelves, detail
   * sections) — one knob, kept intentionally tight. */
  --section-gap: var(--space-4);
  /* The thin pill height shared by segmented toggles, icon buttons, and
   * default buttons, so mixed control rows sit on one line. */
  --control-slim: 2.3rem;
  /* One knob for every control in the floating page headers (segmented
   * toggles, icon buttons, dropdown triggers) — the thin pill height. */
  --header-control: var(--control-slim);
  --content-max: 90rem;
  --nav-height: 4.75rem;
  /* Immersive viewers sit above navigation, sheets, auth overlays, and
   * every feature-local stacking context. Only toasts and sheets opened
   * from inside a viewer stack above it (see toast.css, bottom-sheet.css). */
  --layer-immersive: 110;
  /* Resting strength of companion controls that share the screen with
   * playing media (the trailer overlay's actions, quick rate, and
   * description): present and pressable, but the video owns the eye. */
  --media-companion-opacity: 0.7;
  /* Desktop persistent topbar height; sticky nested-page headers pin
   * directly beneath it. */
  --topbar-height: 4.5rem;
}
/* Wider screens get a wider gutter; every framed and full-bleed page edge
 * follows it through --page-pad and --page-inset. */
@media (min-width: 760px) {
  :root {
    --page-pad: var(--space-8);
  }
}

/*
 * Light variant — an intentional derivation of the brand (the design system
 * itself is dark-only). Violet accent, cool neutrals, dark-tinted glass.
 */
[data-theme="light"] {
  color-scheme: light;
  --color-canvas: #f7f6fa;
  --color-canvas-raised: #ffffff;
  --color-surface: #edebf3;
  --color-surface-strong: #e2dfec;
  --color-text: #17151e;
  --color-text-muted: #5b5870;
  --color-text-faint: #8a879c;
  --color-border: rgb(23 21 30 / 14%);
  --color-border-subtle: rgb(23 21 30 / 8%);
  --glass-1: rgb(255 255 255 / 40%);
  --glass-2: rgb(255 255 255 / 55%);
  --glass-3: rgb(255 255 255 / 75%);
  --glass-border: rgb(23 21 30 / 10%);
  --glass-border-strong: rgb(23 21 30 / 18%);
  --scrim-1: rgb(23 21 30 / 45%);
  --scrim-2: rgb(23 21 30 / 70%);
  --glass-dim: rgb(255 255 255 / 68%);
  --surface-sheet: rgb(255 255 255 / 88%);
  --surface-sheet-opaque: rgb(255 255 255 / 98%);
  --sheet-poster-filter: blur(56px) saturate(1.1) brightness(1.35) opacity(0.5);
  --sheet-poster-scrim: rgb(255 255 255 / 62%);
  --color-accent: #7a3fd1;
  --color-accent-strong: #6930bd;
  --color-accent-soft: rgb(122 63 209 / 14%);
  --color-accent-glow: rgb(122 63 209 / 35%);
  --rate-bad: #e23a3a;
  --rate-bad-soft: rgb(226 58 58 / 14%);
  --rate-fine: #c47f00;
  --rate-fine-soft: rgb(196 127 0 / 14%);
  --rate-like: #1fa85b;
  --rate-like-soft: rgb(31 168 91 / 14%);
  --rate-love: #e0447e;
  --rate-love-soft: rgb(224 68 126 / 14%);
  --color-success: #1fa85b;
  --color-warning: #c47f00;
  --color-danger: #e23a3a;
  --color-focus: #2878ff;
  --color-backdrop: rgb(23 21 30 / 45%);
  --shadow-card: 0 8px 24px rgb(27 20 45 / 14%);
  --shadow-card-hover: 0 16px 48px rgb(27 20 45 / 20%);
  --shadow-raised: 0 16px 48px rgb(27 20 45 / 20%);
  --shadow-sheet: 0 -12px 60px rgb(27 20 45 / 24%);
  --shadow-nav: 0 8px 24px rgb(27 20 45 / 14%);
  --shadow-control: 0 2px 10px rgb(27 20 45 / 14%);
}

/* Compact desktop defaults shared by shelves, grids, and their skeletons. */
@media (min-width: 1240px) {
  :root {
    --card-width-medium: 11.25rem;
    --card-ui-medium: 0.833333;
  }
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --color-canvas: #f7f6fa;
    --color-canvas-raised: #ffffff;
    --color-surface: #edebf3;
    --color-surface-strong: #e2dfec;
    --color-text: #17151e;
    --color-text-muted: #5b5870;
    --color-text-faint: #8a879c;
    --color-border: rgb(23 21 30 / 14%);
    --color-border-subtle: rgb(23 21 30 / 8%);
    --glass-1: rgb(255 255 255 / 40%);
    --glass-2: rgb(255 255 255 / 55%);
    --glass-3: rgb(255 255 255 / 75%);
    --glass-border: rgb(23 21 30 / 10%);
    --glass-border-strong: rgb(23 21 30 / 18%);
    --scrim-1: rgb(23 21 30 / 45%);
    --scrim-2: rgb(23 21 30 / 70%);
    --glass-dim: rgb(255 255 255 / 68%);
    --surface-sheet: rgb(255 255 255 / 88%);
    --surface-sheet-opaque: rgb(255 255 255 / 98%);
    --sheet-poster-filter: blur(56px) saturate(1.1) brightness(1.35)
      opacity(0.5);
    --sheet-poster-scrim: rgb(255 255 255 / 62%);
    --color-accent: #7a3fd1;
    --color-accent-strong: #6930bd;
    --color-accent-soft: rgb(122 63 209 / 14%);
    --color-accent-glow: rgb(122 63 209 / 35%);
    --rate-bad: #e23a3a;
    --rate-bad-soft: rgb(226 58 58 / 14%);
    --rate-fine: #c47f00;
    --rate-fine-soft: rgb(196 127 0 / 14%);
    --rate-like: #1fa85b;
    --rate-like-soft: rgb(31 168 91 / 14%);
    --rate-love: #e0447e;
    --rate-love-soft: rgb(224 68 126 / 14%);
    --color-success: #1fa85b;
    --color-warning: #c47f00;
    --color-danger: #e23a3a;
    --color-focus: #2878ff;
    --color-backdrop: rgb(23 21 30 / 45%);
    --shadow-card: 0 8px 24px rgb(27 20 45 / 14%);
    --shadow-card-hover: 0 16px 48px rgb(27 20 45 / 20%);
    --shadow-raised: 0 16px 48px rgb(27 20 45 / 20%);
    --shadow-sheet: 0 -12px 60px rgb(27 20 45 / 24%);
    --shadow-nav: 0 8px 24px rgb(27 20 45 / 14%);
    --shadow-control: 0 2px 10px rgb(27 20 45 / 14%);
  }
}

[data-theme="dark"] {
  color-scheme: dark;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 1ms;
    --motion-standard: 1ms;
    --motion-slow: 1ms;
  }
}

.state-glyph {
  display: inline-grid;
  flex: none;
  vertical-align: middle;
  pointer-events: none;
}
.state-glyph__layer {
  display: grid;
  place-items: center;
  grid-area: 1 / 1;
  opacity: 0;
  transition: opacity var(--motion-fast) var(--ease-standard);
}
.state-glyph__layer[data-current] {
  opacity: 1;
}
/* Invisible spinners should not keep animating on every card. */
.state-glyph__layer:not([data-current]) .spin {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .state-glyph__layer {
    transition: none;
  }
  .state-glyph .spin {
    animation: none;
  }
}
[data-motion="reduced"] .state-glyph__layer {
  transition: none;
}
[data-motion="reduced"] .state-glyph .spin {
  animation: none;
}



/*
 * Shared element defaults and utilities for every FlickThreads app.
 * Import once, directly after the theme tokens. Everything here is
 * app-agnostic: the reset, focus treatment, text-selection policy for
 * gesture-driven chrome, and the small set of utility classes that shared
 * components render (`.icon-button`, `.empty-state`, `.loading-reveal`…).
 * Feature-specific styling belongs to the owning feature.
 */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  max-inline-size: 100%;
  background: var(--color-canvas);
  /* Prevent WebKit from carrying landscape text autosizing back into the
   * feed after an embedded trailer returns to portrait. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
/* Pages never scroll sideways; only dedicated rows (shelves, filter strips)
 * scroll horizontally inside their own overflow containers. */
html,
body {
  overflow-x: hidden;
  min-inline-size: 0;
  max-inline-size: 100%;
  /* iOS Safari ignores user-scalable=no, so pinch/double-tap zoom is also
   * disabled here; panning stays allowed for normal scrolling. */
  touch-action: pan-x pan-y;
}
body {
  margin: 0;
  color: var(--color-text);
  background: var(--color-canvas);
  font-family: var(--font-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* App chrome is not selectable: long-press gestures (action sheets,
   * press-drag rating) must not start text selection or the iOS image
   * callout. User-authored content opts back in via .selectable-text. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
input,
textarea,
[contenteditable="true"],
.selectable-text,
.selectable-text * {
  user-select: text;
  -webkit-user-select: text;
}
img {
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  letter-spacing: var(--tracking-tight);
}
button,
input,
select,
textarea {
  font: inherit;
}
/* Browsers default placeholders to a faint grey that fails contrast on the
 * light canvas; every field uses the muted text token instead (opacity 1
 * so WebKit does not fade it further). */
input::placeholder,
textarea::placeholder {
  color: var(--color-text-muted);
  opacity: 1;
}
/* iOS zooms the page into any focused field rendered under 16px. Text
 * fields on touch layouts therefore never go below 16px — focus should
 * only focus. */
@media (max-width: 1239px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea {
    font-size: max(16px, 1em);
  }
}
button {
  font-family: var(--font-display);
}
button,
a,
input,
select,
textarea {
  -webkit-tap-highlight-color: transparent;
}
a {
  color: inherit;
}
svg {
  display: block;
}
/* Pointer focus (including focus restored after a sheet closes) stays quiet;
 * keyboard navigation retains the shared visible focus indicator. */
:focus:not(:focus-visible) {
  outline: none;
}
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 3px;
}
/* Text-entry surfaces already retain their caret and field/container shape;
 * focusing them must not add the app-wide control halo. */
:is(input, textarea, select, [contenteditable="true"]):focus-visible {
  outline: none;
}
/* The root never scrolls smoothly: Chromium animates the browser's own
 * history scroll restoration when the root has scroll-behavior: smooth, so
 * Back would land at the top and glide down. Programmatic scrolls that want
 * motion pass behavior: "smooth" themselves, with a reduced-motion fallback. */

/* Page frames */
.page-container {
  width: min(100%, var(--content-max));
  margin: 0 auto;
  padding: var(--space-5) var(--page-pad) var(--space-12);
}
.page-narrow {
  max-width: 50rem;
}
.screen-header {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: var(--space-4);
  margin: 0 0 var(--space-6);
}
.screen-header h1 {
  margin: var(--space-1) 0;
  font-size: clamp(1.75rem, 5vw, 2.5rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: var(--tracking-tight);
}
.screen-header p {
  max-width: 42rem;
  margin: var(--space-2) 0 0;
  color: var(--color-text-muted);
  font-size: var(--text-base);
  line-height: 1.45;
}

/* Horizontal filter row and its pill toggles. */
.filter-strip {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  margin: 0 0 var(--space-6);
  padding-bottom: var(--space-2);
  scrollbar-width: none;
}
.chip {
  display: inline-flex;
  min-height: 2.25rem;
  flex: none;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  background: transparent;
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard),
    background var(--motion-fast) var(--ease-standard);
}
.chip.is-selected,
.chip[aria-pressed="true"] {
  border-color: var(--color-accent);
  color: var(--color-accent);
  background: var(--color-accent-soft);
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover {
    background: var(--glass-2);
  }
}

/* Stacked label + control for free-form fields (textareas, file inputs). */
.field-stack {
  display: grid;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: 600;
}
.field-stack input,
.field-stack textarea,
.field-stack select {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text);
  background: var(--color-canvas-raised);
}
.field-stack textarea {
  min-height: 7rem;
  resize: vertical;
}

/* Utilities */
/* Loader glyphs (LoaderCircle) turn with this class; reduced motion
 * settles them through the shared [data-motion="reduced"] rule. */
.spin {
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: fixed;
  z-index: 100;
  left: var(--space-3);
  top: var(--space-3);
  transform: translateY(-180%);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  color: var(--color-text-inverse);
  background: var(--color-accent);
}
.skip-link:focus {
  transform: translateY(0);
}
.eyebrow {
  color: var(--color-accent);
  font-family: var(--font-display);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.muted {
  color: var(--color-text-muted);
}

/* Shared glyph states — see glyphs.tsx. */
.glyph-active {
  color: var(--color-accent);
}

/* Buttons. Bare <button> elements stay unstyled so components own their
 * chrome; these are the two product-wide text buttons and the icon button. */
.primary-button,
.secondary-button {
  display: inline-flex;
  min-height: var(--control-slim);
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--motion-fast) var(--ease-standard),
    background var(--motion-fast);
}
.primary-button:active,
.secondary-button:active {
  transform: scale(0.96);
}
.primary-button:disabled,
.secondary-button:disabled {
  opacity: 0.6;
  cursor: default;
}
.primary-button {
  color: var(--color-on-accent);
  background: var(--color-accent);
}
@media (hover: hover) and (pointer: fine) {
  .primary-button:hover {
    background: var(--color-accent-strong);
  }
}
.secondary-button {
  color: var(--color-text);
  border-color: var(--glass-border);
  background: var(--glass-2);
  backdrop-filter: var(--blur-glass);
}
@media (hover: hover) and (pointer: fine) {
  .secondary-button:hover {
    background: var(--glass-3);
  }
}
.primary-button svg,
.secondary-button svg {
  width: 1.1rem;
}
.icon-button {
  display: inline-grid;
  flex: none;
  min-width: var(--control-min);
  min-height: var(--control-min);
  padding: 0;
  place-items: center;
  border: 0;
  border-radius: var(--radius-pill);
  color: inherit;
  background: transparent;
  cursor: pointer;
}
/* Icon buttons that sit in a top bar. */
.icon-button--bar {
  border: 1px solid var(--glass-border);
  background: var(--glass-1);
}
@media (hover: hover) and (pointer: fine) {
  .icon-button--bar:hover {
    background: var(--glass-2);
  }
}
.icon-button--bar svg {
  width: 1.1rem;
}

/* Empty and error surfaces. */
.empty-state,
.error-state {
  margin: var(--space-5);
  padding: var(--space-8);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
  background: var(--glass-1);
  text-align: center;
}
.empty-state h2,
.error-state h2 {
  margin: 0 0 var(--space-3);
  color: var(--color-text);
}
.empty-state p,
.error-state p {
  margin: 0 0 var(--space-3);
}
.empty-state p:last-child,
.error-state p:last-child {
  margin-bottom: 0;
}
.empty-state > svg,
.error-state > svg {
  margin: 0 auto var(--space-3);
}
.empty-state__actions,
.error-state__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}
.error-state {
  border-color: color-mix(in srgb, var(--color-danger) 40%, transparent);
  color: var(--color-text);
  background: var(--rate-bad-soft);
}
.form-error {
  margin: var(--space-2) 0 0;
  color: var(--color-danger);
  font-size: var(--text-md);
}

/* Loading placeholders hold invisible for --loading-delay, then fade in —
 * fast responses replace them before they ever paint. */
.loading-reveal {
  opacity: 0;
  animation: loading-reveal-in var(--motion-fast) var(--ease-standard)
    calc(var(--loading-delay) - var(--loading-elapsed, 0ms)) forwards;
}
.loading-reveal .loading-reveal {
  opacity: 1;
  animation: none;
}
@keyframes loading-reveal-in {
  to {
    opacity: 1;
  }
}
.loading-text {
  margin: var(--space-4) 0;
  color: var(--color-text-muted);
  text-align: center;
}
/* First decode reveals softly; previously decoded artwork stays visible on Back. */
:where(img.fade-in-img:not(.is-cached)) {
  transition: opacity var(--motion-fast) var(--ease-standard);
}
img.fade-in-img:not(.is-loaded) {
  opacity: 0;
}
[data-motion="reduced"] img.fade-in-img {
  transition: none;
}
/* Full-screen experiences (Rate, Search) blur-fade in over the shell. */
@keyframes overlay-in {
  from {
    opacity: 0;
    filter: blur(14px);
  }
  to {
    opacity: 1;
    filter: blur(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .loading-reveal {
    animation-duration: 1ms;
  }
  :where(img.fade-in-img) {
    transition: none;
  }
}

@font-face {
  /* stylelint-disable-next-line scale-unlimited/declaration-strict-value -- intrinsic family name registers the locally bundled Outfit font */
  font-family: Outfit;
  src: url("/assets/outfit-latin.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

.landing-document {
  /* Marketing documents retain browser pinch zoom outside the app shell. */
  touch-action: auto;
}
.landing-body {
  --font-outfit: "Outfit";
  /* Dark ink on violet keeps the marketing CTAs above AA text contrast.
   * Hover brightens the accent so that contrast also holds on interaction. */
  --color-on-accent: var(--color-canvas);
  --color-accent-strong: color-mix(
    in srgb,
    var(--color-accent) 85%,
    var(--color-text)
  );
  font-family: var(--font-display);
  touch-action: auto;
  background:
    radial-gradient(
      ellipse at 80% 8%,
      var(--color-accent-soft),
      transparent 32%
    ),
    var(--color-canvas);
}
.landing-container {
  max-width: 80rem;
  margin-inline: auto;
  padding-inline: var(--page-pad);
}
.landing-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-6);
}
.landing-brand {
  display: inline-flex;
  align-items: center;
  color: var(--color-text);
  font-weight: 750;
  font-size: var(--text-xl);
  letter-spacing: var(--tracking-tight);
  text-decoration: none;
  white-space: nowrap;
}
.landing-brand img {
  margin-right: var(--space-2);
  border-radius: var(--radius-xs);
}
.landing-brand span {
  color: var(--color-accent);
}
.landing-header nav {
  display: flex;
  align-items: center;
  gap: var(--space-8);
}
.landing-nav-link {
  color: var(--color-text-muted);
  font-size: var(--text-md);
  text-decoration: none;
}
.landing-nav-link[aria-current="page"] {
  color: var(--color-text);
}
.landing-hero {
  display: grid;
  align-items: center;
  grid-template-columns: 1fr 1fr;
  min-height: 48rem;
  gap: var(--space-8);
  padding-block: var(--space-10) var(--space-12);
}
.landing-hero-copy {
  position: relative;
  z-index: 1;
}
.landing-body .eyebrow {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  font-weight: 600;
}
.landing-hero h1 {
  font-size: clamp(
    calc(var(--text-2xl) * 2.5),
    7.5vw,
    calc(var(--text-2xl) * 4)
  );
  line-height: 0.97;
  letter-spacing: calc(var(--tracking-tight) * 2);
  font-weight: 650;
  margin: var(--space-6) 0;
}
.landing-hero h1 span,
.landing-taste h2 span {
  color: var(--color-accent);
}
.landing-lead {
  font-size: var(--text-2xl);
  margin: var(--space-8) 0 var(--space-3);
}
.landing-intro {
  max-width: 28rem;
  color: var(--color-text-muted);
  font-size: var(--text-lg);
  line-height: 1.6;
}
.landing-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block: var(--space-8) var(--space-5);
}
.landing-cta {
  min-height: calc(var(--control-min) + var(--space-2));
  padding-inline: var(--space-6);
  gap: var(--space-4);
  font-size: var(--text-base);
}
.landing-text-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-3);
  color: var(--color-text);
  text-decoration-color: var(--color-accent);
  text-underline-offset: var(--space-1);
  font-size: var(--text-base);
}
.landing-fine-print {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  margin-top: var(--space-3);
}
.landing-hero-art {
  position: relative;
  height: 42rem;
  margin: 0;
}
.landing-orbit {
  position: absolute;
  width: 105%;
  aspect-ratio: 1;
  top: 5%;
  left: -3%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: radial-gradient(
    ellipse,
    var(--color-accent-soft),
    transparent 68%
  );
}
.landing-orbit::after {
  content: "";
  position: absolute;
  inset: 12%;
  border: 1px solid var(--color-border-subtle);
  border-radius: inherit;
}
.landing-phone {
  width: 16rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--space-10);
  background: var(--color-canvas-raised);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
.landing-phone img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--space-8);
}
.landing-phone-back {
  position: absolute;
  left: 0;
  top: 0;
  transform: rotate(-9deg);
}
.landing-phone-front {
  position: absolute;
  right: 0;
  top: var(--space-12);
  transform: rotate(7deg);
}
.landing-screen-label {
  position: absolute;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.landing-marquee {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  border-block: 1px solid var(--color-border);
  padding-block: var(--space-6);
  color: var(--color-text-muted);
  font-size: var(--text-lg);
}
.landing-marquee i {
  font-style: normal;
  color: var(--color-accent);
}
.landing-section {
  padding-block: calc(var(--space-12) * 2);
}
.landing-section-heading {
  margin-bottom: var(--space-12);
}
.landing-section h2 {
  font-size: clamp(
    calc(var(--text-2xl) * 1.4),
    4vw,
    calc(var(--text-2xl) * 2.2)
  );
  font-weight: 550;
  line-height: 1.1;
  letter-spacing: calc(var(--tracking-tight) * 1.5);
  margin-block: var(--space-4) var(--space-6);
}
.landing-section p {
  color: var(--color-text-muted);
  font-size: var(--text-lg);
  line-height: 1.65;
  max-width: 34rem;
}
.landing-features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
}
.landing-features article,
.landing-features li {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-6);
}
.landing-feature-number {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--color-accent);
}
.landing-features h3 {
  font-size: var(--text-2xl);
  font-weight: 500;
  line-height: 1.3;
  margin-block: var(--space-5) var(--space-4);
}
.landing-features p {
  font-size: var(--text-base);
}
.landing-taste,
.landing-library {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: calc(var(--space-12) * 2);
  border-top: 1px solid var(--color-border);
}
.landing-taste-visual {
  display: grid;
  place-items: center;
  border-radius: var(--radius-sheet);
  padding: var(--space-10);
  background: radial-gradient(
    ellipse at 50% 75%,
    var(--color-accent-soft),
    var(--color-surface)
  );
}
.landing-taste-visual .landing-phone {
  transform: rotate(-5deg);
  width: 15rem;
}
.landing-rating-key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: 0;
  margin-block: var(--space-6);
  list-style: none;
}
.landing-rating-key li {
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--text-md);
}
.landing-rating-key li:nth-child(1) {
  color: var(--rate-bad);
  background: var(--rate-bad-soft);
}
.landing-rating-key li:nth-child(2) {
  color: var(--rate-fine);
  background: var(--rate-fine-soft);
}
.landing-rating-key li:nth-child(3) {
  color: var(--rate-like);
  background: var(--rate-like-soft);
}
.landing-rating-key li:nth-child(4) {
  color: var(--rate-love);
  background: var(--rate-love-soft);
}
.landing-library figure {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: var(--space-4);
}
.landing-library figcaption {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}
.landing-library .landing-phone {
  width: 14rem;
}
.landing-faq {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: var(--space-12);
  border-top: 1px solid var(--color-border);
}
.landing-faq h2 {
  max-width: 22rem;
}
.landing-faq details {
  border-bottom: 1px solid var(--color-border);
  padding-block: var(--space-5);
}
.landing-faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: var(--space-6);
  font-size: var(--text-lg);
}
.landing-faq summary::-webkit-details-marker {
  display: none;
}
.landing-faq summary span {
  color: var(--color-accent);
  transition: transform var(--motion-fast) var(--ease-standard);
}
.landing-faq details[open] summary span {
  transform: rotate(45deg);
}
.landing-faq details p {
  font-size: var(--text-base);
  margin-bottom: 0;
  animation: landing-reveal var(--motion-standard) var(--ease-standard);
}
.landing-end {
  text-align: center;
  border-radius: var(--radius-sheet);
  background: radial-gradient(
    ellipse at 50% 100%,
    var(--color-accent-soft),
    var(--color-canvas-raised)
  );
  padding-inline: var(--space-6);
  margin-bottom: var(--space-12);
}
.landing-end p {
  margin-inline: auto;
}
.landing-end .landing-actions {
  justify-content: center;
}
.landing-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-8);
  padding-block: var(--space-8);
  border-top: 1px solid var(--color-border);
}
.landing-footer p,
.landing-footer small {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.landing-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-left: auto;
}
.landing-footer nav a {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  padding-block: var(--space-3);
}
.landing-footer small {
  flex-basis: 100%;
}
@keyframes landing-reveal {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@media (hover: hover) {
  .landing-nav-link:hover,
  .landing-text-link:hover,
  .landing-footer nav a:hover {
    color: var(--color-accent);
  }
}
.landing-nav-link,
.landing-text-link,
.landing-footer nav a {
  transition: color var(--motion-fast) var(--ease-standard);
}

@media (max-width: 1000px) {
  .landing-phone {
    width: 13rem;
  }
  .landing-hero {
    min-height: 40rem;
  }
  .landing-hero-art {
    height: 36rem;
  }
  .landing-taste,
  .landing-library {
    gap: var(--space-10);
  }
}
@media (max-width: 759px) {
  .landing-header {
    padding-block: var(--space-4);
  }
  .landing-header nav {
    gap: var(--space-3);
  }
  .landing-nav-link {
    display: none;
  }
  .landing-header .secondary-button {
    font-size: var(--text-sm);
    padding-inline: var(--space-4);
  }
  .landing-hero {
    grid-template-columns: 1fr;
    min-height: 0;
    padding-block: var(--space-8) var(--space-10);
    gap: var(--space-10);
  }
  .landing-hero h1 {
    font-size: clamp(
      calc(var(--text-2xl) * 2.3),
      14vw,
      calc(var(--text-2xl) * 3.3)
    );
  }
  .landing-lead {
    margin-top: var(--space-6);
  }
  .landing-intro {
    font-size: var(--text-base);
    max-width: 32rem;
  }
  .landing-hero-art {
    width: min(100%, 28rem);
    height: 34rem;
    justify-self: center;
  }
  .landing-phone {
    width: 13rem;
  }
  .landing-phone-back {
    left: var(--space-3);
  }
  .landing-phone-front {
    right: var(--space-3);
  }
  .landing-marquee {
    font-size: var(--text-sm);
    gap: var(--space-2);
  }
  .landing-marquee i {
    font-size: var(--text-xs);
  }
  .landing-section {
    padding-block: var(--space-12);
  }
  .landing-features,
  .landing-taste,
  .landing-library,
  .landing-faq {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
  .landing-taste-visual {
    order: 2;
  }
  .landing-section h2 {
    font-size: calc(var(--text-2xl) * 1.5);
  }
  .landing-section p {
    font-size: var(--text-base);
  }
  .landing-library .landing-phone {
    width: 15rem;
  }
  .landing-faq h2 {
    max-width: none;
  }
  .landing-faq summary {
    font-size: var(--text-base);
  }
  .landing-footer nav {
    margin-left: 0;
  }
}
@media (max-width: 380px) {
  .landing-phone {
    width: 11.5rem;
  }
  .landing-hero-art {
    height: 30rem;
  }
  .landing-actions {
    flex-direction: column;
  }
  .landing-cta {
    justify-content: center;
  }
  .landing-brand {
    font-size: var(--text-lg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .landing-faq details p {
    animation: none;
  }
}
