/* ============================================
   Quinpix — Legacy & decorative styles
   Theme-token aware; brand colors are layered through .text-brand /
   .bg-brand / .btn-brand / .text-brand-pink / .text-brand-blue defined
   in tailwind.input.css. DaisyUI v4 exposes theme variables (--b1/--bc/etc.)
   in OKLCH form, so any wraps here use oklch().
   ============================================ */

html {
  scroll-behavior: smooth;
}

body {
  font-family: Georgia, "Times New Roman", Times, serif;
}

@font-face {
  font-family: "Inglesa Script Variable";
  src:
    local("Inglesa Script Variable"),
    url("/static/assets/fonts/Inglesa Script Variable/Inglesa Script Variable.woff2") format("woff2"),
    url("/static/assets/fonts/Inglesa Script Variable/Inglesa Script Variable.woff") format("woff"),
    url("/static/assets/fonts/Inglesa Script Variable/Inglesa Script Variable.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Gwendolyn — premium cursive wordmark.
   Regular drives the everyday script; Bold is reserved for hero/title use. */
@font-face {
  font-family: "Gwendolyn";
  src:
    local("Gwendolyn Regular"),
    local("Gwendolyn-Regular"),
    url("/static/assets/fonts/Gwendolyn/Gwendolyn-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Gwendolyn";
  src:
    local("Gwendolyn Bold"),
    local("Gwendolyn-Bold"),
    url("/static/assets/fonts/Gwendolyn/Gwendolyn-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

html[data-theme="pastel"] {
  color-scheme: light;
  /* Quinpix business-card palette: blush surfaces, crimson hearts, rose-gold trim. */
  --brand-bg-a: #fbeee7;
  --brand-bg-b: #f4d8cb;
  --brand-bg-c: #ecc1ae;
  --brand-hero-start: #5c131f;
  --brand-hero-mid: #8b1e2d;
  --brand-hero-end: #2d0e13;
  --brand-glow: rgba(176, 120, 89, 0.32);
  --brand-card-border: rgba(139, 30, 45, 0.22);
}

html[data-theme="dracula"] {
  color-scheme: dark;
  --brand-bg-a: #0e0723;
  --brand-bg-b: #1b0f42;
  --brand-bg-c: #2b0d4f;
  --brand-hero-start: #2e1065;
  --brand-hero-mid: #4c1d95;
  --brand-hero-end: #1e1b4b;
  --brand-glow: rgba(217, 158, 255, 0.26);
  --brand-card-border: rgba(196, 181, 253, 0.26);
}

.text-app-body {
  color: oklch(var(--bc) / 0.88);
}

.text-app-muted {
  color: oklch(var(--bc) / 0.8);
}

.text-app-soft {
  color: oklch(var(--bc) / 0.74);
}

.text-app-inverse {
  color: #ffffff;
}

.text-app-inverse-muted {
  color: rgba(255, 255, 255, 0.9);
}

[data-theme="dracula"] .text-app-inverse-muted {
  color: rgba(255, 255, 255, 0.92);
}

/* ============================================
   Hero wordmark — rendered as a webp logo image, swapped per theme.
   - Light (pastel): rose-gold confirmed logo.
   - Dark (dracula): deep purple confirmed logo.
   Two <img> elements share a stacking wrapper; [data-theme] hides the
   inactive one. Both images share intrinsic dimensions so the wrapper
   reserves a stable aspect-ratio box (no CLS regardless of which variant
   resolves first).
   ============================================ */
.hero-wordmark {
  position: relative;
}

.hero-wordmark__img {
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* Default theme (pastel / light) shows the light logo; the dark one
   collapses out of the layout. */
html[data-theme="pastel"] .hero-wordmark__img--light {
  display: block;
}

html[data-theme="pastel"] .hero-wordmark__img--dark {
  display: none;
}

html[data-theme="dracula"] .hero-wordmark__img--light {
  display: none;
}

html[data-theme="dracula"] .hero-wordmark__img--dark {
  display: block;
}

/* Cursive / script wordmark — mirrors the Quinpix logo.
   Gwendolyn is the primary face; Inglesa / Allura remain as graceful fallbacks
   while the variable font streams. */
.font-script {
  font-family: 'Gwendolyn', 'Inglesa Script Variable', 'Allura', cursive;
  font-weight: 400;
  letter-spacing: 0.008em;
  line-height: 1.1;
  /* Subtle inked baseline — adds depth without becoming a "shadow". */
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.14);
}

/* Hero / title use — Gwendolyn Bold reads with the weight a wordmark needs. */
.font-script-bold {
  font-family: 'Gwendolyn', 'Inglesa Script Variable', 'Allura', cursive;
  font-weight: 700;
  letter-spacing: 0.004em;
  line-height: 1.05;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.16);
}

/* Promote any `.font-script` that's *also* used as a hero wordmark to Bold —
   detected by the large-display Tailwind size classes the templates already
   apply. Keeps existing markup unchanged while delivering a heavier, more
   premium cursive on the headline beats. */
.font-script.text-5xl,
.font-script.text-6xl,
.font-script.text-7xl,
.font-script.text-8xl,
.font-script.text-9xl {
  font-weight: 700;
  letter-spacing: 0.004em;
}

[data-theme="dracula"] .font-script,
[data-theme="dracula"] .font-script-bold {
  /* On dark surfaces, a faint warm glow lifts the cursive without smearing. */
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.45),
    0 0 14px rgba(196, 181, 253, 0.18);
}

.font-serif-display {
  font-family: 'Playfair Display', Georgia, "Times New Roman", serif;
  font-weight: 600;
}

/* ============================================
   Header / title subtle accents
   - Pastel (light): a hairline rose-gold underline with a crimson centerpoint.
   - Dracula (dark): a hairline lavender underline with a soft pink centerpoint.
   Opt-in via `.title-accent`; the underline reads as a refined keyline beneath
   the title, never as decoration heavy enough to draw the eye on its own.
   ============================================ */
.title-accent {
  position: relative;
  display: inline-block;
}

.title-accent::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: -0.35em;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(176, 120, 89, 0.55) 25%,
    rgba(139, 30, 45, 0.85) 50%,
    rgba(176, 120, 89, 0.55) 75%,
    transparent 100%
  );
  pointer-events: none;
}

[data-theme="dracula"] .title-accent::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(196, 181, 253, 0.45) 25%,
    rgba(244, 114, 182, 0.85) 50%,
    rgba(196, 181, 253, 0.45) 75%,
    transparent 100%
  );
}

/* A small flourish above section headlines — opt-in via `.title-flourish`. */
.title-flourish::before {
  content: "";
  display: block;
  width: 2.25rem;
  height: 2px;
  margin: 0 auto 0.75rem;
  border-radius: 999px;
  background: linear-gradient(90deg, #B07859 0%, #8B1E2D 50%, #B07859 100%);
  opacity: 0.85;
}

[data-theme="dracula"] .title-flourish::before {
  background: linear-gradient(90deg, #C4B5FD 0%, #F472B6 50%, #C4B5FD 100%);
}

/* ============================================
   Subtle interaction motion — premium, restrained.
   GPU-only (transform / opacity), gated by prefers-reduced-motion.
   ============================================ */
@media (prefers-reduced-motion: no-preference) {
  /* Script wordmarks lean gently on hover — never more than 1-2px of motion. */
  .font-script,
  .font-script-bold {
    transition:
      transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1),
      text-shadow 0.45s ease;
  }

  a:hover > .font-script,
  a:focus-visible > .font-script,
  .font-script:hover {
    transform: translate3d(0, -1px, 0);
  }

  [data-theme="pastel"] a:hover > .font-script,
  [data-theme="pastel"] .font-script:hover {
    text-shadow:
      0 1px 0 rgba(0, 0, 0, 0.18),
      0 0 18px rgba(139, 30, 45, 0.22);
  }

  [data-theme="dracula"] a:hover > .font-script,
  [data-theme="dracula"] .font-script:hover {
    text-shadow:
      0 1px 0 rgba(0, 0, 0, 0.45),
      0 0 22px rgba(196, 181, 253, 0.35);
  }

  /* Title-accent underline draws in on hover — composited width via scaleX. */
  .title-accent::after {
    transform: scaleX(0.72);
    transform-origin: center;
    transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.3s ease;
    opacity: 0.85;
  }

  .title-accent:hover::after,
  .title-accent:focus-within::after {
    transform: scaleX(1);
    opacity: 1;
  }

  /* Inline SVG icons inside links and buttons get a tasteful wink on hover —
     never more than ~8% scale and a hair of lift. */
  a:hover > .icon-svg,
  button:hover > .icon-svg,
  .btn:hover > .icon-svg,
  .btn-brand:hover > .icon-svg,
  .btn-brand-outline:hover > .icon-svg {
    transform: translate3d(0, -1px, 0) scale(1.08);
  }

  a > .icon-svg,
  button > .icon-svg,
  .btn > .icon-svg {
    transition: transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1), color 0.25s ease;
    will-change: transform;
  }

  /* Inline decorative SVGs (sparkles, hearts) get a slow gentle drift. */
  .heart-marker {
    transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1), color 0.3s ease;
  }

  a:hover .heart-marker,
  button:hover .heart-marker,
  .heart-marker:hover {
    transform: translateY(-0.12em) scale(1.08);
  }

  /* Brand buttons lift a touch on hover — already animate background, this
     adds the y-shift without overriding existing transitions. */
  .btn-brand,
  .btn-brand-outline {
    will-change: transform, box-shadow;
  }

  .btn-brand:hover,
  .btn-brand-outline:hover {
    transform: translate3d(0, -1px, 0);
  }

  .btn-brand:active,
  .btn-brand-outline:active {
    transform: translate3d(0, 0, 0);
  }

  /* Navbar links — underline grows from center on hover. Pure transform, no
     reflow. */
  .site-nav__link {
    position: relative;
  }

  .site-nav__link::after {
    content: "";
    position: absolute;
    left: 1rem;
    right: 1rem;
    bottom: 0.35rem;
    height: 1.5px;
    border-radius: 999px;
    background: currentColor;
    opacity: 0;
    transform: scaleX(0.2);
    transform-origin: center;
    transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.25s ease;
    pointer-events: none;
  }

  .site-nav__link:hover::after,
  .site-nav__link:focus-visible::after {
    transform: scaleX(1);
    opacity: 0.55;
  }
}

@media (prefers-reduced-motion: reduce) {
  .font-script,
  .font-script-bold,
  .btn-brand,
  .btn-brand-outline,
  a > .icon-svg,
  button > .icon-svg,
  .btn > .icon-svg,
  .title-accent::after,
  .heart-marker,
  .site-nav__link::after {
    transition: none !important;
    transform: none !important;
    animation: none !important;
  }
}

/* Hero gradient — intentionally dark on both themes so the white hero
   text stays legible regardless of light/dark mode. In light mode the
   tints are crimson + rose-gold + black (business-card palette); in dark
   mode they remain deep purple. */
.hero-gradient {
  background:
    radial-gradient(1100px 600px at 85% 15%, color-mix(in oklab, var(--brand-glow), transparent 24%), transparent 60%),
    radial-gradient(900px 520px at 10% 90%, rgba(139, 30, 45, 0.30), transparent 60%),
    radial-gradient(800px 480px at 50% 110%, rgba(176, 120, 89, 0.24), transparent 65%),
    linear-gradient(135deg, var(--brand-hero-start) 0%, var(--brand-hero-mid) 55%, var(--brand-hero-end) 100%);
  color: #ffffff;
  border: 1px solid var(--brand-card-border);
}

[data-theme="dracula"] .hero-gradient {
  /* Restore the original purple/pink/blue tints for dark mode. */
  background:
    radial-gradient(1100px 600px at 85% 15%, color-mix(in oklab, var(--brand-glow), transparent 24%), transparent 60%),
    radial-gradient(900px 520px at 10% 90%, rgba(236, 72, 153, 0.22), transparent 60%),
    radial-gradient(800px 480px at 50% 110%, rgba(59, 130, 246, 0.2), transparent 65%),
    linear-gradient(135deg, var(--brand-hero-start) 0%, var(--brand-hero-mid) 55%, var(--brand-hero-end) 100%);
  color: #ffffff;
  border: 1px solid var(--brand-card-border);
}

.hero-gradient h1,
.hero-gradient h2,
.hero-gradient h3,
.hero-gradient p {
  color: inherit;
}

.glass-card {
  background: oklch(var(--b1) / 0.74);
  backdrop-filter: blur(10px);
  border: 1px solid var(--brand-card-border);
  box-shadow: 0 10px 30px -18px var(--brand-glow);
}

.site-nav {
  border-bottom: 1px solid oklch(var(--bc) / 0.1);
}

.site-nav__brand {
  min-width: 0;
}

.site-nav__link,
.site-nav__mobile-link {
  letter-spacing: 0.01em;
}

[x-cloak] {
  display: none !important;
}

.site-nav__mobile-drawer {
  will-change: transform;
  height: auto;
  max-height: min(100dvh, 100vh);
  overflow-y: auto;
}

.site-nav__mobile-body {
  overflow-y: auto;
}

.site-nav__mobile-overlay {
  will-change: opacity;
}

@media (max-width: 1023px) {
  .site-nav--mobile-open .site-nav__mobile-hide-open {
    display: none !important;
  }
}

/* Light-mode gradients use the business-card palette
   (crimson → rose gold → ink). Dracula keeps the original purple→pink. */
.accent-gradient {
  background: linear-gradient(135deg, #8B1E2D 0%, #A92438 50%, #B07859 100%);
}

[data-theme="dracula"] .accent-gradient {
  background: linear-gradient(135deg, #5B21B6 0%, #7C3AED 50%, #F472B6 100%);
}

.pink-gradient {
  background: linear-gradient(135deg, #C7475A 0%, #8B1E2D 100%);
}

[data-theme="dracula"] .pink-gradient {
  background: linear-gradient(135deg, #F472B6 0%, #DB2777 100%);
}

.blue-gradient {
  background: linear-gradient(135deg, #DEA88A 0%, #B07859 100%);
}

[data-theme="dracula"] .blue-gradient {
  background: linear-gradient(135deg, #60A5FA 0%, #2563EB 100%);
}

.brand-spectrum-gradient {
  background: linear-gradient(135deg, var(--brand-bg-b) 0%, #8B1E2D 33%, #A92438 66%, #B07859 100%);
}

[data-theme="dracula"] .brand-spectrum-gradient {
  background: linear-gradient(135deg, var(--brand-bg-b) 0%, #7C3AED 33%, #EC4899 66%, #3B82F6 100%);
}

.section-divider {
  background: linear-gradient(90deg, transparent, #8B1E2D, #B07859, #C89070, #8B1E2D, transparent);
  height: 2px;
}

[data-theme="dracula"] .section-divider {
  background: linear-gradient(90deg, transparent, #5B21B6, #EC4899, #3B82F6, #A78BFA, transparent);
}

/* Focus rings — WCAG-compliant 2px outline w/ 2px offset.
   Crimson in light mode (business-card heart accent), lavender in dark mode. */
.site-nav__link:focus-visible,
.site-nav__mobile-link:focus-visible {
  outline: 2px solid #8B1E2D;
  outline-offset: 2px;
}

[data-theme="dracula"] .site-nav__link:focus-visible,
[data-theme="dracula"] .site-nav__mobile-link:focus-visible {
  outline-color: #C4B5FD;
}

.btn:focus-visible,
.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
  outline: 2px solid #8B1E2D;
  outline-offset: 2px;
}

[data-theme="dracula"] .btn:focus-visible,
[data-theme="dracula"] .input:focus-visible,
[data-theme="dracula"] .textarea:focus-visible,
[data-theme="dracula"] .select:focus-visible {
  outline-color: #C4B5FD;
}

.primary-hero {
  padding-top: clamp(0.25rem, 1.2vw, 1rem);
}

/* Heart marker — matches the deep crimson hearts on the Quinpix business card. */
.heart-marker {
  color: #8B1E2D;
  display: inline-block;
  vertical-align: middle;
  transform: translateY(-0.05em);
}

[data-theme="dracula"] .heart-marker {
  color: #F9A8D4;
}

#project-gallery .gallery-card {
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  #project-gallery .gallery-card.gallery-card-visible {
    animation: gallery-fade-up 0.35s ease-out forwards;
  }
}

@media (prefers-reduced-motion: reduce) {
  #project-gallery .gallery-card {
    opacity: 1 !important;
    transform: none !important;
  }
}

@keyframes gallery-fade-up {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

#project-gallery .gallery-line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ============================================
   Project gallery lightbox / overlay
   The overlay is opened only by projectGallery.js. Its closed state MUST win
   the cascade against the global utility classes it also carries (e.g. `.flex`
   → `display:flex`); otherwise the full-screen backdrop and its close/prev/next
   buttons paint on top of the page at load, inert but blocking, with no image.
   An id selector always out-specifies a utility class, so `display:none` here is
   authoritative — the overlay cannot be forced on screen by any global rule and
   can never intercept clicks while closed. JS adds `.is-open` (display) then
   `.is-visible` (opacity) to reveal it. Everything is namespaced under
   #gallery-lightbox so nothing leaks globally, and the fade animates opacity
   only (compositor-friendly, no layout thrash).
   ============================================ */
#gallery-lightbox {
  display: none;
  opacity: 0;
  transition: opacity 0.25s ease;
}

#gallery-lightbox.is-open {
  display: flex;
  align-items: center;
  justify-content: center;
}

#gallery-lightbox.is-open.is-visible {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  #gallery-lightbox {
    transition: none;
  }
}

/* ============================================
   Pricing section — performant, GPU-friendly motion
   - Animates only transform & opacity (never layout-triggering props).
   - Honors prefers-reduced-motion: cards appear instantly, no hover lift.
   - IntersectionObserver toggles .is-visible so animations only run once,
     entering from the bottom of the viewport — no JS animation loop, no
     main-thread work after paint.
   ============================================ */

.pricing-section .pricing-card,
.pricing-section .addon-card,
.pricing-section .pricing-reveal {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  will-change: opacity, transform;
}

.pricing-section .pricing-card--featured {
  /* Featured tier sits slightly higher to preserve the original visual lift. */
  transform: translate3d(0, 24px, 0) scale(0.985);
}

@media (prefers-reduced-motion: no-preference) {
  .pricing-section .pricing-card,
  .pricing-section .addon-card,
  .pricing-section .pricing-reveal {
    transition:
      opacity 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
      transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
      box-shadow 0.3s ease,
      border-color 0.3s ease;
  }

  .pricing-section .pricing-card.is-visible,
  .pricing-section .addon-card.is-visible,
  .pricing-section .pricing-reveal.is-visible {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }

  .pricing-section .pricing-card--featured.is-visible {
    /* Match the original 1.02–1.05x scale on viewports >= md once visible. */
    transform: translate3d(0, 0, 0) scale(1.02);
  }

  @media (min-width: 1024px) {
    .pricing-section .pricing-card--featured.is-visible {
      transform: translate3d(0, 0, 0) scale(1.045);
    }
  }

  /* Subtle hover lift — composited transform only. */
  .pricing-section .pricing-card.is-visible:hover,
  .pricing-section .pricing-card.is-visible:focus-within {
    transform: translate3d(0, -6px, 0);
    box-shadow: 0 18px 40px -22px var(--brand-glow, rgba(91, 33, 182, 0.35));
  }

  .pricing-section .pricing-card--featured.is-visible:hover,
  .pricing-section .pricing-card--featured.is-visible:focus-within {
    transform: translate3d(0, -6px, 0) scale(1.025);
  }

  @media (min-width: 1024px) {
    .pricing-section .pricing-card--featured.is-visible:hover,
    .pricing-section .pricing-card--featured.is-visible:focus-within {
      transform: translate3d(0, -6px, 0) scale(1.05);
    }
  }

  .pricing-section .addon-card.is-visible:hover,
  .pricing-section .addon-card.is-visible:focus-within {
    transform: translate3d(0, -3px, 0);
    box-shadow: 0 14px 28px -22px var(--brand-glow, rgba(91, 33, 182, 0.3));
  }

  /* Border accent on hover for non-featured tiers — color-only, no reflow. */
  .pricing-section .pricing-card:not(.pricing-card--featured).is-visible:hover,
  .pricing-section .pricing-card:not(.pricing-card--featured).is-visible:focus-within {
    border-color: #8B1E2D;
  }

  [data-theme="dracula"] .pricing-section .pricing-card:not(.pricing-card--featured).is-visible:hover,
  [data-theme="dracula"] .pricing-section .pricing-card:not(.pricing-card--featured).is-visible:focus-within {
    border-color: #C4B5FD;
  }

  /* Icon micro-interaction — gentle pulse on hover, GPU only. */
  .pricing-section .pricing-card__icon {
    transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .pricing-section .pricing-card.is-visible:hover .pricing-card__icon,
  .pricing-section .pricing-card.is-visible:focus-within .pricing-card__icon {
    transform: translate3d(0, 0, 0) scale(1.08) rotate(-3deg);
  }

  /* Featured tier shimmer — single gradient sweep on hover. Composited via
     transform; the ::after layer is non-interactive so it never blocks input. */
  .pricing-section .pricing-card--featured {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }

  .pricing-section .pricing-card--featured::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(
      115deg,
      transparent 30%,
      rgba(255, 255, 255, 0.18) 50%,
      transparent 70%
    );
    transform: translate3d(-110%, 0, 0);
    will-change: transform;
    z-index: 1;
  }

  .pricing-section .pricing-card--featured.is-visible:hover::after,
  .pricing-section .pricing-card--featured.is-visible:focus-within::after {
    transition: transform 1.1s cubic-bezier(0.22, 0.61, 0.36, 1);
    transform: translate3d(110%, 0, 0);
  }

  /* Keep the featured card body above the shimmer overlay. */
  .pricing-section .pricing-card--featured > .card-body {
    position: relative;
    z-index: 2;
  }
}

/* Reduced motion: snap to final state, kill all transitions/animations. */
@media (prefers-reduced-motion: reduce) {
  .pricing-section .pricing-card,
  .pricing-section .addon-card,
  .pricing-section .pricing-reveal,
  .pricing-section .pricing-card--featured {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }

  .pricing-section .pricing-card--featured::after {
    display: none;
  }
}
