﻿/* ============================================================================
   HotelTRS floor-plan operations

   One file for the two components that make up the service-counter screen:
   FloorPlanOperations (the header cards, request panel and timeline) and
   TableOrdersPanel (the side panel that opens on a table). They share the
   `ops-` prefix on purpose - they are one screen - so they share one file.

   Both were <style> blocks: 335 and 195 lines. Neither redefined a Bootstrap
   class, which is why this is a lift rather than a rewrite; the change of
   substance is that ~40 hardcoded colours become tokens, so the screen
   follows the theme instead of being permanently light.
   ============================================================================ */

/* ----------------------------------------------------------------------------
   FULL SCREEN

   Lifts the ops view into a fixed overlay above the app chrome (sidebar and
   header sit low) but below Blazorise modals at ~1050, so dialogs still render
   on top.
   ---------------------------------------------------------------------------- */

.fp-ops-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 1030;
    overflow: auto;
    background: var(--trs-bg);
}

/* ----------------------------------------------------------------------------
   HEADER ROW

   The cards' minimum widths add up to roughly 1400-1800px (name + date nav +
   up to six stat cards + capacity + timeline). The row used to be nowrap, so
   below ~1400px it ran straight out of the content area: the capacity card was
   sliced in half and the timeline card was off screen entirely. The row wraps,
   and each card declares how it behaves when it does.
   ---------------------------------------------------------------------------- */

.ops-name-card {
    display: flex;
    align-items: center;
    gap: var(--trs-space-3);
    padding: var(--trs-space-3) var(--trs-space-5);
    background: var(--trs-surface);
    border: 2px solid var(--trs-fill);
    border-radius: var(--trs-radius-md);
    /* Wide enough that the name still reads after the back button, icon, clock,
       two buttons and the badge have taken their share. At 280px the name was
       squeezed to a single letter and the subtitle collided with the clock.
       The row wraps, so a wider card just takes its own line. */
    min-width: 420px;
    flex: 1 1 460px;
}

/* Flex children default to min-width:auto, which stopped this block from
   shrinking and instead wrapped the plan name one word per line. Allowing it to
   shrink needs a floor, or it collapses to nothing between its siblings. */
.ops-name-text {
    min-width: 140px;
    overflow: hidden;
}

.ops-name-text h5,
.ops-name-text small {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ops-name-icon {
    width: 42px;
    height: 42px;
    border-radius: var(--trs-radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--trs-text-lg);
    background-color: var(--trs-fill);
    color: var(--trs-on-primary);
}

.ops-clock {
    text-align: right;
    line-height: 1.2;
}

.ops-clock-time {
    font-size: var(--trs-text-2xl);
    font-weight: var(--trs-weight-bold);
    color: var(--trs-text-primary);
    font-variant-numeric: tabular-nums;
}

.ops-clock-date {
    font-size: var(--trs-text-xs);
    color: var(--trs-text-muted);
}

.ops-date-nav {
    display: flex;
    align-items: center;
    gap: var(--trs-space-2);
    padding: var(--trs-space-2) var(--trs-space-3);
    background: var(--trs-surface);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-md);
}

.ops-date-input {
    width: 140px;
}

/* ----------------------------------------------------------------------------
   STAT AND CAPACITY CARDS
   ---------------------------------------------------------------------------- */

.ops-stat-card {
    display: flex;
    align-items: center;
    gap: var(--trs-space-3);
    padding: var(--trs-space-3) var(--trs-space-4);
    background: var(--trs-surface);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-md);
    min-width: 130px;
    flex: 0 0 auto;
}

.ops-stat-icon {
    width: 40px;
    height: 40px;
    border-radius: var(--trs-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--trs-text-md);
}

.ops-stat-value {
    font-size: var(--trs-text-xl);
    font-weight: var(--trs-weight-bold);
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.ops-capacity-card {
    display: flex;
    flex-direction: column;
    gap: var(--trs-space-1);
    padding: var(--trs-space-2) var(--trs-space-3);
    background: var(--trs-surface);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-md);
    min-width: 220px;
    justify-content: center;
}

.ops-capacity-bar .progress-bar {
    font-size: 0;
}

/* ----------------------------------------------------------------------------
   REQUEST PANEL
   ---------------------------------------------------------------------------- */

.ops-request-card {
    cursor: pointer;
}

.ops-request-card:hover {
    box-shadow: var(--trs-elevation-2);
}

/* Amber rather than an animation: a permanent pulse gets tuned out in a day. */
.ops-request-stale {
    color: var(--trs-warning);
    background: var(--trs-warning-bg);
    border-radius: var(--trs-radius-sm);
    padding: 0 0.35rem;
    font-weight: var(--trs-weight-medium);
    white-space: nowrap;
}

.ops-request-panel {
    background: var(--trs-surface);
    border: 1px solid var(--trs-info-bg);
    border-left: 4px solid var(--trs-info);
    border-radius: var(--trs-radius-md);
    margin: 0 var(--trs-space-4);
}

.ops-request-filters {
    display: flex;
    align-items: center;
    gap: var(--trs-space-2);
    flex-wrap: wrap;
    margin-bottom: var(--trs-space-2);
}

.ops-request-search {
    max-width: 220px;
}

.ops-request-filters .form-control {
    max-width: 130px;
}

/* Only the rows scroll; filters above and the pager below stay put. */
.ops-request-list {
    max-height: 34vh;
    overflow-y: auto;
}

/* The default pager is small for a touch target on a service counter. */
.ops-request-pagination .page-link {
    padding: 0.45rem 0.85rem;
    font-size: var(--trs-text-md);
}

.ops-request-row {
    display: flex;
    gap: var(--trs-space-3);
    align-items: flex-start;
    justify-content: space-between;
    padding: var(--trs-space-2) 0;
    border-top: 1px solid var(--trs-border);
}

.ops-request-row:first-of-type {
    border-top: none;
}

.ops-request-row-stale {
    background: var(--trs-warning-bg-soft);
}

.ops-request-warning {
    color: var(--trs-warning);
    font-size: var(--trs-text-sm);
    margin-top: 0.15rem;
}

/* ----------------------------------------------------------------------------
   LIVE INDICATOR
   ---------------------------------------------------------------------------- */

.ops-live-indicator {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    font-weight: var(--trs-weight-medium);
    color: var(--trs-success);
    white-space: nowrap;
}

.ops-live-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: var(--trs-success);
    animation: ops-live-pulse 2s ease-in-out infinite;
}

@keyframes ops-live-pulse {
    0%, 100% { opacity: 1;    transform: scale(1); }
    50%      { opacity: 0.35; transform: scale(1.5); }
}

/* ----------------------------------------------------------------------------
   TIMELINE
   ---------------------------------------------------------------------------- */

.ops-timeline-card {
    display: flex;
    flex-direction: column;
    gap: var(--trs-space-1);
    padding: var(--trs-space-2) var(--trs-space-3);
    background: var(--trs-surface);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-md);
    min-width: 300px;
    justify-content: center;
    /* Widest card in the row: give it its own line once the row wraps rather
       than letting it be the card that gets pushed out of view. */
    flex: 1 1 320px;
}

.ops-legend {
    position: absolute;
    top: var(--trs-space-2);
    left: var(--trs-space-2);
    z-index: 10;
    display: flex;
    flex-direction: column;
    gap: var(--trs-space-1);
    background: var(--trs-surface-overlay);
    backdrop-filter: blur(4px);
    padding: var(--trs-space-2) 0.625rem;
    border-radius: var(--trs-radius-sm);
    border: 1px solid var(--trs-border);
    font-size: var(--trs-text-xs);
}

.ops-label-toggles {
    position: absolute;
    top: var(--trs-space-2);
    right: var(--trs-space-2);
    z-index: 10;
    background: var(--trs-surface-overlay);
    backdrop-filter: blur(4px);
    padding: var(--trs-space-1);
    border-radius: var(--trs-radius-sm);
    border: 1px solid var(--trs-border);
}

.ops-timeline {
    display: flex;
    gap: 2px;
    align-items: flex-end;
    height: 44px;
    flex-grow: 1;
}

.ops-timeline-slot {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
}

.ops-timeline-bar-wrapper {
    width: 100%;
    height: 32px;
    display: flex;
    align-items: flex-end;
}

.ops-timeline-bar {
    width: 100%;
    border-radius: 2px 2px 0 0;
    min-height: 2px;
    transition: height var(--trs-motion-slow) var(--trs-ease);
}

/* Was #bbb at 0.55rem - 1.9:1 on white, and 8.8px. These are the hour labels
   under the timeline, which is how staff read the shape of the day; they were
   decoration rather than information. */
.ops-timeline-label {
    font-size: 0.6875rem;
    color: var(--trs-text-muted);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------------------------
   HIGHLIGHT PULSE

   Fires four times when a table is located from the request list - long enough
   to find it across a busy plan, short enough not to become wallpaper.
   ---------------------------------------------------------------------------- */

@keyframes fp-highlight-pulse-anim {
    0%, 100% {
        filter: drop-shadow(0 0 0 rgba(255, 193, 7, 0));
    }
    50% {
        filter:
            drop-shadow(0 0 6px rgba(255, 193, 7, 1))
            drop-shadow(0 0 14px rgba(255, 193, 7, 0.95))
            drop-shadow(0 0 28px rgba(255, 193, 7, 0.75))
            drop-shadow(0 0 50px rgba(255, 193, 7, 0.5))
            brightness(1.4) saturate(1.6);
    }
}

.fp-highlight-pulse {
    animation: fp-highlight-pulse-anim 1.25s ease-in-out 4;
}

@media (prefers-reduced-motion: reduce) {
    .ops-live-dot,
    .ops-timeline-bar {
        animation: none;
        transition: none;
    }

    /* The pulse was the only thing marking the located table, so simply
       removing it would make "find this table" do nothing at all. A static
       ring says the same thing without moving. */
    .fp-highlight-pulse {
        animation: none;
        outline: 3px solid var(--trs-warning);
        outline-offset: 2px;
    }
}

/* ============================================================================
   TABLE ORDERS PANEL - the side panel that opens on a table
   ============================================================================ */

/* Measured 466px of room against 708px of content once the guest form is open,
   and overflow:hidden simply cut the rest off - the submit button was
   unreachable on a short screen. Scroll instead. */
.ops-panel {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
}

.ops-panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.875rem var(--trs-space-4);
    border-bottom: 1px solid var(--trs-border);
    flex-shrink: 0;
}

.ops-table-icon {
    width: 36px;
    height: 36px;
    border-radius: var(--trs-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--trs-fill);
    color: var(--trs-on-primary);
    font-size: var(--trs-text-sm);
}

.ops-table-name {
    font-size: var(--trs-text-md);
    font-weight: var(--trs-weight-bold);
    line-height: 1.2;
}

.ops-swap-banner {
    display: flex;
    align-items: center;
    gap: var(--trs-space-2);
    padding: var(--trs-space-2) var(--trs-space-4);
    background: var(--trs-info-bg);
    border-bottom: 1px solid var(--trs-info);
    color: var(--trs-info);
    font-size: var(--trs-text-sm);
    flex-shrink: 0;
}

/* Was purple - the one hue in the app with no token, and no meaning attached
   to it anywhere else. Departing amber is what "this table is wanted soon"
   already means on the rack. */
.ops-next-reservation {
    display: flex;
    align-items: center;
    gap: var(--trs-space-2);
    padding: var(--trs-space-2) var(--trs-space-4);
    background: var(--trs-status-departing-bg);
    border-bottom: 1px solid var(--trs-status-departing-fg);
    color: var(--trs-status-departing-fg);
    flex-shrink: 0;
}

.ops-quick-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--trs-space-2);
    padding: 0.625rem var(--trs-space-4);
    border-bottom: 1px solid var(--trs-border);
    flex-shrink: 0;
}

.ops-walkin-card {
    margin: var(--trs-space-2) var(--trs-space-3);
    flex-shrink: 0;
}

.ops-panel-content {
    flex: 1;
    overflow-y: auto;
    padding: var(--trs-space-3);
    display: flex;
    flex-direction: column;
    gap: var(--trs-space-3);
}

.ops-section-card {
    border: 1px solid var(--trs-border);
    border-radius: 0.625rem;
    padding: var(--trs-space-3);
    background: var(--trs-surface-sunken);
}

.ops-section-header {
    display: flex;
    align-items: center;
    gap: var(--trs-space-2);
    margin-bottom: 0.625rem;
    padding-bottom: var(--trs-space-2);
    border-bottom: 1px solid var(--trs-border);
    color: var(--trs-text-secondary);
}

.ops-intervention-active {
    background: var(--trs-danger-bg);
    border-color: var(--trs-danger);
}

.ops-reservation-card {
    padding: var(--trs-space-2) 0.625rem;
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-sm);
    cursor: pointer;
    transition: border-color var(--trs-motion-fast) var(--trs-ease),
                background var(--trs-motion-fast) var(--trs-ease);
    background: var(--trs-surface);
}

.ops-reservation-card:hover {
    border-color: var(--trs-border-strong);
    background: var(--trs-bg);
}

.ops-reservation-active {
    border-left: 3px solid var(--trs-fill);
}

.ops-reservation-expanded {
    border-color: var(--trs-info);
    background: var(--trs-info-bg);
}

.ops-reservation-expanded:hover {
    background: var(--trs-info-bg);
    border-color: var(--trs-fill);
}

.ops-order-card {
    padding: var(--trs-space-2) 0.625rem;
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-sm);
    background: var(--trs-surface);
}

.ops-note-box {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem var(--trs-space-2);
    background: var(--trs-warning-bg);
    border-radius: 0.375rem;
    font-size: var(--trs-text-sm);
}

.ops-note-danger {
    background: var(--trs-danger-bg);
}

.ops-action-row {
    flex-wrap: wrap;
    align-items: center;
}

.ops-action-row .b-tooltip,
.ops-action-row .dropdown {
    display: inline-flex;
}

.ops-action-row .btn {
    white-space: nowrap;
}

.ops-guest-selected {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.375rem var(--trs-space-2);
    background: var(--trs-success-bg);
    border: 1px solid var(--trs-success);
    border-radius: 0.375rem;
}

.ops-empty-state {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--trs-space-2);
    padding: var(--trs-space-3);
}

/* ----------------------------------------------------------------------------
   MAIN CONTENT FRAME

   Was three inline styles on the ops screen: the viewport-height row, and the
   plan's ground and border, which were still #f8f9fa / #e9ecef in the markup
   after the <style> block had already been tokenized.
   ---------------------------------------------------------------------------- */

/* THE HEIGHT IS INHERITED, NOT CALCULATED - see the same note in pricing.css
   and availability.css; this is the fourth instance of one bug.

   `height: calc(100vh - 200px)` is a guess at the chrome above the ops row, and
   MEASURED at 1222x711 it was 193px too tall: the row took 511px in a space
   with room for about 318, and the page scrolled. No second scrollbar here,
   because nothing inside the row scrolls vertically - the content simply ran
   past the bottom of the window, which is the same fault wearing a different
   symptom.

   .ops-main itself stays a flex ROW - the plan and the side panel sit side by
   side - so only its ancestors are turned into columns. */
.content:has(.ops-main) {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.content:has(.ops-main) *:has(.ops-main) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.ops-main {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
}

/* ----------------------------------------------------------------------------
   EDITOR CHROME

   The outline editor drew its own furniture - selection handles, outline
   segments, midpoint insert markers, vertex dots - in #0066FF, thirteen times.
   That is not one of the documented floor-plan exceptions: the six table STATUS
   colours are a wire format (FloorPlanMobileViewService sends them and
   GetStatusName reverse-maps the hex, so they stay), but selection chrome is
   drawn client-side and reaches nothing. Checked: #0066FF appears in no service,
   DTO or .cs file at all.

   These are classes rather than attributes because SVG presentation attributes
   are not CSS and cannot hold a var() - but a stylesheet CAN paint SVG, and a
   class rule outranks a presentation attribute, so the tokens reach them here
   and flip with the theme, which a baked hex never did.

   The amber and green that shared those ternaries come along, since selected
   and first-point states are chosen on the same line as the blue they contrast
   with: --trs-warning and --trs-success carry the same meanings the raw
   #FFAA00 and #00CC44 were reaching for.
   ---------------------------------------------------------------------------- */

.fp-handle {
    fill: var(--trs-fill);
}

.fp-outline {
    fill: none;
    stroke: var(--trs-fill);
}

.fp-outline--selected {
    stroke: var(--trs-warning);
}

.fp-midpoint {
    fill: var(--trs-fill);
    fill-opacity: .3;
    stroke: var(--trs-fill);
}

.fp-midpoint-cross {
    stroke: var(--trs-fill);
}

.fp-vertex {
    fill: var(--trs-fill);
    stroke: var(--trs-surface);
}

.fp-vertex--first {
    fill: var(--trs-success);
}

.fp-vertex--selected {
    fill: var(--trs-fill);
    stroke: var(--trs-warning);
}

/* The booking legend's "selected table" swatch, which was the fourteenth
   #0066FF - a light-blue fill behind the same blue border. */
.fp-legend-selected {
    width: 16px;
    height: 16px;
    background-color: var(--trs-p-100);
    border: 2px solid var(--trs-fill);
    border-radius: var(--trs-radius-sm);
}

.ops-plan-frame {
    background: var(--trs-surface-sunken);
    border: 1px solid var(--trs-border);
}

/* The capacity readout sits beside a progress bar and must not wrap. */
.ops-capacity-label {
    white-space: nowrap;
}

/* ----------------------------------------------------------------------------
   TIMELINE BAR STATES

   A chart, not a table status - so unlike the legend below it, these three
   were free to become tokens. The bar height stays an inline style because it
   is computed per hour from the reservation count.
   ---------------------------------------------------------------------------- */

.ops-timeline-bar--now {
    background-color: var(--trs-fill);
    box-shadow: 0 0 4px rgba(60, 65, 60, .4);
}

.ops-timeline-bar--busy {
    background-color: var(--trs-p-300);
}

.ops-timeline-bar--empty {
    background-color: var(--trs-border);
}

/* ----------------------------------------------------------------------------
   STAT CARD AND ICON TINTS

   Only for stats that do NOT mirror a table state. The six table-state hues on
   this screen - Available, ArrivingSoon, Reserved, Seated, Overstay,
   NeedsIntervention - are deliberately still Material literals, because
   FloorPlanOperations.razor.cs writes those same hexes into TableStatuses as
   SVG fills, FloorPlanMobileViewService sends them to the mobile app as
   StatusColor, and GetStatusName() reverse-maps hex back to a status name.
   Retinting the legend without the fill and the wire format would make the
   legend lie. See the note in .steering/design-system.md.
   ---------------------------------------------------------------------------- */

.ops-stat-icon--info {
    background-color: var(--trs-info-bg);
    color: var(--trs-info);
}

.ops-stat-icon--success {
    background-color: var(--trs-success-bg);
    color: var(--trs-success);
}

.ops-stat-icon--danger {
    background-color: var(--trs-danger-bg);
    color: var(--trs-danger);
}

.ops-stat-icon--neutral {
    background-color: var(--trs-surface-sunken);
    color: var(--trs-text-secondary);
}

.ops-stat-value--success {
    color: var(--trs-success);
}

.ops-stat-value--danger {
    color: var(--trs-danger);
}

/* Takes the leftover width on the row - used by the description card. */
.ops-stat-card--grow {
    flex: 1;
    min-width: 180px;
}

/* ----------------------------------------------------------------------------
   PLAN VIEWER

   ViewFloorPlanModal was a second copy of the header cards above, under a
   .vfp- prefix and untokenized: white grounds, #e9ecef borders, a Bootstrap
   blue border and a #999 hint. It now reuses .ops-name-card and .ops-stat-card
   and keeps only what is genuinely modal-sized.
   ---------------------------------------------------------------------------- */

/* The ops header sizes its name card to share a row with a clock, a date nav
   and two buttons. Inside a modal there is nothing else on the row. */
.ops-name-card--compact {
    min-width: 200px;
    flex: 0 1 auto;
}

.fp-viewer {
    height: 550px;
    background: var(--trs-surface-sunken);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-md);
    overflow: hidden;
}

.fp-zoom-hint {
    position: absolute;
    top: var(--trs-space-2);
    right: var(--trs-space-2);
    z-index: 10;
    padding: var(--trs-space-1) var(--trs-space-2);
    background: var(--trs-surface-overlay);
    backdrop-filter: blur(4px);
    border: 1px solid var(--trs-border);
    border-radius: var(--trs-radius-sm);
    font-size: var(--trs-text-xs);
    color: var(--trs-text-muted);
}

/* Every one of the five call sites passed the same ContainerStyle string, and
   the parameter's default - a two-declaration CSS literal in the code-behind -
   was used by none of them. */
.floor-plan-svg-container {
    width: 100%;
    height: 100%;
}
