@import "tailwindcss";

/* Enable Tailwind v4's `dark:` variant via the .dark class on <html>,
   which is what next-themes (attribute="class") writes. */
@custom-variant dark (&:where(.dark, .dark *));

/* All brand colors live in OKLCH so we can reason about lightness +
   chroma + hue independently. The hex equivalents (kept here as
   comments) match the values the codebase used pre-migration. The
   tokens get wired into Tailwind via @theme inline below, so each
   one becomes available as bg-{name}, text-{name}, border-{name},
   ring-{name}, etc. */
:root {
  /* Page surfaces — perceptually near-white with a faint cool tint */
  --bg-app: oklch(0.984 0.009 271.7); /* #f7f8ff */
  --text-default: oklch(0.142 0 0); /* #050505 */

  /* Brand purple family — same hue (~271°), three lightness steps */
  --brand: oklch(0.561 0.207 271.8); /* #5266ea */
  --brand-deep: oklch(0.521 0.26 269.4); /* #3847f5 — hovers/CTAs */
  --brand-light: oklch(0.616 0.193 272.1); /* #6478f6 — borders/highlights */
  --brand-tint: oklch(0.949 0.019 269); /* #eef1ff — chip backgrounds */
  --brand-tint-dark: oklch(0.243 0.075 274.3); /* #1f2240 — dark chip bg */

  /* Body / muted text scale (single hue ~277°, varying L) */
  --text-muted-1: oklch(0.235 0.009 277.1); /* #202127 — body secondary */
  --text-muted-2: oklch(0.317 0.013 280.1); /* #33333a — submit intro */
  --text-muted-3: oklch(0.475 0.024 273.7); /* #5b6076 — OG footer */
  --text-muted-4: oklch(0.43 0.014 277.6); /* #4f515c — nav inactive */

  /* Hero cloud gradient stops */
  --gradient-a: oklch(0.918 0.04 247.6); /* #d8e9ff */
  --gradient-b: oklch(0.829 0.067 290.4); /* #c9c6ff */

  /* --- Semantic surface / border / inverse tokens. Components must
       reach for these instead of hardcoded `bg-white dark:bg-stone-900`,
       so theming changes only happen here. --- */

  /* Cards, popovers, panels: opaque elevated surfaces over the page bg */
  --surface: oklch(1 0 0); /* #ffffff */
  --surface-elev: oklch(0.972 0.006 271.7); /* slightly tinted */
  --surface-muted: oklch(0.949 0.008 271.7); /* #eef1ff-ish */

  /* Hairlines: subtle (10%) and strong (30%) on top of --surface */
  --border-base: oklch(0.142 0 0 / 0.1);
  --border-strong: oklch(0.142 0 0 / 0.3);

  /* Inverse pair — used by primary CTAs (bg flips to dark in light mode,
     bg flips to near-white in dark mode; the text token tracks it). */
  --inverse: oklch(0.142 0 0); /* near-black */
  --inverse-hover: oklch(0.235 0.009 277.1);
  --on-inverse: oklch(0.984 0.009 271.7); /* near-white text */

  /* Status chip pairs (Pending / Approved / Rejected). bg = tint, fg = ink. */
  --chip-warning-bg: oklch(0.948 0.066 91); /* amber-100 */
  --chip-warning-fg: oklch(0.391 0.099 64.5); /* amber-900 */
  --chip-success-bg: oklch(0.946 0.052 156); /* emerald-100 */
  --chip-success-fg: oklch(0.385 0.085 159.5); /* emerald-900 */
  --chip-danger-bg: oklch(0.943 0.038 16.5); /* rose-100 */
  --chip-danger-fg: oklch(0.396 0.139 25); /* rose-900 */
  --chip-info-bg: oklch(0.946 0.03 252); /* blue-100 */
  --chip-info-fg: oklch(0.355 0.144 264); /* blue-900 */

  /* Semantic background <-> foreground mapped via theme below */
  --background: var(--bg-app);
  --foreground: var(--text-default);

  /* shadcn semantic tokens — OKLCH, derived from the Petdex brand seed.
     Verified for AA contrast against their paired surfaces. The hue (272°)
     stays constant across primary/ring; destructive picks a separate hue
     (27° = red). */
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.142 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.142 0 0);
  --primary: oklch(0.561 0.207 271.8);
  --primary-foreground: oklch(0.984 0.009 271.7);
  --secondary: oklch(0.949 0.008 271.7);
  --secondary-foreground: oklch(0.235 0.009 277.1);
  --muted: oklch(0.949 0.008 271.7);
  --muted-foreground: oklch(0.475 0.024 273.7);
  --accent: oklch(0.949 0.019 269);
  --accent-foreground: oklch(0.235 0.009 277.1);
  --destructive: oklch(0.55 0.22 27);
  --destructive-foreground: oklch(0.984 0.009 271.7);
  --border: oklch(0.142 0 0 / 0.1);
  --input: oklch(0.142 0 0 / 0.15);
  --ring: oklch(0.561 0.207 271.8);
}

.dark {
  /* In dark mode, the page surface flips to a near-black with the same
     subtle cool tint, and the default text becomes near-white. The
     brand purple gets pushed lighter (L 0.56 -> 0.74) so eyebrow labels
     like "The Codex pet index" / "Petdex creator" stay readable on
     near-black surfaces. brand-deep (used as $ prefix in CommandLine)
     also gets boosted; brand-tint flips to a deep purple chip bg. */
  --bg-app: oklch(0.157 0.004 285.7); /* #0a0a0c */
  --text-default: oklch(0.949 0.002 286.2); /* #f0f0f3 */

  --brand: oklch(0.745 0.165 272);
  --brand-deep: oklch(0.795 0.15 270);
  --brand-light: oklch(0.7 0.18 272);

  /* Muted text scale flips: in light mode --text-muted-1 was nearly
     black for body secondary, in dark mode it should be a slightly
     dimmed near-white. We keep the same hue (~277°) and invert the
     L axis so the visual hierarchy (1 = strongest, 4 = weakest)
     stays consistent. */
  --text-muted-1: oklch(0.88 0.01 277); /* near-white body */
  --text-muted-2: oklch(0.76 0.012 280); /* secondary */
  --text-muted-3: oklch(0.64 0.015 274); /* dim */
  --text-muted-4: oklch(0.56 0.014 277.5); /* very dim — nav inactive */

  /* Surface tokens flip to near-black variants. --surface is the base
     card bg, --surface-elev is the slightly lighter elevated panel,
     --surface-muted is for chip-style fills inside cards. */
  --surface: oklch(0.215 0.005 285.7); /* stone-900 ish */
  --surface-elev: oklch(0.26 0.005 285.7);
  --surface-muted: oklch(0.3 0.005 285.7);

  /* Borders flip to white-on-dark hairlines */
  --border-base: oklch(1 0 0 / 0.1);
  --border-strong: oklch(1 0 0 / 0.3);

  /* Inverse flips: in dark mode primary CTAs are near-white with dark
     text. on-inverse stays "the readable text on top of --inverse". */
  --inverse: oklch(0.949 0.002 286.2); /* near-white */
  --inverse-hover: oklch(0.88 0.01 277);
  --on-inverse: oklch(0.157 0.004 285.7); /* near-black text */

  /* Status chips: same hue as light mode, but bg becomes a dim tint
     (low L, low chroma) and fg becomes a bright ink so the chip stays
     legible on the dark surface. */
  --chip-warning-bg: oklch(0.281 0.044 64 / 0.5);
  --chip-warning-fg: oklch(0.838 0.14 88); /* amber-300 */
  --chip-success-bg: oklch(0.281 0.044 159 / 0.5);
  --chip-success-fg: oklch(0.819 0.13 158); /* emerald-300 */
  --chip-danger-bg: oklch(0.281 0.046 25 / 0.5);
  --chip-danger-fg: oklch(0.812 0.11 18); /* rose-300 */
  --chip-info-bg: oklch(0.281 0.045 264 / 0.5);
  --chip-info-fg: oklch(0.812 0.105 252); /* blue-300 */

  --background: var(--bg-app);
  --foreground: var(--text-default);

  /* shadcn semantic tokens — dark mode. L values are flipped relative to
     light mode (card/popover use --surface; foregrounds become near-white).
     --primary is brightened (0.745) so chrome on near-black surfaces stays
     readable. --muted-foreground bumped to L=0.7 to clear AA normal text. */
  --card: oklch(0.215 0.005 285.7);
  --card-foreground: oklch(0.949 0.002 286.2);
  --popover: oklch(0.215 0.005 285.7);
  --popover-foreground: oklch(0.949 0.002 286.2);
  --primary: oklch(0.745 0.165 272);
  --primary-foreground: oklch(0.157 0.004 285.7);
  --secondary: oklch(0.3 0.005 285.7);
  --secondary-foreground: oklch(0.88 0.01 277);
  --muted: oklch(0.3 0.005 285.7);
  --muted-foreground: oklch(0.7 0.015 277);
  --accent: oklch(0.243 0.075 274.3);
  --accent-foreground: oklch(0.88 0.01 277);
  --destructive: oklch(0.7 0.18 27);
  --destructive-foreground: oklch(0.157 0.004 285.7);
  --border: oklch(1 0 0 / 0.1);
  --input: oklch(1 0 0 / 0.15);
  --ring: oklch(0.745 0.165 272);
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-brand: var(--brand);
  --color-brand-deep: var(--brand-deep);
  --color-brand-light: var(--brand-light);
  --color-brand-tint: var(--brand-tint);
  --color-brand-tint-dark: var(--brand-tint-dark);
  --color-muted-1: var(--text-muted-1);
  --color-muted-2: var(--text-muted-2);
  --color-muted-3: var(--text-muted-3);
  --color-muted-4: var(--text-muted-4);
  --color-gradient-a: var(--gradient-a);
  --color-gradient-b: var(--gradient-b);

  /* Semantic surface / border / inverse / chip tokens. Use these in
     components instead of bg-white / dark:bg-stone-900 pairs. */
  --color-surface: var(--surface);
  --color-surface-elev: var(--surface-elev);
  --color-surface-muted: var(--surface-muted);
  --color-border-base: var(--border-base);
  --color-border-strong: var(--border-strong);
  --color-inverse: var(--inverse);
  --color-inverse-hover: var(--inverse-hover);
  --color-on-inverse: var(--on-inverse);
  --color-chip-warning-bg: var(--chip-warning-bg);
  --color-chip-warning-fg: var(--chip-warning-fg);
  --color-chip-success-bg: var(--chip-success-bg);
  --color-chip-success-fg: var(--chip-success-fg);
  --color-chip-danger-bg: var(--chip-danger-bg);
  --color-chip-danger-fg: var(--chip-danger-fg);
  --color-chip-info-bg: var(--chip-info-bg);
  --color-chip-info-fg: var(--chip-info-fg);

  /* shadcn semantic color expansions for Tailwind v4. These let
     primitives use bg-card, text-primary-foreground, ring-ring, etc. */
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-foreground: var(--destructive-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);

  --font-sans: var(--font-geist-sans);
  --font-mono: var(--font-geist-mono);
}

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  background: var(--background);
  color: var(--foreground);
}

.build-update-prompt {
  transform-origin: bottom center;
  animation: build-update-enter 360ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.build-update-prompt [data-build-update-icon] {
  animation: build-update-icon 520ms cubic-bezier(0.16, 1, 0.3, 1) 80ms both;
}

@keyframes build-update-enter {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.985);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes build-update-icon {
  0% {
    opacity: 0.72;
    transform: rotate(-14deg) scale(0.86);
  }

  65% {
    opacity: 1;
    transform: rotate(7deg) scale(1.04);
  }

  100% {
    opacity: 1;
    transform: rotate(0deg) scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .build-update-prompt,
  .build-update-prompt [data-build-update-icon] {
    animation: none;
  }
}

button,
a,
input {
  font: inherit;
}

.petdex-cloud {
  background:
    radial-gradient(
      circle at 49% 18%,
      rgb(255 255 255 / 0.96) 0 13%,
      rgb(255 255 255 / 0.62) 24%,
      transparent 42%
    ),
    radial-gradient(
      circle at 12% 68%,
      rgb(216 233 255 / 0.9) 0 20%,
      transparent 48%
    ),
    radial-gradient(
      circle at 83% 44%,
      rgb(100 120 246 / 0.82) 0 25%,
      rgb(82 102 234 / 0.62) 43%,
      transparent 68%
    ),
    linear-gradient(120deg, #d8e9ff 0%, #f7f8ff 47%, #c9c6ff 100%);
}

/* Dark variant: same composition but the cloud whites become deep
   purples and the linear-gradient base flips to a near-black. The
   accent purples gain transparency so they still glow without
   overpowering the page surface. */
.dark .petdex-cloud {
  background:
    radial-gradient(
      circle at 49% 18%,
      rgb(60 70 130 / 0.45) 0 13%,
      rgb(40 50 100 / 0.3) 24%,
      transparent 42%
    ),
    radial-gradient(
      circle at 12% 68%,
      rgb(30 50 110 / 0.55) 0 20%,
      transparent 48%
    ),
    radial-gradient(
      circle at 83% 44%,
      rgb(82 102 234 / 0.45) 0 25%,
      rgb(56 71 245 / 0.3) 43%,
      transparent 68%
    ),
    linear-gradient(120deg, #0d1230 0%, #0a0a0c 47%, #1a1238 100%);
}

.petdex-cloud::before {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: "";
  background:
    radial-gradient(
      ellipse at 18% 48%,
      rgb(255 255 255 / 0.28),
      transparent 34%
    ),
    radial-gradient(
      ellipse at 30% 38%,
      rgb(255 255 255 / 0.18),
      transparent 28%
    ),
    linear-gradient(
      100deg,
      rgb(255 255 255 / 0.16),
      transparent 35%,
      rgb(255 255 255 / 0.1)
    );
  filter: blur(18px);
}

/* Checkerboard transparency tile background. Light mode shows the
   classic photoshop pattern (white + light-stone diamonds); dark mode
   uses near-black + warm dark grey so it reads as "transparent" on
   either theme without ever flipping to a giant white square. */
.pet-checkerboard {
  background:
    linear-gradient(45deg, #e7e5e4 25%, transparent 25%),
    linear-gradient(-45deg, #e7e5e4 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #e7e5e4 75%),
    linear-gradient(-45deg, transparent 75%, #e7e5e4 75%);
  background-size: 24px 24px;
  background-position:
    0 0,
    0 12px,
    12px -12px,
    -12px 0;
  background-color: #ffffff;
}

.dark .pet-checkerboard {
  background:
    linear-gradient(45deg, #2a2a2e 25%, transparent 25%),
    linear-gradient(-45deg, #2a2a2e 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #2a2a2e 75%),
    linear-gradient(-45deg, transparent 75%, #2a2a2e 75%);
  background-size: 24px 24px;
  background-position:
    0 0,
    0 12px,
    12px -12px,
    -12px 0;
  background-color: #15151a;
}

/* The "stage" behind every pet sprite: a soft white halo on light
   mode that helps the pixel art stand out, a muted stone halo on
   dark mode. Used by every PetCard variant via a className so we
   stop pasting the same inline style style={{ background: ... }}
   in five places and keep dark theming in one spot. */
.pet-sprite-stage {
  background: radial-gradient(
    circle at 50% 38%,
    rgb(255 255 255 / 0.95) 0%,
    rgb(238 241 255 / 0.55) 55%,
    transparent 80%
  );
  /* Pause sprite animation cost when the stage is offscreen. Browsers
     skip rendering and layout for elements with content-visibility: auto
     until they enter the viewport, which stops the @keyframes
     `steps()` animation on .pet-sprite from advancing while the card is
     out of view. contain-intrinsic-size reserves layout space so the
     scroll position does not jump as cards enter/leave the viewport.
     Safari supports this from 18; older browsers fall back to always
     animating (no visible regression). */
  content-visibility: auto;
  contain-intrinsic-size: 280px 220px;
}

.dark .pet-sprite-stage {
  background: radial-gradient(
    circle at 50% 38%,
    rgb(64 64 70 / 0.85) 0%,
    rgb(40 40 48 / 0.55) 55%,
    transparent 80%
  );
}

.featured-pin-card {
  box-shadow:
    0 0 0 1px rgb(100 120 246 / 0.18),
    0 18px 45px -22px rgb(82 102 234 / 0.5);
}

.dark .featured-pin-card {
  box-shadow:
    0 0 0 1px rgb(129 145 255 / 0.16),
    0 26px 84px -38px rgb(0 0 0 / 0.95),
    0 0 42px -30px rgb(100 120 246 / 0.55);
}

.dark .featured-pin-stage {
  background: radial-gradient(
    circle at 50% 42%,
    rgb(49 49 56 / 0.62) 0%,
    rgb(31 31 38 / 0.62) 52%,
    transparent 78%
  );
}

.glass-panel {
  background: rgb(255 255 255 / 0.68);
  border: 1px solid rgb(255 255 255 / 0.72);
  box-shadow: 0 24px 80px rgb(42 55 120 / 0.16);
  backdrop-filter: blur(18px);
}

.dark .glass-panel {
  background: rgb(30 30 38 / 0.68);
  border: 1px solid rgb(255 255 255 / 0.1);
  box-shadow: 0 24px 80px rgb(0 0 0 / 0.4);
}

.pet-sprite-frame {
  --pet-scale: 1;
  width: calc(192px * var(--pet-scale));
  height: calc(208px * var(--pet-scale));
  overflow: hidden;
  /* Promote to its own paint layer + isolate so the browser does not
     evict the WebP decode buffer when the card scrolls off-screen.
     Without this, sprites flicker (decode -> paint -> evict -> redecode)
     on every scroll back into view. */
  contain: layout paint;
}

.pet-sprite {
  --sprite-row: 0;
  --sprite-frames: 6;
  --sprite-duration: 1100ms;
  --sprite-y: calc(var(--sprite-row) * -208px);
  --sprite-end-x: calc(var(--sprite-frames) * -192px);
  width: 192px;
  height: 208px;
  background-image: var(--sprite-url);
  background-repeat: no-repeat;
  background-size: 1536px 1872px;
  image-rendering: pixelated;
  /* translateZ(0) forces a GPU-composited layer so background-image
     decode + animation stay on the compositor thread instead of being
     re-rasterized on each scroll-induced repaint. Combined with
     contain:paint on the parent, the WebP stays decoded. */
  transform: scale(var(--pet-scale)) translateZ(0);
  transform-origin: top left;
  will-change: background-position;
  animation: pet-state var(--sprite-duration) steps(var(--sprite-frames))
    infinite;
}

@keyframes pet-state {
  from {
    background-position: 0 var(--sprite-y);
  }

  to {
    background-position: var(--sprite-end-x) var(--sprite-y);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pet-sprite {
    animation: none;
  }
}

/* Static variant for list contexts (leaderboard rows, owner mini-grids).
   Renders only the first frame of a chosen state row — no infinite keyframe, no paint
   thrash on scroll. Same dimensions as .pet-sprite so layouts can
   swap one for the other without touching parent CSS. */
.pet-sprite-static {
  --sprite-row: 0;
  --sprite-y: calc(var(--sprite-row) * -208px);
  width: 192px;
  height: 208px;
  background-image: var(--sprite-url);
  background-repeat: no-repeat;
  background-size: 1536px 1872px;
  background-position: 0 var(--sprite-y);
  image-rendering: pixelated;
  transform: scale(var(--pet-scale, 1));
  transform-origin: top left;
}

/* Tap-me hint ring on the interactive PetFloater. A brand-tinted glow
   pulses outward to invite the user to grab the pet on first visit.
   We render two staggered rings (the second uses --late) so the
   pulses overlap and create a continuous "breathing" effect. */
.pet-floater-hint-ring {
  box-shadow:
    0 0 0 0 oklch(from var(--brand) l c h / 0.55),
    0 0 24px 8px oklch(from var(--brand) l c h / 0.18);
  animation: pet-floater-hint 1.6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  will-change: transform, box-shadow, opacity;
}

.pet-floater-hint-ring--late {
  animation-delay: 0.8s;
}

@keyframes pet-floater-hint {
  0% {
    transform: scale(1);
    box-shadow:
      0 0 0 0 oklch(from var(--brand) l c h / 0.55),
      0 0 18px 4px oklch(from var(--brand) l c h / 0.25);
    opacity: 1;
  }
  70% {
    transform: scale(1.2);
    box-shadow:
      0 0 0 14px oklch(from var(--brand) l c h / 0),
      0 0 30px 12px oklch(from var(--brand) l c h / 0);
    opacity: 0;
  }
  100% {
    transform: scale(1.2);
    box-shadow:
      0 0 0 0 oklch(from var(--brand) l c h / 0),
      0 0 0 0 oklch(from var(--brand) l c h / 0);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pet-floater-hint-ring {
    animation: none;
    box-shadow: 0 0 0 2px oklch(from var(--brand) l c h / 0.45);
    opacity: 1;
  }
}
