/* ==========================================================================
   Free's - shared application styles
   ==========================================================================

   WHY THIS FILE EXISTS (and how to delete most of it)
   --------------------------------------------------------------------------
   Tailwind is loaded from the Play CDN (see templates/components/head_assets.html),
   which is a runtime JIT compiler: no build step, therefore no @layer and no
   @apply, therefore every shared component class has to be hand written here.
   The Play CDN also ships the whole compiler to every visitor, cannot be
   version-pinned or SRI'd, and is documented by Tailwind itself as
   "not designed for production".

   This round deliberately does NOT introduce a build pipeline: node/npm exist
   in CI but not necessarily on the maintainer's machine, and adding one
   changes the day-to-day workflow (every CSS change needs a build). The
   decision is the maintainer's. What follows is the exact runbook so that the
   decision is the only work left.

   --------------------------------------------------------------------------
   MIGRATION RUNBOOK - Tailwind Play CDN  ->  real build
   --------------------------------------------------------------------------
   Prerequisites: node >= 18, npm >= 9.

   1. package.json (new file, repo root)

        {
          "name": "frees-frontend",
          "private": true,
          "version": "0.0.0",
          "scripts": {
            "css:build": "tailwindcss -i ./static/css/tailwind.src.css -o ./static/css/tailwind.build.css --minify",
            "css:watch": "tailwindcss -i ./static/css/tailwind.src.css -o ./static/css/tailwind.build.css --watch"
          },
          "devDependencies": {
            "tailwindcss": "^3.4.17"
          }
        }

   2. tailwind.config.js (new file, repo root)

        module.exports = {
          content: [
            "./templates/**/*.html",
            "./static/js/**/*.js",
            "./core/**/*.py",
            "./store/**/*.py",
            "./dashboard/**/*.py"
          ],
          theme: {
            extend: {
              fontFamily: {
                sans: ["Inter", "sans-serif"],
                serif: ["Playfair Display", "serif"]
              },
              borderRadius: {
                DEFAULT: "0px"
              }
            }
          },
          plugins: []
        };

      The `content` globs must include the Python files: dashboard views and
      core/templatetags emit class strings (e.g. the status badge colour map in
      core/templatetags/status_badge.py), and a purge that only scans templates
      would strip those colours out of the build.

   3. static/css/tailwind.src.css (new file)

        @tailwind base;
        @tailwind components;
        @tailwind utilities;

        @import "./app.css";

      Everything in *this* file can then be progressively rewritten as
      `@layer components { .btn-black { @apply ... } }` inside tailwind.src.css.

   4. npm install && npm run css:build
      Add `static/css/tailwind.build.css` to .gitignore only if the build runs
      in CI/deploy; otherwise commit it so deploys do not need node.

   5. templates/components/head_assets.html - replace

        <script src="https://cdn.tailwindcss.com"></script>
        <link rel="stylesheet" href="{% static 'css/app.css' %}">

      with the single line

        <link rel="stylesheet" href="{% static 'css/tailwind.build.css' %}">

      (that is the ONLY template edit needed - all four skeletons inherit it
      through templates/shell.html.)

   6. frees_project/settings.py - remove "https://cdn.tailwindcss.com" from
      _CSP_CDN_SCRIPT_HOSTS, and drop 'unsafe-eval' from script-src: the Play
      CDN is the only reason it is there. Then flip CSP_REPORT_ONLY to False.

   7. deployment: run `npm ci && npm run css:build` before
      `manage.py collectstatic` in .github/workflows/deploy_app.yml and in
      deployment/update.sh.

   Expected win: ~120 KB of compiler JS per page load replaced by ~10 KB of
   purged CSS, plus a CSP without 'unsafe-eval'.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Typography - one definition for all four skeletons
      (base.html / dashboard/layout.html / dashboard/login.html /
       error_base.html all used to carry their own copy of these two rules,
       one of them via an @import inside <style>, which blocks rendering.)
   -------------------------------------------------------------------------- */
body {
    font-family: 'Inter', sans-serif;
    background-color: #ffffff;
    color: #000000;
}

.logo-font {
    font-family: 'Playfair Display', serif;
}

/* Dashboard sidebar active row (was inline in dashboard/layout.html) */
.sidebar-item.active {
    background-color: #f3f4f6;
    color: #000;
    font-weight: 500;
}

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
    --fr-black: #000000;
    --fr-black-hover: #333333;
    --fr-border: #d1d5db;
    --fr-danger: #dc2626;
    --fr-danger-hover: #b91c1c;
    --fr-muted: #6b7280;

    /* Single source of truth for corner radius.
       The brand language is "sharp corners, no shadow": everything structural
       is square, only pills / avatars use --fr-radius-pill. */
    --fr-radius: 0px;
    --fr-radius-pill: 9999px;

    --fr-focus-ring: 2px solid #000000;
    --fr-focus-ring-inverse: 2px solid #ffffff;
}

/* --------------------------------------------------------------------------
   2. Alpine.js cloaking (this rule never existed before -> FOUC on every
      x-show / x-transition element on the site)
   -------------------------------------------------------------------------- */
[x-cloak] {
    display: none !important;
}

/* --------------------------------------------------------------------------
   3. Accessibility baseline
   -------------------------------------------------------------------------- */
:focus-visible {
    outline: var(--fr-focus-ring);
    outline-offset: 2px;
}

/* Dark surfaces (403 / 404 / 500, footer) need the inverse ring */
.fr-dark :focus-visible,
footer :focus-visible {
    outline: var(--fr-focus-ring-inverse);
    outline-offset: 2px;
}

.sr-only-focusable {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 1000;
    background: #000;
    color: #fff;
    padding: 0.75rem 1.25rem;
    font-size: 0.875rem;
}

.sr-only-focusable:focus {
    left: 0;
}

/* --------------------------------------------------------------------------
   4. Button system
      .btn-black / .btn-outline / .btn-danger  (+ .btn-sm / .btn-lg / .btn-block)
      Each variant is self-sufficient so legacy `class="btn-black ..."` markup
      keeps working without having to add a base `.btn` class everywhere.
   -------------------------------------------------------------------------- */
.btn,
.btn-black,
.btn-outline,
.btn-danger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid transparent;
    border-radius: var(--fr-radius);
    font-size: 0.875rem;
    line-height: 1.25rem;
    font-weight: 500;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
}

.btn-black {
    background-color: var(--fr-black);
    border-color: var(--fr-black);
    color: #ffffff;
}

.btn-black:hover {
    background-color: var(--fr-black-hover);
    border-color: var(--fr-black-hover);
    color: #ffffff;
}

.btn-outline {
    background-color: #ffffff;
    border-color: var(--fr-border);
    color: var(--fr-black);
}

.btn-outline:hover {
    border-color: var(--fr-black);
    background-color: #f9fafb;
}

.btn-danger {
    background-color: #ffffff;
    border-color: #fecaca;
    color: var(--fr-danger);
}

.btn-danger:hover {
    background-color: #fef2f2;
    border-color: var(--fr-danger);
    color: var(--fr-danger-hover);
}

/* Size modifiers */
.btn-sm {
    padding: 0.5rem 1rem;
    font-size: 0.75rem;
}

.btn-lg {
    padding: 1rem 2rem;
}

.btn-block {
    display: flex;
    width: 100%;
}

/* Disabled / in-flight state (used by the submitOnce Alpine helper) */
.btn[disabled],
.btn-black[disabled],
.btn-outline[disabled],
.btn-danger[disabled],
.btn[aria-busy="true"],
.btn-black[aria-busy="true"],
.btn-outline[aria-busy="true"],
.btn-danger[aria-busy="true"] {
    opacity: 0.65;
    cursor: not-allowed;
    pointer-events: none;
}

/* --------------------------------------------------------------------------
   5. Surfaces — flat + square, matching the rest of the storefront
   -------------------------------------------------------------------------- */
.fr-card {
    background-color: #ffffff;
    border: 1px solid #e5e7eb;
    border-radius: var(--fr-radius);
    box-shadow: none;
}

.fr-panel {
    background-color: #f9fafb;
    border-radius: var(--fr-radius);
}

.fr-badge-pill {
    border-radius: var(--fr-radius-pill);
}

/* --------------------------------------------------------------------------
   6. Form controls
   -------------------------------------------------------------------------- */
.fr-input,
.fr-select {
    width: 100%;
    background-color: #ffffff;
    border: 1px solid var(--fr-border);
    border-radius: var(--fr-radius);
    padding: 0.75rem 1rem;
    font-size: 0.875rem;
    line-height: 1.5rem;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.fr-input:focus,
.fr-select:focus {
    outline: none;
    border-color: #000000;
    box-shadow: 0 0 0 1px #000000;
}

/* Denser variant for the back-office, where forms sit in tight table toolbars.
   Replaces the 17 copies of
   "border border-gray-300 rounded-none px-3 py-2 text-sm focus:outline-none
    focus:border-black focus:ring-1 focus:ring-black"
   that were pasted across templates/dashboard/. */
.fr-input-sm {
    width: 100%;
    background-color: #ffffff;
    border: 1px solid var(--fr-border);
    border-radius: var(--fr-radius);
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.fr-input-sm:focus {
    outline: none;
    border-color: #000000;
    box-shadow: 0 0 0 1px #000000;
}

.fr-select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding-right: 2.25rem;
}

/* Hide number input spinners */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"] {
    -moz-appearance: textfield;
}

/* --------------------------------------------------------------------------
   7. Client side validation styling
      (`.show-errors` is toggled on submit, `.field-touched` on blur)
   -------------------------------------------------------------------------- */
.show-errors input:invalid,
.show-errors textarea:invalid,
.show-errors select:invalid,
.field-touched input:invalid,
.field-touched textarea:invalid,
.field-touched select:invalid {
    border-color: #ef4444 !important;
}

.show-errors input:invalid:focus,
.show-errors textarea:invalid:focus,
.show-errors select:invalid:focus,
.field-touched input:invalid:focus,
.field-touched textarea:invalid:focus,
.field-touched select:invalid:focus {
    --tw-ring-color: #ef4444 !important;
    box-shadow: 0 0 0 1px #ef4444;
}

.error-msg {
    display: none;
    color: #ef4444;
    font-size: 0.75rem;
    margin-top: 0.375rem;
}

.show-errors input:invalid ~ .error-msg,
.show-errors textarea:invalid ~ .error-msg,
.show-errors select:invalid ~ .error-msg,
.field-touched input:invalid ~ .error-msg,
.field-touched textarea:invalid ~ .error-msg,
.field-touched select:invalid ~ .error-msg {
    display: block;
    animation: fadeIn 0.3s ease;
}

/* Server side (Django form) errors are always visible */
.error-msg-server {
    display: block;
    color: #ef4444;
    font-size: 0.75rem;
    margin-top: 0.375rem;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --------------------------------------------------------------------------
   8. Overlays (cart drawer / search / mobile menu / confirm modal)
      The focus trap itself lives in static/js/app.js (`x-overlay`). These two
      rules are the CSS half: a fallback for browsers without native `inert`
      (Firefox < 112, Safari < 15.5), and a visible focus ring for the
      close buttons, which sit on white and lose the default ring when a
      template author reaches for `focus:outline-none`.
   -------------------------------------------------------------------------- */
[inert] {
    pointer-events: none;
    cursor: default;
    user-select: none;
}

[inert],
[inert] * {
    -webkit-user-select: none;
}
