/*
 * NeevServe theme entry point (NS-701/NS-208, docs/engineering/ui-standards.md).
 *
 * Narrowly scoped overrides on top of vendored Tabler
 * (static/ui/vendor/tabler/1.4.0/), using the tokens in tokens.css --
 * never a parallel styling system. Loaded on every page via
 * fragments/head-assets.html, so this file is reserved for genuinely
 * global rules and the shared authenticated shell's own chrome
 * (templates/layout/authenticated.html) -- every authenticated page
 * uses that shell, so its CSS belongs here, not duplicated per page.
 *
 * login.html and select-tenant.html do NOT use the shared shell (there
 * is no "current tenant" context yet at either point) and load their
 * own additional, narrowly scoped stylesheet on top of this one --
 * see login.css/tenant-selection.css in this same directory.
 *
 * Ported from the approved NS-902 application-shell mock
 * (mocks/screens/application-shell/application-shell.html) -- layout/
 * chrome rules only. That mock's own illustrative dashboard content
 * (stat cards, activity feed, quick-setup panel) is NOT reproduced
 * here: NS-208's scope is the shared shell "sufficient for later
 * dashboards," not the dashboard content itself, which is each real
 * screen's own NS-9xx ticket.
 */

:focus-visible {
    outline: 3px solid rgba(37, 99, 235, .28);
    outline-offset: 2px;
}

.navbar-brand {
    font-weight: 700;
}

button:disabled {
    cursor: not-allowed;
}

/*
 * Shared "action in flight" loading state -- see
 * layout/authenticated.html's own PsLoadingState script for how every
 * form submit (button click or the shared confirm dialog's own OK
 * button) opts into this automatically, no per-page wiring needed.
 * .ps-btn-spinner reuses Tabler's own already-vendored .spinner-border/
 * .spinner-border-sm component (inherits currentColor, so it already
 * matches whatever text color each button has) -- only the spacing
 * around it is this app's own.
 */
.ps-btn-loading {
    opacity: .75;
}

.ps-btn-spinner {
    margin-right: 6px;
    vertical-align: -2px;
}

/* ---------------------------------------------------------------------
   Shared authenticated shell (NS-902): sidebar + topbar + mobile bar.
   --------------------------------------------------------------------- */

html, body {
    font-family: var(--ps-font-family);
}

button, select, input {
    font: inherit;
}

.ps-app {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 256px minmax(0, 1fr);
}

.ps-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: 256px;
    background: linear-gradient(180deg, var(--ps-nav-bg) 0%, var(--ps-nav-bg-end) 100%);
    color: var(--ps-nav-active);
    padding: 22px 16px;
    display: flex;
    flex-direction: column;
    z-index: 30;
}

.ps-brand {
    height: 42px;
    display: flex;
    align-items: center;
    padding: 0 10px 17px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
    margin-bottom: 18px;
}

.ps-brand-full {
    width: 156px;
    max-height: 37px;
    object-fit: contain;
    object-position: left center;
}

.ps-brand-icon, .ps-mobile-brand {
    display: none;
}

/*
   PingSorted-Icon.svg's own bubble shape is intentionally navy
   (#183153, its own <desc> says so) -- correct for a light background,
   but this asset only ever appears here, inside the navy sidebar
   itself (the collapsed tablet rail): without a light backing behind
   it, the bubble is the exact same colour as the surface it sits on
   and disappears, leaving only its white dots and teal check floating
   with no visible container (reported live, screenshot-confirmed --
   iPhone 13 Pro Chrome). No on-dark variant of this icon exists in
   the vendored brand assets (only the full wordmark has one,
   Logo-OnDark.svg vs Logo-Horizontal.svg) and generating a new image
   asset needs the project's own approval workflow first -- a light
   backing chip fixes the contrast with a CSS-only change, no new
   asset.
 */
.ps-brand-icon {
    background: #fff;
    border-radius: 8px;
    padding: 3px;
    box-sizing: border-box;
}

.ps-nav-label {
    padding: 12px 12px 7px;
    color: var(--ps-nav-muted);
    font-size: 11px;
    font-weight: 750;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.ps-nav {
    display: grid;
    gap: 4px;
}

.ps-nav a {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 43px;
    padding: 10px 12px;
    border-radius: 9px;
    color: var(--ps-nav-text);
    text-decoration: none;
    font-size: 14px;
    font-weight: 550;
}

.ps-nav a:hover {
    background: rgba(255, 255, 255, .08);
    color: #fff;
}

.ps-nav a.active {
    background: var(--ps-nav-active-bg);
    color: var(--ps-nav-active);
}

.ps-nav a.active:before {
    content: "";
    position: absolute;
    left: 0;
    top: 9px;
    bottom: 9px;
    width: 3px;
    border-radius: 3px;
    background: var(--ps-nav-accent);
}

/*
   The mock's full illustrative menu, shown for visual parity, but
   nothing without a real route yet is clickable (review: "show all
   menu and keep them disabled") -- muted, no hover feedback, a small
   "Soon" badge so it reads as deliberately inert, not a broken link.
 */
.ps-nav-disabled {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 43px;
    padding: 10px 12px;
    border-radius: 9px;
    color: var(--ps-nav-muted);
    font-size: 14px;
    font-weight: 550;
    opacity: .6;
    cursor: default;
}

.ps-nav-soon {
    margin-left: auto;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ps-nav-muted);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 999px;
    padding: 2px 7px;
    white-space: nowrap;
}

.ps-nav svg {
    display: block;
    width: 20px !important;
    height: 20px !important;
    min-width: 20px;
    max-width: 20px;
    flex: 0 0 20px;
    stroke-width: 1.8;
}

/*
 * NS-521 (NS-930 mock, approved): the "Testing only" nav group -- its own
 * dashed purple box at the bottom of the sidebar, apart from the live
 * menu. Takes the free space above it, so the sidebar foot follows it.
 */
.ps-nav-testing {
    margin-top: auto;
    border: 1.5px dashed var(--ps-sim-nav-line);
    border-radius: 12px;
    padding: 10px 8px 8px;
    background: var(--ps-sim-nav-bg);
}

.ps-nav-testing + .ps-sidebar-foot {
    margin-top: 14px;
}

.ps-nav-testing-label {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 0 6px 4px;
    color: var(--ps-sim-nav-ink);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.ps-nav-testing-label .ico {
    width: 14px;
    height: 14px;
}

.ps-nav-testing a.active {
    background: var(--ps-sim-nav-active);
}

.ps-nav-testing a.active:before {
    background: var(--ps-sim-nav-ink);
}

.ps-nav-test-tag {
    margin-left: auto;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: 20px;
    background: var(--ps-sim-nav-ink);
    color: var(--ps-sim-ink);
}

.ps-nav-testing-note {
    margin: 4px 6px 0;
    font-size: 11px;
    line-height: 1.35;
    color: var(--ps-sim-nav-note);
}

.ps-sidebar-foot {
    margin-top: auto;
    border-top: 1px solid rgba(255, 255, 255, .12);
    padding: 14px 7px 0;
}

/*
 * NS-909 mock parity (review: "at the bottom we show Restaurant Name
 * but I can't see it in ours") -- the mock's own .location-chip/
 * .tenant-id, ps-* prefixed. Shows which tenant (and, where known,
 * which location) this session is currently looking at -- the same
 * information the topbar's own .ps-context already states, repeated
 * here because the sidebar stays visible while scrolled past the
 * topbar on a long page, and because it's what the approved mock
 * itself puts at the foot of the nav.
 */
.ps-tenant-chip {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 7px;
}

.ps-tenant-id {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    border-radius: 8px;
    background: var(--ps-nav-active-bg);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
}

.ps-tenant-chip b {
    display: block;
    font-size: 12px;
    color: #fff;
}

.ps-tenant-chip span {
    display: block;
    color: var(--ps-nav-muted);
    font-size: 10px;
    margin-top: 3px;
}

.ps-support {
    display: flex;
    gap: 10px;
    align-items: center;
    padding: 9px 7px;
    color: rgba(255, 255, 255, .76);
    font-size: 13px;
}

.ps-support-icon {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: rgba(255, 255, 255, .1);
    display: grid;
    place-items: center;
}

.ps-shell {
    grid-column: 2;
    min-width: 0;
}

.ps-topbar {
    height: 76px;
    background: rgba(255, 255, 255, .96);
    border-bottom: 1px solid var(--ps-border);
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 0 28px;
    position: sticky;
    top: 0;
    z-index: 20;
}

.ps-menu-btn {
    display: none;
    width: 42px;
    height: 42px;
    border: 1px solid var(--ps-border);
    border-radius: 9px;
    background: #fff;
    color: var(--ps-primary);
    place-items: center;
}

.ps-crumbs {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--ps-text-muted);
    white-space: nowrap;
}

.ps-crumbs strong {
    color: var(--ps-text);
}

.ps-contexts {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.ps-context {
    height: 44px;
    border: 1px solid var(--ps-border);
    background: #fff;
    border-radius: 9px;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 0 11px;
    color: var(--ps-text);
    min-width: 180px;
    cursor: pointer;
}

.ps-context:hover {
    border-color: #b9c8d5;
}

.ps-context .ps-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--ps-secondary);
    box-shadow: 0 0 0 3px rgba(21, 183, 158, .12);
}

.ps-context .ps-copy {
    min-width: 0;
    text-align: left;
    line-height: 1.1;
}

.ps-context small {
    display: block;
    color: var(--ps-text-muted);
    font-size: 10px;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .05em;
    margin-bottom: 4px;
}

.ps-context b {
    display: block;
    max-width: 135px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 13px;
}

/* NS-308 mock-parity Phase 9: the topbar's own location switcher -- .ps-location-switch-form sits inside .ps-context .ps-copy, so its select takes over where .ps-context b's own plain text would otherwise sit. */
.ps-location-switch-form {
    margin: 0;
}

.ps-location-switch-form select {
    border: 0;
    background: transparent;
    padding: 0;
    max-width: 135px;
    font-size: 13px;
    font-weight: 700;
    color: var(--ps-text);
    cursor: pointer;
}

.ps-location-switch-form select:focus-visible {
    outline: 2px solid var(--ps-primary);
    outline-offset: 2px;
}

/* NS-308 mock-parity Phase 9 review fix: the sidebar-foot's own copy of the switcher (see layout/authenticated.html's own comment on .ps-tenant-chip for why it needs one too) -- dark-background counterpart to .ps-location-switch-form select above, same light-on-dark treatment .ps-tenant-chip span already uses. */
.ps-location-switch-form-dark select {
    font-size: 10px;
    font-weight: inherit;
    color: var(--ps-nav-muted);
}

.ps-location-switch-form-dark select:focus-visible {
    outline-color: var(--ps-nav-accent);
}

/* NS-308 mock-parity Phase 9: the topbar's own inert notifications bell -- see layout/authenticated.html's own comment on why it's chrome-only. Light-topbar counterpart to .ps-nav-soon (dark sidebar). */
.ps-notifications-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 10px;
    cursor: not-allowed;
}

.ps-nav-soon-light {
    position: absolute;
    bottom: -6px;
    right: -6px;
    font-size: 8px;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #fff;
    background: var(--ps-text-muted);
    border-radius: 999px;
    padding: 1px 4px;
    white-space: nowrap;
}

.ps-chev {
    margin-left: auto;
    color: var(--ps-text-muted);
}

.ps-profile {
    display: flex;
    align-items: center;
    gap: 10px;
    border: 0;
    background: transparent;
    border-left: 1px solid var(--ps-border);
    padding: 0 0 0 17px;
    color: var(--ps-text);
}

.ps-avatar {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--ps-primary), #2d5a87);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 800;
}

.ps-profile-copy {
    text-align: left;
    line-height: 1.15;
}

.ps-profile-copy b {
    display: block;
    font-size: 13px;
}

.ps-profile-copy span {
    font-size: 11px;
    color: var(--ps-text-muted);
}

.ps-shell > main {
    padding: 30px 32px 44px;
    max-width: 1540px;
    margin: 0 auto;
}

.ps-mobile-context {
    display: none;
}

.ps-mobile-bar {
    display: none;
}

@media (max-width: 1080px) {
    .ps-app {
        grid-template-columns: 84px minmax(0, 1fr);
    }

    .ps-sidebar {
        width: 84px;
        padding-inline: 12px;
    }

    .ps-brand {
        padding: 0 5px 15px;
        justify-content: center;
    }

    .ps-brand-full {
        display: none;
    }

    .ps-brand-icon {
        display: block;
        width: 34px;
        height: 34px;
    }

    .ps-nav-label, .ps-nav span:not(.ps-badge), .ps-support-copy {
        display: none;
    }

    .ps-nav-testing {
        padding: 6px 4px;
    }

    .ps-nav-testing-label, .ps-nav-testing-note {
        display: none;
    }

    .ps-nav a {
        height: 44px;
        min-height: 44px;
        justify-content: center;
        padding: 12px;
    }

    .ps-nav a.active:before {
        left: -1px;
    }

    .ps-sidebar-foot {
        padding-inline: 0;
    }

    /*
     * Bug fix: the tenant chip's name/location text had no width
     * constraint of its own, and this collapsed 84px rail never hid it
     * the way .ps-nav-label above already does for nav items -- the
     * text overflowed the icon-only rail, squashing/distorting the
     * "TS" badge next to it. Collapses to just the centered badge here,
     * matching the nav items' own icon-only treatment at this width.
     */
    .ps-tenant-chip {
        justify-content: center;
        padding-inline: 0;
    }

    .ps-tenant-chip > div {
        display: none;
    }

    .ps-support {
        justify-content: center;
        padding-inline: 0;
    }

    .ps-shell {
        grid-column: 2;
    }

    .ps-topbar {
        padding: 0 20px;
    }

    .ps-crumbs {
        display: none;
    }

    .ps-context {
        min-width: 160px;
    }

    .ps-context b {
        max-width: 112px;
    }

    .ps-shell > main {
        padding: 28px 24px 40px;
    }
}

@media (max-width: 700px) {
    .ps-app {
        display: block;
    }

    .ps-sidebar {
        transform: translateX(-105%);
        width: 286px;
        box-shadow: 20px 0 45px rgba(10, 28, 48, .24);
        transition: transform .2s ease;
    }

    .ps-app.ps-sidebar-open .ps-sidebar {
        transform: translateX(0);
    }

    /*
       This off-canvas drawer is 286px wide -- roomier than the
       desktop sidebar (256px) it's standing in for -- so it shows the
       full wordmark, not the icon-only mark the narrower 84px tablet
       rail needs. Without this, the max-width:1080px rule above
       (which also applies here, mobile widths being <1080px too)
       keeps showing the cramped icon-only mark in a drawer with
       plenty of room for the real logo (reported live, screenshot-
       confirmed -- "look at icon of PingSorted").
     */
    .ps-brand-full {
        display: block;
        width: 156px;
    }

    .ps-brand-icon {
        display: none;
    }

    .ps-app.ps-sidebar-open:after {
        content: "";
        position: fixed;
        inset: 0;
        background: rgba(10, 28, 48, .35);
        z-index: 29;
    }

    .ps-shell {
        display: block;
    }

    .ps-topbar {
        height: 64px;
        padding: 0 15px;
        gap: 10px;
    }

    .ps-menu-btn {
        display: grid;
    }

    .ps-mobile-brand {
        display: block;
        width: 106px;
        height: 30px;
        object-fit: contain;
        object-position: left center;
    }

    .ps-contexts, .ps-profile-copy {
        display: none;
    }

    .ps-profile {
        border-left: 0;
        padding-left: 0;
    }

    .ps-profile .ps-chev {
        display: none;
    }

    .ps-avatar {
        width: 36px;
        height: 36px;
    }

    .ps-shell > main {
        padding: 18px 15px 90px;
    }

    .ps-mobile-context {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        margin-bottom: 17px;
    }

    .ps-mobile-context .ps-context {
        min-width: 0;
        height: 52px;
        padding: 0 9px;
    }

    .ps-mobile-context .ps-context b {
        max-width: 108px;
    }

    .ps-mobile-bar {
        display: grid;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        height: 68px;
        background: #fff;
        border-top: 1px solid var(--ps-border);
        grid-template-columns: repeat(4, 1fr);
        z-index: 25;
        padding-bottom: env(safe-area-inset-bottom);
    }

    .ps-mobile-bar a {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        text-decoration: none;
        color: var(--ps-text-muted);
        font-size: 10px;
        font-weight: 650;
    }

    .ps-mobile-bar a svg {
        display: block;
        width: 20px;
        height: 20px;
        flex: 0 0 20px;
    }

    .ps-mobile-bar a.active {
        color: var(--ps-primary);
    }

    .ps-mobile-bar a.active svg {
        color: var(--ps-secondary);
    }

    /*
     * NS-308 review fix (mobile bug: overlapping bottom nav, capped to
     * 4 slots -- see AuthenticatedShellAttributes#populateMobileNavAttributes's
     * own Javadoc): the 4th-slot "More" trigger, styled to match the
     * bottom-tab items above it rather than .ps-menu-btn's own topbar
     * square-icon-button look (width:42px/border/background), which
     * this selector overrides.
     */
    .ps-mobile-bar .ps-menu-btn {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        width: auto;
        height: auto;
        border: 0;
        border-radius: 0;
        background: none;
        color: var(--ps-text-muted);
        font-size: 10px;
        font-weight: 650;
    }

    .ps-mobile-bar .ps-menu-btn svg {
        display: block;
        width: 20px;
        height: 20px;
        flex: 0 0 20px;
    }

    .ps-mobile-bar .ps-menu-btn[aria-expanded="true"] {
        color: var(--ps-primary);
    }

    .ps-mobile-bar .ps-menu-btn[aria-expanded="true"] svg {
        color: var(--ps-secondary);
    }
}

/*
 * NS-704 review fix: the off-canvas sidebar's own slide-in (.ps-sidebar's
 * transition: transform above) had no prefers-reduced-motion guard --
 * the only animated UI in the shared shell that didn't, unlike
 * tenant-catalogue.css's own ps-avail-row-highlighted fade. The open/
 * closed state itself (transform: translateX) is still fully functional
 * here, only the animated slide between the two states is removed.
 */
@media (prefers-reduced-motion: reduce) {
    .ps-sidebar {
        transition: none;
    }
}

/*
 * Shared confirmation dialog (NS-308 review fix: "confirm() everywhere
 * a mock wants a styled popover"). One <dialog> lives once in
 * layout/authenticated.html and is reused by every destructive/
 * consequential action across every authenticated page -- see that
 * file's own script for the trigger contract (data-confirm-title/
 * -message/-label/-variant on a <button type="button"> inside the
 * form it should submit).
 *
 * NS-308 review fix: browsers hide a <dialog> without an [open]
 * attribute via their own UA stylesheet, so this was never explicitly
 * declared here -- confirmed on a real device that a browser without
 * full <dialog> support (or a buggy WebKit build) can render it as
 * plain visible block content instead, sitting at the bottom of every
 * page since that's where the element sits in the DOM. This rule is
 * the CSS half of the fix; the script's own feature-detected fallback
 * (see authenticated.html) is the other half, for browsers that reach
 * this state without even rendering [open] correctly.
 */
dialog:not([open]) {
    display: none;
}

.ps-confirm-dialog {
    border: 1px solid var(--ps-border);
    border-radius: var(--ps-radius);
    box-shadow: 0 20px 48px rgba(24, 49, 83, .18);
    padding: 0;
    width: min(420px, calc(100vw - 32px));
    color: var(--ps-text);
}

.ps-confirm-dialog::backdrop {
    background: rgba(16, 38, 64, .45);
}

.ps-confirm-dialog-body {
    padding: 22px 24px;
}

.ps-confirm-dialog-body h2 {
    margin: 0 0 8px;
    font-size: 16px;
    color: var(--ps-text);
}

.ps-confirm-dialog-body p {
    margin: 0;
    font-size: 13px;
    color: var(--ps-text-muted);
    line-height: 1.55;
}

.ps-confirm-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 14px 24px;
    border-top: 1px solid var(--ps-border);
    background: var(--ps-canvas);
    border-radius: 0 0 var(--ps-radius) var(--ps-radius);
}

.ps-confirm-btn {
    height: 38px;
    border-radius: 8px;
    padding: 0 16px;
    font-weight: 650;
    font-size: 13px;
    cursor: pointer;
    border: 1px solid var(--ps-border);
    background: #fff;
    color: var(--ps-text);
}

.ps-confirm-btn-ok {
    border: 0;
    background: var(--ps-primary);
    color: #fff;
}

.ps-confirm-btn-ok.ps-confirm-btn-danger {
    background: var(--ps-danger);
}

/* Shared "unsaved changes" banner -- see layout/authenticated.html's own script for the data-dirty-guard contract. */
.ps-dirty-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    background: #FBF0DC;
    border: 1px solid #E9C77C;
    border-radius: var(--ps-radius);
    padding: 12px 16px;
    margin-bottom: 18px;
    font-size: 13px;
    font-weight: 600;
    color: #7A4E0A;
}

.ps-dirty-banner-actions {
    display: flex;
    gap: 8px;
    flex: 0 0 auto;
}
