/*
 * App-level CSS tweaks layered on top of Tabler.
 *
 * Keep this file minimal - brand/theme colours live in `assets/themes/*.css`
 * (loaded last so they win the cascade). This file is for structural fixes
 * that apply across every theme, independent of the active brand colours.
 */

/* Above 992px Tabler reserves the scrollbar gutter with `:root { margin-left: calc(100vw - 100%) }`,
   which keeps a *centered* container optically still while a scrollbar comes and goes. Every layout
   here is `layout-fluid`, so `.container-xl` fills the viewport and nothing is centered: that margin
   compensates for nothing and only pushes the whole document right, leaving an empty strip one
   scrollbar wide down the left edge of the navbar and the page. Reserving the gutter on the scroll
   container instead holds both page edges still whether or not the page scrolls.

   The flat `body` padding belongs to the same guarantee. Bootstrap adds `padding-right` equal to the
   scrollbar width whenever a modal or offcanvas puts `overflow: hidden` on the body, to replace the
   space the vanishing scrollbar gave back. With the gutter reserved that space is never given back,
   so the compensation double-counts and pulls the page in by the scrollbar width for as long as the
   dialog is open. Bootstrap writes it inline, which is why this has to be `!important`. */
:root {
    margin-left: 0;
    scrollbar-gutter: stable;
}

body {
    padding-right: 0 !important;
}

/* Emoji still used inside page bodies/buttons keep their own colour
   (Tabler icons inherit `currentColor`; emoji must not be tinted). */
.icon-emoji {
    font-style: normal;
    line-height: 1;
}

.table {
    --tblr-table-bg: var(--tblr-bg-surface);
}

.badge.text-bg-warning,
.badge.text-bg-yellow,
.badge.text-bg-orange,
.badge.text-bg-success,
.badge.text-bg-green,
.badge.text-bg-lime,
.badge.text-bg-teal,
.badge.text-bg-cyan,
.badge.text-bg-info,
.badge.text-bg-azure {
    color: #1f2937 !important;
}

.badge.text-bg-primary {
    color: var(--tblr-primary-fg) !important;
}

.badge.text-bg-secondary {
    background-color: var(--tblr-gray-600) !important;
}

/* Permission matrix: every group against every permission. The left column and the header row are
   frozen, because a tick in the middle of a wide table means nothing once you have scrolled the
   permission name or the group name off screen. */
.perm-matrix-wrap {
    position: relative;
}

.perm-matrix-scroll {
    max-height: 75vh;
    overflow: auto;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
}

.perm-matrix {
    margin-bottom: 0;
    border-collapse: separate;
    border-spacing: 0;
}

.perm-matrix > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--tblr-bg-surface);
    border-bottom: 1px solid var(--tblr-border-color);
    vertical-align: bottom;
}

.perm-matrix-corner {
    left: 0;
    z-index: 4 !important;
    min-width: 22rem;
}

.perm-matrix-name {
    position: sticky;
    left: 0;
    z-index: 1;
    min-width: 22rem;
    background: var(--tblr-bg-surface);
    font-weight: 500;
}

.perm-matrix-group {
    min-width: 8rem;
    text-align: center;
}

.perm-matrix-group-name {
    display: block;
    max-width: 10rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* One merged row per category, the same grouping the group edit screen uses. */
.perm-matrix-category > th {
    position: sticky;
    left: 0;
    background: color-mix(in srgb, var(--tblr-primary) 10%, var(--tblr-bg-surface));
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    font-size: 11px;
}

.perm-matrix-cell {
    text-align: center;
    color: var(--tblr-border-color);
}

.perm-matrix-cell.is-granted {
    /*color: var(--tblr-green);*/
    color: var(--tblr-white);
    /*background: color-mix(in srgb, var(--tblr-green) 10%, transparent);*/
    background: color-mix(in srgb, var(--tblr-green) 100%, transparent);
}

.perm-matrix-nav {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 0;
    z-index: 6;
}

.perm-matrix-arrow {
    position: absolute;
    top: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--tblr-border-color);
    border-radius: 50%;
    background: var(--tblr-bg-surface);
    color: var(--tblr-body-color);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
    cursor: pointer;
}

.perm-matrix-arrow-prev {
    left: calc(22rem + 8px);
}

.perm-matrix-arrow-next {
    right: 8px;
}

/* Multi-select combobox (components/forms `checkbox_dropdown`). A long list of options has to
   scroll inside the dropdown rather than run off the bottom of the screen. */
.checkbox-dropdown-menu {
    max-height: 60vh;
    overflow-y: auto;
}

/* Bootstrap's .form-check hangs its input off the left edge on a negative margin, which the
   scrolling menu above clips: the box disappeared and there was no way to see what was ticked.
   Laying the item out as a row puts the input back inside the box it belongs to. */
.checkbox-dropdown-menu .dropdown-item.form-check {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding-left: 1rem;
    margin-left: 0;
    white-space: normal;
}

.checkbox-dropdown-menu .form-check-input {
    position: static;
    float: none;
    flex: 0 0 auto;
    margin: .2rem 0 0;
}

/* ===== Goodies / reward progress tracker (Tabler add-on) ===== */
.reward {
    --rw-collected: var(--tblr-green, #2fb344);
    --rw-available: var(--tblr-orange, #f76707);
    --rw-blocked:   var(--tblr-yellow, #f59f00);
    --rw-next:      var(--tblr-primary, #206bc4);
    --rw-locked:    var(--tblr-border-color, #dbe0e5);
    --rw-muted:     var(--tblr-secondary, #667382);
    --rw-surface:   var(--tblr-bg-surface, #fff);
}

/* --- Compact bar (profile) --- */
.reward-track {
    position: relative; height: 8px; border-radius: 999px;
    background: var(--rw-locked); margin: 1.5rem .5rem;
}
.reward-track__fill {
    position: absolute; inset: 0 auto 0 0; border-radius: 999px;
    background: var(--rw-collected);
}
.reward-marker {
    position: absolute; top: 50%; width: 14px; height: 14px; border-radius: 50%;
    transform: translate(-50%, -50%); cursor: default;
    background: var(--rw-locked);
    border: 2px solid var(--rw-surface);
    box-shadow: 0 0 0 1px var(--rw-locked);
}
.reward-marker.is-collected { background: var(--rw-collected); box-shadow: 0 0 0 1px var(--rw-collected); }
.reward-marker.is-available { background: var(--rw-available); box-shadow: 0 0 0 1px var(--rw-available); }
.reward-marker.is-next {
    width: 16px; height: 16px; background: var(--rw-surface);
    border-color: var(--rw-next); box-shadow: 0 0 0 2px var(--rw-next);
}
.reward-key { display: inline-block; width: 10px; height: 10px; border-radius: 50%; vertical-align: middle; margin-right: .3rem; }

/* --- Full timeline (info desk) --- */
.reward-timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.reward-timeline > li { position: relative; display: flex; align-items: center; gap: .75rem; padding: .4rem 0; }
.reward-timeline > li::before {
    content: ""; position: absolute; left: 15px; top: 0; bottom: 0; width: 2px;
    background: var(--rw-locked); z-index: 0;
}
.reward-timeline > li:first-child::before { top: 50%; }
.reward-timeline > li:last-child::before  { bottom: 50%; }
.reward-timeline .rw-dot {
    position: relative; z-index: 1; flex-shrink: 0;
    width: 32px; height: 32px; border-radius: 50%;
    display: grid; place-items: center; font-size: 1rem;
    color: #fff; background: var(--rw-muted);
}
.reward-timeline .rw-name { font-weight: 500; flex: 1 1 auto; min-width: 0; }
/* The name absorbs the squeeze; a shrinking badge spills its nowrap text past its own background. */
.reward-timeline .rw-hours,
.reward-timeline .rw-status { flex: 0 0 auto; }
.reward-timeline .rw-note { display: block; font-size: .75rem; font-weight: 400; color: var(--rw-muted); }
.reward-timeline li.is-collected .rw-dot { background: var(--rw-collected); }
.reward-timeline li.is-available .rw-dot { background: var(--rw-available); }
.reward-timeline li.is-blocked  .rw-dot { background: var(--rw-blocked); }
.reward-timeline li.is-next     .rw-dot { background: var(--rw-surface); border: 2px solid var(--rw-next); color: var(--rw-next); }
.reward-timeline li.is-locked   .rw-dot { background: var(--rw-locked); color: var(--rw-muted); }
.reward-timeline li.is-locked   .rw-name { color: var(--rw-muted); }

/* --- Horizontal orientation (same markup, add .is-horizontal) --- */
.reward-timeline.is-horizontal { display: flex; flex-direction: row; overflow-x: auto; padding-bottom: .5rem; }
.reward-timeline.is-horizontal > li { flex-direction: column; text-align: center; gap: .4rem; min-width: 116px; padding: 0 .25rem; }
.reward-timeline.is-horizontal > li::before { left: 0; top: 15px; bottom: auto; width: 100%; height: 2px; }
.reward-timeline.is-horizontal > li:first-child::before { left: 50%; width: 50%; }
.reward-timeline.is-horizontal > li:last-child::before  { left: 0;  width: 50%; }
.reward-timeline.is-horizontal .rw-name { font-size: .8rem; line-height: 1.15; }

/* ===== Equal-height column deck whose panels scroll internally =====
   Bootstrap's .row-deck stretches the cards to match each other; it does nothing to stop an
   unbounded list from growing the whole row. The cap belongs on the scrolling panel rather than on
   the card, so a column that happens to be short is still stretched to its neighbours.

   Both rules are off below the lg breakpoint, where the columns stack: on a phone the page scrolls
   as one document and a nested scroll container only swallows the gesture. */
@media (min-width: 992px) {
    .row-deck-forced { display: flex; flex-wrap: wrap; align-items: stretch; }
    .row-deck-forced > [class*="col-"] { display: flex; flex-direction: column; }
    .row-deck-forced > [class*="col-"] > .card { flex: 1 1 auto; }
    /* Both axes: a table too wide for its column scrolls rather than spilling out of the card. */
    .deck-scroll { max-height: 62vh; overflow: auto; }
}

/* Sticky on the cells, not on <thead>: Tabler's tables collapse their borders, and a sticky thead
   leaves the header's borders behind when the body scrolls under it. */
.table-thead-sticky thead th {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--tblr-bg-surface);
}
