/* CORE (CORE_PLAN.md section 2). The rules every app in the fleet
   needs and none of them should own a private copy of: the upload
   affordances, the brand-mark pulse and its reduced-motion opt-out, the
   top loader's offset under the mobile bar, and the iOS 16px rule.
   Imported at the top of each app's globals.css, right after Tailwind,
   so the app's own rules still come last and win. */

/* Upload affordances. shimmer = a light sweep across a media preview
   while its bytes are in flight; pop = the success check springing in
   when the upload settles. Referenced via arbitrary animate-[…] utils
   in lib/core/brand/upload-progress.tsx. */
@keyframes upload-shimmer {
  100% {
    transform: translateX(200%);
  }
}
@keyframes upload-pop {
  0% {
    transform: scale(0.5);
    opacity: 0;
  }
  60% {
    transform: scale(1.08);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

/* Brand-mark heartbeat shown while a Social Set switch is in flight
   (see SwitchOverlay in set-switcher.tsx) — the bee gently breathes in
   and out instead of a generic spinner, so the wait feels on-brand.
   Referenced via an arbitrary animate-[…] util. */
@keyframes logo-pulse {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.18);
  }
}
@media (prefers-reduced-motion: reduce) {
  .animate-\[logo-pulse_1\.4s_ease-in-out_infinite\] {
    animation: none;
  }
}

/* Mobile nav tray (lib/core/shell/). The
   overlay root carries the class .core-tray plus a data-state of "open" or
   "closing" — there is no "closed" state in the DOM, because the overlay
   unmounts. "closing" is a real phase so the exit is never cut off: the
   card plays core-tray-card-out and the shell drops the overlay on that card's
   animationend. The parts: .core-tray-backdrop (the dimmed page behind),
   .core-tray-card (the floating nav card under the top bar row),
   .core-tray-nav (the nav list, whose direct children stagger in),
   .core-tray-foot (the account footer), .core-tray-x (the hamburger SVG,
   morphed into an ×). */
@keyframes core-tray-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/* Its own name, not core-tray-fade run in reverse: changing only the direction
   of a same-named animation never restarts it, so nothing would play (and
   the shell waits on animationend to unmount). */
@keyframes core-tray-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes core-tray-card-in {
  from {
    opacity: 0;
    transform: translateY(-14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes core-tray-card-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateY(-10px) scale(0.98);
  }
}
@keyframes core-tray-group-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* The three hamburger bars folding into an ×. */
@keyframes core-tray-x-top {
  to {
    translate: 0 5px;
    rotate: 45deg;
  }
}
@keyframes core-tray-x-mid {
  to {
    opacity: 0;
    scale: 0 1;
  }
}
@keyframes core-tray-x-bot {
  to {
    translate: 0 -5px;
    rotate: -45deg;
  }
}
/* And unfolding back into bars, for the same restart reason as above. */
@keyframes core-tray-x-top-back {
  from {
    translate: 0 5px;
    rotate: 45deg;
  }
  to {
    translate: 0 0;
    rotate: 0deg;
  }
}
@keyframes core-tray-x-mid-back {
  from {
    opacity: 0;
    scale: 0 1;
  }
  to {
    opacity: 1;
    scale: 1 1;
  }
}
@keyframes core-tray-x-bot-back {
  from {
    translate: 0 -5px;
    rotate: -45deg;
  }
  to {
    translate: 0 0;
    rotate: 0deg;
  }
}

.core-tray[data-state="open"] .core-tray-backdrop {
  animation: core-tray-fade 0.25s ease-out both;
}
.core-tray[data-state="closing"] .core-tray-backdrop {
  animation: core-tray-fade-out 0.18s ease-in both;
}

/* The card's lift. Hey Locals carried this inline as an arbitrary
   shadow in rgba(29,32,57,.5) — navy at 50% — which is a literal hex in
   a shared file. Same shadow, off the primary token, so Call Show's
   tray lifts in ink. */
.core-tray-card {
  box-shadow: 0 20px 50px -16px
    color-mix(in srgb, var(--color-primary) 50%, transparent);
}

.core-tray[data-state="open"] .core-tray-card {
  transform-origin: 50% 0;
  animation: core-tray-card-in 0.32s cubic-bezier(0.32, 0.72, 0, 1) both;
}
.core-tray[data-state="closing"] .core-tray-card {
  transform-origin: 50% 0;
  animation: core-tray-card-out 0.18s ease-in both;
}

/* The bottom card (PhoneSheet's default side): the same card and the
   same motion, upside down, so a sheet rises from below with a gap
   under it rather than sliding up as a slab glued to the screen's edge. */
@keyframes core-tray-card-up-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes core-tray-card-up-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
}
.core-tray[data-side="bottom"] .core-tray-card {
  box-shadow: 0 -12px 40px -16px
    color-mix(in srgb, var(--color-primary) 45%, transparent);
}
.core-tray[data-side="bottom"][data-state="open"] .core-tray-card {
  transform-origin: 50% 100%;
  animation-name: core-tray-card-up-in;
}
.core-tray[data-side="bottom"][data-state="closing"] .core-tray-card {
  transform-origin: 50% 100%;
  animation-name: core-tray-card-up-out;
}

/* The groups and the footer rise in behind the card, one after the next. */
.core-tray[data-state="open"] .core-tray-nav > *,
.core-tray[data-state="open"] .core-tray-foot {
  animation: core-tray-group-in 0.32s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(1) {
  animation-delay: 60ms;
}
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(2) {
  animation-delay: 100ms;
}
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(3) {
  animation-delay: 140ms;
}
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(4) {
  animation-delay: 180ms;
}
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(5) {
  animation-delay: 220ms;
}
/* A flat nav (Unbusied) puts its ROWS straight into .core-tray-nav, so
   the stagger runs past the five a grouped nav needs. Without this a
   sixth row would land before the first five. It shares the footer's
   delay, which reads as one closing beat. */
.core-tray[data-state="open"] .core-tray-nav > *:nth-child(6) {
  animation-delay: 260ms;
}
.core-tray[data-state="open"] .core-tray-foot {
  animation-delay: 260ms;
}

.core-tray .core-tray-x path {
  transform-box: fill-box;
  transform-origin: center;
}
.core-tray[data-state="open"] .core-tray-x path:nth-child(1) {
  animation: core-tray-x-top 0.3s cubic-bezier(0.32, 0.72, 0, 1) both;
}
.core-tray[data-state="open"] .core-tray-x path:nth-child(2) {
  animation: core-tray-x-mid 0.3s cubic-bezier(0.32, 0.72, 0, 1) both;
}
.core-tray[data-state="open"] .core-tray-x path:nth-child(3) {
  animation: core-tray-x-bot 0.3s cubic-bezier(0.32, 0.72, 0, 1) both;
}
/* Closing unfolds the × back into bars. */
.core-tray[data-state="closing"] .core-tray-x path:nth-child(1) {
  animation: core-tray-x-top-back 0.2s ease-in both;
}
.core-tray[data-state="closing"] .core-tray-x path:nth-child(2) {
  animation: core-tray-x-mid-back 0.2s ease-in both;
}
.core-tray[data-state="closing"] .core-tray-x path:nth-child(3) {
  animation: core-tray-x-bot-back 0.2s ease-in both;
}

@media (prefers-reduced-motion: reduce) {
  /* Everything becomes a short cross-fade, no travel and no stagger. */
  .core-tray[data-state="open"] .core-tray-card,
  .core-tray[data-state="open"] .core-tray-nav > *,
  .core-tray[data-state="open"] .core-tray-foot {
    animation-name: core-tray-fade;
    animation-duration: 0.12s;
    animation-delay: 0s;
  }
  .core-tray[data-state="closing"] .core-tray-card {
    animation-name: core-tray-fade-out;
    animation-duration: 0.12s;
  }
  /* :nth-child(n) matches every child, at the same specificity as the
     stagger rules above, so these clear their delays. */
  .core-tray[data-state="open"] .core-tray-nav > *:nth-child(n) {
    animation-delay: 0s;
  }
  /* The bars still need to land on the × (or back on bars), so keep the
     animations and let them snap to their end state. */
  .core-tray[data-state] .core-tray-x path:nth-child(n) {
    animation-duration: 0.01s;
  }
}


/* iOS Safari zooms the page into any form field whose font-size is
   under 16px. Every text-sm / text-[13px] input, textarea and select in
   the app used to trigger it. On touch devices force 16px (the
   !important beats the per-element Tailwind size utilities); desktop
   keeps its compact sizes. (Jeff, 2026-09-03: app-wide.) */
@media (pointer: coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  textarea,
  select {
    font-size: 16px !important;
  }
}

/* Select arrows, fleet-wide (Jeff, 2026-10-17; Hey Locals! since
   2026-10-01). The platform arrow sits jammed against the right edge, so
   core draws its own chevron with room around it. Unlayered, so the right
   padding beats the px-* utilities and the text never runs under the
   chevron; inside :where(), so it has NO specificity and an app that
   styles its own select (Hiveway's marketing forms) still wins. Multi-row
   lists (multiple / size) keep the platform look. The chevron is a
   neutral grey in a data URI, the one colour here that cannot read a
   token (CONTRACT.md section 1). */
:where(select:not([multiple]):not([size])) {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23555555' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 7.5l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 1.1rem 1.1rem;
  padding-right: 2.6rem;
}
:where(select:not([multiple]):not([size])):disabled {
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  /* The bottom card's rules carry one more attribute than the cross-fade
     above, so they need their own to lose the travel. */
  .core-tray[data-side="bottom"][data-state="open"] .core-tray-card {
    animation-name: core-tray-fade;
  }
  .core-tray[data-side="bottom"][data-state="closing"] .core-tray-card {
    animation-name: core-tray-fade-out;
  }
}
