/* ==============================================
   LIQUID GLASS DESIGN SYSTEM
   Main Entry Point
   
   Import order matters:
   1. Tokens (design primitives)
   2. Base (reset and defaults)
   3. Components (UI elements)
   4. Utilities (helper classes)
   ============================================== */

/* ------------------------------------------
   TOKENS
   ------------------------------------------ */
/* ==============================================
   COLOR TOKENS
   Liquid Glass Design System
   
   Key insight: Fills are almost invisible.
   The edge and blur do the work.
   ============================================== */

:root {
    /* ------------------------------------------
       GLASS FILLS
       Near-invisible, GRADED toward the light:
       brighter upper-left, falling off at 135deg.
       Use only in background: shorthand (these
       are images, not colors).
       ------------------------------------------ */
    --glass-fill-clear: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);
    --glass-fill-subtle: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    --glass-fill-light: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    --glass-fill-medium: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    --glass-fill-solid: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.13) 65%);

    /* Default for most glass elements */
    --glass-fill: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);

    /* ------------------------------------------
       EDGE SYSTEM
       Borders define shape ONLY. The luminous
       lip lives in the shadow rim tokens
       (--shadow-rim-*), not in the border.
       ------------------------------------------ */
    --edge-glow: rgba(255, 255, 255, 0.4);
    --edge-glow-subtle: rgba(255, 255, 255, 0.34);
    --edge-glow-bright: rgba(255, 255, 255, 0.5);
    --edge-glow-intense: rgba(255, 255, 255, 0.65);

    /* ------------------------------------------
       ACTIVE STATE FILLS
       Solid fills for selected/pressed states.
       These ARE visible - contrast with glass.
       ------------------------------------------ */
    --fill-active-white: rgba(255, 255, 255, 0.92);
    --fill-active-gold: rgba(212, 175, 55, 0.95);
    --fill-active-blue: rgba(0, 122, 255, 0.95);
    --fill-active-green: rgba(52, 199, 89, 0.95);
    --fill-active-red: rgba(255, 59, 48, 0.95);
    --fill-active-orange: rgba(255, 149, 0, 0.95);
    --fill-active-purple: rgba(175, 82, 222, 0.95);
    --fill-active-teal: rgba(0, 199, 190, 0.95);

    /* ------------------------------------------
       SEMANTIC COLORS
       For status badges and indicators only.
       Glass elements stay white/transparent.
       ------------------------------------------ */
    --color-primary: rgba(212, 175, 55, 0.95);
    --color-success: rgba(52, 199, 89, 0.95);
    --color-warning: rgba(255, 149, 0, 0.95);
    --color-error: rgba(255, 59, 48, 0.95);
    --color-info: rgba(0, 122, 255, 0.95);
    --color-premium: rgba(212, 175, 55, 0.95);

    /* ------------------------------------------
       TEXT COLORS
       White hierarchy on dark/blurred backgrounds.
       High contrast for legibility.
       ------------------------------------------ */
    --text-primary: rgba(255, 255, 255, 0.95);
    --text-secondary: rgba(255, 255, 255, 0.7);
    --text-tertiary: rgba(255, 255, 255, 0.5);
    --text-placeholder: rgba(255, 255, 255, 0.4);
    --text-disabled: rgba(255, 255, 255, 0.25);
    
    /* For active/solid fill states */
    --text-inverse: rgba(0, 0, 0, 0.9);
    --text-inverse-secondary: rgba(0, 0, 0, 0.6);

    /* ------------------------------------------
       ICON COLORS
       Icons inherit text color by default.
       Always white on glass elements.
       ------------------------------------------ */
    --icon-primary: rgba(255, 255, 255, 0.95);
    --icon-secondary: rgba(255, 255, 255, 0.7);
    --icon-tertiary: rgba(255, 255, 255, 0.5);
}

/* ==============================================
   TYPOGRAPHY TOKENS
   Liquid Glass Design System
   ============================================== */

:root {
    /* ------------------------------------------
       FONT FAMILIES
       ------------------------------------------ */
    --font-system: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    --font-mono: 'SF Mono', 'Fira Code', 'Consolas', monospace;

    /* ------------------------------------------
       FONT SIZES
       15px base for mobile readability
       ------------------------------------------ */
    --font-size-xs: 11px;
    --font-size-sm: 13px;
    --font-size-base: 15px;
    --font-size-md: 17px;
    --font-size-lg: 20px;
    --font-size-xl: 24px;
    --font-size-2xl: 32px;
    --font-size-3xl: 40px;

    /* ------------------------------------------
       FONT WEIGHTS
       ------------------------------------------ */
    --font-weight-regular: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    /* ------------------------------------------
       LINE HEIGHTS
       ------------------------------------------ */
    --line-height-tight: 1.2;
    --line-height-normal: 1.5;
    --line-height-relaxed: 1.7;

    /* ------------------------------------------
       LETTER SPACING
       ------------------------------------------ */
    --letter-spacing-tight: -0.02em;
    --letter-spacing-normal: 0;
    --letter-spacing-wide: 0.02em;
    --letter-spacing-caps: 0.1em;
}

/* ==============================================
   SPACING TOKENS
   Liquid Glass Design System
   4px base unit
   ============================================== */

:root {
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-8: 32px;
    --space-10: 40px;
    --space-12: 48px;
}

/* ==============================================
   BORDER RADIUS TOKENS
   Liquid Glass Design System
   
   Two shape types only:
   - Circles: Single-action atomic elements
   - Pills: Containers and compound elements
   
   No small-radius rectangles. Everything soft.
   ============================================== */

:root {
    /* ------------------------------------------
       SHAPE RADII
       Generous curves, never sharp.
       ------------------------------------------ */
    --radius-sm: 12px;
    --radius-md: 16px;
    --radius-lg: 20px;
    --radius-xl: 24px;
    --radius-2xl: 28px;
    --radius-3xl: 32px;
    
    /* Full radius for circles and pills */
    --radius-pill: 9999px;
    --radius-circle: 50%;

    /* ------------------------------------------
       SEMANTIC RADII
       Use these for consistency.
       ------------------------------------------ */
    
    /* Atomic buttons (icon-only, single action) */
    --radius-button-icon: 50%;
    
    /* Text buttons and inputs */
    --radius-button: 9999px;
    --radius-input: 24px;
    
    /* Cards and panels */
    --radius-card: 28px;
    --radius-panel: 32px;
    
    /* Tiles (square interactive) */
    --radius-tile: 24px;
}

/* ==============================================
   SHADOW TOKENS
   Liquid Glass Design System

   DIRECTIONAL LIGHT: one source, upper-left.
   The edge is a LIP, not a stroke: a soft inset
   rim brightest on the lit side, with a faint
   counter-rim where light exits lower-right.
   Two offset blurred insets overlap at the
   corners - that overlap is what reads as a lip.
   No omnidirectional glow: luminosity lives in
   the rim, never in a halo.
   ============================================== */

:root {
    /* ------------------------------------------
       LIT RIM
       Blurred inset from the upper-left.
       ------------------------------------------ */
    --shadow-rim-lit-subtle: inset 1px 1px 1px rgba(255, 255, 255, 0.4);
    --shadow-rim-lit: inset 1px 1px 1px rgba(255, 255, 255, 0.55);
    --shadow-rim-lit-strong: inset 1.5px 1.5px 1.5px rgba(255, 255, 255, 0.62);

    /* ------------------------------------------
       COUNTER RIM
       Faint light exiting the lower-right edge.
       Always dimmer than the lit rim.
       ------------------------------------------ */
    --shadow-rim-counter-subtle: inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14);
    --shadow-rim-counter: inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2);
    --shadow-rim-counter-strong: inset -1px -1px 1.5px rgba(255, 255, 255, 0.24);

    /* ------------------------------------------
       SPECULAR HAIRLINE
       A crisp 1px inner stroke, even all round.
       This is the clean-cut lip: it draws the
       sharp perimeter the blurred rim alone lacks.
       Keep it thin and low-alpha so it reads as a
       cut edge catching light, not a bright outline.
       ------------------------------------------ */
    --shadow-rim-spec-subtle: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    --shadow-rim-spec: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
    --shadow-rim-spec-strong: inset 0 0 0 1px rgba(255, 255, 255, 0.16);

    /* ------------------------------------------
       CAST SHADOW
       Wide, soft lift off the background.
       ------------------------------------------ */
    --shadow-relief-cast: 0 6px 18px rgba(0, 0, 0, 0.22);
    --shadow-relief-cast-strong: 0 10px 28px rgba(0, 0, 0, 0.28);

    /* ------------------------------------------
       PRESSED STATE
       Inverted relief - pressed INTO glass;
       the shadow falls in from the lit side.
       ------------------------------------------ */
    --shadow-pressed:
        inset 2px 3px 4px rgba(0, 0, 0, 0.18),
        inset -1px -1px 2px rgba(0, 0, 0, 0.08);

    /* ------------------------------------------
       COMPOSITE SHADOWS
       Pre-combined for common use cases.
       ------------------------------------------ */

    /* Subtle glass - for nested/secondary elements (cards, buttons, inputs) */
    --shadow-glass-subtle:
        inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    /* Standard glass element (tiles, panels) */
    --shadow-glass:
        inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);

    /* Elevated glass (modals, overlays) */
    --shadow-glass-elevated:
        inset 0 0 0 1px rgba(255, 255, 255, 0.16),
        inset 1.5px 1.5px 1.5px rgba(255, 255, 255, 0.62),
        inset -1px -1px 1.5px rgba(255, 255, 255, 0.24),
        0 10px 28px rgba(0, 0, 0, 0.28);

    /* Pressed/active state - PRESSED INTO GLASS */
    --shadow-glass-pressed:
        inset 2px 3px 4px rgba(0, 0, 0, 0.18), inset -1px -1px 2px rgba(0, 0, 0, 0.08),
        0 1px 4px rgba(0, 0, 0, 0.1);

    /* ------------------------------------------
       ICON RELIEF
       Drop shadows for embossed icon effect.
       Use with filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.4)) drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
       ------------------------------------------ */
    --icon-relief:
        drop-shadow(0 1px 0 rgba(255, 255, 255, 0.4))
        drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));

    --icon-relief-subtle:
        drop-shadow(0 1px 0 rgba(255, 255, 255, 0.25))
        drop-shadow(0 1px 2px rgba(0, 0, 0, 0.25));
}

/* ==============================================
   BLUR TOKENS
   Liquid Glass Design System
   
   Strong blur is essential. The reference uses
   aggressive blur (25-40px) with saturation boost
   to keep background colors vibrant.
   ============================================== */

:root {
    /* ------------------------------------------
       BLUR AMOUNTS
       Err on the side of more blur, not less.
       ------------------------------------------ */
    --blur-subtle: 16px;
    --blur-regular: 20px;
    --blur-strong: 30px;
    --blur-intense: 50px;

    /* ------------------------------------------
       SATURATION + BRIGHTNESS
       Gaussian blur preserves brightness and
       chroma -- averaging bright pixels stays
       bright -- so light backdrop colours can
       only be muted here, in the transfer:
       moderate saturation (was a 180% boost)
       plus a slight dim so pale regions stop
       punching through the glass.
       ------------------------------------------ */
    --saturation-boost: 120%;
    --backdrop-brightness: 0.92;

    /* ------------------------------------------
       COMPOSITE BACKDROP FILTERS
       Pre-combined for consistency.
       Always include -webkit- prefix.
       Mirror any change in scripts/
       generate-hero-frost.mjs (the TV bake).
       ------------------------------------------ */

    /* Standard glass blur */
    --backdrop-glass: blur(20px) saturate(120%) brightness(0.92);

    /* Subtle blur for secondary elements */
    --backdrop-glass-subtle: blur(16px) saturate(120%) brightness(0.92);

    /* Strong blur for panels/modals */
    --backdrop-glass-strong: blur(30px) saturate(120%) brightness(0.92);
}

/* ==============================================
   EDGE TOKENS
   Liquid Glass Design System

   Borders define SHAPE only - low-alpha
   hairlines. The luminous lip is drawn by the
   shadow rim tokens (--shadow-rim-*); a bright
   uniform border reads as an outline, not glass.
   ============================================== */

:root {
    /* ------------------------------------------
       EDGE WIDTHS
       Thicker than typical borders.
       Must be visible to create glass effect.
       ------------------------------------------ */
    --edge-width-hairline: 1px;
    --edge-width-thin: 1.5px;
    --edge-width: 2px;
    --edge-width-thick: 2.5px;

    /* ------------------------------------------
       COMPOSITE EDGES
       Pre-combined border shorthand.
       ------------------------------------------ */
    
    /* Standard glass edge */
    --edge-glass: 1px solid rgba(255, 255, 255, 0.4);

    /* Hairline edge for nested/secondary elements (cards, buttons, inputs) */
    --edge-glass-hairline: 1px solid rgba(255, 255, 255, 0.34);

    /* Subtle edge for standalone secondary elements (tiles, visual cards) */
    --edge-glass-subtle: 1px solid rgba(255, 255, 255, 0.34);

    /* Bright edge for primary/focused elements */
    --edge-glass-bright: 1.5px solid rgba(255, 255, 255, 0.5);

    /* Intense edge for hero elements */
    --edge-glass-intense: 1.5px solid rgba(255, 255, 255, 0.65);
}

/* ==============================================
   ANIMATION TOKENS
   Liquid Glass Design System
   
   Apple's secret: spring physics, not linear.
   Things have mass and momentum.
   ============================================== */

:root {
    /* ------------------------------------------
       EASING FUNCTIONS
       Spring-inspired curves - never use linear
       ------------------------------------------ */
    
    /* Standard deceleration - most UI uses this */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    
    /* Smooth both ends - repositioning, view transitions */
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    
    /* Overshoot and settle - interactive feedback */
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    
    /* Playful bounce - attention-grabbing */
    --ease-bounce: cubic-bezier(0.34, 1.8, 0.64, 1);
    
    /* Legacy alias */
    --ease-smooth: cubic-bezier(0.16, 1, 0.3, 1);
    
    /* Default for most transitions */
    --ease-default: cubic-bezier(0.16, 1, 0.3, 1);

    /* ------------------------------------------
       DURATIONS
       ------------------------------------------ */
    --duration-instant: 100ms;   /* Micro-feedback (opacity, color) */
    --duration-fast: 200ms;      /* Quick responses (button press) */
    --duration-normal: 300ms;    /* Standard transitions (page, modal) */
    --duration-slow: 500ms;      /* Deliberate motion (drawer, sheet) */
    --duration-dramatic: 800ms;  /* Attention-grabbing (onboarding) */
    
    /* ------------------------------------------
       COMPOSITE TRANSITIONS
       Pre-built for common patterns
       ------------------------------------------ */
    
    /* Standard glass transition - covers all interactive properties */
    --transition-glass: 
        transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1),
        opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
        background 200ms cubic-bezier(0.16, 1, 0.3, 1),
        border-color 200ms cubic-bezier(0.16, 1, 0.3, 1),
        box-shadow 200ms cubic-bezier(0.16, 1, 0.3, 1);
    
    /* Quick state changes */
    --transition-instant: 100ms cubic-bezier(0.16, 1, 0.3, 1);
    --transition-fast: 200ms cubic-bezier(0.16, 1, 0.3, 1);
    --transition-normal: 300ms cubic-bezier(0.16, 1, 0.3, 1);
    --transition-slow: 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* ==============================================
   FOCUS TOKENS
   Liquid Glass Design System
   
   On TV, focus IS the cursor. It must be
   unmistakable from 10 feet away.
   ============================================== */

:root {
    /* ------------------------------------------
       FOCUS RING
       Visible indicator for keyboard/remote nav
       ------------------------------------------ */
    --focus-ring-width: 3px;
    --focus-ring-offset: 4px;
    --focus-ring-color: rgba(255, 255, 255, 0.9);
    --focus-ring-glow: 0 0 20px rgba(255, 255, 255, 0.4);
    
    /* TV needs stronger indicators */
    --focus-ring-width-tv: 4px;
    --focus-ring-offset-tv: 6px;

    /* ------------------------------------------
       FOCUS SCALE
       Focused elements lift slightly
       ------------------------------------------ */
    --focus-scale: 1.02;         /* Subtle lift */
    --focus-scale-card: 1.03;    /* Cards get more emphasis */
    --focus-scale-hero: 1.05;    /* Hero elements pop */

    /* ------------------------------------------
       TOUCH TARGETS
       Minimum sizes for comfortable interaction
       ------------------------------------------ */
    --touch-target-min: 44px;    /* Apple HIG minimum */
    --touch-target-tablet: 48px;
    --touch-target-tv: 56px;     /* Larger for remote precision */
}

/* ------------------------------------------
   TV BREAKPOINT OVERRIDES
   Stronger focus for 10-foot viewing
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    :root {
        --focus-ring-width: 4px;
        --focus-ring-offset: 6px;
        --touch-target-min: 56px;
    }
}

/* ==============================================
   Z-INDEX TOKENS
   Liquid Glass Design System
   ============================================== */

:root {
    --z-base: 0;
    --z-raised: 10;
    --z-dropdown: 100;
    --z-sticky: 200;
    --z-modal: 300;
    --z-toast: 400;
    --z-tooltip: 500;
}


/* ------------------------------------------
   BASE
   ------------------------------------------ */
/* ==============================================
   CSS RESET
   Liquid Glass Design System
   ============================================== */

*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

button,
input,
select,
textarea {
    font: inherit;
    color: inherit;
    background: none;
    border: none;
}

button {
    cursor: pointer;
}

a {
    color: inherit;
    text-decoration: none;
}

img,
svg {
    display: block;
    max-width: 100%;
}

ul,
ol {
    list-style: none;
}

/* ==============================================
   BODY STYLES
   Liquid Glass Design System
   ============================================== */

html,
body {
    height: 100%;
    overflow: hidden;
    overscroll-behavior-y: none;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    font-size: 15px;
    font-weight: 400;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.95);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    
    /* Prevent overscroll bounce on iOS */
    overscroll-behavior: none;
    
    /* Safe area for notched devices */
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}


/* ------------------------------------------
   COMPONENTS
   ------------------------------------------ */
/* ==============================================
   GLASS TILE
   Square interactive element with icon and label.
   Use for grid-based navigation (home screens).
   
   KEY: Almost invisible fill, subtle border,
   tiny upper-left highlight. The backdrop blur
   does most of the work.
   ============================================== */

.glass-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 20px;
    aspect-ratio: 1;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Frosted glass blur - this is the main effect */
    backdrop-filter: blur(20px) saturate(120%) brightness(0.92);
    -webkit-backdrop-filter: blur(20px) saturate(120%) brightness(0.92);

    /* Pronounced bezel border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 24px;

    /* Raised relief - full 3D glass effect */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);

    /* White text/icons only */
    color: rgba(255, 255, 255, 0.95);
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    font-size: 13px;
    font-weight: 500;
    text-align: center;

    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    
    /* Smooth transitions */
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ------------------------------------------
   HOVER STATE
   Slightly brighter fill and border.
   ------------------------------------------ */
.glass-tile:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.28);
    box-shadow:
        inset 1.5px 2.5px 3px rgba(255, 255, 255, 0.5),
        inset -1px -1.5px 2.5px rgba(255, 255, 255, 0.14),
        0 6px 16px rgba(0, 0, 0, 0.18);
}

/* ------------------------------------------
   FOCUS STATE (Keyboard/Remote)
   Must be visible from 10 feet on TV.
   ------------------------------------------ */
.glass-tile:focus {
    outline: none;
}

.glass-tile:focus-visible {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.3);
    outline: 3px solid rgba(255, 255, 255, 0.9);
    outline-offset: 4px;
    box-shadow:
        0 0 20px rgba(255, 255, 255, 0.4),
        inset 1.5px 2.5px 3px rgba(255, 255, 255, 0.5),
        inset -1px -1.5px 2.5px rgba(255, 255, 255, 0.14),
        0 6px 18px rgba(0, 0, 0, 0.2);
    transform: scale(1.02);
}

/* ------------------------------------------
   ACTIVE/PRESSED STATE
   Scale down, slightly brighter.
   ------------------------------------------ */
.glass-tile:active {
    transform: scale(0.95);
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    border-color: rgba(255, 255, 255, 0.25);
    box-shadow:
        inset 2px 3px 4px rgba(0, 0, 0, 0.15),
        0 1px 4px rgba(0, 0, 0, 0.1);
    transition-duration: 100ms;
}

/* ------------------------------------------
   SELECTED STATE (White)
   Solid fill - maximum contrast with glass.
   ------------------------------------------ */
.glass-tile.selected {
    background: rgba(255, 255, 255, 0.9);
    border-color: rgba(255, 255, 255, 0.6);
    color: rgba(0, 0, 0, 0.9);
    box-shadow:
        inset 1.5px 2.5px 3px rgba(255, 255, 255, 0.9),
        inset -1px -1.5px 2.5px rgba(255, 255, 255, 0.14),
        0 6px 18px rgba(0, 0, 0, 0.2);
}

.glass-tile.selected .tile-icon {
    color: rgba(0, 0, 0, 0.9);
    filter: none;
}

/* ------------------------------------------
   COLOR VARIANTS
   For semantic/accent selections.
   ------------------------------------------ */
.glass-tile.selected-gold {
    background: rgba(212, 175, 55, 0.95);
    border-color: rgba(255, 200, 80, 0.4);
    color: #fff;
}

.glass-tile.selected-blue {
    background: rgba(0, 122, 255, 0.95);
    border-color: rgba(100, 170, 255, 0.4);
    color: #fff;
}

.glass-tile.selected-green {
    background: rgba(52, 199, 89, 0.95);
    border-color: rgba(100, 220, 130, 0.4);
    color: #fff;
}

/* ------------------------------------------
   TILE ICON
   White, sized for touch targets.
   Relief effect makes icons appear embossed.
   ------------------------------------------ */
.tile-icon {
    width: 44px;
    height: 44px;
    color: inherit;
    fill: currentColor;
    flex-shrink: 0;
    
    /* Raised relief - icon appears embossed from glass */
    filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.4))
        drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}

.tile-icon.sm {
    width: 32px;
    height: 32px;
}

.tile-icon.lg {
    width: 56px;
    height: 56px;
}

/* ------------------------------------------
   TILE LABEL
   ------------------------------------------ */
.tile-label {
    line-height: 1.2;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ==============================================
   GLASS CARD
   Horizontal list item for navigation.
   Use in scrollable lists and menus.
   
   KEY: Almost invisible fill, subtle border,
   tiny upper-left highlight.
   ============================================== */

.glass-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 20px 24px;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Frosted glass blur */

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 28px;

    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    /* White text */
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.95);

    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ------------------------------------------
   HOVER STATE
   ------------------------------------------ */
.glass-card:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.2);
    box-shadow:
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.35),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 4px 14px rgba(0, 0, 0, 0.12);
}

/* ------------------------------------------
   FOCUS STATE (Keyboard/Remote)
   Must be visible from 10 feet on TV.
   ------------------------------------------ */
.glass-card:focus {
    outline: none;
}

.glass-card:focus-visible {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.24);
    outline: 3px solid rgba(255, 255, 255, 0.9);
    outline-offset: 4px;
    box-shadow:
        0 0 20px rgba(255, 255, 255, 0.4),
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.4),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 6px 16px rgba(0, 0, 0, 0.15);
    transform: scale(1.03);
}

/* ------------------------------------------
   ACTIVE/PRESSED STATE
   ------------------------------------------ */
.glass-card:active {
    transform: scale(0.98);
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    box-shadow:
        inset 1.5px 2px 3px rgba(0, 0, 0, 0.08),
        0 1px 4px rgba(0, 0, 0, 0.08);
    transition-duration: 100ms;
}

/* ------------------------------------------
   CARD ICON
   Raised relief - icon appears embossed.
   ------------------------------------------ */
.card-icon {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    color: rgba(255, 255, 255, 0.95);
    fill: currentColor;
    
    /* Raised relief - icon appears embossed from glass */
    filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.4))
        drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}

/* ------------------------------------------
   CARD CONTENT
   Uses gap for title/subtitle spacing (gap-only contract)
   ------------------------------------------ */
.card-content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    text-align: left;
}

.card-title {
    font-size: 17px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
}

.card-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* ------------------------------------------
   CARD BADGE
   Solid fill - stands out from glass.
   ------------------------------------------ */
.card-badge {
    background: rgba(212, 175, 55, 0.95);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 9999px;
}

.card-badge.success {
    background: rgba(52, 199, 89, 0.95);
}

.card-badge.info {
    background: rgba(0, 122, 255, 0.95);
}

.card-badge.warning {
    background: rgba(255, 149, 0, 0.95);
}

.card-badge.error {
    background: rgba(255, 59, 48, 0.95);
}

/* ------------------------------------------
   CARD CHEVRON
   Subtle relief for secondary icons.
   ------------------------------------------ */
.card-chevron {
    width: 20px;
    height: 20px;
    color: rgba(255, 255, 255, 0.5);
    fill: currentColor;
    flex-shrink: 0;
    
    /* Subtle relief for secondary icons */
    filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.25))
        drop-shadow(0 1px 2px rgba(0, 0, 0, 0.25));
}

/* ==============================================
   GLASS BUTTON
   Action buttons in two forms:
   - Pill: Text buttons (default)
   - Circle: Icon-only buttons
   
   KEY: Almost invisible fill, subtle border,
   tiny upper-left highlight. Backdrop blur
   does most of the work.
   ============================================== */

.glass-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 20px;
    min-height: 44px;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Frosted glass blur */

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;

    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    /* White text */
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    font-size: 15px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);

    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ------------------------------------------
   HOVER STATE
   ------------------------------------------ */
.glass-button:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.2);
    box-shadow:
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.35),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 4px 14px rgba(0, 0, 0, 0.12);
}

/* ------------------------------------------
   FOCUS STATE (Keyboard/Remote)
   Must be visible from 10 feet on TV.
   ------------------------------------------ */
.glass-button:focus {
    outline: none;
}

.glass-button:focus-visible {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.24);
    outline: 3px solid rgba(255, 255, 255, 0.9);
    outline-offset: 4px;
    box-shadow:
        0 0 20px rgba(255, 255, 255, 0.4),
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.4),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 6px 16px rgba(0, 0, 0, 0.15);
    transform: scale(1.02);
}

/* ------------------------------------------
   ACTIVE/PRESSED STATE
   ------------------------------------------ */
.glass-button:active {
    transform: scale(0.96);
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    box-shadow: 
        inset 1.5px 2px 3px rgba(0, 0, 0, 0.08),
        0 1px 4px rgba(0, 0, 0, 0.08);
    transition-duration: 100ms;
}

/* ------------------------------------------
   DISABLED STATE
   ------------------------------------------ */
.glass-button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    transform: none;
}

/* ------------------------------------------
   PRIMARY VARIANT
   Solid gold fill - the main CTA.
   Use sparingly, one per screen.
   ------------------------------------------ */
.glass-button.primary {
    background: rgba(212, 175, 55, 0.95);
    border-color: rgba(255, 200, 80, 0.3);
    color: #fff;
    box-shadow: 
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.3),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 2px 10px rgba(0, 0, 0, 0.15);
}

.glass-button.primary:hover {
    background: rgba(230, 190, 60, 0.95);
    border-color: rgba(255, 215, 100, 0.4);
}

.glass-button.primary:active {
    background: rgba(190, 155, 45, 0.95);
}

/* ------------------------------------------
   SECONDARY VARIANT
   Subtler glass for de-emphasized actions.
   ------------------------------------------ */
.glass-button.secondary {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);
    border-color: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.7);
    box-shadow: 
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.15),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 1px 4px rgba(0, 0, 0, 0.08);
}

.glass-button.secondary:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border-color: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.95);
}

/* ------------------------------------------
   DESTRUCTIVE VARIANT
   Solid red for dangerous actions.
   ------------------------------------------ */
.glass-button.destructive {
    background: rgba(255, 59, 48, 0.95);
    border-color: rgba(255, 100, 90, 0.3);
    color: #fff;
    box-shadow: 
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.25),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 2px 10px rgba(0, 0, 0, 0.15);
}

.glass-button.destructive:hover {
    border-color: rgba(255, 120, 110, 0.4);
}

/* ------------------------------------------
   SUCCESS VARIANT
   Solid green for confirmations.
   ------------------------------------------ */
.glass-button.success {
    background: rgba(52, 199, 89, 0.95);
    border-color: rgba(100, 220, 130, 0.3);
    color: #fff;
    box-shadow: 
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.25),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 2px 10px rgba(0, 0, 0, 0.15);
}

.glass-button.success:hover {
    border-color: rgba(120, 230, 150, 0.4);
}

/* ------------------------------------------
   SIZE: SMALL
   ------------------------------------------ */
.glass-button.sm {
    padding: 8px 16px;
    min-height: 36px;
    font-size: 13px;
}

/* ------------------------------------------
   SIZE: LARGE
   ------------------------------------------ */
.glass-button.lg {
    padding: 16px 24px;
    min-height: 52px;
    font-size: 17px;
}

/* ------------------------------------------
   SHAPE: ICON-ONLY (Circle)
   For single-action atomic buttons.
   Icon fills ~60-62% of button for refined look.
   Minimum 44px touch target (Apple HIG).
   ------------------------------------------ */
.glass-button.icon-only {
    padding: 0;
    width: 44px;
    height: 44px;
    min-height: auto;
    border-radius: 50%;
}

/* Small variant still meets touch target minimum */
.glass-button.icon-only.sm {
    width: 44px;
    height: 44px;
}

/* Smaller icon inside small button */
.glass-button.icon-only.sm .btn-icon {
    width: 20px;
    height: 20px;
}

.glass-button.icon-only.lg {
    width: 56px;
    height: 56px;
}

/* ------------------------------------------
   BUTTON ICON
   Scales with button size for proper ratio.
   Raised relief - icon appears embossed.
   ------------------------------------------ */
.btn-icon {
    width: 24px;
    height: 24px;
    fill: currentColor;
    flex-shrink: 0;
    
    /* Raised relief - subtle for smaller icons */
    filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.25))
        drop-shadow(0 1px 2px rgba(0, 0, 0, 0.25));
}

/* Smaller icon for small buttons */
.glass-button.sm .btn-icon {
    width: 20px;
    height: 20px;
}

/* Larger icon for large buttons */
.glass-button.lg .btn-icon {
    width: 28px;
    height: 28px;
}

/* ==============================================
   GLASS PANEL
   Container for grouped content.
   Can contain child glass elements (nested glass).
   
   KEY: Almost invisible fill, subtle border,
   stronger blur for containers.
   ============================================== */

.glass-panel {
    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Stronger blur for panels */
    backdrop-filter: blur(30px) saturate(120%) brightness(0.92);
    -webkit-backdrop-filter: blur(30px) saturate(120%) brightness(0.92);

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 32px;

    /* Raised relief - full 3D glass effect */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);

    /* Layout: gap-only spacing for children */
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
}

/* ------------------------------------------
   NESTED GLASS
   Child glass elements inside panel.
   Slightly subtler treatment to create hierarchy.
   ------------------------------------------ */
.glass-panel .glass-button,
.glass-panel .glass-tile {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);
}

.glass-panel .glass-button:hover,
.glass-panel .glass-tile:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.18);
}

/* ------------------------------------------
   PANEL HEADER
   ------------------------------------------ */
.panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.panel-title {
    font-size: 20px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
}

.panel-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* ------------------------------------------
   PANEL CONTENT
   Uses gap for all child spacing.
   ------------------------------------------ */
.panel-content {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* ------------------------------------------
   PANEL ACTIONS
   Row of buttons at bottom.
   Parent must use gap to space this from content above.
   ------------------------------------------ */
.panel-actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* ------------------------------------------
   PANEL FOOTER
   Separator + actions.
   Parent must use gap to space this from content above.
   ------------------------------------------ */
.panel-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    padding-top: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
}

/* ==============================================
   GLASS INPUT
   Text input with glass treatment.
   
   KEY: Almost invisible fill, subtle border,
   tiny upper-left highlight.
   ============================================== */

.glass-input {
    width: 100%;
    padding: 16px 20px;
    min-height: 52px;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Frosted glass blur */

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 24px;

    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    /* White text */
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    font-size: 17px;
    color: rgba(255, 255, 255, 0.95);

    outline: none;
    -webkit-appearance: none;
    

}

/* ------------------------------------------
   PLACEHOLDER
   Lower opacity than regular text.
   ------------------------------------------ */
.glass-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

/* ------------------------------------------
   FOCUS STATE
   Brighter edge indicates focus.
   ------------------------------------------ */
.glass-input:focus {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.24);
    box-shadow:
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.35),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 3px 12px rgba(0, 0, 0, 0.12);
}

/* ------------------------------------------
   DISABLED STATE
   ------------------------------------------ */
.glass-input:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ------------------------------------------
   ERROR STATE
   ------------------------------------------ */
.glass-input.error {
    border-color: rgba(255, 80, 70, 0.5);
}

.glass-input.error:focus {
    border-color: rgba(255, 80, 70, 0.7);
}

/* ------------------------------------------
   INPUT WITH ICON
   ------------------------------------------ */
.input-with-icon {
    position: relative;
}

.input-with-icon .glass-input {
    padding-right: calc(20px + 24px + 16px);
}

.input-with-icon .input-icon {
    position: absolute;
    right: 20px;
    top: 50%;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    color: rgba(255, 255, 255, 0.5);
    pointer-events: none;
}

.input-with-icon .input-icon.clickable {
    pointer-events: auto;
    cursor: pointer;
    color: rgba(255, 255, 255, 0.7);
}

.input-with-icon .input-icon.clickable:hover {
    color: rgba(255, 255, 255, 0.95);
}

/* ------------------------------------------
   INPUT WRAPPER
   Label + input + hint/error.
   ------------------------------------------ */
.input-wrapper {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.input-label {
    font-size: 13px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.7);
    padding-left: 8px;
}

.input-hint {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.5);
    padding-left: 8px;
}

.input-error {
    font-size: 11px;
    color: rgba(255, 59, 48, 0.95);
    padding-left: 8px;
}

/* ==============================================
   GLASS TOGGLE
   On/off switch control.
   
   KEY: Almost invisible fill, subtle border,
   tiny highlight from the upper-left.
   ============================================== */

.glass-toggle {
    position: relative;
    width: 56px;
    height: 32px;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    
    /* Frosted glass blur */

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;

    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    

}

/* ------------------------------------------
   TOGGLE THUMB
   Solid white circle that slides.
   ------------------------------------------ */
.toggle-thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 24px;
    height: 24px;

    background: rgba(255, 255, 255, 0.92);
    border-radius: 50%;

    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);

    transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ------------------------------------------
   ACTIVE STATE
   Solid green track.
   ------------------------------------------ */
.glass-toggle.active {
    background: rgba(52, 199, 89, 0.95);
    border-color: rgba(100, 220, 130, 0.3);
    box-shadow:
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.25),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 2px 8px rgba(0, 0, 0, 0.12);
}

.glass-toggle.active .toggle-thumb {
    transform: translateX(24px);
}

/* ------------------------------------------
   HOVER STATE
   ------------------------------------------ */
.glass-toggle:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    border-color: rgba(255, 255, 255, 0.18);
}

.glass-toggle.active:hover {
    background: rgba(60, 210, 100, 0.95);
}

/* ------------------------------------------
   DISABLED STATE
   ------------------------------------------ */
.glass-toggle.disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ------------------------------------------
   SIZE: LARGE
   ------------------------------------------ */
.glass-toggle.lg {
    width: 68px;
    height: 40px;
}

.glass-toggle.lg .toggle-thumb {
    top: 4px;
    left: 4px;
    width: 30px;
    height: 30px;
}

.glass-toggle.lg.active .toggle-thumb {
    transform: translateX(28px);
}

/* ==============================================
   GLASS SLIDER
   Vertical slider for controls like
   brightness, volume, temperature.
   
   KEY: Almost invisible fill, subtle border,
   tiny upper-left highlight.
   ============================================== */

.glass-slider {
    position: relative;
    width: 70px;
    height: 180px;

    /* Almost invisible fill */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    /* Frosted glass blur */

    /* Subtle uniform border */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;

    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    overflow: hidden;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* ------------------------------------------
   SLIDER FILL
   Solid white, rises from bottom.
   ------------------------------------------ */
.slider-fill {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    
    background: rgba(255, 255, 255, 0.92);
    border-radius: 0 0 calc(9999px - 3px) calc(9999px - 3px);
    

}

/* ------------------------------------------
   SLIDER ICON
   At bottom of track, inverts on fill.
   ------------------------------------------ */
.slider-icon {
    position: absolute;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    width: 28px;
    height: 28px;
    color: rgba(0, 0, 0, 0.9);
    z-index: 2;
    

}

/* When fill is low, icon should be white */
.glass-slider[data-value="low"] .slider-icon {
    color: rgba(255, 255, 255, 0.95);
}

/* ------------------------------------------
   SLIDER VALUE LABEL
   ------------------------------------------ */
.slider-value {
    position: absolute;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    z-index: 2;
}

/* ------------------------------------------
   SLIDER LABEL
   ------------------------------------------ */
.slider-label {
    position: absolute;
    top: calc(16px + 20px + 4px);
    left: 50%;
    transform: translateX(-50%);
    font-size: 11px;
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    z-index: 2;
}

/* ------------------------------------------
   SIZE: COMPACT
   ------------------------------------------ */
.glass-slider.compact {
    width: 60px;
    height: 140px;
}

.glass-slider.compact .slider-icon {
    width: 24px;
    height: 24px;
    bottom: 16px;
}

/* ------------------------------------------
   SIZE: LARGE
   ------------------------------------------ */
.glass-slider.lg {
    width: 80px;
    height: 220px;
}

.glass-slider.lg .slider-icon {
    width: 32px;
    height: 32px;
}

/* ==============================================
   GLASS VISUAL CARD
   Large image card with title overlay.
   Use for Pattern A: Direct Display (e.g., Dine & Drink venues)
   
   KEY: Hero image is the visual, text overlays at bottom
   with gradient for legibility. Glass edge treatment.
   ============================================== */

.glass-visual-card {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 160px;
    overflow: hidden;
    
    /* Glass edge treatment */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 28px;
    
    /* Subtle glass shadow */
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);
    
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ------------------------------------------
   BACKGROUND IMAGE
   ------------------------------------------ */
.visual-card-image {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    background-size: cover;
    background-position: center;
    z-index: 0;
    
    /* Smooth zoom on hover */
    transition: transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Gradient overlay for text legibility */
.glass-visual-card::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    background: linear-gradient(
        to top,
        rgba(0, 0, 0, 0.75) 0%,
        rgba(0, 0, 0, 0.4) 40%,
        rgba(0, 0, 0, 0.1) 70%,
        transparent 100%
    );
    z-index: 1;
    pointer-events: none;
}

/* ------------------------------------------
   CONTENT OVERLAY
   ------------------------------------------ */
.visual-card-content {
    position: relative;
    z-index: 2;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.visual-card-title {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

.visual-card-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* ------------------------------------------
   HOVER STATE
   ------------------------------------------ */
.glass-visual-card:hover {
    border-color: rgba(255, 255, 255, 0.28);
    box-shadow:
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.35),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 6px 20px rgba(0, 0, 0, 0.25);
}

.glass-visual-card:hover .visual-card-image {
    transform: scale(1.05);
}

/* ------------------------------------------
   FOCUS STATE (Keyboard/Remote)
   ------------------------------------------ */
.glass-visual-card:focus {
    outline: none;
}

.glass-visual-card:focus-visible {
    border-color: rgba(255, 255, 255, 0.3);
    outline: 3px solid rgba(255, 255, 255, 0.9);
    outline-offset: 4px;
    box-shadow:
        0 0 20px rgba(255, 255, 255, 0.4),
        inset 1px 1.5px 2px rgba(255, 255, 255, 0.4),
        inset -0.5px -1px 1.5px rgba(255, 255, 255, 0.1),
        0 6px 24px rgba(0, 0, 0, 0.3);
    transform: scale(1.03);
}

.glass-visual-card:focus-visible .visual-card-image {
    transform: scale(1.05);
}

/* ------------------------------------------
   ACTIVE/PRESSED STATE
   ------------------------------------------ */
.glass-visual-card:active {
    transform: scale(0.98);
    box-shadow:
        inset 1.5px 2px 3px rgba(0, 0, 0, 0.1),
        0 2px 8px rgba(0, 0, 0, 0.15);
    transition-duration: 100ms;
}

.glass-visual-card:active .visual-card-image {
    transform: scale(1.02);
}

/* ------------------------------------------
   TV MODE - Larger cards
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .glass-visual-card {
        min-height: 200px;
    }
    
    .visual-card-title {
        font-size: 24px;
    }
    
    .visual-card-subtitle {
        font-size: 15px;
    }
}

/* ==============================================
   GLASS INFO CARD
   Single card displaying multiple key/value pairs.
   Use for Pattern B: Info Categories (e.g., Stay Details)
   
   KEY: Comprehensive info on one card, no further
   drilling down. Optional hero image at top.
   ============================================== */

.glass-info-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    
    /* Glass treatment */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 28px;
    
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);
}

/* ------------------------------------------
   HERO IMAGE (Optional)
   ------------------------------------------ */
.info-card-image {
    height: 160px;
    background-size: cover;
    background-position: center;
    border-radius: 28px 28px 0 0;
    margin: -1px -1px 0 -1px; /* Overlap border */
}

/* ------------------------------------------
   HEADER (Title only - subtitle removed as redundant)
   ------------------------------------------ */
.info-card-header {
    padding: 16px 16px 0;
}

.info-card-title {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
}

.info-card-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* Large value display (e.g., room number) */
.info-card-value-large {
    font-size: 32px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    text-align: center;
    padding: 16px 0;
}

/* ------------------------------------------
   CONTENT ROWS
   ------------------------------------------ */
.info-card-content {
    padding: 12px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 0;
}

.info-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.info-row:last-child {
    border-bottom: none;
}

.info-label {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    flex-shrink: 1;
    min-width: 0;
}

.info-value {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.95);
    text-align: right;
    word-break: break-word;
}

/* Monospace variant for codes/passwords */
.info-value.mono {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    letter-spacing: 0.05em;
}

/* ------------------------------------------
   SECTIONS (Groups within card)
   ------------------------------------------ */
.info-section {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.info-section:first-of-type,
.info-section-group + .info-section {
    border-top: none;
}

.info-section-title {
    font-size: 15px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
}

.info-section-content {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

/* Group divider used inside info-screen renders to label sub-groups
   (e.g. hotel-guide groups like "Restaurants", "Spa"). Sits flush against
   the card edge, not indented like info-section. */
.info-section-group {
    padding: 12px 16px 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: rgba(255, 255, 255, 0.5);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.info-section-group:first-of-type {
    border-top: none;
}

/* Compact info-section used when an item has 2+ details and we drop to
   a stacked layout. Less padding than the full info-section, name renders
   like a row label rather than a section heading. */
.info-section-compact {
    padding: 8px 16px;
    gap: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.info-section-compact .info-section-title {
    font-size: 15px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
    padding-bottom: 4px;
}

.info-section-compact .info-row {
    padding: 4px 0;
    border-bottom: none;
}

.info-section-compact .info-row .info-label {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.5);
}

.info-section-compact .info-row .info-value {
    font-size: 13px;
}

/* Items with no detail value (just a name + optional group label) -- the
   right column shows the group as muted text or stays blank. */
.info-row-name-only .info-value {
    min-height: 1em;
}

.info-value-muted {
    color: rgba(255, 255, 255, 0.5);
    font-size: 13px;
    font-weight: normal;
    text-transform: none;
    letter-spacing: 0;
}

/* ------------------------------------------
   NOTE (inline, no special styling)
   ------------------------------------------ */
.info-note {
    padding: 8px 0;
}

.info-note p {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.7;
    margin: 0;
}

/* ------------------------------------------
   BADGE (Included / Extra Charge)
   ------------------------------------------ */
.info-badge {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 9999px;
    font-size: 11px;
    font-weight: 600;
}

.info-badge.included {
    background: rgba(56, 161, 105, 0.2);
    color: rgba(0, 199, 190, 0.95);
}

.info-badge.supplement {
    background: rgba(237, 137, 54, 0.2);
    color: rgba(255, 149, 0, 0.95);
}

/* ------------------------------------------
   GUARDIAN DIETARY CARD (turquoise glass tint)
   ------------------------------------------ */
.glass-guardian {
    background: linear-gradient(
        135deg,
        rgba(56, 161, 105, 0.08) 0%,
        linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%) 60%
    );
    border-color: rgba(56, 161, 105, 0.15);
}

.glass-guardian .info-card-subtitle {
    font-size: 11px;
    color: rgba(56, 161, 105, 0.7);
    letter-spacing: 0.02em;
}

/* ------------------------------------------
   DIETARY PREFERENCE PILLS
   ------------------------------------------ */
.dietary-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.dietary-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Tighter horizontal padding packs more pills per row; vertical padding
       held at --space-2 to keep a comfortable tap target. */
    padding: 8px;
    /* Never let a long custom Opera description (e.g. "Severe Tree Nut and
       Peanut Allergy") stretch a single pill past the card and clip under
       the panel's overflow-x:hidden -- it wraps inside the pill instead. */
    max-width: 100%;
    border-radius: 9999px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.7);
    font-size: 13px;
    text-align: center;
    cursor: pointer;

}

.dietary-pill.active {
    background: rgba(56, 161, 105, 0.25);
    color: rgba(255, 255, 255, 0.95);
    border-color: rgba(0, 199, 190, 0.95);
}

.dietary-pill.saving {
    opacity: 0.5;
}

.dietary-pill:disabled {
    cursor: wait;
}

.dietary-loading {
    color: rgba(255, 255, 255, 0.5);
    font-size: 13px;
}

.guardian-empty {
    color: rgba(255, 255, 255, 0.7);
    font-size: 13px;
    line-height: 1.5;
    margin: 0;
}

/* ------------------------------------------
   TV MODE
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .info-card-image {
        height: 200px;
    }
    
    .info-card-title {
        font-size: 24px;
    }
    
    .info-card-value-large {
        font-size: 44px;
    }
}

/* ==============================================
   GLASS DIVIDER
   Section divider with optional centered text.
   Use to separate groups within a list (e.g., Restaurants | Bars)
   
   KEY: Subtle lines that don't span full width,
   centered text label. Matches glass aesthetic.
   ============================================== */

.glass-divider {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 0;
}

/* Lines on either side of text */
.glass-divider::before,
.glass-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.25) 20%,
        rgba(255, 255, 255, 0.25) 80%,
        transparent 100%
    );
}

/* ------------------------------------------
   DIVIDER TEXT
   ------------------------------------------ */
.divider-text {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

/* ------------------------------------------
   VARIANT: No Text (Line Only)
   ------------------------------------------ */
.glass-divider.line-only::before,
.glass-divider.line-only::after {
    flex: none;
    width: 60%;
    margin: 0 auto;
}

.glass-divider.line-only::after {
    display: none;
}

/* ------------------------------------------
   VARIANT: Full Width
   ------------------------------------------ */
.glass-divider.full-width::before,
.glass-divider.full-width::after {
    background: rgba(255, 255, 255, 0.15);
}

/* ------------------------------------------
   TV MODE
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .divider-text {
        font-size: 15px;
    }
}

/* ==============================================
   GLASS CHAT
   WhatsApp-style conversation thread with glass
   treatment. Used in the Messages top panel.
   
   KEY: Bubbles are glass elements with directional
   tails. Outgoing slightly brighter to distinguish.
   ============================================== */

/* ------------------------------------------
   CHAT VIEW
   Override panel-view defaults for chat layout.
   Panel-view is absolute-positioned; chat needs
   flex column with no parent scroll.
   ------------------------------------------ */
.chat-view {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* 8px inset on the sides + bottom; flush under the header at the top. */
    padding: 0 8px 8px;
}

.chat-view.active {
    opacity: 1;
    pointer-events: auto;
}

/* ------------------------------------------
   MESSAGES PANEL LAYOUT (standard chat panel)
   The panel is a FIXED 65% of the viewport; the header + input bar are pinned
   and ONLY the thread scrolls. Overrides the default top-panel (which shrinks to
   content and scrolls the whole wrapper). Toggled by .is-chat on #topPanel
   (app.openTopPanel for 'messages').
   ------------------------------------------ */
.top-panel.is-chat {
    height: 75vh;
    height: 75dvh;
}

.top-panel.is-chat .panel-container {
    height: 100%;
    max-height: 100%;
}

.top-panel.is-chat .service-header {
    flex-shrink: 0;
}

/* Wrapper fills the container and does NOT scroll -- the thread does. */
.top-panel.is-chat .panel-content-wrapper {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

/* Chat view fills the wrapper as a bounded flex column (override the
   content-driven top-panel panel-view). */
.top-panel.is-chat .chat-view {
    position: absolute;
    inset: 0;
    height: auto;
    overflow: hidden;
}

/* ------------------------------------------
   CHAT CONTAINER
   Flex column: thread fills space, input bar
   sticks to bottom.
   ------------------------------------------ */
.chat-container {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

/* ------------------------------------------
   CHAT THREAD
   Scrollable message area between header
   and input bar.
   ------------------------------------------ */
.chat-thread {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 0;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* ------------------------------------------
   DAY MARKER
   Reuses glass-divider pattern inline.
   ------------------------------------------ */
.chat-day-marker {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 0;
    align-self: stretch;
}

.chat-day-marker::before,
.chat-day-marker::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.25) 20%,
        rgba(255, 255, 255, 0.25) 80%,
        transparent 100%
    );
}

.chat-day-marker:first-child {
    padding-top: 0;
}

.chat-day-text {
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

/* ------------------------------------------
   CHAT BUBBLE (base)
   Glass treatment with directional tail via
   asymmetric border-radius.
   ------------------------------------------ */
.chat-bubble {
    max-width: 80%;
    padding: 8px 12px;

    /* Glass treatment */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 20px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);

    /* Text */
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
    font-size: 15px;
    color: rgba(255, 255, 255, 0.95);
    line-height: 1.5;

    /* No word overflow */
    word-wrap: break-word;
    overflow-wrap: break-word;
}

/* ------------------------------------------
   INCOMING (hotel messages) -- left aligned
   ------------------------------------------ */
.chat-bubble.incoming {
    align-self: flex-start;
    border-bottom-left-radius: 12px;
}

/* ------------------------------------------
   OUTGOING (guest messages) -- right aligned,
   slightly brighter fill to distinguish
   ------------------------------------------ */
.chat-bubble.outgoing {
    align-self: flex-end;
    border-bottom-right-radius: 12px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    border-color: rgba(255, 255, 255, 0.18);
}

/* ------------------------------------------
   REQUEST / STATUS bubble (TLP-083)
   System-generated, one-way status updates for
   guest requests. Styled DISTINCTLY from the
   rounded free-text bubbles -- blocky (square)
   corners + a quiet reference line. Final visual
   treatment is deferred (TLP-083); this is the slot.
   No left-accent border (house rule).
   ------------------------------------------ */
.chat-bubble.chat-request {
    align-self: flex-start;
    /* Blocky vs the rounded free-text bubble. */
    border-radius: 12px;
    /* Tighter than the default bubble so status text has more room. */
    padding: 8px 12px;
}

/* Status bubbles carry the reference + time on ONE normal-flow meta row (not the
   absolute .chat-meta-inline), so the text doesn't reserve bottom padding. */
.chat-bubble.chat-request .chat-bubble-text {
    padding-bottom: 0;
}

.chat-request-meta {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 3px;
    font-size: 11px;
    line-height: 1;
}

.chat-request-ref {
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    letter-spacing: 0.04em;
}

.chat-request-time {
    margin-left: auto;
    color: rgba(255, 255, 255, 0.35);
    white-space: nowrap;
}

/* ------------------------------------------
   CHAT META (inline, inside bubble)
   Floated into the bottom-right corner of
   the bubble text. Spacer reserves room so
   text wraps around the meta naturally.
   ------------------------------------------ */
.chat-bubble {
    position: relative;
}

.chat-bubble-text {
    display: block;
    padding-bottom: 10px;
}

.chat-meta-inline {
    position: absolute;
    bottom: 4px;
    right: 8px;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.35);
    white-space: nowrap;
    line-height: 1;
    letter-spacing: 0.01em;
}

.chat-status {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.35);
    margin-left: 1px;
}

.chat-status.read {
    color: rgba(0, 122, 255, 0.6);
}

/* ------------------------------------------
   CHAT INPUT BAR
   Fixed at bottom of chat container.
   ------------------------------------------ */
.chat-input-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    /* No bottom padding -- the input row sits at the bottom of the bar. */
    padding: 8px 0 0;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    flex-shrink: 0;
}

.chat-input-bar .glass-input {
    flex: 1;
    /* Match the send icon's height; even 8px internal padding all round. */
    height: 44px;
    min-height: 44px;
    padding: 8px;
}

.chat-input-bar .glass-button {
    flex-shrink: 0;
}

/* One-way this phase: the guest can't send. Disabled input + send read as inert. */
.chat-input-bar .glass-input:disabled,
.chat-input-bar .glass-button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

/* ------------------------------------------
   UNREAD BADGE
   On the header Messages button.
   Same pattern as order-badge.
   ------------------------------------------ */
/* Badge wrapper -- backdrop-filter on glass-button
   creates an implicit clip context in WebKit/Safari.
   We wrap the button + badge in a positioned container
   so the badge sits outside the button's filter scope. */
.messages-btn-wrap {
    position: relative;
    display: inline-flex;
}

.chat-unread-badge {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    background: rgba(255, 59, 48, 0.95);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    border-radius: 9999px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    z-index: 1;
}

/* ------------------------------------------
   EMPTY STATE
   When no messages yet.
   ------------------------------------------ */
.chat-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
}

.chat-empty-icon {
    width: 48px;
    height: 48px;
    color: rgba(255, 255, 255, 0.5);
    fill: currentColor;
    filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.25))
        drop-shadow(0 1px 2px rgba(0, 0, 0, 0.25));
}

.chat-empty-text {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

/* ------------------------------------------
   TV MODE
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .chat-bubble {
        max-width: 65%;
    }

    .chat-thread {
        padding: 16px;
        gap: 12px;
    }
}

/* ------------------------------------------
   REDUCED MOTION
   ------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    .chat-bubble,
    .chat-input-bar {
        transition: none;
    }
}

/* ==============================================
   GLASS CAROUSEL
   Full-screen slideshow inside the detail modal.
   Grouped slides: divider (title) + image (content).
   Swipe/snap navigation with dot indicators.
   ============================================== */

/* ------------------------------------------
   CAROUSEL MODAL OVERRIDES
   When the modal hosts a carousel, remove its
   default padding/scroll so the carousel owns
   the viewport.
   ------------------------------------------ */
.detail-modal.carousel-active {
    padding: 0;
    overflow: hidden;
    /* Force tall: content-driven height won't work because
       background-image slides have no intrinsic height */
    height: 80vh;
    max-width: 480px;
}

.detail-modal.carousel-active .modal-content {
    padding: 0;
    gap: 0;
    height: 100%;
}

/* ------------------------------------------
   CAROUSEL CONTAINER
   ------------------------------------------ */
.carousel {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* ------------------------------------------
   GROUP LABEL (current section indicator)
   ------------------------------------------ */
.carousel-group-label {
    position: absolute;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 3;
    padding: 4px 16px;
    /* Tint only -- NO backdrop-filter: this lives inside the modal stack
       (transformed .detail-modal ancestor = backdrop root on WebKit/old
       Blink), and the overlay already supplies the stack's one blur. */
    background: rgba(0, 0, 0, 0.5);
    border-radius: 9999px;
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.9);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    pointer-events: none;
    transition: opacity 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* ------------------------------------------
   TRACK (horizontal scroll-snap)
   ------------------------------------------ */
.carousel-track {
    flex: 1;
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.carousel-track::-webkit-scrollbar {
    display: none;
}

/* ------------------------------------------
   SLIDE (base)
   ------------------------------------------ */
.carousel-slide {
    flex: 0 0 100%;
    width: 100%;
    min-height: 0;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

/* ------------------------------------------
   DIVIDER SLIDE (section title)
   Tint only -- NO backdrop-filter (one blur per modal stack; a live blur
   here is also dead under the transformed .detail-modal on WebKit).
   ------------------------------------------ */
.carousel-slide-divider {
    background: rgba(0, 0, 0, 0.4);
    padding: 24px;
    text-align: center;
    gap: 12px;
}

.carousel-slide-divider .slide-group-title {
    font-size: 24px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    letter-spacing: 0.02em;
}

.carousel-slide-divider .slide-group-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    max-width: 280px;
}

/* Decorative line above title */
.carousel-slide-divider .slide-group-title::before {
    content: '';
    display: block;
    width: 40px;
    height: 2px;
    background: rgba(212, 175, 55, 0.95);
    margin: 0 auto 16px;
    border-radius: 1px;
}

/* ------------------------------------------
   IMAGE SLIDE (full-bleed photo + overlay)
   ------------------------------------------ */
.carousel-slide-image {
    background-size: cover;
    background-position: center;
    background-color: rgba(0, 0, 0, 0.6);
}

/* Dark gradient for text legibility */
.carousel-slide-image::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    background: linear-gradient(
        to top,
        rgba(0, 0, 0, 0.8) 0%,
        rgba(0, 0, 0, 0.3) 35%,
        rgba(0, 0, 0, 0.05) 60%,
        transparent 100%
    );
    z-index: 1;
    pointer-events: none;
}

/* Content overlay at bottom */
.carousel-slide-content {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 2;
    padding: 24px 16px;
    padding-bottom: calc(24px + 40px);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.carousel-slide-content .slide-title {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

.carousel-slide-content .slide-description {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.75);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    line-height: 1.7;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* CTA note */
.carousel-slide-cta {
    font-size: 11px;
    color: rgba(212, 175, 55, 0.95);
    font-weight: 500;
    padding-top: 4px;
}

/* ------------------------------------------
   NAVIGATION BAR (dots + arrows)
   ------------------------------------------ */
.carousel-nav {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 16px;
    background: linear-gradient(
        to top,
        rgba(0, 0, 0, 0.4) 0%,
        transparent 100%
    );
}

/* Arrow buttons */
.carousel-arrow {
    width: 32px;
    height: 32px;
    min-height: 32px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.15);
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 50%;
    color: rgba(255, 255, 255, 0.8);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.carousel-arrow:hover {
    background: rgba(255, 255, 255, 0.25);
}

.carousel-arrow:active {
    transform: scale(0.9);
}

.carousel-arrow:disabled {
    opacity: 0.3;
    cursor: default;
}

.carousel-arrow svg {
    width: 16px;
    height: 16px;
}

/* Dots container */
.carousel-dots {
    display: flex;
    align-items: center;
    gap: 6px;
    max-width: 200px;
    overflow: hidden;
}

.carousel-dot {
    width: 6px;
    height: 6px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.35);
    border: none;
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;

}

.carousel-dot.active {
    width: 18px;
    background: rgba(255, 255, 255, 0.9);
}

/* Divider dots get a subtle gold tint */
.carousel-dot.divider-dot.active {
    background: rgba(212, 175, 55, 0.95);
}

/* ------------------------------------------
   COUNTER (slide number)
   ------------------------------------------ */
.carousel-counter {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 3;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.6);
    pointer-events: none;
}

/* ------------------------------------------
   CLOSE BUTTON OVERRIDE
   Position close button above carousel
   ------------------------------------------ */
.detail-modal.carousel-active .modal-close {
    z-index: 4;
    /* Tint only -- see the group-label note (one blur per modal stack). */
    background: rgba(0, 0, 0, 0.5);
    border-color: rgba(255, 255, 255, 0.22);
}

.detail-modal.carousel-active .modal-close .btn-icon {
    color: #fff;
}

/* ------------------------------------------
   TV MODE
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .detail-modal.carousel-active {
        max-width: 600px;
        height: 80vh;
    }

    .carousel-slide-divider .slide-group-title {
        font-size: 32px;
    }

    .carousel-slide-divider .slide-group-subtitle {
        font-size: 15px;
        max-width: 400px;
    }

    .carousel-slide-content .slide-title {
        font-size: 24px;
    }

    .carousel-slide-content .slide-description {
        font-size: 15px;
    }

    .carousel-arrow {
        width: 44px;
        height: 44px;
        min-height: 44px;
    }

    .carousel-arrow svg {
        width: 20px;
        height: 20px;
    }

    .carousel-dot {
        width: 8px;
        height: 8px;
    }

    .carousel-dot.active {
        width: 24px;
    }

    .carousel-group-label {
        font-size: 13px;
    }
}

/* ------------------------------------------
   REDUCED MOTION
   ------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    .carousel-track {
        scroll-behavior: auto;
    }
}

/* ==============================================
   GLASS VENUE CARD
   Extended card for restaurants and events.
   Hero image + details + per-meal booking rows.

   Structure:
     .glass-venue-card
       .venue-card-hero
       .venue-card-body
         .venue-card-title
         .venue-card-subtitle
         .venue-card-desc
         .venue-card-info
           .venue-info-row (label + value)
       .venue-card-meals
         .venue-meal-row (label + time + book btn)
   ============================================== */

.glass-venue-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 28px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);
    color: rgba(255, 255, 255, 0.95);
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
}

/* Menu carousel variant: card expands to fit info slide content.
   Menu slides scroll internally for long menus. */
.glass-venue-card.has-menu {
    min-height: 0;
}

/* ------------------------------------------
   HERO IMAGE
   ------------------------------------------ */
.venue-card-hero {
    height: 120px;
    background-size: cover;
    background-position: center;
    flex-shrink: 0;
}

/* ------------------------------------------
   BODY (title, subtitle, description, info)
   ------------------------------------------ */
.venue-card-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
}

.venue-card-title {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
}

.venue-card-subtitle {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
    margin-top: -4px;
}

/* Full description shown on the card (TLP-476): no line-clamp, no disclosure --
   the description renders in full, consistent with showing detail up front. */
.venue-card-desc {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

/* Info rows: cuisine, location, dress code */
.venue-card-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-top: 4px;
}

.venue-info-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}

.venue-info-label {
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    flex-shrink: 0;
}

.venue-info-value {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.95);
    text-align: right;
}

/* ------------------------------------------
   MEAL ROWS (bottom section)
   Separated from body by a subtle border.
   ------------------------------------------ */
.venue-card-meals {
    display: flex;
    flex-direction: column;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.venue-meal-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.venue-meal-row:last-child {
    border-bottom: none;
}

.venue-meal-label {
    font-size: 11px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    min-width: 56px;
}

.venue-meal-time {
    font-size: 15px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
    flex: 1;
}

/* Book Now pill -- 44px minimum touch target */
.venue-book-btn {
    padding: 8px 16px;
    min-height: 44px;
    font-size: 13px;
    font-weight: 700;
    color: #fff;
    background: rgba(212, 175, 55, 0.95);
    border: none;
    border-radius: 9999px;
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
    -webkit-tap-highlight-color: transparent;
}

.venue-book-btn:hover {
    background: rgba(212, 175, 55, 1);
}

.venue-book-btn:active {
    transform: scale(0.94);
    transition-duration: 100ms;
}

/* ------------------------------------------
   VENUE CARD GRID
   Full-width single column on mobile with
   scroll-snap for clean card-to-card swiping.
   ------------------------------------------ */
.venue-card-grid {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* ------------------------------------------
   TV BREAKPOINT
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .glass-venue-card.has-menu {
        min-height: 0;
    }

    .venue-card-grid {
        display: -webkit-flex;
        display: flex;
        -webkit-flex-wrap: wrap;
        flex-wrap: wrap;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
        gap: 20px;
    }
    .venue-card-grid > * {
        -webkit-flex: 1 1 380px;
        flex: 1 1 380px;
        margin: 10px;
    }

    .venue-card-hero {
        height: 180px;
    }

    .venue-card-title {
        font-size: 24px;
    }

    .venue-card-subtitle {
        font-size: 17px;
    }

    .venue-card-desc {
        font-size: 17px;
    }

    .venue-info-label {
        font-size: 13px;
        min-width: 64px;
    }

    .venue-info-value {
        font-size: 17px;
    }

    .venue-meal-label {
        font-size: 13px;
        min-width: 64px;
    }

    .venue-meal-time {
        font-size: 17px;
    }

    .venue-book-btn {
        padding: 12px 20px;
        min-height: 48px;
        font-size: 15px;
    }
}

/* ------------------------------------------
   4K TV
   ------------------------------------------ */
@media (min-width: 1920px) and (orientation: landscape) {
    .glass-venue-card.has-menu {
        min-height: 0;
    }

    .venue-card-grid {
        grid-template-columns: repeat(auto-fit, minmax(460px, 1fr));
    }

    .venue-card-hero {
        height: 220px;
    }
}

/* ==============================================
   GLASS VENUE MENU CAROUSEL
   Horizontal carousel within venue cards showing
   restaurant info (slide 0) and menu slides (1..N).
   Uses CSS scroll-snap for native swipe support.

   Structure:
     .glass-venue-card.has-menu
       .venue-carousel-track
         .venue-carousel-slide.venue-slide-info
         .venue-carousel-slide.venue-slide-menu
           .menu-slide-header
           .menu-slide-content
             .menu-course
               .menu-course-title
               .menu-category-title
               .menu-item-row
       .venue-carousel-dots
         .venue-carousel-dot
   ============================================== */

/* ------------------------------------------
   CAROUSEL TRACK (horizontal scroll-snap)
   ------------------------------------------ */
.venue-carousel-track {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex: 0 0 auto;
    min-height: 0;
}

.venue-carousel-track::-webkit-scrollbar {
    display: none;
}

/* ------------------------------------------
   SLIDES (base)
   ------------------------------------------ */
.venue-carousel-slide {
    flex: 0 0 100%;
    width: 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    overflow-x: hidden;
    min-height: 0;
}

/* Info slide: no internal scroll -- card expands to fit */
.venue-slide-info {
    display: flex;
    flex-direction: column;
    overflow-y: visible;
}

/* Menu slide: scrolls internally for long menus */
.venue-slide-menu {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    max-height: 45vh;
}

/* ------------------------------------------
   MENU SLIDE HEADER
   Meal type name + service hours
   ------------------------------------------ */
.menu-slide-header {
    flex-shrink: 0;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    text-align: center;
}

.menu-slide-title {
    font-size: 17px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    letter-spacing: 0.02em;
}

.menu-slide-title::before {
    content: '';
    display: block;
    width: 28px;
    height: 2px;
    background: rgba(212, 175, 55, 0.95);
    margin: 0 auto 8px;
    border-radius: 1px;
}

.menu-slide-hours {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    margin-top: 2px;
}

/* ------------------------------------------
   MENU SLIDE CONTENT (scrollable area)
   ------------------------------------------ */
.menu-slide-content {
    flex: 1;
    overflow-y: auto;
    padding: 8px 12px 12px;
}

.menu-empty {
    padding: 24px;
    text-align: center;
    font-size: 15px;
    color: rgba(255, 255, 255, 0.5);
}

/* ------------------------------------------
   COURSE SECTION (collapsible <details>)
   ------------------------------------------ */
.menu-course {
    padding-bottom: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.menu-course:last-child {
    border-bottom: none;
}

.menu-course-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 700;
    color: rgba(212, 175, 55, 0.95);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 8px 0;
    cursor: pointer;
    list-style: none;
    -webkit-tap-highlight-color: transparent;
}

.menu-course-title::-webkit-details-marker {
    display: none;
}

.menu-course-name {
    flex: 1;
    min-width: 0;
}

.menu-course-count {
    font-size: 11px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.5);
    background: rgba(255, 255, 255, 0.08);
    border-radius: 9999px;
    padding: 1px 5px;
    line-height: 1;
}

.menu-course-chevron {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    overflow: hidden;
    color: rgba(255, 255, 255, 0.5);
    transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.menu-course[open] > .menu-course-title .menu-course-chevron {
    transform: rotate(180deg);
}

.menu-course-items {
    padding-bottom: 8px;
}

.menu-category-title {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 4px 0;
}

/* ------------------------------------------
   MENU ITEM ROW
   Name + description left, badges + price right
   Rendered as <button> for tap-to-detail
   ------------------------------------------ */
.menu-item-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 4px;
    min-height: 44px;
    width: 100%;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    border-radius: 12px;

}

.menu-item-row:hover,
.menu-item-row:focus-visible {
    background: rgba(255, 255, 255, 0.06);
}

.menu-item-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.menu-item-name {
    font-size: 17px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
    line-height: 1.3;
}

.menu-item-desc {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.menu-item-meta {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 3px;
}

.menu-item-price {
    font-size: 15px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.7);
    min-width: 20px;
    text-align: right;
}

/* ------------------------------------------
   MENU ITEM THUMBNAIL
   Small dish photo beside item text
   ------------------------------------------ */
.menu-item-row.has-thumb {
    gap: 8px;
}

.menu-item-thumb {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background-size: cover;
    background-position: center;
    background-color: rgba(255, 255, 255, 0.05);
}

/* ------------------------------------------
   DIETARY BADGES
   Small pill badges (V, VN, GF, LF)
   ------------------------------------------ */
.menu-dietary-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 9999px;
    padding: 2px 5px;
    letter-spacing: 0.02em;
    line-height: 1;
}

/* ------------------------------------------
   PAGINATION DOTS
   ------------------------------------------ */
.venue-carousel-dots {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 12px;
    flex-shrink: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.venue-carousel-dot {
    width: 6px;
    height: 6px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.25);
    border: none;
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;

}

.venue-carousel-dot.active {
    width: 18px;
    background: rgba(255, 255, 255, 0.85);
}

/* First dot (info slide) gets white; menu dots get gold when active */
.venue-carousel-dot:not(:first-child).active {
    background: rgba(212, 175, 55, 0.95);
}

/* ------------------------------------------
   TV BREAKPOINT
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .menu-slide-title {
        font-size: 20px;
    }

    .menu-slide-hours {
        font-size: 13px;
    }

    .menu-category-title {
        font-size: 15px;
    }

    .menu-item-name {
        font-size: 20px;
    }

    .menu-item-desc {
        font-size: 15px;
    }

    .menu-item-price {
        font-size: 20px;
    }

    .menu-item-thumb {
        width: 56px;
        height: 56px;
    }

    .menu-course-title {
        font-size: 15px;
        padding: 12px 0;
    }

    .menu-course-count {
        font-size: 13px;
    }

    .menu-course-chevron {
        width: 18px;
        height: 18px;
    }

    .menu-dietary-badge {
        font-size: 13px;
        padding: 3px 6px;
    }

    .venue-carousel-dot {
        width: 8px;
        height: 8px;
    }

    .venue-carousel-dot.active {
        width: 24px;
    }
}

/* ------------------------------------------
   4K TV
   ------------------------------------------ */
@media (min-width: 1920px) and (orientation: landscape) {
    .menu-slide-header {
        padding: 16px 20px;
    }

    .menu-slide-content {
        padding: 12px 16px 16px;
    }
}

/* ------------------------------------------
   REDUCED MOTION
   ------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    .venue-carousel-track {
        scroll-behavior: auto;
    }
}

/* ==============================================
   GLASS CALENDAR
   Organism: day strip + detail area + view toggle.
   Used for My Bookings and reservation views.

   Structure:
     .glass-calendar
       .calendar-header        (month label + view toggle)
       .calendar-strip         (nav arrows + day cells)
       .calendar-detail        (booking entries for selected day)
   ============================================== */

/* ------------------------------------------
   CONTAINER
   Glass surface that holds the entire calendar.
   ------------------------------------------ */
.glass-calendar {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 24px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08),
        inset 1px 1px 1px rgba(255, 255, 255, 0.4),
        inset -0.5px -0.5px 1px rgba(255, 255, 255, 0.14),
        0 3px 10px rgba(0, 0, 0, 0.14);
}

/* ------------------------------------------
   HEADER (month label + view toggle)
   ------------------------------------------ */
.calendar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 4px;
}

.calendar-month {
    font-size: 17px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
}

/* Segmented toggle: Day / Stay */
.calendar-view-toggle {
    display: flex;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;
    padding: 2px;
    gap: 2px;
}

.calendar-view-btn {
    padding: 4px 12px;
    font-size: 13px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.7);
    background: transparent;
    border: none;
    border-radius: 9999px;
    cursor: pointer;

    -webkit-tap-highlight-color: transparent;
    line-height: 1.4;
}

.calendar-view-btn:hover {
    color: rgba(255, 255, 255, 0.95);
}

.calendar-view-btn.active {
    background: rgba(212, 175, 55, 0.95);
    color: #fff;
    font-weight: 600;
}

/* ------------------------------------------
   DAY STRIP
   Horizontal row of day cells with nav arrows.
   ------------------------------------------ */
.calendar-strip {
    display: flex;
    align-items: center;
    gap: 8px;
}

.calendar-strip-nav {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 50%;
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;

    -webkit-tap-highlight-color: transparent;
}

.calendar-strip-nav:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
    color: rgba(255, 255, 255, 0.95);
}

.calendar-strip-nav:active {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
}

.calendar-strip-nav .nav-icon {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

/* Hide nav arrows in Stay view */
.glass-calendar.view-stay .calendar-strip-nav {
    opacity: 0;
    pointer-events: none;
}

.calendar-days {
    flex: 1;
    display: flex;
    justify-content: flex-start;
    gap: 4px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

/* ------------------------------------------
   DAY CELL
   Molecule: day name + number + dot indicator.
   ------------------------------------------ */
.calendar-day-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 48px;
    min-height: 64px;
    padding: 4px 0;
    border-radius: 16px;
    cursor: pointer;
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
    -webkit-tap-highlight-color: transparent;
    border: 1.5px solid transparent;
    background: transparent;
}

.calendar-day-cell:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
}

.calendar-day-cell:active {
    transform: scale(0.95);
}

/* Day name: Mon, Tue... */
.day-name {
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    line-height: 1;
}

/* Day number: 3, 4, 5... */
.day-number {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    line-height: 1;
}

/* Booking indicator dot */
.day-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: transparent;

}

.day-dot.has-bookings {
    background: rgba(212, 175, 55, 0.95);
}

/* --- Day cell states --- */

/* Today: gold border ring */
.calendar-day-cell.is-today {
    border-color: rgba(212, 175, 55, 0.6);
}

.calendar-day-cell.is-today .day-name {
    color: rgba(212, 175, 55, 0.95);
}

/* Selected: gold fill, dark text */
.calendar-day-cell.is-selected {
    background: rgba(212, 175, 55, 0.95);
    border-color: rgba(212, 175, 55, 0.95);
}

.calendar-day-cell.is-selected .day-name {
    color: rgba(0, 0, 0, 0.6);
}

.calendar-day-cell.is-selected .day-number {
    color: rgba(0, 0, 0, 0.9);
}

.calendar-day-cell.is-selected .day-dot.has-bookings {
    background: rgba(0, 0, 0, 0.5);
}

/* ------------------------------------------
   DETAIL AREA
   Shows bookings for the selected day (Day view)
   or compact agenda (Stay view).
   ------------------------------------------ */
.calendar-detail {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 120px;
    position: relative;
    overflow: hidden;
}

/* Day view: slide transition on day change */
.calendar-detail-inner {
    display: flex;
    flex-direction: column;
    gap: 8px;
    transition:
        opacity 150ms cubic-bezier(0.16, 1, 0.3, 1),
        transform 150ms cubic-bezier(0.16, 1, 0.3, 1);
}

.calendar-detail-inner.slide-out-left {
    opacity: 0;
    transform: translateX(-20px);
}

.calendar-detail-inner.slide-out-right {
    opacity: 0;
    transform: translateX(20px);
}

/* Selected day label in detail area */
.calendar-detail-date {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    padding: 4px 0;
}

/* ------------------------------------------
   BOOKING ENTRY (Day View)
   Two stacked rows: gold left accent.
     Row 1 (.calendar-booking-main): time + service category + actions.
     Row 2 (.calendar-booking-name): venue / entity name, full width.
   Not a full glass card -- lighter treatment.
   ------------------------------------------ */
.calendar-booking {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
    border-left: 3px solid rgba(212, 175, 55, 0.95);
    border-radius: 0 16px 16px 0;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 65%);

}

.calendar-booking:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
}

/* Row 1: time + service category, action buttons pinned right.
   Tight gap so the service sits close to the time. */
.calendar-booking-main {
    display: flex;
    align-items: center;
    gap: 4px;
}

.calendar-booking-time {
    font-size: 13px;
    font-weight: 700;
    color: rgba(212, 175, 55, 0.95);
    white-space: nowrap;
}

.calendar-booking-service {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* Row 2: venue / entity name */
.calendar-booking-name {
    font-size: 15px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
}

.calendar-booking-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

/* 44px touch targets shared by rate / edit / cancel */
.calendar-booking-rate,
.calendar-booking-edit,
.calendar-booking-cancel {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.5);
    cursor: pointer;

}

.calendar-booking-rate:hover,
.calendar-booking-edit:hover {
    background: rgba(212, 168, 67, 0.2);
    color: rgba(212, 175, 55, 0.95);
}

.calendar-booking-cancel:hover {
    background: rgba(239, 68, 68, 0.2);
    color: #ef4444;
}

.calendar-booking-rate:disabled,
.calendar-booking-edit:disabled,
.calendar-booking-cancel:disabled {
    opacity: 0.4;
    pointer-events: none;
}

.calendar-booking.cancelled {
    opacity: 0;
    transform: translateX(20px);
    transition: opacity 0.3s, transform 0.3s;
}

/* ------------------------------------------
   EMPTY STATE (no bookings)
   ------------------------------------------ */
.calendar-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 24px 12px;
    text-align: center;
}

.calendar-empty-icon {
    width: 32px;
    height: 32px;
    color: rgba(255, 255, 255, 0.5);
    fill: currentColor;
    opacity: 0.5;
}

.calendar-empty-text {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
}

/* ------------------------------------------
   STAY VIEW (compact agenda)
   All days visible as compact rows.
   ------------------------------------------ */
.calendar-agenda {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.calendar-agenda-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 8px 8px;
    border-radius: 12px;
    cursor: pointer;

    -webkit-tap-highlight-color: transparent;
}

.calendar-agenda-row:hover {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05) 65%);
}

.calendar-agenda-row:active {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
}

.calendar-agenda-day {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    min-width: 52px;
    white-space: nowrap;
}

.calendar-agenda-row.is-today .calendar-agenda-day {
    color: rgba(212, 175, 55, 0.95);
}

.calendar-agenda-items {
    flex: 1;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.95);
    min-width: 0;
}

.calendar-agenda-items.empty {
    color: rgba(255, 255, 255, 0.5);
}

/* ------------------------------------------
   MODAL CONTEXT (glass background)
   Day cells adapt when inside a detail-modal.
   Same markup, glass palette. Compact sizing
   so the full reservation form fits without scroll.
   ------------------------------------------ */
.detail-modal .calendar-days {
    gap: 3px;
    justify-content: flex-start;
}

.detail-modal .calendar-day-cell {
    width: 36px;
    min-height: 44px;
    padding: 3px 0;
    gap: 1px;
    background: rgba(255, 255, 255, 0.06);
    border-color: transparent;
    border-width: 1px;
    border-radius: 12px;
}

.detail-modal .calendar-day-cell:hover {
    background: rgba(255, 255, 255, 0.12);
}

.detail-modal .day-name {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.5);
}

.detail-modal .day-number {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.95);
}

.detail-modal .day-dot {
    display: none;
}

/* Selected: gold fill (same in both contexts) */
.detail-modal .calendar-day-cell.is-selected {
    background: rgba(212, 175, 55, 0.95);
    border-color: rgba(212, 175, 55, 0.95);
}

.detail-modal .calendar-day-cell.is-selected .day-name {
    color: rgba(255, 255, 255, 0.7);
}

.detail-modal .calendar-day-cell.is-selected .day-number {
    color: #fff;
}

/* Compact form spacing inside reservation modal */
.detail-modal .form-group {
    gap: 4px;
}

.detail-modal .form-label {
    font-size: 11px;
    margin-bottom: 0;
}

/* Compact time pills: 5-column, minimal padding */
.detail-modal .time-picker {
    grid-template-columns: repeat(5, 1fr);
    gap: 4px;
}

.detail-modal .time-option {
    padding: 6px 2px;
    font-size: 13px;
    min-height: 32px;
    border-radius: 12px;
}

/* Tighter info rows in reservation modal */
.detail-modal .modal-info {
    padding: 4px 8px 8px;
}

.detail-modal .modal-info .info-row {
    padding: 4px 0;
}

/* Tighter modal layout when calendar day cells are present (reservation flow) */
.detail-modal.has-calendar .modal-content {
    gap: 4px;
}

.detail-modal.has-calendar .modal-header {
    padding: 8px 8px 0;
}

.detail-modal.has-calendar .modal-actions {
    padding-top: 8px;
}

/* ------------------------------------------
   TV BREAKPOINT
   ------------------------------------------ */
@media (min-width: 1200px) and (orientation: landscape) {
    .calendar-day-cell {
        width: 64px;
        min-height: 76px;
    }

    .day-number {
        font-size: 24px;
    }

    .day-dot {
        width: 6px;
        height: 6px;
    }

    .calendar-strip-nav {
        width: 40px;
        height: 40px;
    }

    .calendar-strip-nav .nav-icon {
        width: 22px;
        height: 22px;
    }

    .calendar-booking {
        padding: 12px 16px;
    }
}

/* Feedback questionnaire + awaiting-feedback menu (guest-app, Liquid Glass).
   Hardcoded values per guest-app CSS convention (no design tokens, manual
   -webkit- prefixes). Renders inside the shared .detail-modal glass surface. */

/* One container owns the form's vertical rhythm: every row -- date strip, meal
   pills, each rating, the comment -- gets the same gap. (The shared .modal-body
   has no gap and .form-group has no inter-group margin, which is what bunched
   the old <select> rows. Mirrors how the booking modal spaces its sections.) */
.fb-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Restore a comfortable label-to-control gap for this form (the reservation
   modal tightens .form-group to 4px; beat it with a more specific selector). */
.detail-modal .fb-form .form-group {
    gap: 8px;
}

.fb-question {
    /* row spacing is owned by .fb-form gap now */
    margin-bottom: 0;
}

.fb-scale {
    display: flex;
    gap: 4px;
}

/* Standing meal selector: tappable pills reusing the booking modal's .time-option
   look, flowed so longer labels (e.g. "Early breakfast") never clip. */
.fb-meal-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Empty-state note when a picker has nothing to show (e.g. no stay dates yet). */
.fb-empty-note {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.6);
    margin: 0;
}

.detail-modal .fb-meal-picker .time-option {
    padding: 8px 14px;
    min-height: 36px;
}

.fb-score {
    flex: 1 1 0;
    min-width: 0;
    height: 38px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;

}

.fb-score:hover {
    background: rgba(255, 255, 255, 0.16);
}

.fb-score.selected {
    background: rgba(255, 255, 255, 0.92);
    color: #1a1a1a;
    border-color: #fff;
    font-weight: 600;
}

.feedback-menu {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.fb-group-title {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
    margin: 6px 0 2px;
}

.fb-pending,
.fb-standing,
.fb-done {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    text-align: left;
    padding: 12px 14px;
}

.fb-pending,
.fb-standing {
    cursor: pointer;
}

/* Already-rated row: present for completeness, not actionable. */
.fb-done {
    opacity: 0.55;
    cursor: default;
}

.fb-row-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.fb-pending-name {
    font-size: 15px;
    font-weight: 600;
    color: #fff;
}

.fb-pending-meta {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

.fb-row-cta {
    flex: none;
    font-size: 13px;
    font-weight: 600;
    color: #fff;
    opacity: 0.85;
}

.fb-rated-badge {
    flex: none;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.65);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    padding: 3px 9px;
    white-space: nowrap;
}

/* Day-after feedback nudge button inside a chat bubble. */
.chat-nudge-btn {
    display: inline-block;
    margin-top: 8px;
    padding: 8px 14px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.chat-nudge-btn:hover {
    background: rgba(255, 255, 255, 0.22);
}

/* ==============================================
   D-PAD FOCUS
   The remote-navigation cursor. Applied as
   .dpad-focused by platform/dpad-input.js.

   Neutral base only. The full glass treatment
   (fill-solid, elevated rim, zoom) lives in the
   TV media block of app.css: it must cascade
   AFTER the :focus-visible rules (this file
   flattens in before app.css), and TV values
   must be literals -- the flatten build does not
   re-resolve tokens inside media queries.
   ============================================== */

.dpad-focused {
    outline: none;
}


/* ------------------------------------------
   UTILITIES
   ------------------------------------------ */
/* ==============================================
   LAYOUT UTILITIES
   Liquid Glass Design System
   ============================================== */

/* ------------------------------------------
   GRID LAYOUTS
   ------------------------------------------ */
.grid-2 {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}
.grid-2 > * { -webkit-flex: 0 0 48%; flex: 0 0 48%; margin: 1%; }

.grid-3 {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}
.grid-3 > * { -webkit-flex: 0 0 31%; flex: 0 0 31%; margin: 1%; }

.grid-4 {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}
.grid-4 > * { -webkit-flex: 0 0 23%; flex: 0 0 23%; margin: 1%; }

/* ------------------------------------------
   FLEX UTILITIES
   ------------------------------------------ */
.flex {
    display: flex;
}

.flex-col {
    flex-direction: column;
}

.flex-wrap {
    flex-wrap: wrap;
}

.items-center {
    align-items: center;
}

.items-start {
    align-items: flex-start;
}

.items-end {
    align-items: flex-end;
}

.justify-center {
    justify-content: center;
}

.justify-between {
    justify-content: space-between;
}

.justify-end {
    justify-content: flex-end;
}

/* ------------------------------------------
   GAP UTILITIES
   ------------------------------------------ */
.gap-1 {
    gap: 4px;
}

.gap-2 {
    gap: 8px;
}

.gap-3 {
    gap: 12px;
}

.gap-4 {
    gap: 16px;
}

.gap-5 {
    gap: 20px;
}

.gap-6 {
    gap: 24px;
}

.gap-8 {
    gap: 32px;
}

/* ------------------------------------------
   PADDING UTILITIES
   ------------------------------------------ */
.p-4 {
    padding: 16px;
}

.p-6 {
    padding: 24px;
}

.px-4 {
    padding-left: 16px;
    padding-right: 16px;
}

.px-6 {
    padding-left: 24px;
    padding-right: 24px;
}

.py-4 {
    padding-top: 16px;
    padding-bottom: 16px;
}

.py-6 {
    padding-top: 24px;
    padding-bottom: 24px;
}

/* ------------------------------------------
   WIDTH/HEIGHT
   ------------------------------------------ */
.w-full {
    width: 100%;
}

.h-full {
    height: 100%;
}

.min-h-screen {
    min-height: 100vh;
}

/* ------------------------------------------
   TEXT UTILITIES
   ------------------------------------------ */
.text-center {
    text-align: center;
}

.text-left {
    text-align: left;
}

.text-right {
    text-align: right;
}

/* ------------------------------------------
   VISIBILITY
   ------------------------------------------ */
.hidden {
    display: none;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* ==============================================
   HOTEL GUEST APP
   Layout, Animation, and TV Media Queries
   Mobile-first approach
   ============================================== */

/* ------------------------------------------
   CSS CUSTOM PROPERTIES (App-specific)
   ------------------------------------------ */
:root {
    /* App viewport — consistent 5% inset on all sides (mobile/tablet) */
    --app-inset: 5vw;

    /* Home content box -- the shared inset for the header, the tile grid, and
       (on TV) the featured row, so all three align to a single box. Phone uses
       this 5vw token; the tablet and TV blocks set their inset as literals on
       the same three consumers, because a token consumed inside a media query
       is not re-resolved by the flatten build (build-css.js). Kept separate
       from --app-inset so the sliding panels are not dragged along. */
    --content-inset: 5vw;

    /* Panel dimensions */
    --panel-height: 75vh;
    --panel-radius-top: 32px;

    /* Safe areas */
    --safe-area-top: env(safe-area-inset-top, 0px);
    --safe-area-bottom: env(safe-area-inset-bottom, 0px);

    /* Hotel hero image — set dynamically by content-loader.js in live mode.
       Fallback is no image (gradient-only dark background for local dev). */
    --hero-image: none;

    /* Server-pre-blurred copy of the hero (hero-frost.jpg), set by
       content-loader.loadHero when the asset exists. Consumed ONLY by the
       body.tier-samsung stratum: engines whose compositor cannot paint live
       backdrop-filter draw this viewport-anchored inside each glass element
       instead. 'none' = tint-only glass (graceful, no broken image). */
    --hero-frost-image: none;
}

/* ------------------------------------------
   ICON SPRITE (Hidden)
   ------------------------------------------ */
.icon-sprite {
    display: none;
}

/* ------------------------------------------
   WALLPAPER BACKGROUND
   The crisp hero image lives on <body> -- the backdrop-root background that
   every glass element's backdrop-filter samples. Kept here (NOT a separate
   z-index:-1 layer, which the TV's Chromium fails to sample through the glass
   containers' stacking contexts -- phones are lenient, the TV is not) so the
   frost is honoured on every device. The image is NEVER blurred; the glass
   frosts what shows through it. content-loader sets --hero-image; Chrome 38
   (no custom properties) gets an inline body.style.backgroundImage instead.
   ------------------------------------------ */
body {
    background:
        linear-gradient(180deg,
            rgba(0, 0, 0, 0.15) 0%,
            rgba(0, 0, 0, 0.4) 100%
        ), var(--hero-image) center / cover no-repeat;
    background-color: #0a1628;
}

/* ------------------------------------------
   TV ROW (Hidden on mobile)
   ------------------------------------------ */
.tv-row {
    display: none;
}

/* ------------------------------------------
   MAIN SCREEN (Level 0)
   Fixed position, always underneath
   ------------------------------------------ */
.main-screen {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding: 5vw;
    padding-left: 5vw;
    padding-right: 5vw;
    padding-bottom: calc(5vw + env(safe-area-inset-bottom, 0px));
    z-index: 1;
    
    /* Recede uses zoom (not transform: scale) so it does not create a
       backdrop root for the tiles' backdrop-filter frost (probe-verified:
       ancestor zoom leaves descendant frost intact). NO opacity here:
       ancestor opacity < 1 IS a backdrop root and kills the tiles' frost
       for the whole open/close window -- the dim lives on the
       .panel-backdrop scrim (a sibling) instead.
       The recede is NOT animated: zoom is a layout property, and easing it
       re-laid-out and repainted the whole home screen every frame of the
       panel slide (the TV jank). The end state applies instantly; the
       scrim fade carries the depth cue. */
}

/* When panel is open, main screen recedes slightly; the scrim does the dim. */
body.panel-open .main-screen,
body.top-panel-open .main-screen {
    zoom: 0.94;
}

/* ------------------------------------------
   PANEL BACKDROP (click-to-dismiss + dim scrim)
   Sits between the main screen (z1) and the panels (z10). Carries the
   panel-open dim as a SIBLING overlay: the tiles behind keep their live
   frost (opacity on their .main-screen ancestor would trap it -- the old
   close-flicker regression), and the sliding panel double-blurs tiles +
   scrim through its own backdrop-filter. Plain rgba, no blur of its own:
   GPU-free on TVs.
   ------------------------------------------ */
.panel-backdrop {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    z-index: 9;
    /* NO dim (PO, 2026-07-25): the scene keeps its daylight when a panel
       opens. The element stays for tap-outside-to-close; depth comes from
       the recede + the panel's own backdrop dim (brightness 0.92), which
       also matches the Samsung baked frost that never sampled this scrim. */
    background: transparent;
    opacity: 0;
    transition: opacity 500ms cubic-bezier(0.16, 1, 0.3, 1);
    pointer-events: none;
    cursor: pointer;
}

body.panel-open .panel-backdrop,
body.top-panel-open .panel-backdrop {
    opacity: 1;
    pointer-events: auto;
}

/* ------------------------------------------
   MAIN HEADER (DND Toggle + Mini-tiles)
   Fixed in viewport — not affected by main-screen scale
   ------------------------------------------ */
.main-header {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 5vw);
    left: 5vw;
    right: 5vw;
    display: flex;
    /* Circle cluster rides right on every tier; on TV the header band
       (flex: 1) fills the space to its left. */
    justify-content: flex-end;
    padding: 0;
    z-index: 5;
}

/* Panel-open fade lives on the glass elements THEMSELVES, never on
   .main-header: opacity < 1 on an ANCESTOR is a backdrop root and kills the
   circles'/band's frost for the whole fade window, while an element's OWN
   opacity just fades the frost with the element (probe-verified).
   Fade-in on panel close: short delay so the panel starts sliding away
   before the circles reappear, then quick fade-in. */
.main-header .header-hero,
.main-header .header-clock,
.main-header .chat-unread-badge {
    transition: opacity 250ms cubic-bezier(0.16, 1, 0.3, 1) 150ms;
}

/* Circles keep the glass-button press animation alongside the fade. */
.main-header .header-circle {
    transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 250ms cubic-bezier(0.16, 1, 0.3, 1) 150ms;
}

/* Block header interaction while a panel is open (pointer-events is not a
   backdrop-root property, so the ancestor may carry it). */
body.panel-open .main-header,
body.top-panel-open .main-header {
    pointer-events: none;
}

/* Fade the header contents out when either panel is open. Delayed so the
   circles stay visible while the panel is still mid-slide, then fade quickly. */
body.panel-open .main-header .header-circle,
body.panel-open .main-header .header-hero,
body.panel-open .main-header .header-clock,
body.panel-open .main-header .chat-unread-badge,
body.top-panel-open .main-header .header-circle,
body.top-panel-open .main-header .header-hero,
body.top-panel-open .main-header .header-clock,
body.top-panel-open .main-header .chat-unread-badge {
    opacity: 0;
    transition: opacity 200ms cubic-bezier(0.16, 1, 0.3, 1) 100ms;
}

/* Keep header circle buttons clickable when top panel is open */
body.top-panel-open .main-header .header-right {
    pointer-events: auto;
}

/* Header right group: two 44px icon-only glass circles */
.header-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

.glass-button.header-circle {
    width: 52px;
    height: 52px;
    border: 1px solid rgba(255, 255, 255, 0.34);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    backdrop-filter: blur(20px) saturate(100%);
    -webkit-backdrop-filter: blur(20px) saturate(100%);
}

.glass-button.header-circle .btn-icon {
    width: 26px;
    height: 26px;
}

.header-circle .logo-img {
    width: 20px;
    height: 20px;
    object-fit: contain;
}

/* ------------------------------------------
   TV HEADER BAND (greeting banners + clock)
   Hidden below the TV regime; phones and
   portrait tablets keep the classic header.
   Widgets follow the header-circle glass
   recipe -- one live blur per element.
   ------------------------------------------ */
.header-band {
    display: none;
}

/* The Hotels (H) circle rides the TV band, not the classic header: hidden
   below the TV regime so phones and portrait tablets never see it. Shown in
   the TV block. ID selector because it beats .glass-button's inline-flex. */
#hotelsBtn {
    display: none;
}

.header-hero {
    -webkit-align-items: center;
    align-items: center;
    min-width: 0;
    padding: 0 28px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    backdrop-filter: blur(20px) saturate(100%);
    -webkit-backdrop-filter: blur(20px) saturate(100%);
}

.hero-banner-text {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: rgba(255, 255, 255, 0.95);
    opacity: 1;
    transition: opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.hero-banner-text.banner-fading {
    opacity: 0;
}

.header-clock {
    -webkit-flex-direction: column;
    flex-direction: column;
    -webkit-align-items: center;
    align-items: center;
    -webkit-justify-content: center;
    justify-content: center;
    padding: 0 28px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 9999px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    backdrop-filter: blur(20px) saturate(100%);
    -webkit-backdrop-filter: blur(20px) saturate(100%);
}

.clock-time {
    color: rgba(255, 255, 255, 0.95);
    font-weight: 600;
}

.clock-date {
    color: rgba(255, 255, 255, 0.7);
}

/* Visually hidden but accessible */
.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;
}

.service-grid {
    /* Flexbox fallback for Chrome 38 (grid overrides below) */
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    width: 100%;
    box-sizing: border-box;
    /* Grid layout for modern browsers */
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: 8px;
}

.service-tile {
    /* Flex fallback: 3 columns with padding-based spacing */
    -webkit-flex: 0 0 31%;
    flex: 0 0 31%;
    margin: 1%;
    padding: 12%;
    aspect-ratio: 1;
    min-width: 0;

    /* Frost comes from .glass-tile (translucent tint + backdrop-filter) -- the
       one glass mechanism, same on every device. Press uses zoom, not
       transform: scale, so the tile never becomes a stacking context that
       would drop its own backdrop-filter frost. */
    transition:
        zoom 200ms cubic-bezier(0.34, 1.56, 0.64, 1),
        background 200ms cubic-bezier(0.16, 1, 0.3, 1),
        border-color 200ms cubic-bezier(0.16, 1, 0.3, 1),
        box-shadow 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.service-tile:hover {
    transform: none;
}

.service-tile:active {
    zoom: 0.95;
    transform: none;
}

.service-tile:focus-visible {
    zoom: 1.02;
    transform: none;
}

/* ------------------------------------------
   GLASS FALLBACK (no backdrop-filter)
   One mechanism everywhere: glass = a translucent tint + backdrop-filter, where
   the blur samples the crisp wallpaper behind it (the wallpaper is never
   blurred). Engines without backdrop-filter (legacy LG / Chrome 38 /
   Tizen < 6.0) cannot blur, so lift the tint enough that every surface still
   reads as frosted glass over the wallpaper. A feature query does this with no
   JS and no device branching. Tizen 6.0+ (both hotel TVs) supports
   backdrop-filter, so this branch never runs there.
   ------------------------------------------ */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .glass-tile,
    .glass-button,
    .glass-panel,
    .header-hero,
    .header-clock {
        background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    }

    /* The modal overlay's dim IS its blur on capable engines (background:
       transparent + backdrop-filter). Without blur it needs a real scrim. */
    .modal-overlay {
        background: rgba(0, 0, 0, 0.45);
    }
}

/* ------------------------------------------
   SAMSUNG HOSPITALITY WEBVIEW (tier-samsung)
   The BU800/AU800 webview CLAIMS backdrop-filter (CSS.supports true; it is
   in the Tizen 6.0+ web-engine spec) but its compositor NEVER PAINTS the
   blur -- pixel-verified on the HG50BU800 via the frost-probe swatch,
   2026-07-24. The @supports branch above can therefore never fire there.
   Same lifted-tint look, keyed on the device-context boot class instead;
   backdrop-filter pinned off so a future firmware that half-paints cannot
   flip the look. KEEP IN LOCKSTEP with the @supports block above.
   These selectors carry one extra class of specificity than the base glass
   rules, so solid VARIANT fills (gold primary etc.) are re-asserted below.
   ------------------------------------------ */
/* Surfaces that carry LIVE blur on capable engines get the BAKED frost here:
   the pre-blurred hero drawn viewport-anchored (background-attachment: fixed
   -- probe-verified WORKING on this webview even though backdrop-filter is
   not), so each element shows exactly the blurred patch of wallpaper it sits
   on, with the standard subtle tint on top. The crisp wallpaper on <body> is
   never touched. When --hero-frost-image is unset the layer paints nothing
   and the tint carries the glass alone. */
body.tier-samsung .glass-tile,
body.tier-samsung .glass-panel,
body.tier-samsung .glass-button.header-circle,
body.tier-samsung .header-hero,
body.tier-samsung .header-clock {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%), var(--hero-frost-image) center / cover no-repeat fixed;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* Plain buttons stay tint-only: in-panel buttons are fill-only glass on
   capable engines too (no live blur to mimic). Panels ARE frosted above --
   probe swatch E verified this webview keeps fixed-attachment
   viewport-anchoring inside the transformed .panel-container, so the
   sliding glass sweeps over a stationary blurred scene, exactly like a
   real backdrop sample. */
body.tier-samsung .glass-button {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.19), rgba(255, 255, 255, 0.08) 65%);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

body.tier-samsung .modal-overlay {
    background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45)), var(--hero-frost-image) center / cover no-repeat fixed;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* Variant protection: the frost/tint rules above out-specify the (0,2,0)
   solid-fill variants, so re-assert them at tier specificity. Same tokens as
   the variant sources (glass-button.css / glass-tile.css / app.css modal). */

/* The modal card keeps its MILK fill (denser pane over the frosted overlay,
   mirroring capable engines) instead of inheriting the panel frost. */
body.tier-samsung .detail-modal {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.1) 65%);
}

body.tier-samsung .glass-button.primary {
    background: rgba(212, 175, 55, 0.95);
}

body.tier-samsung .glass-button.destructive {
    background: rgba(255, 59, 48, 0.95);
}

body.tier-samsung .glass-button.success {
    background: rgba(52, 199, 89, 0.95);
}

body.tier-samsung .glass-tile.selected {
    background: rgba(255, 255, 255, 0.9);
}

body.tier-samsung .glass-tile.selected-gold {
    background: rgba(212, 175, 55, 0.95);
}

body.tier-samsung .glass-tile.selected-blue {
    background: rgba(0, 122, 255, 0.95);
}

body.tier-samsung .glass-tile.selected-green {
    background: rgba(52, 199, 89, 0.95);
}

/* Panel-slide frost freeze: a viewport-anchored (fixed) background inside a
   moving element cannot be composited -- the TV repainted the full-screen
   frost texture every frame of the slide. While the panel is IN MOTION the
   frost rides with the glass (scroll = composited, zero repaint); when the
   slide settles, app.js stamps .panel-settled (transitionend) and the frost
   snaps viewport-anchored. Mid-motion misalignment is invisible -- the pane
   is moving. Closing drops .open immediately, so the closing slide is cheap
   by the same rule. */
body.tier-samsung .panel-container {
    background-attachment: scroll, scroll;
}

body.tier-samsung .service-panel.open.panel-settled .panel-container,
body.tier-samsung .top-panel.open.panel-settled .panel-container {
    background-attachment: scroll, fixed;
}

.service-tile .tile-icon {
    width: 33%;
    height: 33%;
}

.service-tile .tile-label {
    /* The vw term rules on phones; the 15px cap rules on tablet/TV widths.
       Long titles ("Green Choices", "To Your Room") WRAP to two lines on
       narrow tiles instead of ellipsizing -- readable beats microscopic.
       Two-line clamp via the ancient -webkit-box (Chrome 38 safe); short
       titles and wide tiles stay one line, so tablet/TV are unaffected. */
    font-size: clamp(9px, 3.3vw, 15px);
    white-space: normal;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    line-height: 1.2;
    text-align: center;
}

.tile-disabled {
    pointer-events: none;
    opacity: 0.35;
}

/* Disabled tiles read as disabled via .tile-disabled (dimmed +
   pointer-events:none); no " (soon)" suffix -- it overflowed the
   nowrap/ellipsis label and truncated the longer names. */

/* No stagger animation - tiles appear with main screen */

/* ------------------------------------------
   SERVICE PANEL (Level 1)
   Slides up from bottom
   ------------------------------------------ */
.service-panel {
    position: fixed;
    left: 5vw;
    right: 5vw;
    bottom: 0;
    height: 75vh;
    z-index: 10;
    
    visibility: hidden;
    contain: layout style;

    /* The slide lives on .panel-container (the glass element) so its own
       backdrop-filter frost is not trapped by an ancestor transform. The
       wrapper only coordinates visibility with the slide duration. */
    transition: visibility 0ms linear 500ms;

    pointer-events: none;
}

.service-panel .panel-container {
    /* Start off-screen below viewport; smooth deceleration, NOT spring
       (spring overshoot goes above the viewport edge, invisible). */
    transform: translate3d(0, 100%, 0);
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.service-panel.open {
    visibility: visible;
    pointer-events: auto;

    /* Override visibility delay when opening */
    transition: visibility 0ms linear 0ms;
}

.service-panel.open .panel-container {
    transform: translate3d(0, 0, 0);
}

/* ------------------------------------------
   TOP PANEL (Level 1)
   Slides down from top — mirror of service-panel
   ------------------------------------------ */
.top-panel {
    position: fixed;
    left: 5vw;
    right: 5vw;
    top: 0;
    height: 75vh;
    z-index: 10;

    visibility: hidden;
    contain: layout style;
    /* Slide lives on .panel-container (the glass element) -- see .service-panel. */
    transition: visibility 0ms linear 500ms;
    pointer-events: none;
}

.top-panel .panel-container {
    transform: translate3d(0, -100%, 0);
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.top-panel.open {
    visibility: visible;
    pointer-events: auto;
    transition: visibility 0ms linear 0ms;
}

.top-panel.open .panel-container {
    transform: translate3d(0, 0, 0);
}

/* Two-phase open: .preparing makes the still-off-screen panel paintable on
   its own compositor layer, so content and images rasterize BEFORE the
   slide starts -- app.js swaps it for .open two frames later. Without
   this, tiles rasterized as they entered the viewport and the slide
   visibly hitched mid-flight on TV silicon. Same will-change scoping rule
   as .open: transient, transform only, on the container itself. */
.service-panel.preparing,
.top-panel.preparing {
    visibility: visible;
    /* transition:none or the wrapper's DELAYED visibility transition (the
       close-hide delay) starts here and cannot be retargeted by .open --
       measured result was a fully invisible open slide. */
    transition: none;
    /* The wrapper base is pointer-events:none until .open; without auto
       here the effective-visibility walk rejects every candidate during
       prepare and the dead-key window this state exists to close returns. */
    pointer-events: auto;
}

.service-panel.preparing .panel-container,
.top-panel.preparing .panel-container {
    will-change: transform;
}

/* Top panel: shrink to content, rounded bottom corners */
.top-panel .panel-container {
    height: auto;
    max-height: 100%;
    border-radius: 0 0 32px 32px;
}

.top-panel .panel-content-wrapper {
    flex: 0 1 auto;
    overflow-y: auto;
    /* In top-panel the wrapper is the scroll surface (not the inner
       .panel-view, which is position: relative + auto height). iOS Safari
       needs the touch hint on the actual scroller for momentum scroll. */
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

.top-panel .panel-view {
    position: relative;
    inset: auto;
    /* In the top panel the panel-view has auto height (position: relative,
       content-driven). The base .panel-view rule sets overflow-y: auto for
       the bottom-panel absolute layout; leaving that here makes the panel
       a scroll container with nothing to scroll, capturing touches that
       should reach the wrapper.

       IMPORTANT: per CSS spec, when overflow-x and overflow-y disagree
       between visible and a non-visible value, the visible side is
       normalized to auto. So `overflow-y: visible; overflow-x: hidden`
       computes to `overflow-y: auto`. We must set BOTH to visible to
       actually defeat the base rule. */
    overflow: visible;
    -webkit-overflow-scrolling: auto;
}

.top-panel .panel-view:not(.active) {
    display: none;
}

.panel-container {
    height: 100%;
    border-radius: 32px 32px 0 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* Override glass-panel padding and gap - children manage their own */
    padding: 0;
    gap: 0;
}

/* ------------------------------------------
   SERVICE HEADER
   ------------------------------------------ */
.service-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px 16px;
    flex-shrink: 0;
}

/* Breadcrumb */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Back arrow - no longer used (icon is the back affordance) */
.breadcrumb-back {
    display: none;
}

/* Service icon button:
   - Hidden at Level 1 (title only)
   - Shown at Level 2 as the back button (tapping goes back to categories) */
.breadcrumb-btn {
    pointer-events: none;
    cursor: default;
}

.breadcrumb.has-category .breadcrumb-btn {
    pointer-events: auto;
    cursor: pointer;
}

/* Separator: hidden at Level 1, visible at Level 2 between icon and category title */
.breadcrumb-separator {
    color: rgba(255, 255, 255, 0.5);
    font-size: 20px;
    display: none;
}

.breadcrumb-separator::before {
    content: '\203A';
}

.breadcrumb.has-category .breadcrumb-separator {
    display: inline;
}

.breadcrumb-text {
    font-size: 17px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
}

/* Header controls */
.header-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Order badge */
.order-btn {
    position: relative;
}

.order-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    background: rgba(212, 175, 55, 0.95);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    border-radius: 9999px;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: scale(0.5);
    will-change: transform;
    transition:
        opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
        transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
    pointer-events: none;
}

.order-badge.visible {
    opacity: 1;
    transform: scale(1);
}

/* ------------------------------------------
   PANEL CONTENT
   ------------------------------------------ */
.panel-content-wrapper {
    flex: 1;
    position: relative;
    overflow: hidden;
}

.panel-view {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    padding: 0 12px 12px;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    
    /* Hidden by default */
    opacity: 0;
    pointer-events: none;
    
    /* Slide animation - no spring to avoid shimmy */
    transition: 
        opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
        transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Categories view (starts visible when panel opens) */
.categories-view {
    transform: translate3d(0, 0, 0);
    opacity: 0;
}

.categories-view.active {
    transform: translate3d(0, 0, 0);
    opacity: 1;
    pointer-events: auto;
}

.categories-view.slide-out {
    transform: translate3d(-30%, 0, 0);
    opacity: 0;
    pointer-events: none;
}

/* Items view (starts off-screen right) */
.items-view {
    transform: translate3d(100%, 0, 0);
    opacity: 0;
    /* No separate background - shares panel's glass styling */
}

.items-view.active {
    transform: translate3d(0, 0, 0);
    opacity: 1;
    pointer-events: auto;
}

/* ------------------------------------------
   CATEGORY LIST
   ------------------------------------------ */
.category-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* First divider sits flush against service header */
.items-list .glass-divider:first-child {
    padding-top: 0;
}

.category-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    min-height: 64px;
    position: relative;
    overflow: hidden;
}

/* Hidden on mobile - only shown in TV mode */
.category-card .card-image-bg {
    display: none;
}

.category-card.card-disabled {
    opacity: 0.3;
    pointer-events: none;
}

.category-card .card-icon {
    width: 36px;
    height: 36px;
}

/* ------------------------------------------
   ITEMS LIST
   ------------------------------------------ */
.items-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.item-card {
    padding: 12px;
}

/* ------------------------------------------
   VISUAL CARD GRID (Pattern A)
   ------------------------------------------ */
.visual-card-grid {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}
.visual-card-grid > * {
    -webkit-flex: 0 0 48%;
    flex: 0 0 48%;
    margin: 1%;
}

/* Single column on small screens */
@media (max-width: 400px) {
    .visual-card-grid {
        grid-template-columns: 1fr;
    }
}

/* No stagger - items appear with panel view slide */

.item-card {
    display: flex;
    align-items: center;
    gap: 12px;
}

.item-card .card-image {
    width: 60px;
    height: 60px;
    border-radius: 20px;
    background-size: cover;
    background-position: center;
    flex-shrink: 0;
}

.item-card .card-content {
    flex: 1;
    min-width: 0;
}

.card-subtitle-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    width: 100%;
}

.item-price {
    font-size: 13px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    white-space: nowrap;
    margin-left: auto;
}

/* ------------------------------------------
   DETAIL CONTENT STYLES
   Used inside modal for item details
   ------------------------------------------ */
.detail-content {
    height: 100%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* Detail view styling */
.detail-image {
    height: 200px;
    background-size: cover;
    background-position: center;
    border-radius: 32px 32px 0 0;
}

.detail-header {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px 16px 8px;
}

.detail-title {
    font-size: 24px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
}

.detail-subtitle {
    font-size: 17px;
    color: rgba(255, 255, 255, 0.7);
}

.detail-section {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px 16px;
}

.detail-description {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

.detail-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 8px 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.detail-row:last-child {
    border-bottom: none;
}

.detail-label {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.detail-value {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.95);
    text-align: right;
}

.detail-subsection {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border-radius: 20px;
}

.detail-subsection-title {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
}

.detail-badge {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 9999px;
    font-size: 13px;
    font-weight: 500;
}

.detail-badge.included {
    background: rgba(56, 161, 105, 0.2);
    color: rgba(0, 199, 190, 0.95);
}

.detail-badge.supplement {
    background: rgba(237, 137, 54, 0.2);
    color: rgba(212, 175, 55, 0.95);
}

.detail-note {
    padding: 12px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border-radius: 20px;
    border-left: 3px solid rgba(212, 175, 55, 0.95);
}

.detail-note p {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

/* Item value (shown on item cards) */
.item-value {
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
    white-space: nowrap;
    padding: 4px 8px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 65%);
    border-radius: 16px;
}

/* Large value display (detail view) */
.detail-value-large {
    font-size: 32px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    text-align: center;
    padding: 16px 0;
}

/* Monospace value (passwords, codes) */
.detail-value-mono {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    letter-spacing: 0.05em;
}

/* ------------------------------------------
   DETAIL MODAL (Level 2)
   ------------------------------------------ */
.modal-overlay {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    z-index: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 5vw;
    
    /* Frosted backdrop -- ONE blur per modal stack (the card adds milk, not
       a second blur). blur(8) on both prefixes = the iOS rendering, now the
       reference look on every engine. */
    background: transparent;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    
    /* Hidden by default */
    opacity: 0;
    pointer-events: none;
    
    /* Fast fade for backdrop */
    transition: opacity 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.modal-overlay.open {
    opacity: 1;
    pointer-events: auto;
}

.detail-modal {
    width: 100%;
    max-width: 400px;
    max-height: 80vh;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    position: relative;

    /* Level-2 glass: pane over pane. The overlay supplies the (single) blur;
       stacking reads as MILK -- a denser fill -- exactly like a second sheet
       of frosted glass. No second live blur. */
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.1) 65%);
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 32px;

    color: rgba(255, 255, 255, 0.95);
    
    /* Spring scale - overshoot gives pop */
    transform: scale(0.92);
    transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* One blur per stack. This modal also carries .glass-panel, whose rule would
   re-add a live backdrop-filter -- double-blurring over the overlay's blur(8).
   Kill it here so the overlay supplies the single blur and the graded fill
   supplies the milk. Chrome 38 ignores backdrop-filter, so this is a no-op
   there; on every blur-capable engine it removes a full-screen blur pass. */
.modal-overlay .detail-modal {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

.detail-modal .modal-title,
.detail-modal .modal-description,
.detail-modal .quantity-value {
    color: rgba(255, 255, 255, 0.95);
}

.detail-modal .modal-price {
    color: rgba(212, 175, 55, 0.95);
}

.modal-overlay.open .detail-modal {
    transform: scale(1);
}

.modal-close {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 1;
}

/* Modal hero image */
.modal-hero {
    height: 160px;
    background-size: cover;
    background-position: center;
    border-radius: 32px 32px 0 0;
}

.modal-hero.compact {
    height: 100px;
}

/* Modal header */
.modal-header {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px 8px 0;
}

.modal-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* Modal body */
.modal-body {
    padding: 0 8px;
}

/* Modal info section -- scoped overrides for light-background modals.
   The global .info-row styles live in glass-info-card.css using design tokens. */
.modal-info {
    padding: 12px 8px 16px;
}

/* Modal menu section (bar menus inside detail modal) */
.modal-menu-section {
    padding: 0 8px 16px;
}

.modal-menu-section .glass-divider {
    margin-bottom: 8px;
}

/* Modal order section (transactional) */
.modal-order-section {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.modal-order-section .modal-price {
    font-size: 24px;
    font-weight: 700;
    color: rgba(212, 175, 55, 0.95);
}

.add-to-order-btn,
.action-btn {
    width: 100%;
}

/* Large value display (room number, dates) */
.modal-value-display {
    font-size: 32px;
    font-weight: 700;
    text-align: center;
    padding: 12px 16px;
    color: rgba(212, 175, 55, 0.95);
}

/* Info note (special callout) */
.info-note {
    margin-top: 12px;
    padding: 12px;
    background: rgba(0, 0, 0, 0.04);
    border-radius: 20px;
    border-left: 3px solid rgba(212, 175, 55, 0.95);
}

.info-note p {
    font-size: 13px;
    color: rgba(0, 0, 0, 0.7);
    margin: 0;
    line-height: 1.7;
}

.info-value.mono {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    letter-spacing: 0.05em;
}

/* Hotel Collection Grid */
.hotel-collection-grid {
    gap: 12px;
}

.hotel-collection-card {
    min-height: 140px;
}

.hotel-card-badge {
    display: inline-block;
    padding: 2px 8px;
    margin-top: 4px;
    background: rgba(212, 175, 55, 0.95);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    border-radius: 9999px;
    letter-spacing: 0.04em;
}

/* Legacy modal-image support */
.modal-image {
    height: 180px;
    margin: calc(-1 * 24px);
    margin-bottom: 20px;
    background: linear-gradient(135deg, 
        rgba(49, 151, 149, 0.5) 0%, 
        rgba(56, 161, 105, 0.5) 100%
    );
    border-radius: 32px 32px 0 0;
}

.modal-image.has-image {
    background-size: cover;
    background-position: center;
}

.modal-content {
    display: flex;
    flex-direction: column;
    gap: 12px;
    
    /* Fade in slightly after modal scales */
    opacity: 0;
    transform: translateY(8px);
    transition: 
        opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
        transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
    transition-delay: 50ms;
}

.modal-overlay.open .modal-content {
    opacity: 1;
    transform: translateY(0);
}

.modal-title {
    font-size: 24px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
}

.modal-description {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.7;
}

.modal-price {
    font-size: 20px;
    font-weight: 700;
    color: rgba(212, 175, 55, 0.95);
}

/* Quantity selector */
.quantity-selector {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    padding: 16px 0;
}

.quantity-value {
    font-size: 24px;
    font-weight: 700;
    min-width: 40px;
    text-align: center;
}

/* Modal actions */
.modal-actions {
    display: flex;
    gap: 12px;
    padding-top: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.modal-actions .glass-button {
    flex: 1;
}

/* Room request per-task options (To-Your-Room) */
.modal-request-fields {
    display: flex;
    flex-direction: column;
    gap: 16px;
    /* match .modal-body / .modal-info horizontal indent so fields line up with the description */
    padding: 16px 8px 0;
}
.request-field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* quantity-style fields: label + stepper on one row */
.request-field-inline {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
}
.request-field-label {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
}
.request-field .quantity-selector {
    justify-content: flex-start;
    padding: 0;
}
.modal-request-confirm {
    flex: 1;
    text-align: center;
    padding: 12px;
    color: rgba(212, 175, 55, 0.95);
    font-weight: 700;
}
.modal-request-error {
    margin-top: 12px;
    padding: 12px;
    border-radius: 8px;
    background: rgba(214, 92, 92, 0.18);
    color: rgba(255, 255, 255, 0.95);
    font-size: 13px;
}

/* ------------------------------------------
   MODAL FORMS (Action Single Pattern)
   Glass modal = dark surface, light text
   ------------------------------------------ */
.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.form-label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Time picker - grid of time buttons */
.time-picker {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}
.time-picker > * {
    -webkit-flex: 0 0 31%;
    flex: 0 0 31%;
    margin: 1%;
}

.time-option {
    padding: 12px 8px;
    font-size: 15px;
    font-weight: 500;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    color: rgba(255, 255, 255, 0.95);
    cursor: pointer;
}

.time-option.selected {
    background: rgba(212, 175, 55, 0.95);
    color: #fff;
    border-color: rgba(212, 175, 55, 0.3);
}

.time-option.full,
.time-option.past,
.time-option.closed,
.time-option:disabled {
    background: rgba(255, 255, 255, 0.03);
    color: rgba(255, 255, 255, 0.35);
    border-color: rgba(255, 255, 255, 0.05);
    cursor: not-allowed;
    text-decoration: line-through;
}

/* Late Checkout tier chips: the chips SPAN the picker row (3 across when they
   fit) and keep the time + price on a SINGLE line each; they wrap only if a
   single-line chip cannot fit. Reuses the segmented look + gold selected state. */
.lco-tier-picker {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
}
.lco-tier-picker > * {
    -webkit-flex: 1 1 auto;
    flex: 1 1 auto;
    margin: 0;
}
.lco-tier {
    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: baseline;
    align-items: baseline;
    gap: 6px;
    white-space: nowrap;
}
.lco-tier-time {
    font-weight: 600;
}
.lco-tier-price {
    font-size: 12px;
    opacity: 0.72;
}
.lco-tier.selected .lco-tier-price {
    opacity: 0.95;
}

/* Availability banner: surfaced between calendar and time-picker when the
   server signals the whole date is unbookable. Two visual states share the
   muted-warning palette -- closed (operator closure) vs full (no remaining
   capacity). Hidden state collapses to zero height. */
.availability-banner[data-state="hidden"] {
    display: none;
}

.availability-banner[data-state="closed"],
.availability-banner[data-state="full"] {
    display: block;
    margin: 8px 0 12px;
    padding: 12px;
    border-radius: 12px;
    font-size: 13px;
    line-height: 1.4;
    background: rgba(212, 175, 55, 0.08);
    border: 1px solid rgba(212, 175, 55, 0.25);
    color: rgba(255, 255, 255, 0.85);
}

/* Past-date calendar cells: keep them visible (so the layout doesn't shift
   when today moves through the stay) but make them clearly unreachable. */
.calendar-day-cell.disabled,
.calendar-day-cell.past {
    opacity: 0.35;
    cursor: not-allowed;
    pointer-events: none;
}

.calendar-day-cell.past .day-number {
    text-decoration: line-through;
}

/* Option list - vertical list of selectable cards */
.option-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.option-card {
    padding: 12px 16px;
    text-align: left;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 28px;
    transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.option-card:hover {
    background: rgba(255, 255, 255, 0.12);
}

.option-card.selected {
    background: rgba(212, 175, 55, 0.15);
    border-color: rgba(212, 175, 55, 0.95);
}

.option-card .card-content {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.option-card .card-title {
    font-size: 15px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
}

.option-card .card-subtitle {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
}

/* Star rating */
.star-rating {
    display: flex;
    gap: 8px;
    justify-content: center;
    padding: 12px 0;
}

.star-btn {
    width: 44px;
    height: 44px;
    padding: 8px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 50%;
    cursor: pointer;
    transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.star-btn:hover {
    background: rgba(255, 255, 255, 0.12);
}

.star-btn.active {
    background: rgba(212, 175, 55, 0.95);
    border-color: rgba(212, 175, 55, 0.3);
}

.star-icon {
    width: 100%;
    height: 100%;
    color: rgba(255, 255, 255, 0.5);
    fill: currentColor;
}

.star-btn.active .star-icon {
    color: #fff;
}

/* Textarea in modal */
.detail-modal .glass-input {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.95);
}

.detail-modal .glass-input::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.detail-modal .glass-input:focus {
    border-color: rgba(212, 175, 55, 0.95);
    background: rgba(255, 255, 255, 0.1);
}


/* ------------------------------------------
   DND MODAL (inside detail-modal)
   ------------------------------------------ */
.dnd-toggle-wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 0;
}

.dnd-toggle-label {
    font-size: 15px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
}

.dnd-status {
    font-size: 13px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 9999px;
}

.dnd-status.active {
    background: rgba(229, 62, 62, 0.15);
    color: rgba(255, 59, 48, 0.95);
}

.dnd-status.inactive {
    background: rgba(56, 161, 105, 0.15);
    color: rgba(52, 199, 89, 0.95);
}

/* Reservation modal uses calendar day-cell molecule from glass-calendar.css */

/* ==============================================
   TABLET BREAKPOINT
   Tablet keeps the phone layout. Only the home service tiles scale
   up to fill the main screen (see the device-mobile block below).
   Detail modal and item-card image keep their existing tablet sizing.
   ============================================== */
@media (min-width: 768px) {
    .detail-modal {
        max-width: 480px;
    }

    .item-card .card-image {
        width: 80px;
        height: 80px;
    }
}

/* ----------------------------------------------
   TABLET HOME TILES
   Part of the shared content box (see --content-inset). On tablet the header
   circles ease in and the 3x3 grid grows out to one 9vw inset, so their edges
   align; the grid fills that box, so the tiles scale with the viewport
   (portrait-lock bounds the width, so they do not run away). Tiles stay square
   (aspect-ratio: 1). Tile icons are % so they scale with the tile; the label
   is a fixed 20px (a vw label would drift, and labels are nowrap + ellipsis in
   glass-tile.css). Gated on body.device-mobile so real TVs (body.device-tv)
   are never caught here; 600px so small 7-8" tablets are included, not just
   full-size iPads; bounded at 1199px because device-mobile is the fallback
   tier for every non-TV UA (device-context.js) -- desktop lands here too, so
   the class alone would not keep this off large screens. A portrait tablet is
   always under 1199px.
   ---------------------------------------------- */
@media (min-width: 600px) and (max-width: 1199px) {
    /* Inset set as literals (not the --content-inset token) because a token
       consumed inside a media query is not re-resolved by the var-flattening
       build (build-css.js) -- the TV block sets its inset the same way. 9vw is
       the meet-in-the-middle between the phone header (5vw) and the old grid. */
    body.device-mobile .main-header {
        left: 9vw;
        right: 9vw;
    }

    body.device-mobile .main-screen {
        padding-left: 9vw;
        padding-right: 9vw;
    }

    body.device-mobile .service-grid {
        gap: 16px;
    }

    body.device-mobile .service-tile .tile-label {
        font-size: 20px;
    }
}

/* ==============================================
   TV / DESKTOP BREAKPOINT
   Landscape orientation, large screen
   ============================================== */
@media (min-width: 1200px) and (orientation: landscape) {
    :root {
        /* Increase sizes for 10-foot viewing */
        --font-size-sm: 15px;
        --font-size-base: 17px;
        --font-size-md: 20px;
        --font-size-lg: 24px;
        --font-size-xl: 28px;
        --font-size-2xl: 36px;
    }
    
    /* ------------------------------------------
       TV ROW (Fixed at top, mirrors service grid)
       Viewport-relative sizing: tiles occupy the
       same screen proportion on any TV resolution.
       justify-content: center guarantees the 3|3
       split falls on the exact screen midline.
       ------------------------------------------ */
    /* TV content box = 8vw inset. The header circles, this featured row, and
       the 9-tile grid below all use this one value, so their left/right edges
       line up. Set as a literal (not the token) because a token consumed
       inside a media query is not re-resolved by the flatten build -- the
       tablet block sets its inset the same way. Tune all three insets on the
       Samsung test set (192.168.1.175). */
    .main-header {
        left: 8vw;
        right: 8vw;
    }

    /* Header band composition: banners wide-left, circle cluster right.
       Literal sizes throughout -- tokens are not re-resolved inside media
       queries by the flatten build. Spacing is MARGINS, not flex gap: the
       target TVs (Chrome 38, Tizen 6.0 = Chromium 76) ignore gap entirely
       -- same reason .tv-grid spaces with margins. */
    .header-band {
        display: -webkit-flex;
        display: flex;
        -webkit-flex: 1 1 0%;
        flex: 1 1 0%;
        min-width: 0;
    }

    /* Hotels (H) circle is TV-only -- restore the .glass-button display the
       default rule above suppresses. Sized by .header-circle .logo-img below. */
    #hotelsBtn {
        display: -webkit-inline-flex;
        display: inline-flex;
    }

    .main-header .header-right {
        margin-left: 16px;
        gap: 0;
    }

    .header-right > * + * {
        margin-left: 8px;
    }

    .header-hero {
        display: -webkit-flex;
        display: flex;
        -webkit-flex: 1 1 0%;
        flex: 1 1 0%;
    }

    .header-clock {
        display: -webkit-flex;
        display: flex;
        min-width: 150px;
        margin-left: 16px;
    }

    .hero-banner-text {
        font-size: 24px;
    }

    .clock-time {
        font-size: 24px;
        line-height: 1.2;
    }

    .clock-date {
        font-size: 14px;
    }

    /* Header circles 50% larger for 10-foot viewing */
    .glass-button.header-circle {
        width: 78px;
        height: 78px;
    }

    .glass-button.header-circle .btn-icon {
        width: 39px;
        height: 39px;
    }

    .header-circle .logo-img {
        width: 30px;
        height: 30px;
    }

    .tv-row {
        display: block;
        position: fixed;
        top: 22vh;
        left: 8vw;
        right: 8vw;
        z-index: 5;
    }

    .tv-grid {
        display: -webkit-flex;
        display: flex;
        -webkit-justify-content: center;
        justify-content: center;
        display: grid;
        /* Six equal fractions of the content box -- tile size derives from the
           box, not a fixed vw, so the row shares edges with the header and the
           9-row. flex: 1 1 0 is the Chrome 38 (no grid) equivalent. */
        grid-template-columns: repeat(6, 1fr);
        gap: 1.2vw;
    }
    .tv-grid > * {
        -webkit-flex: 1 1 0%;
        flex: 1 1 0%;
        min-width: 0;
        margin: 0.6vw;
    }
    
    .tv-tile {
        padding: 1.5vw;
    }
    
    .tv-tile .tile-icon {
        width: 5.5vw;
        height: 5.5vw;
    }
    
    .tv-tile .tile-label {
        font-size: 1vw;
    }
    
    /* ------------------------------------------
       MAIN SCREEN (TV Layout)
       Single row of 9, positioned 20% from bottom
       ------------------------------------------ */
    .main-screen {
        align-items: flex-end;
        padding-bottom: 15vh;
        padding-top: 0;
        padding-left: 8vw;
        padding-right: 8vw;
    }
    
    .service-grid {
        -webkit-flex-wrap: nowrap;
        flex-wrap: nowrap;
        -webkit-justify-content: center;
        justify-content: center;
        /* Nine equal fractions of the SAME box the featured row uses, so the
           two rows share left/right edges. Nine across the same width makes
           these tiles smaller squares than the featured six -- by design. */
        grid-template-columns: repeat(9, 1fr);
        grid-template-rows: 1fr;
        gap: 0.8vw;
        max-width: 100%;
    }
    .service-tile {
        -webkit-flex: 1 1 0%;
        flex: 1 1 0%;
        min-width: 0;
        margin: 0.4vw;
    }
    
    /* Focus states for remote navigation (TV) */
    .glass-tile:focus,
    .glass-card:focus,
    .glass-button:focus {
        outline: none;
    }
    
    .glass-tile:focus-visible,
    .glass-card:focus-visible,
    .glass-button:focus-visible {
        border-color: rgba(255, 255, 255, 0.65);
        outline: 3px solid rgba(255, 255, 255, 0.9);
        outline-offset: 4px;
        box-shadow:
            0 0 20px rgba(255, 255, 255, 0.4),
            inset 0 0 0 1px rgba(255, 255, 255, 0.16),
        inset 1.5px 1.5px 1.5px rgba(255, 255, 255, 0.62),
        inset -1px -1px 1.5px rgba(255, 255, 255, 0.24),
        0 10px 28px rgba(0, 0, 0, 0.28);
        transform: scale(1.03);
    }

    /* Home-grid tiles keep zoom, never transform: the rule above would
       otherwise re-introduce scale at equal specificity and defeat the
       zoom-not-scale frost protection (see .service-tile base comment). */
    .service-tile:focus-visible {
        transform: none;
        zoom: 1.03;
    }

    /* ------------------------------------------
       D-PAD CURSOR (the glass picked up and held
       closer to the light). No ring, no halo:
       fill steps to the solid tier, the lip
       jumps to the elevated rim, the element
       grows via zoom (frost-safe; layout push is
       absorbed by the flex rows). Literal values
       -- tokens do not re-resolve in here.
       Placed AFTER the :focus-visible rules so
       the cursor wins the cascade at equal
       specificity when both states are active.
       ------------------------------------------ */
    /* Generic cursor fallback FIRST: any stop the enumerated rules below
       do not cover (locked-preview wrapper, menu rows, future stops) still
       shows the lip -- an invisible cursor is a broken remote. The
       specific rules override at higher specificity. */
    .dpad-focused {
        box-shadow:
            inset 2px 3px 4px rgba(255, 255, 255, 0.55),
            inset -1.5px -2px 3px rgba(255, 255, 255, 0.18),
            0 10px 28px rgba(0, 0, 0, 0.28);
        transform: scale(1.02);
    }

    .glass-tile.dpad-focused,
    .glass-button.dpad-focused,
    .glass-card.dpad-focused,
    .glass-visual-card.dpad-focused,
    .glass-venue-card.dpad-focused,
    .header-hero.dpad-focused,
    .header-clock.dpad-focused,
    .calendar-day-cell.dpad-focused,
    .calendar-agenda-row.dpad-focused {
        outline: none;
        background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.13) 65%);
        border-color: rgba(255, 255, 255, 0.5);
        box-shadow:
            inset 2px 3px 4px rgba(255, 255, 255, 0.55),
            inset -1.5px -2px 3px rgba(255, 255, 255, 0.18),
            0 10px 28px rgba(0, 0, 0, 0.28);
        color: rgba(255, 255, 255, 1);
    }

    /* Growth is transform: scale, NOT zoom -- legacy-Blink zoom multiplies
       an element's own specified lengths, so flex/grid-sized tiles would
       not visibly grow on either TV engine. Scale renders the whole box
       larger with no reflow. (Self-scale on a frost carrier matches the
       shipped :focus-visible precedent; both hotel TV tiers paint these
       tiles without live frost anyway.) 1.04 is the overlap ceiling: the
       grid gaps absorb ~4px of growth per side; 1.06 kissed neighbours. */
    .glass-tile.dpad-focused,
    .glass-button.dpad-focused {
        transform: scale(1.04);
    }

    .glass-card.dpad-focused,
    .glass-visual-card.dpad-focused,
    .glass-venue-card.dpad-focused,
    .calendar-day-cell.dpad-focused,
    .calendar-agenda-row.dpad-focused {
        transform: scale(1.05);
    }

    /* Band widgets: the hero spans ~2/3 of the row, so a small scale
       already reads large; the compact clock takes the card scale. */
    .header-hero.dpad-focused {
        transform: scale(1.02);
    }

    .header-clock.dpad-focused {
        transform: scale(1.05);
    }

    .header-hero,
    .header-clock {
        cursor: pointer;
    }

    .dpad-focused .tile-label {
        font-weight: 700;
    }

    .dpad-focused:focus,
    .dpad-focused:focus-visible {
        outline: none;
    }

    /* The Samsung tier pins glass backgrounds at higher specificity
       (body.tier-samsung ...) -- re-assert the cursor's fill-solid step at
       tier specificity or the focused element shows zero fill differential
       on the actual hotel TVs. Tint-only surfaces get the plain step: */
    body.tier-samsung .glass-card.dpad-focused,
    body.tier-samsung .glass-visual-card.dpad-focused,
    body.tier-samsung .glass-venue-card.dpad-focused,
    body.tier-samsung .glass-button.dpad-focused,
    body.tier-samsung .calendar-day-cell.dpad-focused,
    body.tier-samsung .calendar-agenda-row.dpad-focused {
        background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.13) 65%);
    }

    /* ...but frost carriers (tiles, header circles) draw their blur as a
       SECOND background layer on this tier (baked hero-frost, viewport-
       anchored) -- the cursor must re-state that layer under its stepped
       tint or focusing an element strips its frost. Keep the exact
       runtime-var shorthand form (build-css restoreRuntimeVars). */
    body.tier-samsung .glass-tile.dpad-focused,
    body.tier-samsung .glass-button.header-circle.dpad-focused,
    body.tier-samsung .header-hero.dpad-focused,
    body.tier-samsung .header-clock.dpad-focused {
        background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.13) 65%), var(--hero-frost-image) center / cover no-repeat fixed;
    }


    /* ------------------------------------------
       SERVICE PANEL (TV)
       Still slides up from bottom
       ------------------------------------------ */
    .service-panel {
        left: 40px;
        right: 40px;
    }

    /* Snappier slide on the 10-foot layout: 350ms (literal -- tokens do
       not re-resolve in media queries). Wrapper visibility delays match,
       so the pane still hides exactly when the shorter slide ends. */
    .service-panel .panel-container,
    .top-panel .panel-container {
        transition-duration: 350ms;
    }

    .service-panel,
    .top-panel {
        transition: visibility 0ms linear 350ms;
    }

    .panel-container {
        border-radius: 48px 48px 0 0;
    }

    /* ------------------------------------------
       TOP PANEL (TV)
       Still slides down from top
       ------------------------------------------ */
    .top-panel {
        left: 40px;
        right: 40px;
    }

    .top-panel .panel-container {
        border-radius: 0 0 48px 48px;
    }
    
    .service-header {
        padding: 24px 32px;
    }
    
    .panel-view {
        padding: 0 32px 24px;
    }
    
    /* ------------------------------------------
       CATEGORY CARDS (TV - Visual Image Cards)
       auto-fit + 1fr = edge-to-edge filling.
       minmax floor of 240px prevents too many
       cramped columns. Cards stretch to fill
       regardless of count: 2 items = 2 wide
       cards, 10 items = rows of 3-4.
       ------------------------------------------ */
    .category-list {
        display: -webkit-flex;
        display: flex;
        -webkit-flex-wrap: wrap;
        flex-wrap: wrap;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
        gap: 20px;
    }
    .category-list > * {
        -webkit-flex: 0 0 30%;
        flex: 0 0 30%;
        margin: 1.5%;
    }
    
    .category-card {
        flex-direction: column;
        align-items: stretch;
        padding: 0;
        min-height: 220px;
        border-radius: 28px;
    }
    
    /* Show image background in TV mode */
    .category-card .card-image-bg {
        display: block;
        position: absolute;
        top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
        background-size: cover;
        background-position: center;
        border-radius: 28px;
        z-index: 0;
    }
    
    /* Gradient overlay for text legibility */
    .category-card::before {
        content: '';
        position: absolute;
        top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
        background: linear-gradient(
            to top,
            rgba(0, 0, 0, 0.8) 0%,
            rgba(0, 0, 0, 0.4) 40%,
            rgba(0, 0, 0, 0.1) 100%
        );
        border-radius: 28px;
        z-index: 1;
    }

    /* Hide icon in TV mode - image is the visual */
    .category-card .card-icon {
        display: none;
    }
    
    /* Hide chevron in TV mode */
    .category-card .card-chevron {
        display: none;
    }
    
    /* Position content at bottom */
    .category-card .card-content {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        padding: 16px;
        z-index: 2;
        text-align: center;
    }

    .category-card .card-title {
        font-size: 20px;
        font-weight: 700;
        text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
    }

    .category-card .card-subtitle {
        font-size: 13px;
        opacity: 0.9;
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    }
    
    /* TV Mode - Category card hover/focus with image zoom */
    .category-card .card-image-bg {
        transition: transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
    }
    
    .category-card:hover .card-image-bg,
    .category-card:focus-visible .card-image-bg {
        transform: scale(1.08);
    }
    
    .category-card:active .card-image-bg {
        transform: scale(1.02);
    }
    
    /* Items list - grid layout */
    .items-list {
        -webkit-flex-direction: row;
        flex-direction: row;
        -webkit-flex-wrap: wrap;
        flex-wrap: wrap;
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 16px;
    }
    .items-list > .glass-card {
        -webkit-flex: 0 0 48%;
        flex: 0 0 48%;
        margin: 1%;
    }

    /* Dividers and card grids span full width of items-list */
    .items-list > .glass-divider,
    .items-list > .visual-card-grid,
    .items-list > .venue-card-grid {
        grid-column: 1 / -1;
    }

    /* Visual card grid fills edge-to-edge on TV */
    .visual-card-grid {
        grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    }
    
    /* ------------------------------------------
       DETAIL MODAL (TV)
       ------------------------------------------ */
    .detail-modal {
        max-width: 560px;
    }
    
    .modal-image {
        height: 240px;
    }
    
    .detail-image {
        height: 280px;
    }
    
    .item-card .card-image {
        width: 100px;
        height: 100px;
    }
    
}

/* ==============================================
   LARGE TV (4K)
   ============================================== */
@media (min-width: 1920px) and (orientation: landscape) {
    :root {
        --font-size-sm: 18px;
        --font-size-base: 20px;
        --font-size-md: 24px;
        --font-size-lg: 28px;
        --font-size-xl: 34px;
        --font-size-2xl: 44px;
    }
    
    /* Category Cards - 4K adjustments */
    .category-list {
        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    }

    .category-card {
        min-height: 260px;
    }
    
    .category-card .card-title {
        font-size: 24px;
    }
    
    .category-card .card-subtitle {
        font-size: 15px;
    }
}

/* ==============================================
   PWA INSTALL BANNER
   ============================================== */

.install-banner {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    left: 12px;
    right: 12px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px 16px 12px;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.13) 65%);
    backdrop-filter: blur(30px) saturate(120%) brightness(0.92);
    -webkit-backdrop-filter: blur(30px) saturate(120%) brightness(0.92);
    border: 1.5px solid rgba(255, 255, 255, 0.5);
    border-radius: 28px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    transform: translateY(-120%);
    opacity: 0;
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1),
                opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.install-banner.visible {
    transform: translateY(0);
    opacity: 1;
}

.install-banner-content {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.install-banner-heading {
    font-size: 20px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.95);
}

.install-banner-text {
    font-size: 15px;
    color: rgba(255, 255, 255, 0.7);
    line-height: 1.5;
}

.install-banner-actions {
    display: flex;
    gap: 8px;
}

.install-banner-actions .glass-button.primary {
    flex: 1;
}

.install-banner-actions .glass-button.secondary {
    flex-shrink: 0;
}

.install-banner.install-pending .install-banner-heading {
    opacity: 0.6;
}

.install-banner.install-success {
    border-color: rgba(52, 199, 89, 0.95);
}

.install-banner.install-success .install-banner-heading {
    color: rgba(52, 199, 89, 0.95);
}

/* ==============================================
   iOS INSTALL GUIDE OVERLAY
   ============================================== */

.ios-guide-overlay {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    z-index: 10002;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 60px);
    background: rgba(0, 0, 0, 0.4);
    animation: fadeIn 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* In-app / non-Safari guests get a centred card (no toolbar arrow to point at). */
.ios-guide-overlay.is-centered {
    align-items: center;
    padding-bottom: 0;
}

.ios-guide-card {
    position: relative;
    text-align: center;
    padding: 16px;
    background: rgba(255, 255, 255, 0.92);
    border-radius: 24px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    max-width: 320px;
}

.ios-guide-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    background: transparent;
    font-size: 22px;
    line-height: 1;
    color: rgba(0, 0, 0, 0.45);
    cursor: pointer;
}

.ios-guide-text {
    font-size: 15px;
    color: rgba(0, 0, 0, 0.87);
    margin: 0 0 8px;
}

.ios-guide-sub {
    font-size: 13px;
    color: rgba(0, 0, 0, 0.6);
    line-height: 1.5;
    margin: 0 0 12px;
}

.ios-guide-actions {
    display: flex;
    justify-content: center;
}

.ios-guide-copy {
    min-width: 160px;
}

.ios-guide-copy.is-copied {
    background: rgba(52, 199, 89, 0.95);
    border-color: rgba(52, 199, 89, 0.95);
}

.ios-guide-arrow {
    width: 32px;
    height: 32px;
    color: rgba(0, 0, 0, 0.5);
}

/* ==============================================
   IDENTIFICATION POPUP (Layer 3)
   ============================================== */

.identify-overlay {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    padding: 16px;
    animation: fadeIn 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.identify-card {
    width: 100%;
    max-width: 400px;
    background: rgba(255, 255, 255, 0.92);
    border-radius: 32px;
    overflow: hidden;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    animation: scaleIn 300ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.identify-header {
    text-align: center;
    padding: 24px 16px 12px;
}

.identify-title {
    font-size: 24px;
    font-weight: 700;
    color: rgba(0, 0, 0, 0.87);
    margin: 0 0 8px;
}

.identify-subtitle {
    font-size: 15px;
    color: rgba(0, 0, 0, 0.6);
    margin: 0;
}

.identify-body {
    padding: 0 16px 24px;
}

.identify-fields {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Room number + date of birth share one row (surname stays full width above). */
.identify-fields-row {
    display: flex;
    gap: 12px;
}

.identify-fields-row .input-wrapper {
    flex: 1;
    min-width: 0;
}

.identify-body .input-wrapper {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.identify-body .input-label {
    font-size: 13px;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.6);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.identify-body .glass-input {
    background: rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 16px;
    color: rgba(0, 0, 0, 0.87);
    min-height: 48px;
    padding: 0 12px;
    font-size: 15px;
}

.identify-body .glass-input:focus {
    outline: none;
    border-color: rgba(212, 175, 55, 0.95);
    box-shadow: 0 0 0 3px rgba(212, 168, 67, 0.2);
}

.identify-body .glass-input::placeholder {
    color: rgba(0, 0, 0, 0.35);
}

.identify-hint {
    font-size: 11px;
    color: rgba(0, 0, 0, 0.45);
    text-align: center;
    margin: 8px 0 0;
    line-height: 1.4;
}

.identify-error {
    min-height: 20px;
    font-size: 13px;
    color: rgba(255, 59, 48, 0.95);
    padding: 8px 0;
}

/* ------------------------------------------
   CONFIRM DIALOG
   Centered glass card matching the app's frosted-glass aesthetic.
   Uses the same glass tokens as glass-info-card / glass-panel.
   ------------------------------------------ */
.confirm-overlay {
    position: fixed;
    inset: 0;
    z-index: 11000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    padding: 16px;
    animation: fadeIn 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.confirm-overlay.closing {
    animation: fadeOut 200ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.confirm-card {
    width: 100%;
    max-width: 380px;
    /* Level-2 glass over the confirm-overlay's blur(10): stack depth = milk
       (denser fill), not a second live blur. */
    background: rgba(38, 38, 42, 0.86);
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: 32px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12),
        inset 1px 1px 1px rgba(255, 255, 255, 0.55),
        inset -0.5px -0.75px 1px rgba(255, 255, 255, 0.2),
        0 6px 18px rgba(0, 0, 0, 0.22);
    overflow: hidden;
    color: rgba(255, 255, 255, 0.95);
    animation: scaleIn 300ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.confirm-card .confirm-header {
    padding: 24px 20px 12px;
    text-align: center;
}

.confirm-card .confirm-title {
    font-size: 20px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.95);
    margin: 0 0 8px;
    line-height: 1.3;
}

.confirm-card .confirm-message {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    margin: 0;
    line-height: 1.5;
}

.confirm-card .confirm-body {
    padding: 0 20px 20px;
}

.confirm-actions {
    display: flex;
    gap: 12px;
    margin-top: 12px;
}

.confirm-actions .glass-button {
    flex: 1;
    min-height: 48px;
}

/* The .secondary glass-button already pairs with dark backdrops; no extra
   override is needed here -- it inherits the right text/border tokens. */

@keyframes fadeOut {
    from { opacity: 1; }
    to { opacity: 0; }
}

.identify-submit {
    width: 100%;
    margin-top: 8px;
}

.identify-skip {
    display: block;
    width: 100%;
    background: none;
    border: none;
    color: rgba(0, 0, 0, 0.4);
    font-size: 13px;
    padding: 8px 0 0;
    cursor: pointer;
}

.identify-skip:hover {
    color: rgba(0, 0, 0, 0.6);
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes scaleIn {
    from { opacity: 0; transform: scale(0.92); }
    to { opacity: 1; transform: scale(1); }
}

/* Tablet/TV: wider card */
@media (min-width: 768px) {
    .identify-card {
        max-width: 480px;
    }
}

@media (min-width: 1200px) and (orientation: landscape) {
    .identify-card {
        max-width: 560px;
        border-radius: 48px;
    }

    .identify-body .glass-input {
        min-height: 56px;
        font-size: 17px;
    }
}

/* ==============================================
   PREVIEW LOCKED (Not logged in -- show data dimmed with tap overlay)
   ============================================== */

.preview-locked {
    position: relative;
    cursor: pointer;
}

.preview-locked > .glass-info-card,
.preview-locked > .glass-calendar {
    opacity: 0.35;
    filter: blur(1px);
    pointer-events: none;
    user-select: none;
}

.preview-locked-overlay {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;
}

.preview-locked-label {
    background: rgba(0, 0, 0, 0.7);
    color: white;
    font-size: 13px;
    font-weight: 600;
    padding: 8px 16px;
    border-radius: 12px;
}

.preview-locked:active .preview-locked-label {
    background: rgba(0, 0, 0, 0.85);
}

/* ==============================================
   BROWSE MODE -- transactional buttons disabled
   When body.browse-mode is set, all buttons that
   require identification are muted and inert.
   ============================================== */

body.browse-mode .venue-book-btn,
body.browse-mode .action-btn,
body.browse-mode .add-to-order-btn,
body.browse-mode .qty-btn,
body.browse-mode .dietary-pill {
    opacity: 0.35;
    pointer-events: none;
    filter: grayscale(0.5);
    cursor: default;
}

/* ==============================================
   TLP-154 -- DINING RESERVE CONFIRMATION + ADD ROOM
   Glass modal = dark surface, light text. Reuses the
   guest Liquid Glass tokens + the modal-form idiom
   (rgba glass surfaces) -- no operator tokens/atoms.
   ============================================== */

.confirm-room-card {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 16px;
    padding: 12px;
    color: rgba(255, 255, 255, 0.95);
    font-size: 13px;
}

.confirm-room-card.primary {
    font-weight: 600;
}

.confirm-room-card.found {
    display: -webkit-flex;
    display: flex;
    -webkit-align-items: center;
    align-items: center;
    gap: 8px;
}

.confirm-room-main {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-direction: column;
    flex-direction: column;
    -webkit-flex: 1;
    flex: 1;
    min-width: 0;
}

.confirm-room-name {
    font-weight: 600;
}

.confirm-room-sub,
.confirm-room-remaining {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.7);
}

.confirm-room-remaining {
    color: rgba(212, 175, 55, 0.95);
}

.confirm-room-badge {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(52, 199, 89, 0.95);
    white-space: nowrap;
}

.confirm-room-remove {
    -webkit-flex: 0 0 auto;
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 9999px;
    color: rgba(255, 255, 255, 0.7);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}

.confirm-room-remove:hover {
    background: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.95);
}

/* A bit of breathing room above the Allergies / Special requests section headings. */
.confirm-section {
    margin-top: 12px;
}

/* Allergies confirm-only: visible but non-interactive (editing lives in the
   dietary section, not here). */
.confirm-allergies {
    margin-top: 4px;
}

.confirm-allergies-none {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
}

.dietary-pill.confirm-only {
    cursor: default;
    pointer-events: none;
}

.confirm-special-requests {
    width: 100%;
    min-height: 56px;
    padding: 8px 12px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 16px;
    color: rgba(255, 255, 255, 0.95);
    font-size: 13px;
    font-family: inherit;
    resize: vertical;
    box-sizing: border-box;
}

.confirm-special-requests::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.confirm-special-requests:focus {
    outline: none;
    border-color: rgba(212, 175, 55, 0.95);
    background: rgba(255, 255, 255, 0.1);
}

.confirm-added-rooms:not(:empty) {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-direction: column;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

/* Inside a form-group (edit modal) the label-to-list spacing is the
   form-group gap; don't double it with the standalone margin-top. */
.form-group > .confirm-added-rooms:not(:empty) {
    margin-top: 0;
}

.confirm-addroom-zone {
    margin-top: 12px;
}

.confirm-addroom-btn {
    width: 100%;
    background: rgba(255, 255, 255, 0.04);
    border: 1px dashed rgba(255, 255, 255, 0.25);
    border-radius: 16px;
    color: rgba(255, 255, 255, 0.7);
    padding: 12px;
    font-size: 13px;
    cursor: pointer;
}

.confirm-addroom-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.95);
}

.confirm-addroom-form {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-direction: column;
    flex-direction: column;
    gap: 8px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    padding: 12px;
}

.confirm-addroom-surname,
.confirm-addroom-number {
    width: 100%;
    padding: 8px 12px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 16px;
    color: rgba(255, 255, 255, 0.95);
    font-size: 13px;
    font-family: inherit;
    box-sizing: border-box;
}

.confirm-addroom-surname::placeholder,
.confirm-addroom-number::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.confirm-addroom-surname:focus,
.confirm-addroom-number:focus {
    outline: none;
    border-color: rgba(212, 175, 55, 0.95);
    background: rgba(255, 255, 255, 0.1);
}

.confirm-addroom-actions {
    display: -webkit-flex;
    display: flex;
    gap: 8px;
}

.confirm-addroom-actions .glass-button {
    -webkit-flex: 1;
    flex: 1;
}

.confirm-addroom-cancel {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.7);
}

.confirm-lookup-msg {
    font-size: 12px;
    padding: 4px 0;
}

.confirm-lookup-msg.loading {
    color: rgba(255, 255, 255, 0.7);
}

.confirm-lookup-msg.error {
    color: rgba(255, 59, 48, 0.95);
}

/* ==============================================
   QUOTA PROGRESS BAR (Entitlements)
   ============================================== */

.quota-progress {
    padding: 4px 0 8px;
}

.quota-bar {
    height: 6px;
    background: rgba(255, 255, 255, 0.12);
    border-radius: 9999px;
    overflow: hidden;
}

.quota-fill {
    height: 100%;
    background: rgba(212, 175, 55, 0.95);
    border-radius: 9999px;
    transition: width 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.quota-fill.unlimited {
    background: rgba(52, 199, 89, 0.95);
}

/* ==============================================
   GUEST NOTIFICATION TOAST
   ============================================== */

.guest-notification {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 20px);
    left: 50%;
    transform: translateX(-50%) translateY(20px);
    opacity: 0;
    z-index: 10001;
    padding: 12px 16px;
    border-radius: 9999px;
    font-size: 13px;
    font-weight: 500;
    pointer-events: none;
    transition: opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
                transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
    max-width: 90vw;
    text-align: center;
}

.guest-notification.visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

.guest-notification.success {
    background: rgba(52, 199, 89, 0.95);
    color: rgba(0, 0, 0, 0.9);
}

.guest-notification.error {
    background: rgba(255, 59, 48, 0.95);
    color: #fff;
}

.guest-notification.info {
    background: rgba(0, 122, 255, 0.95);
    color: #fff;
}

/* ==============================================
   ANIMATIONS
   ============================================== */

/* Basket pulse on add - asymmetric with settle */
@keyframes pulse {
    0% { transform: scale(1); }
    25% { transform: scale(1.2); }     /* Fast pop */
    45% { transform: scale(1.12); }    /* Settle back */
    65% { transform: scale(1.16); }    /* Small bounce */
    85% { transform: scale(1.02); }    /* Nearly rest */
    100% { transform: scale(1); }
}

.order-btn.pulse {
    animation: pulse 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* ==============================================
   CONNECTIVITY INDICATOR
   ============================================== */

.connectivity-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: rgba(255, 149, 0, 0.95);
    z-index: 9999;
    pointer-events: none;
    opacity: 0;
    transition: opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.connectivity-bar.offline {
    opacity: 1;
}

/* ==============================================
   REDUCED MOTION
   ============================================== */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ==============================================
   DARK MODE ADJUSTMENTS
   (Glass works best on vibrant backgrounds)
   ============================================== */
@media (prefers-color-scheme: dark) {
    /* brightness(0.9) baked into the gradient alphas -- identical output,
       zero full-screen filter pass. */
    body {
        background:
            linear-gradient(180deg,
                rgba(0, 0, 0, 0.235) 0%,
                rgba(0, 0, 0, 0.46) 100%
            ), var(--hero-image) center / cover no-repeat;
        background-color: #0a1628;
    }
}

.rotate-lock {
    display: none;
}

/* Portrait-lock touch handhelds (phones + tablets) held in landscape,
   at any width. Gated on body.device-mobile so real TVs (body.device-tv)
   are excluded, and on pointer:coarse so desktop (fine pointer) is too.
   pointer:coarse is unsupported on Chrome 38 (legacy in-room TV) -- which
   is device-tv anyway, so the overlay is never shown there.
   Installed Android PWAs are hard-locked via the manifest
   "orientation": "portrait"; this overlay is the fallback for browser
   tabs and iOS (where the manifest orientation is ignored). */
@media (orientation: landscape) and (pointer: coarse) {
    body.device-mobile .rotate-lock {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 100000;
        display: -webkit-flex;
        display: flex;
        -webkit-align-items: center;
        align-items: center;
        -webkit-justify-content: center;
        justify-content: center;
        padding: 24px;
        padding-top: calc(env(safe-area-inset-top, 0px) + 24px);
        padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 24px);
        background: #1a365d;
        color: rgba(255, 255, 255, 0.95);
        text-align: center;
    }

    body.device-mobile .rotate-lock__inner {
        max-width: 320px;
        display: -webkit-flex;
        display: flex;
        -webkit-flex-direction: column;
        flex-direction: column;
        -webkit-align-items: center;
        align-items: center;
        gap: 16px;
    }

    body.device-mobile .rotate-lock__icon {
        width: 64px;
        height: 64px;
        color: rgba(255, 255, 255, 0.9);
        -webkit-animation: rotate-lock-nudge 2.4s ease-in-out infinite;
        animation: rotate-lock-nudge 2.4s ease-in-out infinite;
    }

    body.device-mobile .rotate-lock__title {
        margin: 0;
        font-size: 20px;
        font-weight: 600;
    }

    body.device-mobile .rotate-lock__text {
        margin: 0;
        font-size: 15px;
        color: rgba(255, 255, 255, 0.7);
    }
}

@-webkit-keyframes rotate-lock-nudge {
    0%, 55%, 100% { -webkit-transform: rotate(0deg); }
    25% { -webkit-transform: rotate(-90deg); }
}
@keyframes rotate-lock-nudge {
    0%, 55%, 100% { transform: rotate(0deg); }
    25% { transform: rotate(-90deg); }
}

/* ------------------------------------------
   will-change PROMOTION SCOPING (Wave 1)
   Layers reserve GPU memory only while open/animating;
   released when closed. Avoids the permanent-layer
   memory tax on TVs and phones.
   ------------------------------------------ */
/* Promote the element that actually slides -- .panel-container. The wrapper
   must NOT carry will-change: transform: like a real transform it would
   establish a backdrop root and trap the container's backdrop-filter frost.

   NO will-change may ever include OPACITY: probe-verified, will-change:
   opacity on an ancestor silently kills descendant backdrop-filter even in
   current Chromium at computed opacity 1 -- the one trap modern engines
   never fixed. Opacity transitions self-promote while animating, so the
   hint bought nothing. (Lock-tested.) */
.service-panel.open .panel-container,
.top-panel.open .panel-container {
    will-change: transform;
}

.modal-overlay.open .detail-modal {
    will-change: transform;
}

.modal-overlay.open .modal-content {
    will-change: transform;
}

/* Reserve a GPU layer for the L1->L2 slide views only while they are the
   active view -- matching the .open/.active scoping of the panel/modal rules
   above. Previously will-change sat unconditionally on the base
   .categories-view/.items-view rules (a permanent layer, the idle-memory tax);
   scoping to .active releases it when the view is inactive. The slide animates
   transform, which already promotes, so this is a memory scope, not a paint
   fix. Keyed on .active -- the class app.js actually toggles on these views. */
.categories-view.active,
.items-view.active {
    will-change: transform;
}
