/* `source(none)` disables Tailwind's automatic content detection, which walks
   the whole project tree — .gitignore included. Measured: it held 33 142
   inotify watches here, 32 203 of them on storage/, i.e. 97% of the budget
   spent on ActiveStorage blob directories that contain no class at all. With
   enough imports that exhausts fs.inotify.max_user_watches and --watch dies on
   a misleading "No space left on device". Classes only ever live in app/, so
   that is all we declare. Add an @source line if a new directory starts
   carrying markup. */
@import "tailwindcss" source(none);
@source "../../../app";

/* WannaBrunch (wannabrunch.dev) runs its own visual system, separate from
   WannaCollab's: Schibsted Grotesk, a warm ink, and a single yolk → coral
   gradient used on accents only. Everything below is prefixed `wb-` and is
   never applied outside the wannabrunch layout.

   Every colour the palette owns is a token — no wannabrunch view carries a
   literal hex. Swapping the whole brand is then a matter of overriding these
   custom properties on <html>, which is exactly what the dev palette switcher
   does. `--wb-glow` pairs are space-separated triplets so they can be used as
   `rgb(var(--wb-glow) / .35)` in shadows and radial halos. */
@theme {
  --font-brunch: "Schibsted Grotesk", ui-sans-serif, system-ui, sans-serif;

  /* The gradient. `mid` is the true midpoint of from→to for two-stop
     palettes, so one three-stop declaration renders every palette correctly. */
  --color-wb-grad-from: #F4B740;
  --color-wb-grad-mid: #EB8F3F;
  --color-wb-grad-to: #E2673F;

  /* Accent — never a gradient stop: those are too light to read as text. */
  --color-wb-accent: #B4531F;
  --color-wb-accent-dark: #8C3F17;
  --color-wb-accent-soft: #FDF3E6;
  --color-wb-accent-line: #F7DFC0;

  --color-wb-ink: #2B1E16;
  --color-wb-ink-soft: #3D2C21;
  --color-wb-body: #6B5D52;
  --color-wb-muted: #A2948A;
  --color-wb-line: #EDE5DA;
  --color-wb-line-soft: #F1EAE1;
  --color-wb-input: #E7DED3;
  --color-wb-surface: #FDF8F0;
  --color-wb-band-from: #FEF7EA;
  --color-wb-band-to: #FDF0E6;

  /* Money stays green in every palette: it is the one place the product has
     to read as financial rather than edible. */
  --color-wb-money: #0BA05F;
}

:root {
  --wb-glow: 235 143 63;
  --wb-glow-2: 226 103 63;
  --wb-shadow: 43 30 22;
}

/* Tailwind v4 sets `cursor: default` on buttons; restore the pointer for all
   interactive elements (matches v3 / native link behavior). */
/* wannabrunch hero photograph. Off by default, so production renders the
   phone-mockup hero exactly as before; the dev switcher sets data-wb-hero on
   <html> to preview the photographic version. Not in a @layer: it has to beat
   the utilities on those elements. */
[data-wb-hero-photo] {
  display: none;
}
html[data-wb-hero="image"] [data-wb-hero-photo] {
  display: block;
}
html[data-wb-hero="image"] [data-wb-hero-glow] {
  display: none;
}

/* The header is a sibling of <main>, so the only way the picture reaches
   behind it is to lift it out of the flow. The hero then owns the gap the bar
   used to occupy. */
html[data-wb-hero="image"] [data-wb-header] {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  background-color: transparent;
  border-bottom-color: transparent;
}
html[data-wb-hero="image"] [data-wb-hero-section] {
  padding-top: 4.5rem;
}

/* Frosted rather than opaque: a flat white fill over a photograph reads as a
   sticker stuck on top of it. The gradient CTA stays solid — it is the one
   thing in the hero that should not recede. */
html[data-wb-hero="image"] [data-wb-header] .wb-btn-dark {
  background-color: rgb(var(--wb-shadow) / 0.55);
  backdrop-filter: blur(14px);
}
html[data-wb-hero="image"] [data-wb-hero-section] .wb-btn-ghost {
  background-color: rgb(255 255 255 / 0.5);
  border-color: rgb(255 255 255 / 0.7);
  backdrop-filter: blur(14px);
}
html[data-wb-hero="image"] [data-wb-hero-section] .wb-btn-ghost:hover {
  background-color: rgb(255 255 255 / 0.7);
}

@layer base {
  /* Every in-page anchor eases instead of jumping — no JS, so it covers any
     link or button pointing at a #target, present and future. Gated on the
     motion preference: animated scrolling is a vestibular trigger, and the
     instant jump stays the correct behaviour for anyone who asked for it. */
  @media (prefers-reduced-motion: no-preference) {
    html {
      scroll-behavior: smooth;
    }
  }

  a,
  button:not(:disabled),
  [type="button"]:not(:disabled),
  [type="submit"]:not(:disabled),
  [type="reset"]:not(:disabled),
  [role="button"]:not(:disabled),
  summary,
  label[for] {
    cursor: pointer;
  }

  /* Drop the default browser focus ring on form controls (keep a subtle
     border highlight so focus is still visible). */
  input:not([type="checkbox"]):not([type="radio"]),
  select,
  textarea {
    @apply focus:outline-none focus:border-indigo-400;
  }
}

/* Reusable button styles so every CTA looks the same. */
@layer components {
  .btn-primary {
    @apply inline-flex w-full items-center justify-center rounded-lg px-4 py-2.5
           font-semibold text-sm uppercase tracking-wide text-white bg-indigo-500 transition-colors duration-300
           hover:bg-indigo-600 active:bg-indigo-700
           disabled:opacity-50 disabled:pointer-events-none;
  }

  .btn-secondary {
    @apply inline-flex items-center justify-center rounded-lg px-4 py-2.5
           font-semibold text-sm uppercase tracking-wide text-gray-700 bg-gray-100 transition-colors duration-300
           hover:bg-gray-200 disabled:opacity-50 disabled:pointer-events-none;
  }

  .btn-danger {
    @apply inline-flex items-center justify-center rounded-lg px-4 py-2.5
           font-semibold text-sm uppercase tracking-wide text-white bg-rose-500 transition-colors duration-300
           hover:bg-rose-600 active:bg-rose-700
           disabled:opacity-50 disabled:pointer-events-none;
  }

  /* Size variants — defined last so their padding/size win when combined. */
  .btn-mini {
    @apply w-auto rounded-md px-3 py-1.5 text-xs;
  }
  .btn-large {
    @apply py-3.5 text-base;
  }

  /* Creator screens — category chips + cards (match public/demo prototype). */
  .wc-chip {
    @apply inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-[11px] font-bold
           whitespace-nowrap border transition-colors no-underline
           sm:text-xs;
  }
  .wc-chip-on  { @apply bg-[#1D1733] text-white border-transparent; }
  .wc-chip-off { @apply bg-white text-gray-500 border-gray-200 hover:text-gray-900; }
  .wc-card {
    @apply bg-white rounded-xl;
  }
  /* The Discover search renders its own clear button — hide WebKit's native one. */
  input[type="search"]::-webkit-search-cancel-button {
    -webkit-appearance: none;
  }
}

/* Modal open/close transition (opacity + subtle scale, 200ms), driven by the
   `.modal-visible` class toggled in lib/modals.js — same pattern as Vouched.
   Put `.wc-modal` on any modal overlay to opt in. Mechanism, not looks: the
   `.wb-modal` twin exists so WannaBrunch can share the transition without
   carrying a `wc-` class through its markup. */
.wc-modal,
.wb-modal {
  opacity: 0;
  transition: opacity 200ms;
}
.wc-modal > div,
.wb-modal > div {
  transform: scale(0.95);
  transition: transform 200ms;
}
.wc-modal.modal-visible,
.wb-modal.modal-visible {
  opacity: 1;
}
.wc-modal.modal-visible > div,
.wb-modal.modal-visible > div {
  transform: scale(1);
}

/* ── WannaBrunch ───────────────────────────────────────────────────────────
   The gradient is the brand's one loud element, so it lives in exactly two
   forms: a fill (`wb-gradient`) and a text clip (`wb-gradient-text`). Buttons
   are defined here rather than reusing `.btn-primary`, which belongs to
   WannaCollab and must keep its indigo. */
.wb-gradient {
  background-image: linear-gradient(90deg, var(--color-wb-grad-from), var(--color-wb-grad-mid), var(--color-wb-grad-to));
}
.wb-gradient-text {
  background-image: linear-gradient(90deg, var(--color-wb-grad-from), var(--color-wb-grad-mid), var(--color-wb-grad-to));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* The primary button's three gradient stops, registered as colours so they
   interpolate: a plain background-image cannot be transitioned, and the button
   is an <input type="submit"> on the landing page, which rules out fading a
   second gradient in on a pseudo-element. */
@property --wb-btn-g1 { syntax: "<color>"; inherits: false; initial-value: transparent; }
@property --wb-btn-g2 { syntax: "<color>"; inherits: false; initial-value: transparent; }
@property --wb-btn-g3 { syntax: "<color>"; inherits: false; initial-value: transparent; }

@layer components {
  /* Shape only — pair it with a variant: `class="wb-btn wb-btn-primary"`.
     Tailwind v4 cannot `@apply` a component class, so the composition happens
     in the markup rather than here. */
  .wb-btn {
    @apply inline-flex items-center justify-center rounded-xl px-7 py-3.5
           font-brunch text-[15px] font-bold transition
           disabled:opacity-50 disabled:pointer-events-none;
  }
  /* Hover deepens the fill and nothing else: each stop slides a little toward
     the warm end of the brand ramp, so the gradient stays a gradient and the
     button stays put. Derived from the tokens rather than hard-coded, so the
     dev palette switcher carries the hover state with it. */
  .wb-btn-primary {
    @apply text-white shadow-[0_8px_24px_rgb(var(--wb-glow)/.35)];
    --wb-btn-g1: var(--color-wb-grad-from);
    --wb-btn-g2: var(--color-wb-grad-mid);
    --wb-btn-g3: var(--color-wb-grad-to);
    background-image: linear-gradient(90deg, var(--wb-btn-g1), var(--wb-btn-g2), var(--wb-btn-g3));
    transition: --wb-btn-g1 250ms, --wb-btn-g2 250ms, --wb-btn-g3 250ms, box-shadow 250ms;
  }
  .wb-btn-primary:hover {
    --wb-btn-g1: color-mix(in oklch, var(--color-wb-grad-from) 82%, var(--color-wb-grad-to));
    --wb-btn-g2: color-mix(in oklch, var(--color-wb-grad-mid) 82%, var(--color-wb-grad-to));
    --wb-btn-g3: color-mix(in oklch, var(--color-wb-grad-to) 90%, #000);
  }
  .wb-btn-ghost {
    @apply border border-wb-input bg-white font-semibold text-wb-ink
           hover:border-wb-accent-line hover:text-wb-accent;
  }
  .wb-btn-dark {
    @apply bg-wb-ink text-white hover:bg-wb-ink-soft;
  }

  /* Section shell: the mockup keeps every band on the same 1180px measure. */
  .wb-section {
    @apply mx-auto w-full max-w-[1180px] px-6 sm:px-10;
  }
  .wb-card {
    @apply bg-white border border-wb-line rounded-[20px]
           shadow-[0_2px_10px_rgb(var(--wb-shadow)/.04)];
  }
  .wb-pill {
    @apply inline-flex items-center gap-2 rounded-full border border-wb-accent-line
           bg-wb-accent-soft px-3.5 py-1.5 font-brunch text-xs font-semibold text-wb-accent;
  }
  .wb-input {
    @apply w-full rounded-xl border border-wb-input bg-white px-4 py-3.5
           text-[15px] text-wb-ink placeholder:text-wb-muted
           focus:border-wb-accent-line;
  }

  /* The Map/List switch on a "Where to spend" section. State rides on a
     `data-on` attribute rather than a class list, so both buttons are declared
     identically in the markup and the controller flips one attribute. */
  /* Sized to sit beside a heading, not to be a control in its own right: two
     words that swap one view for another. The padding was set when this was
     the only thing on its row; next to "My places" on a 380px phone it was
     taking a quarter of the width to say "Map". */
  .wb-toggle {
    @apply inline-flex shrink-0 rounded-full border border-wb-input bg-white p-0.5;
  }
  .wb-toggle-btn {
    @apply cursor-pointer rounded-full border-none bg-transparent px-2.5 py-1
           font-brunch text-xs font-bold text-wb-muted transition
           hover:text-wb-ink;
  }
  .wb-toggle-btn[data-on="true"] {
    @apply bg-wb-accent-soft text-wb-accent;
  }

  /* A partner on the club map. The basemap is deliberately pale, so the pins
     are the only saturated thing on it and carry the brand gradient; the white
     ring keeps two places on the same block from reading as one blob.

     The pin is NOT the element MapLibre is handed — see partners_map_controller,
     which wraps it. MapLibre keeps a marker in place with `transform:
     translate(-50%,-50%) translate(x,y)`, and `scale-150` below compiles to the
     individual `scale` property, which composes with that transform rather than
     replacing it: the scale multiplies the translation too, and a hovered pin
     flew 1.5× further from the map's origin than it belonged. Two elements, so
     the transform and the scale never meet. */
  /* Carries its rate, because that is now the question the map answers. Rates
     are negotiated per place — 5% at one, 20% at the next — so a field of
     identical dots would hide the only thing that separates them. A label costs
     more room than a dot and crowds a dense block; the rate is worth it. */
  .wb-pin {
    @apply block cursor-pointer rounded-full border-2 border-white px-1.5 py-px
           font-brunch text-[11px] font-bold leading-[1.25] text-white
           shadow-[0_2px_8px_rgb(var(--wb-shadow)/.45)]
           transition-transform duration-200 hover:scale-125
           focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-wb-accent;
    background-image: linear-gradient(135deg, var(--color-wb-grad-from), var(--color-wb-grad-to));
  }
  /* The pin whose card the strip is currently showing. Holds the hover size so
     the answer to "which one did I just tap" survives the pointer leaving. */
  .wb-pin[data-active] {
    @apply scale-125 ring-2 ring-wb-accent;
  }

  /* Labels overlap where dots did not — downtown Miami stacks five partners
     inside a few blocks — so the one being pointed at, and the one being shown,
     have to come to the front. The z-index has to sit on MapLibre's own marker
     element: that is what is positioned, and a z-index on the button inside it
     cannot order it against a sibling marker. Reached with :has() rather than
     from the controller, so the hover case needs no JS at all. */
  .maplibregl-marker:has(.wb-pin:hover) {
    z-index: 1;
  }
  .maplibregl-marker:has(.wb-pin[data-active]) {
    z-index: 2;
  }

  /* The card strip along the bottom edge of the map. It scrolls horizontally
     over the map itself, where a native scrollbar would read as a rule drawn
     across the frame; the snap points and the cards bleeding past the right
     edge carry the affordance instead. */
  .wb-strip {
    scrollbar-width: none;
  }
  .wb-strip::-webkit-scrollbar {
    display: none;
  }
  /* The card a pin was tapped for. Ring and shadow on the <li> rather than
     anything inside it: the card's own markup is the List view's, shared, and
     nothing here should depend on its internals. The <li> is given the same
     rounding so both follow the card's silhouette.

     An outline, not a ring, because the gap has to be a real gap. Tailwind's
     ring-offset paints the offset colour as an opaque shadow layered over the
     ring, so a transparent offset hides nothing and only leaves a thicker ring;
     the stock white offset would draw a white halo, which on a white card is a
     border, not a space. outline-offset leaves actual room, and the map shows
     through it. */
  .wb-strip [data-active] {
    @apply shadow-[0_8px_24px_rgb(var(--wb-shadow)/.35)]
           outline-2 outline-wb-accent outline-offset-3;
  }

  /* Once one card is the answer to "which pin was that", the others step back.
     Only then — :has() keeps the strip at full strength until something is
     picked, so it does not arrive looking washed out.

     Far enough back to be nearly gone. A gentler fade was tried and read badly:
     these cards are white and they sit on a map, so a card left mostly opaque
     shows the basemap's roads and place names through its own address — dirty
     rather than dimmed. Taken this far there is no white left to muddy, and the
     strip reads as a spotlight on the one that was picked. */
  .wb-strip li {
    @apply transition-opacity duration-200;
  }
  .wb-strip:has([data-active]) li:not([data-active]) {
    @apply opacity-20;
  }
}
