/* =============================================================================
   Motaleb E-File - Filament v5 admin panel visual overrides
   -----------------------------------------------------------------------------
   This project has no Vite/Tailwind pipeline (legacy Laravel Mix + Bootstrap 4),
   so a Filament custom theme cannot be compiled. This file is plain, hand-written
   CSS injected into every panel page through the `panels::head.end` render hook
   registered in app/Providers/Filament/AdminPanelProvider.php. No build step.

   IMPORTANT - why this file barely needs `!important`:
   Filament v5 ships its CSS inside real CSS cascade layers
   (`@layer base | components | utilities`). Unlayered CSS - which this file is,
   because it declares no `@layer` - always beats layered CSS regardless of
   specificity. `!important` is still used on the two content-width declarations
   as belt-and-braces in case a future build flattens those layers.

   Dark mode: Filament v5 toggles dark mode with a `dark` class on the <html>
   element (`:root.dark { color-scheme: dark }` in its base.css) and it sets that
   class for the OS preference too. So `prefers-color-scheme` is deliberately NOT
   used here: it would paint dark shadows on a light UI whenever a user with a
   dark OS explicitly picks the light theme. `.fi-theme-dark` and
   `[data-theme='dark']` are included only as harmless forward-compatible extras.

   Brand colour: every accent in this file derives from `--ac-brand`, which the
   panel provider re-declares per request from Site Settings -> Brand Colour in a
   <style> tag emitted *after* this file's <link>. The value below is therefore
   only the fallback. Shades are produced with color-mix() rather than a hard-
   coded ramp so one hex is genuinely enough.

   Everything below is written so that a selector that does not match is simply
   inert - no rule depends on another rule's selector matching.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */

:root {
    /* Content width. Set to a length (e.g. 110rem) to re-introduce a cap on
       ultra-wide monitors; 100% means "use the whole screen". */
    --ac-main-max-width: 100%;

    /* Horizontal gutter of the content area. Filament's defaults are
       1rem / 1.5rem / 2rem - these are deliberately tighter. */
    --ac-main-gutter: 0.75rem;

    /* Brand colour. Overridden per request by the panel provider. */
    --ac-brand: #f59e0b;

    /* Kept as its own name because the sidebar rules below were written against
       it; it now simply follows the brand. */
    --ac-accent: var(--ac-brand);

    /* THE SECOND HUE, AND THE REASON THE SIDEBAR AND THE WALLPAPER MATCH.
       -------------------------------------------------------------------------
       Section 8's animated background is painted from two hues: the brand colour
       and the brand nudged towards indigo, because two hues make a gradient
       readable where one is just a smudge. That second hue used to be spelled
       out inside `--ac-bg-cool` and nowhere else, which is why the navigation
       looked like it had been designed by somebody who had never seen the page
       it sits on. It is hoisted here so the sidebar, the menu items and the
       wallpaper are all mixing from the SAME two colours - and so that an
       install picking a new brand colour moves all three together.

       Indigo rather than a literal blue, and derived rather than fixed, for the
       reason the background note gives: a hard-coded second hue cannot be
       guaranteed not to clash with a brand colour nobody has picked yet. */
    --ac-brand-cool: color-mix(in oklab, var(--ac-brand) 45%, #6366f1);

    /* Which way the menu washes below run.
       -------------------------------------------------------------------------
       A gradient angle cannot be written logically - there is no `to
       inline-end` - so the one thing that differs between LTR and RTL is
       lifted into a variable and flipped in a single rule down in section 4,
       rather than every gradient in this file being written out twice. */
    --ac-menu-wash-angle: 90deg;

    /* Sidebar surface + edge shadow (light theme). */
    --ac-sidebar-surface: #ffffff;
    --ac-sidebar-shadow:
        1px 0 0 0 rgb(15 23 42 / 0.06),
        6px 0 18px -8px rgb(15 23 42 / 0.18);
    --ac-sidebar-divider: rgb(15 23 42 / 0.08);

    /* The faintest possible tint on the sidebar panel itself, in the two brand
       hues and in the same corners the wallpaper puts them: warm at the top of
       the menu, cool at the bottom. It is deliberately weaker than anything else
       in this file - the sidebar is a surface that TEXT sits on, and its job is
       to belong to the page behind it rather than to be looked at. Anything
       stronger and every label on it starts fighting a colour. */
    --ac-sidebar-wash:
        radial-gradient(125% 45% at 0% 0%, color-mix(in oklab, var(--ac-brand) 9%, transparent) 0%, transparent 70%),
        radial-gradient(115% 40% at 100% 100%, color-mix(in oklab, var(--ac-brand-cool) 7%, transparent) 0%, transparent 72%);

    /* Menu foreground scale (light theme).
       Filament's own inactive item colour is a light gray that reads fine on
       white but goes muddy the moment the sidebar sits on a tinted surface, so
       the whole scale is pinned here for both themes rather than patched in one. */
    --ac-menu-fg: #334155;          /* slate-700  - resting label   */
    --ac-menu-fg-strong: #0f172a;   /* slate-900  - hover label     */
    --ac-menu-group-fg: #64748b;    /* slate-500  - group heading   */

    /* HOVER IS BRAND-TINTED RATHER THAN GREY, and that is the whole change.
       -------------------------------------------------------------------------
       This used to be a flat `rgb(15 23 42 / 0.05)`, i.e. a smear of the page's
       neutral - correct, invisible, and the same on every install whatever brand
       colour the office had chosen. The fill below is the brand at a strength
       that still reads as "the mouse is here" rather than as "this one is
       selected": the ACTIVE item has to stay the loudest thing in the sidebar,
       so resting, hovered and active now step up in three clearly separated
       weights instead of two.

       The wash on top of it is where the second hue arrives. It is a separate
       token, and it is applied to a pseudo-element rather than to the button,
       because `background-image` DOES NOT TRANSITION - a gradient swapped in on
       :hover appears in one frame, however long the transition is set to. Fading
       a layer's opacity is the only way to get a gradient to arrive gently, and
       section 4 explains how that layer is kept behind the label. */
    --ac-menu-hover-bg: color-mix(in oklab, var(--ac-brand) 8%, transparent);
    --ac-menu-hover-wash: linear-gradient(
        var(--ac-menu-wash-angle),
        color-mix(in oklab, var(--ac-brand) 14%, transparent) 0%,
        color-mix(in oklab, var(--ac-brand-cool) 8%, transparent) 60%,
        transparent 100%);

    /* Active item. The foreground is mixed towards near-black so it stays
       readable even when an admin picks a very light brand colour.

       42% AND NOT THE 55% THIS WAS. The fill underneath it got stronger when the
       wash below was added, and measured on the composited result - sidebar
       wash, then active fill, then the wash's strongest stop - the old label
       came out at 4.24:1, under the 4.5:1 small text needs. Mixing a further 13%
       of slate-900 into it costs nothing anybody can see and takes the same
       measurement to 5.75:1. If the active fill is ever restrengthened, this is
       the number that has to move with it, and it has to be measured against the
       three layers composited rather than against the fill alone. */
    --ac-menu-active-fg: color-mix(in oklab, var(--ac-brand) 42%, #0f172a);
    --ac-item-active-bg: color-mix(in oklab, var(--ac-brand) 14%, transparent);
    --ac-item-active-wash: linear-gradient(
        var(--ac-menu-wash-angle),
        color-mix(in oklab, var(--ac-brand) 20%, transparent) 0%,
        color-mix(in oklab, var(--ac-brand-cool) 12%, transparent) 58%,
        color-mix(in oklab, var(--ac-brand) 4%, transparent) 100%);
    --ac-item-active-bar: 0.1875rem; /* 3px accent bar */

    /* The bar itself is a two-stop gradient rather than a flat accent, which is
       what stops a 3px sliver of solid colour reading as a border. Vertical, so
       it needs no RTL counterpart. */
    --ac-menu-bar-image: linear-gradient(180deg, var(--ac-brand) 0%, var(--ac-brand-cool) 100%);

    /* The lift under the active item is now tinted with the brand instead of
       being a neutral drop shadow: a coloured shadow reads as the item GLOWING,
       which is the cheapest way to make one row of a menu feel lit. The first,
       tight shadow stays neutral - that one is doing the actual edge definition,
       and a coloured hairline there just looks like a printing error. */
    --ac-item-active-shadow:
        0 1px 2px 0 rgb(15 23 42 / 0.08),
        0 6px 14px -8px color-mix(in oklab, var(--ac-brand) 50%, transparent);

    /* How long a menu item takes to react. Short enough that the sidebar never
       feels laggy under a fast mouse running down a list of twenty items, long
       enough that the colour arrives rather than snaps. Held as a token because
       four separate properties on three selectors have to agree on it, and
       because the reduced-motion block in section 9 then only has one number to
       take away. */
    --ac-menu-transition: 170ms;

    /* Login screen (light theme). */
    --ac-login-brand-width: min(46%, 33rem);
    --ac-login-page-bg: #f6f7fb;
    --ac-login-card-bg: #ffffff;
    --ac-login-card-border: rgb(15 23 42 / 0.07);
    --ac-login-card-shadow: 0 30px 70px -40px rgb(15 23 42 / 0.55);

    /* Brand shades for the login artwork. Mixing towards a deep navy rather
       than towards pure black keeps light brand colours (yellow, lime, cyan)
       dark enough for white text to stay legible. */
    --ac-brand-mid: color-mix(in oklab, var(--ac-brand) 74%, #0b1120);
    --ac-brand-deep: color-mix(in oklab, var(--ac-brand) 42%, #0b1120);
    --ac-brand-glow: color-mix(in oklab, var(--ac-brand) 70%, #ffffff);

    /* Sticky table actions column (section 6). A sticky cell floats over the
       columns scrolling beneath it, so it needs an OPAQUE fill of its own -
       "no background" means the row underneath reads straight through it.
       These two mirror what Filament paints on the elements involved:
         surface     = `.fi-ta-ctn { bg-white }`
         surface-alt = `bg-gray-50` - the striped/hovered/selected row, and the
                       header row.
       The panel pins `gray` to Color::Slate (see AdminPanelProvider::colors),
       so gray-50 is slate-50 and the literal below is exact. */
    --ac-ta-sticky-surface: #ffffff;
    --ac-ta-sticky-surface-alt: #f8fafc;    /* slate-50 */
    --ac-ta-sticky-edge: rgb(15 23 42 / 0.08);
    --ac-ta-sticky-shade: rgb(15 23 42 / 0.24);

    /* Verification row tints (light theme).
       -------------------------------------------------------------------------
       Mixed from the same two hues Filament's own `success` and `danger` resolve
       to, rather than picked by eye, so a green row and a green badge in the
       same row are the same green.

       DELIBERATELY THIS PALE. The tint has to survive being read THROUGH: every
       cell of the row sits on top of it, and a saturated fill turns slate-950
       body text into something that has to be squinted at. 8% is enough to tell
       two rows apart at a glance down a column of a hundred and not enough to
       compete with what is written on them. The hover step is roughly double,
       which is what makes the row still feel like it responds to a mouse - the
       tint replaces Filament's own hover fill, so without it the row would go
       inert under the cursor. */
    --ac-row-complete-bg: color-mix(in srgb, #16a34a 8%, #ffffff);
    --ac-row-complete-bg-hover: color-mix(in srgb, #16a34a 15%, #ffffff);
    --ac-row-incomplete-bg: color-mix(in srgb, #dc2626 8%, #ffffff);
    --ac-row-incomplete-bg-hover: color-mix(in srgb, #dc2626 15%, #ffffff);
}

@media (min-width: 48rem) {
    :root {
        --ac-main-gutter: 1rem;
    }
}

@media (min-width: 64rem) {
    :root {
        --ac-main-gutter: 1.25rem;
    }
}

/* Dark theme token overrides.
   -----------------------------------------------------------------------------
   THIS BLOCK MUST OUT-SPECIFY `:root`, and that is why it is not written as
   `:where(.dark, ...)`. `:where()` contributes zero specificity, so a
   `:where(.dark)` block scores (0,0,0) while the `:root` block above scores
   (0,1,0) - `:root` is a pseudo-class, not an element. Source order only settles
   ties at *equal* specificity, so a `:where()` version of this block loses every
   single declaration and the panel keeps its light tokens in dark mode: a white
   sidebar sitting on a near-black page, with the light theme's low-contrast
   label colours on top of it.

   `:root.dark` scores (0,2,0) and wins. Filament v5 puts the `dark` class on
   <html>, so `:root.dark` is the case that actually fires; the descendant forms
   are harmless extras in case a future release moves the class further down. */
:root.dark,
:root.fi-theme-dark,
:root[data-theme='dark'],
:root .dark,
:root .fi-theme-dark,
:root [data-theme='dark'] {
    --ac-sidebar-surface: #0f172a; /* gray-900, one step above the gray-950 page */
    --ac-sidebar-shadow:
        1px 0 0 0 rgb(255 255 255 / 0.06),
        8px 0 22px -10px rgb(0 0 0 / 0.70);
    --ac-sidebar-divider: rgb(255 255 255 / 0.08);

    /* Roughly half again as strong as the light one, which is the same finding
       as everywhere else in this file: a tint on a near-black surface has to add
       light to be seen at all, and the percentage that reads as a soft wash on
       white reads as nothing here. */
    --ac-sidebar-wash:
        radial-gradient(125% 45% at 0% 0%, color-mix(in oklab, var(--ac-brand) 14%, transparent) 0%, transparent 70%),
        radial-gradient(115% 40% at 100% 100%, color-mix(in oklab, var(--ac-brand-cool) 11%, transparent) 0%, transparent 72%);

    /* The contrast fix. On the dark sidebar surface Filament's resting label is
       around #94a3b8, which fails against #0f172a for small text; these lift it
       to a comfortable ratio without making every item shout. */
    --ac-menu-fg: #cbd5e1;         /* slate-300 */
    --ac-menu-fg-strong: #f8fafc;  /* slate-50  */
    --ac-menu-group-fg: #94a3b8;   /* slate-400 */

    /* The dark hover fill is the brand at double the light theme's strength,
       for the reason above - but it is still a TRANSLUCENT brand rather than the
       plain `rgb(255 255 255 / 0.07)` it replaces, so hovering a row here tints
       it the same way it does in the light theme instead of just making it
       paler. The wash percentages step up with it. */
    --ac-menu-hover-bg: color-mix(in oklab, var(--ac-brand) 16%, transparent);
    --ac-menu-hover-wash: linear-gradient(
        var(--ac-menu-wash-angle),
        color-mix(in oklab, var(--ac-brand) 20%, transparent) 0%,
        color-mix(in oklab, var(--ac-brand-cool) 14%, transparent) 60%,
        transparent 100%);

    /* Mixed towards white here, the mirror of the light theme's mix towards
       black - a saturated brand colour is unreadable on a dark tint otherwise. */
    --ac-menu-active-fg: color-mix(in oklab, var(--ac-brand) 42%, #ffffff);

    /* THE FILL COMES DOWN FROM 22% AND THE WASH MAKES UP THE DIFFERENCE, which
       is not a taste decision either: the layers composite. A 22% fill under a
       26% wash lights the row up to rgb(129, 92, 30) and leaves the pale label
       above at 4.58:1 - passing, with nothing in hand for an install whose brand
       colour is brighter than amber. Split as below it lands at rgb(114, 81, 27)
       and 5.37:1, and looks no less lit, because what makes it read as lit is
       the coloured glow rather than the fill. */
    --ac-item-active-bg: color-mix(in oklab, var(--ac-brand) 16%, transparent);
    --ac-item-active-wash: linear-gradient(
        var(--ac-menu-wash-angle),
        color-mix(in oklab, var(--ac-brand) 22%, transparent) 0%,
        color-mix(in oklab, var(--ac-brand-cool) 15%, transparent) 58%,
        color-mix(in oklab, var(--ac-brand) 5%, transparent) 100%);

    /* The glow has to be stronger AND the black shadow has to stay: on a dark
       surface the coloured halo is the only part that is visible, and the black
       is what still separates the row from the panel it sits on. */
    --ac-item-active-shadow:
        0 1px 2px 0 rgb(0 0 0 / 0.45),
        0 6px 16px -8px color-mix(in oklab, var(--ac-brand) 60%, transparent);

    --ac-login-page-bg: #030712;
    --ac-login-card-bg: #0f172a;
    --ac-login-card-border: rgb(255 255 255 / 0.08);
    --ac-login-card-shadow: 0 30px 70px -35px rgb(0 0 0 / 0.85);

    /* Dark counterparts of the sticky-cell fills. `.fi-ta-ctn` is
       `dark:bg-gray-900`, and every tinted row state is `dark:bg-white/5` - a
       TRANSLUCENT overlay, which is precisely what a sticky cell cannot use.
       color-mix() flattens that 5% white onto the surface underneath it, so the
       cell ends up the colour the row appears to be while still being opaque. */
    --ac-ta-sticky-surface: #0f172a;        /* slate-900 */
    --ac-ta-sticky-surface-alt: color-mix(in srgb, #ffffff 5%, #0f172a);
    --ac-ta-sticky-edge: rgb(255 255 255 / 0.10);
    --ac-ta-sticky-shade: rgb(0 0 0 / 0.55);

    /* Dark counterparts of the verification tints. Mixed onto slate-900 - the
       table's own dark surface - rather than onto white, and from the LIGHTER
       500-weight hues: a dark-mode tint has to add light to be seen at all, so
       the same 600-weight greens that read as a wash on white read as mud here.

       THE PERCENTAGES ARE MUCH HIGHER THAN THE LIGHT ONES AND THAT IS NOT A
       TASTE DECISION. slate-900 is not a neutral grey, it is a BLUE - #0f172a is
       (15, 23, 42), half again as much blue as red. Mixed at the 8% the light
       theme uses, the base's own blue channel stays the largest one in the
       result and both rows come out a slightly different navy: measured on the
       real table, a 12% green gave (0.068, 0.172, 0.189) - more blue than green
       - and a 12% red gave (0.164, 0.111, 0.177), more blue than red. A green
       row that is teal and a red row that is purple are not a subtle problem;
       they are two colours nobody can name, which is the entire job the tint
       has.

       25% is where the intended channel overtakes the base's blue with room to
       spare (green -> (0.077, 0.261, 0.216), red -> (0.278, 0.135, 0.191)).
       Text stays comfortably readable: the body colour in dark mode is
       near-white, so contrast against a fill this dark is still enormous. If
       these are ever retuned, measure the computed colour rather than trusting
       the swatch - that is what caught it. */
    --ac-row-complete-bg: color-mix(in srgb, #22c55e 25%, #0f172a);
    --ac-row-complete-bg-hover: color-mix(in srgb, #22c55e 35%, #0f172a);
    --ac-row-incomplete-bg: color-mix(in srgb, #ef4444 25%, #0f172a);
    --ac-row-incomplete-bg-hover: color-mix(in srgb, #ef4444 35%, #0f172a);
}

/* -----------------------------------------------------------------------------
   2. Full-width content
   -----------------------------------------------------------------------------
   Filament renders the page body as
   `<main id="fi-main-content" class="fi-main fi-width-7xl">`, and its CSS has
   `.fi-main { margin-inline: auto; padding-inline: 1rem/1.5rem/2rem }` plus
   `.fi-width-7xl { max-width: 80rem }`. That 80rem cap is the large empty
   margin on both sides of every table. `->maxContentWidth(Width::Full)` in the
   panel provider swaps the class to `.fi-width-full`; the rules below make the
   result correct even if that PHP call ever stops taking effect.
   -------------------------------------------------------------------------- */

.fi-main {
    max-width: var(--ac-main-max-width) !important;
    padding-inline: var(--ac-main-gutter) !important;
}

/* The topbar is a sibling of the content, with its own `px-4`. Match it to the
   content gutter so the brand/user menu line up with the table edges. */
.fi-topbar {
    padding-inline: var(--ac-main-gutter);
}

/* Content column must be free to consume the space the width cap gave back. */
.fi-main-ctn {
    min-width: 0;
    width: 100%;
}

/* Tables fill the widened content column; horizontal scrolling for wide tables
   is Filament's own `.fi-ta-content` behaviour and is left untouched. */
.fi-ta-ctn {
    width: 100%;
}

/* Guard: the login screen uses the *simple* layout (`.fi-simple-main`), which
   has its own width setting and must stay a narrow centred card. It does not
   carry `.fi-main`, but this keeps it narrow even if that ever changes. */
.fi-simple-main.fi-main {
    max-width: 32rem !important;
}

/* -----------------------------------------------------------------------------
   3. Sidebar surface + edge shadow
   -----------------------------------------------------------------------------
   Below the `lg` breakpoint the sidebar is an off-canvas overlay and Filament
   already gives it `bg-white dark:bg-gray-900`, `shadow-xl` and a ring - that is
   left completely alone so mobile/tablet behaviour cannot break.

   From `lg` up, Filament makes the sidebar `bg-transparent` and removes the
   shadow (`lg:bg-transparent lg:shadow-none lg:ring-0`), so the sidebar blends
   into the page. A shadow on a transparent element would read as a stray smudge,
   so the desktop sidebar gets back the same surface colour Filament already uses
   for it on mobile, plus a soft edge shadow.

   Scoped to `.fi-sidebar-open` on purpose: when the sidebar is collapsed on
   desktop Filament moves it off-screen with `-translate-x-full` rather than
   shrinking it, and an unscoped shadow would bleed a few pixels back into view.
   -------------------------------------------------------------------------- */

@media (min-width: 64rem) {
    .fi-sidebar.fi-sidebar-open {
        background-color: var(--ac-sidebar-surface);
        /* The two brand hues, at the two corners the wallpaper puts them. An
           opaque panel over an animated background is a hole in the artwork
           unless it is tinted from the same palette; this is what closes it.
           Painted on the sidebar element and not on the scrolling list inside
           it, so the tint stays put while a long menu scrolls through it -
           a wash that scrolls reads as content, not as a surface. */
        background-image: var(--ac-sidebar-wash);
        box-shadow: var(--ac-sidebar-shadow);
    }

    [dir='rtl'] .fi-sidebar.fi-sidebar-open {
        box-shadow:
            -1px 0 0 0 rgb(15 23 42 / 0.06),
            -6px 0 18px -8px rgb(15 23 42 / 0.18);
    }

    :where(.dark, .fi-theme-dark, [data-theme='dark'])[dir='rtl'] .fi-sidebar.fi-sidebar-open,
    :where(.dark, .fi-theme-dark, [data-theme='dark']) [dir='rtl'] .fi-sidebar.fi-sidebar-open {
        box-shadow:
            -1px 0 0 0 rgb(255 255 255 / 0.06),
            -8px 0 22px -10px rgb(0 0 0 / 0.70);
    }
}

/* Hairline under the brand block so the logo does not float into the menu.
   Inert if the class is ever renamed. */
.fi-sidebar-header {
    border-bottom: 1px solid var(--ac-sidebar-divider);
}

/* -----------------------------------------------------------------------------
   4. Menu items - readable in both themes
   -----------------------------------------------------------------------------
   Markup is `<li class="fi-sidebar-item fi-active"><a class="fi-sidebar-item-btn">`.

   The colour is set on the *button* and the label/icon are told to inherit, so
   one declaration covers the row even if a child class is renamed. Badges are
   deliberately not included - they carry their own semantic colour.

   Three selectors are listed for the same element on purpose, so a rename of any
   single class still leaves the effect working:
     - `.fi-sidebar-item.fi-active > .fi-sidebar-item-btn`  (verified v5.7.5)
     - `.fi-sidebar-item.fi-active > a`                     (button class renamed)
     - `.fi-sidebar-item > .fi-sidebar-item-btn[aria-current='page']` (state renamed)
   The child combinator keeps a collapsible *group* header from being highlighted
   alongside the item that is actually active.

   EVERY ITEM CARRIES TWO PSEUDO-ELEMENTS, and it is worth saying up front what
   each is for, because between them they are most of this section:

     ::before  the accent bar on the inline-start edge. It exists at rest (at
               zero opacity and squashed), grows to half height under the cursor
               and to full height when the item is the current page - so the bar
               is one continuous thing that responds, rather than a border that
               blinks into existence. Placed with `inset-inline-start`, so RTL
               costs nothing.
     ::after   the two-hue gradient wash. It is a layer purely so its OPACITY can
               be transitioned: `background-image` is not an animatable property,
               and a gradient assigned on :hover therefore arrives in a single
               frame no matter what the transition says. This is also why the
               button keeps a plain `background-color` underneath - that one does
               interpolate, and it is what carries the first half of the fade.

   HOW THE WASH STAYS BEHIND THE LABEL. A positioned pseudo-element paints above
   its parent's in-flow text, so `::after` would otherwise be a film of colour
   over every menu label. `isolation: isolate` on the button makes it a stacking
   context, and inside a stacking context the order is: the element's own
   background, then negative-z descendants, then the in-flow content. So the
   button's fill, then the wash, then the text - exactly the three layers wanted,
   with no z-index on anything that Filament owns.
   -------------------------------------------------------------------------- */

.fi-sidebar-item > .fi-sidebar-item-btn,
.fi-sidebar-item > a {
    color: var(--ac-menu-fg);
    /* Both pseudo-elements below are positioned against this, and the isolation
       is what keeps the wash under the label - see the note above. */
    position: relative;
    isolation: isolate;
    transition-property: background-color, box-shadow, color;
    transition-duration: var(--ac-menu-transition);
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

/* The accent bar.
   -----------------------------------------------------------------------------
   INSET FROM THE TOP AND BOTTOM RATHER THAN FLUSH, for a reason that is only
   obvious once it is wrong: Filament rounds the corners of these buttons, and a
   3px bar hard against the inline-start edge pokes out past the curve at both
   ends. Pulled in by 5px it is a pill inside the rounded rectangle instead, which
   is also simply the better-looking of the two.

   Scaled rather than resized. `transform` is composited, so the growth costs a
   matrix multiply; animating `height` would relayout the button on every frame of
   every hover, twenty times as the mouse runs down the menu. */
.fi-sidebar-item > .fi-sidebar-item-btn::before,
.fi-sidebar-item > a::before {
    content: '';
    position: absolute;
    inset-block: 0.3125rem;
    inset-inline-start: 0;
    width: var(--ac-item-active-bar);
    border-radius: 999px;
    background-image: var(--ac-menu-bar-image);
    opacity: 0;
    transform: scaleY(0.25);
    transition-property: opacity, transform;
    transition-duration: var(--ac-menu-transition);
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
}

/* The gradient wash. `border-radius: inherit` so it follows whatever corner
   radius Filament is using this release rather than a number copied out of it,
   and `z-index: -1` to sit between the button's own fill and its label. */
.fi-sidebar-item > .fi-sidebar-item-btn::after,
.fi-sidebar-item > a::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background-image: var(--ac-menu-hover-wash);
    opacity: 0;
    transition: opacity var(--ac-menu-transition) cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
}

/* The one thing that genuinely differs between the two writing directions: the
   washes are linear gradients, and there is no logical form of a gradient angle.
   -----------------------------------------------------------------------------
   ON `:root` AND NOT ON `[dir='rtl'] .fi-sidebar`, which is the obvious place to
   reach for. The two washes are themselves custom properties, declared on
   `:root` in section 1, and a var() nested inside a custom property is a case
   where it matters WHERE the substitution happens: resolved at the declaring
   element, an angle flipped further down the tree is simply never seen, and the
   rule fails silently with the sweep still running left-to-right. Declaring the
   flip on the same element that declares the gradients sidesteps the question
   entirely - it is correct either way. Filament puts `dir` on <html>, which IS
   `:root`, so there is no cost to doing it here. */
:root[dir='rtl'] {
    --ac-menu-wash-angle: 270deg;
}

.fi-sidebar-item > .fi-sidebar-item-btn .fi-sidebar-item-label,
.fi-sidebar-item > a .fi-sidebar-item-label,
.fi-sidebar-item > .fi-sidebar-item-btn .fi-sidebar-item-icon,
.fi-sidebar-item > a .fi-sidebar-item-icon,
.fi-sidebar-item > .fi-sidebar-item-btn > svg,
.fi-sidebar-item > a > svg {
    color: inherit;
}

/* Icons a touch quieter than the label, so the row still has a hierarchy now
   that both share one colour. */
.fi-sidebar-item > .fi-sidebar-item-btn .fi-sidebar-item-icon,
.fi-sidebar-item > a .fi-sidebar-item-icon,
.fi-sidebar-item > .fi-sidebar-item-btn > svg,
.fi-sidebar-item > a > svg {
    opacity: 0.72;
}

/* Hover AND keyboard focus, deliberately the same treatment.
   -----------------------------------------------------------------------------
   Somebody tabbing through the sidebar is doing exactly what somebody pointing
   at it is doing, and the focus ring further down says "this is where the
   keyboard is" without saying "this is the row you are about to open". Listing
   :focus-visible here costs one selector and makes the two agree. */
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:hover,
.fi-sidebar-item:not(.fi-active) > a:hover,
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:focus-visible,
.fi-sidebar-item:not(.fi-active) > a:focus-visible {
    background-color: var(--ac-menu-hover-bg);
    color: var(--ac-menu-fg-strong);
}

.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:hover::after,
.fi-sidebar-item:not(.fi-active) > a:hover::after,
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:focus-visible::after,
.fi-sidebar-item:not(.fi-active) > a:focus-visible::after {
    opacity: 1;
}

/* Half a bar, not a whole one. The hovered row and the current page must never
   be mistakable for each other in a sidebar where both are on screen at once, so
   the bar's height is the thing that says which is which. */
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:hover::before,
.fi-sidebar-item:not(.fi-active) > a:hover::before,
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:focus-visible::before,
.fi-sidebar-item:not(.fi-active) > a:focus-visible::before {
    opacity: 0.8;
    transform: scaleY(0.5);
}

.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:hover .fi-sidebar-item-icon,
.fi-sidebar-item:not(.fi-active) > a:hover .fi-sidebar-item-icon,
.fi-sidebar-item:not(.fi-active) > .fi-sidebar-item-btn:hover > svg,
.fi-sidebar-item:not(.fi-active) > a:hover > svg {
    opacity: 1;
}

/* The active item.
   -----------------------------------------------------------------------------
   The bar used to be an `inset` box-shadow, which is why this rule needed an
   RTL twin below it with the offset negated. It is the ::before pseudo-element
   now - placed logically, so the one remaining shadow is direction-agnostic and
   the twin is gone. */
.fi-sidebar-item.fi-active > .fi-sidebar-item-btn,
.fi-sidebar-item.fi-active > a,
.fi-sidebar-item > .fi-sidebar-item-btn[aria-current='page'] {
    color: var(--ac-menu-active-fg);
    background-color: var(--ac-item-active-bg);
    box-shadow: var(--ac-item-active-shadow);
}

.fi-sidebar-item.fi-active > .fi-sidebar-item-btn::after,
.fi-sidebar-item.fi-active > a::after,
.fi-sidebar-item > .fi-sidebar-item-btn[aria-current='page']::after {
    background-image: var(--ac-item-active-wash);
    opacity: 1;
}

.fi-sidebar-item.fi-active > .fi-sidebar-item-btn::before,
.fi-sidebar-item.fi-active > a::before,
.fi-sidebar-item > .fi-sidebar-item-btn[aria-current='page']::before {
    opacity: 1;
    transform: scaleY(1);
}

/* NOTHING HAPPENS WHEN THE ACTIVE ROW IS HOVERED, and that is on purpose rather
   than an omission - the `:not(.fi-active)` on every hover rule above is what
   arranges it. The current page is already the strongest state in the menu, and
   stepping it up again under the cursor only makes the page you are ON look like
   the page you are about to leave for. */

.fi-sidebar-item.fi-active > .fi-sidebar-item-btn .fi-sidebar-item-icon,
.fi-sidebar-item.fi-active > a .fi-sidebar-item-icon,
.fi-sidebar-item.fi-active > .fi-sidebar-item-btn > svg,
.fi-sidebar-item.fi-active > a > svg {
    opacity: 1;
}

/* Slightly firmer label weight on the active item. */
.fi-sidebar-item.fi-active > .fi-sidebar-item-btn .fi-sidebar-item-label,
.fi-sidebar-item.fi-active > a .fi-sidebar-item-label {
    font-weight: 600;
}

/* Group headings. Filament renders them at body size in a mid gray, which in
   dark mode sits almost on top of the item labels; small uppercase type in a
   dimmer tone separates "heading" from "item" by shape as well as by colour. */
.fi-sidebar-group-label {
    color: var(--ac-menu-group-fg);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.fi-sidebar-group-btn,
.fi-sidebar-group-btn .fi-sidebar-group-icon,
.fi-sidebar-group-btn > svg {
    color: var(--ac-menu-group-fg);
    transition-property: background-color, color;
    transition-duration: var(--ac-menu-transition);
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

/* A collapsible group heading is a button that opens and closes a chunk of the
   sidebar, so it gets the same brand tint the items get - otherwise the one
   clickable thing in the menu that does NOT light up under the cursor is the one
   that hides four links. No bar and no wash: those two say "this is a
   destination", and a group heading is not one. */
.fi-sidebar-group-btn:hover,
.fi-sidebar-group-btn:hover .fi-sidebar-group-label,
.fi-sidebar-group-btn:hover .fi-sidebar-group-icon,
.fi-sidebar-group-btn:hover > svg,
.fi-sidebar-group-btn:focus-visible,
.fi-sidebar-group-btn:focus-visible .fi-sidebar-group-label,
.fi-sidebar-group-btn:focus-visible .fi-sidebar-group-icon,
.fi-sidebar-group-btn:focus-visible > svg {
    color: var(--ac-menu-fg-strong);
}

.fi-sidebar-group-btn:hover,
.fi-sidebar-group-btn:focus-visible {
    background-color: var(--ac-menu-hover-bg);
}

/* Keyboard focus has to survive the colour changes above - including the two
   pseudo-elements, which is why the ring is an `outline` and not a box-shadow:
   an outline is painted over everything in the element's stacking context, so
   neither the wash nor the accent bar can end up on top of it. Inset by its own
   width so it lands on the button rather than in the gap between two menu rows,
   where 2px of brand colour would read as a divider. */
.fi-sidebar-item > .fi-sidebar-item-btn:focus-visible,
.fi-sidebar-item > a:focus-visible,
.fi-sidebar-group-btn:focus-visible {
    outline: 2px solid var(--ac-accent);
    outline-offset: -2px;
}

/* -----------------------------------------------------------------------------
   5. Login screen - split layout
   -----------------------------------------------------------------------------
   `.ac-login-brand` is injected as the first child of <body> by the
   `panels::body.start` render hook, on the login route only. Filament's own auth
   markup is never touched: on desktop the brand panel is taken out of flow with
   `position: fixed` and the page is inset by the same width, so nothing depends
   on the brand panel being a sibling of any particular Filament element.

   On narrow screens it collapses to a compact band above the card instead, which
   is why the mobile rules come first and the desktop ones override them.
   -------------------------------------------------------------------------- */

.ac-login-brand {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.875rem;
    overflow: hidden;
    padding: 1.125rem 1.25rem;
    color: #ffffff;
    background-color: var(--ac-brand-deep);
    background-image: linear-gradient(115deg, var(--ac-brand-mid) 0%, var(--ac-brand-deep) 100%);
}

.ac-login-brand__inner {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    min-width: 0;
}

.ac-login-brand__logo {
    display: block;
    height: 2rem;
    width: auto;
    max-width: 11rem;
    object-fit: contain;
}

.ac-login-brand__monogram {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.625rem;
    background-color: rgb(255 255 255 / 0.16);
    font-size: 1.125rem;
    font-weight: 700;
    line-height: 1;
}

.ac-login-brand__name {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

/* Everything that only earns its place on a full-height panel. */
.ac-login-brand__decor,
.ac-login-brand__eyebrow,
.ac-login-brand__tagline,
.ac-login-brand__points,
.ac-login-brand__footer {
    display: none;
}

/* Page background behind the card, both breakpoints. `:has()` scopes every rule
   in this section to the login screen without needing a body class. */
body:has(> .ac-login-brand) {
    background-color: var(--ac-login-page-bg);
    background-image:
        radial-gradient(55rem 55rem at 108% -8%, color-mix(in oklab, var(--ac-brand) 20%, transparent) 0%, transparent 62%),
        radial-gradient(40rem 40rem at -8% 108%, color-mix(in oklab, var(--ac-brand) 13%, transparent) 0%, transparent 62%);
    background-attachment: fixed;
}

/* The card itself: rounder, deeper shadow, and a hairline that reads on both
   the tinted light background and the near-black dark one. */
body:has(> .ac-login-brand) .fi-simple-main {
    border-radius: 1.125rem;
    border: 1px solid var(--ac-login-card-border);
    background-color: var(--ac-login-card-bg);
    box-shadow: var(--ac-login-card-shadow);
}

/* Filament prints the brand logo above the card; the brand panel already shows
   it, so the duplicate goes. Inert if the class is renamed - worst case the logo
   simply appears twice. */
body:has(> .ac-login-brand) .fi-logo {
    display: none;
}

@media (min-width: 64rem) {
    .ac-login-brand {
        position: fixed;
        inset-block: 0;
        inset-inline-start: 0;
        z-index: 10;
        width: var(--ac-login-brand-width);
        flex-direction: column;
        align-items: stretch;
        justify-content: space-between;
        gap: 2rem;
        padding: 3.25rem 3rem;
        background-image:
            radial-gradient(75% 55% at 12% 8%, color-mix(in oklab, var(--ac-brand) 78%, transparent) 0%, transparent 70%),
            radial-gradient(65% 55% at 92% 96%, color-mix(in oklab, var(--ac-brand-glow) 45%, transparent) 0%, transparent 68%),
            linear-gradient(155deg, var(--ac-brand-mid) 0%, var(--ac-brand-deep) 58%, #0b1120 100%);
    }

    /* The page is inset by exactly the panel's width, so the login card centres
       in what is left rather than under the artwork. */
    body:has(> .ac-login-brand) {
        padding-inline-start: var(--ac-login-brand-width);
    }

    /* Soft diagonal sheen over the gradient - one element, no images. */
    .ac-login-brand__decor {
        display: block;
        position: absolute;
        inset: -30% -20% auto -20%;
        height: 90%;
        background-image: linear-gradient(180deg, rgb(255 255 255 / 0.14) 0%, transparent 100%);
        transform: rotate(-8deg);
        pointer-events: none;
    }

    .ac-login-brand__inner {
        position: relative;
        flex-direction: column;
        align-items: flex-start;
        gap: 1.75rem;
    }

    .ac-login-brand__logo {
        height: 2.75rem;
        max-width: 15rem;
    }

    .ac-login-brand__monogram {
        width: 3.25rem;
        height: 3.25rem;
        border-radius: 0.875rem;
        font-size: 1.5rem;
    }

    .ac-login-brand__copy {
        display: flex;
        flex-direction: column;
        gap: 0.625rem;
    }

    .ac-login-brand__eyebrow {
        display: block;
        margin: 0;
        font-size: 0.75rem;
        font-weight: 600;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        color: rgb(255 255 255 / 0.72);
    }

    .ac-login-brand__name {
        font-size: clamp(1.75rem, 2.6vw, 2.5rem);
        line-height: 1.15;
    }

    .ac-login-brand__tagline {
        display: block;
        margin: 0;
        max-width: 30ch;
        font-size: 1rem;
        line-height: 1.6;
        color: rgb(255 255 255 / 0.82);
    }

    .ac-login-brand__points {
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
        margin: 0;
        padding: 0;
        list-style: none;
    }

    .ac-login-brand__point {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        font-size: 0.9375rem;
        color: rgb(255 255 255 / 0.9);
    }

    /* Tick drawn with borders so the panel needs no icon font or SVG. */
    .ac-login-brand__tick {
        flex: none;
        width: 1.125rem;
        height: 1.125rem;
        border-radius: 999px;
        background-color: rgb(255 255 255 / 0.18);
        box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.35);
        position: relative;
    }

    .ac-login-brand__tick::after {
        content: '';
        position: absolute;
        inset-inline-start: 0.375rem;
        inset-block-start: 0.1875rem;
        width: 0.3125rem;
        height: 0.5625rem;
        border: solid #ffffff;
        border-width: 0 2px 2px 0;
        transform: rotate(45deg);
    }

    .ac-login-brand__footer {
        display: block;
        position: relative;
        margin: 0;
        font-size: 0.8125rem;
        color: rgb(255 255 255 / 0.6);
    }
}

/* Short-but-wide viewports (laptops at 125% scaling) would otherwise clip the
   panel; drop the optional block rather than let it scroll. */
@media (min-width: 64rem) and (max-height: 40rem) {
    .ac-login-brand__points,
    .ac-login-brand__footer {
        display: none;
    }
}

/* -----------------------------------------------------------------------------
   6. Tables - the row actions column stays put while the table scrolls
   -----------------------------------------------------------------------------
   Several tables in this panel are far wider than any screen (Passengers has
   dozens of columns), and Filament scrolls them sideways inside
   `.fi-ta-content-ctn`, which carries `overflow-x: auto`
   (filament/tables/resources/css/content.css:2). The row actions sit at the far
   right, so on those tables View / Edit / Delete were only reachable after
   scrolling to the end of the row - and then the name of the record you were
   acting on had scrolled off the other side. Pinning the column to the trailing
   edge fixes both halves of that at once.

   THE MARKUP THIS TARGETS, read off
   filament/tables/resources/views/index.blade.php rather than remembered:

     - The actions cell is `<td class="fi-ta-cell">` wrapping
       `<div class="fi-ta-actions ...">` (line 2367 for the default position,
       and identically at 2240 / 2286 / 2413 for the other three). The `<td>`
       itself carries NO distinguishing class, which is why the selector has to
       reach for the div inside it. Filament's own stylesheet identifies the
       same cell the same way - `.fi-ta-cell:has(.fi-ta-actions)` in
       filament/tables/resources/css/cell.css:60.
     - Its header is `<th class="fi-ta-actions-header-cell fi-ta-empty-header-cell">`
       (line 1859 for the default position; 1663 / 1725 / 1924 for the others).
       That class only appears when the column has no label of its own; a table
       that calls `->recordActionsColumnLabel(...)` gets a plain
       `.fi-ta-header-cell` instead and its header will not stick. No table here
       sets one.
     - Position defaults to AfterColumns for a normal (non-grid) table -
       filament/tables/src/Table/Concerns/HasRecordActions.php:112-125 - so this
       is the last cell in the row. The rules are written without depending on
       that: they match the actions cell wherever it is, and a leading actions
       column would simply pin to the wrong edge rather than break.

   WHY IT IS SAFE ON TABLES THAT DO NOT SCROLL: a sticky element only ever moves
   within its own containing block. With nothing to scroll, the cell is already
   flush against the trailing edge and stays exactly where it was.

   WHY THE `sm` FLOOR: below Filament's `sm` breakpoint a stacked table turns
   every `<td>` into a block element
   (filament/tables/resources/css/table.css:72-73). Sticky on a block inside a
   block row would peel the buttons off the row entirely, so the whole section is
   gated at 40rem - the same 640px Filament's own `sm` variant compiles to. On a
   phone the table is a stack of cards and there is no sideways scroll to escape
   from anyway.
   -------------------------------------------------------------------------- */

@media (min-width: 40rem) {
    .fi-ta-table > thead > tr > .fi-ta-actions-header-cell,
    .fi-ta-table > tbody > tr > .fi-ta-cell:has(> .fi-ta-actions),
    /* Summary rows emit a bare, class-less `<td></td>` under the actions column
       (components/summary/row.blade.php:114). Without this it is the one gap in
       the pinned strip, and the summary figures slide through it. `:not([class])`
       is what tells that placeholder apart from a real summary cell, which always
       carries `fi-ta-cell`. */
    .fi-ta-table > tbody > tr.fi-ta-summary-row > td:last-child:not([class]) {
        position: sticky;
        inset-inline-end: 0;
        z-index: 1;
        background-color: var(--ac-ta-sticky-surface);
        /* The hairline reads as an ordinary column rule when the table fits, and
           as the edge of the pinned strip when it does not. The second, softer
           shadow is what gives the strip depth once content is passing under it;
           it is spread inwards (-0.75rem) so it stays a suggestion rather than a
           band. Drawn with box-shadow rather than a border because Tailwind's
           preflight collapses table borders, and collapsed borders on a sticky
           cell are a well-known source of browser-specific gaps. */
        box-shadow:
            inset 1px 0 0 0 var(--ac-ta-sticky-edge),
            -0.5rem 0 0.75rem -0.75rem var(--ac-ta-sticky-shade);
    }

    [dir='rtl'] .fi-ta-table > thead > tr > .fi-ta-actions-header-cell,
    [dir='rtl'] .fi-ta-table > tbody > tr > .fi-ta-cell:has(> .fi-ta-actions),
    [dir='rtl'] .fi-ta-table > tbody > tr.fi-ta-summary-row > td:last-child:not([class]) {
        box-shadow:
            inset -1px 0 0 0 var(--ac-ta-sticky-edge),
            0.5rem 0 0.75rem -0.75rem var(--ac-ta-sticky-shade);
    }

    /* The header row is `bg-gray-50 dark:bg-white/5`
       (filament/tables/resources/css/table.css:165), so its pinned cell needs the
       tinted fill, not the plain one. Also a step higher in the stack, so that a
       header cell wins against the row cells if a future release ever makes the
       header sticky vertically as well. */
    .fi-ta-table > thead > tr > .fi-ta-actions-header-cell {
        z-index: 2;
        background-color: var(--ac-ta-sticky-surface-alt);
    }

    /* Striped and selected rows paint themselves `bg-gray-50 dark:bg-white/5`
       (filament/tables/resources/css/row.css). A cell background sits ON TOP of
       its row's, so the pinned cell would otherwise be the one white stripe in an
       alternating table. Each of these out-specifies the base rule above by the
       extra class on the `<tr>`. */
    .fi-ta-table > tbody > tr.fi-striped > .fi-ta-cell:has(> .fi-ta-actions),
    .fi-ta-table > tbody > tr.fi-selected > .fi-ta-cell:has(> .fi-ta-actions) {
        background-color: var(--ac-ta-sticky-surface-alt);
    }

    /* Same again for the hover tint, which Filament only applies to rows that do
       something when clicked (`.fi-clickable`). Behind a hover media query for
       the same reason Filament puts its own row transition there: on a touch
       screen the tint sticks to the last row tapped. */
    @media (hover: hover) {
        .fi-ta-table > tbody > tr.fi-clickable:hover > .fi-ta-cell:has(> .fi-ta-actions) {
            background-color: var(--ac-ta-sticky-surface-alt);
        }
    }
}

/* -----------------------------------------------------------------------------
   7. Passenger verification row tints
   -----------------------------------------------------------------------------
   The passenger list paints every row by whether the Create/Edit Passenger form
   has been filled in - green for yes, red for no. The classes come from
   PassengerResource::table()'s ->recordClasses(); what counts as filled in is
   PassengerCompleteness, and both explain themselves at length.

   WHY THIS IS CSS AND NOT A TAILWIND CLASS ON THE ROW. Filament paints three
   backgrounds on a <tr> of its own accord - the striped fill, the selected fill
   and the hover fill - and all three are real declarations rather than defaults.
   A utility class would tie with them on specificity and lose to whichever came
   later in the sheet, so the row would be tinted until the mouse touched it and
   then turn grey. It is not a specificity fight here: this file is UNLAYERED and
   Filament's is inside @layer, so everything below wins on cascade layer alone,
   whatever it is competing with (see the note at the top of this file).

   THE STICKY ACTIONS CELL HAS TO BE TINTED SEPARATELY, and that is the part that
   is easy to miss. Section 6 gives that one cell an opaque fill of its own so it
   does not go transparent when the table scrolls under it - and a cell
   background sits ON TOP of its row's, so without the rules below every tinted
   row would have an unpainted white block at the right-hand end of it. Those
   rules and these are in the same file and the same layer, so these are placed
   AFTER them on purpose: the selectors tie on specificity and source order is
   what settles it. The :hover pair below exists for the same reason - section
   6's hover rule carries a :hover and would otherwise out-specify a version of
   this without one.
   -------------------------------------------------------------------------- */

.fi-ta-table > tbody > tr.passenger-row-complete,
.fi-ta-table > tbody > tr.passenger-row-complete > .fi-ta-cell:has(> .fi-ta-actions) {
    background-color: var(--ac-row-complete-bg);
}

.fi-ta-table > tbody > tr.passenger-row-incomplete,
.fi-ta-table > tbody > tr.passenger-row-incomplete > .fi-ta-cell:has(> .fi-ta-actions) {
    background-color: var(--ac-row-incomplete-bg);
}

/* The hover list, one field per line.
   -----------------------------------------------------------------------------
   PassengerCompleteness::summary() builds its list with real newlines, and a
   tooltip is plain text with allowHTML off - so without this the browser
   collapses every one of them to a space and twenty-eight field names arrive as
   a single wrapped paragraph with bullets buried mid-line. Measured on the real
   tooltip before this rule existed: `white-space: normal`, 350x206px, reading
   "28 fields not filled in: • ID No • Date of Passport Issued • ...".

   `pre-line` and not `pre`: it honours the newlines while still collapsing runs
   of spaces and, crucially, still WRAPPING - `pre` would let a long field name
   push the tooltip off the side of the screen instead of folding it.

   Unscoped, because a tippy renders in a portal at the end of <body> rather than
   inside the cell that owns it, so there is nothing left to scope it by. It is
   safe unscoped: every other tooltip in this panel is a single line with no
   newline in it, and `pre-line` leaves those exactly as they were. */
.tippy-box .tippy-content {
    white-space: pre-line;
}

/* Behind a hover query for the same reason Filament puts its own row transition
   there: on a touch screen the tint sticks to the last row tapped, so the list
   ends up with one permanently highlighted row that means nothing. */
@media (hover: hover) {
    .fi-ta-table > tbody > tr.passenger-row-complete:hover,
    .fi-ta-table > tbody > tr.passenger-row-complete:hover > .fi-ta-cell:has(> .fi-ta-actions) {
        background-color: var(--ac-row-complete-bg-hover);
    }

    .fi-ta-table > tbody > tr.passenger-row-incomplete:hover,
    .fi-ta-table > tbody > tr.passenger-row-incomplete:hover > .fi-ta-cell:has(> .fi-ta-actions) {
        background-color: var(--ac-row-incomplete-bg-hover);
    }
}

/* -----------------------------------------------------------------------------
   7b. The money still owed on a file, in a dialog
   -----------------------------------------------------------------------------
   Used by the "Send to Delivery" dialog on the manpower desk, which is the last
   moment anybody in this office is holding the passport and the person collecting
   it at the same time. If money is still owed on the file, THAT is when it can be
   asked for, and a figure tucked into a sentence gets read after the passport has
   gone. So it is large, red, and above the fields rather than beside them.

   HERE RATHER THAN IN A SCOPED <style>, unlike the dashboard's layout: this is
   panel chrome — it is drawn inside a Filament modal, in a schema component, and
   the same block will belong in every other dialog that hands something over. A
   scoped block inside one action's Blade would be one copy per dialog.

   Both themes are declared, because a dialog is one of the few places this panel
   paints a coloured surface of its own and #dc2626 on a dark modal is a colour
   nobody can read. The green half is not decoration either: "nothing due" has to
   be as unmistakable as a figure, or a clear file reads as a missing one.
   -------------------------------------------------------------------------- */

.ac-due {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.ac-due__value {
    font-size: 1.75rem;
    line-height: 2.25rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: #dc2626;
}

.ac-due__note {
    font-size: 0.8125rem;
    color: #6b7280;
}

.ac-due--clear .ac-due__value {
    color: #047857;
    font-size: 1.25rem;
    line-height: 1.75rem;
}

.dark .ac-due__value {
    color: #f87171;
}

.dark .ac-due__note {
    color: #9ca3af;
}

.dark .ac-due--clear .ac-due__value {
    color: #6ee7b7;
}

/* -----------------------------------------------------------------------------
   8. Animated page background
   -----------------------------------------------------------------------------
   Site Settings -> Appearance -> Background Animation. The panel provider injects
   `<div class="ac-bg ac-bg--KEY">` with three empty spans as the first element in
   <body>, and everything below is the artwork for the four keys
   App\SiteSetting::BACKGROUND_ANIMATIONS offers. With the setting Off the div is
   never emitted and not one rule in this section matches - which is why the
   markup is three anonymous spans rather than a template per animation: the HTML
   is a canvas, the stylesheet is the picture on it.

   WHAT IT IS ALLOWED TO COST. This runs on every page of a panel the office
   keeps open all day, on hardware nobody chose, so the section is held to three
   rules:

     1. ONLY `transform` AND `opacity` ARE ANIMATED. Both are composited, so a
        frame costs the GPU a matrix multiply and nothing else. Animating a
        gradient's colour stops, a `background-position` or a `filter: blur()`
        instead would repaint a full-viewport surface sixty times a second, which
        is the difference between a background and a space heater.
     2. NO BLUR, NO IMAGES, NOTHING TO DOWNLOAD. Every soft edge here is a radial
        gradient fading to transparent, which the browser paints once into a layer
        and afterwards only ever moves.
     3. NOTHING FASTER THAN TWENTY SECONDS, and every cycle is a slow drift or
        cross-fade rather than a loop with a seam in it. Motion this slow reads as
        the light changing in a room rather than as something happening on the
        screen, and that is the entire point: it must never pull an eye off a
        column of passport numbers.

   WHERE IT IS VISIBLE, AND WHERE IT IS DELIBERATELY NOT. Filament paints
   `.fi-body` with gray-50 / gray-950; the two rules below turn that off and move
   the same colour up to the root element, so the canvas behind the layer is
   exactly the colour it always was. The sidebar, the topbar and every card, table
   and panel on top of them stay opaque, so the animation only ever shows in the
   gutters BETWEEN them - never behind text. That is what lets the tints be as
   weak as they are and still be worth having.

   `z-index: -1` RATHER THAN 0. A negatively-stacked fixed element paints after
   the root's background and before every piece of in-flow content, which is
   precisely the slot wanted - and it gets there without positioning, layering or
   otherwise touching a single element of Filament's.

   THE COLOURS ALL DERIVE FROM `--ac-brand`, so an install that changes its brand
   colour gets a background that matches it for free. The second hue is the brand
   mixed towards indigo rather than a literal blue: two hues make a drift readable
   where one is just a smudge, and deriving the second one means it cannot clash
   with a brand colour nobody has picked yet.
   -------------------------------------------------------------------------- */

/* The page's own paint, moved from <body> up to <html>.
   -----------------------------------------------------------------------------
   Both selectors are conditional on the layer actually being in the document, so
   an install with the animation Off keeps Filament's own body background and
   these rules are inert. The literals are Filament's gray-50 and gray-950 with
   `gray` pinned to Color::Slate (see AdminPanelProvider::colors), i.e. exactly
   the colours the body was painted before. */
:root:has(> body > .ac-bg) {
    background-color: #f8fafc; /* slate-50 */
}

:root.dark:has(> body > .ac-bg),
:root.fi-theme-dark:has(> body > .ac-bg),
:root[data-theme='dark']:has(> body > .ac-bg) {
    background-color: #020617; /* slate-950 */
}

.fi-body:has(> .ac-bg) {
    background-color: transparent;
}

/* The canvas.
   -----------------------------------------------------------------------------
   `pointer-events: none` is not a nicety: this is a fixed element over the whole
   viewport, and without it every click in the panel would land on the wallpaper.
   `contain: layout paint` tells the browser nothing inside can affect anything
   outside, so a drifting layer can never invalidate the page's layout. No
   `will-change`: browsers already promote a transform animation to its own layer,
   and pinning three viewport-sized bitmaps in memory for a whole working day is a
   real cost on exactly the machines this section is trying to be kind to. */
.ac-bg {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
    contain: layout paint;

    --ac-bg-warm: color-mix(in oklab, var(--ac-brand) 20%, transparent);
    /* The inner mix used to be spelled out here. It is `--ac-brand-cool` in
       section 1 now - same colour, one definition, and the sidebar reads it
       too, which is the entire reason the navigation and this background look
       related rather than merely adjacent. */
    --ac-bg-cool: color-mix(in oklab, var(--ac-brand-cool) 18%, transparent);
    --ac-bg-soft: color-mix(in oklab, var(--ac-brand) 11%, transparent);
    --ac-bg-line: color-mix(in oklab, var(--ac-brand) 18%, transparent);
}

/* Dark theme runs STRONGER, which is the same finding as the row tints in
   section 1: a tint on a near-black page has to add light to be seen at all, and
   the percentage that reads as a soft wash on white reads as nothing here. */
:root.dark .ac-bg,
:root.fi-theme-dark .ac-bg,
:root[data-theme='dark'] .ac-bg {
    --ac-bg-warm: color-mix(in oklab, var(--ac-brand) 30%, transparent);
    --ac-bg-cool: color-mix(in oklab, var(--ac-brand-cool) 30%, transparent);
    --ac-bg-soft: color-mix(in oklab, var(--ac-brand) 16%, transparent);
    --ac-bg-line: color-mix(in oklab, var(--ac-brand) 22%, transparent);
}

.ac-bg__layer {
    display: block;
    position: absolute;
}

/* Aurora - three soft lights drifting past each other.
   `vmax` rather than `vw` so a light is the same size on a tall laptop as on a
   wide monitor; sized well past the viewport and hung off the edges so a drift
   never brings a gradient's own centre into the middle of the screen, which is
   what would make it read as a blob rather than as light. */
.ac-bg--aurora .ac-bg__layer {
    width: 58vmax;
    height: 58vmax;
    border-radius: 50%;
}

.ac-bg--aurora .ac-bg__layer--a {
    top: -20vmax;
    left: -14vmax;
    background: radial-gradient(closest-side, var(--ac-bg-warm), transparent);
    animation: ac-bg-drift-a 38s ease-in-out infinite alternate;
}

.ac-bg--aurora .ac-bg__layer--b {
    top: 10vmax;
    right: -18vmax;
    background: radial-gradient(closest-side, var(--ac-bg-cool), transparent);
    animation: ac-bg-drift-b 46s ease-in-out infinite alternate;
}

.ac-bg--aurora .ac-bg__layer--c {
    bottom: -26vmax;
    left: 16vmax;
    background: radial-gradient(closest-side, var(--ac-bg-soft), transparent);
    animation: ac-bg-drift-c 32s ease-in-out infinite alternate;
}

/* Mesh - one still picture cross-fading into the next.
   -----------------------------------------------------------------------------
   NOTHING TRAVELS HERE, and that is the whole design. Each layer is a
   full-viewport arrangement of three gradients, and the three take turns at full
   opacity, so what changes is where the colour IS rather than anything moving
   across the screen. It is the calmest of the four for the same reason it is the
   cheapest: an opacity animation on a layer the browser has already painted.

   THE TIMING FUNCTION MUST STAY `linear`. The three layers share one 78s keyframe
   set offset by a third of a cycle each, and the set is written so the layer
   fading out and the layer fading in are always at complementary opacities. That
   only holds while the interpolation is straight - an `ease` of any kind leaves
   the pair summing to less than one through the middle of every hand-over, and
   the whole page visibly pulses lighter three times a cycle. */
.ac-bg--mesh .ac-bg__layer {
    inset: 0;
    opacity: 0;
    animation: ac-bg-wash 78s linear infinite;
}

.ac-bg--mesh .ac-bg__layer--a {
    background:
        radial-gradient(58% 48% at 10% 6%, var(--ac-bg-warm), transparent 70%),
        radial-gradient(52% 46% at 88% 24%, var(--ac-bg-cool), transparent 72%),
        radial-gradient(62% 52% at 42% 98%, var(--ac-bg-soft), transparent 74%);
}

/* Negative delays start each layer part-way into the cycle, so the cross-fade is
   already under way on the first frame instead of the page opening on layer a
   and then holding still for half a minute. */
.ac-bg--mesh .ac-bg__layer--b {
    background:
        radial-gradient(56% 50% at 86% 4%, var(--ac-bg-warm), transparent 72%),
        radial-gradient(54% 44% at 14% 34%, var(--ac-bg-cool), transparent 70%),
        radial-gradient(60% 50% at 70% 96%, var(--ac-bg-soft), transparent 74%);
    animation-delay: -26s;
}

.ac-bg--mesh .ac-bg__layer--c {
    background:
        radial-gradient(60% 46% at 46% 0%, var(--ac-bg-cool), transparent 72%),
        radial-gradient(50% 48% at 4% 78%, var(--ac-bg-warm), transparent 70%),
        radial-gradient(58% 52% at 96% 62%, var(--ac-bg-soft), transparent 74%);
    animation-delay: -52s;
}

/* Grid - a fine ruled surface panning under two slow lights.
   The pan is exactly ONE TILE, `linear`, and without `alternate`, so the loop
   closes on itself invisibly: the grid displaced by 4rem is the same picture as
   the grid at rest. The layer is inset NEGATIVELY by two tiles on every side so
   the travel can never drag an edge into view. */
.ac-bg--grid .ac-bg__layer--a {
    inset: -8rem;
    background-image:
        linear-gradient(to right, var(--ac-bg-line) 0 1px, transparent 1px 100%),
        linear-gradient(to bottom, var(--ac-bg-line) 0 1px, transparent 1px 100%);
    background-size: 4rem 4rem;
    animation: ac-bg-pan 26s linear infinite;
}

.ac-bg--grid .ac-bg__layer--b {
    inset: 0;
    background: radial-gradient(72% 58% at 18% 0%, var(--ac-bg-warm), transparent 72%);
    animation: ac-bg-drift-b 44s ease-in-out infinite alternate;
}

.ac-bg--grid .ac-bg__layer--c {
    inset: 0;
    background: radial-gradient(72% 58% at 92% 100%, var(--ac-bg-cool), transparent 74%);
    animation: ac-bg-drift-c 54s ease-in-out infinite alternate;
}

/* Waves - three wide, flat bands sliding across each other.
   Wider than the viewport on both sides (`left` and `right` are both negative) so
   the end of a band is never on screen; the ellipse comes from
   `border-radius: 50%` on a short, very wide box rather than from an SVG path,
   because a fill that fades to transparent at its own edge needs no outline to
   read as a wave. */
.ac-bg--waves .ac-bg__layer {
    left: -30%;
    right: -30%;
    height: 62vh;
    border-radius: 50%;
}

.ac-bg--waves .ac-bg__layer--a {
    top: -24vh;
    background: radial-gradient(closest-side, var(--ac-bg-warm), transparent);
    animation: ac-bg-slide-a 40s ease-in-out infinite alternate;
}

.ac-bg--waves .ac-bg__layer--b {
    top: 24vh;
    background: radial-gradient(closest-side, var(--ac-bg-cool), transparent);
    animation: ac-bg-slide-b 52s ease-in-out infinite alternate;
}

.ac-bg--waves .ac-bg__layer--c {
    bottom: -26vh;
    background: radial-gradient(closest-side, var(--ac-bg-soft), transparent);
    animation: ac-bg-slide-c 34s ease-in-out infinite alternate;
}

@keyframes ac-bg-drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to { transform: translate3d(7vmax, 5vmax, 0) scale(1.18); }
}

@keyframes ac-bg-drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.14); }
    to { transform: translate3d(-8vmax, -6vmax, 0) scale(1); }
}

@keyframes ac-bg-drift-c {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to { transform: translate3d(6vmax, -7vmax, 0) scale(1.22); }
}

/* Read the note on `linear` above before touching these four stops. */
@keyframes ac-bg-wash {
    0% { opacity: 1; }
    33.333% { opacity: 0; }
    66.667% { opacity: 0; }
    100% { opacity: 1; }
}

@keyframes ac-bg-pan {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-4rem, -4rem, 0); }
}

@keyframes ac-bg-slide-a {
    from { transform: translate3d(-8%, 0, 0); }
    to { transform: translate3d(8%, 3vh, 0); }
}

@keyframes ac-bg-slide-b {
    from { transform: translate3d(9%, 0, 0); }
    to { transform: translate3d(-9%, -4vh, 0); }
}

@keyframes ac-bg-slide-c {
    from { transform: translate3d(-6%, 2vh, 0); }
    to { transform: translate3d(7%, -2vh, 0); }
}

/* Decoration has no business on paper, and a full-page gradient behind a printed
   report is toner spent on nothing. */
@media print {
    .ac-bg {
        display: none;
    }
}

/* -----------------------------------------------------------------------------
   9. Accessibility
   -------------------------------------------------------------------------- */

/* THE COLOUR IS NEVER THE ONLY SIGNAL. Red and green are the pair most likely to
   read as one colour, so the row tint is backed by a badge in the first column
   carrying the words "Ready for Embassy" or "Not Ready" and an icon whose shape differs -
   see the completeness column in PassengerResource::table(). In forced-colours
   mode the tints are dropped by the UA entirely, and that badge is all that is
   left, which is why it is not optional. */

@media (prefers-reduced-motion: reduce) {
    /* THE MENU STILL CHANGES COLOUR, IT JUST STOPS TAKING TIME OVER IT. Every
       state in section 4 is still painted - the tint, the wash and the accent
       bar all arrive exactly as they do otherwise, on the frame the cursor lands
       rather than over the following sixth of a second. Somebody who asked their
       operating system for less motion has not asked for a sidebar that stops
       telling them where they are.

       ONE DECLARATION REACHES ALL OF IT, which is the whole reason the duration
       is a token: section 4 spends `--ac-menu-transition` on the button, on the
       accent bar's opacity and transform, on the wash's opacity and on the group
       headings, so re-declaring it here is the entire override. It out-specifies
       the `:root` block in section 1 on source order at equal specificity, and
       nothing in the dark-theme block redefines it, so it holds in both themes.
       Anything added to section 4 later gets this for free as long as it spends
       the token rather than writing its own number. */
    :root {
        --ac-menu-transition: 0.01ms;
    }

    /* THE PAGE BACKGROUND STOPS, IT DOES NOT DISAPPEAR. Section 8's whole reason
       for existing is that the panel looks better with it, and somebody who has
       asked their operating system for less motion has asked for less MOTION -
       not for a different colour scheme. So every animation is cancelled and the
       artwork is left standing on its first frame.

       `!important`, AND IT IS NOT BELT-AND-BRACES. Section 8 sets each animation
       on a two-class selector (`.ac-bg--aurora .ac-bg__layer--a`), and this one
       is a single class - so section 8 scores (0,2,0) against this rule's
       (0,1,0) and wins. A MEDIA QUERY CONTRIBUTES NOTHING TO SPECIFICITY; being
       inside one buys this rule nothing at all, and being later in the file buys
       it nothing either, because source order only settles ties. Written without
       the `!important` this rule silently does nothing, which is exactly how it
       was first written and exactly what a browser in reduced-motion mode caught:
       the layers were still drifting. The alternative - repeating all four
       variant prefixes here - is four selectors to keep in step with section 8
       for the same result.

       Mesh needs the second rule below. Its layers are painted at `opacity: 0`
       and lifted to full opacity by the animation itself, so cancelling the
       animation alone would leave all three invisible and the chosen background
       silently blank. Layer a is pinned on instead, which is exactly the still
       picture the cross-fade would have been resting on. That one needs no
       `!important`: it ties with `.ac-bg--mesh .ac-bg__layer` at (0,2,0) and wins
       on source order. */
    .ac-bg__layer {
        animation: none !important;
    }

    .ac-bg--mesh .ac-bg__layer--a {
        opacity: 1;
    }
}
