/* ============================================================================
   Rently loading-UX kit — entrance reveal + skeleton↔content crossfade
   ----------------------------------------------------------------------------
   GLOBAL stylesheet (linked in App.razor) so the consumer classes below carry
   NO Blazor scope attribute and cascade into every page/component that uses
   <ContentReveal>. Do NOT move these rules into a *.razor.css companion — scoped
   CSS would rewrite the selectors and silently drop them on child components.

   Pairs with: Server/Components/CustomComponents/ContentReveal.razor
   Standard:   Documentation/active/RenderModeStatePersistenceRoadmap.md (§2(a), §7)

   Design rationale (confirmed against ASP.NET Core 10.0 via dotnet10-blazor-expert):
   • Entrance glide-in = a one-shot keyframe ANIMATION on an UNCONDITIONALLY
     rendered wrapper. A CSS animation fires once when its element is inserted and
     is reused (not re-inserted) across re-renders, so it never re-fires — provided
     the wrapper is never given a rotating @key. This is the ONLY smoothness
     mechanism that also covers enhanced-navigation arrivals, where [StreamRendering]
     is structurally inert.
   • Skeleton→content crossfade = a CSS TRANSITION on the always-present skeleton
     (opacity 1→0 when the parent gains .rently-cf--loaded). A transition only runs
     on a property CHANGE to an existing node, so it is immune to "re-fire when the
     interactive circuit reattaches and restoration makes the render a no-op".
   • The skeleton stays in the DOM at opacity:0 (grid-stacked under the content) so
     it (a) reserves layout height — no blank-wipe / no layout shift — and (b) gives
     a true crossfade rather than a pop. It is aria-hidden + pointer-events:none.
   ============================================================================ */

/* ── Keyframes ──────────────────────────────────────────────────────────────
   Reuses the same shape as the home page's existing fadeIn (opacity + 10px lift)
   so the entrance feel is consistent across the site. */
@keyframes rently-reveal-in {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes rently-fade-in {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* ── Entrance glide-in (optional, on the outer wrapper) ──────────────────────
   `both` keeps the element at the from-state before the animation starts and the
   to-state after it ends, so there is no flash-of-final-state on slow paints. */
.rently-reveal {
    /* The wrapper itself is layout-only by default; the --entrance modifier adds
       the one-shot animation. Kept separate so a consumer can reserve the wrapper
       for layout without animating (e.g. when a parent already animates). */
    display: block;
}

.rently-reveal--entrance {
    animation: rently-reveal-in 0.45s ease-out both;
}

/* ── Crossfade container ─────────────────────────────────────────────────────
   Skeleton and content occupy the SAME grid cell (1/1) so they stack. Both layers
   share the cell's box, which is sized to the taller of the two — that is what
   reserves space while loading. min-width:0 lets grid children shrink instead of
   forcing horizontal overflow. */
.rently-cf {
    display: grid;
}

    .rently-cf > * {
        grid-area: 1 / 1;
        min-width: 0;
    }

/* Skeleton layer: visible while loading, fades OUT via transition when the parent
   gains .rently-cf--loaded. pointer-events:none so the (still-present) invisible
   skeleton can never intercept clicks meant for the live content stacked above it. */
.rently-cf__skeleton {
    opacity: 1;
    transition: opacity 0.35s ease-out;
    pointer-events: none;
}

.rently-cf--loaded .rently-cf__skeleton {
    opacity: 0;
}

/* Content layer: rendered only once loaded (so it is never asked to render against
   null data), and fades IN. It is grid-stacked ABOVE the skeleton, so as it fades
   to opacity:1 it covers the fading skeleton — a true crossfade. The animation
   fires once on insertion; on the [PersistentState] restore path the content is
   already in the prerendered HTML, so it animates once at prerender paint and the
   reused element does not re-fire on circuit attach. */
.rently-cf__content {
    opacity: 1;
    animation: rently-fade-in 0.4s ease-out both;
}

/* ── Reduced motion ─────────────────────────────────────────────────────────
   Vestibular-safe: drop the translateY entirely (opacity is not "motion" in the
   vestibular sense) and shorten everything. */
@media (prefers-reduced-motion: reduce) {
    .rently-reveal--entrance {
        animation: rently-fade-in 0.2s ease-out both;
    }

    .rently-cf__skeleton {
        transition: opacity 0.15s ease-out;
    }

    .rently-cf__content {
        animation: rently-fade-in 0.15s ease-out both;
    }
}

/* ── Skeleton component layout hooks ─────────────────────────────────────────
   Layout-only styling for the standard skeleton components' OWN elements (plain
   divs/cards), kept here rather than in *.razor.css so they need no ::deep into the
   MudSkeleton children and carry no scope attribute. */
.rently-card-grid-skeleton__card {
    border-radius: 8px; /* brand radius — matches RentalCard */
    overflow: hidden;
}

.rental-details-skeleton__hero {
    border-radius: 8px;
}

.rental-details-skeleton__thumbs {
    display: flex;
    gap: 8px;
    margin-top: 12px;
    flex-wrap: wrap;
}

.rental-details-skeleton__panel {
    border-radius: 8px;
    border: 1px solid #e0e0e0;
}

/* Initiative C · C5 Pt3c.C — dark border for the details-skeleton panel. The light #e0e0e0 reads as a
   faint light line on the dark page; flip it to the dark border token. Dark-only so light is byte-identical.
   (The MudSkeleton shimmer inside flips via the --mud-palette-* dark tokens.) */
[data-theme="dark"] .rental-details-skeleton__panel {
    border-color: var(--rently-border);
}

/* ── Inline distance-update indicator ───────────────────────────────────────
   Replaces the rental details page's old full-screen dark MudOverlay ("Updating
   distances…") with a thin, sticky, non-blocking progress bar. The page stays
   readable while distances refresh in place. */
.rently-distance-update-bar {
    position: sticky;
    top: 0;
    z-index: 1000;
}

/* ============================================================================
   Premium Guided UX — motion layer + celebration / empty-state surfaces (Phase 0)
   ----------------------------------------------------------------------------
   GLOBAL (in this file, not a *.razor.css) for two reasons: (1) the celebration
   card renders inside a MudOverlay that PORTALS to the document root — outside any
   component scope — so scoped CSS could never reach it; (2) the motion utility
   classes are reused across components. All animations are neutralised under
   prefers-reduced-motion at the foot of this block.
   ============================================================================ */

/* Easing curves, exposed on the utility classes (NOT :root, so they remain usable
   from scoped CSS contexts that reference them too).
   S7-06: these two names are now ALSO defined canonically on :root in rently-dashboard-tokens.css,
   with these exact values. They are deliberately left as LITERALS here rather than aliased to the
   :root copies, because both spellings would be the same property name on the same element:
   `--rently-ease-emphasized: var(--rently-ease-emphasized, …)` is a self-reference, which CSS treats
   as a cyclic dependency that is invalid at computed-value time — and a cycle does NOT fall back to
   the var() fallback, it drops the declaration. Keeping the literal also keeps this sheet working on
   any page that loads it without the token sheet. If these ever need to change, change both. */
.rently-pop,
.rently-celebrate-card,
.rently-pulse-once {
    --rently-ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
    --rently-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes rently-pop-in {
    from {
        opacity: 0;
        transform: scale(0.96);
    }

    to {
        opacity: 1;
        transform: scale(1);
    }
}

@keyframes rently-celebrate {
    0% {
        opacity: 0;
        transform: scale(0.8);
    }

    60% {
        opacity: 1;
        transform: scale(1.04);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}

@keyframes rently-pulse-once {
    /* Brand teal sourced from --rently-primary-rgb (rently-dashboard-tokens.css, loaded globally before
       this file). rgba(var(--channels), a) preserves the exact hue while the alpha fades 0.45→0 — a
       single var()-with-fallback, NOT color-mix (which would interpolate the hue through black). */
    0% {
        box-shadow: 0 0 0 0 rgba(var(--rently-primary-rgb, 53, 160, 174), 0.45);
    }

    100% {
        box-shadow: 0 0 0 14px rgba(var(--rently-primary-rgb, 53, 160, 174), 0);
    }
}

/* One-shot entrance pop (cards, empty states). */
.rently-pop {
    animation: rently-pop-in 0.3s var(--rently-ease-emphasized, ease-out) both;
}

/* Single attention pulse for a CTA. */
.rently-pulse-once {
    animation: rently-pulse-once 1.2s ease-out;
}

/* ── Celebration overlay (global — MudOverlay portals outside component scope) ── */
.rently-celebration-center {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 16px;
}

.rently-celebration-card {
    width: 100%;
    max-width: 420px;
    padding: 32px 28px;
    border-radius: 16px;
    text-align: center;
}

.rently-celebrate-card {
    animation: rently-celebrate 0.5s var(--rently-ease-spring, ease-out) both;
}

.rently-celebration-mascot {
    width: 120px;
    height: auto;
    margin: 0 auto 8px;
    display: block;
}

/* ── Empty-state illustration ── */
.rently-empty-state__art {
    width: 160px;
    max-width: 60%;
    height: auto;
    opacity: 0.95;
}

@media (prefers-reduced-motion: reduce) {
    .rently-pop,
    .rently-celebrate-card {
        animation: rently-fade-in 0.15s ease-out both;
    }

    .rently-pulse-once {
        animation: none;
    }
}

/* ============================================================================
   GuidedTip coach-mark (Phase 10 — Guided Discovery)
   ----------------------------------------------------------------------------
   GLOBAL (not a *.razor.css) because MudPopover PORTALS its content into
   MudPopoverProvider at the document root — outside GuidedTip's CSS scope — so a
   companion ::deep rule would silently never match. Keyed on the forwarded
   Class="rently-guided-tip-pop" (MudBlazor forwards Class onto the .mud-popover
   node). Paper="false" on the popover, so this rule owns the whole card surface.
   ============================================================================ */
.rently-guided-tip-pop {
    background: var(--rently-card-bg);
    border: 1px solid var(--rently-border);
    border-radius: var(--rently-radius-md);
    box-shadow: var(--rently-shadow-hero);
}

/* Zero-height top-of-content anchor: lets a GuidedTip point at the TOP of a tall block
   (e.g. a wizard step) — the popover marker sits just after this, at the block's top. */
.rently-guided-tip-anchor {
    display: block;
    width: 100%;
    height: 0;
}

/* Width is constrained HERE (on the content element we own), not on .rently-guided-tip-pop:
   MudBlazor's own .mud-popover-open rule overrides max-width on the portaled popover node, but
   never touches this inner div. box-sizing folds the padding into the cap. */
.rently-guided-tip-pop__content {
    box-sizing: border-box;
    max-width: 300px;
    padding: var(--rently-space-6);
}

/* Mobile: keep the coach-mark inside a narrow viewport (MudPopover does not clamp horizontally —
   it only flips vertically). 260px fits centered under a typical mobile control button at 375px. */
@media (max-width: 599px) {
    .rently-guided-tip-pop__content {
        max-width: 272px;
    }
}

.rently-guided-tip-pop__title {
    font-family: var(--rently-font-display);
    font-weight: 700;
    font-size: 0.9rem;
    line-height: var(--rently-leading-snug);
    color: var(--rently-text-primary);
    margin-bottom: var(--rently-space-1);
}

.rently-guided-tip-pop__body {
    font-size: 0.85rem;
    line-height: var(--rently-leading-normal);
    color: var(--rently-text-secondary); /* #475569 ~7:1 — replaces the old opacity:0.85 (a11y, SC 1.4.3) */
}

.rently-guided-tip-pop__actions {
    display: flex;
    justify-content: flex-end;
    margin-top: var(--rently-space-6);
}

/* 44px touch target (SYS-08) + accessible teal label: #256f7a (5.78:1) not raw
   #35a0ae (3.09:1, fails SC 1.4.3 for this small text). Global — the button portals too. */
.rently-guided-tip-pop .mud-button-root {
    min-height: 44px;
    color: var(--rently-primary-dark) !important;
    font-weight: 600;
}

/* Entrance + reduced-motion fallback come from the global .rently-pop class on the content
   element (see the reduced-motion block above) — it is unscoped, so it reaches the portaled node. */

/* ============================================================================
   Phase 11 — Motion & Loading Polish: count-up, sparkle, hover-lift utilities
   ----------------------------------------------------------------------------
   GLOBAL (this file is linked in App.razor) so these reusable motion classes carry NO Blazor scope
   attribute and reach every consumer — including content portaled out of component scope. Every new
   animation is neutralised under prefers-reduced-motion at the foot of this block.
   ============================================================================ */

/* CountUp — tabular figures so the number's width can't jitter frame-to-frame while it counts.
   The animating span is aria-hidden; the real value rides on the adjacent .rently-visually-hidden. */
.rently-countup {
    font-variant-numeric: tabular-nums;
}

/* Canonical screen-reader-only text — self-contained (NOT dependent on a framework class). CountUp
   uses it to expose the real value to assistive tech while the visible node animates. */
.rently-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;
}

/* Decorative one-shot glint for a celebratory accent (e.g. a freshly-earned trust milestone). Apply
   to a small aria-hidden element. One ~0.9s cycle ≈ 1.1 luminance pulses/sec — well under the SC 2.3.1
   three-per-second limit. Base opacity:0 so it is invisible except while animating (and under
   reduced-motion, where the animation is dropped entirely). */
@keyframes rently-sparkle {
    0% {
        opacity: 0;
        transform: scale(0.4) rotate(0deg);
    }

    50% {
        opacity: 1;
        transform: scale(1) rotate(8deg);
    }

    100% {
        opacity: 0;
        transform: scale(0.6) rotate(0deg);
    }
}

.rently-sparkle {
    opacity: 0;
    animation: rently-sparkle 0.9s ease-out both;
}

/* Reusable card hover-lift — ONE source of truth for the translateY + shadow idiom that was
   hand-rolled across many surfaces. Interaction-only; the movement is dropped under reduced motion. */
.rently-hover-lift,
.rently-hover-lift-sm {
    transition: transform var(--rently-transition-fast), box-shadow var(--rently-transition-fast);
}

.rently-hover-lift:hover {
    transform: translateY(-2px);
    box-shadow: var(--rently-shadow-hover);
}

.rently-hover-lift-sm:hover {
    transform: translateY(-1px);
    box-shadow: var(--rently-shadow-hover);
}

@media (prefers-reduced-motion: reduce) {
    /* Decorative glint dropped entirely (base opacity:0 keeps it invisible). */
    .rently-sparkle {
        animation: none;
    }

    /* Hover-lift: nothing moves (vestibular-safe). */
    .rently-hover-lift,
    .rently-hover-lift-sm {
        transition: none;
    }

    .rently-hover-lift:hover,
    .rently-hover-lift-sm:hover {
        transform: none;
    }
}

