/*
The member portal's own bundle.

`source(none)` is the whole point. app.css and website.css are each a bare
`@import 'tailwindcss'` plus one @theme block, so Tailwind v4 auto-detects from
the project root and both emit the identical complete utility set — website.css
is app.css plus components. A third file written the same way would be a third
identical copy, and "its own bundle" would isolate nothing at all.

With source(none) plus explicit @source lines, this file contains only what the
portal's own templates use.

Never load this alongside app.css on one document: two Tailwind entrypoints mean
two preflights and a non-deterministic @layer order. The QR scanner screen is an
admin screen and builds with app.css.
*/
@import 'tailwindcss' source(none);

/*
The layouts come first and are not optional: every utility that appears only in
the shell — the header, the tab bar, the centred column — lives there and
nowhere else. Leaving them out builds a stylesheet that styles the content and
forgets the frame, which is exactly how a 32px logo renders at its natural size.
*/
@source '../views/layouts/portal.blade.php';
@source '../views/layouts/portal-public.blade.php';
@source '../views/portal/**/*.blade.php';
@source '../views/livewire/portal/**/*.blade.php';
@source '../views/components/portal/**/*.blade.php';
@source '../../app/Livewire/Portal/**/*.php';

/*
Classes built by interpolation never appear whole in a template, so the scanner
cannot see them. These are the status and tone variants the portal composes.
*/
@source inline('bg-brand-{50,100,500,600,700} text-brand-{600,700,fg} border-brand-{200,300} ring-brand-500');
@source inline('bg-{emerald,amber,rose,slate,sky}-{50,100,500,600} text-{emerald,amber,rose,slate,sky}-{600,700,800} border-{emerald,amber,rose,slate,sky}-200');

/*
`inline` matters: without it Tailwind copies the variable's value at build time
and every tenant would get whatever colour was in the build. With it the utility
emits var(--brand-500), which the layout's server-rendered :root block fills in
per tenant, per request.
*/
@theme inline {
    --color-brand-50:  var(--brand-50);
    --color-brand-100: var(--brand-100);
    --color-brand-200: var(--brand-200);
    --color-brand-300: var(--brand-300);
    --color-brand-400: var(--brand-400);
    --color-brand-500: var(--brand-500);
    --color-brand-600: var(--brand-600);
    --color-brand-700: var(--brand-700);
    --color-brand-800: var(--brand-800);
    --color-brand-900: var(--brand-900);
    --color-brand-fg:  var(--brand-fg);

    --color-brand-success: var(--brand-success);
    --color-brand-warning: var(--brand-warning);
    --color-brand-danger:  var(--brand-danger);

    --font-sans: var(--brand-font-ar), var(--brand-font-en), ui-sans-serif, system-ui, sans-serif;

    --radius-card: 1rem;
    --radius-sheet: 1.5rem;
}

/* Bound to the class, not to prefers-color-scheme: the tenant's theme_mode
   setting decides, and the OS does not get a vote it was never given. */
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));

@layer base {
    :root {
        color-scheme: light;
    }

    /*
    Focus is never removed here, and it is stated rather than left to the
    browser: the default ring is a thin blue line that vanishes against a
    tenant whose brand is blue. `currentColor` inherits the text colour, which
    has already been contrast-checked against its own background, so the ring
    is legible on every surface in the app and in either theme.

    :focus-visible, not :focus — a mouse user tapping a card should not get a
    ring, and a keyboard user always should.
    */
    :focus-visible {
        outline: 2px solid currentColor;
        outline-offset: 2px;
        border-radius: 4px;
    }

    /* A focused control must not end up underneath the sticky header or the
       bottom tab bar when the page scrolls to it (WCAG 2.4.11). */
    :focus {
        scroll-margin-top: 5rem;
        scroll-margin-bottom: 6rem;
    }

    [data-theme='dark'] {
        color-scheme: dark;
    }

    body {
        /* A phone-shaped surface, not a page. */
        -webkit-tap-highlight-color: transparent;
        overscroll-behavior-y: none;
    }

    /* Numbers read left-to-right even inside an RTL document. */
    .num {
        direction: ltr;
        unicode-bidi: isolate;
        font-variant-numeric: tabular-nums;
    }
}

@layer components {
    /* Safe areas: this runs full-bleed inside a WebView and under a notch. */
    .pt-safe { padding-top: env(safe-area-inset-top, 0px); }
    .pb-safe { padding-bottom: env(safe-area-inset-bottom, 0px); }

    /*
    The brand mark is sized in CSS, not in utilities. A tenant uploads whatever
    it has — a square crest, a wide wordmark, a 2000px PNG — and the shell has
    to survive all three. Height is fixed, width follows the aspect ratio, and
    the cap stops a wide wordmark from eating the header.
    */
    .portal-logo {
        height: 2rem;
        width: auto;
        max-width: 7.5rem;
        object-fit: contain;
        object-position: center;
    }

    .portal-card {
        border-radius: var(--radius-card);
        background: var(--portal-surface);
        border: 1px solid var(--portal-border);
    }

    /* Visually hidden but available to a screen reader — for the text that
       names an icon-only control where an aria-label would be the wrong tool. */
    .visually-hidden {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }

    /* 44x44 minimum with 8px between, per the accessibility gate. */
    .tap-target {
        min-width: 2.75rem;
        min-height: 2.75rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /*
    A horizontal scroller, and only that.

    It used to also pad itself by 1rem and pull itself back out by -1rem — the
    bleed trick for a rail sitting inside a padded column. Its one caller is the
    profile switcher, which sits in the header with no padding to cancel and
    supplies its own, so the negative margins had nothing to subtract from and
    made the element 2rem wider than the viewport. That is what was scrolling
    every portal screen sideways and cutting the first tab off the tab bar.

    Spacing belongs to the element, not to the scroll behaviour.
    */
    .rail {
        display: flex;
        gap: 0.75rem;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
    }

    .rail::-webkit-scrollbar { display: none; }
    .rail > * { scroll-snap-align: start; flex: 0 0 auto; }
}

/*
Every animation here is a spatial cue — where a card went — and every one of
them stops for a viewer who has asked for less motion.
*/
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

@layer utilities {
    .sheet-enter {
        animation: portal-sheet-in 260ms cubic-bezier(0.32, 0.72, 0, 1);
    }

    @keyframes portal-sheet-in {
        from { transform: translateY(8%); opacity: 0; }
        to   { transform: translateY(0);  opacity: 1; }
    }

    .stagger-in > * {
        animation: portal-fade-up 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
    }

    .stagger-in > *:nth-child(1) { animation-delay: 0ms; }
    .stagger-in > *:nth-child(2) { animation-delay: 40ms; }
    .stagger-in > *:nth-child(3) { animation-delay: 80ms; }
    .stagger-in > *:nth-child(4) { animation-delay: 120ms; }
    .stagger-in > *:nth-child(n+5) { animation-delay: 160ms; }

    @keyframes portal-fade-up {
        from { transform: translateY(6px); opacity: 0; }
        to   { transform: translateY(0);   opacity: 1; }
    }
}
