defmodule SimpleshopThemeWeb.ShopComponents do
  @moduledoc """
  Provides shop/storefront UI components.

  These components are shared between the theme preview system and
  the public storefront pages. They render using CSS custom properties
  defined by the theme settings.
  """
  use Phoenix.Component

  @doc """
  Renders the announcement bar.

  The bar displays promotional messaging at the top of the page.
  It uses CSS custom properties for theming.

  ## Attributes

  * `theme_settings` - Required. The theme settings map.
  * `message` - Optional. The announcement message to display.
    Defaults to "Free delivery on orders over £40".

  ## Examples

      <.announcement_bar theme_settings={@theme_settings} />
      <.announcement_bar theme_settings={@theme_settings} message="20% off this weekend!" />
  """
  attr :theme_settings, :map, required: true
  attr :message, :string, default: "Sample announcement – e.g. free delivery, sales, or new drops"

  def announcement_bar(assigns) do
    ~H"""
    <div
      class="announcement-bar"
      style="background-color: var(--t-accent-button, hsl(var(--t-accent-h) var(--t-accent-s) 42%)); color: var(--t-text-inverse); text-align: center; padding: 0.5rem 1rem; font-size: var(--t-text-small);"
    >
      <p style="margin: 0;">{@message}</p>
    </div>
    """
  end

  @doc """
  Renders the skip link for keyboard navigation accessibility.

  This is a standard accessibility pattern that allows keyboard users
  to skip directly to the main content.
  """
  def skip_link(assigns) do
    ~H"""
    <a href="#main-content" class="skip-link">
      Skip to main content
    </a>
    """
  end

  # =============================================================================
  # Themed Form Components
  # =============================================================================
  # These components wrap common form elements with the themed CSS classes.
  # They provide a consistent, theme-aware appearance across shop pages.

  @doc """
  Renders a themed text input.

  This component applies the `.themed-input` CSS class which inherits
  colors, borders, and radii from the current theme's CSS variables.

  ## Attributes

  * `type` - Optional. Input type. Defaults to "text".
  * `class` - Optional. Additional CSS classes.
  * All other attributes are passed through to the input element.

  ## Examples

      <.shop_input type="email" placeholder="your@email.com" />
      <.shop_input type="text" name="name" class="flex-1" />
  """
  attr :type, :string, default: "text"
  attr :class, :string, default: nil
  attr :rest, :global, include: ~w(name value placeholder required disabled autocomplete readonly)

  def shop_input(assigns) do
    ~H"""
    <input type={@type} class={["themed-input", @class]} {@rest} />
    """
  end

  @doc """
  Renders a themed textarea.

  ## Attributes

  * `class` - Optional. Additional CSS classes.
  * All other attributes are passed through to the textarea element.

  ## Examples

      <.shop_textarea placeholder="Your message..." rows="5" />
  """
  attr :class, :string, default: nil
  attr :rest, :global, include: ~w(name rows placeholder required disabled readonly)

  def shop_textarea(assigns) do
    ~H"""
    <textarea class={["themed-input", @class]} {@rest}></textarea>
    """
  end

  @doc """
  Renders a themed select dropdown.

  ## Attributes

  * `class` - Optional. Additional CSS classes.
  * `options` - Required. List of options (strings or {value, label} tuples).
  * `selected` - Optional. Currently selected value.
  * All other attributes are passed through to the select element.

  ## Examples

      <.shop_select options={["Option 1", "Option 2"]} />
      <.shop_select options={[{"value", "Label"}]} selected="value" />
  """
  attr :class, :string, default: nil
  attr :options, :list, required: true
  attr :selected, :any, default: nil
  attr :rest, :global, include: ~w(name required disabled aria-label)

  def shop_select(assigns) do
    ~H"""
    <select class={["themed-select", @class]} {@rest}>
      <%= for option <- @options do %>
        <%= case option do %>
          <% {value, label} -> %>
            <option value={value} selected={@selected == value}>{label}</option>
          <% label -> %>
            <option selected={@selected == label}>{label}</option>
        <% end %>
      <% end %>
    </select>
    """
  end

  @doc """
  Renders a themed primary button (accent color background).

  ## Attributes

  * `class` - Optional. Additional CSS classes.
  * `type` - Optional. Button type. Defaults to "button".
  * All other attributes are passed through to the button element.

  ## Slots

  * `inner_block` - Required. Button content.

  ## Examples

      <.shop_button>Send Message</.shop_button>
      <.shop_button type="submit" class="w-full">Subscribe</.shop_button>
  """
  attr :class, :string, default: nil
  attr :type, :string, default: "button"
  attr :rest, :global, include: ~w(disabled name value phx-click phx-value-page)

  slot :inner_block, required: true

  def shop_button(assigns) do
    ~H"""
    <button type={@type} class={["themed-button", @class]} {@rest}>
      {render_slot(@inner_block)}
    </button>
    """
  end

  @doc """
  Renders a themed outline/secondary button.

  ## Attributes

  * `class` - Optional. Additional CSS classes.
  * `type` - Optional. Button type. Defaults to "button".
  * All other attributes are passed through to the button element.

  ## Slots

  * `inner_block` - Required. Button content.

  ## Examples

      <.shop_button_outline>Continue Shopping</.shop_button_outline>
  """
  attr :class, :string, default: nil
  attr :type, :string, default: "button"
  attr :rest, :global, include: ~w(disabled name value phx-click phx-value-page)

  slot :inner_block, required: true

  def shop_button_outline(assigns) do
    ~H"""
    <button type={@type} class={["themed-button-outline", @class]} {@rest}>
      {render_slot(@inner_block)}
    </button>
    """
  end

  @doc """
  Renders a themed link styled as a primary button.

  ## Attributes

  * `href` - Required. Link destination.
  * `class` - Optional. Additional CSS classes.

  ## Slots

  * `inner_block` - Required. Link content.

  ## Examples

      <.shop_link_button href="/checkout">Checkout</.shop_link_button>
  """
  attr :href, :string, required: true
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def shop_link_button(assigns) do
    ~H"""
    <a
      href={@href}
      class={["themed-button", @class]}
      style="text-decoration: none; display: inline-block;"
    >
      {render_slot(@inner_block)}
    </a>
    """
  end

  @doc """
  Renders a themed link styled as an outline button.

  ## Attributes

  * `href` - Required. Link destination.
  * `class` - Optional. Additional CSS classes.

  ## Slots

  * `inner_block` - Required. Link content.

  ## Examples

      <.shop_link_outline href="/collections/all">Continue Shopping</.shop_link_outline>
  """
  attr :href, :string, required: true
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def shop_link_outline(assigns) do
    ~H"""
    <a
      href={@href}
      class={["themed-button-outline", @class]}
      style="text-decoration: none; display: inline-block;"
    >
      {render_slot(@inner_block)}
    </a>
    """
  end

  @doc """
  Renders a themed card container.

  ## Attributes

  * `class` - Optional. Additional CSS classes.

  ## Slots

  * `inner_block` - Required. Card content.

  ## Examples

      <.shop_card class="p-6">
        <h3>Card Title</h3>
        <p>Card content...</p>
      </.shop_card>
  """
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def shop_card(assigns) do
    ~H"""
    <div class={["themed-card", @class]}>
      {render_slot(@inner_block)}
    </div>
    """
  end

  @doc """
  Renders a mobile bottom navigation bar.

  This component provides thumb-friendly navigation for mobile devices,
  following modern UX best practices. It's hidden on larger screens where
  the standard header navigation is used.

  ## Attributes

  * `active_page` - Required. The current page identifier (e.g., "home", "collection", "about", "contact").
  * `mode` - Optional. Either `:live` (default) for real navigation or
    `:preview` for theme preview mode with phx-click handlers.
  * `cart_count` - Optional. Number of items in cart for badge display. Default: 0.

  ## Examples

      <.mobile_bottom_nav active_page="home" />
      <.mobile_bottom_nav active_page="collection" mode={:preview} />
  """
  attr :active_page, :string, required: true
  attr :mode, :atom, default: :live
  attr :cart_count, :integer, default: 0

  def mobile_bottom_nav(assigns) do
    ~H"""
    <nav
      class="mobile-bottom-nav md:hidden"
      style="position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; background-color: var(--t-surface-raised); border-top: 1px solid var(--t-border-default); box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); padding-bottom: env(safe-area-inset-bottom, 0px);"
      aria-label="Main navigation"
    >
      <ul
        class="flex justify-around items-center h-16"
        style="margin: 0; padding: 0; list-style: none;"
      >
        <.mobile_nav_item
          icon={:home}
          label="Home"
          page="home"
          href="/"
          active_page={@active_page}
          mode={@mode}
        />
        <.mobile_nav_item
          icon={:shop}
          label="Shop"
          page="collection"
          href="/collections/all"
          active_page={@active_page}
          active_pages={["collection", "pdp"]}
          mode={@mode}
        />
        <.mobile_nav_item
          icon={:about}
          label="About"
          page="about"
          href="/about"
          active_page={@active_page}
          mode={@mode}
        />
        <.mobile_nav_item
          icon={:contact}
          label="Contact"
          page="contact"
          href="/contact"
          active_page={@active_page}
          mode={@mode}
        />
      </ul>
    </nav>
    """
  end

  attr :icon, :atom, required: true
  attr :label, :string, required: true
  attr :page, :string, required: true
  attr :href, :string, required: true
  attr :active_page, :string, required: true
  attr :active_pages, :list, default: nil
  attr :mode, :atom, default: :live

  defp mobile_nav_item(assigns) do
    active_pages = assigns.active_pages || [assigns.page]
    is_current = assigns.active_page in active_pages
    assigns = assign(assigns, :is_current, is_current)

    ~H"""
    <li class="flex-1">
      <%= if @mode == :preview do %>
        <a
          href="#"
          phx-click="change_preview_page"
          phx-value-page={@page}
          class="flex flex-col items-center justify-center gap-1 py-2 mx-1 rounded-lg min-h-[56px]"
          style={"color: #{if @is_current, do: "hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 15%))", else: "var(--t-text-secondary)"}; text-decoration: none; font-weight: #{if @is_current, do: "600", else: "500"}; background-color: #{if @is_current, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1)", else: "transparent"};"}
          aria-current={if @is_current, do: "page", else: nil}
        >
          <.nav_icon icon={@icon} size={if @is_current, do: "w-6 h-6", else: "w-5 h-5"} />
          <span class="text-xs">{@label}</span>
        </a>
      <% else %>
        <a
          href={@href}
          class="flex flex-col items-center justify-center gap-1 py-2 mx-1 rounded-lg min-h-[56px]"
          style={"color: #{if @is_current, do: "hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 15%))", else: "var(--t-text-secondary)"}; text-decoration: none; font-weight: #{if @is_current, do: "600", else: "500"}; background-color: #{if @is_current, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1)", else: "transparent"};"}
          aria-current={if @is_current, do: "page", else: nil}
        >
          <.nav_icon icon={@icon} size={if @is_current, do: "w-6 h-6", else: "w-5 h-5"} />
          <span class="text-xs">{@label}</span>
        </a>
      <% end %>
    </li>
    """
  end

  defp nav_icon(%{icon: :home} = assigns) do
    assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)

    ~H"""
    <svg
      class={@size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"></path>
      <polyline points="9 22 9 12 15 12 15 22"></polyline>
    </svg>
    """
  end

  defp nav_icon(%{icon: :shop} = assigns) do
    assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)

    ~H"""
    <svg
      class={@size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <rect x="3" y="3" width="7" height="7"></rect>
      <rect x="14" y="3" width="7" height="7"></rect>
      <rect x="14" y="14" width="7" height="7"></rect>
      <rect x="3" y="14" width="7" height="7"></rect>
    </svg>
    """
  end

  defp nav_icon(%{icon: :about} = assigns) do
    assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)

    ~H"""
    <svg
      class={@size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <circle cx="12" cy="12" r="10"></circle>
      <line x1="12" y1="16" x2="12" y2="12"></line>
      <line x1="12" y1="8" x2="12.01" y2="8"></line>
    </svg>
    """
  end

  defp nav_icon(%{icon: :contact} = assigns) do
    assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)

    ~H"""
    <svg
      class={@size}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
      <polyline points="22,6 12,13 2,6"></polyline>
    </svg>
    """
  end

  @doc """
  Renders the search modal overlay.

  This is a modal dialog for searching products. Currently provides
  the UI shell; search functionality will be added later.

  ## Attributes

  * `hint_text` - Optional. Hint text shown below the search input.
    Defaults to nil (no hint shown).

  ## Examples

      <.search_modal />
      <.search_modal hint_text="Try searching for \"mountain\" or \"forest\"" />
  """
  attr :hint_text, :string, default: nil

  def search_modal(assigns) do
    ~H"""
    <div
      id="search-modal"
      class="search-modal"
      style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1001; display: none; align-items: flex-start; justify-content: center; padding-top: 10vh;"
      phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
    >
      <div
        class="search-modal-content w-full max-w-xl mx-4"
        style="background: var(--t-surface-raised); border-radius: var(--t-radius-card); overflow: hidden; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);"
        phx-click-away={Phoenix.LiveView.JS.hide(to: "#search-modal")}
      >
        <div
          class="flex items-center gap-3 p-4"
          style="border-bottom: 1px solid var(--t-border-default);"
        >
          <svg
            class="w-5 h-5 flex-shrink-0"
            style="color: var(--t-text-tertiary);"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
          >
            <circle cx="11" cy="11" r="8"></circle>
            <path d="M21 21l-4.35-4.35"></path>
          </svg>
          <input
            type="text"
            id="search-input"
            class="flex-1 text-lg bg-transparent border-none outline-none"
            style="font-family: var(--t-font-body); color: var(--t-text-primary);"
            placeholder="Search products..."
            phx-click={Phoenix.LiveView.JS.dispatch("stop-propagation")}
          />
          <button
            type="button"
            class="w-8 h-8 flex items-center justify-center transition-all"
            style="color: var(--t-text-tertiary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
            phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
            aria-label="Close search"
          >
            <svg
              class="w-5 h-5"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
            >
              <line x1="18" y1="6" x2="6" y2="18"></line>
              <line x1="6" y1="6" x2="18" y2="18"></line>
            </svg>
          </button>
        </div>
        <%= if @hint_text do %>
          <div class="p-6" style="color: var(--t-text-tertiary);">
            <p class="text-sm">{@hint_text}</p>
          </div>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders the shop footer with newsletter signup and links.

  ## Attributes

  * `theme_settings` - Required. The theme settings map containing site_name.
  * `mode` - Optional. Either `:live` (default) for real navigation or
    `:preview` for theme preview mode with phx-click handlers.

  ## Examples

      <.shop_footer theme_settings={@theme_settings} />
      <.shop_footer theme_settings={@theme_settings} mode={:preview} />
  """
  attr :theme_settings, :map, required: true
  attr :mode, :atom, default: :live

  def shop_footer(assigns) do
    assigns = assign(assigns, :current_year, Date.utc_today().year)

    ~H"""
    <footer style="background-color: var(--t-surface-raised); border-top: 1px solid var(--t-border-default);">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <div class="grid grid-cols-1 md:grid-cols-2 gap-12">
          <.newsletter_card variant={:inline} />
          
    <!-- Links -->
          <div class="grid grid-cols-2 gap-8">
            <div>
              <h4
                class="font-semibold mb-4 text-sm"
                style="font-family: var(--t-font-heading); color: var(--t-text-primary);"
              >
                Shop
              </h4>
              <ul class="flex flex-col gap-2 text-sm">
                <%= if @mode == :preview do %>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="collection"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      All products
                    </a>
                  </li>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="collection"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      New arrivals
                    </a>
                  </li>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="collection"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      Best sellers
                    </a>
                  </li>
                <% else %>
                  <li>
                    <a
                      href="/collections/all"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      All products
                    </a>
                  </li>
                  <li>
                    <a
                      href="/collections/all"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      New arrivals
                    </a>
                  </li>
                  <li>
                    <a
                      href="/collections/all"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      Best sellers
                    </a>
                  </li>
                <% end %>
              </ul>
            </div>
            <div>
              <h4
                class="font-semibold mb-4 text-sm"
                style="font-family: var(--t-font-heading); color: var(--t-text-primary);"
              >
                Help
              </h4>
              <ul class="flex flex-col gap-2 text-sm">
                <%= if @mode == :preview do %>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="delivery"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      Delivery & returns
                    </a>
                  </li>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="privacy"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      Privacy policy
                    </a>
                  </li>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="terms"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      Terms of service
                    </a>
                  </li>
                  <li>
                    <a
                      href="#"
                      phx-click="change_preview_page"
                      phx-value-page="contact"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary); cursor: pointer;"
                    >
                      Contact
                    </a>
                  </li>
                <% else %>
                  <li>
                    <a
                      href="/delivery"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      Delivery & returns
                    </a>
                  </li>
                  <li>
                    <a
                      href="/privacy"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      Privacy policy
                    </a>
                  </li>
                  <li>
                    <a
                      href="/terms"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      Terms of service
                    </a>
                  </li>
                  <li>
                    <a
                      href="/contact"
                      class="transition-colors hover:opacity-80"
                      style="color: var(--t-text-secondary);"
                    >
                      Contact
                    </a>
                  </li>
                <% end %>
              </ul>
            </div>
          </div>
        </div>
        
    <!-- Bottom Bar -->
        <div
          class="mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4"
          style="border-top: 1px solid var(--t-border-subtle);"
        >
          <p class="text-xs" style="color: var(--t-text-tertiary);">
            © {@current_year} {@theme_settings.site_name}
          </p>
          <div class="flex gap-2">
            <a
              href="https://instagram.com"
              target="_blank"
              rel="noopener noreferrer"
              class="social-link w-9 h-9 flex items-center justify-center transition-all"
              style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
              aria-label="Instagram"
            >
              <svg
                class="w-5 h-5"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
              >
                <rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
                <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
                <line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
              </svg>
            </a>
            <a
              href="https://pinterest.com"
              target="_blank"
              rel="noopener noreferrer"
              class="social-link w-9 h-9 flex items-center justify-center transition-all"
              style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
              aria-label="Pinterest"
            >
              <svg
                class="w-5 h-5"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
              >
                <circle cx="12" cy="12" r="10"></circle>
                <path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
                <line x1="12" y1="16" x2="9" y2="21"></line>
              </svg>
            </a>
          </div>
        </div>
      </div>
    </footer>
    """
  end

  @doc """
  Renders the shop header with logo, navigation, and actions.

  ## Attributes

  * `theme_settings` - Required. The theme settings map.
  * `logo_image` - Optional. The logo image struct (with id, is_svg fields).
  * `header_image` - Optional. The header background image struct.
  * `active_page` - Optional. Current page for nav highlighting.
  * `mode` - Optional. Either `:live` (default) or `:preview`.
  * `cart_count` - Optional. Number of items in cart. Defaults to 0.

  ## Examples

      <.shop_header theme_settings={@theme_settings} />
      <.shop_header theme_settings={@theme_settings} mode={:preview} cart_count={2} />
  """
  attr :theme_settings, :map, required: true
  attr :logo_image, :map, default: nil
  attr :header_image, :map, default: nil
  attr :active_page, :string, default: nil
  attr :mode, :atom, default: :live
  attr :cart_count, :integer, default: 0

  def shop_header(assigns) do
    ~H"""
    <header
      class="shop-header px-2 py-2 sm:px-4 sm:py-3 md:px-8 md:py-4"
      style="background-color: var(--t-surface-raised); border-bottom: 1px solid var(--t-border-default); display: flex; align-items: center;"
    >
      <%= if @theme_settings.header_background_enabled && @header_image do %>
        <div style={header_background_style(@theme_settings, @header_image)} />
      <% end %>

      <div
        class="shop-logo"
        style="display: flex; align-items: center; position: relative; z-index: 1;"
      >
        <.logo_content
          theme_settings={@theme_settings}
          logo_image={@logo_image}
          active_page={@active_page}
          mode={@mode}
        />
      </div>

      <nav class="shop-nav hidden md:flex md:gap-6" style="position: relative; z-index: 1;">
        <%= if @mode == :preview do %>
          <.nav_item label="Home" page="home" active_page={@active_page} mode={:preview} />
          <.nav_item
            label="Shop"
            page="collection"
            active_page={@active_page}
            mode={:preview}
            active_pages={["collection", "pdp"]}
          />
          <.nav_item label="About" page="about" active_page={@active_page} mode={:preview} />
          <.nav_item label="Contact" page="contact" active_page={@active_page} mode={:preview} />
        <% else %>
          <.nav_item label="Home" href="/" active_page={@active_page} page="home" />
          <.nav_item
            label="Shop"
            href="/collections/all"
            active_page={@active_page}
            page="collection"
            active_pages={["collection", "pdp"]}
          />
          <.nav_item label="About" href="/about" active_page={@active_page} page="about" />
          <.nav_item label="Contact" href="/contact" active_page={@active_page} page="contact" />
        <% end %>
      </nav>

      <div class="shop-actions flex items-center" style="position: relative; z-index: 1;">
        <button
          type="button"
          class="header-icon-btn w-9 h-9 flex items-center justify-center transition-all"
          style="color: var(--t-text-secondary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
          phx-click={
            Phoenix.LiveView.JS.show(to: "#search-modal", display: "flex")
            |> Phoenix.LiveView.JS.focus(to: "#search-input")
          }
          aria-label="Search"
        >
          <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <circle cx="11" cy="11" r="8"></circle>
            <path d="M21 21l-4.35-4.35"></path>
          </svg>
        </button>
        <button
          type="button"
          class="header-icon-btn w-9 h-9 flex items-center justify-center transition-all relative"
          style="color: var(--t-text-secondary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
          phx-click={open_cart_drawer_js()}
          aria-label="Cart"
        >
          <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"></path>
            <line x1="3" y1="6" x2="21" y2="6"></line>
            <path d="M16 10a4 4 0 01-8 0"></path>
          </svg>
          <%= if @cart_count > 0 do %>
            <span
              class="cart-count"
              style="position: absolute; top: -4px; right: -4px; background: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); font-size: var(--t-text-caption); font-weight: 600; min-width: 18px; height: 18px; border-radius: 9999px; display: flex; align-items: center; justify-content: center; padding: 0 4px;"
            >
              {@cart_count}
            </span>
          <% end %>
          <span class="sr-only">Cart ({@cart_count})</span>
        </button>
      </div>
    </header>
    """
  end

  defp logo_url(logo_image, %{logo_recolor: true, logo_color: color}) when logo_image.is_svg do
    clean_color = String.trim_leading(color, "#")
    "/images/#{logo_image.id}/recolored/#{clean_color}"
  end

  defp logo_url(logo_image, _), do: "/images/#{logo_image.id}"

  # Logo content that links to home, except when already on home page.
  # This follows accessibility best practices - current page should not be a link.
  attr :theme_settings, :map, required: true
  attr :logo_image, :map, default: nil
  attr :active_page, :string, default: nil
  attr :mode, :atom, default: :live

  defp logo_content(assigns) do
    is_home = assigns.active_page == "home"
    assigns = assign(assigns, :is_home, is_home)

    ~H"""
    <%= if @is_home do %>
      <.logo_inner theme_settings={@theme_settings} logo_image={@logo_image} />
    <% else %>
      <%= if @mode == :preview do %>
        <a
          href="#"
          phx-click="change_preview_page"
          phx-value-page="home"
          style="display: flex; align-items: center; text-decoration: none;"
        >
          <.logo_inner theme_settings={@theme_settings} logo_image={@logo_image} />
        </a>
      <% else %>
        <a href="/" style="display: flex; align-items: center; text-decoration: none;">
          <.logo_inner theme_settings={@theme_settings} logo_image={@logo_image} />
        </a>
      <% end %>
    <% end %>
    """
  end

  attr :theme_settings, :map, required: true
  attr :logo_image, :map, default: nil

  defp logo_inner(assigns) do
    ~H"""
    <%= case @theme_settings.logo_mode do %>
      <% "text-only" -> %>
        <span
          class="shop-logo-text"
          style="font-family: var(--t-font-heading); font-size: var(--t-text-xl); font-weight: var(--t-heading-weight); color: var(--t-text-primary);"
        >
          {@theme_settings.site_name}
        </span>
      <% "logo-text" -> %>
        <%= if @logo_image do %>
          <img
            src={logo_url(@logo_image, @theme_settings)}
            alt={@theme_settings.site_name}
            style={"height: #{@theme_settings.logo_size}px; width: auto; margin-right: 0.5rem;"}
          />
        <% end %>
        <span
          class="shop-logo-text"
          style="font-family: var(--t-font-heading); font-size: var(--t-text-xl); font-weight: var(--t-heading-weight); color: var(--t-text-primary);"
        >
          {@theme_settings.site_name}
        </span>
      <% "logo-only" -> %>
        <%= if @logo_image do %>
          <img
            src={logo_url(@logo_image, @theme_settings)}
            alt={@theme_settings.site_name}
            style={"height: #{@theme_settings.logo_size}px; width: auto;"}
          />
        <% else %>
          <span
            class="shop-logo-text"
            style="font-family: var(--t-font-heading); font-size: var(--t-text-xl); font-weight: var(--t-heading-weight); color: var(--t-text-primary);"
          >
            {@theme_settings.site_name}
          </span>
        <% end %>
      <% _ -> %>
        <span
          class="shop-logo-text"
          style="font-family: var(--t-font-heading); font-size: var(--t-text-xl); font-weight: var(--t-heading-weight); color: var(--t-text-primary);"
        >
          {@theme_settings.site_name}
        </span>
    <% end %>
    """
  end

  defp header_background_style(settings, header_image) do
    "position: absolute; top: 0; left: 0; right: 0; bottom: 0; " <>
      "background-image: url('/images/#{header_image.id}'); " <>
      "background-size: #{settings.header_zoom}%; " <>
      "background-position: #{settings.header_position_x}% #{settings.header_position_y}%; " <>
      "background-repeat: no-repeat; z-index: 0;"
  end

  # Navigation item that renders as a span (not a link) when on the current page.
  # This follows accessibility best practices - current page should not be a link.
  attr :label, :string, required: true
  attr :page, :string, required: true
  attr :active_page, :string, required: true
  attr :href, :string, default: nil
  attr :mode, :atom, default: :live
  attr :active_pages, :list, default: nil

  defp nav_item(assigns) do
    # Allow matching multiple pages (e.g., "Shop" is active for both collection and pdp)
    active_pages = assigns.active_pages || [assigns.page]
    is_current = assigns.active_page in active_pages
    assigns = assign(assigns, :is_current, is_current)

    ~H"""
    <%= if @is_current do %>
      <span aria-current="page" style="color: var(--t-text-secondary); text-decoration: none;">
        {@label}
      </span>
    <% else %>
      <%= if @mode == :preview do %>
        <a
          href="#"
          phx-click="change_preview_page"
          phx-value-page={@page}
          style="color: var(--t-text-secondary); text-decoration: none; cursor: pointer;"
        >
          {@label}
        </a>
      <% else %>
        <a href={@href} style="color: var(--t-text-secondary); text-decoration: none;">
          {@label}
        </a>
      <% end %>
    <% end %>
    """
  end

  defp open_cart_drawer_js do
    Phoenix.LiveView.JS.push("open_cart_drawer")
  end

  defp close_cart_drawer_js do
    Phoenix.LiveView.JS.push("close_cart_drawer")
  end

  @doc """
  Renders the cart drawer (floating sidebar).

  The drawer slides in from the right when opened. It displays cart items
  and checkout options. Follows WAI-ARIA dialog pattern for accessibility.

  ## Attributes

  * `cart_items` - List of cart items to display. Each item should have
    `image`, `name`, `variant`, `price`, and `variant_id` keys. Default: []
  * `subtotal` - The subtotal to display. Default: nil (shows "£0.00")
  * `cart_count` - Number of items for screen reader description. Default: 0
  * `mode` - Either `:live` (default) for real stores or `:preview` for theme editor.
    In preview mode, "View basket" navigates via LiveView JS commands.

  ## Examples

      <.cart_drawer cart_items={@cart.items} subtotal={@cart.subtotal} />
      <.cart_drawer cart_items={demo_items} subtotal="£72.00" mode={:preview} />
  """

  attr :cart_items, :list, default: []
  attr :subtotal, :string, default: nil
  attr :cart_count, :integer, default: 0
  attr :cart_status, :string, default: nil
  attr :mode, :atom, default: :live
  attr :open, :boolean, default: false

  def cart_drawer(assigns) do
    assigns =
      assign_new(assigns, :display_subtotal, fn ->
        assigns.subtotal || "£0.00"
      end)

    ~H"""
    <%!-- Screen reader announcements for cart changes --%>
    <div aria-live="polite" aria-atomic="true" class="sr-only">
      {@cart_status}
    </div>

    <!-- Cart Drawer Overlay -->
    <div
      id="cart-drawer-overlay"
      class={["cart-drawer-overlay", @open && "open"]}
      aria-hidden={to_string(!@open)}
      style="position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 999; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease;"
      phx-click={close_cart_drawer_js()}
    >
    </div>

    <!-- Cart Drawer -->
    <div
      id="cart-drawer"
      role="dialog"
      aria-modal="true"
      aria-labelledby="cart-drawer-title"
      aria-describedby="cart-drawer-description"
      aria-hidden={to_string(!@open)}
      phx-hook="CartDrawer"
      class={["cart-drawer", @open && "open"]}
      style="position: fixed; top: 0; right: -400px; width: 400px; max-width: 90vw; height: 100vh; height: 100dvh; background: var(--t-surface-raised); z-index: 1001; display: flex; flex-direction: column; transition: right 0.3s ease; box-shadow: -4px 0 20px rgba(0,0,0,0.15);"
    >
      <p id="cart-drawer-description" class="sr-only">
        Shopping basket with {@cart_count} {if @cart_count == 1, do: "item", else: "items"}. Press Escape to close.
      </p>
      <div
        class="cart-drawer-header"
        style="display: flex; justify-content: space-between; align-items: center; padding: 1rem 1.5rem; border-bottom: 1px solid var(--t-border-default);"
      >
        <h2
          id="cart-drawer-title"
          style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); font-size: var(--t-text-large); color: var(--t-text-primary); margin: 0;"
        >
          Your basket
        </h2>
        <button
          type="button"
          class="cart-drawer-close"
          style="background: none; border: none; padding: 0.5rem; cursor: pointer; color: var(--t-text-secondary);"
          phx-click={close_cart_drawer_js()}
          aria-label="Close cart"
        >
          <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="18" y1="6" x2="6" y2="18"></line>
            <line x1="6" y1="6" x2="18" y2="18"></line>
          </svg>
        </button>
      </div>

      <div class="cart-drawer-items" style="flex: 1; overflow-y: auto; padding: 1rem;">
        <%= if @cart_items == [] do %>
          <.cart_empty_state mode={@mode} />
        <% else %>
          <ul role="list" aria-label="Cart items" style="list-style: none; margin: 0; padding: 0;">
            <%= for item <- @cart_items do %>
              <li style="border-bottom: 1px solid var(--t-border-default);">
                <.cart_item_row item={item} size={:compact} mode={@mode} />
              </li>
            <% end %>
          </ul>
        <% end %>
      </div>

      <div
        class="cart-drawer-footer"
        style="padding: 1rem 1.5rem; border-top: 1px solid var(--t-border-default); background: var(--t-surface-sunken);"
      >
        <div style="display: flex; justify-content: space-between; font-family: var(--t-font-body); font-size: var(--t-text-small); color: var(--t-text-secondary); margin-bottom: 0.5rem;">
          <span>Delivery</span>
          <span>Calculated at checkout</span>
        </div>
        <div
          class="cart-drawer-total"
          style="display: flex; justify-content: space-between; font-family: var(--t-font-body); font-size: var(--t-text-base); font-weight: 600; color: var(--t-text-primary); margin-bottom: 1rem;"
        >
          <span>Subtotal</span>
          <span>{@display_subtotal}</span>
        </div>
        <%= if @mode == :preview do %>
          <button
            type="button"
            class="cart-drawer-checkout w-full mb-2"
            style="width: 100%; padding: 0.75rem 1.5rem; font-weight: 600; transition: all 0.2s ease; background: var(--t-accent-button, hsl(var(--t-accent-h) var(--t-accent-s) 42%)); color: var(--t-text-inverse); border-radius: var(--t-radius-button); border: none; cursor: pointer; font-family: var(--t-font-body);"
          >
            Checkout
          </button>
        <% else %>
          <form action="/checkout" method="post">
            <input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
            <button
              type="submit"
              class="cart-drawer-checkout w-full mb-2"
              style="width: 100%; padding: 0.75rem 1.5rem; font-weight: 600; transition: all 0.2s ease; background: var(--t-accent-button, hsl(var(--t-accent-h) var(--t-accent-s) 42%)); color: var(--t-text-inverse); border-radius: var(--t-radius-button); border: none; cursor: pointer; font-family: var(--t-font-body);"
            >
              Checkout
            </button>
          </form>
        <% end %>
        <%= if @mode == :preview do %>
          <a
            href="#"
            phx-click={
              close_cart_drawer_js()
              |> Phoenix.LiveView.JS.push("change_preview_page", value: %{page: "cart"})
            }
            class="cart-drawer-link"
            style="display: block; text-align: center; font-family: var(--t-font-body); font-size: var(--t-text-small); color: var(--t-text-secondary); text-decoration: underline; cursor: pointer;"
          >
            View basket
          </a>
        <% else %>
          <a
            href="/cart"
            phx-click={close_cart_drawer_js()}
            class="cart-drawer-link"
            style="display: block; text-align: center; font-family: var(--t-font-body); font-size: var(--t-text-small); color: var(--t-text-secondary); text-decoration: underline; cursor: pointer;"
          >
            View basket
          </a>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Shared cart item row component used by both drawer and cart page.

  ## Attributes

  * `item` - Required. Cart item with `name`, `variant`, `price`, `quantity`, `image`, `variant_id`, `product_id`.
  * `size` - Either `:compact` (drawer) or `:default` (cart page). Default: :default
  * `show_quantity_controls` - Show +/- buttons. Default: false
  * `mode` - Either `:live` or `:preview`. Default: :live
  """
  attr :item, :map, required: true
  attr :size, :atom, default: :default
  attr :show_quantity_controls, :boolean, default: false
  attr :mode, :atom, default: :live

  def cart_item_row(assigns) do
    ~H"""
    <div
      class="cart-item-row"
      style={"display: flex; gap: #{if @size == :compact, do: "0.75rem", else: "1rem"}; padding: 0.75rem 0;"}
    >
      <%= if @mode != :preview do %>
        <a
          href={"/products/#{@item.product_id}"}
          class="cart-item-image"
          style={"display: block; width: #{if @size == :compact, do: "60px", else: "80px"}; height: #{if @size == :compact, do: "60px", else: "80px"}; border-radius: var(--t-radius-card); background-size: cover; background-position: center; flex-shrink: 0; #{if @item.image, do: "background-image: url('#{@item.image}');", else: "background-color: var(--t-surface-sunken);"}"}
          aria-label={"View #{@item.name}"}
        >
        </a>
      <% else %>
        <div
          class="cart-item-image"
          style={"width: #{if @size == :compact, do: "60px", else: "80px"}; height: #{if @size == :compact, do: "60px", else: "80px"}; border-radius: var(--t-radius-card); background-size: cover; background-position: center; flex-shrink: 0; #{if @item.image, do: "background-image: url('#{@item.image}');", else: "background-color: var(--t-surface-sunken);"}"}
        >
        </div>
      <% end %>
      <div class="cart-item-details" style="flex: 1; min-width: 0;">
        <h3 style={"font-family: var(--t-font-body); font-size: #{if @size == :compact, do: "var(--t-text-small)", else: "var(--t-text-base)"}; font-weight: 500; margin: 0 0 2px;"}>
          <%= if @mode != :preview do %>
            <a
              href={"/products/#{@item.product_id}"}
              style="color: var(--t-text-primary); text-decoration: none;"
              onmouseover="this.style.textDecoration='underline'"
              onmouseout="this.style.textDecoration='none'"
            >
              {@item.name}
            </a>
          <% else %>
            <span style="color: var(--t-text-primary);">{@item.name}</span>
          <% end %>
        </h3>
        <%= if @item.variant do %>
          <p style="font-family: var(--t-font-body); font-size: var(--t-text-caption); color: var(--t-text-tertiary); margin: 0;">
            {@item.variant}
          </p>
        <% end %>

        <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 4px; flex-wrap: wrap; gap: 0.5rem;">
          <%= if @show_quantity_controls do %>
            <div
              class="flex items-center"
              style="border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input);"
            >
              <button
                type="button"
                phx-click="decrement"
                phx-value-id={@item.variant_id}
                class="px-3 py-1"
                style="background: none; border: none; cursor: pointer; color: var(--t-text-primary);"
                aria-label={"Decrease quantity of #{@item.name}"}
              >
                −
              </button>
              <span
                class="px-3 py-1 border-x"
                style="border-color: var(--t-border-default); color: var(--t-text-primary); min-width: 2rem; text-align: center;"
              >
                {@item.quantity}
              </span>
              <button
                type="button"
                phx-click="increment"
                phx-value-id={@item.variant_id}
                class="px-3 py-1"
                style="background: none; border: none; cursor: pointer; color: var(--t-text-primary);"
                aria-label={"Increase quantity of #{@item.name}"}
              >
                +
              </button>
            </div>
          <% else %>
            <span style="font-size: var(--t-text-caption); color: var(--t-text-tertiary);">
              Qty: {@item.quantity}
            </span>
          <% end %>

          <.cart_remove_button variant_id={@item.variant_id} item_name={@item.name} />
        </div>
      </div>

      <div class="text-right" style="flex-shrink: 0;">
        <p style={"font-weight: 500; font-size: #{if @size == :compact, do: "var(--t-text-small)", else: "var(--t-text-base)"}; color: var(--t-text-primary); margin: 0;"}>
          {SimpleshopTheme.Cart.format_price(@item.price * @item.quantity)}
        </p>
      </div>
    </div>
    """
  end

  @doc """
  Cart empty state component.
  """
  attr :mode, :atom, default: :live

  def cart_empty_state(assigns) do
    ~H"""
    <div class="text-center py-8" style="color: var(--t-text-secondary);">
      <svg
        class="w-16 h-16 mx-auto mb-4"
        style="color: var(--t-text-tertiary);"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.5"
      >
        <path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"></path>
        <line x1="3" y1="6" x2="21" y2="6"></line>
        <path d="M16 10a4 4 0 01-8 0"></path>
      </svg>
      <p class="mb-4">Your basket is empty</p>
      <%= if @mode == :preview do %>
        <button
          type="button"
          phx-click="change_preview_page"
          phx-value-page="collection"
          style="color: var(--t-text-accent); text-decoration: underline; background: none; border: none; cursor: pointer;"
        >
          Continue shopping
        </button>
      <% else %>
        <a href="/collections/all" style="color: var(--t-text-accent); text-decoration: underline;">
          Continue shopping
        </a>
      <% end %>
    </div>
    """
  end

  @doc """
  Remove button for cart items.
  """
  attr :variant_id, :string, required: true
  attr :item_name, :string, default: "item"

  def cart_remove_button(assigns) do
    ~H"""
    <button
      type="button"
      phx-click="remove_item"
      phx-value-id={@variant_id}
      style="background: none; border: none; padding: 0; cursor: pointer; font-family: var(--t-font-body); font-size: var(--t-text-caption); color: var(--t-text-tertiary); text-decoration: underline;"
      aria-label={"Remove #{@item_name} from cart"}
    >
      Remove
    </button>
    """
  end

  @doc """
  Renders a product card with configurable variants.

  ## Attributes

  * `product` - Required. The product map with `name`, `image_url`, `price`, etc.
  * `theme_settings` - Required. The theme settings map.
  * `mode` - Either `:live` (default) or `:preview`.
  * `variant` - The visual variant:
    - `:default` - Collection page style with border, category, full details
    - `:featured` - Home page style with hover lift, no border
    - `:compact` - PDP related products with aspect-square, minimal info
    - `:minimal` - Error 404 style, smallest, not clickable
  * `show_category` - Show category label. Defaults based on variant.
  * `show_badges` - Show product badges. Defaults based on variant.
  * `show_delivery_text` - Show "Free delivery" text. Defaults based on variant.
  * `clickable` - Whether the card navigates. Defaults based on variant.

  ## Examples

      <.product_card product={product} theme_settings={@theme_settings} />
      <.product_card product={product} theme_settings={@theme_settings} variant={:featured} mode={:preview} />
  """
  attr :product, :map, required: true
  attr :theme_settings, :map, required: true
  attr :mode, :atom, default: :live
  attr :variant, :atom, default: :default
  attr :show_category, :boolean, default: nil
  attr :show_badges, :boolean, default: nil
  attr :show_delivery_text, :boolean, default: nil
  attr :clickable, :boolean, default: nil

  def product_card(assigns) do
    # Apply variant defaults for nil values
    defaults = variant_defaults(assigns.variant)

    assigns =
      assigns
      |> assign_new(:show_category_resolved, fn ->
        if assigns.show_category == nil, do: defaults.show_category, else: assigns.show_category
      end)
      |> assign_new(:show_badges_resolved, fn ->
        if assigns.show_badges == nil, do: defaults.show_badges, else: assigns.show_badges
      end)
      |> assign_new(:show_delivery_text_resolved, fn ->
        if assigns.show_delivery_text == nil,
          do: defaults.show_delivery_text,
          else: assigns.show_delivery_text
      end)
      |> assign_new(:clickable_resolved, fn ->
        if assigns.clickable == nil, do: defaults.clickable, else: assigns.clickable
      end)

    ~H"""
    <%= if @clickable_resolved do %>
      <%= if @mode == :preview do %>
        <a
          href="#"
          phx-click="change_preview_page"
          phx-value-page="pdp"
          class={card_classes(@variant)}
          style={card_style(@variant)}
        >
          <.product_card_inner
            product={@product}
            theme_settings={@theme_settings}
            variant={@variant}
            show_category={@show_category_resolved}
            show_badges={@show_badges_resolved}
            show_delivery_text={@show_delivery_text_resolved}
          />
        </a>
      <% else %>
        <a
          href={"/products/#{@product[:slug] || @product[:id]}"}
          class={card_classes(@variant)}
          style={card_style(@variant)}
        >
          <.product_card_inner
            product={@product}
            theme_settings={@theme_settings}
            variant={@variant}
            show_category={@show_category_resolved}
            show_badges={@show_badges_resolved}
            show_delivery_text={@show_delivery_text_resolved}
          />
        </a>
      <% end %>
    <% else %>
      <div
        class={card_classes(@variant)}
        style={card_style(@variant)}
      >
        <.product_card_inner
          product={@product}
          theme_settings={@theme_settings}
          variant={@variant}
          show_category={@show_category_resolved}
          show_badges={@show_badges_resolved}
          show_delivery_text={@show_delivery_text_resolved}
        />
      </div>
    <% end %>
    """
  end

  attr :product, :map, required: true
  attr :theme_settings, :map, required: true
  attr :variant, :atom, required: true
  attr :show_category, :boolean, required: true
  attr :show_badges, :boolean, required: true
  attr :show_delivery_text, :boolean, required: true

  defp product_card_inner(assigns) do
    ~H"""
    <div class={image_container_classes(@variant)}>
      <%= if @show_badges do %>
        <.product_badge product={@product} />
      <% end %>
      <.product_card_image
        product={@product}
        variant={@variant}
        class="product-image-primary w-full h-full object-cover transition-opacity duration-300"
      />
      <%= if @theme_settings.hover_image && @product[:hover_image_url] do %>
        <.product_card_image
          product={@product}
          variant={@variant}
          image_key={:hover}
          class="product-image-hover w-full h-full object-cover"
        />
      <% end %>
    </div>
    <div class={content_padding_class(@variant)}>
      <%= if @show_category && @product[:category] do %>
        <p class="text-xs mb-1" style="color: var(--t-text-tertiary);">
          {@product.category}
        </p>
      <% end %>
      <h3 class={title_classes(@variant)} style={title_style(@variant)}>
        {@product.name}
      </h3>
      <%= if @theme_settings.show_prices do %>
        <.product_price product={@product} variant={@variant} />
      <% end %>
      <%= if @show_delivery_text do %>
        <p class="text-xs mt-1" style="color: var(--t-text-tertiary);">
          Made to order
        </p>
      <% end %>
    </div>
    """
  end

  # Helper to render product images with responsive variants.
  # Works for both mockups (static files) and database images.
  # Requires source_width to be set for responsive image support.
  attr :product, :map, required: true
  attr :variant, :atom, required: true
  attr :class, :string, default: ""
  attr :image_key, :atom, default: :primary

  defp product_card_image(assigns) do
    # Determine which image fields to use based on primary vs hover
    {image_id_field, image_url_field, source_width_field} =
      case assigns.image_key do
        :hover -> {:hover_image_id, :hover_image_url, :hover_source_width}
        _ -> {:image_id, :image_url, :source_width}
      end

    # Build the base image path:
    # - Database images: /images/{id}/variant
    # - Mockup images: {image_url} (e.g., /mockups/product-1)
    image_id = assigns.product[image_id_field]
    image_url = assigns.product[image_url_field]

    src =
      if image_id do
        # Trailing slash so build_srcset produces /images/{id}/variant/800.webp
        "/images/#{image_id}/variant/"
      else
        image_url
      end

    assigns =
      assigns
      |> assign(:src, src)
      |> assign(:source_width, assigns.product[source_width_field])

    ~H"""
    <%= if @source_width do %>
      <.responsive_image
        src={@src}
        alt={@product.name}
        source_width={@source_width}
        sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
        class={@class}
        width={600}
        height={600}
        priority={@variant == :minimal}
      />
    <% else %>
      <img
        src={@src}
        alt={@product.name}
        width="600"
        height="600"
        loading={if @variant == :minimal, do: nil, else: "lazy"}
        decoding={if @variant == :minimal, do: nil, else: "async"}
        class={@class}
      />
    <% end %>
    """
  end

  attr :product, :map, required: true

  defp product_badge(assigns) do
    ~H"""
    <%= cond do %>
      <% Map.get(@product, :in_stock, true) == false -> %>
        <span class="product-badge badge-sold-out">Sold out</span>
      <% @product[:is_new] -> %>
        <span class="product-badge badge-new">New</span>
      <% @product[:on_sale] -> %>
        <span class="product-badge badge-sale">Sale</span>
      <% true -> %>
    <% end %>
    """
  end

  attr :product, :map, required: true
  attr :variant, :atom, required: true

  defp product_price(assigns) do
    ~H"""
    <%= case @variant do %>
      <% :default -> %>
        <div>
          <%= if @product.on_sale do %>
            <span
              class="text-lg font-bold"
              style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
            >
              {SimpleshopTheme.Cart.format_price(@product.price)}
            </span>
            <span class="text-sm line-through ml-2" style="color: var(--t-text-tertiary);">
              {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
            </span>
          <% else %>
            <span class="text-lg font-bold" style="color: var(--t-text-primary);">
              {SimpleshopTheme.Cart.format_price(@product.price)}
            </span>
          <% end %>
        </div>
      <% :featured -> %>
        <p class="text-sm" style="color: var(--t-text-secondary);">
          <%= if @product.on_sale do %>
            <span class="line-through mr-1" style="color: var(--t-text-tertiary);">
              {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
            </span>
          <% end %>
          {SimpleshopTheme.Cart.format_price(@product.price)}
        </p>
      <% :compact -> %>
        <p class="font-bold" style="color: var(--t-text-primary);">
          {SimpleshopTheme.Cart.format_price(@product.price)}
        </p>
      <% :minimal -> %>
        <p class="text-xs" style="color: var(--t-text-secondary);">
          {SimpleshopTheme.Cart.format_price(@product.price)}
        </p>
    <% end %>
    """
  end

  defp variant_defaults(:default),
    do: %{show_category: true, show_badges: true, show_delivery_text: true, clickable: true}

  defp variant_defaults(:featured),
    do: %{show_category: false, show_badges: true, show_delivery_text: true, clickable: true}

  defp variant_defaults(:compact),
    do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: true}

  defp variant_defaults(:minimal),
    do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: false}

  defp card_classes(:default), do: "product-card group overflow-hidden transition-all"

  defp card_classes(:featured),
    do: "product-card group overflow-hidden transition-all hover:-translate-y-1"

  defp card_classes(:compact), do: "product-card group overflow-hidden cursor-pointer"
  defp card_classes(:minimal), do: "product-card group overflow-hidden"

  defp card_style(:default),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card); cursor: pointer;"

  defp card_style(:featured),
    do:
      "background-color: var(--t-surface-raised); border-radius: var(--t-radius-card); cursor: pointer;"

  defp card_style(:compact),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card);"

  defp card_style(:minimal),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-subtle); border-radius: var(--t-radius-card);"

  defp image_container_classes(:compact),
    do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative"

  defp image_container_classes(:minimal),
    do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative"

  defp image_container_classes(_),
    do: "product-image-container bg-gray-200 overflow-hidden relative"

  defp content_padding_class(:compact), do: "p-3"
  defp content_padding_class(:minimal), do: "p-2"
  defp content_padding_class(_), do: ""

  defp title_classes(:default), do: "font-semibold mb-2"
  defp title_classes(:featured), do: "text-sm font-medium mb-1"
  defp title_classes(:compact), do: "font-semibold text-sm mb-1"
  defp title_classes(:minimal), do: "text-xs font-semibold truncate"

  defp title_style(:default),
    do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"

  defp title_style(:featured), do: "color: var(--t-text-primary);"

  defp title_style(:compact),
    do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"

  defp title_style(:minimal), do: "color: var(--t-text-primary);"

  @doc """
  Renders a responsive product grid container.

  This component wraps product cards in a responsive grid layout. It supports
  theme-based column settings or fixed column layouts for specific use cases.

  ## Attributes

  * `theme_settings` - Optional. When provided, uses `grid_columns` setting for lg breakpoint.
  * `columns` - Optional. Fixed column count for lg breakpoint (overrides theme_settings).
    Use `:fixed_4` for a fixed 2/4 column layout (error page, related products).
  * `gap` - Optional. Gap size. Defaults to standard gap.
  * `class` - Optional. Additional CSS classes to add.

  ## Slots

  * `inner_block` - Required. The product cards to render inside the grid.

  ## Examples

      <.product_grid theme_settings={@theme_settings}>
        <%= for product <- @products do %>
          <.product_card product={product} theme_settings={@theme_settings} />
        <% end %>
      </.product_grid>

      <.product_grid columns={:fixed_4} gap="gap-6">
        ...
      </.product_grid>
  """
  attr :theme_settings, :map, default: nil
  attr :columns, :atom, default: nil
  attr :gap, :string, default: nil
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def product_grid(assigns) do
    ~H"""
    <div class={grid_classes(@theme_settings, @columns, @gap, @class)}>
      {render_slot(@inner_block)}
    </div>
    """
  end

  defp grid_classes(theme_settings, columns, gap, extra_class) do
    base = "product-grid grid"

    cols =
      cond do
        columns == :fixed_4 ->
          "grid-cols-2 md:grid-cols-4"

        theme_settings != nil ->
          responsive_cols = "grid-cols-1 sm:grid-cols-2"

          lg_cols =
            case theme_settings.grid_columns do
              "2" -> "lg:grid-cols-2"
              "3" -> "lg:grid-cols-3"
              "4" -> "lg:grid-cols-4"
              _ -> "lg:grid-cols-3"
            end

          "#{responsive_cols} #{lg_cols}"

        true ->
          "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
      end

    gap_class = gap || ""

    [base, cols, gap_class, extra_class]
    |> Enum.reject(&is_nil/1)
    |> Enum.reject(&(&1 == ""))
    |> Enum.join(" ")
  end

  @doc """
  Renders a centered hero section with title, description, and optional CTAs.

  ## Attributes

  * `title` - Required. The main heading text.
  * `description` - Required. The description paragraph text.
  * `variant` - The visual variant:
    - `:default` - Standard hero with section wrapper and padding
    - `:page` - Page header style, larger title, more spacing, no section wrapper
    - `:error` - Error page with pre-title (404), two buttons
  * `background` - Background style. Either `:base` (default) or `:sunken`.
  * `pre_title` - Optional. Text shown above title (e.g., "404" for error pages).
  * `cta_text` - Optional. Text for the primary CTA button.
  * `cta_page` - Optional. Page to navigate to on click (for preview mode).
  * `cta_href` - Optional. URL for live mode navigation.
  * `secondary_cta_text` - Optional. Text for secondary button (error variant).
  * `secondary_cta_page` - Optional. Page for secondary button (preview mode).
  * `secondary_cta_href` - Optional. URL for secondary button (live mode).
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.hero_section
        title="Original designs, printed on demand"
        description="From art prints to apparel..."
        cta_text="Shop the collection"
        cta_page="collection"
        mode={:preview}
      />

      <.hero_section
        variant={:page}
        title="Get in touch"
        description="Questions about your order?"
      />

      <.hero_section
        variant={:error}
        pre_title="404"
        title="Page Not Found"
        description="Sorry, that page doesn't exist..."
        cta_text="Go to Homepage"
        secondary_cta_text="Browse Products"
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :variant, :atom, default: :default
  attr :background, :atom, default: :base
  attr :pre_title, :string, default: nil
  attr :cta_text, :string, default: nil
  attr :cta_page, :string, default: nil
  attr :cta_href, :string, default: nil
  attr :secondary_cta_text, :string, default: nil
  attr :secondary_cta_page, :string, default: nil
  attr :secondary_cta_href, :string, default: nil
  attr :mode, :atom, default: :live

  def hero_section(assigns) do
    ~H"""
    <%= case @variant do %>
      <% :default -> %>
        <section
          class="text-center"
          style={"padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-#{@background});"}
        >
          <h1
            class="text-3xl md:text-4xl mb-4"
            style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
          >
            {@title}
          </h1>
          <p
            class="text-lg max-w-lg mx-auto mb-8"
            style="color: var(--t-text-secondary); line-height: 1.6;"
          >
            {@description}
          </p>
          <.hero_cta
            :if={@cta_text}
            text={@cta_text}
            page={@cta_page}
            href={@cta_href}
            mode={@mode}
            variant={:primary}
          />
        </section>
      <% :page -> %>
        <div class="text-center">
          <h1
            class="text-4xl md:text-5xl font-bold mb-6"
            style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
          >
            {@title}
          </h1>
          <p class="text-lg mb-12 max-w-2xl mx-auto" style="color: var(--t-text-secondary);">
            {@description}
          </p>
        </div>
      <% :error -> %>
        <div class="text-center">
          <%= if @pre_title do %>
            <h1
              class="text-8xl md:text-9xl font-bold mb-4"
              style="font-family: var(--t-font-heading); color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); font-weight: var(--t-heading-weight);"
            >
              {@pre_title}
            </h1>
          <% end %>
          <h2
            class="text-3xl md:text-4xl font-bold mb-6"
            style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
          >
            {@title}
          </h2>
          <p class="text-lg mb-8 max-w-md mx-auto" style="color: var(--t-text-secondary);">
            {@description}
          </p>
          <%= if @cta_text || @secondary_cta_text do %>
            <div class="flex flex-col sm:flex-row gap-4 justify-center">
              <.hero_cta
                :if={@cta_text}
                text={@cta_text}
                page={@cta_page}
                href={@cta_href}
                mode={@mode}
                variant={:primary}
              />
              <.hero_cta
                :if={@secondary_cta_text}
                text={@secondary_cta_text}
                page={@secondary_cta_page}
                href={@secondary_cta_href}
                mode={@mode}
                variant={:secondary}
              />
            </div>
          <% end %>
        </div>
    <% end %>
    """
  end

  attr :text, :string, required: true
  attr :page, :string, default: nil
  attr :href, :string, default: nil
  attr :mode, :atom, required: true
  attr :variant, :atom, required: true

  defp hero_cta(assigns) do
    ~H"""
    <%= if @mode == :preview do %>
      <button
        phx-click="change_preview_page"
        phx-value-page={@page}
        class={hero_cta_classes(@variant)}
        style={hero_cta_style(@variant)}
      >
        {@text}
      </button>
    <% else %>
      <a
        href={@href || "/"}
        class={["inline-block", hero_cta_classes(@variant)]}
        style={hero_cta_style(@variant) <> " text-decoration: none;"}
      >
        {@text}
      </a>
    <% end %>
    """
  end

  defp hero_cta_classes(:primary), do: "themed-button px-8 py-3 font-semibold transition-all"

  defp hero_cta_classes(:secondary),
    do: "themed-button-outline px-8 py-3 font-semibold transition-all"

  defp hero_cta_style(:primary), do: ""
  defp hero_cta_style(:secondary), do: ""

  @doc """
  Renders a row of category circles for navigation.

  ## Attributes

  * `categories` - Required. List of category maps with `name` and `image_url`.
  * `limit` - Optional. Maximum number of categories to show. Defaults to 3.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.category_nav categories={@categories} mode={:preview} />
      <.category_nav categories={@categories} limit={4} />
  """
  attr :categories, :list, required: true
  attr :limit, :integer, default: 3
  attr :mode, :atom, default: :live

  def category_nav(assigns) do
    ~H"""
    <section style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-base);">
      <h2 class="sr-only">Shop by Category</h2>
      <nav class="grid grid-cols-3 gap-4 max-w-3xl mx-auto" aria-label="Product categories">
        <%= for category <- Enum.take(@categories, @limit) do %>
          <%= if @mode == :preview do %>
            <a
              href="#"
              phx-click="change_preview_page"
              phx-value-page="collection"
              class="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5"
              style="text-decoration: none; cursor: pointer;"
            >
              <div
                class="w-24 h-24 rounded-full bg-gray-200 bg-cover bg-center transition-transform hover:scale-105"
                style={"background-image: url('#{category.image_url}');"}
              >
              </div>
              <span
                class="text-sm font-medium"
                style="font-family: var(--t-font-body); color: var(--t-text-primary);"
              >
                {category.name}
              </span>
            </a>
          <% else %>
            <a
              href={"/collections/#{category.slug}"}
              class="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5"
              style="text-decoration: none;"
            >
              <div
                class="w-24 h-24 rounded-full bg-gray-200 bg-cover bg-center transition-transform hover:scale-105"
                style={"background-image: url('#{category.image_url}');"}
              >
              </div>
              <span
                class="text-sm font-medium"
                style="font-family: var(--t-font-body); color: var(--t-text-primary);"
              >
                {category.name}
              </span>
            </a>
          <% end %>
        <% end %>
      </nav>
    </section>
    """
  end

  @doc """
  Renders a featured products section with title, product grid, and view-all button.

  ## Attributes

  * `title` - Required. Section heading text.
  * `products` - Required. List of products to display.
  * `theme_settings` - Required. The theme settings map.
  * `limit` - Optional. Maximum products to show. Defaults to 4.
  * `mode` - Either `:live` (default) or `:preview`.
  * `cta_text` - Optional. Text for the "view all" button. Defaults to "View all products".
  * `cta_page` - Optional. Page to navigate to (preview mode). Defaults to "collection".
  * `cta_href` - Optional. URL for live mode. Defaults to "/collections/all".

  ## Examples

      <.featured_products_section
        title="Featured products"
        products={@products}
        theme_settings={@theme_settings}
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :products, :list, required: true
  attr :theme_settings, :map, required: true
  attr :limit, :integer, default: 4
  attr :mode, :atom, default: :live
  attr :cta_text, :string, default: "View all products"
  attr :cta_page, :string, default: "collection"
  attr :cta_href, :string, default: "/collections/all"

  def featured_products_section(assigns) do
    ~H"""
    <section style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-sunken);">
      <h2
        class="text-2xl mb-6"
        style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
      >
        {@title}
      </h2>

      <.product_grid theme_settings={@theme_settings}>
        <%= for product <- Enum.take(@products, @limit) do %>
          <.product_card
            product={product}
            theme_settings={@theme_settings}
            mode={@mode}
            variant={:featured}
          />
        <% end %>
      </.product_grid>

      <div class="text-center mt-8">
        <%= if @mode == :preview do %>
          <button
            phx-click="change_preview_page"
            phx-value-page={@cta_page}
            class="px-6 py-3 font-medium transition-all"
            style="background-color: transparent; color: var(--t-text-primary); border: 1px solid var(--t-text-primary); border-radius: var(--t-radius-button); cursor: pointer;"
          >
            {@cta_text}
          </button>
        <% else %>
          <a
            href={@cta_href}
            class="inline-block px-6 py-3 font-medium transition-all"
            style="background-color: transparent; color: var(--t-text-primary); border: 1px solid var(--t-text-primary); border-radius: var(--t-radius-button); text-decoration: none;"
          >
            {@cta_text}
          </a>
        <% end %>
      </div>
    </section>
    """
  end

  @doc """
  Renders a two-column image + text section.

  ## Attributes

  * `title` - Required. Section heading text.
  * `description` - Required. Body text content.
  * `image_url` - Required. URL for the image.
  * `link_text` - Optional. Text for the link. If nil, no link is shown.
  * `link_page` - Optional. Page to navigate to (preview mode).
  * `link_href` - Optional. URL for live mode.
  * `image_position` - Either `:left` (default) or `:right`.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.image_text_section
        title="Made with passion, printed with care"
        description="Every design starts with an idea..."
        image_url="/mockups/example.jpg"
        link_text="Learn more about the studio →"
        link_page="about"
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :image_url, :string, required: true
  attr :link_text, :string, default: nil
  attr :link_page, :string, default: nil
  attr :link_href, :string, default: nil
  attr :image_position, :atom, default: :left
  attr :mode, :atom, default: :live

  def image_text_section(assigns) do
    ~H"""
    <section
      class="grid grid-cols-1 md:grid-cols-2 gap-12 items-center"
      style="padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-base);"
    >
      <%= if @image_position == :left do %>
        <.image_text_image image_url={@image_url} />
        <.image_text_content
          title={@title}
          description={@description}
          link_text={@link_text}
          link_page={@link_page}
          link_href={@link_href}
          mode={@mode}
        />
      <% else %>
        <.image_text_content
          title={@title}
          description={@description}
          link_text={@link_text}
          link_page={@link_page}
          link_href={@link_href}
          mode={@mode}
        />
        <.image_text_image image_url={@image_url} />
      <% end %>
    </section>
    """
  end

  attr :image_url, :string, required: true

  defp image_text_image(assigns) do
    ~H"""
    <div
      class="h-72 rounded-lg bg-cover bg-center"
      style={"background-image: url('#{@image_url}'); border-radius: var(--t-radius-image);"}
    >
    </div>
    """
  end

  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :link_text, :string, default: nil
  attr :link_page, :string, default: nil
  attr :link_href, :string, default: nil
  attr :mode, :atom, required: true

  defp image_text_content(assigns) do
    ~H"""
    <div>
      <h2
        class="text-2xl mb-4"
        style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
      >
        {@title}
      </h2>
      <p class="text-base mb-4" style="color: var(--t-text-secondary); line-height: 1.7;">
        {@description}
      </p>
      <%= if @link_text do %>
        <%= if @mode == :preview do %>
          <a
            href="#"
            phx-click="change_preview_page"
            phx-value-page={@link_page}
            class="text-sm font-medium transition-colors"
            style="color: var(--t-accent-text, hsl(var(--t-accent-h) var(--t-accent-s) 38%)); text-decoration: none; cursor: pointer;"
          >
            {@link_text}
          </a>
        <% else %>
          <a
            href={@link_href || "/"}
            class="text-sm font-medium transition-colors"
            style="color: var(--t-accent-text, hsl(var(--t-accent-h) var(--t-accent-s) 38%)); text-decoration: none;"
          >
            {@link_text}
          </a>
        <% end %>
      <% end %>
    </div>
    """
  end

  @doc """
  Renders a page header with title and optional product count.

  ## Attributes

  * `title` - Required. The page title.
  * `subtitle` - Optional. Text below the title.
  * `product_count` - Optional. Number to display as "X products".

  ## Examples

      <.collection_header title="All Products" product_count={24} />
  """
  attr :title, :string, required: true
  attr :subtitle, :string, default: nil
  attr :product_count, :integer, default: nil

  def collection_header(assigns) do
    ~H"""
    <div
      class="border-b"
      style="background-color: var(--t-surface-raised); border-color: var(--t-border-default);"
    >
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        <h1
          class="text-3xl md:text-4xl font-bold mb-2"
          style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
        >
          {@title}
        </h1>
        <%= if @subtitle do %>
          <p style="color: var(--t-text-secondary);">{@subtitle}</p>
        <% end %>
        <%= if @product_count do %>
          <p style="color: var(--t-text-secondary);">{@product_count} products</p>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders a filter bar with category pills and sort dropdown.

  ## Attributes

  * `categories` - Required. List of category maps with `name` field.
  * `active_category` - Optional. Currently selected category name. Defaults to "All".
  * `sort_options` - Optional. List of sort option strings.

  ## Examples

      <.filter_bar categories={@categories} />
      <.filter_bar categories={@categories} active_category="Art Prints" />
  """
  attr :categories, :list, required: true
  attr :active_category, :string, default: "All"

  attr :sort_options, :list,
    default: [
      "Sort by: Featured",
      "Price: Low to High",
      "Price: High to Low",
      "Newest",
      "Best Selling"
    ]

  def filter_bar(assigns) do
    ~H"""
    <div class="flex flex-wrap items-center justify-between gap-4 mb-6">
      <!-- Category Pills -->
      <div class="filter-pills-container flex gap-2 overflow-x-auto">
        <button class={"filter-pill#{if @active_category == "All", do: " filter-pill-active", else: ""}"}>
          All
        </button>
        <%= for category <- @categories do %>
          <button class={"filter-pill#{if @active_category == category.name, do: " filter-pill-active", else: ""}"}>
            {category.name}
          </button>
        <% end %>
      </div>
      
    <!-- Sort Dropdown -->
      <.shop_select options={@sort_options} class="px-4 py-2" />
    </div>
    """
  end

  @doc """
  Renders a content body container for long-form content pages (about, etc.).

  ## Attributes

  * `image_src` - Optional. Base path to image (without size/extension), used with responsive_image.
  * `image_alt` - Optional. Alt text for the image. Defaults to "Page image".

  ## Slots

  * `inner_block` - Required. The content to render.

  ## Examples

      <.content_body image_src="/mockups/night-sky-blanket-3" image_alt="A cosy blanket">
        <p>Content here...</p>
      </.content_body>
  """
  attr :image_src, :string, default: nil
  attr :image_alt, :string, default: "Page image"

  slot :inner_block, required: true

  def content_body(assigns) do
    ~H"""
    <div
      class="content-body"
      style="padding: var(--space-xl) var(--space-lg); max-width: 800px; margin: 0 auto;"
    >
      <%= if @image_src do %>
        <div
          class="content-image about-image"
          style="margin-bottom: var(--space-lg); border-radius: var(--t-radius-image); overflow: hidden;"
        >
          <.responsive_image
            src={@image_src}
            source_width={1200}
            alt={@image_alt}
            sizes="(max-width: 800px) 100vw, 800px"
            class="w-full h-[300px] object-cover"
          />
        </div>
      <% end %>

      <div class="content-text" style="line-height: 1.7;">
        {render_slot(@inner_block)}
      </div>
    </div>
    """
  end

  @doc """
  Renders a contact form card.

  ## Attributes

  * `title` - Optional. Form heading. Defaults to "Send a message".
  * `email` - Optional. If provided, displays "Email me: [email]" below the title.

  ## Examples

      <.contact_form />
      <.contact_form title="Get in touch" />
      <.contact_form email="hello@example.com" />
  """
  attr :title, :string, default: "Send a message"
  attr :email, :string, default: nil
  attr :response_time, :string, default: nil

  def contact_form(assigns) do
    ~H"""
    <.shop_card class="p-8">
      <h2
        class="text-xl font-bold mb-2"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary);"
      >
        {@title}
      </h2>
      <%= if @email || @response_time do %>
        <div class="flex flex-col gap-1 mb-6 text-sm" style="color: var(--t-text-secondary);">
          <%= if @email do %>
            <p>
              Email me:
              <a
                href={"mailto:#{@email}"}
                style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
              >
                {@email}
              </a>
            </p>
          <% end %>
          <%= if @response_time do %>
            <p>{@response_time}</p>
          <% end %>
        </div>
      <% else %>
        <div class="mb-4"></div>
      <% end %>

      <form class="flex flex-col gap-4">
        <div>
          <label class="block font-medium mb-2" style="color: var(--t-text-primary);">
            Name
          </label>
          <.shop_input type="text" placeholder="Your name" class="w-full px-4 py-2" />
        </div>

        <div>
          <label class="block font-medium mb-2" style="color: var(--t-text-primary);">
            Email
          </label>
          <.shop_input type="email" placeholder="your@email.com" class="w-full px-4 py-2" />
        </div>

        <div>
          <label class="block font-medium mb-2" style="color: var(--t-text-primary);">
            Subject
          </label>
          <.shop_input type="text" placeholder="How can I help?" class="w-full px-4 py-2" />
        </div>

        <div>
          <label class="block font-medium mb-2" style="color: var(--t-text-primary);">
            Message
          </label>
          <.shop_textarea rows="5" placeholder="Your message..." class="w-full px-4 py-2" />
        </div>

        <.shop_button type="submit" class="w-full px-6 py-3 font-semibold transition-all">
          Send Message
        </.shop_button>
      </form>
    </.shop_card>
    """
  end

  @doc """
  Renders the order tracking card.

  ## Examples

      <.order_tracking_card />
  """
  def order_tracking_card(assigns) do
    ~H"""
    <.shop_card class="p-6">
      <h3 class="font-bold mb-3" style="color: var(--t-text-primary);">Track your order</h3>
      <p class="text-sm mb-3" style="color: var(--t-text-secondary);">
        Enter your email and I'll send you a link to check your order status.
      </p>
      <div class="flex flex-wrap gap-2">
        <.shop_input
          type="email"
          placeholder="your@email.com"
          class="flex-1 min-w-0 px-3 py-2 text-sm"
          style="min-width: 150px;"
        />
        <.shop_button class="px-4 py-2 text-sm font-medium whitespace-nowrap">
          Send
        </.shop_button>
      </div>
    </.shop_card>
    """
  end

  @doc """
  Renders the info card with bullet points (e.g., "Handy to know" section).

  ## Attributes

  * `title` - Required. Card heading.
  * `items` - Required. List of maps with `label` and `value` keys.

  ## Examples

      <.info_card title="Handy to know" items={[
        %{label: "Printing", value: "2-5 business days"},
        %{label: "Delivery", value: "3-7 business days after printing"}
      ]} />
  """
  attr :title, :string, required: true
  attr :items, :list, required: true

  def info_card(assigns) do
    ~H"""
    <.shop_card class="p-6">
      <h3 class="font-bold mb-3" style="color: var(--t-text-primary);">{@title}</h3>
      <ul class="flex flex-col gap-2 text-sm" style="color: var(--t-text-secondary);">
        <%= for item <- @items do %>
          <li class="flex items-start gap-2">
            <span style="color: var(--t-text-tertiary);">•</span>
            <span>
              <strong style="color: var(--t-text-primary);">{item.label}:</strong> {item.value}
            </span>
          </li>
        <% end %>
      </ul>
    </.shop_card>
    """
  end

  @doc """
  Renders the contact info card with email link.

  ## Attributes

  * `title` - Optional. Card heading. Defaults to "Get in touch".
  * `email` - Required. Email address.
  * `response_text` - Optional. Response time text. Defaults to "We typically respond within 24 hours".

  ## Examples

      <.contact_info_card email="hello@example.com" />
  """
  attr :title, :string, default: "Get in touch"
  attr :email, :string, required: true
  attr :response_text, :string, default: "We typically respond within 24 hours"

  def contact_info_card(assigns) do
    ~H"""
    <.shop_card class="p-6">
      <h3 class="font-bold mb-3" style="color: var(--t-text-primary);">{@title}</h3>
      <a
        href={"mailto:#{@email}"}
        class="flex items-center gap-2 mb-2"
        style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); text-decoration: none;"
      >
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            stroke-width="2"
            d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
          />
        </svg>
        {@email}
      </a>
      <p class="text-sm" style="color: var(--t-text-secondary);">
        {@response_text}
      </p>
    </.shop_card>
    """
  end

  @doc """
  Renders a newsletter signup card.

  ## Attributes

  * `title` - Optional. Card heading. Defaults to "Stay in touch".
  * `description` - Optional. Card description.
  * `button_text` - Optional. Button text. Defaults to "Subscribe".
  * `variant` - Optional. Either `:card` (default, with border/background) or `:inline` (no card styling, for embedding in footer).

  ## Examples

      <.newsletter_card />
      <.newsletter_card title="Studio news" description="Get updates on new products." />
      <.newsletter_card variant={:inline} />
  """
  attr :title, :string, default: "Newsletter"

  attr :description, :string,
    default: "Sample newsletter signup. Replace with your own message to encourage subscribers."

  attr :button_text, :string, default: "Subscribe"
  attr :variant, :atom, default: :card

  def newsletter_card(%{variant: :inline} = assigns) do
    ~H"""
    <div>
      <h3
        class="text-xl font-bold mb-2"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);"
      >
        {@title}
      </h3>
      <p class="text-sm mb-4" style="color: var(--t-text-secondary);">
        {@description}
      </p>
      <form class="flex flex-wrap gap-2">
        <.shop_input
          type="email"
          placeholder="your@email.com"
          class="flex-1 min-w-0 px-4 py-2 text-sm"
          style="min-width: 150px;"
        />
        <.shop_button type="submit" class="px-6 py-2 text-sm font-medium whitespace-nowrap">
          {@button_text}
        </.shop_button>
      </form>
    </div>
    """
  end

  def newsletter_card(assigns) do
    ~H"""
    <.shop_card class="p-6">
      <h3 class="font-bold mb-2" style="color: var(--t-text-primary);">{@title}</h3>
      <p class="text-sm mb-4" style="color: var(--t-text-secondary);">
        {@description}
      </p>
      <form class="flex flex-wrap gap-2">
        <.shop_input
          type="email"
          placeholder="your@email.com"
          class="flex-1 min-w-0 px-3 py-2 text-sm"
          style="min-width: 150px;"
        />
        <.shop_button type="submit" class="px-4 py-2 text-sm font-medium whitespace-nowrap">
          {@button_text}
        </.shop_button>
      </form>
    </.shop_card>
    """
  end

  @doc """
  Renders social media links in a single card with a compact grid layout.

  ## Attributes

  * `title` - Optional. Card heading. Defaults to "Follow us".
  * `links` - Optional. List of maps with `platform`, `url`, and `label` keys.
    Supported platforms: :instagram, :pinterest, :facebook, :twitter, :tiktok, :patreon, :youtube

  ## Examples

      <.social_links_card />
      <.social_links_card title="Elsewhere" links={[%{platform: :instagram, url: "https://instagram.com/example", label: "Instagram"}]} />
  """
  attr :title, :string, default: "Find me on"

  attr :links, :list,
    default: [
      %{platform: :instagram, url: "#", label: "Instagram"},
      %{platform: :pinterest, url: "#", label: "Pinterest"}
    ]

  def social_links_card(assigns) do
    ~H"""
    <.shop_card class="p-6">
      <h3 class="font-bold mb-4" style="color: var(--t-text-primary);">{@title}</h3>
      <div class="flex flex-wrap gap-2">
        <%= for link <- @links do %>
          <a
            href={link.url}
            target="_blank"
            rel="noopener noreferrer"
            class="themed-button-outline flex items-center gap-2 px-3 py-2 text-sm transition-all hover:opacity-80"
            style="text-decoration: none;"
          >
            <span style="color: var(--t-text-secondary);">
              <.social_icon platform={link.platform} />
            </span>
            <span>{link.label}</span>
          </a>
        <% end %>
      </div>
    </.shop_card>
    """
  end

  @doc """
  Renders social media icon links.

  ## Attributes

  * `links` - Optional. List of maps with `platform`, `url`, and `label` keys.
    Supported platforms: :instagram, :pinterest

  ## Examples

      <.social_links />
      <.social_links links={[%{platform: :instagram, url: "https://instagram.com/example", label: "Instagram"}]} />
  """
  attr :links, :list,
    default: [
      %{platform: :instagram, url: "https://instagram.com", label: "Instagram"},
      %{platform: :pinterest, url: "https://pinterest.com", label: "Pinterest"}
    ]

  def social_links(assigns) do
    ~H"""
    <div class="flex gap-4 justify-center">
      <%= for link <- @links do %>
        <a
          href={link.url}
          target="_blank"
          rel="noopener noreferrer"
          class="social-link w-9 h-9 flex items-center justify-center transition-all"
          style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
          aria-label={link.label}
        >
          <.social_icon platform={link.platform} />
        </a>
      <% end %>
    </div>
    """
  end

  # Renders a social media icon for the given platform.
  #
  # All icons are from Simple Icons (simpleicons.org), MIT licensed.
  #
  # ## Supported platforms
  #
  # **Commercial/Creative:**
  # :instagram, :pinterest, :tiktok, :facebook, :twitter, :youtube, :patreon, :kofi, :etsy, :gumroad, :bandcamp
  #
  # **Open Web/Federated:**
  # :mastodon, :pixelfed, :bluesky, :peertube, :lemmy, :matrix
  #
  # **Developer/Hacker:**
  # :github, :gitlab, :codeberg, :sourcehut
  #
  # **Communication:**
  # :discord, :telegram, :signal
  #
  # **Other:**
  # :substack, :rss, :website
  attr :platform, :atom, required: true

  # Commercial/Creative platforms
  defp social_icon(%{platform: :instagram} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077" />
    </svg>
    """
  end

  defp social_icon(%{platform: :pinterest} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.162-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.099.12.112.225.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.401.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.354-.629-2.758-1.379l-.749 2.848c-.269 1.045-1.004 2.352-1.498 3.146 1.123.345 2.306.535 3.55.535 6.607 0 11.985-5.365 11.985-11.987C23.97 5.39 18.592.026 11.985.026L12.017 0z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :tiktok} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :facebook} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :twitter} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :youtube} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :patreon} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M15.386.524c-4.764 0-8.64 3.876-8.64 8.64 0 4.75 3.876 8.613 8.64 8.613 4.75 0 8.614-3.864 8.614-8.613C24 4.4 20.136.524 15.386.524M.003 23.537h4.22V.524H.003" />
    </svg>
    """
  end

  defp social_icon(%{platform: :kofi} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M23.881 8.948c-.773-4.085-4.859-4.593-4.859-4.593H.723c-.604 0-.679.798-.679.798s-.082 7.324-.022 11.822c.164 2.424 2.586 2.672 2.586 2.672s8.267-.023 11.966-.049c2.438-.426 2.683-2.566 2.658-3.734 4.352.24 7.422-2.831 6.649-6.916zm-11.062 3.511c-1.246 1.453-4.011 3.976-4.011 3.976s-.121.119-.31.023c-.076-.057-.108-.09-.108-.09-.443-.441-3.368-3.049-4.034-3.954-.709-.965-1.041-2.7-.091-3.71.951-1.01 3.005-1.086 4.363.407 0 0 1.565-1.782 3.468-.963 1.904.82 1.832 3.011.723 4.311zm6.173.478c-.928.116-1.682.028-1.682.028V7.284h1.77s1.971.551 1.971 2.638c0 1.913-.985 2.667-2.059 3.015z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :etsy} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M8.559 1.067c0-.263.128-.435.349-.442 1.074-.034 2.15-.066 3.225-.1.058-.002.22-.012.282.099.014.026.026.061.026.12 0 0 .006 2.548.006 3.85 0 .163.147.28.322.28h4.64c.239 0 .505.209.505.447 0 0-.002.818-.005 1.76-.003.88-.064 1.668-.064 1.668-.025.235-.229.418-.462.418h-4.551c-.244 0-.383.155-.383.398v8.34c0 2.1 1.32 2.581 2.429 2.581.867 0 2.028-.323 2.428-.521.112-.056.251-.06.315.053.024.043.05.089.074.144.305.697.628 1.391.929 2.088.073.163.038.335-.143.454-1.008.665-2.691 1.229-4.577 1.229-2.606 0-5.811-1.032-5.811-6.049V9.692c0-.266-.137-.394-.36-.394H5.62c-.227 0-.372-.14-.372-.37V7.321c0-.175.067-.285.23-.391 2.23-1.441 2.992-4.102 3.08-5.6.006-.099.001-.198.001-.263z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :gumroad} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm4.152 16.053c-.752.822-1.882 1.37-3.449 1.37-3.071 0-5.3-2.037-5.3-5.442 0-3.238 2.062-5.47 5.135-5.47 1.498 0 2.598.465 3.378 1.198l-.978 1.483c-.588-.466-1.206-.74-2.14-.74-1.935 0-3.058 1.418-3.058 3.475 0 2.119 1.205 3.502 3.14 3.502.85 0 1.578-.3 2.004-.63v-1.507h-2.309v-1.835h4.576v4.596z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :bandcamp} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M0 18.75l7.437-13.5H24l-7.438 13.5H0z" />
    </svg>
    """
  end

  # Open Web/Federated platforms
  defp social_icon(%{platform: :mastodon} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :pixelfed} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.372 0 0 5.372 0 12s5.372 12 12 12 12-5.372 12-12S18.628 0 12 0zm5.696 14.943c-.156 1.015-.776 1.885-1.681 2.351-.598.307-1.263.44-1.967.44H8.34c-.63 0-1.235-.123-1.79-.368-.588-.26-1.105-.63-1.536-1.1a4.347 4.347 0 0 1-.953-1.6c-.189-.588-.26-1.207-.199-1.855.093-.996.497-1.855 1.199-2.569.732-.746 1.623-1.19 2.66-1.33.147-.02.298-.033.445-.045h5.682c.88.08 1.651.39 2.312.953.729.62 1.182 1.392 1.354 2.321a4.09 4.09 0 0 1-.018 1.802zM12.186 9.592H9.109c-.517.054-.976.238-1.373.553-.57.452-.907 1.034-.997 1.737-.059.465.003.91.196 1.33.258.564.66.992 1.21 1.275.383.196.795.283 1.235.26h3.108c.518-.054.977-.238 1.374-.553.57-.452.907-1.033.996-1.737.06-.465-.002-.91-.196-1.33a2.345 2.345 0 0 0-1.209-1.274 2.48 2.48 0 0 0-1.267-.261z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :bluesky} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :peertube} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0 1.608 6v12L12 24l10.392-6V6zm-1.476 2.94 8.64 4.98v2.401L9.6 4.86l.924-1.92zm-1.848 3.839 8.64 4.98v2.4l-8.64-4.98V6.78zm0 4.078 8.64 4.98v2.401l-8.64-4.98v-2.401z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :lemmy} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.372 0 0 5.372 0 12s5.372 12 12 12 12-5.372 12-12S18.628 0 12 0zm-.5 4.5a2.5 2.5 0 0 1 1 4.793V15.5a.5.5 0 0 1-1 0V9.293A2.5 2.5 0 0 1 11.5 4.5zm-5 7a2 2 0 1 1 0 4 2 2 0 0 1 0-4zm10 0a2 2 0 1 1 0 4 2 2 0 0 1 0-4z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :matrix} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.481.314.448.208.785.582 1.02 1.108.254-.374.6-.706 1.034-.992.434-.287.95-.43 1.546-.43.453 0 .872.056 1.26.167.388.11.716.286.993.53.276.245.489.559.646.951.152.392.23.863.23 1.417v5.728h-2.349V11.52c0-.286-.01-.559-.032-.812a1.755 1.755 0 0 0-.18-.66 1.106 1.106 0 0 0-.438-.448c-.194-.11-.457-.166-.785-.166-.332 0-.6.064-.803.189a1.38 1.38 0 0 0-.48.499 1.946 1.946 0 0 0-.231.696 5.56 5.56 0 0 0-.06.785v4.768h-2.35v-4.8c0-.254-.004-.503-.018-.752a2.074 2.074 0 0 0-.143-.688 1.052 1.052 0 0 0-.415-.503c-.194-.125-.476-.19-.854-.19-.111 0-.259.024-.439.074-.18.051-.36.143-.53.282-.171.138-.319.33-.439.573-.121.245-.18.56-.18.946v5.058H5.46V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z" />
    </svg>
    """
  end

  # Developer/Hacker platforms
  defp social_icon(%{platform: :github} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
    </svg>
    """
  end

  defp social_icon(%{platform: :gitlab} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="m23.6 9.593-.033-.086L20.3.98a.851.851 0 0 0-.336-.405.874.874 0 0 0-.994.066.873.873 0 0 0-.29.441L16.47 7.674H7.53L5.32 1.082a.857.857 0 0 0-.29-.441.874.874 0 0 0-.994-.067.852.852 0 0 0-.336.406L.433 9.507.4 9.593a6.062 6.062 0 0 0 2.012 7.01l.01.008.028.02 4.984 3.73 2.466 1.865 1.502 1.135a1.009 1.009 0 0 0 1.22 0l1.502-1.135 2.466-1.866 5.012-3.75.013-.01a6.063 6.063 0 0 0 2.005-7.007z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :codeberg} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M11.955.49A12 12 0 0 0 0 12.49a12 12 0 0 0 1.832 6.373L11.838 5.928a.187.187 0 0 1 .324 0l10.006 12.935A12 12 0 0 0 24 12.49a12 12 0 0 0-12-12 12 12 0 0 0-.045 0zm.375 6.467 4.416 16.553a12 12 0 0 0 5.137-4.213z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :sourcehut} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.371 0 0 5.371 0 12s5.371 12 12 12 12-5.371 12-12S18.629 0 12 0zm0 21.677c-5.335 0-9.677-4.342-9.677-9.677S6.665 2.323 12 2.323 21.677 6.665 21.677 12 17.335 21.677 12 21.677z" />
    </svg>
    """
  end

  # Communication platforms
  defp social_icon(%{platform: :discord} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :telegram} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :signal} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M9.237 1.805a9.72 9.72 0 0 1 5.527 0l.558-1.343A11.14 11.14 0 0 0 8.678.462l.559 1.343Zm-3.91 1.95A9.678 9.678 0 0 0 1.805 9.24l1.448.295a8.261 8.261 0 0 1 3.003-4.672l-.93-1.108Zm13.346 0-.929 1.108a8.261 8.261 0 0 1 3.003 4.672l1.449-.295a9.678 9.678 0 0 0-3.523-5.485ZM1.463 10.723A9.81 9.81 0 0 0 1.5 12c0 .893.12 1.758.344 2.58l1.41-.393A8.315 8.315 0 0 1 3 12c0-.373.024-.742.073-1.104l-1.61-.173Zm20.59 1.104.073 1.104c0 .373-.024.742-.073 1.104l1.61.173a9.81 9.81 0 0 0-.037-2.381h-1.573Zm-19.699 4.43a9.723 9.723 0 0 0 2.973 4.047l.929-1.108a8.222 8.222 0 0 1-2.513-3.42l-1.39.48Zm17.291 0-1.389-.48a8.221 8.221 0 0 1-2.513 3.42l.929 1.108a9.723 9.723 0 0 0 2.973-4.048Zm-13.17 5.052a9.72 9.72 0 0 0 5.526 0l-.559-1.343a8.262 8.262 0 0 1-4.41 0l-.558 1.343ZM12 4.2a7.8 7.8 0 1 0 0 15.6 7.8 7.8 0 0 0 0-15.6ZM2.7 12a9.3 9.3 0 1 1 18.6 0 9.3 9.3 0 0 1-18.6 0Z" />
    </svg>
    """
  end

  # Other platforms
  defp social_icon(%{platform: :substack} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M22.539 8.242H1.46V5.406h21.08v2.836zM1.46 10.812V24L12 18.11 22.54 24V10.812H1.46zM22.54 0H1.46v2.836h21.08V0z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :rss} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415a3.3 3.3 0 0 1 3.293 3.295A3.303 3.303 0 0 1 3.283 24C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z" />
    </svg>
    """
  end

  defp social_icon(%{platform: :website} = assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm-.5 2.047A10.003 10.003 0 0 1 21.95 11.5h-4.4a15.93 15.93 0 0 0-1.55-6.33 10.05 10.05 0 0 1 1.45-.93A9.933 9.933 0 0 0 11.5 2.047zm-.5 0v4.4c-1.55-.09-3.03-.4-4.4-.93a15.93 15.93 0 0 1 4.4-3.47zm0 5.4v4.06H6.44c.08-1.47.33-2.87.73-4.17a16.93 16.93 0 0 0 4.33.91v-.8zm1 0v.8c1.5-.08 2.96-.39 4.33-.91.4 1.3.65 2.7.73 4.17H12.5V7.447zM11 12.5H6.44c.08 1.47.33 2.87.73 4.17a16.93 16.93 0 0 0 4.33-.91V12.5h-.5zm1 0v3.26c1.5.08 2.96.39 4.33.91.4-1.3.65-2.7.73-4.17H12.5H12zm-1 4.25c-1.55.09-3.03.4-4.4.93a15.93 15.93 0 0 1 4.4 3.47v-4.4zm1 0v4.4a15.93 15.93 0 0 1 4.4-3.47c-1.37-.53-2.85-.84-4.4-.93z" />
    </svg>
    """
  end

  # Fallback for unknown platforms
  defp social_icon(assigns) do
    ~H"""
    <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm0 22c-5.523 0-10-4.477-10-10S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10z" />
    </svg>
    """
  end

  @doc """
  Renders a cart item row.

  ## Attributes

  * `item` - Required. Map with `product` (containing `image_url`, `name`, `price`), `variant`, and `quantity`.
  * `currency` - Optional. Currency symbol. Defaults to "£".

  ## Examples

      <.cart_item item={item} />
  """
  attr :item, :map, required: true

  def cart_item(assigns) do
    ~H"""
    <.shop_card class="flex gap-4 p-4">
      <div
        class="w-24 h-24 flex-shrink-0 bg-gray-200 overflow-hidden"
        style="border-radius: var(--t-radius-image);"
      >
        <img
          src={@item.product.image_url}
          alt={@item.product.name}
          width="96"
          height="96"
          loading="lazy"
          class="w-full h-full object-cover"
        />
      </div>

      <div class="flex-1">
        <h3
          class="font-semibold mb-1"
          style="font-family: var(--t-font-heading); color: var(--t-text-primary);"
        >
          {@item.product.name}
        </h3>
        <p class="text-sm mb-2" style="color: var(--t-text-secondary);">
          {@item.variant}
        </p>

        <div class="flex items-center gap-4">
          <div
            class="flex items-center"
            style="border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input);"
          >
            <button class="px-3 py-1" style="color: var(--t-text-primary);">−</button>
            <span
              class="px-3 py-1 border-x"
              style="border-color: var(--t-border-default); color: var(--t-text-primary);"
            >
              {@item.quantity}
            </span>
            <button class="px-3 py-1" style="color: var(--t-text-primary);">+</button>
          </div>

          <button class="text-sm" style="color: var(--t-text-tertiary);">
            Remove
          </button>
        </div>
      </div>

      <div class="text-right">
        <p class="font-bold text-lg" style="color: var(--t-text-primary);">
          {SimpleshopTheme.Cart.format_price(@item.product.price * @item.quantity)}
        </p>
      </div>
    </.shop_card>
    """
  end

  @doc """
  Renders the order summary card.

  ## Attributes

  * `subtotal` - Required. Subtotal amount (in pence/cents).
  * `delivery` - Optional. Delivery cost. Defaults to 800 (£8.00).
  * `vat` - Optional. VAT amount. Defaults to 720 (£7.20).
  * `currency` - Optional. Currency symbol. Defaults to "£".
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.order_summary subtotal={3600} />
  """
  attr :subtotal, :integer, required: true
  attr :mode, :atom, default: :live

  def order_summary(assigns) do
    ~H"""
    <.shop_card class="p-6 sticky top-4">
      <h2
        class="text-xl font-bold mb-6"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary);"
      >
        Order summary
      </h2>

      <div class="flex flex-col gap-3 mb-6">
        <div class="flex justify-between">
          <span style="color: var(--t-text-secondary);">Subtotal</span>
          <span style="color: var(--t-text-primary);">
            {SimpleshopTheme.Cart.format_price(@subtotal)}
          </span>
        </div>
        <div class="flex justify-between">
          <span style="color: var(--t-text-secondary);">Delivery</span>
          <span class="text-sm" style="color: var(--t-text-secondary);">
            Calculated at checkout
          </span>
        </div>
        <div class="border-t pt-3" style="border-color: var(--t-border-default);">
          <div class="flex justify-between text-lg">
            <span class="font-semibold" style="color: var(--t-text-primary);">Subtotal</span>
            <span class="font-bold" style="color: var(--t-text-primary);">
              {SimpleshopTheme.Cart.format_price(@subtotal)}
            </span>
          </div>
        </div>
      </div>

      <%= if @mode == :preview do %>
        <.shop_button class="w-full px-6 py-3 font-semibold transition-all mb-3">
          Checkout
        </.shop_button>
        <.shop_button_outline
          phx-click="change_preview_page"
          phx-value-page="collection"
          class="w-full px-6 py-3 font-semibold transition-all"
        >
          Continue shopping
        </.shop_button_outline>
      <% else %>
        <form action="/checkout" method="post" class="mb-3">
          <input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
          <.shop_button type="submit" class="w-full px-6 py-3 font-semibold transition-all">
            Checkout
          </.shop_button>
        </form>
        <.shop_link_outline
          href="/collections/all"
          class="block w-full px-6 py-3 font-semibold transition-all text-center"
        >
          Continue shopping
        </.shop_link_outline>
      <% end %>
    </.shop_card>
    """
  end

  @doc """
  Renders a breadcrumb navigation.

  ## Attributes

  * `items` - Required. List of breadcrumb items. Each item is a map with:
    - `label` - Required. Display text
    - `page` - Optional. Page name for preview mode navigation
    - `href` - Optional. URL for live mode navigation
    - `current` - Optional. Boolean, if true this is the current page (not a link)
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.breadcrumb items={[
        %{label: "Home", page: "home", href: "/"},
        %{label: "Art Prints", page: "collection", href: "/collections/art-prints"},
        %{label: "Mountain Sunrise", current: true}
      ]} mode={:preview} />
  """
  attr :items, :list, required: true
  attr :mode, :atom, default: :live

  def breadcrumb(assigns) do
    ~H"""
    <nav class="mb-8 flex items-center gap-2 text-sm" style="color: var(--t-text-secondary);">
      <%= for {item, index} <- Enum.with_index(@items) do %>
        <%= if index > 0 do %>
          <span>/</span>
        <% end %>
        <%= if item[:current] do %>
          <span style="color: var(--t-text-primary);">{item.label}</span>
        <% else %>
          <%= if @mode == :preview do %>
            <a
              href="#"
              phx-click="change_preview_page"
              phx-value-page={item.page}
              class="hover:underline"
            >
              {item.label}
            </a>
          <% else %>
            <a href={item.href || "/"} class="hover:underline">{item.label}</a>
          <% end %>
        <% end %>
      <% end %>
    </nav>
    """
  end

  @doc """
  Renders a related products section with title and product grid.

  ## Attributes

  * `title` - Optional. Section heading. Defaults to "You might also like".
  * `products` - Required. List of products to display.
  * `theme_settings` - Required. The theme settings map.
  * `limit` - Optional. Maximum products to show. Defaults to 4.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.related_products_section
        products={@related_products}
        theme_settings={@theme_settings}
        mode={:preview}
      />
  """
  attr :title, :string, default: "You might also like"
  attr :products, :list, required: true
  attr :theme_settings, :map, required: true
  attr :limit, :integer, default: 4
  attr :mode, :atom, default: :live

  def related_products_section(assigns) do
    ~H"""
    <div class="py-12" style="border-top: 1px solid var(--t-border-default);">
      <h2
        class="text-2xl font-bold mb-6"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);"
      >
        {@title}
      </h2>

      <.product_grid columns={:fixed_4} gap="gap-6">
        <%= for product <- Enum.take(@products, @limit) do %>
          <.product_card
            product={product}
            theme_settings={@theme_settings}
            mode={@mode}
            variant={:compact}
          />
        <% end %>
      </.product_grid>
    </div>
    """
  end

  @doc """
  Renders a star rating display.

  ## Attributes

  * `rating` - Required. Number of filled stars (1-5).
  * `max` - Optional. Maximum stars to display. Defaults to 5.
  * `size` - Optional. Size variant: `:sm` (w-4), `:md` (w-5). Defaults to `:sm`.
  * `color` - Optional. Star color. Defaults to "#f59e0b" (amber).

  ## Examples

      <.star_rating rating={5} />
      <.star_rating rating={4} size={:md} />
  """
  attr :rating, :integer, required: true
  attr :max, :integer, default: 5
  attr :size, :atom, default: :sm
  attr :color, :string, default: "#f59e0b"

  def star_rating(assigns) do
    size_class = if assigns.size == :md, do: "w-5 h-5", else: "w-4 h-4"
    assigns = assign(assigns, :size_class, size_class)

    ~H"""
    <div class="flex gap-0.5">
      <%= for i <- 1..@max do %>
        <svg
          class={@size_class}
          viewBox="0 0 20 20"
          style={"color: #{if i <= @rating, do: @color, else: "var(--t-border-default)"};"}
        >
          <path
            d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z"
            fill="currentColor"
          />
        </svg>
      <% end %>
    </div>
    """
  end

  @doc """
  Renders trust badges (e.g., Free Delivery, Easy Returns).

  ## Attributes

  * `items` - Optional. List of badge items. Each item is a map with:
    - `icon` - Icon type: `:check` or `:shield`
    - `title` - Badge title
    - `description` - Badge description
    Defaults to Free Delivery and Easy Returns badges.

  ## Examples

      <.trust_badges />
      <.trust_badges items={[%{icon: :check, title: "Custom", description: "Badge text"}]} />
  """
  attr :items, :list,
    default: [
      %{icon: :check, title: "Made to Order", description: "Printed just for you"},
      %{icon: :shield, title: "Quality Materials", description: "Premium inks and substrates"}
    ]

  def trust_badges(assigns) do
    ~H"""
    <div
      class="flex flex-col gap-3 p-4"
      style="background-color: var(--t-surface-sunken); border-radius: var(--t-radius-card);"
    >
      <%= for item <- @items do %>
        <div class="flex items-start gap-3">
          <.trust_badge_icon icon={item.icon} />
          <div>
            <p class="font-semibold" style="color: var(--t-text-primary);">{item.title}</p>
            <p class="text-sm" style="color: var(--t-text-secondary);">{item.description}</p>
          </div>
        </div>
      <% end %>
    </div>
    """
  end

  attr :icon, :atom, required: true

  defp trust_badge_icon(%{icon: :check} = assigns) do
    ~H"""
    <svg
      class="w-5 h-5 mt-0.5"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
    >
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
    </svg>
    """
  end

  defp trust_badge_icon(%{icon: :shield} = assigns) do
    ~H"""
    <svg
      class="w-5 h-5 mt-0.5"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
    >
      <path
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
      />
    </svg>
    """
  end

  defp trust_badge_icon(assigns) do
    ~H"""
    <svg
      class="w-5 h-5 mt-0.5"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
    >
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
    </svg>
    """
  end

  @doc """
  Renders a customer reviews section with collapsible header and review cards.

  ## Attributes

  * `reviews` - Required. List of review maps with:
    - `rating` - Star rating (1-5)
    - `title` - Review title
    - `body` - Review text
    - `author` - Reviewer name
    - `date` - Relative date string (e.g., "2 weeks ago")
    - `verified` - Boolean, if true shows "Verified purchase" badge
  * `average_rating` - Optional. Average rating to show in header. Defaults to 5.
  * `total_count` - Optional. Total number of reviews. Defaults to length of reviews list.
  * `open` - Optional. Whether section is expanded by default. Defaults to true.

  ## Examples

      <.reviews_section reviews={@product.reviews} average_rating={4.8} total_count={24} />
  """
  attr :reviews, :list, required: true
  attr :average_rating, :integer, default: 5
  attr :total_count, :integer, default: nil
  attr :open, :boolean, default: true

  def reviews_section(assigns) do
    assigns =
      assign_new(assigns, :display_count, fn ->
        assigns.total_count || length(assigns.reviews)
      end)

    ~H"""
    <details
      open={@open}
      class="pdp-reviews group"
      style="border-top: 1px solid var(--t-border-default);"
    >
      <summary
        class="flex justify-between items-center py-6 cursor-pointer list-none [&::-webkit-details-marker]:hidden"
        style="color: var(--t-text-primary);"
      >
        <div class="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
          <h2
            class="text-2xl font-bold"
            style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);"
          >
            Customer reviews
          </h2>
          <div class="flex items-center gap-2">
            <.star_rating rating={@average_rating} />
            <span class="text-sm" style="color: var(--t-text-secondary);">({@display_count})</span>
          </div>
        </div>
        <svg
          class="w-5 h-5 transition-transform duration-200 group-open:rotate-180 flex-shrink-0"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
        </svg>
      </summary>

      <div class="pb-8">
        <div class="flex flex-col gap-6">
          <%= for review <- @reviews do %>
            <.review_card review={review} />
          <% end %>
        </div>

        <.shop_button_outline class="mt-6 px-6 py-2 text-sm font-medium transition-all mx-auto block">
          Load more reviews
        </.shop_button_outline>
      </div>
    </details>
    """
  end

  @doc """
  Renders a single review card.

  ## Attributes

  * `review` - Required. Map with `rating`, `title`, `body`, `author`, `date`, `verified`.

  ## Examples

      <.review_card review={%{rating: 5, title: "Great!", body: "...", author: "Jane", date: "1 week ago", verified: true}} />
  """
  attr :review, :map, required: true

  def review_card(assigns) do
    ~H"""
    <article class="pb-6" style="border-bottom: 1px solid var(--t-border-subtle);">
      <div class="flex items-center justify-between mb-2">
        <.star_rating rating={@review.rating} />
        <span class="text-xs" style="color: var(--t-text-tertiary);">{@review.date}</span>
      </div>
      <h3 class="font-semibold mb-1" style="color: var(--t-text-primary);">{@review.title}</h3>
      <p class="text-sm mb-3" style="color: var(--t-text-secondary); line-height: 1.6;">
        {@review.body}
      </p>
      <div class="flex items-center gap-2">
        <span class="text-sm font-medium" style="color: var(--t-text-primary);">
          {@review.author}
        </span>
        <%= if @review.verified do %>
          <span
            class="text-xs px-2 py-0.5 rounded"
            style="background-color: var(--t-surface-sunken); color: var(--t-text-tertiary);"
          >
            Verified purchase
          </span>
        <% end %>
      </div>
    </article>
    """
  end

  @doc """
  Renders a product image gallery with thumbnails and lightbox.

  ## Attributes

  * `images` - Required. List of image URLs.
  * `product_name` - Required. Product name for alt text.
  * `id_prefix` - Optional. Prefix for element IDs. Defaults to "pdp".

  ## Examples

      <.product_gallery images={@product_images} product_name={@product.name} />
  """
  attr :images, :list, required: true
  attr :product_name, :string, required: true
  attr :id_prefix, :string, default: "pdp"

  def product_gallery(assigns) do
    ~H"""
    <div>
      <div
        class="pdp-main-image-container aspect-square bg-gray-200 mb-4 overflow-hidden relative"
        style="border-radius: var(--t-radius-image);"
        phx-click={Phoenix.LiveView.JS.exec("data-show", to: "##{@id_prefix}-lightbox")}
      >
        <img
          id={"#{@id_prefix}-main-image"}
          src={List.first(@images)}
          alt={@product_name}
          width="600"
          height="600"
          class="w-full h-full object-cover"
        />
        <div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity bg-black/10">
          <div class="w-12 h-12 bg-white/90 rounded-full flex items-center justify-center shadow-lg">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v3m0 0v3m0-3h3m-3 0H7"
              />
            </svg>
          </div>
        </div>
      </div>
      <div class="grid grid-cols-4 gap-4">
        <%= for {img_url, idx} <- Enum.with_index(@images) do %>
          <button
            type="button"
            class={"aspect-square bg-gray-200 cursor-pointer overflow-hidden pdp-thumbnail#{if idx == 0, do: " pdp-thumbnail-active", else: ""}"}
            style="border-radius: var(--t-radius-image);"
            data-index={idx}
            phx-click={
              Phoenix.LiveView.JS.set_attribute({"src", img_url}, to: "##{@id_prefix}-main-image")
              |> Phoenix.LiveView.JS.set_attribute({"data-current-index", to_string(idx)},
                to: "##{@id_prefix}-lightbox"
              )
              |> Phoenix.LiveView.JS.remove_class("pdp-thumbnail-active", to: ".pdp-thumbnail")
              |> Phoenix.LiveView.JS.add_class("pdp-thumbnail-active")
            }
          >
            <img
              src={img_url}
              alt={@product_name}
              width="150"
              height="150"
              loading="lazy"
              class="w-full h-full object-cover"
            />
          </button>
        <% end %>
      </div>

      <.product_lightbox images={@images} product_name={@product_name} id_prefix={@id_prefix} />
    </div>
    """
  end

  # Private: Renders a product image lightbox dialog used by `product_gallery`.
  attr :images, :list, required: true
  attr :product_name, :string, required: true
  attr :id_prefix, :string, required: true

  defp product_lightbox(assigns) do
    ~H"""
    <dialog
      class="lightbox"
      id={"#{@id_prefix}-lightbox"}
      aria-label="Product image gallery"
      data-current-index="0"
      data-images={Jason.encode!(@images)}
      data-show={Phoenix.LiveView.JS.exec("phx-show-lightbox", to: "##{@id_prefix}-lightbox")}
      phx-show-lightbox={
        Phoenix.LiveView.JS.dispatch("pdp:open-lightbox", to: "##{@id_prefix}-lightbox")
      }
      phx-hook="Lightbox"
    >
      <div class="lightbox-content">
        <button
          type="button"
          class="lightbox-close"
          aria-label="Close gallery"
          phx-click={
            Phoenix.LiveView.JS.dispatch("pdp:close-lightbox", to: "##{@id_prefix}-lightbox")
          }
        >
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="18" y1="6" x2="6" y2="18"></line>
            <line x1="6" y1="6" x2="18" y2="18"></line>
          </svg>
        </button>
        <button
          type="button"
          class="lightbox-nav lightbox-prev"
          aria-label="Previous image"
          phx-click={Phoenix.LiveView.JS.dispatch("pdp:prev-image", to: "##{@id_prefix}-lightbox")}
        >
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <polyline points="15 18 9 12 15 6"></polyline>
          </svg>
        </button>
        <figure class="lightbox-figure">
          <div class="lightbox-image-container">
            <img
              class="lightbox-image"
              id="lightbox-image"
              src={List.first(@images)}
              alt={@product_name}
              width="1200"
              height="1200"
            />
          </div>
          <figcaption class="lightbox-caption">{@product_name}</figcaption>
        </figure>
        <button
          type="button"
          class="lightbox-nav lightbox-next"
          aria-label="Next image"
          phx-click={Phoenix.LiveView.JS.dispatch("pdp:next-image", to: "##{@id_prefix}-lightbox")}
        >
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <polyline points="9 18 15 12 9 6"></polyline>
          </svg>
        </button>
        <div class="lightbox-counter" id="lightbox-counter">1 / {length(@images)}</div>
      </div>
    </dialog>
    """
  end

  @doc """
  Renders product title and price information.

  ## Attributes

  * `product` - Required. Product map with `name`, `price`, `on_sale`, `compare_at_price`.
  * `currency` - Optional. Currency symbol. Defaults to "£".

  ## Examples

      <.product_info product={@product} />
  """
  attr :product, :map, required: true

  def product_info(assigns) do
    ~H"""
    <div>
      <h1
        class="text-3xl md:text-4xl font-bold mb-4"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
      >
        {@product.name}
      </h1>

      <div class="flex items-center gap-4 mb-6">
        <%= if @product.on_sale do %>
          <span
            class="text-3xl font-bold"
            style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
          >
            {SimpleshopTheme.Cart.format_price(@product.price)}
          </span>
          <span class="text-xl line-through" style="color: var(--t-text-tertiary);">
            {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
          </span>
          <span
            class="px-2 py-1 text-sm font-bold text-white rounded"
            style="background-color: var(--t-sale-color);"
          >
            SAVE {round(
              (@product.compare_at_price - @product.price) / @product.compare_at_price * 100
            )}%
          </span>
        <% else %>
          <span class="text-3xl font-bold" style="color: var(--t-text-primary);">
            {SimpleshopTheme.Cart.format_price(@product.price)}
          </span>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders a variant selector for a single option type.

  Shows color swatches for color-type options, text buttons for others.
  Disables unavailable options and fires `select_option` event on click.

  ## Attributes

  * `option_type` - Required. Map with :name, :type, :values keys
  * `selected` - Required. Currently selected value (string)
  * `available` - Required. List of available values for this option
  * `mode` - Optional. :shop or :preview (default: :shop)

  ## Examples

      <.variant_selector
        option_type={%{name: "Size", type: :size, values: [%{title: "S"}, ...]}}
        selected="M"
        available={["S", "M", "L"]}
      />
  """
  attr :option_type, :map, required: true
  attr :selected, :string, required: true
  attr :available, :list, required: true
  attr :mode, :atom, default: :shop

  def variant_selector(assigns) do
    ~H"""
    <div class="mb-6">
      <label class="block font-semibold mb-2" style="color: var(--t-text-primary);">
        {@option_type.name}
      </label>
      <div class="flex flex-wrap gap-2">
        <%= if @option_type.type == :color do %>
          <.color_swatch
            :for={value <- @option_type.values}
            title={value.title}
            hex={value[:hex] || "#888888"}
            selected={value.title == @selected}
            disabled={value.title not in @available}
            option_name={@option_type.name}
            mode={@mode}
          />
        <% else %>
          <.size_button
            :for={value <- @option_type.values}
            title={value.title}
            selected={value.title == @selected}
            disabled={value.title not in @available}
            option_name={@option_type.name}
            mode={@mode}
          />
        <% end %>
      </div>
    </div>
    """
  end

  attr :title, :string, required: true
  attr :hex, :string, required: true
  attr :selected, :boolean, required: true
  attr :disabled, :boolean, required: true
  attr :option_name, :string, required: true
  attr :mode, :atom, default: :shop

  defp color_swatch(assigns) do
    ~H"""
    <button
      type="button"
      phx-click={if @mode == :shop and not @disabled, do: "select_option"}
      phx-value-option={@option_name}
      phx-value-value={@title}
      class={[
        "w-10 h-10 rounded-full border-2 transition-all relative",
        @selected && "ring-2 ring-offset-2",
        @disabled && "opacity-40 cursor-not-allowed"
      ]}
      style={"background-color: #{@hex}; border-color: #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))", else: "var(--t-border-default)"}; --tw-ring-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"}
      title={@title}
      disabled={@disabled}
      aria-label={"Select #{@title}"}
      aria-pressed={@selected}
    >
      <span :if={@disabled} class="absolute inset-0 flex items-center justify-center">
        <span class="w-full h-0.5 bg-gray-400 rotate-45 absolute"></span>
      </span>
    </button>
    """
  end

  attr :title, :string, required: true
  attr :selected, :boolean, required: true
  attr :disabled, :boolean, required: true
  attr :option_name, :string, required: true
  attr :mode, :atom, default: :shop

  defp size_button(assigns) do
    ~H"""
    <button
      type="button"
      phx-click={if @mode == :shop and not @disabled, do: "select_option"}
      phx-value-option={@option_name}
      phx-value-value={@title}
      class={[
        "px-4 py-2 font-medium transition-all",
        @disabled && "opacity-40 cursor-not-allowed line-through"
      ]}
      style={"border: 2px solid #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))", else: "var(--t-border-default)"}; border-radius: var(--t-radius-button); color: var(--t-text-primary); background: #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1)", else: "transparent"};"}
      disabled={@disabled}
      aria-pressed={@selected}
    >
      {@title}
    </button>
    """
  end

  @doc """
  Renders a quantity selector with increment/decrement buttons.

  ## Attributes

  * `quantity` - Optional. Current quantity value. Defaults to 1.
  * `in_stock` - Optional. Whether the product is in stock. Defaults to true.
  * `min` - Optional. Minimum quantity. Defaults to 1.
  * `max` - Optional. Maximum quantity. Defaults to 99.

  ## Examples

      <.quantity_selector />
      <.quantity_selector quantity={2} in_stock={false} />
  """
  attr :quantity, :integer, default: 1
  attr :in_stock, :boolean, default: true
  attr :min, :integer, default: 1
  attr :max, :integer, default: 99

  def quantity_selector(assigns) do
    ~H"""
    <div class="mb-8">
      <label class="block font-semibold mb-2" style="color: var(--t-text-primary);">
        Quantity
      </label>
      <div class="flex items-center gap-4">
        <div
          class="flex items-center"
          style="border: 2px solid var(--t-border-default); border-radius: var(--t-radius-input);"
        >
          <button type="button" class="px-4 py-2" style="color: var(--t-text-primary);">−</button>
          <span
            class="px-4 py-2 border-x-2"
            style="border-color: var(--t-border-default); color: var(--t-text-primary);"
          >
            {@quantity}
          </span>
          <button type="button" class="px-4 py-2" style="color: var(--t-text-primary);">+</button>
        </div>
        <%= if @in_stock do %>
          <span class="text-sm" style="color: var(--t-text-tertiary);">In stock</span>
        <% else %>
          <span class="text-sm font-semibold" style="color: var(--t-sale-color);">Out of stock</span>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders the add to cart button.

  ## Attributes

  * `text` - Optional. Button text. Defaults to "Add to basket".
  * `disabled` - Optional. Whether button is disabled. Defaults to false.
  * `sticky` - Optional. Whether to use sticky positioning on mobile. Defaults to true.
  * `mode` - Either `:live` (sends add_to_cart event) or `:preview` (opens drawer only).

  ## Examples

      <.add_to_cart_button />
      <.add_to_cart_button text="Add to bag" disabled={true} />
  """
  attr :text, :string, default: "Add to basket"
  attr :disabled, :boolean, default: false
  attr :sticky, :boolean, default: true
  attr :mode, :atom, default: :live

  def add_to_cart_button(assigns) do
    ~H"""
    <div
      class={[
        "mb-4",
        @sticky &&
          "sticky bottom-0 z-10 py-3 md:relative md:py-0 -mx-4 px-4 md:mx-0 md:px-0 border-t md:border-0"
      ]}
      style="background-color: var(--t-surface-base); border-color: var(--t-border-subtle);"
    >
      <button
        type="button"
        phx-click={if @mode == :preview, do: open_cart_drawer_js(), else: "add_to_cart"}
        disabled={@disabled}
        class="w-full px-6 py-4 text-lg font-semibold transition-all"
        style={"background-color: #{if @disabled, do: "var(--t-border-default)", else: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))"}; color: var(--t-text-inverse); border-radius: var(--t-radius-button); cursor: #{if @disabled, do: "not-allowed", else: "pointer"}; border: none;"}
      >
        {@text}
      </button>
    </div>
    """
  end

  @doc """
  Renders a collapsible details/accordion item.

  ## Attributes

  * `title` - Required. Section heading text.
  * `open` - Optional. Whether section is expanded by default. Defaults to false.

  ## Slots

  * `inner_block` - Required. Content to show when expanded.

  ## Examples

      <.accordion_item title="Description" open={true}>
        <p>Product description here...</p>
      </.accordion_item>
  """
  attr :title, :string, required: true
  attr :open, :boolean, default: false

  slot :inner_block, required: true

  def accordion_item(assigns) do
    ~H"""
    <details open={@open} class="group">
      <summary
        class="flex justify-between items-center py-4 cursor-pointer list-none [&::-webkit-details-marker]:hidden"
        style="color: var(--t-text-primary);"
      >
        <span class="font-semibold">{@title}</span>
        <svg
          class="w-5 h-5 transition-transform duration-200 group-open:rotate-180"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
        </svg>
      </summary>
      <div class="pb-4" style="color: var(--t-text-secondary);">
        {render_slot(@inner_block)}
      </div>
    </details>
    """
  end

  @doc """
  Renders a product details accordion with Description, Size Guide, and Shipping sections.

  ## Attributes

  * `product` - Required. Product map with `description`.
  * `show_size_guide` - Optional. Whether to show size guide. Defaults to true.
  * `size_guide` - Optional. Custom size guide data. Uses default if not provided.

  ## Examples

      <.product_details product={@product} />
      <.product_details product={@product} show_size_guide={false} />
  """
  attr :product, :map, required: true
  attr :show_size_guide, :boolean, default: true
  attr :size_guide, :list, default: nil

  def product_details(assigns) do
    assigns =
      assign_new(assigns, :sizes, fn ->
        assigns.size_guide ||
          [
            %{size: "S", chest: "86-91", length: "71"},
            %{size: "M", chest: "91-96", length: "73"},
            %{size: "L", chest: "96-101", length: "75"},
            %{size: "XL", chest: "101-106", length: "77"}
          ]
      end)

    ~H"""
    <div
      class="mt-8 divide-y"
      style="border-top: 1px solid var(--t-border-subtle); border-bottom: 1px solid var(--t-border-subtle); border-color: var(--t-border-subtle);"
    >
      <.accordion_item title="Description" open={true}>
        <p class="leading-relaxed">
          {@product.description}. Crafted with attention to detail and quality materials, this product is designed to last. Perfect for everyday use or special occasions.
        </p>
      </.accordion_item>

      <%= if @show_size_guide do %>
        <.accordion_item title="Size Guide">
          <table class="w-full text-sm">
            <thead>
              <tr style="border-bottom: 1px solid var(--t-border-subtle);">
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Size
                </th>
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Chest (cm)
                </th>
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Length (cm)
                </th>
              </tr>
            </thead>
            <tbody>
              <%= for {size_row, idx} <- Enum.with_index(@sizes) do %>
                <tr style={
                  if idx < length(@sizes) - 1,
                    do: "border-bottom: 1px solid var(--t-border-subtle);",
                    else: ""
                }>
                  <td class="py-2">{size_row.size}</td>
                  <td class="py-2">{size_row.chest}</td>
                  <td class="py-2">{size_row.length}</td>
                </tr>
              <% end %>
            </tbody>
          </table>
        </.accordion_item>
      <% end %>

      <.accordion_item title="Shipping & Returns">
        <div class="flex flex-col gap-3">
          <div>
            <p class="font-semibold mb-1" style="color: var(--t-text-primary);">Delivery</p>
            <p class="text-sm">
              Free UK delivery on orders over £40. Standard delivery 3-5 working days. Express delivery available at checkout.
            </p>
          </div>
          <div>
            <p class="font-semibold mb-1" style="color: var(--t-text-primary);">Returns</p>
            <p class="text-sm">
              We offer a 30-day return policy. Items must be unused and in original packaging. Please contact us to arrange a return.
            </p>
          </div>
        </div>
      </.accordion_item>
    </div>
    """
  end

  @doc """
  Renders a page title heading.

  ## Attributes

  * `text` - Required. The title text.
  * `class` - Optional. Additional CSS classes.

  ## Examples

      <.page_title text="Your basket" />
      <.page_title text="Order History" class="mb-4" />
  """
  attr :text, :string, required: true
  attr :class, :string, default: "mb-8"

  def page_title(assigns) do
    ~H"""
    <h1
      class={"text-3xl md:text-4xl font-bold #{@class}"}
      style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
    >
      {@text}
    </h1>
    """
  end

  @doc """
  Renders a cart items list with order summary layout.

  ## Attributes

  * `items` - Required. List of cart items.
  * `subtotal` - Required. Subtotal in pence/cents.
  * `currency` - Optional. Currency symbol. Defaults to "£".
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.cart_layout items={@cart_items} subtotal={3600} mode={:preview} />
  """
  attr :items, :list, required: true
  attr :subtotal, :integer, required: true
  attr :mode, :atom, default: :live

  def cart_layout(assigns) do
    ~H"""
    <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
      <div class="lg:col-span-2">
        <div class="flex flex-col gap-4">
          <%= for item <- @items do %>
            <.cart_item item={item} />
          <% end %>
        </div>
      </div>

      <div>
        <.order_summary subtotal={@subtotal} mode={@mode} />
      </div>
    </div>
    """
  end

  @doc """
  Renders rich text content with themed typography.

  This component renders structured content blocks (paragraphs, headings)
  with appropriate theme styling.

  ## Attributes

  * `blocks` - Required. List of content blocks. Each block is a map with:
    - `type` - Either `:paragraph`, `:heading`, or `:lead`
    - `text` - The text content
    - `level` - For headings, the level (2, 3, etc.). Defaults to 2.

  ## Examples

      <.rich_text blocks={[
        %{type: :lead, text: "Introduction paragraph..."},
        %{type: :paragraph, text: "Regular paragraph..."},
        %{type: :heading, text: "Section Title"},
        %{type: :paragraph, text: "More content..."}
      ]} />
  """
  attr :blocks, :list, required: true

  def rich_text(assigns) do
    ~H"""
    <div class="rich-text" style="line-height: 1.7;">
      <%= for block <- @blocks do %>
        <.rich_text_block block={block} />
      <% end %>
    </div>
    """
  end

  attr :block, :map, required: true

  defp rich_text_block(%{block: %{type: :lead}} = assigns) do
    ~H"""
    <p class="lead-text text-lg mb-4" style="color: var(--t-text-primary);">
      {@block.text}
    </p>
    """
  end

  defp rich_text_block(%{block: %{type: :paragraph}} = assigns) do
    ~H"""
    <p class="mb-4" style="color: var(--t-text-secondary);">
      {@block.text}
    </p>
    """
  end

  defp rich_text_block(%{block: %{type: :heading}} = assigns) do
    ~H"""
    <h2
      class="mt-8 mb-3"
      style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); font-size: var(--t-text-xl); color: var(--t-text-primary);"
    >
      {@block.text}
    </h2>
    """
  end

  defp rich_text_block(%{block: %{type: :closing}} = assigns) do
    ~H"""
    <p class="mt-8" style="color: var(--t-text-secondary);">
      {@block.text}
    </p>
    """
  end

  defp rich_text_block(%{block: %{type: :list}} = assigns) do
    ~H"""
    <ul class="mb-4 ml-6 list-disc" style="color: var(--t-text-secondary);">
      <%= for item <- @block.items do %>
        <li class="mb-1">{item}</li>
      <% end %>
    </ul>
    """
  end

  defp rich_text_block(assigns) do
    ~H"""
    <p class="mb-4" style="color: var(--t-text-secondary);">
      {@block.text}
    </p>
    """
  end

  @doc """
  Renders a responsive `<picture>` element with AVIF, WebP, and JPEG sources.

  Computes available widths from `source_width` to avoid upscaling - only generates
  srcset entries for sizes smaller than or equal to the original image dimensions.

  The component renders:
  - `<source>` for AVIF (best compression, modern browsers)
  - `<source>` for WebP (good compression, broad support)
  - `<img>` with JPEG srcset (fallback for legacy browsers)

  ## Attributes

  * `src` - Required. Base path to the image variants (without size/extension).
  * `alt` - Required. Alt text for accessibility.
  * `source_width` - Required. Original image width in pixels.
  * `sizes` - Optional. Responsive sizes attribute. Defaults to "100vw".
  * `class` - Optional. CSS classes to apply to the `<img>` element.
  * `width` - Optional. Explicit width attribute.
  * `height` - Optional. Explicit height attribute.
  * `priority` - Optional. If true, sets eager loading and high fetchpriority.
    Defaults to false (lazy loading).

  ## Examples

      <.responsive_image
        src="/image_cache/abc123"
        source_width={1200}
        alt="Product image"
      />

      <.responsive_image
        src="/image_cache/abc123"
        source_width={1200}
        alt="Hero banner"
        priority={true}
        sizes="(max-width: 768px) 100vw, 50vw"
      />
  """
  attr :src, :string, required: true, doc: "Base path without size/extension"
  attr :alt, :string, required: true
  attr :source_width, :integer, required: true, doc: "Original image width"
  attr :sizes, :string, default: "100vw"
  attr :class, :string, default: ""
  attr :width, :integer, default: nil
  attr :height, :integer, default: nil
  attr :priority, :boolean, default: false

  def responsive_image(assigns) do
    alias SimpleshopTheme.Images.Optimizer

    # Compute available widths from source dimensions (no upscaling)
    available = Optimizer.applicable_widths(assigns.source_width)
    default_width = Enum.max(available)

    # Database images end with / (e.g., /images/{id}/variant/)
    # Mockups use - separator (e.g., /mockups/product-1)
    separator = if String.ends_with?(assigns.src, "/"), do: "", else: "-"

    assigns =
      assigns
      |> assign(:available_widths, available)
      |> assign(:default_width, default_width)
      |> assign(:separator, separator)

    ~H"""
    <picture>
      <source
        type="image/avif"
        srcset={build_srcset(@src, @available_widths, "avif")}
        sizes={@sizes}
      />
      <source
        type="image/webp"
        srcset={build_srcset(@src, @available_widths, "webp")}
        sizes={@sizes}
      />
      <img
        src={"#{@src}#{@separator}#{@default_width}.jpg"}
        srcset={build_srcset(@src, @available_widths, "jpg")}
        sizes={@sizes}
        alt={@alt}
        width={@width}
        height={@height}
        loading={if @priority, do: "eager", else: "lazy"}
        decoding={if @priority, do: "sync", else: "async"}
        fetchpriority={if @priority, do: "high", else: nil}
        class={@class}
      />
    </picture>
    """
  end

  @doc """
  Renders flash messages styled for the shop theme.
  """
  attr :flash, :map, required: true

  def shop_flash_group(assigns) do
    ~H"""
    <div
      id="shop-flash-group"
      aria-live="polite"
      class="fixed top-4 right-4 z-[200] flex flex-col gap-2"
    >
      <%= if msg = Phoenix.Flash.get(@flash, :info) do %>
        <div
          id="shop-flash-info"
          class="flex items-center gap-3 px-4 py-3 rounded-lg shadow-lg max-w-sm animate-in"
          style="background-color: var(--t-surface-raised, #fff); color: var(--t-text-primary); border: 1px solid var(--t-border-default);"
          role="alert"
          phx-click={
            Phoenix.LiveView.JS.push("lv:clear-flash", value: %{key: :info})
            |> Phoenix.LiveView.JS.hide(
              to: "#shop-flash-info",
              transition: {"ease-out duration-200", "opacity-100", "opacity-0"}
            )
          }
        >
          <svg
            class="w-5 h-5 shrink-0"
            style="color: var(--t-accent);"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
          >
            <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
          </svg>
          <p class="text-sm">{msg}</p>
        </div>
      <% end %>
      <%= if msg = Phoenix.Flash.get(@flash, :error) do %>
        <div
          id="shop-flash-error"
          class="flex items-center gap-3 px-4 py-3 rounded-lg shadow-lg max-w-sm animate-in"
          style="background-color: var(--t-surface-raised, #fff); color: var(--t-text-primary); border: 1px solid hsl(0 70% 50% / 0.3);"
          role="alert"
          phx-click={
            Phoenix.LiveView.JS.push("lv:clear-flash", value: %{key: :error})
            |> Phoenix.LiveView.JS.hide(
              to: "#shop-flash-error",
              transition: {"ease-out duration-200", "opacity-100", "opacity-0"}
            )
          }
        >
          <svg
            class="w-5 h-5 shrink-0"
            style="color: hsl(0 70% 50%);"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
            />
          </svg>
          <p class="text-sm">{msg}</p>
        </div>
      <% end %>
    </div>
    """
  end

  defp build_srcset(base, widths, format) do
    # Database images end with / (e.g., /images/{id}/variant/)
    # Mockups use - separator (e.g., /mockups/product-1)
    separator = if String.ends_with?(base, "/"), do: "", else: "-"

    widths
    |> Enum.sort()
    |> Enum.map(&"#{base}#{separator}#{&1}.#{format} #{&1}w")
    |> Enum.join(", ")
  end
end
