/*
 * Kwamua PWA - external CSS only, per project convention (no inline
 * <style> blocks). Hand-written, no build step, so the PWA has zero
 * compile requirement to run - matches "thin client" intent.
 *
 * Full visual pass (this file, top to bottom): the app worked correctly
 * before this but read as a bare form - flat bordered boxes, two flat
 * brand hexes with no tonal range, identical weight on every button and
 * input, a fixed font-size per breakpoint. This pass builds one small,
 * consistent visual language on top of the *same* markup and the *same*
 * class names everywhere they were already used: soft elevation instead
 * of flat borders, a navy/gold palette with actual tints and shades, a
 * type scale that flows with the viewport instead of being hardcoded per
 * breakpoint, and motion that's felt rather than noticed (and turns off
 * entirely for prefers-reduced-motion). Still zero new dependencies.
 */

:root {
    /* --- Brand: navy + gold, expanded from the two flat hexes in
     * app/Support/BrandColors.php into a small tonal range - lets the UI
     * express depth (a hover state, a tinted surface, a focus ring)
     * without inventing off-brand colors to do it. */
    --kw-ink: #071d49;         /* brand navy - headings, active states */
    --kw-ink-2: #12296b;       /* one step lighter navy - gradients, hover */
    --kw-ink-tint: #eef1f8;    /* navy at roughly 5% - tinted surfaces */
    --kw-amber: #c59b27;       /* brand gold - primary actions */
    --kw-amber-dark: #ad8721;  /* pressed state */
    --kw-amber-tint: #faf3de;  /* gold at roughly 12% - highlighted surfaces, focus rings */

    /* --- Neutrals: a real gray scale instead of jumping straight from
     * white to navy, so secondary text/borders/backgrounds each get
     * their own step instead of borrowing --kw-ink at reduced opacity. */
    --kw-gray-50: #f9fafb;
    --kw-gray-100: #f3f4f6;
    --kw-gray-200: #e5e7eb;
    --kw-gray-300: #d1d5db;
    --kw-gray-400: #9ca3af;
    --kw-gray-500: #6b7280;
    --kw-gray-700: #374151;

    --kw-text: #1f2933;        /* body copy - softer than navy so headings still lead the eye */
    --kw-ink-soft: var(--kw-gray-700);
    --kw-bg: var(--kw-gray-50);
    --kw-white: #ffffff;
    --kw-border: var(--kw-gray-200);

    /* --- Semantic --- */
    --kw-red: #dc2626;
    --kw-red-tint: #fee2e2;
    --kw-green: #16a34a;
    --kw-green-tint: #dcfce7;

    /* --- Elevation: navy-tinted rather than pure black, so shadows read
     * as this brand's depth rather than a generic grey haze. Three steps
     * - resting cards, hovered/raised cards, sheets/overlays. */
    --kw-shadow-sm: 0 1px 2px rgba(7, 29, 73, 0.06), 0 1px 1px rgba(7, 29, 73, 0.04);
    --kw-shadow-md: 0 6px 16px rgba(7, 29, 73, 0.08), 0 2px 4px rgba(7, 29, 73, 0.04);
    --kw-shadow-lg: 0 16px 40px rgba(7, 29, 73, 0.14);

    /* Softer, more "squircle" than a typical web app's 6-8px - closer to
     * what iOS/macOS use for cards and controls, part of this pass's
     * platform-native feel (see the iOS-FEEL section further down). */
    --kw-radius-sm: 10px;
    --kw-radius: 16px;
    --kw-radius-lg: 22px;

    --kw-ease: cubic-bezier(0.4, 0, 0.2, 1);

    /* One width, referenced by both #app and .kw-tabbar below, so the
     * fixed-position tab bar can never drift out of sync with the
     * content column above it. Grows in three steps as the viewport
     * does - phones keep exactly the width they had before (this file
     * was written phone-first, and that's still correct there), but a
     * tablet or desktop browser no longer gets a narrow app-sized
     * column marooned in the middle of empty page, the way installing
     * an Android app's layout onto a website would look. */
    --kw-app-width: 480px;
}

@media (min-width: 640px) {
    :root { --kw-app-width: 720px; }
}

@media (min-width: 1024px) {
    :root { --kw-app-width: 960px; }
}

/* A wide enough desktop window stops being "a phone screen that grew" and
 * gets an actual desktop pattern: the bottom tab bar (a mobile-only
 * convention - no real desktop web app floats a nav bar over the bottom
 * of the content) becomes a fixed left sidebar instead, and the content
 * column shifts to sit beside it rather than centered under it. 1280px,
 * not 1024px - narrower than that and a 240px sidebar plus a readable
 * content column doesn't comfortably both fit, so medium/tablet widths
 * keep the bottom bar from the step above rather than a cramped sidebar. */
@media (min-width: 1280px) {
    :root {
        /* Not a real cap at any common desktop size - 1680px is wider
         * than the content column ever gets on anything up to a 1920px
         * display with the sidebar subtracted, so #app just fills the
         * remaining width. It exists purely as a ceiling for ultra-wide
         * monitors, so .kw-dashboard's fixed 2-column layout doesn't
         * stretch into two ~1600px-wide form cards on a 3440px screen.
         * (900px was the previous value here - that's what was leaving
         * the app looking like a narrow column with grey either side
         * instead of filling the screen on an ordinary laptop display.) */
        --kw-app-width: 1680px;
        --kw-sidebar-width: 240px;
    }
}

* {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    background: var(--kw-bg);
    color: var(--kw-text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    /* Removes Android Chrome's default grey flash on every tap - every
     * pressed/active state in this file is hand-built (button scale,
     * card lift, chip color), so the browser's own tap feedback on top
     * of that just looks like a glitch, not an extra affordance. */
    -webkit-tap-highlight-color: transparent;
}

::selection {
    background: var(--kw-amber-tint);
    color: var(--kw-ink);
}

/* Motion is felt, not decorative - every transition/animation in this
 * file exists to make a state change easier to track (a card lifting on
 * hover, a view fading in), never as a flourish. Turning it off for
 * anyone who's asked for less motion costs nothing functionally. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

#app {
    max-width: var(--kw-app-width);
    margin: 0 auto;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--kw-white);
    box-shadow: var(--kw-shadow-lg);
}

@media (min-width: 1280px) {
    /* Sits beside the sidebar, not centered under it - centering would
     * put the sidebar and the content column fighting over the same
     * middle-of-viewport space instead of sitting cleanly side by side. */
    #app {
        margin: 0 0 0 var(--kw-sidebar-width);
    }
}

header.kw-topbar {
    /* Translucent rather than a flat fill, with a blur behind it - the
     * "frosted glass" navigation bar is the single most recognizable
     * iOS/macOS chrome pattern (Safari's own toolbar, every UINavigationBar).
     * backdrop-filter degrades gracefully: browsers that don't support it
     * just see the ~92%-opaque gradient underneath, which reads almost
     * identically to the flat fill this replaces. */
    background: linear-gradient(135deg, rgba(7, 29, 73, 0.92) 0%, rgba(18, 41, 107, 0.92) 100%);
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    color: var(--kw-white);
    /* Top gets the notch/status-bar allowance (0 on anything without
     * one - env() just resolves to 0), so an installed iOS PWA's navy
     * header paints all the way to the top edge instead of stopping at
     * a plain Safari status bar. See apple-mobile-web-app-status-bar-style
     * in app.blade.php's <head>, which is what makes that safe area
     * ours to fill instead of Safari's. */
    padding: calc(16px + env(safe-area-inset-top)) 18px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    z-index: 10;
    box-shadow: var(--kw-shadow-md);
}

header.kw-topbar .kw-brand {
    display: flex;
    align-items: center;
    gap: 9px;
    font-weight: 700;
    font-size: 1.1rem;
    letter-spacing: 0.01em;
}

/* Small circular "K" monogram before the wordmark - purely CSS, no new
 * markup and no image asset, so it's free wherever .kw-brand already
 * appears (the auth screen's topbar and the signed-in one both reuse
 * the same span). Gives the header an actual mark instead of just text
 * on a color. */
header.kw-topbar .kw-brand::before {
    content: "K";
    display: flex;
    align-items: center;
    justify-content: center;
    width: 27px;
    height: 27px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--kw-amber);
    color: var(--kw-ink);
    font-size: 0.85rem;
    font-weight: 800;
}

header.kw-topbar button {
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.28);
    color: var(--kw-white);
    padding: 7px 12px;
    border-radius: var(--kw-radius-sm);
    font-size: 0.8rem;
    width: auto;
    margin-top: 0;
    box-shadow: none;
    transition: background 0.15s var(--kw-ease);
}

header.kw-topbar button:hover {
    background: rgba(255, 255, 255, 0.18);
}

main {
    flex: 1;
    padding: 16px;
    padding-bottom: 90px;
}

@media (min-width: 1280px) {
    /* No fixed bottom bar to clear once .kw-tabbar becomes a sidebar. */
    main {
        padding-bottom: 24px;
    }
}

/* The signed-in app's screens (search results, booking lists) earn the
 * width #app grows to - a login form doesn't, and a "Sign in" card just
 * left anchored at the top of an otherwise-blank page (the previous
 * behaviour here) read as unfinished rather than deliberate: one side
 * empty, nothing to look at while your eye searches for the form.
 *
 * Two changes, together: the card now floats truly centered - both
 * axes, not just horizontally - inside a soft brand-tinted backdrop
 * instead of flat page background, and it carries real elevation
 * (shadow-lg, no hard border) so it reads as a raised sheet rather than
 * a bordered box sitting on the page. This is the same pattern iOS/macOS
 * use for their own sign-in surfaces (Sign in with Apple, System
 * Settings' own auth sheets): a shallow gradient field with one clearly
 * elevated card on top, never a flat white void around a bordered form. */
.kw-auth-screen {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background:
        radial-gradient(circle at 12% 18%, rgba(197, 155, 39, 0.16), transparent 42%),
        radial-gradient(circle at 88% 82%, rgba(7, 29, 73, 0.14), transparent 46%),
        var(--kw-bg);
}

.kw-auth-screen main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    /* No fixed bottom tab bar on the auth screen to clear, unlike the
     * base `main` rule's 90px allowance for the signed-in app. */
    padding-bottom: 16px;
}

.kw-auth-screen .kw-card {
    width: 100%;
    max-width: 440px;
    border: none;
    box-shadow: var(--kw-shadow-lg);
}

/* .kw-link is width:auto/inline-flex everywhere else on purpose (a "<-
 * Back" link, "View earnings" - short text that shouldn't force its own
 * full-width row). On the auth screen specifically that let "Forgot
 * password?" and "New here? Create an account" run onto the same line
 * whenever the card was wide enough to fit both (exactly the 440px this
 * card sits at) - two distinct actions reading as one sentence. Forcing
 * each onto its own centered line here removes the ambiguity without
 * touching how .kw-link behaves anywhere else in the app. */
.kw-auth-screen .kw-card button.kw-link {
    display: flex;
    width: 100%;
    justify-content: center;
    text-align: center;
}

/* Each screen's root element is a direct child of <main> (every x-if
 * block wraps its content in exactly one <div>, or renders a .kw-card
 * directly on the auth screen) - Alpine's x-if only removes/reinserts
 * that element when the boolean itself flips, not on every reactive
 * update inside it, so this animation plays once per view switch and
 * never mid-typing. A small, cheap way to stop screen changes feeling
 * like a hard cut. */
@keyframes kw-view-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

main > div {
    animation: kw-view-in 0.22s var(--kw-ease);
}

.kw-card {
    background: var(--kw-white);
    border: 1px solid var(--kw-border);
    border-radius: var(--kw-radius);
    padding: 18px;
    margin-bottom: 14px;
    box-shadow: var(--kw-shadow-sm);
    transition: box-shadow 0.15s var(--kw-ease), transform 0.15s var(--kw-ease), border-color 0.15s var(--kw-ease);
}

/* Opt-in hover lift for cards that are themselves a tap target (the
 * bookings list row, the activity feed row) - a card that merely
 * contains a button (a search result, a settings card) shouldn't look
 * clickable everywhere you touch it, only the button should. */
.kw-card-clickable:hover,
.kw-activity-item:hover {
    box-shadow: var(--kw-shadow-md);
    transform: translateY(-1px);
    border-color: var(--kw-gray-300);
}

.kw-card-clickable,
.kw-activity-item {
    cursor: pointer;
}

h1, h2, h3 {
    margin: 0 0 8px;
    color: var(--kw-ink);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
}

/* Fluid sizing (clamp, tied to viewport width) instead of one fixed size
 * per breakpoint - headings grow smoothly from phone to desktop rather
 * than jumping at 1280px, and it means the desktop-overhaul block below
 * no longer needs its own h1/h2/h3 override to look right at that width. */
h1 { font-size: clamp(1.4rem, 1.15rem + 1vw, 1.9rem); }
h2 { font-size: clamp(1.1rem, 1rem + 0.4vw, 1.35rem); }
h3 { font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.05rem); font-weight: 600; letter-spacing: 0; }

p { margin: 4px 0; line-height: 1.5; }

label {
    display: block;
    font-size: 0.76rem;
    font-weight: 600;
    color: var(--kw-gray-500);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin: 12px 0 5px;
}

input, select, textarea {
    width: 100%;
    padding: 11px 13px;
    border: 1.5px solid var(--kw-border);
    border-radius: var(--kw-radius-sm);
    font-size: 0.95rem;
    background: var(--kw-white);
    color: var(--kw-text);
    transition: border-color 0.15s var(--kw-ease), box-shadow 0.15s var(--kw-ease);
}

input::placeholder, textarea::placeholder {
    color: var(--kw-gray-400);
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--kw-amber);
    box-shadow: 0 0 0 3px var(--kw-amber-tint);
}

input:disabled {
    background: var(--kw-gray-50);
    color: var(--kw-gray-500);
}

textarea {
    resize: vertical;
    min-height: 76px;
}

/* Every password field (login, register, forgot-password, change-password)
 * was a plain secureTextEntry-style input with no way to check what you'd
 * typed before it got hashed. */
.kw-password-field {
    position: relative;
}

.kw-password-field input {
    padding-right: 42px;
}

.kw-password-toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--kw-gray-500);
}

.kw-password-toggle svg {
    width: 19px;
    height: 19px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Native file inputs (profile photo, ID document, business docs) used to
 * render as whatever the OS defaults to - visibly out of step with the
 * rest of the form. ::file-selector-button re-skins just the button part
 * with zero markup change and zero JS (hidden-input-plus-label tricks
 * aren't needed for a purely cosmetic pass like this one). */
input[type="file"] {
    padding: 8px;
    font-size: 0.85rem;
    color: var(--kw-gray-500);
}

input[type="file"]::file-selector-button {
    margin-right: 10px;
    padding: 8px 14px;
    border: none;
    border-radius: var(--kw-radius-sm);
    background: var(--kw-ink-tint);
    color: var(--kw-ink);
    font-weight: 600;
    font-size: 0.82rem;
    cursor: pointer;
    transition: background 0.15s var(--kw-ease);
}

input[type="file"]::file-selector-button:hover {
    background: var(--kw-gray-200);
}

button, .kw-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: none;
    border-radius: var(--kw-radius-sm);
    padding: 12px 18px;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    background: var(--kw-amber);
    color: var(--kw-white);
    width: 100%;
    margin-top: 10px;
    text-decoration: none;
    box-shadow: var(--kw-shadow-sm);
    transition: background 0.15s var(--kw-ease), box-shadow 0.15s var(--kw-ease), transform 0.05s var(--kw-ease);
}

button:hover { background: var(--kw-amber-dark); }
button:active { background: var(--kw-amber-dark); transform: scale(0.98); }
button:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; transform: none; }

button:focus-visible,
.kw-btn:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.kw-heart:focus-visible,
.kw-star:focus-visible,
.kw-switch:focus-visible {
    outline: 2px solid var(--kw-ink);
    outline-offset: 2px;
}

button.kw-secondary {
    background: var(--kw-white);
    color: var(--kw-ink);
    border: 1.5px solid var(--kw-border);
    box-shadow: none;
}

button.kw-secondary:hover {
    background: var(--kw-gray-50);
    border-color: var(--kw-gray-300);
}

button.kw-danger {
    background: var(--kw-red);
}

button.kw-danger:hover {
    background: #b91c1c;
}

button.kw-ghost {
    background: transparent;
    color: var(--kw-amber);
    width: auto;
    padding: 6px 8px;
    margin-top: 0;
    box-shadow: none;
}

button.kw-ghost:hover {
    background: var(--kw-amber-tint);
}

.kw-tabbar {
    position: fixed;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    max-width: var(--kw-app-width);
    /* Same frosted-glass treatment as the topbar - an iOS tab bar has
     * always been translucent (content visibly scrolls up underneath
     * it), never a flat opaque strip. */
    background: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    border-top: 1px solid var(--kw-border);
    box-shadow: 0 -4px 16px rgba(7, 29, 73, 0.06);
    display: flex;
    padding: 8px 4px calc(8px + env(safe-area-inset-bottom));
    z-index: 10;
}

.kw-tabbar button {
    flex: 1;
    background: none;
    color: var(--kw-gray-500);
    font-size: 0.7rem;
    font-weight: 600;
    padding: 6px 2px;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    border-radius: var(--kw-radius-sm);
    box-shadow: none;
    transition: color 0.15s var(--kw-ease);
}

.kw-tabbar button:active {
    transform: none;
    background: var(--kw-ink-tint);
}

.kw-tabbar svg {
    width: 22px;
    height: 22px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.kw-tabbar button.active {
    color: var(--kw-amber);
}

/* Wraps just the <svg> inside a tab button so the badge can anchor to the
 * icon itself (top-right corner) rather than the whole button - matches
 * the mobile app's tabBarBadge, which sits on the icon the same way. */
.kw-tab-icon { position: relative; display: inline-flex; }
.kw-tab-badge {
    position: absolute;
    top: -4px;
    right: -8px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--kw-red-tint, #fee2e2);
    color: #991b1b;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* Comes after the plain .kw-tabbar button.active rule above on purpose -
 * both match with identical specificity, and the sidebar's filled amber
 * background (with white text) needs to win over the bottom-bar's
 * amber-on-white text-only active state, which only a later source
 * position (not the media query itself) guarantees. Learned the hard
 * way: this block used to sit above that rule and the active button's
 * label rendered amber-on-amber, invisible. */
@media (min-width: 1280px) {
    .kw-tabbar {
        top: 0;
        bottom: 0;
        left: 0;
        transform: none;
        width: var(--kw-sidebar-width);
        max-width: var(--kw-sidebar-width);
        height: 100vh;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: 4px;
        padding: 28px 14px;
        border-top: none;
        border-right: 1px solid var(--kw-border);
        box-shadow: none;
        /* macOS sidebars (Finder, Mail, Notes) use exactly this
         * translucent-vibrancy treatment, not a flat fill - matches the
         * mobile tab bar's frosted glass above for the same reason. */
        background: rgba(255, 255, 255, 0.82);
        backdrop-filter: blur(24px) saturate(160%);
        -webkit-backdrop-filter: blur(24px) saturate(160%);
    }

    .kw-tabbar::before {
        /* The topbar carries the "Kwamua" wordmark inside #app, which
         * now sits to the right of the sidebar, not above it - without
         * something here the sidebar has no identity of its own at the
         * one moment (page load) it's visible before any nav item is. */
        content: "Kwamua";
        display: block;
        font-weight: 700;
        font-size: 1.05rem;
        color: var(--kw-ink);
        padding: 0 10px 20px;
    }

    .kw-tabbar button {
        flex: none;
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
        gap: 12px;
        font-size: 0.88rem;
        padding: 10px 14px;
        border-radius: var(--kw-radius-sm);
        text-align: left;
    }

    .kw-tabbar svg {
        width: 19px;
        height: 19px;
    }

    .kw-tabbar button:hover {
        background: var(--kw-ink-tint);
    }

    .kw-tabbar button.active {
        background: var(--kw-amber);
        color: var(--kw-white);
        box-shadow: var(--kw-shadow-sm);
    }
}

.kw-badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.kw-badge.pending, .kw-badge.requested { background: #fef3c7; color: #92400e; }
.kw-badge.verified, .kw-badge.accepted, .kw-badge.active, .kw-badge.completed { background: var(--kw-green-tint); color: #166534; }
.kw-badge.rejected, .kw-badge.cancelled, .kw-badge.failed, .kw-badge.inactive { background: var(--kw-red-tint); color: #991b1b; }
.kw-badge.grace, .kw-badge.en_route, .kw-badge.in_progress { background: #dbeafe; color: #1e40af; }

.kw-error, .kw-success {
    padding: 12px 14px;
    border-radius: var(--kw-radius-sm);
    font-size: 0.85rem;
    margin-bottom: 12px;
    border-left: 3px solid;
}

.kw-error {
    background: var(--kw-red-tint);
    color: #991b1b;
    border-color: var(--kw-red);
}

.kw-success {
    background: var(--kw-green-tint);
    color: #166534;
    border-color: var(--kw-green);
}

/* Sort chips (nearby search) */
.kw-sort-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 0 14px;
    flex-wrap: wrap;
}

.kw-chip {
    width: auto;
    margin: 0;
    padding: 6px 13px;
    font-size: 0.78rem;
    font-weight: 600;
    background: var(--kw-white);
    color: var(--kw-gray-500);
    border: 1.5px solid var(--kw-border);
    border-radius: 999px;
    box-shadow: none;
    transition: background 0.15s var(--kw-ease), color 0.15s var(--kw-ease), border-color 0.15s var(--kw-ease);
}

.kw-chip:hover {
    border-color: var(--kw-gray-300);
}

.kw-chip.active {
    background: var(--kw-ink);
    color: var(--kw-white);
    border-color: var(--kw-ink);
}

/* Favorite heart toggle (nearby results, saved providers, provider profile) */
.kw-heart {
    width: auto;
    margin: 0;
    background: none;
    color: var(--kw-gray-300);
    font-size: 1.3rem;
    padding: 0 2px;
    line-height: 1;
    box-shadow: none;
    transition: color 0.15s var(--kw-ease), transform 0.15s var(--kw-ease);
}

.kw-heart:active {
    transform: scale(1.15);
}

.kw-heart.filled {
    color: var(--kw-red);
}

/* Provider name as a tap target that isn't a full-width button - reads
 * as a clickable heading (opens the provider's profile), not another
 * <button> stacked in the card's action area. */
.kw-link-text {
    cursor: pointer;
    text-decoration: underline;
    text-decoration-color: var(--kw-border);
    text-underline-offset: 3px;
    transition: text-decoration-color 0.15s var(--kw-ease);
}

.kw-link-text:hover {
    text-decoration-color: var(--kw-amber);
}

.kw-avatar-preview {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    margin: 8px 0;
    display: block;
    box-shadow: var(--kw-shadow-sm);
    border: 2px solid var(--kw-white);
    outline: 1px solid var(--kw-border);
}

.kw-earnings-row {
    display: flex;
    justify-content: space-around;
    text-align: center;
}

.kw-earnings-row h3 {
    color: var(--kw-amber-dark);
    font-size: clamp(1.05rem, 1rem + 0.4vw, 1.3rem);
}

.kw-empty {
    text-align: center;
    color: var(--kw-gray-400);
    padding: 48px 20px;
    font-size: 0.9rem;
    border: 1.5px dashed var(--kw-border);
    border-radius: var(--kw-radius);
    background: var(--kw-gray-50);
}

.kw-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
}

.kw-muted {
    color: var(--kw-gray-500);
    font-size: 0.85rem;
}

.kw-star {
    font-size: 1.4rem;
    cursor: pointer;
    color: var(--kw-gray-300);
    transition: color 0.15s var(--kw-ease), transform 0.1s var(--kw-ease);
}

.kw-star:active {
    transform: scale(1.15);
}

.kw-star.filled {
    color: var(--kw-amber);
}

.kw-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
}

.kw-switch {
    width: 46px;
    height: 26px;
    border-radius: 999px;
    background: var(--kw-gray-300);
    position: relative;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.2s var(--kw-ease);
}

.kw-switch.on {
    /* iOS's actual UISwitch green, not the semantic --kw-green used for
     * badges elsewhere - this toggle is deliberately styled to read as
     * a native switch, not a status indicator. */
    background: #34c759;
}

.kw-switch::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--kw-white);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    transition: left 0.2s var(--kw-ease);
}

.kw-switch.on::after {
    left: 23px;
}

.kw-link {
    color: var(--kw-amber);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.85rem;
    background: none;
    border: none;
    padding: 0;
    width: auto;
    margin-top: 8px;
    box-shadow: none;
}

.kw-link:hover {
    text-decoration: underline;
}

.kw-spinner {
    display: inline-block;
    width: 16px;
    height: 16px;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: var(--kw-white);
    border-radius: 50%;
    animation: kw-spin 0.7s linear infinite;
}

@keyframes kw-spin {
    to { transform: rotate(360deg); }
}

/* --- Chat --- */

.kw-chat-card {
    padding: 12px;
}

.kw-chat-messages {
    max-height: 320px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 4px 2px;
    margin-bottom: 8px;
}

.kw-chat-empty {
    text-align: center;
    padding: 16px 0;
}

.kw-chat-bubble {
    align-self: flex-start;
    max-width: 78%;
    background: var(--kw-gray-100);
    border-radius: 14px 14px 14px 4px;
    padding: 8px 12px;
    box-shadow: var(--kw-shadow-sm);
}

.kw-chat-bubble.mine {
    align-self: flex-end;
    background: var(--kw-amber);
    color: var(--kw-white);
    border-radius: 14px 14px 4px 14px;
}

.kw-chat-bubble p {
    margin: 0;
    font-size: 0.9rem;
    white-space: pre-wrap;
    word-break: break-word;
}

.kw-chat-meta {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    margin-top: 3px;
    font-size: 0.68rem;
    opacity: 0.75;
}

.kw-chat-tick {
    letter-spacing: -2px;
}

.kw-chat-tick.read {
    color: #60a5fa; /* WhatsApp-style blue double-tick for "read" */
}

.kw-chat-input-row {
    display: flex;
    gap: 8px;
    align-items: center;
}

.kw-chat-input-row input {
    flex: 1;
    margin: 0;
}

.kw-chat-send {
    width: auto;
    margin: 0;
    padding: 10px 16px;
}

.kw-chat-typing {
    margin: 0 0 6px;
    font-size: 0.75rem;
    font-style: italic;
    color: var(--kw-amber);
}

.kw-chat-hint {
    margin: 8px 0 0;
    font-size: 0.72rem;
}

.kw-unlock-card {
    border-color: var(--kw-amber);
    background: var(--kw-amber-tint);
}

/* =====================================================================
 * TABLET (>=768px, below the 1280px sidebar threshold)
 * ---------------------------------------------------------------------
 * iPad portrait/landscape and small laptop windows land here. Below
 * this, the phone layout is still correct - there's no room for two
 * columns on a real phone. At 1280px+, the desktop block further down
 * takes over: it sets these same properties to more generous values,
 * and because it comes later in the file it correctly wins that tie on
 * every property both blocks touch (same lesson as the sidebar
 * active-state fix earlier in this file - equal specificity, so source
 * order decides, not which media query is "more specific").
 *
 * This exists because tablets don't get the sidebar - they keep the
 * bottom tab bar all the way up to 1280px - so without this, an iPad
 * was landing in exactly the pre-desktop-overhaul trap: a single
 * stretched column of ~700-900px-wide cards and giant near-empty form
 * inputs, on a screen with plenty of width to spare.
 * ===================================================================== */
@media (min-width: 768px) {
    main {
        padding-left: 24px;
        padding-right: 24px;
    }

    .kw-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
        gap: 14px;
        align-items: start;
    }

    .kw-grid .kw-card {
        margin-bottom: 0;
    }

    .kw-list {
        max-width: 640px;
    }

    .kw-dashboard {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
        gap: 14px;
        align-items: start;
    }

    .kw-dashboard .kw-card {
        margin-bottom: 0;
    }

    .kw-dashboard-wide {
        grid-column: 1 / -1;
    }
}

/* =====================================================================
 * DESKTOP OVERHAUL (>=1280px)
 * ---------------------------------------------------------------------
 * Deliberately one consolidated block at the very end of the file, not
 * scattered next to each rule it touches - every rule here has already
 * been fought over once before in this file (see the "amber text on
 * amber background" bug from the sidebar work above) purely because a
 * media query sat *above* the plain rule it needed to beat in the
 * cascade. Appending everything after every other rule in the file
 * guarantees these always win on equal specificity, without having to
 * reason about it individually per rule.
 *
 * The goal: stop this being "the phone layout, just wider." Real
 * desktop web apps don't stretch a single card to 900px, and they
 * don't make every button span the full content width - they use the
 * horizontal space for an actual multi-column layout, and buttons stay
 * sized to their own label. (Heading sizes no longer need overriding
 * here - h1/h2/h3 use clamp() in the base rules above and already scale
 * correctly at this width.)
 * ===================================================================== */
@media (min-width: 1280px) {
    /* More breathing room than the 16px mobile padding - a dense phone
     * layout read as cramped once the column itself got wider. */
    main {
        padding-left: 32px;
        padding-right: 32px;
    }

    /* Buttons default to their label's width, not the full column -
     * the single biggest tell of "mobile app stretched wide." Explicit
     * opt-outs below for the handful that should stay full-width
     * (a lone primary CTA card, a search action spanning its own
     * search-bar-width card - normal on desktop too, just not by
     * default for every button everywhere). */
    button, .kw-btn {
        width: auto;
    }

    .kw-auth-screen button,
    .kw-tabbar button,
    .kw-heart,
    .kw-link,
    .kw-ghost {
        width: auto;
    }

    /* A collection of same-shaped cards a person picks *one* of
     * (nearby results, saved providers, bookings to open, reviews to
     * read) becomes an actual grid, not one per row down a narrow
     * column - this is the other half of "stop looking like a phone
     * app." minmax(280px, 1fr) rather than a fixed column count: the
     * number of columns should follow the window's width, not a
     * guess at a "typical" desktop size. */
    .kw-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
        gap: 16px;
        align-items: start;
    }

    .kw-grid .kw-card {
        margin-bottom: 0;
    }

    .kw-grid .kw-card button {
        width: 100%;
    }

    /* .kw-list's max-width is set once, in the TABLET block above -
     * 640px is already correct from 768px all the way through desktop,
     * so there's nothing left to override at this breakpoint. */

    /* Settings-style screens (provider home, account/profile) become a
     * real multi-column dashboard instead of five cards stacked one
     * under another - this is what actually reads as "desktop app,"
     * not just "the same list, wider." auto-fit/minmax rather than a
     * fixed 2 columns for the same reason .kw-grid uses it: now that
     * #app fills the screen instead of stopping at 900px, a hard
     * 2-column split would stretch a "National ID number" input to
     * ~800px wide on an ordinary laptop - letting columns multiply
     * instead keeps each card a sane width and uses the freed space
     * for more of them per row. */
    .kw-dashboard {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
        gap: 16px;
        align-items: start;
    }

    .kw-dashboard .kw-card {
        margin-bottom: 0;
    }

    .kw-dashboard-wide {
        grid-column: 1 / -1;
    }

    .kw-profile-actions {
        display: flex;
        gap: 12px;
        margin-top: 4px;
    }

    .kw-profile-actions button {
        width: auto;
    }

    /* The search/location button and "Send request" stay a deliberate
     * full-width primary action - they're the one thing that card/form
     * exists to do, and a search bar's own action button spanning its
     * own width is normal desktop UI (a Google search button is
     * exactly as wide as the search bar above it, not label-sized). */
    #app .kw-card > button:first-of-type[\@click*="searchNearby"],
    #app .kw-card > button[\@click*="submitBooking"] {
        width: 100%;
    }
}
