/* File: assets/css/app.css */

/* ==========================================================================
   Design tokens
   Mirrors assets/js/tailwind.config.js for anything Tailwind utilities cannot
   express — gradients on pseudo-elements, scrollbars, custom scroll snapping.
   ========================================================================== */
:root {
    --canvas: #0A0B1E;
    --canvas-soft: #0D0E24;
    --surface: #16172E;
    --surface-alt: #1E1F3A;
    --hairline: #262845;
    --brand: #5B4FE9;
    --brand-hover: #4A3FD4;
    --grad-from: #7C5CE6;
    --grad-to: #C05CE6;
    --ink: #FFFFFF;
    --ink-muted: #A0A3C4;

    --admin-sidebar: #0B1437;
    --admin-active: #4634FF;
    --admin-bg: #F4F5FA;
    --admin-card: #FFFFFF;
    --admin-line: #E5E7F0;
    --admin-ink: #1F2544;

    --ok: #22C55E;
    --warn: #F59E0B;
    --bad: #EF4444;
    --info: #3B82F6;

    --radius: 14px;
    --radius-lg: 20px;
    --radius-xl: 24px;

    --header-h: 4rem;
    --bottomnav-h: 4.5rem;
}

/* ==========================================================================
   Base
   ========================================================================== */
* { -webkit-tap-highlight-color: transparent; }

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: Inter, ui-sans-serif, system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Prevents any child from creating a horizontal scrollbar. Combined with
       min-w-0 on flex children, this is what keeps the 320px promise. */
    overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6, .font-display {
    font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
    letter-spacing: -0.02em;
}

/* Tabular figures everywhere money or counters appear, so digits do not jitter
   as values update during polling. */
.tabular, .money, .countdown {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* ==========================================================================
   Accessibility
   ========================================================================== */
:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: 4px;
}

.admin-scope :focus-visible {
    outline-color: var(--admin-active);
}

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

.skip-link {
    position: absolute;
    top: -100px; left: 1rem;
    z-index: 100;
    padding: 0.75rem 1.25rem;
    background: var(--brand);
    color: #fff;
    border-radius: var(--radius);
    transition: top 0.2s;
}
.skip-link:focus { top: 1rem; }

/* Every animation in the application is gated on this preference. */
@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;
    }
    .skeleton-shimmer::after { display: none !important; }
    .skeleton-box { background: rgba(255, 255, 255, 0.08) !important; }
    .admin-scope .skeleton-box { background: rgba(31, 37, 68, 0.07) !important; }
}

/* ==========================================================================
   Skeletons
   A skeleton must occupy the same box as the content that replaces it. Any
   layout shift on load is a defect, not a cosmetic issue.
   ========================================================================== */
.skeleton-box {
    position: relative;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.055);
    border-radius: 8px;
}

.admin-scope .skeleton-box {
    background: rgba(31, 37, 68, 0.06);
}

.skeleton-shimmer::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.07) 50%, transparent 100%);
    animation: shimmer 1.6s infinite;
}

.admin-scope .skeleton-shimmer::after {
    background: linear-gradient(90deg, transparent 0%, rgba(31, 37, 68, 0.06) 50%, transparent 100%);
}

@keyframes shimmer {
    100% { transform: translateX(100%); }
}

[data-skeleton][hidden],
[data-content][hidden] { display: none !important; }

/* ==========================================================================
   Scrollbars
   ========================================================================== */
.scroll-slim { scrollbar-width: thin; scrollbar-color: var(--hairline) transparent; }
.scroll-slim::-webkit-scrollbar { width: 6px; height: 6px; }
.scroll-slim::-webkit-scrollbar-track { background: transparent; }
.scroll-slim::-webkit-scrollbar-thumb { background: var(--hairline); border-radius: 999px; }
.scroll-slim::-webkit-scrollbar-thumb:hover { background: #34375C; }

.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
.no-scrollbar::-webkit-scrollbar { display: none; }

/* ==========================================================================
   Layout helpers
   ========================================================================== */
.safe-bottom { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 0.5rem); }
.safe-top    { padding-top: calc(env(safe-area-inset-top, 0px) + 0.5rem); }

/* Reserve space for the fixed bottom navigation so the last row of content is
   never hidden underneath it. */
.has-bottom-nav {
    padding-bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px) + 1rem);
}

@media (min-width: 768px) {
    .has-bottom-nav { padding-bottom: 2rem; }
}

.scroll-snap-x {
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
}
.scroll-snap-x > * { scroll-snap-align: start; }

/* ==========================================================================
   Toasts
   ========================================================================== */
#toast-region {
    position: fixed;
    z-index: 70;
    right: 1rem;
    bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px) + 1rem);
    left: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    pointer-events: none;
}

@media (min-width: 768px) {
    #toast-region {
        left: auto;
        bottom: 1.5rem;
        right: 1.5rem;
        width: 24rem;
    }
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border-radius: var(--radius);
    background: var(--surface-alt);
    border: 1px solid var(--hairline);
    box-shadow: 0 12px 40px rgba(10, 11, 30, 0.55);
    color: var(--ink);
    animation: toast-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.toast[data-state="leaving"] { animation: toast-out 0.18s ease-in forwards; }

.toast-success { border-left: 3px solid var(--ok); }
.toast-error   { border-left: 3px solid var(--bad); }
.toast-warning { border-left: 3px solid var(--warn); }
.toast-info    { border-left: 3px solid var(--info); }

@keyframes toast-in  { from { opacity: 0; transform: translateY(14px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(8px) scale(0.98); } }

/* ==========================================================================
   Forms
   ========================================================================== */
.field-error-text {
    display: block;
    margin-top: 0.375rem;
    font-size: 0.8125rem;
    color: var(--bad);
}

.has-error .field-control,
.field-control[aria-invalid="true"] {
    border-color: var(--bad) !important;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.14);
}

/* Hide the native number spinners — they are a usability problem on money
   inputs, where a stray scroll can silently change an amount. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; }

/* Prevent iOS zooming on focus. Anything below 16px triggers it. */
@media (max-width: 767px) {
    input, select, textarea { font-size: 16px !important; }
}

.btn-loading { position: relative; color: transparent !important; pointer-events: none; }
.btn-loading > * { visibility: hidden; }
.btn-loading::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 1.05rem; height: 1.05rem;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    color: #fff;
    visibility: visible;
    animation: spin 0.6s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   Modals, drawers, sheets
   ========================================================================== */
body.overlay-open { overflow: hidden; }

.sheet-handle {
    width: 2.5rem; height: 0.25rem;
    border-radius: 999px;
    background: var(--hairline);
    margin: 0.75rem auto 0.25rem;
}

/* ==========================================================================
   Admin scope
   ========================================================================== */
.admin-scope { background: var(--admin-bg); color: var(--admin-ink); }
.admin-scope .toast { background: #fff; border-color: var(--admin-line); color: var(--admin-ink); box-shadow: 0 12px 40px rgba(31, 37, 68, 0.16); }

.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.admin-table thead th {
    background: var(--admin-active);
    color: #fff;
    font-weight: 600;
    font-size: 0.8125rem;
    text-align: left;
    padding: 0.9rem 1rem;
    white-space: nowrap;
}
.admin-table thead th:first-child { border-top-left-radius: 10px; }
.admin-table thead th:last-child  { border-top-right-radius: 10px; }
.admin-table tbody td { padding: 0.9rem 1rem; border-bottom: 1px solid var(--admin-line); font-size: 0.875rem; }
.admin-table tbody tr:hover td { background: #FAFBFF; }
.admin-table tbody tr:last-child td { border-bottom: 0; }

/* ==========================================================================
   Utility
   ========================================================================== */
.gradient-text {
    background: linear-gradient(135deg, var(--grad-from) 0%, var(--grad-to) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.card-glow { box-shadow: 0 8px 32px -8px rgba(91, 79, 233, 0.45); }

.hairline-t { border-top: 1px solid var(--hairline); }
.hairline-b { border-bottom: 1px solid var(--hairline); }

.truncate-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* Alpine sets x-cloak until it initialises; without this rule the raw markup
   flashes on screen before hydration. */
[x-cloak] { display: none !important; }

/* End of file: assets/css/app.css */
