/* B&G Solutions — Custom Styles */

/* Smooth scrolling */
html { scroll-behavior: smooth; }

/* ─── Dark-mode transition: gradual 2s shift ─── */
html, body,
.bg-white, .bg-slate-50, .bg-slate-100,
input, select, textarea,
.dark .bg-white, .dark .bg-slate-50, .dark .bg-slate-100 {
    transition: background-color 2s ease, color 1.5s ease, border-color 1.5s ease;
}

/* Hide Alpine.js cloak elements */
[x-cloak] { display: none !important; }

/* Hide the desktop/mobile layout-toggle on any device with a fine pointer
   (mouse/trackpad) — owner asked the option not show up on computers, even
   when the browser window is narrow. Combined with the existing lg:hidden
   class, this means: hidden on big screens AND hidden on small windows
   with a mouse. Still visible on phones/tablets where it's actually useful.
   Plan ref: P3.3 (2026-05-19). */
@media (any-pointer: fine) {
    .touch-only-toggle { display: none !important; }
}

/* iOS Safari zooms the viewport on focus when the focused input has
   font-size < 16px. The Tailwind text-sm default (14px) on inputs across
   the dashboard caused the "search bar makes everything zoom" complaint.
   Force a 16px minimum on all text-entry controls under the mobile
   breakpoint (≤768px). Larger viewports keep the original sm sizing.
   Owner gripe: "Whenever there is a search bar, you click on it on the
   mobile version of dashboard, it zooms in" (2026-05-18 plan G14/P3.2). */
@media (max-width: 768px) {
    input[type="text"],
    input[type="search"],
    input[type="email"],
    input[type="tel"],
    input[type="url"],
    input[type="password"],
    input[type="number"],
    input[type="date"],
    input[type="time"],
    input:not([type]),
    textarea,
    select {
        font-size: 16px !important;
    }
}

/* ── FOUC-safe card stack ──
   Tailwind is loaded via the CDN-JIT compiler (cdn.tailwindcss.com), which
   means classes like `space-y-6` don't apply until after first paint. On
   first cold load (no cache), settings/forms render with their cards
   collapsed against each other; reload paints correctly because the JIT
   output is cached. This rule is delivered from the static CSS file
   (render-blocking) so the gap is correct on first paint. */
.card-stack > * + * { margin-top: 1.5rem; }

/* HTMX loading indicator */
.htmx-request {
    opacity: 0.7;
    pointer-events: none;
    transition: opacity 200ms;
}

.htmx-request::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 20px;
    height: 20px;
    margin: -10px 0 0 -10px;
    border: 2px solid #0074d9;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 600ms linear infinite;
}

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

/* Line clamp utility */
.line-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Select dropdown fix for dark backgrounds */
select option {
    background: #1e293b;
    color: white;
}

/* WCAG 2.4.11 — keyboard-only focus rings (web-app-best-practices-2026
   audit). :focus-visible fires only when focus came from keyboard nav,
   not mouse/touch. The :not(:focus-visible) selector suppresses every
   Tailwind `focus:ring-*` utility and similar :focus rules when the
   user clicked the element instead of tabbed to it — kills the
   noisy-click-ring problem app-wide without touching 60+ templates. */
:focus:not(:focus-visible) {
    box-shadow: none !important;
    outline: none !important;
}

/* Inputs/textareas/selects keep focus styling for mouse users too —
   they still need to see which field is active. !important wins back
   over the suppressor above. */
input:focus, textarea:focus, select:focus {
    box-shadow: 0 0 0 3px rgba(0, 116, 217, 0.15) !important;
}

/* Light mode card definition is handled by Tailwind classes directly:
   border-slate-400, shadow-md, bg-slate-200 page background.
   No CSS overrides needed — avoids Tailwind CDN specificity fight. */

/* Dark mode: auto-invert common dashboard cards — WCAG AA contrast checked */
.dark .bg-white { background-color: #1e293b; }
.dark .border-slate-200 { border-color: #334155; }
.dark .border-slate-100 { border-color: #1e293b; }
.dark .bg-slate-50 { background-color: #0f172a; }
.dark .text-slate-800 { color: #f1f5f9; }   /* was #e2e8f0 — bumped for contrast */
.dark .text-slate-700 { color: #e2e8f0; }   /* was #cbd5e1 */
.dark .text-slate-600 { color: #cbd5e1; }   /* was #94a3b8 */
.dark .text-slate-500 { color: #94a3b8; }   /* was #64748b — bumped significantly */
.dark .text-slate-400 { color: #94a3b8; }   /* ensure hints are readable */
.dark .divide-slate-100 > :not(:last-child) { border-color: #1e293b; }
.dark .hover\:bg-slate-50:hover { background-color: #334155; }
.dark select, .dark input, .dark textarea {
    background-color: #1e293b;
    border-color: #475569;
    color: #f1f5f9;
}
.dark select option {
    background-color: #1e293b;
    color: #f1f5f9;
}
.dark ::placeholder {
    color: #64748b;
}
.dark label { color: #e2e8f0; }
.dark p.text-xs.text-slate-400 { color: #94a3b8; }  /* hint text readable in dark */

/* ═══════════════════════════════════════════════════════════════
   GLOBAL TRANSITIONS & EFFECTS
   ═══════════════════════════════════════════════════════════════ */

/* ── KPI stat cards ── */
.kpi-card {
    display: block;
    background: white;
    border: 1px solid #cbd5e1;  /* slate-300 — visible on light bg */
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 0 0 1px rgba(0,0,0,0.02);
    transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
    cursor: pointer;
    text-decoration: none;
}
.kpi-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.1);
    border-color: #0074d9;
}
.dark .kpi-card {
    background: #1e293b;
    border-color: #334155;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.dark .kpi-card:hover {
    border-color: #d4a843;
    box-shadow: 0 8px 24px rgba(212,168,67,0.12);
}

/* Tabular numbers for count-up (prevent layout shift) */
.tabular-nums { font-variant-numeric: tabular-nums; }

/* ── Fade-in on load ── */
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}
.animate-in {
    animation: fadeInUp 400ms ease-out both;
}

/* ── Generic card hover lift ── */
.card-hover {
    transition: transform 200ms ease, box-shadow 200ms ease;
}
.card-hover:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 16px rgba(0,0,0,0.06);
}
.dark .card-hover:hover {
    box-shadow: 0 4px 16px rgba(0,0,0,0.3);
}

/* ── Row hover for tables/lists ── */
.row-hover {
    transition: background-color 150ms ease;
}
.row-hover:hover {
    background-color: #f8fafc;
}
.dark .row-hover:hover {
    background-color: rgba(51, 65, 85, 0.5);
}

/* ── Sidebar active link (JS-managed after HTMX swap) ── */
nav a.nav-active { background: rgba(255,255,255,0.1); color: #fff !important; }
nav a:not(.nav-active) { color: rgba(255,255,255,0.6); }
nav a:not(.nav-active):hover { color: #fff; background: rgba(255,255,255,0.05); }

/* ── Mobile bottom-nav active state ── */
[data-bnav].bnav-active {
    color: #d4a843 !important;     /* gold */
}

[data-bnav].bnav-active svg { color: #d4a843; }

/* ── Smooth content swap (HTMX) ── */
.htmx-settling {
    opacity: 0;
}
.htmx-added {
    animation: fadeInUp 300ms ease-out both;
}

/* ═══════════════════════════════════════════════════════════════
   MOBILE FIXES — 375px and up
   ═══════════════════════════════════════════════════════════════ */

/* Tighter padding on small screens */
@media (max-width: 640px) {
    /* Tight side padding, but bottom clearance must clear BOTH the fixed
       bottom-nav (~54px) AND the "Ask AI" FAB which sits at bottom-24
       (96px) + ~40px tall = top at ~136px from viewport bottom. We use
       12rem (192px) + iOS safe-area-inset-bottom so the last content
       row sits ~24px above the FAB top with comfortable breathing room
       — verified at iPhone 14 viewport (390×844). */
    #page-content {
        padding: 12px 12px calc(12rem + env(safe-area-inset-bottom)) 12px !important;
    }

    /* Reserve right-edge space so the fixed Ask AI FAB
       (bottom-24 right-4, ~88px wide) doesn't cover card content
       like 'View all' links or right-aligned actions. */
    .fab-clear-right { padding-right: 5.5rem !important; }

    /* KPI cards: 2-col grid stays but cards are compact */
    .kpi-card { padding: 14px; }
    .kpi-card .text-3xl { font-size: 1.5rem; }

    /* Tables: horizontal scroll wrapper (default — right for wide data grids) */
    table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }

    /* Opt-in: narrow comparison tables (e.g. plan/billing tiers) should wrap
       their cells to fit the viewport instead of h-scrolling and clipping the
       'What's included' column. Add class="table-wrap". Cells flagged with the
       Tailwind .whitespace-nowrap class (e.g. Price) keep their no-wrap intent. */
    table.table-wrap { display: table; width: 100%; overflow-x: visible; }
    table.table-wrap th,
    table.table-wrap td { white-space: normal; word-break: break-word; overflow-wrap: anywhere; }
    table.table-wrap .whitespace-nowrap { white-space: nowrap; }

    /* Cards: reduce padding */
    .rounded-xl { overflow: hidden; }
    .px-6 { padding-left: 14px; padding-right: 14px; }
    .p-5 { padding: 14px; }
    .p-6 { padding: 14px; }

    /* Progress stepper: smaller circles + hide labels on very small screens */
    .text-\[10px\] { font-size: 8px; }

    /* Reports charts: prevent overflow */
    canvas { max-width: 100%; }

    /* Forms: full-width inputs */
    input, select, textarea { max-width: 100%; }

    /* Sidebar: already handled by translate-x toggle */
}

/* Prevent any horizontal overflow at the page level */
html, body { overflow-x: hidden; }
main { overflow-x: hidden; max-width: 100vw; }

/* ─── Tap feedback for touch surfaces ──────────────────────────────
   iOS Safari mutes the default tap-highlight when a button is inside
   an Alpine `<template x-for>` because Alpine init briefly disables
   pointer-events. We restore an immediate visual confirm via :active
   styling so the selection feels instant even before Alpine binds the
   :class swap. Apply via `.tap-card` class or via the .tier-card
   selectors below.
   ──────────────────────────────────────────────────────────────── */
.tap-card,
button[type="button"].tap-card {
    -webkit-tap-highlight-color: rgba(0, 116, 217, 0.15);
}
.tap-card:active {
    transform: scale(0.98);
    transition: transform 80ms ease-out;
}

/* ─── Dropzone frame ───────────────────────────────────────────────
   CSS `border-dashed` + `border-radius` renders inconsistently on iOS
   Safari (corners get tick-marks while edges look bare). Use an SVG
   background pattern so the dashed outline is paint-stable everywhere.
   `.dropzone-frame` = idle outline; `.dropzone-frame--drag` = active
   drag-over highlight. Color goes through the `--dz` CSS var so dark
   mode + drag state can swap without rebuilding the SVG.
   ──────────────────────────────────────────────────────────────── */
.dropzone-frame {
    --dz: #cbd5e1;          /* slate-300 */
    --dz-bg: transparent;
    background-color: var(--dz-bg);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><rect width='100%25' height='100%25' fill='none' rx='10' ry='10' stroke='%23cbd5e1' stroke-width='2' stroke-dasharray='8 6'/></svg>");
    border-radius: 10px;
}
html.dark .dropzone-frame {
    --dz: #475569;          /* slate-600 */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><rect width='100%25' height='100%25' fill='none' rx='10' ry='10' stroke='%23475569' stroke-width='2' stroke-dasharray='8 6'/></svg>");
}
.dropzone-frame:hover {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><rect width='100%25' height='100%25' fill='none' rx='10' ry='10' stroke='%230074d9' stroke-width='2' stroke-dasharray='8 6'/></svg>");
    background-color: rgba(15,23,42,0.02);
}
html.dark .dropzone-frame:hover {
    background-color: rgba(255,255,255,0.04);
}
.dropzone-frame--drag,
.dropzone-frame--drag:hover {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><rect width='100%25' height='100%25' fill='none' rx='10' ry='10' stroke='%23d4af37' stroke-width='2.5' stroke-dasharray='10 5'/></svg>");
    background-color: rgba(212,175,55,0.10);
}

/* Fix grid items from blowing out their containers.
   Keep min-width: 0 (real flex/grid blowout fix).
   Dropped overflow: hidden — it was clipping absolutely-positioned
   children (e.g. the "Most Popular" pricing badge at -top-3). */
.grid > * { min-width: 0; }

/* ────────────────────────────────────────────────────────────────
   Global dark-mode polish — strong-contrast layered palette
   Supplements patchy `dark:` Tailwind classes across all pages
   (dashboard + marketing). Hierarchy:
     Layer 0 (body)     #050810 — almost black, deep navy cast
     Layer 1 (sections) #0B1120
     Layer 2 (cards)    #182033 — noticeably lighter, pops off body
     Layer 3 (inputs)   #0E1526 — recessed
   All body text stays at near-white for strong WCAG AAA contrast.
   ──────────────────────────────────────────────────────────────── */

html.dark body {
    background-color: #03060D !important;     /* deeper black-navy for max card contrast */
    color: #F1F5F9;
}
html.dark .bg-slate-50,
html.dark .bg-slate-100 {
    background-color: #080C18 !important;
    color: #F1F5F9;
}
html.dark .bg-white {
    background-color: #1E2A44 !important;     /* was #182033 — lifted for clearer separation */
    color: #F8FAFC;
    border: 1px solid rgba(255,255,255,0.12) !important;  /* stronger, always-visible border */
}
html.dark .bg-slate-200 {
    background-color: #0E1526 !important;
}

/* Marketing-style translucent cards — add a readable fallback */
html.dark .bg-white\/5,
html.dark .bg-white\/10 {
    background-color: rgba(255,255,255,0.04) !important;
    border-color: rgba(255,255,255,0.10) !important;
}

/* Plan-picker selection states (peer-checked + Alpine :class) must
   beat the bg-white/* dark-mode border override above, otherwise the
   selected card looks identical to the unselected ones on iPhone with
   dark mode toggled. Both drivers converge on `border-gold` /
   `peer-checked:border-gold`, so re-assert with !important here. */
html.dark .border-gold {
    border-color: #d4a843 !important;
}
html.dark .peer:checked ~ .peer-checked\:border-gold {
    border-color: #d4a843 !important;
}
html.dark .peer:checked ~ .peer-checked\:bg-white\/10 {
    background-color: rgba(255,255,255,0.10) !important;
}

/* Text — raised floor on all "muted" colors for WCAG AA on dark bg */
html.dark .text-slate-800,
html.dark .text-slate-900,
html.dark .text-navy:not(.bg-navy):not([class*="bg-navy"]) {
    color: #F8FAFC !important;
}
html.dark .text-slate-600,
html.dark .text-slate-700 {
    color: #E2E8F0 !important;     /* was #cbd5e1 — raised for readability */
}
html.dark .text-slate-500 {
    color: #B6C2D4 !important;     /* was #94a3b8 — raised */
}
html.dark .text-slate-400 {
    color: #94A3B8 !important;     /* was #64748b — raised */
}
html.dark .text-white\/40 { color: rgba(255,255,255,0.55) !important; }
html.dark .text-white\/50 { color: rgba(255,255,255,0.65) !important; }
html.dark .text-white\/60 { color: rgba(255,255,255,0.75) !important; }
html.dark .text-white\/70 { color: rgba(255,255,255,0.85) !important; }

/* Borders & dividers — subtle but always visible against dark bg */
html.dark .border-slate-100,
html.dark .border-slate-200,
html.dark .border-slate-300,
html.dark .border-slate-400 {
    border-color: rgba(255,255,255,0.14) !important;
}
html.dark .border-white\/10 { border-color: rgba(255,255,255,0.15) !important; }
html.dark .border-white\/20 { border-color: rgba(255,255,255,0.22) !important; }
html.dark .divide-slate-200 > :not([hidden]) ~ :not([hidden]),
html.dark .divide-slate-300 > :not([hidden]) ~ :not([hidden]) {
    border-color: rgba(255,255,255,0.10) !important;
}

/* Table headers — distinct from body rows */
html.dark thead.bg-slate-50,
html.dark thead tr,
html.dark .bg-slate-50 tr {
    background-color: #0E1526 !important;
    color: #B6C2D4;
}
html.dark tbody tr:hover { background-color: rgba(255,255,255,0.03); }

/* Inputs / selects / textareas */
html.dark input:not([type="checkbox"]):not([type="radio"]),
html.dark select,
html.dark textarea {
    background-color: #0E1526 !important;
    color: #F8FAFC !important;
    border-color: rgba(255,255,255,0.12) !important;
}
html.dark input:focus,
html.dark select:focus,
html.dark textarea:focus {
    border-color: #d4a843 !important;
    box-shadow: 0 0 0 3px rgba(212,168,67,0.15) !important;
}
/* Dark mode: keyboard-only ring on buttons/links (matches the global
   :focus-visible rule above; uses gold on dark for contrast). */
html.dark *:focus-visible:not(input):not(textarea):not(select) {
    outline: 2px solid #d4a843;
    outline-offset: 2px;
}
html.dark input::placeholder,
html.dark textarea::placeholder {
    color: #64748B !important;
}
/* Marketing form fields specifically */
html.dark .bg-white\/10 input,
html.dark .bg-white\/10 select,
html.dark .bg-white\/10 textarea {
    background-color: rgba(255,255,255,0.04) !important;
    border-color: rgba(255,255,255,0.18) !important;
}

/* Hovers */
html.dark .hover\:bg-slate-50:hover,
html.dark .hover\:bg-slate-100:hover {
    background-color: #232D45 !important;
}

/* Shadows: invisible on dark, replace with a subtle lift via border */
html.dark .shadow-sm  { box-shadow: 0 1px 3px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04) !important; }
html.dark .shadow-md  { box-shadow: 0 4px 14px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.05) !important; }
html.dark .shadow-lg  { box-shadow: 0 12px 32px rgba(0,0,0,0.6),  0 0 0 1px rgba(255,255,255,0.06) !important; }
html.dark .shadow-xl  { box-shadow: 0 24px 48px rgba(0,0,0,0.65), 0 0 0 1px rgba(255,255,255,0.06) !important; }

/* Light-to-white gradients — convert to layered dark gradient */
html.dark .bg-gradient-to-br.from-slate-50,
html.dark .bg-gradient-to-b.from-white,
html.dark [class*="from-slate-50"],
html.dark [class*="from-white"] {
    background: linear-gradient(to bottom, #050810, #182033) !important;
}

/* Brand-color elements should stay brand-colored in dark too */
html.dark .bg-navy { background-color: #001f3f !important; }
html.dark .text-navy.bg-white { color: #F8FAFC !important; } /* navy text on white card flips to white on dark card */

/* SVG stroke currentColor fallback on navy cards */
html.dark .bg-white svg { color: inherit; }

/* ────────────────────────────────────────────────────────────────
   Blue-on-blue fixes — brighten brand blue + semantic colors on dark
   ──────────────────────────────────────────────────────────────── */

/* Brand accent blue: brighten so it reads on dark bg */
html.dark .text-accent             { color: #4DA3FF !important; }
html.dark .text-accent-light       { color: #7CBFFF !important; }

/* Semantic text colors (icons etc.) — richer mid-saturation 400s,
   NOT pale pastels. On translucent chips below, these read with real color. */
html.dark .text-blue-500,
html.dark .text-blue-600           { color: #60A5FA !important; }   /* blue-400 */
html.dark .text-green-500,
html.dark .text-green-600          { color: #4ADE80 !important; }   /* green-400 */
html.dark .text-red-500,
html.dark .text-red-600            { color: #F87171 !important; }   /* red-400 */
html.dark .text-yellow-600         { color: #FDE047 !important; }   /* yellow-300 — bright icon for dark amber chip below */
html.dark .text-orange-600         { color: #FB923C !important; }   /* orange-400 */
html.dark .text-purple-500,
html.dark .text-purple-600         { color: #C084FC !important; }   /* purple-400 */
html.dark .text-gold-dark          { color: #E6C570 !important; }

/* Semantic tint chips (bg-*-50 and bg-*-100 variants both used in templates).
   Pair with the richer icon colors above for clear chip/icon contrast. */
html.dark .bg-blue-50,
html.dark .bg-blue-100             { background-color: rgba(59,130,246,0.22) !important; }
html.dark .bg-green-50,
html.dark .bg-green-100            { background-color: rgba(34,197,94,0.22) !important; }
html.dark .bg-red-50,
html.dark .bg-red-100              { background-color: rgba(239,68,68,0.22) !important; }
html.dark .bg-orange-50,
html.dark .bg-orange-100           { background-color: rgba(249,115,22,0.22) !important; }
html.dark .bg-purple-50,
html.dark .bg-purple-100           { background-color: rgba(168,85,247,0.22) !important; }
/* Amber/yellow: flip the pattern — dark warm chip so bright amber icon pops
   (yellow has low luminance range; bright-on-bright doesn't resolve shapes) */
html.dark .bg-yellow-50,
html.dark .bg-yellow-100,
html.dark .bg-amber-50,
html.dark .bg-amber-100            { background-color: rgba(120,53,15,0.55) !important; }
html.dark .bg-gold\/10             { background-color: rgba(212,168,67,0.22) !important; }
html.dark .bg-accent\/10           { background-color: rgba(77,163,255,0.22) !important; }

/* amber-600 = same as yellow-600 context */
html.dark .text-amber-500,
html.dark .text-amber-600          { color: #FCD34D !important; }    /* amber-300 — bright, pops off dark chip */

/* ─── Pull-to-refresh progress bar (mobile) ───
   Appended to <body> by pull_to_refresh.js. Pinned to the very top edge,
   below safe-area inset on iOS. Width is driven by transform:scaleX so
   the GPU can animate it cheaply. */
#ptr-bar {
    position: fixed;
    top: env(safe-area-inset-top, 0px);
    left: 0;
    right: 0;
    height: 3px;
    z-index: 60;
    background: #d4a843; /* gold — same accent the splash uses */
    transform: scaleX(0);
    transform-origin: left center;
    opacity: 0;
    pointer-events: none;
    will-change: transform, opacity;
}
#ptr-bar.ptr-bar--active     { opacity: 1; }
#ptr-bar.ptr-bar--ready      { background: #0074d9; box-shadow: 0 0 8px rgba(0,116,217,0.55); }
#ptr-bar.ptr-bar--reset      { transition: transform 200ms cubic-bezier(0.4,0,0.2,1), opacity 200ms ease 60ms; opacity: 0; }
#ptr-bar.ptr-bar--committing {
    background: linear-gradient(90deg, #0074d9 0%, #4da3ff 50%, #0074d9 100%);
    background-size: 200% 100%;
    animation: ptr-shimmer 800ms linear infinite;
    transition: transform 140ms ease-out;
}
@keyframes ptr-shimmer {
    from { background-position: 0% 0; }
    to   { background-position: -200% 0; }
}
@media (min-width: 1024px) { #ptr-bar { display: none; } }
@media (prefers-reduced-motion: reduce) {
    #ptr-bar.ptr-bar--committing { animation: none; }
}

/* === Phase 2 (v2-only) === */
[data-v="2"] {
    --accent-gold: #d4af37;
}
@supports (view-transition-name: a) {
    @view-transition {
        navigation: auto;
    }
}
[data-v="2"] {
    /* View Transitions opt-in */
}
[data-v="2"] .v2-fade-in {
    animation: v2FadeIn 200ms ease-out both;
}
@starting-style {
    [data-v="2"] .v2-fade-in {
        opacity: 0;
        transform: translateY(4px);
    }
}
@keyframes v2FadeIn {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}
[data-v="2"] .v2-list-row {
    content-visibility: auto;
    contain-intrinsic-size: 0 80px;
}
[data-v="2"] .v2-list-row.v2-post-row {
    padding-inline-start: 1.75rem;
    padding-inline-end: 1rem;
}

/* WCAG 2.2 — 24x24 minimum, 44x44 for primary actions */
[data-v="2"] .v2-chip {
    min-height: 36px;
    min-width: 44px;
    padding: 6px 14px;
    border-radius: 999px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    border: 1px solid var(--border, #cbd5e1);
    color: #0f172a;
    background: #ffffff;
}
[data-v="2"] .v2-chip[aria-pressed="true"],
[data-v="2"] .v2-chip.is-on {
    background: #0f172a;
    color: #ffffff;
    border-color: #0f172a;
}
@media (prefers-color-scheme: dark) {
    [data-v="2"] .v2-chip {
        background: #1e293b;
        color: #e2e8f0;
        border-color: #475569;
    }
    [data-v="2"] .v2-chip[aria-pressed="true"],
    [data-v="2"] .v2-chip.is-on {
        background: #f8fafc;
        color: #0f172a;
        border-color: #f8fafc;
    }
}
html.dark [data-v="2"] .v2-chip[aria-pressed="true"],
html.dark [data-v="2"] .v2-chip.is-on {
    background: #0f172a;
    color: var(--accent-gold);
    border-color: var(--accent-gold);
}
[data-v="2"] .v2-action-btn {
    min-height: 44px;
    min-width: 44px;
}
[data-v="2"] .v2-swipe-handle {
    min-height: 44px;
}

/* === Phase 3 (v2-only) === */
@keyframes v2-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

@keyframes v2-shake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-3px); }
    50% { transform: translateX(3px); }
    75% { transform: translateX(-2px); }
}

[data-v="2"] .v2-action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 44px;
    min-width: 44px;
    padding: 0.75rem 1rem;
    border-radius: 0.9rem;
    border: 1px solid transparent;
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1;
    text-decoration: none;
    transition: transform 160ms ease, background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease, opacity 160ms ease;
}

[data-v="2"] .v2-action-btn--primary {
    background: #0f172a;
    border-color: #0f172a;
    color: #f8fafc;
    box-shadow: 0 10px 22px rgba(15, 23, 42, 0.14);
}

[data-v="2"] .v2-action-btn--secondary {
    background: #ffffff;
    border-color: #cbd5e1;
    color: #0f172a;
}

[data-v="2"] .v2-action-btn--danger {
    background: #7f1d1d;
    border-color: #7f1d1d;
    color: #fef2f2;
}

[data-v="2"] .v2-action-btn.is-pending {
    opacity: 0.72;
    cursor: not-allowed;
    animation: v2-shimmer 1.5s linear infinite;
    background-image: linear-gradient(90deg, rgba(255,255,255,0.12), rgba(255,255,255,0.3), rgba(255,255,255,0.12));
    background-size: 200% 100%;
}

[data-v="2"] .v2-action-btn.is-success {
    background: #166534;
    border-color: #166534;
    color: #f0fdf4;
}

[data-v="2"] .v2-action-btn.is-error {
    background: #fee2e2;
    border-color: #ef4444;
    color: #991b1b;
    animation: v2-shake 220ms ease-in-out 1;
}

[data-v="2"] .v2-skeleton-row {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    min-height: 60px;
    padding: 0.75rem 0;
}

[data-v="2"] .v2-skel-bar {
    border-radius: 999px;
    background: linear-gradient(90deg, rgba(226,232,240,0.95) 20%, rgba(241,245,249,1) 50%, rgba(226,232,240,0.95) 80%);
    background-size: 200% 100%;
    animation: v2-shimmer 1.5s linear infinite;
}

[data-v="2"] .v2-skel-bar--avatar {
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    border-radius: 999px;
}

[data-v="2"] .v2-skel-bar--line {
    height: 12px;
}

[data-v="2"] .v2-skel-bar--w70 {
    width: 70%;
}

[data-v="2"] .v2-skel-bar--w40 {
    width: 40%;
}

[data-v="2"] .v2-empty-state {
    max-width: 360px;
    margin: 0 auto;
    padding: 48px 24px;
    text-align: center;
}

[data-v="2"] .v2-empty-state__icon {
    display: grid;
    place-items: center;
    width: 64px;
    height: 64px;
    margin: 0 auto 1rem;
    border-radius: 999px;
    background: #e2e8f0;
    color: #b45309;
    font-size: 1.5rem;
}

[data-v="2"] .v2-empty-state__title {
    font-size: 18px;
    font-weight: 700;
    color: #0f172a;
}

[data-v="2"] .v2-empty-state__body {
    margin-top: 0.5rem;
    font-size: 14px;
    line-height: 1.55;
    color: #475569;
}

[data-v="2"] .v2-error-page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 3rem 1.5rem;
    text-align: center;
}

[data-v="2"] .v2-error-page__code {
    font-size: 96px;
    line-height: 1;
    font-weight: 900;
    letter-spacing: -0.04em;
    color: rgba(180, 83, 9, 0.28);
}

[data-v="2"] .v2-error-page__title {
    max-width: 32rem;
    font-size: 2rem;
    line-height: 1.1;
    font-weight: 800;
    color: #0f172a;
}

[data-v="2"] .v2-error-page__body {
    max-width: 28rem;
    font-size: 1rem;
    line-height: 1.6;
    color: #475569;
}

html.dark [data-v="2"] .v2-action-btn--primary {
    background: #f8fafc;
    border-color: #f8fafc;
    color: #0f172a;
    box-shadow: 0 10px 24px rgba(2, 6, 23, 0.35);
}

html.dark [data-v="2"] .v2-action-btn--secondary {
    background: #1e293b;
    border-color: #475569;
    color: #e2e8f0;
}

html.dark [data-v="2"] .v2-action-btn--danger {
    background: #7f1d1d;
    border-color: #991b1b;
    color: #fef2f2;
}

html.dark [data-v="2"] .v2-action-btn.is-pending {
    background-image: linear-gradient(90deg, rgba(255,255,255,0.05), rgba(255,255,255,0.16), rgba(255,255,255,0.05));
}

html.dark [data-v="2"] .v2-action-btn.is-success {
    background: #166534;
    border-color: #22c55e;
    color: #f0fdf4;
}

html.dark [data-v="2"] .v2-action-btn.is-error {
    background: rgba(127, 29, 29, 0.35);
    border-color: #f87171;
    color: #fecaca;
}

html.dark [data-v="2"] .v2-skel-bar {
    background: linear-gradient(90deg, rgba(51,65,85,0.95) 20%, rgba(71,85,105,1) 50%, rgba(51,65,85,0.95) 80%);
    background-size: 200% 100%;
}

html.dark [data-v="2"] .v2-empty-state__icon {
    background: rgba(71, 85, 105, 0.38);
    color: #fbbf24;
}

html.dark [data-v="2"] .v2-empty-state__title {
    color: #f8fafc;
}

html.dark [data-v="2"] .v2-empty-state__body {
    color: #cbd5e1;
}

html.dark [data-v="2"] .v2-error-page__code {
    color: rgba(212, 168, 67, 0.34);
}

html.dark [data-v="2"] .v2-error-page__title {
    color: #f8fafc;
}

html.dark [data-v="2"] .v2-error-page__body {
    color: #cbd5e1;
}

/* === Phase 4 (v2-only) === */
[data-v="2"] .v2-section { margin-block-end: 1.5rem; }
[data-v="2"] .v2-section-header { margin-block-end: 0.75rem; }
[data-v="2"] .v2-row-gap { row-gap: 1rem; }
[data-v="2"] .v2-action-cluster > * + * { margin-inline-start: 0.5rem; }
[data-v="2"] .v2-list-row { padding-block: 0.875rem; padding-inline: 1rem; }
[data-v="2"] .v2-toolbar { padding-block: 0.625rem; gap: 0.625rem; }
[data-v="2"] .v2-mobile-only { display: none; }

@media (max-width: 767px) {
    [data-v="2"] .v2-mobile-only { display: inline-flex; }
}

@media (prefers-color-scheme: light) {
    html:not(.dark) [data-v="2"] .v2-sidebar {
        background: rgba(15, 23, 42, 0.08);
        backdrop-filter: blur(8px);
        border-right: 1px solid rgba(15, 23, 42, 0.08);
    }
    html:not(.dark) [data-v="2"] .v2-sidebar nav a.nav-active {
        background: rgba(15, 23, 42, 0.12);
        color: #0f172a !important;
    }
    html:not(.dark) [data-v="2"] .v2-sidebar nav a:not(.nav-active) {
        color: rgba(15, 23, 42, 0.72);
    }
    html:not(.dark) [data-v="2"] .v2-sidebar nav a:not(.nav-active):hover {
        color: #0f172a;
        background: rgba(15, 23, 42, 0.06);
    }
}

/* Desktop-forced layout (replaces the old viewport=1280 hack)
   Keeps native scale so login forms and all touch targets stay usable.
   Applied via .bg-force-desktop on <html> when localStorage flag is set. */
.bg-force-desktop .v2-sidebar {
    transform: translateX(0) !important;
    z-index: 40;
}
.bg-force-desktop main {
    margin-left: 16rem !important; /* 64 * 0.25rem */
    padding-top: 0 !important;
}
.bg-force-desktop .lg\:hidden,
.bg-force-desktop [class*="lg:hidden"] {
    display: none !important;
}
.bg-force-desktop #page-content {
    max-width: 100% !important;
}

/* D1 — prevent iOS Safari zoom on input focus.
   iOS auto-zooms when a focused input's computed font-size is <16px.
   Force 16px on form controls at the phone breakpoint to suppress it. */
@media (max-width: 640px) {
    input[type="text"],
    input[type="search"],
    input[type="email"],
    input[type="tel"],
    input[type="number"],
    input[type="url"],
    input[type="password"],
    input:not([type]),
    textarea,
    select {
        font-size: 16px !important;
    }
}

/* Day-view booking time-states.
   .booking-imminent: amber tint with a diagonal sheen sweep when the
     appointment starts within 1h. Sheen is clipped inside the row, so the
     glow doesn't bleed past the "Now" divider above.
   .booking-in-progress: steady green tint while the appointment is live.
   Tints survive Tailwind hover via higher specificity (.booking-* attribute). */
@keyframes booking-imminent-sheen {
    0% { transform: translateX(-120%) skewX(-18deg); }
    60%, 100% { transform: translateX(260%) skewX(-18deg); }
}

.booking-imminent {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background-color: rgba(245, 158, 11, 0.10);
    box-shadow: inset 4px 0 0 0 rgb(245, 158, 11);
}
.booking-imminent::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 45%;
    pointer-events: none;
    background: linear-gradient(
        100deg,
        rgba(252, 211, 77, 0) 0%,
        rgba(252, 211, 77, 0.55) 50%,
        rgba(252, 211, 77, 0) 100%
    );
    transform: translateX(-120%) skewX(-18deg);
    animation: booking-imminent-sheen 3.6s ease-in-out infinite;
    mix-blend-mode: screen;
}
.dark .booking-imminent {
    background-color: rgba(245, 158, 11, 0.16);
}
.dark .booking-imminent::after {
    background: linear-gradient(
        100deg,
        rgba(252, 211, 77, 0) 0%,
        rgba(252, 211, 77, 0.35) 50%,
        rgba(252, 211, 77, 0) 100%
    );
}

.booking-in-progress {
    position: relative;
    z-index: 1;
    background-color: rgba(16, 185, 129, 0.10);
    box-shadow: inset 4px 0 0 0 rgb(16, 185, 129);
}
.dark .booking-in-progress {
    background-color: rgba(16, 185, 129, 0.16);
}

/* Desktop-only: give LIVE rows a green sheen sweep (same pattern as amber).
   Mobile keeps the steady tint above — no motion on narrow screens. */
@keyframes booking-live-sheen {
    0% { transform: translateX(-120%) skewX(-18deg); }
    60%, 100% { transform: translateX(260%) skewX(-18deg); }
}
@media (min-width: 768px) {
    .booking-in-progress {
        isolation: isolate;
        overflow: hidden;
        box-shadow: inset 4px 0 0 0 rgb(16, 185, 129);
    }
    .booking-in-progress::after {
        content: "";
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        width: 45%;
        pointer-events: none;
        background: linear-gradient(
            100deg,
            rgba(110, 231, 183, 0) 0%,
            rgba(110, 231, 183, 0.50) 50%,
            rgba(110, 231, 183, 0) 100%
        );
        transform: translateX(-120%) skewX(-18deg);
        animation: booking-live-sheen 3.6s ease-in-out infinite;
        mix-blend-mode: screen;
    }
    .dark .booking-in-progress::after {
        background: linear-gradient(
            100deg,
            rgba(110, 231, 183, 0) 0%,
            rgba(110, 231, 183, 0.32) 50%,
            rgba(110, 231, 183, 0) 100%
        );
    }
}

/* Mobile-only override: hide the SOON sheen sweep. LIVE already has no
   animation on mobile via the base rule. Both states keep tint + 4px
   colored left bar only — no motion, no inner ring. */
@media (max-width: 767px) {
    .booking-imminent::after { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .booking-imminent::after { display: none; }
    .booking-imminent {
        box-shadow:
            inset 4px 0 0 0 rgb(245, 158, 11),
            inset 0 0 0 1px rgba(245, 158, 11, 0.45);
    }
    .booking-in-progress::after { display: none; }
    .booking-in-progress {
        box-shadow:
            inset 4px 0 0 0 rgb(16, 185, 129),
            inset 0 0 0 1px rgba(16, 185, 129, 0.45);
    }
}
