/* ===========================
   Listpad — theme + animations
   ===========================
   CSS variables hold RGB tuples so Tailwind's rgb(var() / <alpha>) works.
*/

html {
  /* LIGHT MODE defaults — warm paper, not stark white */
  --bg-ink: 250 246 237;
  --bg-paper: 243 235 217;
  --bg-vellum: 237 226 204;
  --bg-edge: 214 200 168;
  --text-cream: 42 36 25;
  --text-taupe: 92 82 64;
  --text-ash: 138 125 101;
  --grain-opacity: 0.025;
  color-scheme: light;
}

html.dark {
  --bg-ink: 14 13 10;
  --bg-paper: 22 20 15;
  --bg-vellum: 28 26 20;
  --bg-edge: 42 38 32;
  --text-cream: 245 239 228;
  --text-taupe: 163 154 139;
  --text-ash: 109 102 91;
  --grain-opacity: 0.04;
  color-scheme: dark;
}

/* Apply transitions only after first paint to avoid initial flicker */
html.theme-ready body,
html.theme-ready body * {
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.font-display { font-variation-settings: "opsz" 120; }
h1.font-display, h2.font-display { font-variation-settings: "opsz" 144; }

/* Grain overlay */
.grain-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
}

/* Scrollbar */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: rgb(var(--bg-ink)); }
::-webkit-scrollbar-thumb { background: rgb(var(--bg-edge)); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: rgb(var(--text-ash)); }
* {
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--bg-edge)) rgb(var(--bg-ink));
}

::selection { background: #d4a72c; color: #0e0d0a; }
::-moz-selection { background: #d4a72c; color: #0e0d0a; }

*:focus-visible {
  outline: 2px solid #d4a72c;
  outline-offset: 2px;
  border-radius: 4px;
}
input:focus-visible, textarea:focus-visible, select:focus-visible { outline: none; }

/* No-scrollbar utility for horizontal scrollers */
.ticker-scroll { scrollbar-width: none; -ms-overflow-style: none; }
.ticker-scroll::-webkit-scrollbar { display: none; }

/* Auto-scrolling marquee for the news + price strips */
.marquee {
  display: flex;
  overflow: hidden;
  user-select: none;
}
.marquee__track {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 1.5rem;
  min-width: 100%;
  animation: marquee-scroll var(--marquee-duration, 40s) linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .marquee { overflow-x: auto; }
}

/* Theme toggle icon swap */
.theme-toggle-icon-sun { display: none; }
.theme-toggle-icon-moon { display: inline; }
html.dark .theme-toggle-icon-sun { display: inline; }
html.dark .theme-toggle-icon-moon { display: none; }

/* ===========================
   Price flash animations
   ===========================
   When a price updates, the cell flashes green or orange for 700ms.
   Uses background-color, not text color, so the actual price text
   stays readable.
*/
@keyframes priceFlashUp {
  0%   { background-color: rgba(148, 193, 51, 0.0); }
  20%  { background-color: rgba(148, 193, 51, 0.35); }
  100% { background-color: rgba(148, 193, 51, 0.0); }
}
@keyframes priceFlashDown {
  0%   { background-color: rgba(234, 88, 12, 0.0); }
  20%  { background-color: rgba(234, 88, 12, 0.35); }
  100% { background-color: rgba(234, 88, 12, 0.0); }
}
.price-flash-up {
  animation: priceFlashUp 700ms ease-out;
  border-radius: 4px;
  padding: 2px 4px;
  margin: -2px -4px;
}
.price-flash-down {
  animation: priceFlashDown 700ms ease-out;
  border-radius: 4px;
  padding: 2px 4px;
  margin: -2px -4px;
}

/* ===========================
   Skeleton shimmer (loading placeholders)
   =========================== */
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(
    90deg,
    rgb(var(--bg-paper)) 0%,
    rgb(var(--bg-vellum)) 50%,
    rgb(var(--bg-paper)) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
  border-radius: 4px;
}

/* ===========================
   Pulse dot — live indicator
   =========================== */
@keyframes livePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(148, 193, 51, 0.5); }
  50%      { box-shadow: 0 0 0 6px rgba(148, 193, 51, 0); }
}
.live-dot {
  animation: livePulse 2s infinite;
}

/* Fear & Greed semicircle gauge needle. The inline transform sets the real
   angle from the value; this adds a smooth settle-in on load plus a tiny live
   sway so the gauge reads as active without changing the published value. */
.fg-needle {
  transition: transform 900ms cubic-bezier(0.22, 1, 0.36, 1);
  animation: fgSway 4s ease-in-out infinite;
}
@keyframes fgSway {
  0%, 100% { filter: none; }
  50%      { filter: drop-shadow(0 0 2px rgba(245, 239, 228, 0.6)); }
}
@media (prefers-reduced-motion: reduce) {
  .fg-needle { animation: none; }
}
