<template>
  <div class="inventory-list">

    <!-- Stats Strip -->
    <div v-if="stats" class="stats-strip">
      <div class="stat-strip-item">
        <div class="stat-num">{{ stats.total_items }}</div>
        <div class="stat-lbl">Total</div>
      </div>
      <div class="stat-strip-item">
        <div class="stat-num text-amber">{{ stats.available_items }}</div>
        <div class="stat-lbl">Available</div>
      </div>
      <div
        :class="['stat-strip-item', 'stat-clickable', { 'stat-active': expiryView === 'soon' }]"
        @click="toggleExpiryView('soon')"
        @keydown.enter="toggleExpiryView('soon')"
        role="button"
        tabindex="0"
        :aria-label="`${store.expiringItems.length} items expiring soon — tap to view`"
      >
        <div class="stat-num text-warning">{{ store.expiringItems.length }}</div>
        <div class="stat-lbl">Expiring</div>
      </div>
      <div
        :class="['stat-strip-item', 'stat-clickable', { 'stat-active': expiryView === 'expired' }]"
        @click="toggleExpiryView('expired')"
        @keydown.enter="toggleExpiryView('expired')"
        role="button"
        tabindex="0"
        :aria-label="`${store.expiredItems.length} expired items — tap to view`"
      >
        <div class="stat-num text-error">{{ store.expiredItems.length }}</div>
        <div class="stat-lbl">Expired</div>
      </div>
    </div>

    <!-- Scan Card — collapsible with Gun / Camera toggle -->
    <div class="card scan-card">
      <div class="scan-card-header">
        <h2 class="section-title">Add Item</h2>
        <div class="scan-mode-toggle">
          <button
            :class="['scan-mode-btn', { active: scanMode === 'gun' }]"
            @click="scanMode = 'gun'"
            type="button"
            aria-label="Scanner gun mode"
          >
            <!-- barcode icon -->
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
              <rect x="2" y="4" width="2" height="16" rx="0.5"/>
              <rect x="6" y="4" width="1" height="16" rx="0.5"/>
              <rect x="9" y="4" width="2" height="16" rx="0.5"/>
              <rect x="13" y="4" width="1" height="16" rx="0.5"/>
              <rect x="16" y="4" width="2" height="16" rx="0.5"/>
              <rect x="20" y="4" width="2" height="16" rx="0.5"/>
            </svg>
            <span>Gun</span>
          </button>
          <button
            :class="['scan-mode-btn', { active: scanMode === 'camera' }]"
            @click="scanMode = 'camera'"
            type="button"
            aria-label="Camera scan mode"
          >
            <!-- camera icon -->
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
              <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/>
              <circle cx="12" cy="13" r="4"/>
            </svg>
            <span>Camera</span>
          </button>
          <button
            :class="['scan-mode-btn', { active: scanMode === 'manual' }]"
            @click="scanMode = 'manual'"
            type="button"
            aria-label="Manual entry mode"
          >
            <!-- pencil icon -->
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
              <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
              <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
            </svg>
            <span>Manual</span>
          </button>
        </div>
      </div>

      <!-- Scanner Gun Panel -->
      <div v-if="scanMode === 'gun'" class="scan-panel">
        <div class="form-group">
          <label class="form-label">Barcode input</label>
          <input
            id="scannerGunInput"
            ref="scannerGunInput"
            v-model="scannerBarcode"
            type="text"
            placeholder="Focus here and scan with barcode gun…"
            @keypress.enter="handleScannerGunInput"
            autocomplete="off"
            class="form-input scanner-input"
          />
        </div>

        <div class="scan-meta-row">
          <div class="form-group scan-location-group">
            <label class="form-label">Location</label>
            <div class="filter-chip-row">
              <button
                v-for="loc in locations"
                :key="loc.value"
                :class="['btn-chip', { active: scannerLocation === loc.value }]"
                @click="scannerLocation = loc.value"
                type="button"
              >{{ loc.label }}</button>
            </div>
          </div>

          <div class="form-group scan-qty-group">
            <label class="form-label">Qty</label>
            <div class="quantity-control">
              <button class="btn-qty" @click="scannerQuantity = Math.max(0.1, scannerQuantity - 1)" type="button" aria-label="Decrease quantity">−</button>
              <input v-model.number="scannerQuantity" type="number" min="0.1" step="0.1" class="qty-input" aria-label="Quantity" />
              <button class="btn-qty" @click="scannerQuantity += 1" type="button" aria-label="Increase quantity">+</button>
            </div>
          </div>
        </div>

        <div v-if="scannerLoading" class="loading-inline">
          <div class="spinner spinner-sm"></div>
          <span>Processing barcode…</span>
        </div>

        <div v-if="scannerResults.length > 0" class="results">
          <div v-for="(result, index) in scannerResults" :key="index" :class="['result-item', `result-${result.type}`]">
            {{ result.message }}
          </div>
        </div>
      </div>

      <!-- Label Capture Panel (paid tier — appears after gap detection) -->
      <div v-if="capturePhase !== null" class="label-capture-panel">

        <!-- Offer phase -->
        <div v-if="capturePhase === 'offer'" class="capture-offer">
          <p class="capture-offer-text">We couldn't find this product. Photograph the nutrition label to add it.</p>
          <div class="capture-offer-actions">
            <button class="btn btn-primary" type="button" @click="triggerCaptureLabelInput">
              Capture label
            </button>
            <button class="btn btn-ghost" type="button" @click="dismissCapture">
              Skip
            </button>
          </div>
          <input
            ref="captureFileInput"
            type="file"
            accept="image/*"
            capture="environment"
            style="display: none"
            @change="handleLabelPhotoSelect"
          />
        </div>

        <!-- Uploading / processing phase -->
        <div v-else-if="capturePhase === 'uploading'" class="capture-processing">
          <div class="loading-inline">
            <div class="spinner spinner-sm"></div>
            <span>Reading the label…</span>
          </div>
        </div>

        <!-- Review phase -->
        <div v-else-if="capturePhase === 'reviewing' && captureExtraction" class="capture-review">
          <p class="capture-review-note">
            Check the details below.
            <span v-if="captureExtraction.needs_review" class="capture-review-low-conf">
              Fields highlighted in amber weren't fully legible — please verify them.
            </span>
          </p>

          <div class="form-row">
            <div class="form-group">
              <label class="form-label">Product name</label>
              <input v-model="captureReview.product_name" type="text" class="form-input" placeholder="Product name" />
            </div>
            <div class="form-group">
              <label class="form-label">Brand</label>
              <input v-model="captureReview.brand" type="text" class="form-input" placeholder="Brand (optional)" />
            </div>
          </div>

          <p class="form-section-label">Nutrition per serving</p>
          <div class="capture-nutrition-grid">
            <div
              v-for="field in captureNutritionFields"
              :key="field.key"
              class="form-group"
            >
              <label
                :class="['form-label', { 'capture-field-amber': captureExtraction.needs_review && captureExtraction[field.src as keyof typeof captureExtraction] == null }]"
              >{{ field.label }}</label>
              <input
                v-model="captureReview[field.key as keyof typeof captureReview]"
                type="number"
                min="0"
                step="0.1"
                class="form-input"
                :placeholder="field.unit"
              />
            </div>
          </div>

          <div class="form-group" style="margin-top: var(--spacing-sm)">
            <label class="form-label">Ingredients (comma-separated)</label>
            <input v-model="captureReview.ingredients" type="text" class="form-input" placeholder="flour, water, salt…" />
          </div>
          <div class="form-group">
            <label class="form-label">Allergens (comma-separated)</label>
            <input v-model="captureReview.allergens" type="text" class="form-input" placeholder="wheat, milk…" />
          </div>

          <div class="capture-review-actions">
            <button class="btn btn-primary" type="button" :disabled="captureLoading" @click="confirmCapture">
              <span v-if="captureLoading"><div class="spinner spinner-sm"></div></span>
              <span v-else>Looks good — save</span>
            </button>
            <button class="btn btn-ghost" type="button" @click="capturePhase = 'offer'">
              Retake photo
            </button>
            <button class="btn btn-ghost" type="button" @click="dismissCapture">
              Discard
            </button>
          </div>
        </div>
      </div>

      <!-- Camera Scan Panel -->
      <div v-if="scanMode === 'camera'" class="scan-panel">
        <div class="upload-area" @click="triggerBarcodeInput">
          <svg class="upload-icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
            <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/>
            <circle cx="12" cy="13" r="4"/>
          </svg>
          <div class="upload-text">Tap to photograph a barcode</div>
          <div class="upload-hint">JPG, PNG — takes a snapshot via your camera</div>
        </div>
        <input
          ref="barcodeFileInput"
          type="file"
          accept="image/*"
          capture="environment"
          style="display: none"
          @change="handleBarcodeImageSelect"
        />

        <div class="scan-meta-row" style="margin-top: var(--spacing-md)">
          <div class="form-group scan-location-group">
            <label class="form-label">Location</label>
            <div class="filter-chip-row">
              <button
                v-for="loc in locations"
                :key="loc.value"
                :class="['btn-chip', { active: barcodeLocation === loc.value }]"
                @click="barcodeLocation = loc.value"
                type="button"
              >{{ loc.label }}</button>
            </div>
          </div>

          <div class="form-group scan-qty-group">
            <label class="form-label">Qty</label>
            <div class="quantity-control">
              <button class="btn-qty" @click="barcodeQuantity = Math.max(0.1, barcodeQuantity - 1)" type="button" aria-label="Decrease quantity">−</button>
              <input v-model.number="barcodeQuantity" type="number" min="0.1" step="0.1" class="qty-input" aria-label="Quantity" />
              <button class="btn-qty" @click="barcodeQuantity += 1" type="button" aria-label="Increase quantity">+</button>
            </div>
          </div>
        </div>

        <div v-if="barcodeLoading" class="loading-inline">
          <div class="spinner spinner-sm"></div>
          <span>Scanning barcode…</span>
        </div>

        <div v-if="barcodeResults.length > 0" class="results">
          <div v-for="(result, index) in barcodeResults" :key="index" :class="['result-item', `result-${result.type}`]">
            {{ result.message }}
          </div>
        </div>
      </div>

      <!-- Manual Add Panel -->
      <div v-if="scanMode === 'manual'" class="scan-panel">
        <div class="form-row">
          <div class="form-group">
            <label class="form-label">Product Name *</label>
            <input v-model="manualForm.name" type="text" placeholder="e.g., Organic Milk" required class="form-input" />
          </div>
          <div class="form-group">
            <label class="form-label">Brand</label>
            <input v-model="manualForm.brand" type="text" placeholder="e.g., Horizon" class="form-input" />
          </div>
        </div>

        <div class="scan-meta-row">
          <div class="form-group scan-location-group">
            <label class="form-label">Location *</label>
            <div class="filter-chip-row">
              <button
                v-for="loc in locations"
                :key="loc.value"
                :class="['btn-chip', { active: manualForm.location === loc.value }]"
                @click="manualForm.location = loc.value"
                type="button"
              >{{ loc.label }}</button>
            </div>
          </div>

          <div class="form-group scan-qty-group">
            <label class="form-label">Qty</label>
            <div class="quantity-control">
              <button class="btn-qty" @click="manualForm.quantity = Math.max(0.1, manualForm.quantity - 1)" type="button" aria-label="Decrease quantity">−</button>
              <input v-model.number="manualForm.quantity" type="number" min="0.1" step="0.1" required class="qty-input" aria-label="Quantity" />
              <button class="btn-qty" @click="manualForm.quantity += 1" type="button" aria-label="Increase quantity">+</button>
            </div>
          </div>
        </div>

        <div class="form-row">
          <div class="form-group">
            <label class="form-label">Unit</label>
            <div class="filter-chip-row">
              <button
                v-for="unit in units"
                :key="unit.value"
                :class="['btn-chip', { active: manualForm.unit === unit.value }]"
                @click="manualForm.unit = unit.value"
                type="button"
              >{{ unit.label }}</button>
            </div>
          </div>
          <div class="form-group">
            <label class="form-label">Expiration Date</label>
            <input v-model="manualForm.expirationDate" type="date" class="form-input" />
          </div>
        </div>

        <button @click="addManualItem" class="btn btn-primary w-full" :disabled="manualLoading">
          {{ manualLoading ? 'Adding…' : 'Add to Pantry' }}
        </button>
      </div>
    </div>

    <!-- Inventory Section -->
    <div class="inventory-section">
      <!-- Filter chips -->
      <div class="inventory-header">
        <h2 class="section-title">
          {{ expiryView === 'soon' ? 'Expiring Soon' : expiryView === 'expired' ? 'Expired Items' : 'Pantry' }}
        </h2>
        <button v-if="expiryView" @click="expiryView = null" class="btn-text expiry-back-btn" type="button">
          ← All items
        </button>
      </div>

      <!-- Expiry Panel -->
      <template v-if="expiryView === 'soon'">
        <div v-if="!store.expiringItems.length" class="empty-state">
          <p class="text-secondary">Nothing expiring in the next 7 days.</p>
        </div>
        <div v-else class="expiry-panel">
          <!-- Urgent: ≤3 days -->
          <div v-if="urgentItems.length" class="expiry-group">
            <div class="expiry-group-label expiry-group-urgent">Use within 3 days</div>
            <div
              v-for="item in urgentItems"
              :key="item.id"
              class="expiry-item-row"
            >
              <span :class="['loc-dot', `loc-dot-${item.location}`]"></span>
              <div class="expiry-item-name">
                <span class="inv-name">{{ item.product_name || 'Unknown' }}</span>
                <span v-if="item.category" class="inv-category">{{ item.category }}</span>
              </div>
              <div class="expiry-item-right">
                <span class="inv-qty">{{ formatQuantity(item.quantity, item.unit, settingsStore.unitSystem) }}</span>
                <span :class="['expiry-badge', getExpiryBadgeClass(item.expiration_date!)]">
                  {{ daysLabel(item.expiration_date!) }}
                </span>
                <div class="inv-actions">
                  <button @click="markAsConsumed(item)" class="btn-icon btn-icon-success" aria-label="Use">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <polyline points="4 10 8 14 16 6"/>
                    </svg>
                  </button>
                  <button @click="markAsDiscarded(item)" class="btn-icon btn-icon-discard" aria-label="Not used">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <path d="M4 4l12 12M4 16L16 4"/>
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </div>
          <!-- Soon: 4-7 days -->
          <div v-if="soonItems.length" class="expiry-group">
            <div class="expiry-group-label expiry-group-soon">Coming up (4–7 days)</div>
            <div
              v-for="item in soonItems"
              :key="item.id"
              class="expiry-item-row"
            >
              <span :class="['loc-dot', `loc-dot-${item.location}`]"></span>
              <div class="expiry-item-name">
                <span class="inv-name">{{ item.product_name || 'Unknown' }}</span>
                <span v-if="item.category" class="inv-category">{{ item.category }}</span>
              </div>
              <div class="expiry-item-right">
                <span class="inv-qty">{{ formatQuantity(item.quantity, item.unit, settingsStore.unitSystem) }}</span>
                <span :class="['expiry-badge', getExpiryBadgeClass(item.expiration_date!)]">
                  {{ daysLabel(item.expiration_date!) }}
                </span>
                <div class="inv-actions">
                  <button @click="markAsConsumed(item)" class="btn-icon btn-icon-success" aria-label="Use">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <polyline points="4 10 8 14 16 6"/>
                    </svg>
                  </button>
                  <button @click="markAsDiscarded(item)" class="btn-icon btn-icon-discard" aria-label="Not used">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <path d="M4 4l12 12M4 16L16 4"/>
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </template>

      <!-- Expired panel -->
      <template v-else-if="expiryView === 'expired'">
        <div v-if="!store.expiredItems.length" class="empty-state">
          <p class="text-secondary">No expired items.</p>
        </div>
        <div v-else class="expiry-panel">
          <!-- Items with a secondary use window -->
          <div v-if="secondaryStateItems.length" class="expiry-group">
            <div class="expiry-group-label expiry-group-secondary">Still useful with the right recipe</div>
            <div
              v-for="item in secondaryStateItems"
              :key="item.id"
              class="expiry-item-row expiry-item-secondary"
            >
              <span :class="['loc-dot', `loc-dot-${item.location}`]"></span>
              <div class="expiry-item-name">
                <span class="inv-name">{{ item.product_name || 'Unknown' }}</span>
                <span class="secondary-state-badge">{{ item.secondary_state }}</span>
                <span v-if="item.secondary_uses?.length" class="secondary-uses-text">
                  Good for: {{ item.secondary_uses!.slice(0, 3).join(', ') }}
                </span>
                <span v-if="item.secondary_warning" class="secondary-warning-text">
                  ⚠ {{ item.secondary_warning }}
                </span>
              </div>
              <div class="expiry-item-right">
                <span class="inv-qty">{{ formatQuantity(item.quantity, item.unit, settingsStore.unitSystem) }}</span>
                <div class="inv-actions">
                  <button @click="markAsConsumed(item)" class="btn-icon btn-icon-success" aria-label="Use now">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <polyline points="4 10 8 14 16 6"/>
                    </svg>
                  </button>
                  <button @click="markAsDiscarded(item)" class="btn-icon btn-icon-discard" aria-label="Not used">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <path d="M4 4l12 12M4 16L16 4"/>
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </div>
          <!-- Truly expired — past secondary window -->
          <div v-if="trulyExpiredItems.length" class="expiry-group">
            <div class="expiry-group-label expiry-group-done">Time to let it go</div>
            <div
              v-for="item in trulyExpiredItems"
              :key="item.id"
              class="expiry-item-row"
            >
              <span :class="['loc-dot', `loc-dot-${item.location}`]"></span>
              <div class="expiry-item-name">
                <span class="inv-name">{{ item.product_name || 'Unknown' }}</span>
                <span v-if="item.category" class="inv-category">{{ item.category }}</span>
              </div>
              <div class="expiry-item-right">
                <span class="inv-qty">{{ formatQuantity(item.quantity, item.unit, settingsStore.unitSystem) }}</span>
                <span class="expiry-badge expiry-expired">{{ daysLabel(item.expiration_date!) }}</span>
                <div class="inv-actions">
                  <button @click="markAsDiscarded(item)" class="btn-icon btn-icon-discard" aria-label="Not used">
                    <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                      <path d="M4 4l12 12M4 16L16 4"/>
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </template>

      <!-- Normal filter + list view -->
      <template v-else>
      <div class="filter-row">
        <div class="filter-chip-row">
          <button
            :class="['btn-chip', { active: locationFilter === 'all' }]"
            @click="locationFilter = 'all'; onFilterChange()"
            type="button"
          >All</button>
          <button
            v-for="loc in locations"
            :key="loc.value"
            :class="['btn-chip', { active: locationFilter === loc.value }]"
            @click="locationFilter = loc.value; onFilterChange()"
            type="button"
          >{{ loc.label }}</button>
        </div>

        <div class="filter-chip-row status-filter-row">
          <button
            v-for="status in statuses"
            :key="status.value"
            :class="['btn-chip', { active: statusFilter === status.value }]"
            @click="statusFilter = status.value; onFilterChange()"
            type="button"
          >{{ status.label }}</button>
        </div>
      </div>

      <!-- Loading -->
      <div v-if="loading && items.length === 0" class="empty-state">
        <div class="spinner"></div>
        <p class="text-muted text-sm" style="margin-top: var(--spacing-md)">Loading pantry…</p>
      </div>

      <!-- Empty State: clean slate (no items at all) -->
      <div v-else-if="!loading && filteredItems.length === 0 && store.items.length === 0" class="empty-state">
        <svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" class="empty-icon">
          <rect x="6" y="10" width="36" height="6" rx="2"/>
          <rect x="6" y="21" width="36" height="6" rx="2"/>
          <rect x="6" y="32" width="36" height="6" rx="2"/>
        </svg>
        <p class="text-secondary">Clean slate.</p>
        <p class="text-muted text-sm">Your pantry is ready for anything — scan a barcode or add an item above.</p>
      </div>

      <!-- Empty State: filter has no matches -->
      <div v-else-if="!loading && filteredItems.length === 0" class="empty-state">
        <svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" class="empty-icon">
          <circle cx="20" cy="20" r="12"/>
          <line x1="29" y1="29" x2="42" y2="42"/>
        </svg>
        <p class="text-secondary">Nothing matches that filter.</p>
        <p class="text-muted text-sm">Try a different location or status.</p>
      </div>

      <!-- Inventory shelf list -->
      <div v-else class="inv-list">
        <div
          v-for="item in filteredItems"
          :key="item.id"
          class="inv-row"
          :class="[getItemClass(item), `inv-row-${item.location}`]"
        >
          <!-- Location dot -->
          <span :class="['loc-dot', `loc-dot-${item.location}`]"></span>

          <!-- Name -->
          <div class="inv-row-name">
            <span class="inv-name">{{ item.product_name || 'Unknown Product' }}</span>
            <span v-if="item.category" class="inv-category">{{ item.category }}</span>
          </div>

          <!-- Right side: qty + expiry + actions -->
          <div class="inv-row-right">
            <span class="inv-qty">{{ formatQuantity(item.quantity, item.unit, settingsStore.unitSystem) }}</span>

            <!-- Opened expiry takes priority over sell-by date -->
            <span
              v-if="item.opened_expiry_date"
              :class="['expiry-badge', 'expiry-opened', getExpiryBadgeClass(item.opened_expiry_date)]"
              :title="`Opened · ${formatDateFull(item.opened_expiry_date)}`"
            >📂 {{ formatDateShort(item.opened_expiry_date) }}</span>
            <span
              v-else-if="item.expiration_date"
              :class="['expiry-badge', getExpiryBadgeClass(item.expiration_date)]"
              :title="formatDateFull(item.expiration_date)"
            >{{ formatDateShort(item.expiration_date) }}</span>

            <div class="inv-actions">
              <button @click="editItem(item)" class="btn-icon" aria-label="Edit">
                <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                  <path d="M13.586 3.586a2 2 0 112.828 2.828L7 14.828 4 16l1.172-3L13.586 3.586z"/>
                </svg>
              </button>
              <button
                v-if="!item.opened_date && item.status === 'available'"
                @click="markAsOpened(item)"
                class="btn-icon btn-icon-open"
                aria-label="Mark as opened today"
                title="I opened this today"
              >
                <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                  <path d="M5 8V6a7 7 0 0114 0v2"/>
                  <rect x="3" y="8" width="14" height="10" rx="2"/>
                  <circle cx="10" cy="13" r="1.5" fill="currentColor"/>
                </svg>
              </button>
              <button
                v-if="item.status === 'available'"
                @click="markAsConsumed(item)"
                class="btn-icon btn-icon-success"
                :aria-label="item.quantity > 1 ? `Use some (${item.quantity} ${item.unit})` : 'Mark as used'"
                :title="item.quantity > 1 ? `Use some or all (${item.quantity} ${item.unit})` : 'Mark as used'"
              >
                <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                  <polyline points="4 10 8 14 16 6"/>
                </svg>
              </button>
              <button
                v-if="item.status === 'available'"
                @click="markAsDiscarded(item)"
                class="btn-icon btn-icon-discard"
                aria-label="Mark as not used"
                title="I didn't use this (went bad, too much, etc)"
              >
                <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                  <path d="M4 4l12 12M4 16L16 4"/>
                </svg>
              </button>
              <button @click="confirmDelete(item)" class="btn-icon btn-icon-danger" aria-label="Delete">
                <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
                  <polyline points="3 6 5 6 17 6"/>
                  <path d="M8 6V4h4v2"/>
                  <rect x="5" y="6" width="10" height="10" rx="1"/>
                </svg>
              </button>
            </div>
          </div>
        </div>
      </div>
      </template><!-- end v-else normal view -->
    </div>

    <!-- Export -->
    <div class="card export-card">
      <h2 class="section-title">Export</h2>
      <div class="flex gap-sm flex-wrap" style="margin-top: var(--spacing-sm)">
        <button @click="exportJSON" class="btn btn-primary">Download JSON (full backup)</button>
        <button @click="exportCSV" class="btn btn-secondary">Download CSV</button>
        <button @click="exportExcel" class="btn btn-secondary">Download Excel</button>
      </div>
      <p class="text-sm text-secondary" style="margin-top: var(--spacing-xs)">
        JSON includes pantry + saved recipes. Import it into another Kiwi instance any time.
      </p>
    </div>

    <!-- Edit Modal -->
    <EditItemModal
      v-if="editingItem"
      :item="editingItem"
      @close="editingItem = null"
      @save="handleSave"
    />

    <!-- Confirm Dialog -->
    <ConfirmDialog
      :show="confirmDialog.show"
      :title="confirmDialog.title"
      :message="confirmDialog.message"
      :type="confirmDialog.type"
      :confirm-text="confirmDialog.confirmText"
      @confirm="confirmDialog.onConfirm"
      @cancel="confirmDialog.show = false"
    />

    <!-- Action Dialog (partial consume / discard reason) -->
    <ActionDialog
      :show="actionDialog.show"
      :title="actionDialog.title"
      :message="actionDialog.message"
      :type="actionDialog.type"
      :confirm-text="actionDialog.confirmText"
      :input-type="actionDialog.inputType"
      :input-label="actionDialog.inputLabel"
      :input-max="actionDialog.inputMax"
      :input-unit="actionDialog.inputUnit"
      :input-options="actionDialog.inputOptions"
      @confirm="(v) => { actionDialog.onConfirm(v); actionDialog.show = false }"
      @cancel="actionDialog.show = false"
    />

    <!-- Toast Notification -->
    <ToastNotification
      :show="toast.show"
      :message="toast.message"
      :type="toast.type"
      :duration="toast.duration"
      @close="toast.show = false"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, reactive } from 'vue'
import { storeToRefs } from 'pinia'
import { useInventoryStore } from '../stores/inventory'
import { useSettingsStore } from '../stores/settings'
import { inventoryAPI } from '../services/api'
import type { InventoryItem, LabelCaptureResult } from '../services/api'
import { formatQuantity } from '../utils/units'
import EditItemModal from './EditItemModal.vue'
import ConfirmDialog from './ConfirmDialog.vue'
import ActionDialog from './ActionDialog.vue'
import ToastNotification from './ToastNotification.vue'

const store = useInventoryStore()
const settingsStore = useSettingsStore()
const { items, stats, loading, locationFilter, statusFilter } = storeToRefs(store)

const filteredItems = computed(() => store.filteredItems)
const editingItem = ref<InventoryItem | null>(null)

// Expiry view
const expiryView = ref<'soon' | 'expired' | null>(null)

function toggleExpiryView(mode: 'soon' | 'expired') {
  expiryView.value = expiryView.value === mode ? null : mode
  // Ensure available items are loaded so computeds have data
  if (expiryView.value && statusFilter.value !== 'available' && statusFilter.value !== 'all') {
    statusFilter.value = 'available'
    store.fetchItems()
  }
}

const urgentItems = computed(() =>
  store.expiringItems.filter((item) => {
    if (!item.expiration_date) return false
    const diff = Math.ceil((new Date(item.expiration_date).getTime() - Date.now()) / 86_400_000)
    return diff <= 3
  })
)

const soonItems = computed(() =>
  store.expiringItems.filter((item) => {
    if (!item.expiration_date) return false
    const diff = Math.ceil((new Date(item.expiration_date).getTime() - Date.now()) / 86_400_000)
    return diff > 3
  })
)

const secondaryStateItems = computed(() =>
  store.expiredItems.filter((item) => item.secondary_state != null)
)

const trulyExpiredItems = computed(() =>
  store.expiredItems.filter((item) => item.secondary_state == null)
)

function daysLabel(dateStr: string): string {
  const diff = Math.ceil((new Date(dateStr).getTime() - Date.now()) / 86_400_000)
  if (diff < 0) return `${Math.abs(diff)}d ago`
  if (diff === 0) return 'today'
  if (diff === 1) return '1 day'
  return `${diff} days`
}

// Scan mode toggle
const scanMode = ref<'gun' | 'camera' | 'manual'>('gun')

// Options for button groups
// Label capture nutrition field descriptors used in the review form
const captureNutritionFields = [
  { key: 'calories',      src: 'calories',      label: 'Calories',    unit: 'kcal' },
  { key: 'fat_g',         src: 'fat_g',         label: 'Total fat',   unit: 'g' },
  { key: 'saturated_fat_g', src: 'saturated_fat_g', label: 'Saturated fat', unit: 'g' },
  { key: 'carbs_g',       src: 'carbs_g',       label: 'Carbs',       unit: 'g' },
  { key: 'protein_g',     src: 'protein_g',     label: 'Protein',     unit: 'g' },
  { key: 'sodium_mg',     src: 'sodium_mg',     label: 'Sodium',      unit: 'mg' },
]

const locations = [
  { value: 'fridge', label: 'Fridge', icon: '🧊' },
  { value: 'freezer', label: 'Freezer', icon: '❄️' },
  { value: 'garage_freezer', label: 'Garage Freezer', icon: '🏠' },
  { value: 'pantry', label: 'Pantry', icon: '🏪' },
  { value: 'cabinet', label: 'Cabinet', icon: '🗄️' },
]

const units = [
  { value: 'count', label: 'Count' },
  { value: 'kg', label: 'kg' },
  { value: 'lbs', label: 'lbs' },
  { value: 'oz', label: 'oz' },
  { value: 'liters', label: 'L' },
]

const statuses = [
  { value: 'available', label: 'Available' },
  { value: 'consumed', label: 'Consumed' },
  { value: 'expired', label: 'Expired' },
]

// Confirm Dialog
const confirmDialog = reactive({
  show: false,
  title: 'Confirm',
  message: '',
  type: 'primary' as 'primary' | 'danger' | 'warning',
  confirmText: 'Confirm',
  onConfirm: () => {},
})

const actionDialog = reactive({
  show: false,
  title: '',
  message: '',
  type: 'primary' as 'primary' | 'danger' | 'warning' | 'secondary',
  confirmText: 'Confirm',
  inputType: null as 'quantity' | 'select' | null,
  inputLabel: '',
  inputMax: 1,
  inputUnit: '',
  inputOptions: [] as string[],
  onConfirm: (_v: number | string | undefined) => {},
})

// Toast Notification
const toast = reactive({
  show: false,
  message: '',
  type: 'info' as 'success' | 'error' | 'warning' | 'info',
  duration: 3000,
})

function showToast(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info', duration = 3000) {
  toast.message = message
  toast.type = type
  toast.duration = duration
  toast.show = true
}

function showConfirm(
  message: string,
  onConfirm: () => void,
  options: {
    title?: string
    type?: 'primary' | 'danger' | 'warning'
    confirmText?: string
  } = {}
) {
  confirmDialog.message = message
  confirmDialog.onConfirm = () => {
    onConfirm()
    confirmDialog.show = false
  }
  confirmDialog.title = options.title || 'Confirm'
  confirmDialog.type = options.type || 'primary'
  confirmDialog.confirmText = options.confirmText || 'Confirm'
  confirmDialog.show = true
}

// Scanner Gun
const scannerGunInput = ref<HTMLInputElement | null>(null)
const scannerBarcode = ref('')
const scannerLocation = ref('pantry')
const scannerQuantity = ref(1)
const scannerLoading = ref(false)
const scannerResults = ref<Array<{ type: string; message: string }>>([])

// Barcode Image
const barcodeFileInput = ref<HTMLInputElement | null>(null)
const barcodeLocation = ref('pantry')
const barcodeQuantity = ref(1)
const barcodeLoading = ref(false)
const barcodeResults = ref<Array<{ type: string; message: string }>>([])

// Label Capture Flow (kiwi#79)
type CapturePhase = 'offer' | 'uploading' | 'reviewing' | null
const capturePhase = ref<CapturePhase>(null)
const captureBarcode = ref('')
const captureLocation = ref('pantry')
const captureQuantity = ref(1)
const captureLoading = ref(false)
const captureFileInput = ref<HTMLInputElement | null>(null)
const captureExtraction = ref<LabelCaptureResult | null>(null)
// Editable review form — populated from extraction, user may correct fields
const captureReview = ref({
  product_name: '',
  brand: '',
  calories: '' as string,
  fat_g: '' as string,
  saturated_fat_g: '' as string,
  carbs_g: '' as string,
  protein_g: '' as string,
  sodium_mg: '' as string,
  ingredients: '',
  allergens: '',
})

// Manual Form
const manualForm = ref({
  name: '',
  brand: '',
  quantity: 1,
  unit: 'count',
  location: 'pantry',
  expirationDate: '',
})
const manualLoading = ref(false)

onMounted(async () => {
  await store.fetchItems()
  await store.fetchStats()
  // Auto-focus scanner gun input — desktop only (avoids popping mobile keyboard)
  if (!('ontouchstart' in window)) {
    setTimeout(() => {
      scannerGunInput.value?.focus()
    }, 100)
  }
})

function onFilterChange() {
  store.fetchItems()
}

async function refreshItems() {
  await store.fetchItems()
  await store.fetchStats()
}

function editItem(item: InventoryItem) {
  editingItem.value = item
}

async function handleSave() {
  editingItem.value = null
  await refreshItems()
}

async function confirmDelete(item: InventoryItem) {
  showConfirm(
    `Are you sure you want to delete ${item.product_name || 'item'}?`,
    async () => {
      try {
        await store.deleteItem(item.id)
        showToast(`${item.product_name || 'item'} deleted successfully`, 'success')
      } catch (err) {
        showToast('Failed to delete item', 'error')
      }
    },
    {
      title: 'Delete Item',
      type: 'danger',
      confirmText: 'Delete',
    }
  )
}

async function markAsOpened(item: InventoryItem) {
  try {
    await inventoryAPI.openItem(item.id)
    await refreshItems()
    showToast(`${item.product_name || 'Item'} marked as opened — tracking freshness`, 'info')
  } catch {
    showToast('Could not mark item as opened', 'error')
  }
}

function markAsConsumed(item: InventoryItem) {
  const isMulti = item.quantity > 1
  const label = item.product_name || 'item'
  Object.assign(actionDialog, {
    show: true,
    title: 'Mark as Used',
    message: isMulti
      ? `How much of ${label} did you use?`
      : `Mark ${label} as used?`,
    type: 'primary',
    confirmText: isMulti ? 'Use' : 'Mark as Used',
    inputType: isMulti ? 'quantity' : null,
    inputLabel: 'Amount used:',
    inputMax: item.quantity,
    inputUnit: item.unit,
    inputOptions: [],
    onConfirm: async (val: number | string | undefined) => {
      const qty = isMulti ? (val as number) : undefined
      try {
        await inventoryAPI.consumeItem(item.id, qty)
        await refreshItems()
        const verb = qty !== undefined && qty < item.quantity ? 'partially used' : 'marked as used'
        showToast(`${label} ${verb}`, 'success')
      } catch {
        showToast('Could not update item', 'error')
      }
    },
  })
}

function markAsDiscarded(item: InventoryItem) {
  const label = item.product_name || 'item'
  Object.assign(actionDialog, {
    show: true,
    title: 'Item Not Used',
    message: `${label} — what happened to it?`,
    type: 'secondary',
    confirmText: 'Log It',
    inputType: 'select',
    inputLabel: 'Reason (optional):',
    inputMax: 1,
    inputUnit: '',
    inputOptions: [
      'went bad before I could use it',
      'too much — had excess',
      'changed my mind',
      'other',
    ],
    onConfirm: async (val: number | string | undefined) => {
      const reason = typeof val === 'string' && val ? val : undefined
      try {
        await inventoryAPI.discardItem(item.id, reason)
        await refreshItems()
        showToast(`${label} logged as not used`, 'info')
      } catch {
        showToast('Could not update item', 'error')
      }
    },
  })
}

// Scanner Gun Functions
async function handleScannerGunInput() {
  const barcode = scannerBarcode.value.trim()
  if (!barcode) return

  scannerLoading.value = true
  scannerResults.value = []

  try {
    const result = await inventoryAPI.scanBarcodeText(
      barcode,
      scannerLocation.value,
      scannerQuantity.value,
      true
    )

    const item = result.results[0]
    if (item?.added_to_inventory) {
      const productName = item.product?.name || 'item'
      const productBrand = item.product?.brand ? ` (${item.product.brand})` : ''
      scannerResults.value.push({
        type: 'success',
        message: `Added: ${productName}${productBrand} to ${scannerLocation.value}`,
      })
      await refreshItems()
    } else if (item?.needs_visual_capture) {
      captureBarcode.value = barcode
      captureLocation.value = scannerLocation.value
      captureQuantity.value = scannerQuantity.value
      capturePhase.value = 'offer'
      scannerResults.value.push({
        type: 'info',
        message: item.message,
      })
    } else if (item?.needs_manual_entry) {
      // Barcode not found in any database — guide user to manual entry
      scannerResults.value.push({
        type: 'warning',
        message: `Barcode ${barcode} not found. Fill in the details below.`,
      })
      scanMode.value = 'manual'
    } else {
      scannerResults.value.push({
        type: 'error',
        message: result.message || 'Barcode not found',
      })
    }
  } catch (error: any) {
    scannerResults.value.push({
      type: 'error',
      message: `Error: ${error.message}`,
    })
  } finally {
    scannerLoading.value = false
    scannerBarcode.value = ''
    if (scanMode.value === 'gun') scannerGunInput.value?.focus()
  }
}

// Barcode Image Functions
function triggerBarcodeInput() {
  barcodeFileInput.value?.click()
}

async function handleBarcodeImageSelect(e: Event) {
  const target = e.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return

  barcodeLoading.value = true
  barcodeResults.value = []

  try {
    const result = await inventoryAPI.scanBarcodeImage(
      file,
      barcodeLocation.value,
      barcodeQuantity.value,
      true
    )

    if (result.success && result.barcodes_found > 0) {
      const item = result.results[0]
      barcodeResults.value.push({
        type: 'success',
        message: `Found: ${item.product_name || 'item'}`,
      })
      await refreshItems()
    } else {
      barcodeResults.value.push({
        type: 'error',
        message: 'No barcode found in image',
      })
    }
  } catch (error: any) {
    barcodeResults.value.push({
      type: 'error',
      message: `Error: ${error.message}`,
    })
  } finally {
    barcodeLoading.value = false
    if (barcodeFileInput.value) {
      barcodeFileInput.value.value = ''
    }
  }
}

// Label Capture Functions

function triggerCaptureLabelInput() {
  captureFileInput.value?.click()
}

function dismissCapture() {
  capturePhase.value = null
  captureBarcode.value = ''
  captureExtraction.value = null
}

async function handleLabelPhotoSelect(e: Event) {
  const target = e.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return

  captureLoading.value = true
  capturePhase.value = 'uploading'

  try {
    const result = await inventoryAPI.captureLabelPhoto(file, captureBarcode.value)
    captureExtraction.value = result
    // Pre-populate the review form with extracted values
    captureReview.value = {
      product_name: result.product_name || '',
      brand: result.brand || '',
      calories: result.calories != null ? String(result.calories) : '',
      fat_g: result.fat_g != null ? String(result.fat_g) : '',
      saturated_fat_g: result.saturated_fat_g != null ? String(result.saturated_fat_g) : '',
      carbs_g: result.carbs_g != null ? String(result.carbs_g) : '',
      protein_g: result.protein_g != null ? String(result.protein_g) : '',
      sodium_mg: result.sodium_mg != null ? String(result.sodium_mg) : '',
      ingredients: (result.ingredient_names || []).join(', '),
      allergens: (result.allergens || []).join(', '),
    }
    capturePhase.value = 'reviewing'
  } catch {
    showToast('Could not read the label. Please try again or add manually.', 'error')
    capturePhase.value = 'offer'
  } finally {
    captureLoading.value = false
    if (target) target.value = ''
  }
}

async function confirmCapture() {
  if (!captureBarcode.value) return

  captureLoading.value = true
  try {
    const toNum = (s: string) => s ? parseFloat(s) || null : null
    const toList = (s: string) => s.split(',').map(x => x.trim()).filter(Boolean)

    await inventoryAPI.confirmLabelCapture({
      barcode: captureBarcode.value,
      product_name: captureReview.value.product_name || null,
      brand: captureReview.value.brand || null,
      calories: toNum(captureReview.value.calories),
      fat_g: toNum(captureReview.value.fat_g),
      saturated_fat_g: toNum(captureReview.value.saturated_fat_g),
      carbs_g: toNum(captureReview.value.carbs_g),
      protein_g: toNum(captureReview.value.protein_g),
      sodium_mg: toNum(captureReview.value.sodium_mg),
      ingredient_names: toList(captureReview.value.ingredients),
      allergens: toList(captureReview.value.allergens),
      confidence: captureExtraction.value?.confidence ?? 0,
      location: captureLocation.value,
      quantity: captureQuantity.value,
      auto_add: true,
    })
    const name = captureReview.value.product_name || 'item'
    showToast(`${name} saved and added to ${captureLocation.value}`, 'success')
    await refreshItems()
    dismissCapture()
  } catch {
    showToast('Could not save. Please try again.', 'error')
  } finally {
    captureLoading.value = false
  }
}

// Manual Add Functions
async function addManualItem() {
  const { name, brand, quantity, unit, location, expirationDate } = manualForm.value

  if (!name || !quantity || !location) {
    showToast('Please fill in required fields', 'warning')
    return
  }

  manualLoading.value = true

  try {
    // Create product first
    const product = await inventoryAPI.createProduct({
      name,
      brand: brand || undefined,
      source: 'manual',
    })

    // Add to inventory
    await inventoryAPI.createItem({
      product_id: product.id,
      quantity,
      unit,
      location,
      expiration_date: expirationDate || undefined,
      source: 'manual',
    })

    showToast(`${name} added to inventory!`, 'success')
    // Clear form
    manualForm.value = {
      name: '',
      brand: '',
      quantity: 1,
      unit: 'count',
      location: 'pantry',
      expirationDate: '',
    }
    await refreshItems()
  } catch (error: any) {
    showToast(`Error: ${error.message}`, 'error')
  } finally {
    manualLoading.value = false
  }
}

// Export Functions
function exportCSV() {
  const apiUrl = import.meta.env.VITE_API_URL || '/api/v1'
  window.open(`${apiUrl}/export/inventory/csv`, '_blank')
}

function exportExcel() {
  const apiUrl = import.meta.env.VITE_API_URL || '/api/v1'
  window.open(`${apiUrl}/export/inventory/excel`, '_blank')
}

function exportJSON() {
  const apiUrl = import.meta.env.VITE_API_URL || '/api/v1'
  window.open(`${apiUrl}/export/json`, '_blank')
}

// Full date string for tooltip (accessible label)
function formatDateFull(dateStr: string): string {
  const date = new Date(dateStr)
  const today = new Date()
  today.setHours(0, 0, 0, 0)
  const expiry = new Date(dateStr)
  expiry.setHours(0, 0, 0, 0)
  const diffDays = Math.ceil((expiry.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
  const cal = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
  if (diffDays < 0) return `Expired ${cal}`
  if (diffDays === 0) return `Expires today (${cal})`
  if (diffDays === 1) return `Expires tomorrow (${cal})`
  return `Expires in ${diffDays} days (${cal})`
}

// Short date for compact row display
function formatDateShort(dateStr: string): string {
  const today = new Date()
  today.setHours(0, 0, 0, 0)
  const expiry = new Date(dateStr)
  expiry.setHours(0, 0, 0, 0)
  const diffDays = Math.ceil((expiry.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
  const cal = new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })

  if (diffDays < 0) return `${Math.abs(diffDays)}d ago`
  if (diffDays === 0) return 'today'
  if (diffDays === 1) return `tmrw · ${cal}`
  if (diffDays <= 14) return `${diffDays}d · ${cal}`
  return cal
}

function getExpiryBadgeClass(expiryStr: string): string {
  const today = new Date()
  const expiry = new Date(expiryStr)
  const diffDays = Math.ceil((expiry.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))

  if (diffDays < 0) return 'expiry-expired'
  if (diffDays <= 3) return 'expiry-urgent'
  if (diffDays <= 7) return 'expiry-soon'
  return 'expiry-ok'
}

function getItemClass(item: InventoryItem): string {
  if (!item.expiration_date) return ''

  const today = new Date()
  const expiry = new Date(item.expiration_date)
  const diffDays = Math.ceil((expiry.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))

  if (diffDays < 0) return 'item-expired'
  if (diffDays <= 3) return 'item-expiring-soon'
  if (diffDays <= 7) return 'item-expiring-warning'
  return ''
}
</script>

<style scoped>
.inventory-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  padding: var(--spacing-xs) 0 0;
  overflow-x: hidden;
  width: 100%;        /* Firefox: explicit width stops flex column from auto-sizing to content */
}

/* ============================================
   STATS STRIP
   ============================================ */
.stats-strip {
  display: flex;
  border-radius: var(--radius-lg);
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  overflow: hidden;
}

.stat-strip-item {
  flex: 1;
  text-align: center;
  padding: var(--spacing-sm) var(--spacing-xs);
  border-right: 1px solid var(--color-border);
}

.stat-strip-item:last-child {
  border-right: none;
}

.stat-num {
  font-family: var(--font-mono);
  font-size: var(--font-size-xl);
  font-weight: 500;
  color: var(--color-text-primary);
  line-height: 1.1;
}

.stat-lbl {
  font-family: var(--font-body);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 2px;
}

/* ============================================
   SCAN CARD
   ============================================ */
.scan-card {
  padding: var(--spacing-md);
}

.scan-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--spacing-md);
}

.scan-mode-toggle {
  display: flex;
  gap: 2px;
  background: var(--color-bg-secondary);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 3px;
}

.scan-mode-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 5px var(--spacing-sm);
  border: none;
  border-radius: calc(var(--radius-lg) - 3px);
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 600;
  font-family: var(--font-body);
  cursor: pointer;
  transition: all 0.18s ease;
  white-space: nowrap;
}

.scan-mode-btn svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.scan-mode-btn:hover {
  color: var(--color-text-secondary);
  transform: none;
  border-color: transparent;
}

.scan-mode-btn.active {
  background: var(--color-primary);
  color: #1e1c1a;
}

.scan-panel {
  /* spacing handled by parent gap */
}

.scan-meta-row {
  display: flex;
  gap: var(--spacing-md);
  align-items: flex-start;
  flex-wrap: wrap;
}

.scan-location-group {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
}

.scan-qty-group {
  flex-shrink: 0;
  margin-bottom: 0;
}

/* ============================================
   UPLOAD AREA
   ============================================ */
.upload-area {
  border: 2px dashed var(--color-border-focus);
  border-radius: var(--radius-lg);
  padding: var(--spacing-xl) var(--spacing-lg);
  text-align: center;
  cursor: pointer;
  transition: all 0.2s ease;
  background: var(--color-bg-secondary);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-xs);
}

.upload-area:hover {
  border-color: var(--color-primary);
  background: var(--color-bg-elevated);
}

.upload-icon-svg {
  width: 40px;
  height: 40px;
  color: var(--color-text-muted);
  margin-bottom: var(--spacing-xs);
}

.upload-text {
  font-size: var(--font-size-base);
  font-weight: 600;
  color: var(--color-text-primary);
}

.upload-hint {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

/* ============================================
   FORMS
   ============================================ */
.scanner-input {
  font-family: var(--font-mono);
  font-size: var(--font-size-base);
  background: var(--color-bg-input);
}

.quantity-control {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

.btn-qty {
  width: 34px;
  height: 34px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-secondary);
  color: var(--color-text-primary);
  font-size: var(--font-size-lg);
  font-weight: 700;
  cursor: pointer;
  transition: all 0.18s ease;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-qty:hover {
  background: var(--color-primary);
  color: #1e1c1a;
  border-color: var(--color-primary);
  transform: none;
}

.btn-qty:active {
  transform: scale(0.93);
}

.qty-input {
  width: 72px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 500;
  padding: var(--spacing-xs) var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-input);
  color: var(--color-text-primary);
}

/* ============================================
   INVENTORY SHELF LIST
   ============================================ */
.inventory-section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  width: 100%;
  max-width: 100%;
  overflow-x: hidden;
}

.inventory-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 2px;
}

.filter-row {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.status-filter-row {
  padding-top: 0;
}

.inv-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  width: 100%;
  max-width: 100%;
}

.inv-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  border-left: 3px solid var(--color-border);
  max-width: 100%;
  box-sizing: border-box;
  background: var(--color-bg-card);
  transition: background 0.15s ease;
  min-height: 52px;
  border-bottom: 1px solid var(--color-border);
}

.inv-row:last-child {
  border-bottom: none;
}

.inv-row:hover {
  background: var(--color-bg-elevated);
}

/* Urgency borders */
.inv-row.item-expiring-soon {
  border-left-color: var(--color-error) !important;
  animation: urgencyPulse 1.8s ease-in-out infinite;
}

.inv-row.item-expiring-warning {
  border-left-color: var(--color-warning) !important;
}

.inv-row.item-expired {
  opacity: 0.55;
  border-left-color: var(--color-text-muted) !important;
}

.inv-row-name {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.inv-name {
  font-family: var(--font-body);
  font-size: var(--font-size-sm);
  font-weight: 500;
  color: var(--color-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.inv-category {
  font-family: var(--font-body);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.inv-row-right {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  flex-shrink: 0;
}

.inv-qty {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  font-weight: 500;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.inv-unit {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

/* Expiry badges */
.expiry-badge {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  padding: 2px 6px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  flex-shrink: 0;
}

.expiry-urgent {
  background: var(--color-error-bg);
  color: var(--color-error-light);
  border: 1px solid var(--color-error-border);
}

.expiry-soon {
  background: var(--color-warning-bg);
  color: var(--color-warning-light);
  border: 1px solid var(--color-warning-border);
}

.expiry-ok {
  background: var(--color-success-bg);
  color: var(--color-success-light);
  border: 1px solid var(--color-success-border);
}

.expiry-expired {
  background: rgba(100, 100, 100, 0.15);
  color: var(--color-text-muted);
  border: 1px solid rgba(100, 100, 100, 0.25);
  text-decoration: line-through;
}

/* "I opened this today" button */
.btn-icon-open {
  color: var(--color-warning);
}

.btn-icon-open:hover {
  background: var(--color-warning-bg);
}

/* "Item not used" discard button — muted, not alarming */
.btn-icon-discard {
  color: var(--color-text-tertiary);
}

.btn-icon-discard:hover {
  color: var(--color-text-secondary);
  background: var(--color-bg-secondary);
}

/* Opened badge — distinct icon prefix signals this is after-open expiry */
.expiry-opened {
  letter-spacing: 0;
}

/* Action icons inline */
.inv-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

/* ============================================
   EMPTY STATE
   ============================================ */
.empty-state {
  text-align: center;
  padding: var(--spacing-xl) var(--spacing-lg);
  color: var(--color-text-secondary);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
}

.empty-icon {
  width: 48px;
  height: 48px;
  color: var(--color-text-muted);
}

/* ============================================
   LOADING
   ============================================ */
.loading-inline {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: var(--spacing-sm);
}

/* ============================================
   RESULTS
   ============================================ */
.results {
  margin-top: var(--spacing-sm);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.result-item {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
}

.result-success {
  background: var(--color-success-bg);
  color: var(--color-success-light);
  border: 1px solid var(--color-success-border);
}

.result-error {
  background: var(--color-error-bg);
  color: var(--color-error-light);
  border: 1px solid var(--color-error-border);
}

.result-info {
  background: var(--color-info-bg);
  color: var(--color-info-light);
  border: 1px solid var(--color-info-border);
}

.result-warning {
  background: var(--color-warning-bg, #fffbeb);
  color: var(--color-warning-dark, #92400e);
  border: 1px solid var(--color-warning-border, #fcd34d);
}

/* ============================================
   LABEL CAPTURE FLOW (kiwi#79)
   ============================================ */
.label-capture-panel {
  margin: var(--spacing-md) 0;
  padding: var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.capture-offer-text {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  margin: 0 0 var(--spacing-md);
}

.capture-offer-actions {
  display: flex;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

.capture-processing {
  display: flex;
  justify-content: center;
  padding: var(--spacing-md) 0;
}

.capture-review-note {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  margin: 0 0 var(--spacing-md);
}

.capture-review-low-conf {
  color: var(--color-amber, #d97706);
  font-size: var(--font-size-xs);
  display: block;
  margin-top: var(--spacing-xs);
}

.form-section-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: var(--spacing-md) 0 var(--spacing-sm);
}

.capture-nutrition-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--spacing-sm);
}

/* Amber highlight for unread/low-confidence label fields */
.capture-field-amber {
  color: var(--color-amber, #d97706);
}

.capture-field-amber + input {
  border-color: var(--color-amber, #d97706);
}

.capture-review-actions {
  display: flex;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
  margin-top: var(--spacing-md);
}

/* ============================================
   EXPORT CARD
   ============================================ */
.export-card {
  padding: var(--spacing-md);
}

/* ============================================
   URGENCY ANIMATION
   ============================================ */
@keyframes urgencyPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

/* ============================================
   MOBILE RESPONSIVE
   ============================================ */
@media (max-width: 480px) {
  .scan-card-header {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-sm);
  }

  /* Mode toggle fills the card width when header stacks */
  .scan-mode-toggle {
    width: 100%;
  }

  .scan-mode-btn {
    flex: 1;
    justify-content: center;
  }

  .scan-meta-row {
    flex-direction: column;
  }

  .scan-location-group,
  .scan-qty-group {
    width: 100%;
  }

  .inv-row {
    padding: var(--spacing-xs) var(--spacing-sm);
    min-height: 46px;
  }

  /* On very small screens, hide category line */
  .inv-category {
    display: none;
  }

  .stats-strip .stat-num {
    font-size: var(--font-size-lg);
  }

  .inv-actions {
    gap: 1px;
  }

  /* Prevent right section from blowing out row width on narrow screens */
  .inv-row-right {
    flex-shrink: 1;
    min-width: 0;
    gap: var(--spacing-xs);
  }

  /* Shrink action buttons slightly on mobile */
  .inv-row-right .btn-icon {
    width: 28px;
    height: 28px;
  }
}

/* Very narrow phones (360px and below): hide mode button labels, keep icons */
@media (max-width: 360px) {
  .scan-mode-btn span {
    display: none;
  }

  .scan-mode-btn svg {
    width: 16px;
    height: 16px;
  }
}

@media (min-width: 481px) and (max-width: 768px) {
  .scan-meta-row {
    flex-wrap: nowrap;
  }
}

/* ============================================
   STATS — clickable badges
   ============================================ */
.stat-clickable {
  cursor: pointer;
  transition: background var(--transition-fast);
}

.stat-clickable:hover {
  background: var(--color-bg-secondary);
}

.stat-clickable.stat-active {
  background: var(--color-bg-secondary);
  box-shadow: inset 0 -2px 0 var(--color-accent);
}

/* ============================================
   EXPIRY PANEL
   ============================================ */
.expiry-back-btn {
  background: none;
  border: none;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.expiry-back-btn:hover {
  color: var(--color-text-primary);
}

.expiry-panel {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.expiry-group {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.expiry-group-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: var(--spacing-xs) 0;
  color: var(--color-text-muted);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 2px;
}

.expiry-group-urgent { color: var(--color-error); }
.expiry-group-soon   { color: var(--color-warning); }
.expiry-group-secondary { color: var(--color-success); }
.expiry-group-done   { color: var(--color-text-muted); }

.expiry-item-row {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--color-border-subtle, var(--color-border));
}

.expiry-item-row:last-child {
  border-bottom: none;
}

.expiry-item-secondary {
  background: color-mix(in srgb, var(--color-success) 5%, transparent);
  border-radius: var(--radius-md);
  padding: var(--spacing-sm);
}

.expiry-item-name {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.expiry-item-right {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  flex-shrink: 0;
}

.secondary-state-badge {
  display: inline-flex;
  align-items: center;
  background: color-mix(in srgb, var(--color-success) 15%, transparent);
  color: var(--color-success);
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  width: fit-content;
}

.secondary-uses-text {
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

.secondary-warning-text {
  font-size: var(--font-size-xs);
  color: var(--color-warning);
}
</style>
