Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
840 lines
23 KiB
CSS
840 lines
23 KiB
CSS
/* app/globals.css */
|
|
@import 'tailwindcss';
|
|
@import '@heroui/styles';
|
|
/*@custom-variant dark (&:is(.dark *));*/
|
|
|
|
@keyframes slide-down {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-100%);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Consumer bottom sheets use HeroUI's `data-entering` / `data-exiting` states.
|
|
* Keeping this on the Modal container lets React Aria preserve the dialog while
|
|
* the exit animation completes and keeps backdrop clicks managed by HeroUI.
|
|
*/
|
|
@keyframes consumer-modal-slide-in {
|
|
from {
|
|
transform: translateY(100%);
|
|
}
|
|
|
|
to {
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes consumer-modal-slide-out {
|
|
from {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
to {
|
|
transform: translateY(100%);
|
|
}
|
|
}
|
|
|
|
@keyframes consumer-modal-backdrop-in {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes consumer-modal-backdrop-out {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* HeroUI sizes the backdrop/container to `--visual-viewport-height`. On mobile,
|
|
* focusing an input can shrink/scroll the visual viewport while the layout
|
|
* viewport stays tall — leaving a hole where page content shows through the
|
|
* sheet. Keep the backdrop pinned to the dynamic viewport (`dvh`, not `lvh`:
|
|
* large viewport is taller than the visible area when browser chrome is shown
|
|
* and clips the bottom sheet) and lift the sheet with `--keyboard-inset`
|
|
* instead of relying on the visual-viewport height.
|
|
*/
|
|
.consumer-modal-backdrop {
|
|
top: 0 !important;
|
|
right: 0 !important;
|
|
bottom: 0 !important;
|
|
left: 0 !important;
|
|
width: 100% !important;
|
|
/* Override `h-(--visual-viewport-height)` so top/bottom stretch covers the layout. */
|
|
height: auto !important;
|
|
min-height: 100%;
|
|
min-height: 100dvh;
|
|
max-height: 100dvh;
|
|
align-items: stretch !important;
|
|
overscroll-behavior: none;
|
|
}
|
|
|
|
.consumer-modal-container {
|
|
/* Fill the dynamic-viewport backdrop; do not track `--visual-viewport-height`. */
|
|
height: 100% !important;
|
|
min-height: 100%;
|
|
min-height: 100dvh;
|
|
max-height: 100dvh;
|
|
flex: 1 1 auto;
|
|
/* Keyboard open: inset lifts the sheet; keyboard closed: inset is 0. */
|
|
padding-bottom: var(--keyboard-inset, 0px);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.consumer-modal-container[data-entering='true'] {
|
|
animation: consumer-modal-slide-in 300ms var(--ease-out-fluid, cubic-bezier(0.32, 0.72, 0, 1)) both;
|
|
will-change: transform;
|
|
}
|
|
|
|
.consumer-modal-container[data-exiting='true'] {
|
|
animation: consumer-modal-slide-out 220ms var(--ease-out-fluid, cubic-bezier(0.32, 0.72, 0, 1)) both;
|
|
will-change: transform;
|
|
}
|
|
|
|
.consumer-modal-backdrop[data-entering='true'] {
|
|
animation: consumer-modal-backdrop-in 240ms ease-out both;
|
|
will-change: opacity;
|
|
}
|
|
|
|
.consumer-modal-backdrop[data-exiting='true'] {
|
|
animation: consumer-modal-backdrop-out 220ms ease-out both;
|
|
will-change: opacity;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.consumer-modal-backdrop[data-entering='true'],
|
|
.consumer-modal-backdrop[data-exiting='true'],
|
|
.consumer-modal-container[data-entering='true'],
|
|
.consumer-modal-container[data-exiting='true'] {
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
/* HeroUI v3 semantic tokens: preserve the brand orange with AA contrast. */
|
|
:root,
|
|
.light,
|
|
.default,
|
|
[data-theme='light'],
|
|
[data-theme='default'] {
|
|
--accent: var(--color-primary);
|
|
--accent-foreground: var(--color-secondary-100);
|
|
--focus: var(--accent);
|
|
}
|
|
|
|
/*
|
|
* Admin theme contract
|
|
*
|
|
* Keep HeroUI's semantic variables scoped to the admin shell. This lets
|
|
* compound components (fields, overlays, tables, toasts) share the same
|
|
* brand, focus, border, radius, and elevation language without leaking
|
|
* admin presentation into the consumer application.
|
|
*/
|
|
[data-theme='ghabilee-admin'] {
|
|
color-scheme: light;
|
|
|
|
--background: var(--color-secondary-50);
|
|
--foreground: var(--color-text);
|
|
--background-inverse: var(--color-tertiary);
|
|
|
|
--surface: var(--color-surface);
|
|
--surface-foreground: var(--foreground);
|
|
--surface-secondary: var(--color-secondary-50);
|
|
--surface-secondary-foreground: var(--foreground);
|
|
--surface-tertiary: var(--color-divider);
|
|
--surface-tertiary-foreground: var(--foreground);
|
|
|
|
--overlay: var(--color-surface);
|
|
--overlay-foreground: var(--foreground);
|
|
--muted: var(--color-secondary-30);
|
|
|
|
--default: var(--color-divider);
|
|
--default-foreground: var(--color-secondary-20);
|
|
--accent: var(--color-primary);
|
|
--accent-foreground: var(--color-secondary-100);
|
|
|
|
--success: var(--color-fifth);
|
|
--success-foreground: var(--color-tertiary);
|
|
--warning: var(--color-warning);
|
|
--warning-foreground: var(--color-tertiary);
|
|
--danger: var(--color-fourth);
|
|
--danger-foreground: var(--color-secondary-100);
|
|
|
|
--border: var(--color-divider);
|
|
--separator: var(--color-divider);
|
|
--focus: var(--accent);
|
|
--link: var(--color-tertiary);
|
|
|
|
--field-background: var(--color-surface);
|
|
--field-foreground: var(--foreground);
|
|
--field-placeholder: var(--color-secondary-30);
|
|
--field-border: var(--color-divider);
|
|
--field-border-width: 1px;
|
|
--field-radius: 0.75rem;
|
|
|
|
--radius: 0.75rem;
|
|
--surface-shadow: 0 1px 2px rgb(51 58 68 / 3%), 0 10px 30px rgb(51 58 68 / 4%);
|
|
--overlay-shadow: 0 16px 48px rgb(51 58 68 / 14%);
|
|
--field-shadow: 0 1px 2px rgb(51 58 68 / 4%);
|
|
|
|
--scrollbar-thumb: rgb(128 128 128 / 55%);
|
|
--scrollbar-track: transparent;
|
|
--scrollbar-width: thin;
|
|
|
|
--admin-page-bg: var(--background);
|
|
--admin-surface: var(--surface);
|
|
--admin-border: var(--separator);
|
|
--admin-radius: 1.125rem;
|
|
--admin-shadow: var(--surface-shadow);
|
|
}
|
|
|
|
@theme {
|
|
--font-sans: var(--font-pinar), ui-sans-serif, system-ui, sans-serif;
|
|
--font-mono: ui-monospace, 'SFMono-Regular', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
--font-family-sans: var(--font-sans);
|
|
|
|
--color-text: var(--color-secondary);
|
|
--color-text-main: var(--color-text);
|
|
|
|
--color-surface: var(--color-secondary-100);
|
|
--color-divider: var(--color-secondary-40);
|
|
--color-accent-light: var(--color-primary-50);
|
|
--color-primary-hover: var(--color-primary-700);
|
|
|
|
--color-primary: var(--color-primary-600);
|
|
--color-primary-25: #fefaf6;
|
|
--color-primary-50: #fcf5ed;
|
|
--color-primary-100: #f9eadb;
|
|
--color-primary-200: #f4d6b8;
|
|
--color-primary-300: #eec194;
|
|
--color-primary-400: #f1af6d;
|
|
--color-primary-500: #f39d46;
|
|
--color-primary-600: #f68b1f;
|
|
--color-primary-700: #dd8022;
|
|
--color-primary-800: #c47625;
|
|
--color-primary-900: #ab6b28;
|
|
--color-primary-1000: #74481c;
|
|
|
|
/* Secondary: neutral / gray — base #333A44 */
|
|
--color-secondary: var(--color-secondary-10);
|
|
--color-secondary-10: #333a44;
|
|
--color-secondary-20: #585858;
|
|
--color-secondary-30: #808080;
|
|
--color-secondary-40: #e2e2e2;
|
|
--color-secondary-45: #ebeced;
|
|
--color-secondary-50: #f5f5f5;
|
|
--color-secondary-100: #ffffff;
|
|
|
|
/* Numeric aliases keep existing secondary-* utilities available. */
|
|
--color-secondary-200: var(--color-secondary-45);
|
|
--color-secondary-300: var(--color-secondary-40);
|
|
--color-secondary-400: var(--color-secondary-30);
|
|
--color-secondary-500: var(--color-secondary-30);
|
|
--color-secondary-600: var(--color-secondary-20);
|
|
--color-secondary-700: var(--color-secondary-20);
|
|
--color-secondary-800: var(--color-secondary-10);
|
|
--color-secondary-900: var(--color-secondary-10);
|
|
|
|
/* Tertiary: blue — base #1C2473 */
|
|
--color-tertiary: var(--color-tertiary-900);
|
|
--color-tertiary-50: #eeeef4;
|
|
--color-tertiary-100: #ddddea;
|
|
--color-tertiary-200: #bbbbd4;
|
|
--color-tertiary-300: #9898bf;
|
|
--color-tertiary-400: #7676a9;
|
|
--color-tertiary-500: #545494;
|
|
--color-tertiary-600: #3c4089;
|
|
--color-tertiary-700: #34377a;
|
|
--color-tertiary-800: #282e76;
|
|
--color-tertiary-900: #1c2473;
|
|
|
|
/* Fourth: red — base #ED1C24 */
|
|
--color-fourth: var(--color-fourth-500);
|
|
--color-fourth-100: #f8aa98;
|
|
--color-fourth-300: #f37160;
|
|
--color-fourth-500: #ed1c24;
|
|
--color-fourth-700: #c8161d;
|
|
--color-fourth-900: #9a061a;
|
|
|
|
/* Fifth: green — base #007839 */
|
|
--color-fifth: var(--color-fifth-900);
|
|
--color-fifth-50: var(--color-fifth-100);
|
|
--color-fifth-100: #b9e0d2;
|
|
--color-fifth-200: var(--color-fifth-100);
|
|
--color-fifth-500: #38a77f;
|
|
--color-fifth-600: var(--color-fifth-500);
|
|
--color-fifth-700: var(--color-fifth-500);
|
|
--color-fifth-900: #007839;
|
|
|
|
--color-warning: #ffcc00;
|
|
--color-warning-dark: #b88d0a;
|
|
|
|
/* Consumer theme aliases → text-consumer-text, bg-consumer-surface, … */
|
|
--color-consumer-canvas: var(--consumer-canvas);
|
|
--color-consumer-surface: var(--consumer-surface);
|
|
--color-consumer-surface-muted: var(--consumer-surface-muted);
|
|
--color-consumer-event-card: var(--consumer-event-card-bg);
|
|
--color-consumer-text: var(--consumer-text);
|
|
--color-consumer-text-muted: var(--consumer-text-muted);
|
|
--color-consumer-border: var(--consumer-border);
|
|
--color-consumer-focus: var(--consumer-focus);
|
|
|
|
--radius-consumer-control: var(--consumer-radius-control);
|
|
--radius-consumer-card: var(--consumer-radius-card);
|
|
--radius-consumer-modal: var(--consumer-radius-modal);
|
|
--radius-consumer-surface: var(--consumer-radius-surface);
|
|
|
|
--spacing-consumer-bottom-nav: var(--consumer-bottom-nav-height);
|
|
|
|
--container-center: true;
|
|
--container-padding: 1rem;
|
|
--container-padding-sm: 2rem;
|
|
--container-padding-lg: 3rem;
|
|
--container-padding-xl: 4rem;
|
|
--container-padding-2xl: 5rem;
|
|
|
|
--container-sm: 100%;
|
|
--container-md: 100%;
|
|
--container-lg: 1024px;
|
|
--container-xl: 1280px;
|
|
--container-2xl: 1440px;
|
|
}
|
|
|
|
@utility type-label {
|
|
font-size: var(--text-sm);
|
|
font-weight: 500;
|
|
line-height: 1.4;
|
|
letter-spacing: normal;
|
|
}
|
|
|
|
@utility text-2xs {
|
|
font-size: 10px;
|
|
}
|
|
|
|
@utility type-display {
|
|
font-weight: 800;
|
|
line-height: 1.35;
|
|
letter-spacing: normal;
|
|
}
|
|
|
|
@layer base {
|
|
:root {
|
|
--admin-page-bg: var(--color-secondary-50);
|
|
--admin-surface: var(--color-surface);
|
|
--admin-border: var(--color-divider);
|
|
--admin-radius: 18px;
|
|
--admin-shadow: 0 1px 2px rgb(51 58 68 / 3%), 0 10px 30px rgb(51 58 68 / 4%);
|
|
|
|
--consumer-canvas: var(--color-secondary-45);
|
|
--consumer-surface: var(--color-surface);
|
|
--consumer-surface-muted: var(--color-secondary-50);
|
|
--consumer-event-card-bg: var(--color-secondary-50);
|
|
--consumer-text: var(--color-text);
|
|
--consumer-text-muted: var(--color-secondary-30);
|
|
--consumer-border: var(--color-divider);
|
|
--consumer-focus: var(--color-primary);
|
|
--consumer-radius-control: 12px;
|
|
--consumer-radius-card: 16px;
|
|
--consumer-radius-modal: 22px;
|
|
--consumer-radius-surface: 22px;
|
|
/*
|
|
* Consumer surfaces fill the available viewport on phones. The desktop
|
|
* breakpoint below turns the same token into the centred device preview,
|
|
* which keeps pages, sheets, bottom navigation, and sticky actions aligned.
|
|
*/
|
|
--consumer-app-max-width: 100%;
|
|
--consumer-bottom-nav-height: 80px;
|
|
--keyboard-inset: 0px;
|
|
}
|
|
|
|
html {
|
|
font-family: var(--font-sans);
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
:root {
|
|
--consumer-app-max-width: 390px;
|
|
}
|
|
}
|
|
|
|
body {
|
|
--pinar-dsty: 0;
|
|
--pinar-kshd: 100;
|
|
color: var(--color-tertiary);
|
|
font-family: var(--font-sans);
|
|
font-variation-settings:
|
|
'DSTY' var(--pinar-dsty),
|
|
'KSHD' var(--pinar-kshd);
|
|
direction: rtl;
|
|
background: var(--color-primary-25);
|
|
overscroll-behavior-y: none;
|
|
}
|
|
|
|
input,
|
|
textarea,
|
|
select,
|
|
button {
|
|
font: inherit;
|
|
text-align: right;
|
|
}
|
|
|
|
input[type='email'],
|
|
input[type='url'],
|
|
input[type='number'] {
|
|
direction: ltr;
|
|
text-align: right;
|
|
}
|
|
|
|
/* tel: LTR digits; placeholder on the right, typed value from the left */
|
|
input[type='tel'] {
|
|
direction: ltr !important;
|
|
text-align: left !important;
|
|
}
|
|
|
|
input[type='tel']:placeholder-shown {
|
|
text-align: right !important;
|
|
}
|
|
|
|
[dir='ltr']:not(input):not(textarea) {
|
|
direction: ltr;
|
|
text-align: left;
|
|
}
|
|
|
|
tr[aria-hidden='true'] {
|
|
display: none !important;
|
|
}
|
|
|
|
[data-selected='true']::before,
|
|
[data-selected='true']::after {
|
|
opacity: 0 !important;
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
canvas {
|
|
font-family: var(--font-sans);
|
|
}
|
|
|
|
button[role='tab']:not([data-selected]),
|
|
button[role='tab']:not([data-selected]) * {
|
|
color: var(--color-primary-600) !important;
|
|
}
|
|
|
|
button[role='tab'][data-selected],
|
|
button[role='tab'][data-selected] * {
|
|
color: var(--color-primary-700) !important;
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
.button--xl {
|
|
height: 54px;
|
|
padding: 5px 12px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.button--xl svg:not([data-slot='spinner'] svg, [data-slot='link-icon'] svg) {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.consumer-wheel-picker > div:last-child {
|
|
display: none;
|
|
}
|
|
|
|
.admin-surface {
|
|
border: 1px solid var(--admin-border);
|
|
border-radius: var(--admin-radius);
|
|
background: var(--admin-surface);
|
|
box-shadow: var(--admin-shadow);
|
|
}
|
|
|
|
.admin-page-container {
|
|
@apply mx-auto w-full max-w-[1600px] p-3 sm:p-5 lg:p-6 xl:p-7;
|
|
}
|
|
|
|
.admin-page-header {
|
|
box-shadow: 0 1px 0 rgb(51 58 68 / 2%);
|
|
}
|
|
|
|
.admin-sidebar-scroll {
|
|
scrollbar-color: rgb(226 226 226 / 70%) transparent;
|
|
scrollbar-width: thin;
|
|
}
|
|
|
|
.admin-sidebar-scroll::-webkit-scrollbar {
|
|
width: 4px;
|
|
}
|
|
|
|
.admin-sidebar-scroll::-webkit-scrollbar-thumb {
|
|
border-radius: 999px;
|
|
background: rgb(226 226 226 / 70%);
|
|
}
|
|
|
|
.consumer-mobile-viewport,
|
|
.consumer-app {
|
|
position: relative;
|
|
width: 100%;
|
|
max-width: var(--consumer-app-max-width);
|
|
margin-inline: auto;
|
|
}
|
|
|
|
.consumer-app {
|
|
--consumer-chrome-bottom: var(--keyboard-inset, 0px);
|
|
--consumer-sticky-pad-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
|
|
background: var(--consumer-canvas);
|
|
color: var(--consumer-text);
|
|
overscroll-behavior-y: contain;
|
|
}
|
|
|
|
.consumer-content {
|
|
overscroll-behavior-y: contain;
|
|
/* Tab shell remounts tall ↔ short content; anchoring would fight restore-to-top. */
|
|
overflow-anchor: none;
|
|
}
|
|
|
|
/*
|
|
* Consumer scrollbars are hidden by default (scroll still works).
|
|
* Opt in with `.consumer-scrollbar` on the scroll container when a visible
|
|
* bar is needed.
|
|
*/
|
|
.consumer-app,
|
|
.consumer-app *,
|
|
.consumer-mobile-viewport,
|
|
.consumer-mobile-viewport *,
|
|
.consumer-overlay,
|
|
.consumer-overlay * {
|
|
scrollbar-width: none;
|
|
-ms-overflow-style: none;
|
|
}
|
|
|
|
.consumer-app::-webkit-scrollbar,
|
|
.consumer-app *::-webkit-scrollbar,
|
|
.consumer-mobile-viewport::-webkit-scrollbar,
|
|
.consumer-mobile-viewport *::-webkit-scrollbar,
|
|
.consumer-overlay::-webkit-scrollbar,
|
|
.consumer-overlay *::-webkit-scrollbar {
|
|
display: none;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.consumer-app .consumer-scrollbar,
|
|
.consumer-mobile-viewport .consumer-scrollbar,
|
|
.consumer-overlay .consumer-scrollbar {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: rgb(128 128 128 / 40%) transparent;
|
|
-ms-overflow-style: auto;
|
|
}
|
|
|
|
.consumer-app .consumer-scrollbar::-webkit-scrollbar,
|
|
.consumer-mobile-viewport .consumer-scrollbar::-webkit-scrollbar,
|
|
.consumer-overlay .consumer-scrollbar::-webkit-scrollbar {
|
|
display: block;
|
|
width: 4px;
|
|
height: 4px;
|
|
}
|
|
|
|
.consumer-app .consumer-scrollbar::-webkit-scrollbar-thumb,
|
|
.consumer-mobile-viewport .consumer-scrollbar::-webkit-scrollbar-thumb,
|
|
.consumer-overlay .consumer-scrollbar::-webkit-scrollbar-thumb {
|
|
border-radius: 999px;
|
|
background: rgb(128 128 128 / 40%);
|
|
}
|
|
|
|
/*
|
|
* HeroUI modal dialog/body use overflow clip. Full-width rounded fields sit flush
|
|
* on the content edge; extend the clip margin so 1px borders are not shaved at corners.
|
|
*/
|
|
.consumer-overlay[data-slot='modal-dialog'],
|
|
.consumer-overlay [data-slot='modal-body'] {
|
|
overflow-clip-margin: 1px;
|
|
}
|
|
|
|
.consumer-app-with-bottom-nav {
|
|
--consumer-chrome-bottom: calc(var(--consumer-bottom-nav-height) + env(safe-area-inset-bottom, 0px) + var(--keyboard-inset, 0px));
|
|
--consumer-sticky-pad-bottom: 12px;
|
|
}
|
|
|
|
.consumer-page-container {
|
|
@apply mx-auto w-full px-2;
|
|
max-width: var(--consumer-app-max-width);
|
|
}
|
|
|
|
.consumer-content-with-bottom-nav {
|
|
/* background-color: white; */
|
|
padding-bottom: calc(var(--consumer-bottom-nav-height) + env(safe-area-inset-bottom, 0px) + var(--keyboard-inset, 0px));
|
|
}
|
|
|
|
.consumer-bottom-nav {
|
|
inset-inline: 0;
|
|
bottom: var(--keyboard-inset, 0px);
|
|
width: 100%;
|
|
max-width: var(--consumer-app-max-width);
|
|
margin-inline: auto;
|
|
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
}
|
|
|
|
/*
|
|
* شیشهٔ frosted مثل منوی macOS. blur روی خودِ nav (همان stacking context) است؛
|
|
* این کلاس فقط تهرنگ نیمهشفاف و لبهٔ براق را میسازد.
|
|
*/
|
|
.consumer-bottom-nav-glass {
|
|
border: 1px solid color-mix(in srgb, white 70%, var(--consumer-border));
|
|
border-radius: inherit;
|
|
background:
|
|
linear-gradient(180deg, rgb(255 255 255 / 58%) 0%, rgb(255 255 255 / 22%) 100%),
|
|
color-mix(in srgb, var(--consumer-surface) 62%, transparent);
|
|
box-shadow:
|
|
0 10px 32px rgb(51 58 68 / 14%),
|
|
0 1px 0 rgb(255 255 255 / 78%) inset;
|
|
}
|
|
|
|
.consumer-form-action-bar {
|
|
inset-inline: 0;
|
|
bottom: var(--keyboard-inset, 0px);
|
|
width: 100%;
|
|
max-width: var(--consumer-app-max-width);
|
|
margin-inline: auto;
|
|
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
}
|
|
|
|
.consumer-chat-thread {
|
|
inset-inline: 0;
|
|
width: 100%;
|
|
max-width: var(--consumer-app-max-width);
|
|
margin-inline: auto;
|
|
}
|
|
|
|
.consumer-sticky-action {
|
|
@apply sticky z-20 -mx-4 mt-1 border-t px-4 pt-3;
|
|
bottom: var(--consumer-chrome-bottom);
|
|
/* Keeps bottom actions above the iOS home indicator when no BottomNav exists. */
|
|
padding-bottom: var(--consumer-sticky-pad-bottom);
|
|
border-color: var(--consumer-border);
|
|
background: color-mix(in srgb, var(--consumer-surface) 94%, transparent);
|
|
backdrop-filter: blur(16px);
|
|
}
|
|
|
|
/* Fixed booking/reserve bar — same viewport slot as BottomNav on event detail. */
|
|
.consumer-booking-action-bar {
|
|
@apply fixed inset-x-0 z-50 px-4 py-4;
|
|
bottom: calc(var(--keyboard-inset, 0px));
|
|
width: 100%;
|
|
max-width: var(--consumer-app-max-width);
|
|
margin-inline: auto;
|
|
padding-bottom: max(15px, env(safe-area-inset-bottom, 0px));
|
|
background: transparent;
|
|
backdrop-filter: blur(16px);
|
|
}
|
|
|
|
.consumer-with-booking-action {
|
|
padding-bottom: calc(var(--consumer-bottom-nav-height) + env(safe-area-inset-bottom, 0px) + var(--keyboard-inset, 0px) + 20px);
|
|
}
|
|
|
|
.consumer-chat-composer {
|
|
padding-bottom: max(var(--consumer-sticky-pad-bottom), 12px);
|
|
border-top: 0;
|
|
background: color-mix(in srgb, var(--consumer-surface) 78%, transparent);
|
|
backdrop-filter: blur(16px);
|
|
}
|
|
|
|
.consumer-chat-composer-control {
|
|
min-height: 60px;
|
|
}
|
|
|
|
.consumer-chat-composer-input {
|
|
height: 44px !important;
|
|
min-height: 44px !important;
|
|
border: 0 !important;
|
|
border-radius: 14px !important;
|
|
background: transparent !important;
|
|
}
|
|
|
|
.consumer-chat-composer-input:hover,
|
|
.consumer-chat-composer-input:focus-within,
|
|
.consumer-chat-composer-input[data-focused='true'] {
|
|
border: 0 !important;
|
|
background: var(--consumer-surface-muted) !important;
|
|
}
|
|
|
|
.consumer-chat-composer-send {
|
|
height: 42px !important;
|
|
width: 42px !important;
|
|
min-height: 42px !important;
|
|
min-width: 42px !important;
|
|
border-radius: 14px !important;
|
|
}
|
|
|
|
.consumer-chat-composer-icon {
|
|
height: 40px !important;
|
|
width: 32px !important;
|
|
min-height: 40px !important;
|
|
min-width: 32px !important;
|
|
padding-inline: 0 !important;
|
|
color: var(--consumer-text-muted);
|
|
}
|
|
|
|
.consumer-chat-message-highlight .consumer-chat-message-bubble {
|
|
animation: consumer-chat-message-flash 1.4s ease-out;
|
|
}
|
|
|
|
@keyframes consumer-chat-message-flash {
|
|
0% {
|
|
box-shadow: 0 0 0 0 color-mix(in srgb, var(--consumer-primary, #f97316) 45%, transparent);
|
|
}
|
|
35% {
|
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--consumer-primary, #f97316) 35%, transparent);
|
|
}
|
|
100% {
|
|
box-shadow: 0 0 0 0 transparent;
|
|
}
|
|
}
|
|
|
|
.consumer-chat-reply-preview {
|
|
border: 1px solid var(--consumer-border);
|
|
border-radius: 16px;
|
|
background: var(--consumer-surface);
|
|
}
|
|
|
|
.consumer-deep-header {
|
|
border-bottom: 1px solid var(--consumer-border);
|
|
background: color-mix(in srgb, var(--consumer-surface) 92%, transparent);
|
|
}
|
|
|
|
.consumer-surface {
|
|
border-radius: var(--consumer-radius-surface);
|
|
background: var(--consumer-surface);
|
|
}
|
|
|
|
.consumer-list-card {
|
|
@apply m-2 p-4 transition-[border-color,background-color] hover:border-primary-300;
|
|
border: 1px solid var(--consumer-border);
|
|
border-radius: var(--consumer-radius-card);
|
|
background: var(--consumer-surface);
|
|
}
|
|
|
|
.consumer-event-card {
|
|
transition-property: border-color, transform;
|
|
transition-duration: 300ms;
|
|
}
|
|
|
|
.consumer-event-card-image {
|
|
transition: transform 500ms;
|
|
}
|
|
|
|
.consumer-empty-state {
|
|
@apply mx-auto flex min-h-64 max-w-md flex-col items-center justify-center gap-3 px-6 py-12 text-center;
|
|
background: color-mix(in srgb, var(--consumer-surface) 74%, transparent);
|
|
}
|
|
|
|
.consumer-focus-ring {
|
|
outline: none;
|
|
}
|
|
|
|
.consumer-focus-ring:focus-visible {
|
|
outline: 2px solid var(--consumer-focus);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.consumer-content > section > :first-child:not(header),
|
|
.consumer-content > div > :first-child:not(header) {
|
|
text-align: right;
|
|
}
|
|
|
|
.consumer-content input,
|
|
.consumer-content textarea,
|
|
.consumer-content button,
|
|
.consumer-content [role='tab'] {
|
|
text-align: right;
|
|
}
|
|
|
|
.consumer-content input[type='tel'] {
|
|
text-align: left !important;
|
|
}
|
|
|
|
.consumer-content input[type='tel']:placeholder-shown {
|
|
text-align: right !important;
|
|
}
|
|
}
|
|
|
|
@media (hover: hover) and (pointer: fine) {
|
|
.consumer-event-card:hover {
|
|
transform: translateY(-4px);
|
|
border-color: var(--color-primary-200);
|
|
}
|
|
|
|
.consumer-event-card:hover .consumer-event-card-image {
|
|
transform: scale(1.02);
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.consumer-app *,
|
|
.consumer-app *::before,
|
|
.consumer-app *::after {
|
|
scroll-behavior: auto !important;
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
|
|
@keyframes loading-slide {
|
|
0% {
|
|
transform: translateX(220%);
|
|
}
|
|
50% {
|
|
transform: translateX(-20%);
|
|
}
|
|
100% {
|
|
transform: translateX(-220%);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ToastRegion can portal with dir=ltr when @react-aria/i18n is duplicated.
|
|
* Force physical RTL packing so icon+title sit on the right: [empty][text][icon].
|
|
* z-index 70: above modal overlays (z-60) so toasts stay visible during and after
|
|
* HeroUI view-transition enter/exit (top layer only applies while animating).
|
|
*/
|
|
[data-slot='toast-region'] {
|
|
z-index: 70;
|
|
}
|
|
|
|
[data-slot='toast-region'],
|
|
[data-slot='toast'] {
|
|
direction: rtl !important;
|
|
text-align: right !important;
|
|
}
|
|
|
|
[data-slot='toast'] {
|
|
flex-direction: row !important;
|
|
justify-content: right !important;
|
|
}
|
|
|
|
[data-slot='toast-content'] {
|
|
align-items: flex-start !important;
|
|
text-align: right !important;
|
|
}
|
|
|
|
[data-slot='toast-title'],
|
|
[data-slot='toast-description'] {
|
|
width: 100%;
|
|
text-align: right !important;
|
|
}
|