/** * Central Theme System for Kiwi * * This file contains all reusable, theme-aware, responsive CSS classes. * Components should use these classes instead of custom styles where possible. */ /* ============================================ LAYOUT UTILITIES - RESPONSIVE GRIDS ============================================ */ .grid-responsive { display: grid; gap: var(--spacing-md); } .grid-auto { display: grid; gap: var(--spacing-md); grid-template-columns: 1fr; } /* Stats grid — horizontal strip of compact stats */ .grid-stats { display: grid; gap: var(--spacing-md); grid-template-columns: 1fr; } .grid-stats-strip { display: flex; gap: 0; overflow: hidden; border-radius: var(--radius-lg); background: var(--color-bg-secondary); border: 1px solid var(--color-border); } .grid-stats-strip .stat-strip-item { flex: 1; text-align: center; padding: var(--spacing-sm) var(--spacing-xs); border-right: 1px solid var(--color-border); } .grid-stats-strip .stat-strip-item:last-child { border-right: none; } /* Force specific column counts */ .grid-1 { grid-template-columns: 1fr; } .grid-2 { grid-template-columns: repeat(2, 1fr); } .grid-3 { grid-template-columns: repeat(3, 1fr); } .grid-4 { grid-template-columns: repeat(4, 1fr); } /* ============================================ FLEXBOX UTILITIES ============================================ */ .flex { display: flex; } .flex-col { display: flex; flex-direction: column; } .flex-wrap { flex-wrap: wrap; } .flex-center { display: flex; align-items: center; justify-content: center; } .flex-between { display: flex; justify-content: space-between; align-items: center; } .flex-start { display: flex; justify-content: flex-start; align-items: center; } .flex-end { display: flex; justify-content: flex-end; align-items: center; } .flex-responsive { display: flex; gap: var(--spacing-md); flex-wrap: wrap; } /* ============================================ SPACING UTILITIES ============================================ */ .gap-xs { gap: var(--spacing-xs); } .gap-sm { gap: var(--spacing-sm); } .gap-md { gap: var(--spacing-md); } .gap-lg { gap: var(--spacing-lg); } .gap-xl { gap: var(--spacing-xl); } .p-0 { padding: 0; } .p-xs { padding: var(--spacing-xs); } .p-sm { padding: var(--spacing-sm); } .p-md { padding: var(--spacing-md); } .p-lg { padding: var(--spacing-lg); } .p-xl { padding: var(--spacing-xl); } .m-0 { margin: 0; } .m-xs { margin: var(--spacing-xs); } .m-sm { margin: var(--spacing-sm); } .m-md { margin: var(--spacing-md); } .m-lg { margin: var(--spacing-lg); } .m-xl { margin: var(--spacing-xl); } .mt-xs { margin-top: var(--spacing-xs); } .mt-sm { margin-top: var(--spacing-sm); } .mt-md { margin-top: var(--spacing-md); } .mb-xs { margin-bottom: var(--spacing-xs); } .mb-sm { margin-bottom: var(--spacing-sm); } .mb-md { margin-bottom: var(--spacing-md); } .mb-lg { margin-bottom: var(--spacing-lg); } .ml-xs { margin-left: var(--spacing-xs); } .ml-md { margin-left: var(--spacing-md); } .mr-md { margin-right: var(--spacing-md); } .pt-md { padding-top: var(--spacing-md); } .pb-md { padding-bottom: var(--spacing-md); } .pl-md { padding-left: var(--spacing-md); } .pr-md { padding-right: var(--spacing-md); } /* ============================================ CARD COMPONENTS - THEME AWARE ============================================ */ .card { background: var(--color-bg-card); border-radius: var(--radius-xl); padding: var(--spacing-lg); box-shadow: var(--shadow-md); border: 1px solid var(--color-border); transition: box-shadow 0.2s ease; } .card:hover { box-shadow: var(--shadow-lg); } .card-sm { background: var(--color-bg-card); border-radius: var(--radius-lg); padding: var(--spacing-md); box-shadow: var(--shadow-sm); border: 1px solid var(--color-border); } .card-secondary { background: var(--color-bg-secondary); border-radius: var(--radius-lg); padding: var(--spacing-md); box-shadow: var(--shadow-sm); border: 1px solid var(--color-border); } /* Status border variants */ .card-success { border-left: 3px solid var(--color-success); } .card-warning { border-left: 3px solid var(--color-warning); } .card-error { border-left: 3px solid var(--color-error); } .card-info { border-left: 3px solid var(--color-info); } /* ============================================ BUTTON COMPONENTS - THEME AWARE ============================================ */ .btn { padding: var(--spacing-sm) var(--spacing-md); border: 1px solid transparent; border-radius: var(--radius-md); font-size: var(--font-size-sm); font-weight: 600; font-family: var(--font-body); cursor: pointer; transition: all 0.18s ease; white-space: nowrap; display: inline-flex; align-items: center; justify-content: center; gap: var(--spacing-xs); } .btn:hover { transform: translateY(-1px); } .btn:active { transform: translateY(0); } .btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; } /* Button variants */ .btn-primary { background: var(--gradient-primary); color: #1e1c1a; border: none; font-weight: 700; box-shadow: var(--shadow-amber); } .btn-primary:hover:not(:disabled) { box-shadow: 0 6px 20px rgba(232, 168, 32, 0.35); } .btn-success { background: var(--color-success); color: white; } .btn-success:hover:not(:disabled) { background: var(--color-success-dark); } .btn-error { background: var(--color-error); color: white; } .btn-error:hover:not(:disabled) { background: var(--color-error-dark); } .btn-info { background: var(--color-info); color: white; } .btn-info:hover:not(:disabled) { background: var(--color-info-dark); } .btn-secondary { background: var(--color-bg-elevated); color: var(--color-text-secondary); border: 1px solid var(--color-border); } .btn-secondary:hover:not(:disabled) { background: var(--color-bg-primary); border-color: var(--color-primary); color: var(--color-primary); } .btn-secondary.active { background: var(--color-primary); color: #1e1c1a; border-color: var(--color-primary); font-weight: 700; } /* Pill chip button — for filter chips */ .btn-chip { padding: var(--spacing-xs) var(--spacing-sm); border: 1px solid var(--color-border); border-radius: var(--radius-pill); font-size: var(--font-size-xs); font-weight: 500; font-family: var(--font-body); background: var(--color-bg-elevated); color: var(--color-text-secondary); cursor: pointer; transition: all 0.18s ease; white-space: nowrap; } .btn-chip:hover { border-color: var(--color-primary); color: var(--color-primary); } .btn-chip.active { background: var(--color-primary); color: #1e1c1a; border-color: var(--color-primary); font-weight: 700; } /* Button sizes */ .btn-sm { padding: var(--spacing-xs) var(--spacing-sm); font-size: var(--font-size-xs); } .btn-lg { padding: var(--spacing-md) var(--spacing-xl); font-size: var(--font-size-base); } /* Icon-only action button */ .btn-icon { width: 32px; height: 32px; padding: 0; border: none; border-radius: var(--radius-md); background: transparent; color: var(--color-text-muted); cursor: pointer; transition: all 0.18s ease; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; } .btn-icon:hover { background: var(--color-bg-primary); color: var(--color-text-primary); transform: none; } .btn-icon.btn-icon-danger:hover { color: var(--color-error); } .btn-icon.btn-icon-success:hover { color: var(--color-success); } /* ============================================ FORM COMPONENTS - THEME AWARE ============================================ */ .form-group { margin-bottom: var(--spacing-md); } .form-label { display: block; margin-bottom: var(--spacing-xs); font-weight: 600; color: var(--color-text-secondary); font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: 0.06em; font-family: var(--font-body); } .form-input, .form-select, .form-textarea { width: 100%; padding: var(--spacing-sm) var(--spacing-md); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-bg-input); color: var(--color-text-primary); font-size: var(--font-size-sm); font-family: var(--font-body); transition: border-color 0.18s ease, box-shadow 0.18s ease; box-sizing: border-box; } .form-input:focus, .form-select:focus, .form-textarea:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-warning-bg); } .form-textarea { resize: vertical; min-height: 80px; font-family: var(--font-body); } .form-row { display: grid; gap: var(--spacing-md); grid-template-columns: 1fr; } /* Chip row filter bar — horizontal scroll */ .filter-chip-row { display: flex; gap: var(--spacing-xs); overflow-x: auto; padding-bottom: var(--spacing-xs); scrollbar-width: none; } .filter-chip-row::-webkit-scrollbar { display: none; } /* ============================================ TEXT UTILITIES ============================================ */ .text-xs { font-size: var(--font-size-xs); } .text-sm { font-size: var(--font-size-sm); } .text-base { font-size: var(--font-size-base); } .text-lg { font-size: var(--font-size-lg); } .text-xl { font-size: var(--font-size-xl); } .text-2xl { font-size: var(--font-size-2xl); } /* Display font */ .text-display { font-family: var(--font-display); font-style: italic; } /* Mono font */ .text-mono { font-family: var(--font-mono); } .text-primary { color: var(--color-text-primary); } .text-secondary { color: var(--color-text-secondary); } .text-muted { color: var(--color-text-muted); } .text-success { color: var(--color-success); } .text-warning { color: var(--color-warning); } .text-error { color: var(--color-error); } .text-info { color: var(--color-info); } .text-amber { color: var(--color-primary); } .text-center { text-align: center; } .text-left { text-align: left; } .text-right { text-align: right; } .font-bold { font-weight: 700; } .font-semibold { font-weight: 600; } .font-normal { font-weight: 400; } /* ============================================ LOCATION DOT INDICATORS ============================================ */ .loc-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; display: inline-block; } .loc-dot-fridge { background: var(--color-loc-fridge); } .loc-dot-freezer { background: var(--color-loc-freezer); } .loc-dot-garage_freezer { background: var(--color-loc-garage-freezer); } .loc-dot-pantry { background: var(--color-loc-pantry); } .loc-dot-cabinet { background: var(--color-loc-cabinet); } /* Location left-border strip on inventory rows */ .inv-row-fridge { border-left-color: var(--color-loc-fridge) !important; } .inv-row-freezer { border-left-color: var(--color-loc-freezer) !important; } .inv-row-garage_freezer { border-left-color: var(--color-loc-garage-freezer) !important; } .inv-row-pantry { border-left-color: var(--color-loc-pantry) !important; } .inv-row-cabinet { border-left-color: var(--color-loc-cabinet) !important; } /* ============================================ RESPONSIVE UTILITIES ============================================ */ .mobile-only { display: none; } .desktop-only { display: block; } .w-full { width: 100%; } .w-auto { width: auto; } .h-full { height: 100%; } .h-auto { height: auto; } /* ============================================ MOBILE BREAKPOINTS (<=480px) ============================================ */ @media (max-width: 480px) { .mobile-only { display: block; } .desktop-only { display: none; } .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr !important; } .flex-responsive { flex-direction: column; } .btn-mobile-full { width: 100%; min-width: 100%; } .card { padding: var(--spacing-md); border-radius: var(--radius-lg); } .card-sm { padding: var(--spacing-sm); } .btn { white-space: normal; text-align: center; } } /* ============================================ TABLET BREAKPOINTS (481px - 768px) ============================================ */ @media (min-width: 481px) and (max-width: 768px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); } .grid-auto { grid-template-columns: repeat(2, 1fr); } .grid-stats { grid-template-columns: repeat(2, 1fr); } .form-row { grid-template-columns: 1fr 1fr; } } /* ============================================ DESKTOP BREAKPOINTS (769px - 1024px) ============================================ */ @media (min-width: 769px) and (max-width: 1024px) { .grid-auto { grid-template-columns: repeat(2, 1fr); } .grid-stats { grid-template-columns: repeat(4, 1fr); } .grid-4 { grid-template-columns: repeat(3, 1fr); } } /* ============================================ LARGE DESKTOP (>=1025px) ============================================ */ @media (min-width: 1025px) { .grid-auto { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); } .grid-stats { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } .form-row { grid-template-columns: 1fr 1fr; } } /* ============================================ STATUS & STATE UTILITIES ============================================ */ .status-badge { display: inline-flex; align-items: center; padding: 3px var(--spacing-sm); border-radius: var(--radius-pill); font-size: var(--font-size-xs); font-weight: 600; font-family: var(--font-mono); letter-spacing: 0.02em; } .status-success { background: var(--color-success-bg); color: var(--color-success-light); border: 1px solid var(--color-success-border); } .status-warning { background: var(--color-warning-bg); color: var(--color-warning-light); border: 1px solid var(--color-warning-border); } .status-error { background: var(--color-error-bg); color: var(--color-error-light); border: 1px solid var(--color-error-border); } .status-info { background: var(--color-info-bg); color: var(--color-info-light); border: 1px solid var(--color-info-border); } /* ============================================ ANIMATION UTILITIES ============================================ */ .fade-in { animation: fadeIn 0.3s ease-in; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .slide-up { animation: slideUp 0.3s ease-out; } @keyframes slideUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } /* Urgency pulse — for items expiring very soon */ @keyframes urgencyPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } .pulse-urgent { animation: urgencyPulse 1.8s ease-in-out infinite; } /* ============================================ LOADING UTILITIES ============================================ */ .spinner { border: 2px solid var(--color-border); border-top: 2px solid var(--color-primary); border-radius: 50%; width: 36px; height: 36px; animation: spin 0.9s linear infinite; margin: 0 auto; } .spinner-sm { width: 18px; height: 18px; border-width: 2px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* ============================================ DIVIDER ============================================ */ .divider { height: 1px; background: var(--color-border); margin: var(--spacing-lg) 0; } .divider-md { margin: var(--spacing-md) 0; } /* ============================================ SECTION HEADERS (display font) ============================================ */ .section-title { font-family: var(--font-display); font-style: italic; font-weight: 600; color: var(--color-text-primary); margin: 0; } /* ============================================ EASTER EGG — GRID KITCHEN NEON MODE Activated via Konami code ============================================ */ body.neon-mode .card, body.neon-mode .card-sm, body.neon-mode .card-secondary { box-shadow: 0 0 0 1px rgba(255, 0, 110, 0.35), 0 0 12px rgba(255, 0, 110, 0.18), 0 2px 20px rgba(131, 56, 236, 0.15); } body.neon-mode .btn-primary { box-shadow: 0 0 18px rgba(255, 0, 110, 0.55), 0 0 36px rgba(131, 56, 236, 0.25); color: #fff; } body.neon-mode .wordmark-kiwi { text-shadow: 0 0 10px rgba(255, 0, 110, 0.7), 0 0 24px rgba(131, 56, 236, 0.5); } body.neon-mode .sidebar, body.neon-mode .bottom-nav { border-color: rgba(255, 0, 110, 0.3); box-shadow: 4px 0 20px rgba(255, 0, 110, 0.12); } body.neon-mode .sidebar-item.active, body.neon-mode .nav-item.active { text-shadow: 0 0 8px currentColor; } /* Scanline overlay */ body.neon-mode::after { content: ''; position: fixed; inset: 0; background: repeating-linear-gradient( 0deg, transparent, transparent 3px, rgba(0, 0, 0, 0.08) 3px, rgba(0, 0, 0, 0.08) 4px ); pointer-events: none; z-index: 9998; animation: scanlineScroll 8s linear infinite; } @keyframes scanlineScroll { 0% { background-position: 0 0; } 100% { background-position: 0 80px; } } /* CRT flicker on wordmark */ body.neon-mode .wordmark-kiwi { animation: crtFlicker 6s ease-in-out infinite; } @keyframes crtFlicker { 0%, 94%, 100% { opacity: 1; } 95% { opacity: 0.88; } 97% { opacity: 0.95; } 98% { opacity: 0.82; } } /* ============================================ EASTER EGG — KIWI BIRD SPRITE ============================================ */ .kiwi-bird-stage { position: fixed; bottom: 72px; /* above bottom nav */ left: 0; right: 0; height: 72px; pointer-events: none; z-index: 9999; overflow: hidden; } @media (min-width: 769px) { .kiwi-bird-stage { bottom: 0; left: 200px; /* clear the sidebar */ } } .kiwi-bird { position: absolute; bottom: 8px; width: 64px; height: 64px; will-change: transform; } /* Enters from right, walks left */ .kiwi-bird.rtl { animation: kiwiWalkRtl 5.5s ease-in-out forwards; } .kiwi-bird.rtl .kiwi-svg { transform: scaleX(1); /* faces left */ } /* Enters from left, walks right */ .kiwi-bird.ltr { animation: kiwiWalkLtr 5.5s ease-in-out forwards; } .kiwi-bird.ltr .kiwi-svg { transform: scaleX(-1); /* faces right */ } /* Bob on each step */ .kiwi-svg { display: block; animation: kiwiBob 0.38s steps(1) infinite; } @keyframes kiwiWalkRtl { 0% { right: -80px; } 15% { right: 35%; } /* enter and slow */ 40% { right: 35%; } /* pause — sniffing */ 55% { right: 38%; } /* tiny shuffle */ 60% { right: 35%; } 85% { right: 35%; } 100% { right: calc(100% + 80px); } /* exit left */ } @keyframes kiwiWalkLtr { 0% { left: -80px; } 15% { left: 35%; } 40% { left: 35%; } 55% { left: 38%; } 60% { left: 35%; } 85% { left: 35%; } 100% { left: calc(100% + 80px); } } @keyframes kiwiBob { 0% { transform: translateY(0) scaleX(var(--bird-flip, 1)); } 50% { transform: translateY(-4px) scaleX(var(--bird-flip, 1)); } }