@font-face { font-family: 'Iosevka Patrick'; src: url('/static/fonts/IosevkaPatrickNerdFont-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'Iosevka Patrick'; src: url('/static/fonts/IosevkaPatrickNerdFont-Medium.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; } @font-face { font-family: 'Iosevka Patrick'; src: url('/static/fonts/IosevkaPatrickNerdFont-SemiBold.woff2') format('woff2'); font-weight: 600; font-style: normal; font-display: swap; } /* ======================================== Design Tokens (CSS Custom Properties) Light theme (default) ======================================== */ :root { /* Page */ --page-bg: #FAF7F5; --page-text: #3d2319; /* Cards */ --card-bg: #FFFFFF; --card-border: #eaddd7; --card-shadow: rgba(61, 35, 25, 0.06); --card-shadow-hover: rgba(61, 35, 25, 0.10); /* Surfaces (inset areas inside cards) */ --surface-bg: rgba(250, 247, 245, 0.5); --surface-border: #f2e8e5; /* Header */ --header-bg-from: #4a2c2a; --header-bg-to: #3d2319; --header-border: #7f5539; --header-text: #FAF7F5; /* Text hierarchy */ --text-primary: #3d2319; --text-secondary: #4a2c2a; --text-muted: #7f5539; --text-faint: #bfa094; --text-placeholder: #d2bab0; /* Interactive */ --btn-primary-bg: #4a2c2a; --btn-primary-bg-hover: #3d2319; --btn-primary-text: #FAF7F5; --btn-secondary-bg: #FFFFFF; --btn-secondary-border: #e0cec7; --btn-secondary-text: #6b4423; --btn-secondary-bg-hover: #FAF7F5; /* Forms */ --input-bg: #FFFFFF; --input-border: #e0cec7; --input-border-focus: #7f5539; --input-ring-focus: rgba(127, 85, 57, 0.15); --input-bg-focus: rgba(250, 247, 245, 0.3); /* Tables */ --table-bg: #FFFFFF; --table-header-bg: #FAF7F5; --table-border: #eaddd7; --table-row-hover: #FAF7F5; --table-divider: #f2e8e5; /* Modals */ --modal-bg: #FFFFFF; --modal-border: #eaddd7; --modal-backdrop: rgba(0, 0, 0, 0.4); /* Feed type indicators (left border + filter pills) */ --type-brew: #6b4423; --type-bean: #b45309; --type-recipe: #7f5539; --type-roaster: #92400e; --type-grinder: #6b4423; --type-brewer: #6b4423; /* Rating badges */ --rating-bg: #fef3c7; --rating-text: #78350f; /* Alerts/warnings */ --alert-warning-bg: #fffbeb; --alert-warning-border: #fbbf24; --alert-warning-text: #78350f; --alert-warning-text-muted: #92400e; /* Shadows */ --shadow-sm: 0 1px 3px var(--card-shadow); --shadow-md: 0 4px 12px var(--card-shadow-hover); --shadow-lg: 0 10px 25px var(--card-shadow-hover); /* Footer */ --footer-bg: #FAF7F5; --footer-border: #eaddd7; } /* ======================================== Dark theme Activates via: OS preference OR data-theme="dark" on data-theme="light" forces light even on dark OS ======================================== */ @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { /* Page */ --page-bg: #0F0A08; --page-text: #FAF7F5; /* Cards */ --card-bg: #1C1210; --card-border: #2E211B; --card-shadow: rgba(0, 0, 0, 0.3); --card-shadow-hover: rgba(0, 0, 0, 0.4); /* Surfaces (inset areas inside cards) */ --surface-bg: rgba(36, 26, 22, 0.6); --surface-border: #2E211B; /* Header */ --header-bg-from: #0F0A08; --header-bg-to: #0F0A08; --header-border: #2E211B; --header-text: #FAF7F5; /* Text hierarchy */ --text-primary: #FAF7F5; --text-secondary: #E0CEC4; --text-muted: #C4A898; --text-faint: #8B7265; --text-placeholder: #5A4A40; /* Interactive */ --btn-primary-bg: #7f5539; --btn-primary-bg-hover: #6b4423; --btn-primary-text: #FAF7F5; --btn-secondary-bg: #241A16; --btn-secondary-border: #3D2D24; --btn-secondary-text: #E0CEC4; --btn-secondary-bg-hover: #2E211B; /* Forms */ --input-bg: #241A16; --input-border: #3D2D24; --input-border-focus: #fbbf24; --input-ring-focus: rgba(251, 191, 36, 0.15); --input-bg-focus: rgba(36, 26, 22, 0.8); /* Tables */ --table-bg: #1C1210; --table-header-bg: #241A16; --table-border: #2E211B; --table-row-hover: #241A16; --table-divider: #241A16; /* Modals */ --modal-bg: #1C1210; --modal-border: #2E211B; --modal-backdrop: rgba(0, 0, 0, 0.6); /* Feed type indicators (left border) - brighter on dark */ --type-brew: #6b4423; --type-bean: #b45309; --type-recipe: #7f5539; --type-roaster: #92400e; --type-grinder: #6b4423; --type-brewer: #6b4423; /* Rating badges */ --rating-bg: rgba(251, 191, 36, 0.15); --rating-text: #fbbf24; /* Alerts/warnings */ --alert-warning-bg: rgba(251, 191, 36, 0.08); --alert-warning-border: rgba(251, 191, 36, 0.3); --alert-warning-text: #fde68a; --alert-warning-text-muted: #fcd34d; /* Shadows - darker, less visible on dark bg */ --shadow-sm: 0 1px 3px var(--card-shadow); --shadow-md: 0 4px 12px var(--card-shadow-hover); --shadow-lg: 0 10px 25px var(--card-shadow-hover); /* Footer */ --footer-bg: #0F0A08; --footer-border: #2E211B; } /* Override common hardcoded Tailwind classes for dark mode */ .text-brown-900 { color: var(--text-primary) !important; } .text-brown-800 { color: var(--text-primary) !important; } .text-brown-700 { color: var(--text-secondary) !important; } .text-brown-600 { color: var(--text-muted) !important; } .text-brown-500 { color: var(--text-faint) !important; } .text-brown-400 { color: var(--text-placeholder) !important; } .bg-brown-50 { background-color: var(--page-bg) !important; } .bg-brown-100 { background-color: var(--surface-bg) !important; } .bg-brown-200 { background-color: var(--card-border) !important; } .bg-brown-300 { background-color: var(--surface-bg) !important; } .border-brown-200 { border-color: var(--card-border) !important; } .border-brown-300 { border-color: var(--card-border) !important; } .bg-white { background-color: var(--card-bg) !important; } .bg-white\/60 { background-color: var(--surface-bg) !important; } /* Amber badges stay visible on dark */ .bg-amber-50 { background-color: rgba(251, 191, 36, 0.1) !important; } .bg-amber-100 { background-color: rgba(251, 191, 36, 0.15) !important; } .bg-amber-400 { background-color: #fbbf24 !important; } .text-amber-900 { color: #fde68a !important; } .text-amber-700 { color: #fcd34d !important; } .text-amber-600 { color: #fbbf24 !important; } .border-amber-400 { border-color: rgba(251, 191, 36, 0.4) !important; } /* Warning/alert backgrounds */ .bg-green-50 { background-color: rgba(251, 191, 36, 0.08) !important; } /* Hover states */ .hover\:bg-brown-200:hover { background-color: var(--surface-bg) !important; } .hover\:bg-brown-100:hover { background-color: var(--surface-bg) !important; } .hover\:bg-brown-50:hover { background-color: var(--surface-bg) !important; } .hover\:text-brown-900:hover { color: var(--text-primary) !important; } .hover\:text-brown-800:hover { color: var(--text-primary) !important; } .hover\:text-brown-700:hover { color: var(--text-secondary) !important; } /* Dividers */ .divide-brown-200 > :not([hidden]) ~ :not([hidden]) { border-color: var(--card-border) !important; } .divide-brown-300 > :not([hidden]) ~ :not([hidden]) { border-color: var(--card-border) !important; } /* Ring colors for avatars */ .ring-brown-500 { --tw-ring-color: #3D2D24 !important; } .hover\:ring-brown-400:hover { --tw-ring-color: #5A4A40 !important; } /* Opacity-variant backgrounds (used in recipe stats grid, etc.) */ .bg-brown-50\/60 { background-color: var(--surface-bg) !important; } .bg-brown-200\/60 { background-color: var(--card-border) !important; } .border-brown-200\/60 { border-color: var(--card-border) !important; } /* Group hover text (used in recipe author links) */ .group-hover\/author\:text-brown-900:hover, .group\/author:hover .group-hover\/author\:text-brown-900 { color: var(--text-primary) !important; } .group-hover\/author\:text-brown-800:hover, .group\/author:hover .group-hover\/author\:text-brown-800 { color: var(--text-primary) !important; } /* Forker avatar borders */ .border-white { border-color: var(--card-bg) !important; } /* Decoration colors */ .decoration-brown-300 { text-decoration-color: var(--card-border) !important; } .hover\:decoration-brown-500:hover { text-decoration-color: var(--text-faint) !important; } } /* Manual dark theme override (data-theme="dark" on ) */ :root[data-theme="dark"] { --page-bg: #0F0A08; --page-text: #FAF7F5; --card-bg: #1C1210; --card-border: #2E211B; --card-shadow: rgba(0, 0, 0, 0.3); --card-shadow-hover: rgba(0, 0, 0, 0.4); --surface-bg: rgba(36, 26, 22, 0.6); --surface-border: #2E211B; --header-bg-from: #0F0A08; --header-bg-to: #0F0A08; --header-border: #2E211B; --header-text: #FAF7F5; --text-primary: #FAF7F5; --text-secondary: #E0CEC4; --text-muted: #C4A898; --text-faint: #8B7265; --text-placeholder: #5A4A40; --btn-primary-bg: #7f5539; --btn-primary-bg-hover: #6b4423; --btn-primary-text: #FAF7F5; --btn-secondary-bg: #241A16; --btn-secondary-border: #3D2D24; --btn-secondary-text: #E0CEC4; --btn-secondary-bg-hover: #2E211B; --input-bg: #241A16; --input-border: #3D2D24; --input-border-focus: #fbbf24; --input-ring-focus: rgba(251, 191, 36, 0.15); --input-bg-focus: rgba(36, 26, 22, 0.8); --table-bg: #1C1210; --table-header-bg: #241A16; --table-border: #2E211B; --table-row-hover: #241A16; --table-divider: #241A16; --modal-bg: #1C1210; --modal-border: #2E211B; --modal-backdrop: rgba(0, 0, 0, 0.6); --type-brew: #6b4423; --type-bean: #b45309; --type-recipe: #7f5539; --type-roaster: #92400e; --type-grinder: #6b4423; --type-brewer: #6b4423; --rating-bg: rgba(251, 191, 36, 0.15); --rating-text: #fbbf24; --alert-warning-bg: rgba(251, 191, 36, 0.08); --alert-warning-border: rgba(251, 191, 36, 0.3); --alert-warning-text: #fde68a; --alert-warning-text-muted: #fcd34d; --shadow-sm: 0 1px 3px var(--card-shadow); --shadow-md: 0 4px 12px var(--card-shadow-hover); --shadow-lg: 0 10px 25px var(--card-shadow-hover); --footer-bg: #0F0A08; --footer-border: #2E211B; } /* Tailwind class overrides for dark theme (both auto and manual) */ :root[data-theme="dark"] .text-brown-900, :root[data-theme="dark"] .text-brown-800 { color: var(--text-primary) !important; } :root[data-theme="dark"] .text-brown-700 { color: var(--text-secondary) !important; } :root[data-theme="dark"] .text-brown-600 { color: var(--text-muted) !important; } :root[data-theme="dark"] .text-brown-500 { color: var(--text-faint) !important; } :root[data-theme="dark"] .text-brown-400 { color: var(--text-placeholder) !important; } :root[data-theme="dark"] .bg-brown-50 { background-color: var(--page-bg) !important; } :root[data-theme="dark"] .bg-brown-100 { background-color: var(--surface-bg) !important; } :root[data-theme="dark"] .bg-brown-200 { background-color: var(--card-border) !important; } :root[data-theme="dark"] .bg-brown-300 { background-color: var(--surface-bg) !important; } :root[data-theme="dark"] .border-brown-200, :root[data-theme="dark"] .border-brown-300 { border-color: var(--card-border) !important; } :root[data-theme="dark"] .bg-white { background-color: var(--card-bg) !important; } :root[data-theme="dark"] .bg-white\/60 { background-color: var(--surface-bg) !important; } :root[data-theme="dark"] .bg-amber-50 { background-color: rgba(251, 191, 36, 0.1) !important; } :root[data-theme="dark"] .bg-amber-100 { background-color: rgba(251, 191, 36, 0.15) !important; } :root[data-theme="dark"] .text-amber-900 { color: #fde68a !important; } :root[data-theme="dark"] .text-amber-700 { color: #fcd34d !important; } :root[data-theme="dark"] .text-amber-600 { color: #fbbf24 !important; } :root[data-theme="dark"] .border-amber-400 { border-color: rgba(251, 191, 36, 0.4) !important; } :root[data-theme="dark"] .bg-green-50 { background-color: rgba(251, 191, 36, 0.08) !important; } :root[data-theme="dark"] .hover\:bg-brown-200:hover, :root[data-theme="dark"] .hover\:bg-brown-100:hover, :root[data-theme="dark"] .hover\:bg-brown-50:hover { background-color: var(--surface-bg) !important; } :root[data-theme="dark"] .hover\:text-brown-900:hover, :root[data-theme="dark"] .hover\:text-brown-800:hover { color: var(--text-primary) !important; } :root[data-theme="dark"] .hover\:text-brown-700:hover { color: var(--text-secondary) !important; } :root[data-theme="dark"] .divide-brown-200 > :not([hidden]) ~ :not([hidden]), :root[data-theme="dark"] .divide-brown-300 > :not([hidden]) ~ :not([hidden]) { border-color: var(--card-border) !important; } :root[data-theme="dark"] .ring-brown-500 { --tw-ring-color: #3D2D24 !important; } :root[data-theme="dark"] .hover\:ring-brown-400:hover { --tw-ring-color: #5A4A40 !important; } :root[data-theme="dark"] .bg-brown-50\/60 { background-color: var(--surface-bg) !important; } :root[data-theme="dark"] .bg-brown-200\/60 { background-color: var(--card-border) !important; } :root[data-theme="dark"] .border-brown-200\/60 { border-color: var(--card-border) !important; } :root[data-theme="dark"] .border-white { border-color: var(--card-bg) !important; } :root[data-theme="dark"] .decoration-brown-300 { text-decoration-color: var(--card-border) !important; } :root[data-theme="dark"] .hover\:decoration-brown-500:hover { text-decoration-color: var(--text-faint) !important; } @tailwind base; @tailwind components; @tailwind utilities; @layer base { h1, h2, h3 { @apply font-semibold; } /* Touch targets for interactive elements only */ button, input[type="submit"], input[type="button"] { min-height: 44px; min-width: 44px; } /* Filter pills opt out of the 44px touch target */ [class*="filter-pill"] { min-height: auto; min-width: auto; } /* Prevent iOS zoom on input focus */ @media (max-width: 768px) { input, select, textarea { font-size: 16px; } } } @layer components { /* Page Containers */ .page-container { @apply mx-auto px-2 sm:px-4; } .page-container-sm { @apply page-container max-w-2xl; } .page-container-md { @apply page-container max-w-3xl; } .page-container-lg { @apply page-container max-w-4xl; } .page-container-xl { @apply page-container max-w-6xl; } /* Cards and Containers */ .card { background: var(--card-bg); border: 1px solid var(--card-border); @apply rounded-xl; box-shadow: var(--shadow-sm); transition: box-shadow 200ms ease; } .card:hover { box-shadow: var(--shadow-md); } .card-inner { @apply p-6; } .card-sm { background: var(--card-bg); border: 1px solid var(--card-border); @apply rounded-lg; box-shadow: var(--shadow-sm); } /* Section box for lighter content areas */ .section-box { background: var(--surface-bg); @apply rounded-lg p-4; } /* Buttons */ .btn { @apply inline-flex items-center justify-center px-4 py-2 rounded-lg font-medium transition-colors cursor-pointer; } .btn-primary { @apply btn text-white; background: var(--btn-primary-bg); } .btn-primary:hover { background: var(--btn-primary-bg-hover); } .btn-secondary { @apply btn; background: var(--btn-secondary-bg); color: var(--btn-secondary-text); border: 1px solid var(--btn-secondary-border); } .btn-secondary:hover { background: var(--btn-secondary-bg-hover); } .btn-tertiary { @apply btn text-white; background: var(--btn-primary-bg); } .btn-tertiary:hover { background: var(--btn-primary-bg-hover); } .btn-link { color: var(--text-muted); @apply font-medium underline transition-colors cursor-pointer; } .btn-link:hover { color: var(--text-primary); } .btn-danger { @apply text-red-600 hover:text-red-800 font-medium underline transition-colors cursor-pointer; } /* Forms */ .form-label { @apply block text-sm font-medium mb-2; color: var(--text-primary); } .form-input { @apply rounded-lg text-base py-2 px-3; background: var(--input-bg); border: 1px solid var(--input-border); color: var(--text-primary); transition: border-color 150ms ease, box-shadow 150ms ease, background-color 150ms ease; } .form-input:focus { border-color: var(--input-border-focus); box-shadow: 0 0 0 2px var(--input-ring-focus); background: var(--input-bg-focus); outline: none; } /* Hide number input spinners */ input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } input[type="number"] { -moz-appearance: textfield; } .form-input::placeholder { color: var(--text-placeholder); } .form-input-lg { @apply form-input py-3 px-4; } /* Combo select dropdown */ .combo-select { @apply relative; } .combo-dropdown { @apply absolute z-50 w-full mt-1 rounded-lg overflow-hidden; background: var(--card-bg); border: 1px solid var(--input-border); box-shadow: var(--shadow-lg); max-height: 280px; overflow-y: auto; } .combo-section-label { @apply text-xs font-medium uppercase tracking-wider px-3 py-1.5; color: var(--text-muted); background: var(--surface-bg); } .combo-item { @apply px-3 py-2 cursor-pointer text-sm; color: var(--text-primary); } .combo-item:hover, .combo-item[data-highlighted="true"] { background: var(--surface-bg); } .combo-item-create { @apply px-3 py-2 cursor-pointer text-sm font-medium; color: var(--accent-primary); border-top: 1px solid var(--surface-border); } .combo-item-create:hover, .combo-item-create[data-highlighted="true"] { background: var(--surface-bg); } .combo-item-sub { @apply text-xs; color: var(--text-muted); } .combo-creating { @apply px-3 py-2 text-sm text-center; color: var(--text-muted); } .form-select { @apply form-input truncate max-w-full min-w-0; } .form-textarea { @apply form-input min-h-[100px]; } /* Tables */ .table-container { background: var(--table-bg); border: 1px solid var(--table-border); @apply rounded-lg overflow-hidden; box-shadow: var(--shadow-sm); } .table { @apply min-w-full; border-collapse: collapse; } .table-header { background: var(--table-header-bg); border-bottom: 1px solid var(--table-border); } .table-th { @apply px-6 py-3 text-left text-xs font-medium uppercase tracking-wider; color: var(--text-muted); } .table-body { background: var(--table-bg); } .table-body tr { border-bottom: 1px solid var(--table-divider); } .table-body tr:last-child { border-bottom: none; } .table-row { transition: background-color 150ms ease; } .table-row:hover { background: var(--table-row-hover); } .table-td { @apply px-6 py-4 whitespace-nowrap text-sm; color: var(--text-secondary); } /* Modals */ .modal-backdrop { @apply fixed inset-0 flex items-center justify-center z-50 p-4; background: var(--modal-backdrop); backdrop-filter: blur(4px); } .modal-content { background: var(--modal-bg); border: 1px solid var(--modal-border); @apply rounded-xl p-6 max-w-md w-full max-h-[90vh] overflow-y-auto; box-shadow: var(--shadow-lg); } .modal-title { @apply text-xl font-semibold mb-4; color: var(--text-primary); } /* Native Dialog Element */ .modal-dialog { @apply p-0 bg-transparent border-none shadow-none max-w-md w-full; } .modal-dialog::backdrop { background: var(--modal-backdrop); backdrop-filter: blur(4px); } .modal-dialog .modal-content { background: var(--modal-bg); border: 1px solid var(--modal-border); @apply rounded-xl p-6 w-full max-h-[90vh] overflow-y-auto; box-shadow: var(--shadow-lg); } /* Entity suggestion typeahead dropdown */ .suggestions-dropdown { @apply absolute z-50 left-0 right-0 mt-1 rounded-lg max-h-48 overflow-y-auto; background: var(--card-bg); border: 1px solid var(--card-border); box-shadow: var(--shadow-md); } .suggestions-item { @apply w-full text-left px-3 py-2 flex items-center gap-2 transition-colors cursor-pointer last:border-b-0; border-bottom: 1px solid var(--surface-border); } .suggestions-item:hover { background: var(--surface-bg); } /* Typography */ .section-title { @apply text-xs font-semibold uppercase tracking-widest mb-4; color: var(--text-faint); } .page-title { @apply text-2xl font-semibold; color: var(--text-primary); } /* Feed Components */ .feed-card { background: var(--card-bg); border: 1px solid var(--card-border); @apply rounded-lg p-3 sm:p-4 transition-shadow; box-shadow: var(--shadow-sm); } .feed-card:hover { box-shadow: var(--shadow-md); } /* Feed card type indicators */ .feed-card-brew { border-left: 3px solid var(--type-brew); } .feed-card-bean { border-left: 3px solid var(--type-bean); } .feed-card-recipe { border-left: 3px solid var(--type-recipe); } .feed-card-roaster { border-left: 3px solid var(--type-roaster); } .feed-card-grinder { border-left: 3px solid var(--type-grinder); } .feed-card-brewer { border-left: 3px solid var(--type-brewer); } .feed-content-box { background: var(--surface-bg); @apply rounded-lg p-3 sm:p-4; } .feed-content-box-sm { background: var(--surface-bg); @apply rounded-lg p-2 sm:p-3; } /* Avatar - base styles */ .avatar { @apply rounded-full object-cover transition-all duration-200; } .avatar-sm { @apply avatar w-8 h-8 ring-2 ring-brown-500 hover:ring-brown-400 hover:ring-4; } .avatar-md { @apply avatar w-12 h-12 ring-2 ring-brown-500 hover:ring-brown-400 hover:ring-4; } .avatar-lg { @apply avatar w-20 h-20 border-2 border-brown-300 hover:border-brown-400 hover:border-4; } /* Avatar placeholder - for missing images */ .avatar-placeholder { @apply rounded-full bg-brown-300 flex items-center justify-center transition-all duration-200; } .avatar-placeholder-sm { @apply avatar-placeholder w-8 h-8 ring-2 ring-brown-500 hover:ring-brown-400 hover:ring-4; } .avatar-placeholder-md { @apply avatar-placeholder w-12 h-12 ring-2 ring-brown-500 hover:ring-brown-400 hover:ring-4; } .avatar-placeholder-lg { @apply avatar-placeholder w-20 h-20 hover:bg-brown-400; } /* Avatar text sizing */ .avatar-text-sm { @apply text-brown-600 text-sm; } .avatar-text-md { @apply text-brown-600 text-base; } .avatar-text-lg { @apply text-brown-600 text-2xl; } /* Text Utilities */ .text-helper { @apply text-sm mt-1; color: var(--text-muted); } .text-meta { @apply text-xs; color: var(--text-muted); } .text-meta-sm { @apply text-sm; color: var(--text-muted); } .text-label { color: var(--text-muted); } /* Badges */ .badge-rating { @apply inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium flex-shrink-0; background: var(--rating-bg); color: var(--rating-text); } .badge-rating-sm { @apply inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-medium; background: var(--rating-bg); color: var(--rating-text); } /* Filter Pills */ .filter-pill { @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; color: var(--text-muted); background: transparent; border: 1px solid var(--card-border); } .filter-pill:hover { color: var(--text-secondary); border-color: var(--input-border-focus); background: var(--surface-bg); } /* Type-aware hover: preview the active color on hover */ .filter-pill[data-tab="brew"]:hover { border-color: var(--type-brew); color: var(--type-brew); } .filter-pill[data-tab="bean"]:hover { border-color: var(--type-bean); color: var(--type-bean); } .filter-pill[data-tab="recipe"]:hover { border-color: var(--type-recipe); color: var(--type-recipe); } .filter-pill[data-tab="roaster"]:hover { border-color: var(--type-roaster); color: var(--type-roaster); } .filter-pill[data-tab="grinder"]:hover { border-color: var(--type-grinder); color: var(--type-grinder); } .filter-pill[data-tab="brewer"]:hover { border-color: var(--type-brewer); color: var(--type-brewer); } .filter-pill-active { @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; color: var(--btn-primary-text); background: var(--btn-primary-bg); border: 1px solid var(--btn-primary-bg); } .filter-pill-active:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); } /* Type-colored filter pills (active state matches feed card left border) */ .filter-pill-brew, .filter-pill-bean, .filter-pill-recipe, .filter-pill-roaster, .filter-pill-grinder, .filter-pill-brewer { @apply inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-full transition-all cursor-pointer; color: var(--btn-primary-text); } .filter-pill-brew { background: var(--type-brew); border: 1px solid var(--type-brew); } .filter-pill-bean { background: var(--type-bean); border: 1px solid var(--type-bean); } .filter-pill-recipe { background: var(--type-recipe); border: 1px solid var(--type-recipe); } .filter-pill-roaster { background: var(--type-roaster); border: 1px solid var(--type-roaster); } .filter-pill-grinder { background: var(--type-grinder); border: 1px solid var(--type-grinder); } .filter-pill-brewer { background: var(--type-brewer); border: 1px solid var(--type-brewer); } /* Links */ .link { color: var(--text-muted); @apply hover:underline transition-colors; } .link:hover { color: var(--text-primary); } .link-bold { color: var(--text-muted); @apply font-medium hover:underline transition-colors; } .link-bold:hover { color: var(--text-primary); } /* Like Button */ .like-btn { @apply inline-flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors min-h-[44px]; } .like-btn-liked { @apply like-btn text-red-600; background: transparent; animation: like-pop 400ms ease-out; } .like-btn-liked:hover { background: var(--surface-bg); } .like-btn-unliked { @apply like-btn; color: var(--text-muted); background: transparent; animation: like-shrink 200ms ease-out; } .like-btn-unliked:hover { background: var(--surface-bg); } /* Share Button */ .share-btn { @apply inline-flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors min-h-[44px]; color: var(--text-muted); background: transparent; } .share-btn:hover { background: var(--surface-bg); } /* Comment Button */ .comment-btn { @apply inline-flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors min-h-[44px]; color: var(--text-muted); background: transparent; } .comment-btn:hover { background: var(--surface-bg); } /* Comment Section */ .comment-section { @apply mt-8 pt-6; border-top: 2px solid var(--card-border); } .comment-section-header { @apply mb-5; } .comment-count-badge { @apply inline-flex items-center justify-center text-xs font-bold bg-brown-700 text-brown-100 rounded-full min-w-[1.375rem] h-[1.375rem] px-1.5; } .comment-login-prompt { @apply flex items-center gap-3 rounded-lg p-4 mb-5 border border-dashed; background: var(--surface-bg); border-color: var(--card-border); } .comment-compose { @apply rounded-lg p-4 mb-5 flex flex-col gap-2; background: var(--surface-bg); border: 1px solid var(--card-border); } .comment-textarea { @apply w-full rounded-lg px-3 py-2.5 text-base resize-none transition-colors focus:ring-0 focus:outline-none; background: var(--card-bg); border: 1px solid var(--card-border); color: var(--text-primary); } .comment-textarea::placeholder { color: var(--text-placeholder); } .comment-textarea:focus { border-color: var(--input-border-focus); } .comment-list { @apply space-y-1; } .comment-empty-state { @apply text-center py-8; } .comment-item { @apply relative rounded-lg p-3 transition-colors; } .comment-item:hover { background: var(--surface-bg); } .comment-item-inner { @apply relative; } .comment-depth-1 { @apply ml-6 pl-4; } .comment-depth-2 { @apply ml-12 pl-4; } .comment-thread-line { @apply absolute left-0 top-3 bottom-3 w-0.5 rounded-full; background: var(--card-border); } .comment-reply-btn { @apply inline-flex items-center gap-1 transition-colors text-xs font-medium; color: var(--text-placeholder); } .comment-reply-btn:hover { color: var(--text-muted); } .comment-delete-btn { @apply transition-colors; color: var(--text-placeholder); } .comment-delete-btn:hover { color: var(--text-muted); } .comment-reply-form { @apply flex flex-col gap-2 rounded-lg p-3; background: var(--surface-bg); border: 1px solid var(--card-border); } /* Action Bar */ .action-bar { @apply flex items-center gap-2 mt-3 pt-3; border-top: 1px solid var(--surface-border); } /* Action bar inside brew view container - no separator needed */ .brew-view-actions .action-bar { @apply mt-0 pt-0 border-t-0; } /* Compact action bar variant for comments */ .comment-item .action-bar { @apply mt-1 border-t-0 gap-1 rounded-lg px-1.5 py-1 inline-flex items-center; background: var(--surface-bg); } .comment-item .action-btn, .comment-item .like-btn { @apply px-2 py-1 text-xs min-h-[28px] bg-transparent; } .action-btn { @apply inline-flex items-center justify-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer min-h-[44px]; color: var(--text-muted); background: transparent; } .action-btn:hover { background: var(--surface-bg); color: var(--text-secondary); } .action-btn-liked { @apply text-red-600; animation: like-pop 400ms ease-out; } .action-btn-disabled { @apply opacity-50 cursor-not-allowed; } .action-btn-disabled:hover { background: transparent; } /* Action Menu (More dropdown) */ .action-menu { @apply absolute left-1/2 -translate-x-1/2 w-36 rounded-lg py-1 z-50; background: var(--card-bg); border: 1px solid var(--card-border); box-shadow: var(--shadow-md); } /* Dropdown menu (top-positioned, for headers/nav) */ .dropdown-menu { @apply absolute right-0 mt-2 w-48 rounded-lg py-1 z-50; background: var(--card-bg); border: 1px solid var(--card-border); box-shadow: var(--shadow-md); } .dropdown-item { @apply block px-4 py-2 text-sm transition-colors; color: var(--text-muted); } .dropdown-item:hover { background: var(--surface-bg); } .dropdown-item-disabled { @apply block px-4 py-2 text-sm cursor-not-allowed; color: var(--text-placeholder); } .dropdown-item-mod { @apply text-amber-700; } .dropdown-item-mod:hover { @apply bg-amber-50; } .dropdown-header { @apply px-4 py-2; border-bottom: 1px solid var(--surface-border); } .dropdown-divider { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--surface-border); } .action-menu-item { @apply flex items-center gap-2 w-full px-3 py-2 text-sm transition-colors cursor-pointer text-left; color: var(--text-muted); } .action-menu-item:hover { background: var(--surface-bg); } .action-menu-item-danger { @apply text-red-600; } .action-menu-item-danger:hover { @apply bg-red-50; } .action-menu-item-warning { @apply text-amber-600; } .action-menu-item-warning:hover { @apply bg-amber-50; } .action-menu-divider { @apply my-1; border-top: 1px solid var(--surface-border); } /* Hidden record indicator badge */ .hidden-badge { @apply inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-amber-100 text-amber-700 rounded; } /* Alert banners */ .alert-warning { @apply rounded-lg p-4; background: var(--alert-warning-bg); border: 1px solid var(--alert-warning-border); color: var(--alert-warning-text); } .alert-warning-muted { color: var(--alert-warning-text-muted); } /* Home page action buttons */ .home-action-primary { @apply inline-flex items-center justify-center font-medium transition-all cursor-pointer; background: linear-gradient(135deg, #6b4423, #4a2c2a); color: #FAF7F5; border: 1px solid #6b4423; box-shadow: var(--shadow-sm); } .home-action-primary:hover { box-shadow: var(--shadow-md); filter: brightness(1.1); } .home-action-secondary { @apply inline-flex items-center justify-center font-medium transition-all cursor-pointer; background: var(--card-bg); color: var(--text-primary); border: 1.5px solid var(--card-border); box-shadow: var(--shadow-sm); } .home-action-secondary:hover { border-color: var(--input-border-focus); box-shadow: var(--shadow-md); } } /* ======================================== HTMX Transition Classes ======================================== */ /* CRITICAL: Prevent content from being stuck invisible during history restore */ /* Override HTMX transition classes during history restoration */ body.htmx-history-restoring main, body.htmx-history-restoring .htmx-swapping, body.htmx-history-restoring .htmx-transitioning { opacity: 1 !important; transform: none !important; animation: none !important; transition: none !important; } /* During swap transition */ .htmx-swapping { opacity: 0; transform: translateY(5px); transition: opacity 100ms ease-out, transform 100ms ease-out; } /* After content is added */ .htmx-added { opacity: 0; animation: fade-in-slide-up 200ms ease-out forwards; } /* During settling phase */ .htmx-settling { opacity: 1; transform: translateY(0); transition: opacity 100ms ease-in, transform 100ms ease-in; } /* Transitioning state (no overlay - looks bad) */ .htmx-transitioning { position: relative; /* Removed overlay ::after pseudo-element - it created unwanted shadow effects */ } /* ======================================== Component-Specific Transitions ======================================== */ /* Feed cards appear with stagger effect */ .feed-card { animation: fade-in-slide-up 300ms ease-out backwards; } .feed-card:nth-child(1) { animation-delay: 0ms; } .feed-card:nth-child(2) { animation-delay: 50ms; } .feed-card:nth-child(3) { animation-delay: 100ms; } .feed-card:nth-child(4) { animation-delay: 150ms; } .feed-card:nth-child(5) { animation-delay: 200ms; } .feed-card:nth-child(n + 6) { animation-delay: 250ms; } /* Modal transitions (enhanced) */ .modal-backdrop { animation: fade-in 100ms ease-out; } .modal-content { animation: modal-appear 150ms ease-out; } @keyframes modal-appear { from { opacity: 0; transform: scale(0.9) translateY(-20px); } to { opacity: 1; transform: scale(1) translateY(0); } } /* HTML5 Dialog Element Transitions */ .modal-dialog { opacity: 0; transform: scale(0.95); transition: opacity 100ms ease-out, transform 100ms ease-out, overlay 100ms ease-out allow-discrete, display 100ms ease-out allow-discrete; } .modal-dialog[open] { opacity: 1; transform: scale(1); } /* Backdrop fade-in transition */ .modal-dialog::backdrop { background-color: rgba(0, 0, 0, 0); transition: background-color 100ms ease-out, backdrop-filter 100ms ease-out, display 100ms ease-out allow-discrete, overlay 100ms ease-out allow-discrete; } .modal-dialog[open]::backdrop { background-color: rgba(0, 0, 0, 0.4); } /* Starting style for new browsers that support @starting-style */ @supports (transition-behavior: allow-discrete) { @starting-style { .modal-dialog[open] { opacity: 0; transform: scale(0.95); } .modal-dialog[open]::backdrop { background-color: rgba(0, 0, 0, 0); } } } /* Modal content inside dialog - no separate animation needed */ /* The dialog element itself handles the transition */ /* ======================================== Keyframes ======================================== */ @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes fade-in-slide-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Like button pop animation */ @keyframes like-pop { 0% { transform: scale(1); } 15% { transform: scale(1.3); } 30% { transform: scale(0.9); } 45% { transform: scale(1.15); } 60% { transform: scale(0.95); } 75% { transform: scale(1.05); } 100% { transform: scale(1); } } /* Like button shrink animation for unlike */ @keyframes like-shrink { 0% { transform: scale(1); } 50% { transform: scale(0.8); } 100% { transform: scale(1); } } /* ======================================== Loading States ======================================== */ /* Enhance skeleton loading animations */ .animate-pulse { animation: enhanced-pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite; } @keyframes enhanced-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* ======================================== Reduced Motion Override ======================================== */ /* Respect user's motion preferences */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }