/* custom.css — only what Tailwind can't do.
   Tailwind utilities come from the CDN; theme tokens are configured in includes/header.php.
   Color values use CSS variables so we can flip them all at once via the .dark class on <html>.

   Design language: bold creative-agency (inspired by the "Lettery" theme) rendered in the
   Resulve brand — cream + near-black + Resulve amber, oversized Space Grotesk display type,
   and scroll-driven motion. No build step, no framework: Tailwind CDN + Alpine + vanilla JS. */

/* ───────── Fonts ─────────
   Matches the Lettery reference: Outfit (geometric display) + Inter for body. */
:root {
  --font-display: 'Outfit', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body:    'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --btn-radius:   9999px;
}

/* ───────── Theme variables (light) ─────────
   Resulve's own brand palette — warm stone + burnt amber (kept by request). Only the fonts,
   layout and motion follow the Lettery reference; the colors stay Resulve. */
:root {
  --color-bg:           #fafaf9;
  --color-bg-warm:      #f5f5f4;
  --color-ink:          #1c1917;
  --color-ink-muted:    #57534e;
  --color-ink-soft:     #78716c;
  --color-hair:         #e7e5e4;
  --color-accent:       #b45309;
  --color-accent-hover: #92400e;
  --color-accent-bright: #f59e0b;  /* brighter Resulve amber — for fills & dark surfaces */
  --color-code-bg:      #1c1917;   /* code-block background, kept dark in both modes */
  --color-code-fg:      #fafaf9;
  --color-inline-code-bg: #f5f5f4;
  --color-card-bg:      #ffffff;   /* white surfaces (form inputs, preview pane) */
}

/* ───────── Theme variables (dark) — toggled via .dark on <html> ───────── */
:root.dark {
  --color-bg:           #0c0a09;
  --color-bg-warm:      #1c1917;
  --color-ink:          #fafaf9;
  --color-ink-muted:    #a8a29e;
  --color-ink-soft:     #78716c;
  --color-hair:         #292524;
  --color-accent:       #f59e0b;
  --color-accent-hover: #fbbf24;
  --color-accent-bright: #fbbf24;
  --color-code-bg:      #292524;
  --color-code-fg:      #fafaf9;
  --color-inline-code-bg: #292524;
  --color-card-bg:      #1c1917;
}

/* Smooth fade on theme switch. */
html { transition: background-color 0.15s ease, color 0.15s ease; }

/* Hide Alpine-managed elements until Alpine boots, to prevent a flash. */
[x-cloak] { display: none !important; }

/* ───────── Display typography ─────────
   Repointing Tailwind's `serif` family to Space Grotesk (see header.php config) turns every
   existing `font-serif` heading into the agency display face with zero markup churn. Here we
   give those headings weight + tight tracking so they read as a bold grotesk, not a light one. */
.font-serif        { font-weight: 500; letter-spacing: -0.01em; }
main h1, .h-display { letter-spacing: -0.03em; line-height: 1.0; font-weight: 700; }
main h2            { letter-spacing: -0.02em; }

/* Oversized hero / section display type. */
.h-display {
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 8vw, 6.25rem);
}
.h-section {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.02;
  font-size: clamp(2rem, 4.5vw, 3.5rem);
}

/* Eyebrow label with a leading accent tick — the small agency section marker. */
.eyebrow-tick { display: inline-flex; align-items: center; gap: 0.6rem; }
.eyebrow-tick::before {
  content: ""; width: 1.75rem; height: 2px; background: var(--color-accent); display: inline-block;
}

/* ───────── Buttons ─────────
   Pill-shaped, lifting CTAs. Scoped to the actual button pattern (inline-block link / <button>
   with horizontal padding) so text-only "Learn more →" links and cards are untouched. */
main a.inline-block[class*="px-"],
main button[class*="px-"],
footer a.inline-block[class*="px-"],
.btn-pill {
  border-radius: var(--btn-radius);
  font-weight: 600;
  transition: transform 0.2s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
  will-change: transform;
}
main a.inline-block[class*="px-"]:hover,
main button[class*="px-"]:hover,
footer a.inline-block[class*="px-"]:hover,
.btn-pill:hover { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
  main a.inline-block[class*="px-"]:hover,
  main button[class*="px-"]:hover,
  footer a.inline-block[class*="px-"]:hover,
  .btn-pill:hover { transform: none; }
}

/* ───────── Scroll reveal ─────────
   Progressive enhancement: elements are only hidden once JS adds `.reveal-ready` to <html>
   (see js/script.js), so with JS disabled every section is fully visible. */
html.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}
html.reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.reveal-ready [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ───────── Marquee ─────────
   Seamless horizontal scroll. The track holds the content twice; translating it -50% loops
   invisibly. Pauses on hover and for reduced-motion users. */
.marquee { overflow: hidden; white-space: nowrap; }
.marquee__track {
  display: inline-flex; align-items: center;
  animation: marquee-scroll 34s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item { display: inline-flex; align-items: center; }
.marquee__dot { color: var(--color-accent); margin: 0 1.25rem; font-size: 0.6em; }
@keyframes marquee-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } }

/* ───────── Dark band ─────────
   The alternating full-contrast section that gives the site its agency rhythm. */
.band-dark { background: var(--color-ink); color: var(--color-bg); }
.band-dark .band-muted { color: color-mix(in srgb, var(--color-bg) 70%, transparent); }

/* ───────── Preloader ─────────
   Full-screen overlay with a counting number, matching Lettery's "Loading • Please wait"
   intro. JS removes .is-loading from <html> on window load; CSS handles the fade-out.
   Only active once JS adds .js-preload, so no-JS visitors never see a stuck screen. */
.preloader {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  background: var(--color-ink); color: var(--color-bg);
  opacity: 0; visibility: hidden; transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}
html.js-preload.is-loading .preloader { opacity: 1; visibility: visible; transition: none; }
.preloader__count { font-family: var(--font-display); font-weight: 700; font-size: clamp(3rem, 12vw, 8rem); letter-spacing: -0.04em; line-height: 1; }
html.is-loading body { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { .preloader { transition: none; } }

/* ───────── Custom cursor ─────────
   A dot + a lagging ring that grows over interactive elements. Enabled only by JS on
   fine-pointer devices (.has-cursor on <html>); touch and reduced-motion keep the native cursor. */
.cursor-dot, .cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 300; pointer-events: none;
  border-radius: 9999px; transform: translate3d(-50%, -50%, 0); opacity: 0;
}
.cursor-dot  { width: 7px; height: 7px; background: var(--color-accent); }
.cursor-ring { width: 34px; height: 34px; border: 1.5px solid var(--color-accent);
  transition: width 0.25s ease, height 0.25s ease, background-color 0.25s ease, opacity 0.3s ease; }
html.has-cursor .cursor-dot, html.has-cursor .cursor-ring { opacity: 1; }
html.has-cursor.cursor-hover .cursor-ring { width: 58px; height: 58px; background: color-mix(in srgb, var(--color-accent) 12%, transparent); }
html.has-cursor * { cursor: none !important; }

/* ───────── Word-by-word heading reveal ─────────
   JS wraps each word of [data-words] in <span class="word"><span>…</span></span>. Words rise
   into place with a stagger when the heading scrolls in. No-JS / reduced-motion = plain text. */
.words-split .word { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.14em; margin-bottom: -0.14em; }
.words-split .word > span { display: inline-block; transform: translateY(115%); transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); transition-delay: var(--word-delay, 0s); }
.words-split.is-visible .word > span { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .words-split .word > span { transform: none; transition: none; }
}

/* ───────── Scale-on-scroll media ─────────
   Wrap media in <figure class="scale-media" data-scale>. The inner img/box starts slightly
   enlarged and settles to 1× as it enters view — Lettery's mil-scale-img reveal. */
.scale-media { overflow: hidden; }
.scale-media > * { transform: scale(1.18); transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1); will-change: transform; display: block; }
.scale-media.is-visible > * { transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .scale-media > * { transform: none; transition: none; }
}

/* ───────── Editorial body typography (Parsedown-rendered Markdown) ─────────
   Wrap rendered HTML in <div class="prose">. Headings use the display face to match the site;
   colors driven by CSS variables so they swap with the theme. */
.prose                  { color: var(--color-ink); max-width: 38rem; }
.prose > * + *          { margin-top: 1.25em; }
.prose h2               { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.02em; font-size: 1.9rem; line-height: 1.15; margin-top: 2.5em; margin-bottom: 0.5em; color: var(--color-ink); }
.prose h3               { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.01em; font-size: 1.5rem; line-height: 1.3; margin-top: 2em; margin-bottom: 0.5em; color: var(--color-ink); }
.prose h4               { font-family: var(--font-display); font-weight: 600; font-size: 1.25rem; line-height: 1.4; margin-top: 1.5em; margin-bottom: 0.5em; color: var(--color-ink); }
.prose p                { line-height: 1.75; }
.prose a                { color: var(--color-accent); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover          { color: var(--color-accent-hover); }
/* Lists: Tailwind's Preflight resets `list-style` to none on ul/ol, which hides bullets and
   numbers in rendered Markdown. Restore them explicitly, or every list looks like plain
   indented text. `list-style-position: outside` keeps wrapped lines aligned under the text. */
.prose ul, .prose ol    { padding-left: 1.5rem; list-style-position: outside; }
.prose ul               { list-style-type: disc; }
.prose ol               { list-style-type: decimal; }
.prose ul ul            { list-style-type: circle; margin-top: 0.5em; }
.prose ol ol            { list-style-type: lower-alpha; margin-top: 0.5em; }
.prose li::marker       { color: var(--color-accent); }
.prose ol > li::marker  { font-weight: 600; }
.prose ul > li,
.prose ol > li          { line-height: 1.7; margin-top: 0.5em; padding-left: 0.25rem; }

/* Tables: Preflight also strips table borders/spacing. Markdown tables are common in posts,
   so give them real styling. `display:block` + `overflow-x:auto` lets a wide table scroll
   inside itself on mobile instead of forcing the whole page to scroll sideways. */
.prose table {
  display: block;
  width: max-content;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: 0.95em;
  margin-top: 1.75em;
  margin-bottom: 1.75em;
}
.prose thead           { background: var(--color-bg-warm); }
.prose th              { font-weight: 600; text-align: left; color: var(--color-ink); }
.prose th, .prose td   { border: 1px solid var(--color-hair); padding: 0.6rem 0.9rem; vertical-align: top; }
.prose tbody tr:nth-child(even) { background: color-mix(in srgb, var(--color-bg-warm) 45%, transparent); }
/* First column often holds the row label; make it read as one. */
.prose tbody td:first-child { font-weight: 600; color: var(--color-ink); }
.prose blockquote       { border-left: 3px solid var(--color-accent); padding-left: 1.25rem; font-style: italic; color: var(--color-ink-muted); }
.prose code             { background: var(--color-inline-code-bg); padding: 1px 6px; border-radius: 3px; font-size: 0.9em; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.prose pre              { background: var(--color-code-bg); color: var(--color-code-fg); padding: 1rem; border-radius: 6px; overflow-x: auto; font-size: 0.875rem; line-height: 1.5; }
.prose pre code         { background: transparent; padding: 0; color: inherit; font-size: 1em; }
.prose strong           { font-weight: 600; color: var(--color-ink); }
.prose em               { font-style: italic; }
.prose hr               { border: 0; border-top: 1px solid var(--color-hair); margin: 2em 0; }
.prose img              { max-width: 100%; height: auto; border-radius: 4px; }

/* Respect users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ───────── Card hover treatment ─────────
   The editorial card pattern (services index, work grid, "more work" / "related" strips,
   homepage featured grid). Subtle lift on hover. */
a.group.border-t-2 {
  transition: transform 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
  will-change: transform;
}
a.group.border-t-2:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  a.group.border-t-2:hover { transform: none; }
}

/* Image-zoom hook: wrap a card's hero image in <div class="card-image"> and the image scales
   subtly on hover. (Inert until real hero images exist.) */
.card-image          { overflow: hidden; border-radius: 4px; }
.card-image img      { transition: transform 0.4s ease; display: block; width: 100%; height: auto; }
a:hover .card-image img { transform: scale(1.04); }
@media (prefers-reduced-motion: reduce) {
  a:hover .card-image img { transform: none; }
}

/* ───────── Client logo strip ─────────
   An auto-scrolling monochrome logo row (like the Lettery reference). Logos read as a
   calm grey set and bloom to full colour on hover; the whole strip pauses on hover. */
.marquee__track--slow { animation-duration: 48s; }
.client-logo { flex: 0 0 auto; }
/* Logos render as a uniform silhouette that follows the theme (dark marks on the light theme,
   light marks on the dark theme). This is what makes a WHITE logo visible on the light page —
   brightness(0) flattens any colour to a solid shape. Requires transparent logo files; a logo
   with a baked-in solid background will show as a filled block, so use a transparent PNG/WebP. */
.client-logo img { filter: brightness(0); opacity: 0.5; transition: opacity 0.3s ease; }
:root.dark .client-logo img { filter: brightness(0) invert(1); }
.client-logo:hover img { opacity: 1; }
.client-logo span { filter: grayscale(1); opacity: 0.6; transition: opacity 0.3s ease, color 0.3s ease; }
.client-logo:hover span { opacity: 1; color: var(--color-ink); }
@media (prefers-reduced-motion: reduce) {
  .client-logo img, .client-logo span { transition: none; }
}

/* ───────── Services nav flyout ─────────
   Desktop only: the grouped services panel opens on hover or keyboard focus
   (focus-within covers tabbing through the panel's links). On mobile the
   services sub-list renders inline inside the nav dropdown instead. */
@media (min-width: 768px) {
  .nav-svc:hover .nav-svc__panel,
  .nav-svc:focus-within .nav-svc__panel { display: block; }
}

/* Flyout card — uses the elevated-surface token so it reads as a raised card in
   both themes (white on cream, warm charcoal on near-black) instead of blending
   into the page background. Shadows barely register on dark backgrounds, so the
   dark theme leans on surface contrast + border and a deeper shadow. */
.nav-svc__card {
  background: var(--color-card-bg);
  border: 1px solid var(--color-hair);
  box-shadow: 0 20px 45px -18px rgb(28 25 23 / 0.25);
}
:root.dark .nav-svc__card { box-shadow: 0 24px 50px -16px rgb(0 0 0 / 0.7); }

/* ───────── Band-aware controls ─────────
   .band-dark inverts with the theme (dark band on the light site, light band on
   the dark site), so nothing inside it may hardcode white/black. These classes
   derive every color from the band's own foreground (--band-fg). */
.band-dark { --band-fg: var(--color-bg); }
.band-field {
  background: color-mix(in srgb, var(--band-fg) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--band-fg) 24%, transparent);
  color: var(--band-fg);
}
.band-field::placeholder { color: color-mix(in srgb, var(--band-fg) 50%, transparent); }
.band-field:focus { border-color: var(--color-accent-bright); outline: none; }
.band-hair { border-color: color-mix(in srgb, var(--band-fg) 14%, transparent); }
.band-surface { background: color-mix(in srgb, var(--band-fg) 7%, transparent); }
.band-outline-btn {
  border: 1px solid color-mix(in srgb, var(--band-fg) 35%, transparent);
  color: var(--band-fg);
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.band-outline-btn:hover { background: var(--band-fg); color: var(--color-ink); border-color: var(--band-fg); }

/* Accent-filled buttons: the dark theme's accent is bright amber, where white
   text fails contrast — flip the label to near-black there. */
:root.dark .bg-accent.text-white { color: #1c1917; }

/* ───────── Lifting cards ─────────
   Soft-surface cards (no border — the tinted background does the separation)
   that lift on hover. Shadow is theme-tuned; motion respects reduced-motion. */
.card-lift {
  background: var(--color-bg-warm);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.card-lift:hover {
  transform: translateY(-5px);
  box-shadow: 0 16px 32px -14px rgb(28 25 23 / 0.2);
}
:root.dark .card-lift:hover { box-shadow: 0 16px 32px -14px rgb(0 0 0 / 0.65); }
@media (prefers-reduced-motion: reduce) {
  .card-lift { transition: none; }
  .card-lift:hover { transform: none; box-shadow: none; }
}

/* Hero with the orb column: cap the display type slightly so "Marketing,"
   never overflows its (narrower) grid column. */
@media (min-width: 768px) {
  .hero-grid .h-display { font-size: clamp(2.75rem, 6.2vw, 5.25rem); }
}

/* ───────── Sticky header surface ─────────
   Tailwind's opacity modifiers (bg-paper/85) silently no-op on colors defined
   as plain CSS variables, which left the header fully transparent — dark nav
   text became invisible whenever a dark band scrolled underneath. Solid paper
   fallback; translucent + blur where supported. */
.site-header { background: var(--color-bg); }
@supports ((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px))) {
  .site-header {
    background: color-mix(in srgb, var(--color-bg) 84%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }
}

/* Soft accent border (same fix — border-accent/40 was a silent no-op). */
.accent-hair { border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); }

/* Orb canvas: fade out entirely over the hero's text column so shards and glow
   never overlap the copy — the animation lives right of the text, full stop. */
#orb-canvas {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 40%, #000 64%);
  mask-image: linear-gradient(90deg, transparent 0%, transparent 40%, #000 64%);
}

/* Preloader orb — the pulsating brand circle shown while the page loads
   (replaces the counting number; .preloader__count CSS kept for easy revert). */
.preloader__orb {
  width: clamp(6rem, 18vw, 9rem);
  height: clamp(6rem, 18vw, 9rem);
  border-radius: 9999px;
  background: radial-gradient(circle,
    rgba(196, 105, 42, 0.95) 0%,
    rgba(196, 105, 42, 0.65) 55%,
    rgba(196, 105, 42, 0.25) 80%,
    rgba(196, 105, 42, 0) 100%);
  animation: preloader-pulse 1.1s ease-in-out infinite;
}
@keyframes preloader-pulse {
  0%, 100% { transform: scale(0.9); opacity: 0.8; }
  50%      { transform: scale(1.08); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .preloader__orb { animation: none; } }
