/* ═════════════════════════════════════════════════════════════
   MIRROR UI PRIMITIVES — Phase 0 step 0.5
   Modal · Toast · Skeleton · Empty state

   Each is derived from the Flutter app widget it ports, cited below.
   The apps are the parity source of truth; this file adapts those
   patterns to a desktop interaction model without inventing a
   different product experience.

   Consumes public/assets/tokens/mirror-tokens.css — no literal
   colour, radius or spacing values may be introduced here.
   ═════════════════════════════════════════════════════════════ */


/* ─────────────────────────────────────────────────────────────
   MODAL / CONFIRMATION
   Ports: lib/app/global/widgets/app_widgets/custom_dialog.dart
     - BackdropFilter blur sigma 5
     - white surface, border-radius 15, padding 12w / 24h
     - title 14sp bold; optional 12sp message carrying the record id
       ("Are you sure you want to cancel reservation number {orderNo}?")
     - button row: CONFIRM is the OUTLINED/recessive treatment
       (transparent bg, 2px brand border, brand text, radius 8) and
       CANCEL is the FILLED/dominant one. That hierarchy is deliberate
       in the app — the safe action dominates — and is preserved here.

   Web adaptation: native <dialog> so focus trap, Escape-to-close and
   inertness come from the platform rather than hand-rolled JS.
   ───────────────────────────────────────────────────────────── */

.mirror-modal {
    border: none;
    padding: 0;
    background: transparent;
    max-width: min(420px, calc(100vw - (2 * var(--mirror-space-4))));
    color: inherit;
}

.mirror-modal::backdrop {
    /* app: BackdropFilter(sigmaX: 5, sigmaY: 5) */
    backdrop-filter: blur(5px);
    background: rgba(0, 0, 0, .35);
}

.mirror-modal__panel {
    background: var(--mirror-surface);
    border-radius: 15px;               /* app: BorderRadius.circular(15) */
    padding: var(--mirror-space-5) var(--mirror-space-3);  /* app: 24h / 12w */
    box-shadow: var(--mirror-shadow-lg);
    text-align: start;
}

.mirror-modal__title {
    font-size: var(--mirror-text-sm);          /* app: 14sp bold */
    font-weight: var(--mirror-weight-bold);
    color: var(--mirror-ink);
    margin: 0;
}

.mirror-modal__message {
    font-size: var(--mirror-text-xs);          /* app: 12sp */
    color: var(--mirror-body);
    margin: var(--mirror-space-4) 0 0;
    line-height: var(--mirror-leading-body);
}

.mirror-modal__actions {
    display: flex;
    gap: var(--mirror-space-2);                /* app: 8.wSpace */
    margin-top: var(--mirror-space-4);         /* app: 16.hSpace */
}

.mirror-modal__btn {
    border-radius: var(--mirror-radius-md);    /* app: radius 8 */
    padding: var(--mirror-space-3) var(--mirror-space-4);
    font-size: var(--mirror-text-sm);
    font-weight: var(--mirror-weight-semibold);
    cursor: pointer;
    line-height: 1;
    transition: background-color .15s ease, color .15s ease;
}

/* CONFIRM — outlined, recessive (app: transparent bg + 2px brand border) */
.mirror-modal__btn--confirm {
    background: transparent;
    color: var(--mirror-brand);
    border: 2px solid var(--mirror-brand);
}
.mirror-modal__btn--confirm:hover {
    background: var(--mirror-brand);
    color: var(--mirror-text-on-brand);
}

/* CANCEL — filled, dominant and flexible (app: Expanded + filled) */
.mirror-modal__btn--cancel {
    flex: 1;
    background: var(--mirror-brand);
    color: var(--mirror-text-on-brand);
    border: 2px solid var(--mirror-brand);
}
.mirror-modal__btn--cancel:hover { background: var(--mirror-brand-dark); border-color: var(--mirror-brand-dark); }

/* Destructive variant — used when the confirmed action deletes data.
   Uses the semantic error role rewired in step 0.3. */
.mirror-modal__btn--confirm.is-destructive {
    color: var(--mirror-error-fg);
    border-color: var(--mirror-error-fg);
}
.mirror-modal__btn--confirm.is-destructive:hover {
    background: var(--mirror-error-fg);
    color: var(--mirror-text-on-brand);
}

.mirror-modal__btn:focus-visible {
    outline: 2px solid var(--mirror-brand);
    outline-offset: 2px;
}


/* ─────────────────────────────────────────────────────────────
   TOAST / FEEDBACK
   Ports: lib/app/global/services/flashbar_helper.dart
     - SnackBarBehavior.floating, backgroundColor Colors.black87
     - 3 second duration
     - leading icon coloured by role: error red / info blue / success green
     - optional trailing action button in the same role colour

   Web adaptation: fixed-position live region so screen readers announce
   it. Non-blocking, dismissible, and it does NOT steal focus.
   ───────────────────────────────────────────────────────────── */

.mirror-toast-region {
    position: fixed;
    inset-block-end: var(--mirror-space-5);
    left: 50%;   /* OD-85 (2026-09-02, R1C-5): physical, to match the physical translateX — was inset-inline-start, a full width off-centre in RTL */
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: var(--mirror-space-2);
    pointer-events: none;
    width: min(520px, calc(100vw - (2 * var(--mirror-space-4))));
}

.mirror-toast {
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: var(--mirror-space-2);                 /* app: SizedBox(width: 8) */
    background: rgba(0, 0, 0, .87);             /* app: Colors.black87 */
    color: #fff;
    border-radius: var(--mirror-radius-md);
    padding: var(--mirror-space-3) var(--mirror-space-4);
    font-size: var(--mirror-text-sm);
    box-shadow: var(--mirror-shadow-md);
    animation: mirror-toast-in .18s ease-out;
}

.mirror-toast__icon { flex: none; display: inline-flex; }
.mirror-toast__text { flex: 1; min-width: 0; }

.mirror-toast--success .mirror-toast__icon { color: var(--mirror-success); }
.mirror-toast--error   .mirror-toast__icon { color: var(--mirror-error); }
.mirror-toast--info    .mirror-toast__icon { color: var(--mirror-info-fg); }

.mirror-toast__dismiss {
    flex: none;
    background: none;
    border: none;
    color: inherit;
    opacity: .7;
    cursor: pointer;
    padding: var(--mirror-space-1);
    line-height: 1;
}
.mirror-toast__dismiss:hover { opacity: 1; }

@keyframes mirror-toast-in {
    from { opacity: 0; transform: translateY(var(--mirror-space-2)); }
    to   { opacity: 1; transform: translateY(0); }
}


/* ─────────────────────────────────────────────────────────────
   SKELETON / LOADING
   Ports: lib/app/global/widgets/shimmer_loading.dart (CustomShimmer)
     - base #EBEBEB, highlight white
     - variants: post (circle + lines), circle, rectangle

   Web adaptation: CSS gradient sweep rather than the shimmer package.
   The app's blocking full-screen loading dialog with a 20-second
   auto-dismiss is deliberately NOT ported — it masks failures. Web
   uses scoped inline pending states instead.
   ───────────────────────────────────────────────────────────── */

.mirror-skeleton {
    --_base: #EBEBEB;                   /* app: baseColor */
    --_highlight: #FFFFFF;              /* app: highlightColor */
    background: var(--_base);
    background-image: linear-gradient(90deg, var(--_base) 0%, var(--_highlight) 50%, var(--_base) 100%);
    background-size: 200% 100%;
    animation: mirror-skeleton-sweep 1.4s ease-in-out infinite;
    border-radius: var(--mirror-radius-md);
    display: block;
}

.mirror-skeleton--circle { border-radius: 50%; aspect-ratio: 1; }
.mirror-skeleton--text   { height: 0.75em; border-radius: var(--mirror-radius-sm); margin-block: 0.25em; }

.mirror-skeleton--post { display: flex; gap: var(--mirror-space-4); align-items: flex-start; background: none; animation: none; }
.mirror-skeleton--post > .mirror-skeleton { flex: none; }

@keyframes mirror-skeleton-sweep {
    from { background-position: 200% 0; }
    to   { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .mirror-skeleton { animation: none; }
    .mirror-toast { animation: none; }
}


/* ─────────────────────────────────────────────────────────────
   EMPTY STATE
   Ports: lib/app/modules/main/tabs/search/view/widgets/empty_data.dart
     - centred illustration, 16px gap, centred caption

   Consolidates the two web forks found at runtime: .portal-empty
   (italic, dashed border) and the ad-hoc .services-empty (unstyled).
   Both are re-pointed at this one component.
   ───────────────────────────────────────────────────────────── */

.mirror-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--mirror-space-4);                 /* app: 16.hSpace */
    padding: var(--mirror-space-7) var(--mirror-space-5);
    text-align: center;
    color: var(--mirror-hint);
}

.mirror-empty__media { max-width: 220px; width: 40%; opacity: .9; }
.mirror-empty__media img,
.mirror-empty__media svg { width: 100%; height: auto; display: block; }

.mirror-empty__text {
    font-size: var(--mirror-text-sm);
    color: var(--mirror-hint);
    margin: 0;
}

.mirror-empty__action { margin-top: var(--mirror-space-2); }


/* ─────────────────────────────────────────────────────────────
   AUTH SURFACE — Phase 2 step (A)

   The guest auth views ship as stock Jetstream components whose
   colours were Tailwind defaults: bg-gray-800 primary button and
   indigo focus rings, plus hard-coded rgba(125,23,71,…) — the
   RETIRED Round 10.57 burgundy #7d1747, which Phase 0's hex sweep
   never caught because it only scanned portal.css and custom.css.

   These classes take over colour/radius from those components so
   every value resolves through the token layer. Layout utilities
   stay on the elements; only the colour utilities were removed, so
   there is no specificity race with Tailwind (which loads after
   this file in layouts/guest.blade.php).

   Ports the Flutter auth visual language:
     brand              constants.dart:9        #711D43
     input radius 12    input_decoration_theme.dart:17,23,29
     pill CTA           CustomButton default radius 50
   ───────────────────────────────────────────────────────────── */

.mirror-auth-btn {
    background: var(--mirror-brand);
    color: var(--mirror-text-on-brand);
    border: 1px solid transparent;
    border-radius: var(--mirror-radius-button);   /* pill — the apps' CustomButton */
    transition: background-color .15s ease;
}
.mirror-auth-btn:hover,
.mirror-auth-btn:focus { background: var(--mirror-brand-dark); }
.mirror-auth-btn:active { background: var(--mirror-brand-dark); }
.mirror-auth-btn:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(var(--mirror-brand-rgb), .25);
}
.mirror-auth-btn:disabled { opacity: .5; }

.mirror-auth-input {
    border: 1px solid var(--mirror-line);
    border-radius: var(--mirror-radius-input);    /* 12px — the apps' value */
    background: var(--mirror-surface);
    color: var(--mirror-ink);
}
.mirror-auth-input:focus {
    outline: none;
    border-color: var(--mirror-brand);
    box-shadow: 0 0 0 3px rgba(var(--mirror-brand-rgb), .15);
}

.mirror-auth-label { color: var(--mirror-body); }

.mirror-auth-checkbox {
    border: 1px solid var(--mirror-line);
    border-radius: var(--mirror-radius-sm);
    accent-color: var(--mirror-brand);
}
.mirror-auth-checkbox:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(var(--mirror-brand-rgb), .15);
}

.mirror-auth-link { color: var(--mirror-brand); }
.mirror-auth-link:hover { color: var(--mirror-brand-dark); }

/* Card + logo — replaces the inline retired-burgundy rgba() values. */
.mirror-auth-canvas {
    background:
        radial-gradient(circle at 50% 30%, rgba(var(--mirror-brand-rgb), .08), transparent 30%),
        linear-gradient(135deg, var(--mirror-legacy-cream) 0%, var(--mirror-surface) 46%, var(--mirror-legacy-tint) 100%);
    /* Tailwind's .font-sans still resolves to Figtree via tailwind.config.js,
       which is no longer loaded. Point the auth surface at the shared token
       stack instead so it matches the portals rather than falling through to
       an arbitrary system default. */
    font-family: var(--mirror-font-sans);
}
.mirror-auth-card {
    background: var(--mirror-surface);
    border: 1px solid rgba(var(--mirror-brand-rgb), .10);
    box-shadow: var(--mirror-shadow-lg);
}
.mirror-auth-logo-plate {
    background: var(--mirror-surface);
    border: 1px solid rgba(var(--mirror-brand-rgb), .16);
    border-radius: 28px;
    box-shadow: 0 18px 45px rgba(var(--mirror-brand-rgb), .14);
}
.mirror-auth-wordmark {
    color: var(--mirror-brand);
    letter-spacing: .32em;
}

/* Error summary + inline field errors — the semantic error role. */
.mirror-auth-error { color: var(--mirror-error-fg); }


/* ─────────────────────────────────────────────────────────────
   SOCIAL SIGN-IN — Phase 2 step (E)

   Ports the social row on the app's sign-in screen
   (signin_screen.dart:330-359): a separated block beneath the form.

   The app renders icon-only circular buttons. Web uses a labelled
   full-width button instead: an unlabelled icon is an undiscoverable
   affordance on desktop, and "Continue with Google" is the pattern
   users expect. Same action, same placement, same product intent.

   Web shows GOOGLE ONLY — Apple is credential-blocked (.env is frozen
   and carries no APPLE_* keys) and Facebook is commented out in the
   app itself (signin_screen.dart:360-374). Showing either would be
   inventing product surface the source of truth does not have.
   ───────────────────────────────────────────────────────────── */

.mirror-auth-social {
    margin-top: var(--mirror-space-5);
    padding-top: var(--mirror-space-4);
    border-top: 1px solid var(--mirror-line-soft);
}

.mirror-auth-social__btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--mirror-space-3);
    width: 100%;
    padding: var(--mirror-space-3) var(--mirror-space-4);
    border: 1px solid var(--mirror-line);
    border-radius: var(--mirror-radius-button);
    background: var(--mirror-surface);
    color: var(--mirror-ink);
    font-size: var(--mirror-text-sm);
    font-weight: var(--mirror-weight-semibold);
    text-decoration: none;
    transition: background-color .15s ease, border-color .15s ease;
}
.mirror-auth-social__btn:hover {
    background: var(--mirror-canvas, #f8f8f8);
    border-color: var(--mirror-line-strong);
}
.mirror-auth-social__btn:focus-visible {
    outline: 2px solid var(--mirror-brand);
    outline-offset: 2px;
}
.mirror-auth-social__icon { flex: none; width: 18px; height: 18px; }

/* Guest-layout language toggle — replaces two hard-coded #7d1747 arbitrary
   Tailwind values (the retired Round 10.57 burgundy) with the brand token. */
.mirror-auth-lang-toggle {
    background: var(--mirror-surface);
    color: var(--mirror-brand);
    border: 1px solid rgba(var(--mirror-brand-rgb), .20);
}
