/*
 * Agent desktop styling, mobile-first.
 *
 * Two rules drive most of what looks unusual here:
 *   1. Everything interactive is at least 48px tall. An agent taps these while holding a device
 *      one-handed, often in a hurry.
 *   2. The sticky bars pad themselves with env(safe-area-inset-*) so nothing hides behind a notch
 *      or a home indicator. That only works because the layout sets viewport-fit=cover.
 */

:root {
    --agent-topbar-h: 3.75rem;
    --agent-callbar-h: 4.75rem;

    --state-available: #198754;
    --state-idle: #fd7e14;
    --state-reserved: #d63384;
    --state-talking: #0d6efd;
    --state-hold: #ffc107;
    --state-consulting: #0dcaf0;
    --state-wrapup: #6f42c1;
    --state-offline: #6c757d;
}

html,
body {
    height: 100%;
    overscroll-behavior-y: none;
}

body {
    /* Removes the 300ms tap delay without disabling pinch zoom the way a locked viewport would. */
    touch-action: manipulation;
    -webkit-text-size-adjust: 100%;
}

/* Chrome's dynamic viewport unit keeps the layout correct while the mobile URL bar collapses. */
#app {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

/* ---------------------------------------------------------------- brand bar */

/*
 * Deliberately scrolls away while the status bar below it stays pinned: identity is worth a strip
 * of screen on arrival, not during a call on a phone.
 */
.brandbar {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: calc(.5rem + env(safe-area-inset-top)) max(.75rem, env(safe-area-inset-left)) .5rem
             max(.75rem, env(safe-area-inset-right));
    background: var(--bs-tertiary-bg);
    border-bottom: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
}

.brand-mark {
    width: 28px;
    height: 28px;
    flex: 0 0 auto;
}

.brand-text {
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.brand-by {
    font-weight: 400;
    opacity: .75;
}

/* ------------------------------------------------------------------ top bar */

.topbar {
    position: sticky;
    top: 0;
    z-index: 1030;
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--bs-border-color);
}

.topbar-inner {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-height: var(--agent-topbar-h);
    padding: .5rem max(.75rem, env(safe-area-inset-left)) .5rem max(.75rem, env(safe-area-inset-right));
}

.state-pill {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-height: 44px;
    padding: .25rem .75rem .25rem .5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background: var(--bs-tertiary-bg);
    color: inherit;
    font: inherit;
}

.state-dot {
    width: .75rem;
    height: .75rem;
    border-radius: 50%;
    background: var(--state-offline);
    flex: 0 0 auto;
}

/* Chosen by the agent. */
.state-pill[data-state="Available"] .state-dot { background: var(--state-available); }
.state-pill[data-state="Idle"] .state-dot { background: var(--state-idle); }

/* Derived from the call, since the platform reports none of these as agent states. */
.state-pill[data-state="Reserved"] .state-dot { background: var(--state-reserved); }
.state-pill[data-state="Talking"] .state-dot { background: var(--state-talking); }
.state-pill[data-state="Hold"] .state-dot { background: var(--state-hold); }
.state-pill[data-state="Consulting"] .state-dot { background: var(--state-consulting); }
.state-pill[data-state="Wrapup"] .state-dot { background: var(--state-wrapup); }

/* Reserved is the one state that needs the agent to act, so it does not sit still. */
@media (prefers-reduced-motion: no-preference) {
    .state-pill[data-state="Reserved"] .state-dot {
        animation: state-blink 1s steps(1, end) infinite;
    }
}

@keyframes state-blink {
    50% { opacity: .25; }
}

.state-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.15;
}

.state-timer {
    font-variant-numeric: tabular-nums;
    color: var(--bs-secondary-color);
}

.conn-badge {
    /* Pushed to the right so the state pill keeps the left, with the avatar last. */
    margin-left: auto;
    flex: 0 0 auto;
    font-size: .6875rem;
}

.conn-badge.is-hidden {
    /* Hidden rather than removed: a bar that reflows every time the connection blips is worse
       than a little unused space. */
    visibility: hidden;
    width: 0;
    padding: 0;
    overflow: hidden;
}

/* The agent's initials, doubling as the menu button. */
.topbar-avatar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--bs-primary);
    color: #fff;
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .02em;
    line-height: 1;
}

.topbar-avatar:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* -------------------------------------------------------------------- main */

.main {
    flex: 1 1 auto;
    padding: 1rem max(1rem, env(safe-area-inset-left)) 1rem max(1rem, env(safe-area-inset-right));
}

.screen-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 60dvh;
}

.setup-card,
.signin-block,
.station-block {
    width: 100%;
    max-width: 30rem;
    margin-inline: auto;
    text-align: left;
}

/* ------------------------------------------------------------ station login */

.login-options {
    display: grid;
    gap: .5rem;
}

.login-option {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    min-height: 56px;
    padding: .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    background: var(--bs-body-bg);
    text-align: left;
    width: 100%;
    color: inherit;
}

.login-option.is-selected {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 .15rem rgba(var(--bs-primary-rgb), .25);
}

.login-option-title {
    font-weight: 600;
}

.login-option-hint {
    display: block;
    font-size: .8125rem;
    color: var(--bs-secondary-color);
}

/* --------------------------------------------------------------------- desk */

.desk-idle {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    padding-top: 2rem;
}

.desk-idle-text {
    color: var(--bs-secondary-color);
    margin: 0;
}

.caller {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.caller-avatar {
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: var(--bs-tertiary-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    font-weight: 600;
    flex: 0 0 auto;
}

.caller-id {
    min-width: 0;
    flex: 1 1 auto;
}

.caller-number {
    font-size: 1.125rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.caller-queue {
    font-size: .8125rem;
}

.caller-timer {
    font-variant-numeric: tabular-nums;
    font-size: 1.125rem;
    color: var(--bs-secondary-color);
}

.task-flags {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
    padding: .75rem 0;
}

.cad {
    display: grid;
    gap: .5rem;
}

.cad-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem 0;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.cad-key {
    color: var(--bs-secondary-color);
    font-size: .8125rem;
}

.cad-value {
    text-align: right;
    word-break: break-word;
}

/* ------------------------------------------------------------- call control */

.callbar {
    position: sticky;
    bottom: 0;
    z-index: 1030;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: .25rem;
    background: var(--bs-body-bg);
    border-top: 1px solid var(--bs-border-color);
    padding: .5rem max(.5rem, env(safe-area-inset-left))
             calc(.5rem + env(safe-area-inset-bottom)) max(.5rem, env(safe-area-inset-right));
}

.callbtn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .125rem;
    min-height: 56px;
    padding: .375rem .25rem;
    border: 0;
    border-radius: .5rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    font-size: .6875rem;
    line-height: 1.1;
}

.callbtn:disabled {
    opacity: .4;
}

/* Icons inherit the button's colour, so they invert with the active and danger states. */
.callbtn-icon {
    width: 1.5rem;
    height: 1.5rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A record indicator reads better filled than outlined. */
#btn-record .callbtn-icon circle {
    fill: currentColor;
    stroke: none;
}

/* Only the handset body is filled; the two drop lines stay strokes. */
#btn-end .callbtn-icon path:first-child {
    fill: currentColor;
}

.callbtn.is-active {
    background: var(--bs-primary);
    color: #fff;
}

.callbtn-danger {
    background: var(--bs-danger);
    color: #fff;
}

/* -------------------------------------------------------------- incoming call */

/*
 * The full-screen overlay this file used to hold is gone from the desktop: a ringing call is a
 * card in the bottom-right corner now, and its rules are .calltoast in desktop.css. The mobile
 * front end keeps its own copy of that overlay in its own copy of this file — the two are separate
 * clients on purpose, and this change is about a PC screen where an agent is doing something else
 * when the call arrives.
 *
 * What is left here is the one rule that was never about the shape: the answer button pulses so it
 * reads as urgent at a glance, which matters more in a corner than it did over a dimmed screen.
 */
@media (prefers-reduced-motion: no-preference) {
    #btn-accept {
        animation: incoming-pulse 1.6s ease-in-out infinite;
    }
}

@keyframes incoming-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(25, 135, 84, .55); }
    50% { box-shadow: 0 0 0 .75rem rgba(25, 135, 84, 0); }
}

/* ------------------------------------------------------------------- sheets */

.sheet.offcanvas-bottom {
    height: auto;
    max-height: 80dvh;
    border-top-left-radius: 1rem;
    border-top-right-radius: 1rem;
}

/*
 * Side sheets run the full height from y=0, so their header — and the close button in it — lands
 * behind the notch or the status bar in standalone mode. The bottom sheets do not need this: they
 * are anchored to the other end of the screen.
 */
.sheet.offcanvas-end,
.sheet.offcanvas-start,
.sheet.offcanvas-top {
    padding-top: env(safe-area-inset-top);
}

.sheet.offcanvas-end {
    padding-right: env(safe-area-inset-right);
}

.sheet.offcanvas-start {
    padding-left: env(safe-area-inset-left);
}

.sheet .offcanvas-header {
    min-height: 60px;
}

/*
 * Bootstrap pulls the close button up and out with a negative margin and sizes it at 1em, which is
 * both hard to hit and part of why it ended up under the status bar. Give it back its space and a
 * real touch target.
 */
.sheet .offcanvas-header .btn-close {
    width: 44px;
    height: 44px;
    padding: 0;
    margin: 0 0 0 auto;
    background-size: 1rem;
    flex: 0 0 auto;
    opacity: .75;
}

.sheet .offcanvas-body {
    padding-bottom: calc(1rem + env(safe-area-inset-bottom));
}

/* A grid in a full-height sheet shares the leftover space between its rows, which stretched the
   menu buttons to a couple of hundred pixels each. Keep them their natural height, stacked at the
   top — but not below the touch target the rest of the app holds to. */
.sheet .offcanvas-body .d-grid {
    align-content: start;
}

.sheet .offcanvas-body .d-grid .btn {
    min-height: 48px;
}

/* ---------------------------------------------------------------- menu sheet */

.menu-user {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding-bottom: 1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.menu-avatar {
    width: 2.75rem;
    height: 2.75rem;
    flex: 0 0 auto;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    background: var(--bs-primary);
    color: #fff;
}

.menu-identity {
    min-width: 0;
}

.menu-name {
    font-weight: 600;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.menu-email {
    display: block;
    font-size: .8125rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.menu-email:hover {
    text-decoration: underline;
}

.menu-field {
    margin-bottom: 1rem;
}

.menu-field .form-select {
    min-height: 48px;
}

.menu-team-row {
    display: flex;
    align-items: center;
    gap: .625rem;
}

.menu-team-row .form-select {
    flex: 1 1 auto;
}

#menu-team-spinner {
    flex: 0 0 auto;
    color: var(--bs-primary);
}

.menu-facts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .375rem 1rem;
    margin-bottom: 1.5rem;
}

.menu-facts dt {
    font-weight: 400;
    font-size: .8125rem;
    color: var(--bs-secondary-color);
}

.menu-facts dd {
    margin: 0;
    text-align: right;
    font-size: .8125rem;
    word-break: break-word;
}

.menu-version {
    margin: 1.5rem 0 0;
    text-align: center;
    font-size: .75rem;
    color: var(--bs-secondary-color);
    /* Long enough to wrap awkwardly on a phone, and worth being able to select and paste. */
    word-break: break-all;
    user-select: text;
    -webkit-user-select: text;
}

.sheet .list-group-item {
    min-height: 52px;
    display: flex;
    align-items: center;
}

/* ------------------------------------------------------- tablet and desktop */

@media (min-width: 768px) {
    .brand-mark {
        width: 32px;
        height: 32px;
    }

    .brand-text {
        font-size: .9375rem;
    }

    .main {
        max-width: 46rem;
        margin-inline: auto;
        width: 100%;
    }

    /* On a tablet there is room for labels beside the icons and for a bar that does not span
       the full width of a landscape screen. */
    .callbar {
        max-width: 46rem;
        margin-inline: auto;
        width: 100%;
        gap: .5rem;
    }

    .callbtn {
        font-size: .8125rem;
        min-height: 60px;
    }

    .caller-avatar {
        width: 3.5rem;
        height: 3.5rem;
    }
}

@media (min-width: 992px) {
    .main {
        max-width: 60rem;
    }

    .callbar {
        max-width: 60rem;
    }
}
