﻿/* ============================================================================
   HotelTRS availability timelines

   RoomAvailabilityTable and StaffAvailabilityTable are the same grid - a sticky
   header of dates, rows of resources, absolutely-positioned bars laid over the
   day cells. Their two <style> blocks were byte-identical for every shared
   rule; the staff one differed only by a min-height on two selectors.

   The names they used were the problem. `.guest-card`, `.header-row`,
   `.scroll-container`, `.scrollable-table` and `.pagination-wrapper` are
   generic enough to belong to anything, and both components defined all of
   them globally: whichever <style> block rendered last won. Everything is
   trs-avail-* here.

   `.ellipsis` is NOT here. Thirteen files use it and only these two defined it,
   so it moved to components.css as the app-wide utility it always was.
   ============================================================================ */

.trs-avail-wrapper {
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    width: auto;
    position: relative;
}

/* ----------------------------------------------------------------------------
   SCROLL AND STICKY HEADER

   The header sticks to the top of the scroll container so the dates stay
   readable while scrolling down a long list of rooms.
   ---------------------------------------------------------------------------- */

.trs-avail-scroll {
    overflow-x: auto;
    overflow-y: auto;
    max-height: calc(100vh - 250px);
}

/* ----------------------------------------------------------------------------
   THE HEIGHT IS INHERITED, NOT CALCULATED

   `max-height: calc(100vh - 250px)` above is the same class of mistake the
   workdays board used to carry: 250 is a guess at the height of everything
   around the table, and it is wrong the moment any of it moves.

   MEASURED at 1000x620 - main.b-layout-content overflowed by 107px while the
   table ALSO had its own 616px of scroll, so the screen had two vertical
   scrollbars. The reserve had handed the table 370px in a space with room for
   about 290. Note the page scroller is `main`, not `.content` or the document:
   that is why the document's own scrollHeight reads clean and the bug looks
   invisible from the top.

   The toolbar is what pushed it over the edge here, because the filter button
   grew when its caption moved inside it - but the constant was already wrong,
   and any change to the heading, the legend or the pager would have found it.

   So the chain measures itself instead: main gives .content a definite height,
   each box between it and the scroller passes that down, and the scroller takes
   whatever is left. The :has() chain is needed because the markup between them
   - a LoadingIndicator wrapper and the page's own root div - has no classes
   this file can name. Same shape as .content:has(.wd-board) in workdays.css.

   Opt-in via --fill so StaffAvailabilityTable, which shares .trs-avail-wrapper
   and carries its own min-height floor, is left exactly as it was. */
.content:has(.trs-avail-wrapper--fill) {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.content:has(.trs-avail-wrapper--fill) *:has(.trs-avail-wrapper--fill) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.trs-avail-wrapper--fill {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* The constant is overridden rather than deleted: .trs-avail-scroll is shared
   with the staff table, which still wants it. */
.trs-avail-wrapper--fill .trs-avail-scroll {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}

/* The filter button's label moved inside the control, and "Filter by room
   status" is long enough to wrap to THREE lines in a narrow button - MEASURED
   61px tall at 1000px wide, against 38 for the buttons beside it. The row wraps
   instead of the words. */
.trs-avail-toolbar {
    flex-wrap: wrap;
    gap: var(--trs-space-2);
}

.trs-avail-toolbar .btn {
    white-space: nowrap;
}

/* The staff view reserves a floor so a hotel with three employees does not
   render a timeline two rows tall with the pager jammed under it.

   The floor is on the TABLE only now. It used to be on the scroller as well,
   which fought the --fill sizing below: a hard 400px minimum on a box that is
   supposed to take the leftover height puts it back to overflowing the moment
   the window is shorter than the floor plus the chrome. With the scroller
   filling, it is never two rows tall anyway - the reason for the floor is
   already handled - and the table keeps its own so a nearly-empty timeline
   still has something to draw against. */
.trs-avail-scroll-min .trs-avail-table {
    min-height: 400px;
}

.trs-avail-table {
    display: flex;
    flex-direction: column;
    min-width: max-content;
}

.trs-avail-header,
.trs-avail-table > .trs-avail-header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--trs-surface);
    display: flex;
    border-bottom: 2px solid var(--trs-border-strong);
    font-weight: var(--trs-weight-bold);
    flex-shrink: 0;
    min-width: max-content;
}

.trs-avail-header {
    border-radius: 5px 0;
}

/* ----------------------------------------------------------------------------
   FROZEN COLUMNS

   Room and Status stay put while the month scrolls under them. Without this,
   scrolling right to reach the end of a month took the row's identity with it -
   MEASURED at scrollLeft 400 the Room cell sat at x=12 against a scrollport
   starting at 259, i.e. entirely off screen, leaving a wall of unlabelled bars.

   The two frozen cells are named by POSITION, not by what they hold: the room
   grid puts Room and Status there, the staff grid puts Staff and Role, and the
   sticky offsets only care which comes first.

   These four cells (two header, two per row) each carried the same inline style
   string - flex:2 1 0, 8px 12px of padding, a #ccc right border, min-width 130
   - which is why they are a class now: a sticky offset has to know the column's
   width, and `flex: 2 1 0` does not have one until it is laid out. Fixed at
   140px, which is what the flex basis was resolving to anyway (MEASURED 139).

   z-index 4 clears the bars, which run 1 for a stay, 2 for maintenance hatching
   and 3 for the guest-count pill. The header sits at 10 and makes its own
   stacking context, so its two frozen cells are ordered within that.

   The background is not decoration: the cells were transparent all the way down
   to the page ground, so without one the bars would scroll visibly underneath.
   Header cells keep their Background.Primary - Bootstrap marks .bg-primary
   !important, so it wins here, which is what we want. */
.trs-avail-col {
    position: sticky;
    z-index: 4;
    flex: 0 0 140px;
    width: 140px;
    min-width: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    padding: 8px 12px;
    border-right: 1px solid var(--trs-border);
    background: var(--trs-surface);
    font-size: 0.9rem;
    word-wrap: break-word;
}

.trs-avail-col-first {
    left: 0;
}

.trs-avail-col-second {
    left: 140px;
}

.trs-avail-header .trs-avail-col-first {
    border-radius: var(--trs-radius-sm) 0 0 0;
}

/* ----------------------------------------------------------------------------
   MONTH NAVIGATION

   The band spans the whole timeline - 1650px of it - and the controls used to be
   centred in it. Centred against the CONTENT width, not the visible width, so on
   a 1366px screen the month picker sat at x=1003 in a scrollport 1063 wide and
   was cut in half; you had to scroll right to change month. MEASURED before the
   change: header 1927 wide inside a 1063 scrollport.

   The controls are now a sticky group parked immediately right of the two frozen
   columns, so they hold that position at any width and any scroll offset. 280 is
   the two columns' combined width - keep the three in step. */
.trs-avail-monthbar {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    width: 100%;
    padding: 4px 0;
    border-bottom: 1px solid var(--trs-border);
    border-radius: 0 var(--trs-radius-sm) 0 0;
    font-size: 0.85rem;
}

.trs-avail-monthnav {
    position: sticky;
    left: 280px;
    z-index: 3;
    display: inline-flex;
    align-items: center;
    padding-inline: var(--trs-space-2);
}

/* `.room-row` and `.day-cell` were defined in BOTH style blocks and used in
   neither - searched the whole solution, razor and cs. Dropped rather than
   carried across; the rows and day cells are laid out by the components' own
   markup. */

.trs-avail-pagination {
    position: sticky;
    bottom: 0;
    background: var(--trs-surface);
    z-index: 10;
    width: 100%;
    border-radius: 5px;
}

/* ----------------------------------------------------------------------------
   BARS

   A bar is positioned absolutely over the day cells it spans. The component
   writes position, left, width, top AND height as an inline style computed from
   the date range, so those five properties here are inert - an inline style
   beats any stylesheet. The `height: 45px` below has been dead for as long as
   it has existed (bars render at the inline 40px); it is kept only so the box
   still makes sense if the inline height ever goes away. Change the component,
   not this number.

   Background colour is also inline, from the booking or shift status, so
   nothing here may set one - only the chrome around it.
   ---------------------------------------------------------------------------- */

/* :root, not a bare class, and this is why the status icon looked like it was
   falling out of the bar.

   The bar is a Blazorise <Card>, so it carries .card, and the theme emits
   `.card { border-radius: <RadiusLg> }` into a <style> inside <body>. That ties
   .trs-avail-bar on specificity (0,1,0) and wins on document order, so the 4px
   asked for here never applied - MEASURED 16px. The bar is also overflow:hidden,
   so a 16px corner curve ate the status icon sitting at the top right: the icon
   was never outside the card, it was sliced diagonally by the card's own corner.

   (0,2,0) clears .card. --trs-radius-sm rather than the old literal 4 - a 45px
   bar is exactly the case the token doc describes, where the 11px signature
   would swallow the element. */
:root .trs-avail-bar {
    position: absolute;
    height: 45px;
    border-radius: var(--trs-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px 4px;
    color: var(--trs-on-primary);
    cursor: pointer;
    z-index: 1;
    transition: transform var(--trs-motion-base) var(--trs-ease),
                box-shadow var(--trs-motion-base) var(--trs-ease);
    font-size: var(--trs-text-xs);
    overflow: hidden;
    box-shadow: var(--trs-elevation-1);
}

.trs-avail-bar:hover {
    box-shadow: var(--trs-elevation-2);
}

/* The bar's status colours, so the timeline and the Status column beside it finally
   say the same thing.

   The bar took a Blazorise Background, and that map DISAGREED with the badge's:
   Reserved was Warning on the bar and Info on the badge, CheckedOut was Success and
   Secondary, DidntShowUp was Secondary and Warning. Three of five statuses rendered
   two colours on one screen, four pixels apart.

   Its own classes rather than the badge's .trs-badge--*, because the base rule above
   is `:root .trs-avail-bar` at (0,2,0) and it sets `color`. A badge class at (0,1,0)
   would be out-specified on the foreground and leave a pale label on a pale bar.

   The selector is long on purpose, and COUNTING IT MATTERS. The bar is a Blazorise
   <Card>, and the generated dark.css carries

       :root[data-theme="dark"] .card { background-color: var(--trs-surface) }

   which is (0,3,0). dark.css is linked last, so anything that merely TIES loses.

       :root .trs-avail-bar--occupied              (0,2,0)  loses
       :root:root .trs-avail-bar--occupied         (0,3,0)  ties, still loses
       :root:root .trs-avail-bar.trs-avail-bar--…  (0,4,0)  wins

   Both of the first two were tried and MEASURED here: the bar came back
   rgb(32,36,34), the surface colour, while --trs-status-occupied-bg resolved
   correctly to #3C6555 and went unused. design-system.md prescribes a :root:root
   prefix for painted rules that must clear that sheet; against a (0,3,0) rule one
   doubling is not enough, and the repeated class is what buys the last point.

   Only the three RACK statuses are here. Cancelled and DidntShowUp are semantic and
   keep the Blazorise background they have always had - a cancellation is an error in
   the booking, not a position in the room's day. */
:root:root .trs-avail-bar.trs-avail-bar--occupied {
    background: var(--trs-status-occupied-bg);
    color: var(--trs-status-occupied-fg);
}

:root:root .trs-avail-bar.trs-avail-bar--arriving {
    background: var(--trs-status-arriving-bg);
    color: var(--trs-status-arriving-fg);
}

:root:root .trs-avail-bar.trs-avail-bar--departing {
    background: var(--trs-status-departing-bg);
    color: var(--trs-status-departing-fg);
}

/* Out-of-order rooms. Diagonal hatching rather than a colour, so it reads as
   "not available" even where a status colour already occupies the bar. */
.trs-avail-bar-maintenance {
    z-index: 2;
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.08) 0,
        rgba(255, 255, 255, 0.08) 8px,
        transparent 8px,
        transparent 16px
    );
}

/* The status icon in the bar's top-right. Was an inline `top:0px; right:3px` on
   the Tooltip, which put it hard into the corner - fine against the intended 4px
   radius, clipped against the 16px the bar was actually getting. Inset so it
   clears the curve whatever the radius resolves to. */
.trs-avail-bar-status {
    top: 3px;
    right: 6px;
}

.trs-avail-count {
    position: absolute;
    bottom: 3px;
    right: 4px;
    font-size: 0.6875rem;
    font-weight: var(--trs-weight-bold);
    background-color: var(--trs-surface);
    color: var(--trs-text);
    padding: 0 6px;
    border-radius: 999px;
    line-height: 1.4;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    box-shadow: var(--trs-elevation-1);
    z-index: 3;
    pointer-events: none;
}

/* Keeps the guest name clear of the count badge sitting in the corner. */
.trs-avail-bar.has-count .ellipsis {
    padding-right: 30px;
}

/* ----------------------------------------------------------------------------
   CLOSED DATES

   A restriction closing a date is not a booking - it gets hatching on the cell
   rather than a bar, so a booking laid over the same date still reads.
   ---------------------------------------------------------------------------- */

.trs-avail-closed {
    background-image: repeating-linear-gradient(
        135deg,
        var(--trs-danger-bg) 0,
        var(--trs-danger-bg) 4px,
        transparent 4px,
        transparent 10px
    );
}

/* The legend swatch on RoomAvailabilityIndex. It was a hand-made copy of the
   gradient above in Bootstrap red, so the key and the thing it explains were
   two separate definitions that could drift apart. Same tokens now. */
.restriction-legend-closed {
    width: 18px;
    height: 14px;
    border-radius: 2px;
    background-color: var(--trs-danger-bg-soft);
    background-image: repeating-linear-gradient(
        135deg,
        var(--trs-danger-bg) 0,
        var(--trs-danger-bg) 4px,
        transparent 4px,
        transparent 10px
    );
}

.trs-avail-closed-badge {
    bottom: 2px;
    left: 2px;
    color: var(--trs-danger);
    font-size: 0.6875rem;
    line-height: 1;
    z-index: 4;
}

/* Phones. The two frozen columns are 280px and the scrollport is about 270, so
   they covered the whole timeline. Only the first stays frozen here, narrower;
   the second scrolls away with the bars. The month controls follow the first
   column's width, as above. */
@media (max-width: 575.98px) {
    .trs-avail-col {
        flex-basis: 96px;
        width: 96px;
        min-width: 96px;
        padding: 6px 8px;
        font-size: 0.8rem;
    }

    .trs-avail-col-second {
        position: static;
    }

    .trs-avail-monthnav {
        left: 96px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .trs-avail-bar,
    .trs-avail-bar:hover {
        transition: none;
    }
}

/* ----------------------------------------------------------------------------
   DATE PICKER IN THE TOOLBAR

   Both components carried `#date-picker-container .form-control` - an ID
   selector with five !important declarations forcing white text. It sits on a
   dark toolbar, so the white was right, but an ID is global and the rule
   applied to any .form-control that ever landed inside that container.
   Scoped to the wrapper and reading the token instead.
   ---------------------------------------------------------------------------- */

.trs-avail-datepicker .form-control {
    background: transparent;
    color: var(--trs-on-primary);
    border: none;
    font-weight: var(--trs-weight-bold);
    text-align: center;
    font-size: var(--trs-text-md);
    width: 100%;
}

/* :focus needs its own rule, not just inheritance from the one above.
   Blazorise emits `.form-control:focus` from a <style> element inside <body>,
   which is (0,2,0) - the same specificity as the rule above and later in
   document order, so on focus it would win and repaint the field light. Under
   white text that is an invisible input. (0,3,0) settles it without
   !important, which is what the original rule used five of. */
.trs-avail-datepicker .form-control:focus {
    background: transparent;
    color: var(--trs-on-primary);
    border: none;
    box-shadow: none;
}

.trs-avail-datepicker .form-control::placeholder {
    color: var(--trs-on-primary);
    opacity: .75;
}

/* ----------------------------------------------------------------------------
   DAY CELLS

   The header cell and every body cell in a column share these. They were built
   as inline style strings in the code-behind, which is how the "today" column
   ended up white on #95d197 - 1.77:1, on the one column staff look for first.

   Only min-width stays inline: it is computed from how many days are on screen.
   ---------------------------------------------------------------------------- */

.trs-avail-daycell {
    flex: 1 1 0;
    text-align: center;
    border-right: 1px solid var(--trs-border);
    font-size: var(--trs-text-xs);
    padding: 6px 0;
}

/* Today is a wayfinding band running the height of the rack, so it has to stay
   light enough that booking bars still read over it. The old colour was strong
   enough; the text on it was not. Dark-on-light instead of white-on-light. */
.trs-avail-day-today {
    background-color: var(--trs-success-bg);
    color: var(--trs-success);
    font-weight: var(--trs-weight-bold);
}

.trs-avail-day-weekend {
    background-color: var(--trs-warning-bg-soft);
}

/* Restriction-closed cells outrank both - a date that cannot be sold is more
   important than which day of the week it is. */
.trs-avail-day-closed {
    background-color: var(--trs-danger-bg);
}
