/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/* Prevent double-tap zoom and horizontal scroll */
html {
  touch-action: manipulation;
  overflow-x: hidden;
}

/* Mobile nav button press states for better touch feedback */
@media (hover: none) and (pointer: coarse) {
  nav a:active {
    opacity: 0.85;
    transform: scale(0.98);
  }
}

/* Department collapse animations */
[data-collapsible-department-target="content"] {
  transition: opacity 0.25s ease-out, max-height 0.3s ease-out;
  max-height: 5000px;
  opacity: 1;
  overflow: hidden;
}

[data-collapsible-department-target="content"].collapsing {
  max-height: 0;
  opacity: 0;
}

[data-collapsible-department-target="content"].expanding {
  max-height: 5000px;
  opacity: 1;
}

/* View Transitions z-index hierarchy */
::view-transition-group(mobile-nav),
::view-transition-group(mobile-header),
::view-transition-group(desktop-shopping-header),
::view-transition-group(desktop-meal-plan-header),
::view-transition-group(desktop-recipes-header) {
  z-index: 100;
}

/* Department headers should be above content but below fixed UI */
::view-transition-group(*) {
  z-index: 1;
}

/* Shopping list department layout - desktop */
@media (min-width: 768px) {
    .department-items {
        display: flex;
        flex-wrap: wrap;
        margin: -0.5rem;
    }

    .department-items li {
        width: calc(33.333% - 1rem);
        margin: 0.5rem;
    }
}

/* Shopping list department layout - mobile */
@media (max-width: 767px) {
    .department-items {
        display: block;
    }

    .department-items li {
        margin-bottom: 0.75rem;
    }
}

/* Department headings */
#shopping-list-section h4 {
    font-size: 1.1rem;
    font-weight: 500;
    color: #374151;
    padding-bottom: 0.25rem;
    border-bottom: 1px solid #e5e7eb;
    margin-bottom: 0.75rem;
    text-transform: capitalize;
}

/* Better alignment for shopping list item checkboxes */
#shopping-list-section button[type="submit"] {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* Transition for better UX when items are checked */
#shopping-list-section span {
    transition: color 0.2s, text-decoration 0.2s;
}

/* Increase spacing between department sections */
#shopping-list-section .mb-6:not(:last-child) {
    margin-bottom: 2rem;
}

/* Turbo optimizations for snappy feel */
@keyframes fade-in {
    from { opacity: 0; transform: scale(0.8); }
    to { opacity: 1; transform: scale(1); }
}

@keyframes slide-up {
    from { 
        opacity: 0.7; 
        transform: translateY(4px) scale(0.98);
    }
    to { 
        opacity: 1; 
        transform: translateY(0) scale(1);
    }
}

@keyframes slide-out {
    from { 
        opacity: 1; 
        transform: translateY(0) scale(1);
    }
    to { 
        opacity: 0; 
        transform: translateY(-8px) scale(0.9);
    }
}

@keyframes checkmark-pop {
    0% {
        transform: scale(0);
        opacity: 0;
    }
    50% {
        transform: scale(1.2);
    }
    100% {
        transform: scale(1);
        opacity: 1;
    }
}

.animate-fade-in {
    animation: fade-in 0.2s ease-out;
}

.animate-slide-up {
    animation: slide-up 0.08s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.animate-checkmark-pop {
    animation: checkmark-pop 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

/* Smooth transitions for chips */
.chip-item {
    transition: all 0.08s ease-out;
    -webkit-tap-highlight-color: transparent;
}

/* Press effects using data attribute (works reliably on mobile) */
[data-pressed="true"] {
    opacity: 0.92 !important;
    transform: translateY(0.5px) !important;
}

.chip-item[data-pressed="true"] {
    opacity: 0.85 !important;
    transform: translateY(0.25px) !important;
}

/* Desktop hover */
.chip-item:hover {
    opacity: 0.9;
}

/* Active state for both desktop click and mobile tap on the chip */
.chip-item:active {
    opacity: 0.9;
    transform: translateY(0.4px);
}

/* Also apply active state when the form/button inside is pressed */
.chip-item:has(form:active),
.chip-item:has(button:active) {
    opacity: 0.9;
    transform: translateY(0.4px);
}

/* Hidden on purpose. Measured on throttled cellular, the bar was visible for
   ~1.3s on every navigation while the underlying timings were unchanged or
   better — it narrated the wait rather than shortening it. */
.turbo-progress-bar {
    display: none;
}

/* Smooth transitions for Turbo replacements */
[data-turbo-temporary] {
    opacity: 0.6;
    transition: opacity 0.15s;
}

/* Recipe card transitions for floating selected cards */
[id^="user_recipe_"] {
    transition: height 0.2s ease-out, transform 0.2s ease-out;
}

/* Smooth image size transitions */
[id^="user_recipe_"] img {
    transition: width 0.2s ease-out, height 0.2s ease-out;
}

/* Spring settle for the recipe card that just changed state: it overshoots its
   resting size, then eases back. Transform only - animating opacity here reads
   as a flicker, because this outlasts the view transition that precedes it. */
@keyframes recipe-change {
    0% {
        transform: scale(0.95);
    }
    50% {
        transform: scale(1.02);
    }
    100% {
        transform: scale(1);
    }
}

/* 0.3s, not 0.5s. This starts when the server's re-render lands, after the view
   transition has finished, so anything longer is a tail the card spends bouncing
   alone — measured at ~250ms of it. The 2% overshoot stays legible this short. */
.animate-recipe-change {
    animation: recipe-change 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* View Transitions API - automatically animates between states */
/* Only works in Chrome/Edge and Safari 18+ - gracefully falls back to animation above */
/* Note: Can't use wildcards in CSS, so these rules apply to all view transitions */
::view-transition-old(*),
::view-transition-new(*) {
    animation-duration: 0.2s;
    animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
}

/* The group animation morphs position and size — it is the movement you
   actually see, and it defaults to 250ms. Without this it outlasts the
   cross-fade above, so the card is still travelling after the fade has ended. */
::view-transition-group(*) {
    animation-duration: 0.2s;
    animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
}

/* Exclude fixed nav/header elements from view transitions to prevent z-index issues */
/* During transitions, these stay in place and don't animate */
#mobile-nav {
    view-transition-name: mobile-nav;
}

#mobile-header-container {
    view-transition-name: mobile-header;
}

aside nav {
    view-transition-name: desktop-nav;
}

#recipes-header {
    view-transition-name: desktop-recipes-header;
}

.shopping-list-header {
    view-transition-name: desktop-shopping-header;
}

.meal-plan-header {
    view-transition-name: desktop-meal-plan-header;
}

/* Ensure recipe cards have positioning context */
[id^="wrapper_user_recipe_"] {
    position: relative;
}

/* Mobile touch states - now handled by data-pressed attribute */
@media (hover: none) and (pointer: coarse) {
    /* Disable :hover on touch devices */
    .hover\:opacity-90:hover {
        opacity: 1;
    }
}

/* Style shopping list checkboxes */
input[type="checkbox"].shopping-checkbox {
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid #002656;
  border-radius: 2px;
  background-color: white;
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
}

input[type="checkbox"].shopping-checkbox:checked {
  background-color: #002656;
  border-color: #002656;
}

input[type="checkbox"].shopping-checkbox:checked::after {
  content: '';
  position: absolute;
  left: 5px;
  top: 2px;
  width: 6px;
  height: 10px;
  border: solid white;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

input[type="checkbox"].shopping-checkbox:focus,
input[type="checkbox"].shopping-checkbox:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

/* Mobile modal View Transitions - slide up/down animations */
::view-transition-old(modal-overlay-mobile) {
  animation: fade-out 0.25s ease-out;
}

::view-transition-new(modal-overlay-mobile) {
  animation: fade-in-overlay 0.25s ease-out;
}

::view-transition-old(modal-content-mobile) {
  animation: slide-down 0.3s cubic-bezier(0.4, 0.0, 1, 1);
}

::view-transition-new(modal-content-mobile) {
  animation: slide-up-modal 0.3s cubic-bezier(0.0, 0.0, 0.2, 1);
}

@keyframes fade-in-overlay {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes slide-up-modal {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

@keyframes slide-down {
  from { transform: translateY(0); }
  to { transform: translateY(100%); }
}

/* CSS-only modal animations (no View Transitions API needed) */
/* Mobile modal: slide up/down */
.modal-opening .modal-content {
  animation: slide-up-modal 0.25s cubic-bezier(0.0, 0.0, 0.2, 1);
}

.modal-opening .modal-overlay {
  animation: fade-in-overlay 0.25s ease-out;
}

.modal-closing .modal-content {
  animation: slide-down 0.2s cubic-bezier(0.4, 0.0, 1, 1);
}

.modal-closing .modal-overlay {
  animation: fade-out 0.2s ease-out;
}

/* Desktop modal: subtle scale + fade */
@keyframes scale-fade-in {
  from { 
    opacity: 0; 
    transform: scale(0.95) translateY(-8px);
  }
  to { 
    opacity: 1; 
    transform: scale(1) translateY(0);
  }
}

@keyframes scale-fade-out {
  from { 
    opacity: 1; 
    transform: scale(1) translateY(0);
  }
  to { 
    opacity: 0; 
    transform: scale(0.95) translateY(-8px);
  }
}

.modal-opening .modal-content-desktop {
  animation: scale-fade-in 0.15s cubic-bezier(0.0, 0.0, 0.2, 1);
}

.modal-closing .modal-content-desktop {
  animation: scale-fade-out 0.12s cubic-bezier(0.4, 0.0, 1, 1);
}

/* Loading spinner for submit button */
@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid rgba(0, 38, 86, 0.3);
  border-top-color: #002656;
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

.spinner.hidden {
  display: none;
}

/* A finished aisle: the title recedes and the amber count gives way to "done".
   The marker sits beside the badge, not inside it, because turbo_stream.update
   rewrites the badge's innerHTML whenever the server echoes a new count. */
[data-controller~="collapsible-department"].is-complete h3 {
  color: #00265699;
}

[data-controller~="collapsible-department"].is-complete [id^="department_badge_"],
[data-controller~="collapsible-department"].is-complete [id^="department_total_badge_"] {
  display: none;
}

.department-done-marker.hidden {
  display: none;
}

/* Applied from JS while offline. Defined here rather than as Tailwind utilities
   because Tailwind only compiles classes it finds in scanned source, and a class
   that only ever appears in a JS string never gets generated. */
.is-offline-disabled {
  opacity: 0.4;
  pointer-events: none;
}

/* Rows that can be held down to edit. Stops iOS raising its text-selection
   callout mid-press. Deliberately does not touch touch-action, which would
   interfere with scrolling the list. */
.is-long-pressable {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Respect users who prefer reduced motion.
   Loading indicators keep animating: a frozen spinner reads as a hang. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation-duration: 0.01ms !important;
  }

  *:not(.spinner):not(.turbo-progress-bar),
  *:not(.spinner):not(.turbo-progress-bar)::before,
  *:not(.spinner):not(.turbo-progress-bar)::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}