/* ============================================================================
 * Page fit / master-detail layout
 * ============================================================================ */
.page-fit {
    height: 100%;
    max-width: var(--page-max-width);
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    width: 100%;
}
/* Loading spinner state (e.g. Ticket.razor while the ticket loads): stretch
   the centring wrapper to fill the whole pane AND make it the positioning
   context. Syncfusion's SfSpinner renders an absolutely-positioned
   .e-spinner-pane; without a `position: relative` ancestor that pane climbs to
   the viewport and the spinner ends up centred on the whole page. Anchoring it
   here keeps the spinner dead-centre of the ticket-detail area — also on the
   split-pane (grid left / detail right) layout. Scoped to a DIRECT child so
   nested .center-block uses (e.g. release-notes tab content) are unaffected. */
.page-fit > .center-block {
    flex: 1;
    min-height: 0;
    position: relative;
}
.page-fit > .detail-grid {
    flex: 1; min-height: 0;
    overflow: hidden;
}
.page-fit > .detail-grid > .sf-card {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden;
}

.tickets-layout {
    position: relative; /* anchor for the absolutely-positioned grid-pane-show button */
    display: flex;
    height: 100%;
    gap: 16px;
    max-width: var(--page-max-width);
    margin: 0 auto;
    width: 100%;
}

/* Grid collapse/expand toggles. Hidden by default — only the split-pane media
   query (≥1200px) reveals the relevant one, because collapsing is meaningless
   when the grid and detail aren't shown side-by-side. */
.grid-pane-toggle { display: none; }

/* Both toggles share one look — transparent with a hero-tinted border/text so
   they sit on the navy hero and follow its background (the collapse button in
   the master hero, the show-list button floating over the detail hero). */
.grid-pane-collapse,
.grid-pane-show {
    align-items: center;
    height: 34px;
    border: 1px solid color-mix(in srgb, var(--hero-text) 35%, transparent);
    border-radius: 8px;
    background: transparent; color: var(--hero-text);
    cursor: pointer; transition: background-color .15s ease;
}
.grid-pane-collapse:hover,
.grid-pane-show:hover { background: color-mix(in srgb, var(--hero-text) 14%, transparent); }

/* Collapse button — square icon button in the master page-hero. */
.grid-pane-collapse { justify-content: center; width: 34px; }

/* Show-list button — floats top-left over the detail hero (icon + label). */
.grid-pane-show {
    position: absolute; top: 14px; left: 14px; z-index: 20;
    gap: 6px; padding: 0 12px;
    font-size: .85rem; font-weight: 600;
}
.tickets-layout > .tickets-master {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column;
}
.tickets-layout > .tickets-detail {
    flex: 1; min-width: 0;
    display: none;
    flex-direction: column;
}
.tickets-layout .page-fit { max-width: none; margin: 0; }

.tickets-layout.has-selection > .tickets-master { display: none; }
.tickets-layout.has-selection > .tickets-detail { display: flex; }

/* Split-pane (master grid + detail side by side) runs from 1200px up. Between
   1200–1920 the panes share the row 50/50; from 1920 up the grid takes 40%
   (override block further down). Below 1200 the layout falls back to single
   pane. 1200 (not 1280) so a half-snapped window on a 1440p/2560px-wide display
   — whose viewport lands just under 1280 once window chrome is subtracted —
   still gets both panes. The grid pane independently flips to cards when its own
   width drops below ~850px (ResizeObserver — see TicketsGrid.CardModeMaxWidth),
   so a narrow 50% pane still reads well. */
@media (min-width: 1200px) {
    .tickets-layout { max-width: none; margin: 0; }
    .tickets-layout > .tickets-master,
    .tickets-layout.has-selection > .tickets-master {
        display: flex; flex: 0 0 50%;
    }
    .tickets-layout > .tickets-detail,
    .tickets-layout.has-selection > .tickets-detail { display: flex; }
    .tickets-layout .ticket-hero-back { visibility: hidden; }

    /* Inside the split-pane detail panel the hero goes back to its stacked
       (top-of-page, horizontal stepper) layout — there's no room to also
       have an inner sidebar on this side of the master/detail. Resets all
       the side-by-side overrides from the @media (min-width: 1100px) block. */
    .tickets-layout > .tickets-detail .ticket-layout {
        flex-direction: column;
        align-items: stretch;
    }
    .tickets-layout > .tickets-detail .ticket-layout > .ticket-main { order: 1; }
    .tickets-layout > .tickets-detail .ticket-layout > .ticket-aside {
        order: 0;
        flex: 0 0 auto;
        max-width: none;
    }
    .tickets-layout > .tickets-detail .ticket-layout > .ticket-aside .page-hero {
        height: auto;
        flex-direction: column;
        align-items: stretch;
        overflow: visible;
        padding: 14px 22px 12px;
    }
    /* Tighten the spacing between title row / meta / stepper so the hero
       doesn't dominate the split-pane height. */
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-meta {
        padding: 8px 0 0;
        margin-top: 6px;
    }
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-stepper {
        margin-top: 6px;
        padding: 10px 14px 0;
    }
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-title { font-size: 1.25rem; }
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-meta {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 16px 24px;
    }
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-meta-item {
        flex-direction: column;
        gap: 3px;
        align-items: flex-start;
        text-align: left;
    }
    .tickets-layout > .tickets-detail .ticket-layout .ticket-hero-meta-value {
        text-align: left;
        max-width: 260px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* The show-details chevron stays available in the split-pane too; the
       details default to open here (HeroExpanded follows screen size) but the
       user can collapse them. Open/closed is driven by .is-open below. */
}

/* From 1920px up give the grid the smaller 40% share (the 1200px block above
   sets 50/50 for the 1200–1920 range). Same selectors + later source order, so
   this wins the specificity tie only where the wider viewport applies. */
@media (min-width: 1920px) {
    .tickets-layout > .tickets-master,
    .tickets-layout.has-selection > .tickets-master { flex: 0 0 40%; }
}

/* Grid collapse in split-pane — placed AFTER the block above so its
   `> .tickets-master { display:none }` wins the specificity tie against the
   `.has-selection > .tickets-master { display:flex }` rule there. */
@media (min-width: 1200px) {
    /* Expanded: offer the collapse affordance in the master hero — but only
       while a ticket is open. With no selection the list is the whole view, so
       collapsing it would just leave an empty detail pane (the button is
       pointless there). */
    .tickets-layout.has-selection:not(.is-grid-collapsed) .grid-pane-collapse { display: inline-flex; }

    /* Collapsed: drop the master entirely and re-apply the normal page max-width
       (the split-pane block above stretches the layout edge-to-edge) so the lone
       detail pane reads at the SAME centred width as a single-screen ticket view,
       not full-bleed. */
    .tickets-layout.is-grid-collapsed {
        max-width: var(--page-max-width);
        margin: 0 auto;
    }
    .tickets-layout.is-grid-collapsed > .tickets-master { display: none; }
    .tickets-layout.is-grid-collapsed .grid-pane-show { display: inline-flex; }
}

.tickets-detail-empty {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 12px;
    color: var(--text-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 40px 32px;
    text-align: center;
    box-shadow: var(--shadow-card);
}
.tickets-detail-empty i { font-size: 2.8rem; color: var(--primary); opacity: .45; }
.tickets-detail-empty h2 { margin: 0; font-size: 1.1rem; color: var(--text); font-weight: 600; }
.tickets-detail-empty p { margin: 0; max-width: 320px; font-size: .9rem; line-height: 1.5; }

.page-fit-grid > .grid-card {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
.page-fit-grid > .grid-card .e-grid { flex: 1; min-height: 0; }
.page-fit-grid > .grid-card .e-gridcontent { overflow-y: auto; }

/* ============================================================================
 * Cards, utility classes, ticket description
 * ============================================================================ */
.sf-card {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: var(--shadow-card);
}
.pa-3 { padding: 12px; }
.pa-4 { padding: 16px; }
.pa-5 { padding: 20px; }
.pa-6 { padding: 24px; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 12px; }
.mb-4 { margin-bottom: 16px; }
.my-3 { margin: 12px 0; }
.mt-2 { margin-top: 8px; }
.mt-3 { margin-top: 12px; }
.mt-4 { margin-top: 16px; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.d-flex { display: flex; }
.align-center { align-items: center; }
.justify-between { justify-content: space-between; }
.pre-wrap { white-space: pre-wrap; word-break: break-word; }
.text-muted { color: var(--text-muted); }
.text-end { text-align: right; }
.full-width { width: 100%; }
hr { border: none; border-top: 1px solid var(--border); margin: 12px 0; }

.ticket-desc {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 16px 18px 14px;
    margin-top: 8px;            /* leave room for the floating label */
    margin-bottom: 16px;
    box-shadow: var(--shadow-card);
}
/* Floating "Description" label sitting on the top border, like a fieldset
   legend. Background matches the surrounding card so the border underneath
   is visually broken. */
.ticket-desc::before {
    content: "Description";
    position: absolute;
    top: -8px;
    left: 50%;
    transform: translateX(-50%);
    padding: 0 10px;
    background: var(--surface);
    color: var(--text-muted);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    line-height: 1;
    white-space: nowrap;
}
.ticket-desc-header {
    display: flex; align-items: center; gap: 10px;
    padding-bottom: 10px; margin-bottom: 10px;
    border-bottom: 1px solid var(--border);
}
.ticket-desc-header i {
    color: var(--primary); font-size: 14px;
    width: 28px; height: 28px;
    background: rgba(var(--s2c-primary-rgb), .12);
    border-radius: 6px;
    display: inline-flex; align-items: center; justify-content: center;
}
.ticket-desc-header .card-title {
    margin: 0; font-size: .78rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--text-muted);
}
.ticket-desc-body { color: var(--text); font-size: .92rem; line-height: 1.55; }
.ticket-desc-body p { margin: 0; }
.ticket-desc-empty { color: var(--text-muted); font-style: italic; }
/* The scroll lives on the inner body — keeping .ticket-desc itself with
   `overflow: visible` so the ::before "Description" label can sit on the
   top border without being clipped. */
.page-fit .sf-card .ticket-desc { flex-shrink: 0; }
.page-fit .sf-card .ticket-desc .ticket-desc-body { max-height: 180px; overflow-y: auto; }
.page-fit .thread { max-height: none; flex: 1; }
/* Empty state must fill the same space as a populated thread, so the composer
   stays pinned to the bottom whether or not there are messages yet (otherwise
   with zero messages the short empty box lets the composer ride up). Centre the
   "no messages" placeholder within the filled area. */
.page-fit .thread-empty {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
}
.page-fit .composer { flex-shrink: 0; }
.page-fit > .detail-grid > aside.sf-card { overflow-y: auto; }

/* ----------------------------------------------------------------------------
 * Ticket detail layout — stacked on narrow viewports (hero on top, messages
 * below); side-by-side on ≥1100px (messages left, compact hero + vertical
 * stepper on the right). Avoids the hero eating most of the laptop viewport.
 * ---------------------------------------------------------------------------- */
.ticket-layout {
    display: flex;
    flex-direction: column;
    gap: 16px;
    height: 100%;
    min-height: 0;
}
.ticket-layout > .ticket-main {
    flex: 1; min-width: 0; min-height: 0;
    display: flex; flex-direction: column;
    order: 1;
}
.ticket-layout > .ticket-main > .sf-card {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
.ticket-layout > .ticket-aside { order: 0; flex-shrink: 0; }
.ticket-layout .ticket-aside .page-hero { margin-bottom: 0; }


/* Hero (meta + stepper) collapses behind the show-details toggle so the
   messages stay dominant. The chevron is available on EVERY width — phone,
   tablet, single-pane desktop AND the ≥1200px split-pane. Open/closed is driven
   entirely by the .is-open class (HeroExpanded in Ticket.razor, which defaults
   to open on non-small screens), so the user can always collapse the details,
   even on a large screen. */
.ticket-hero-details {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    transition: max-height .25s ease, opacity .18s ease;
}
.ticket-hero-details.is-open {
    max-height: 2000px;
    opacity: 1;
    /* The title↔details spacing lives here (not as a hero `gap`) so a collapsed
       hero has no phantom gap pushing the title off-centre — see .ticket-hero. */
    margin-top: 8px;
}

/* ============================================================================
 * Hero (kept on S2C navy regardless of theme — see --hero-bg)
 * ============================================================================ */
.page-hero {
    background: var(--hero-bg);
    color: var(--hero-text); border-radius: 12px;
    padding: 24px 28px; margin-bottom: 20px;
    box-shadow: 0 10px 30px -10px rgba(2,38,63,.35);
    display: flex; flex-wrap: wrap; gap: 16px; align-items: center;
}
.page-hero-text { display: flex; flex-direction: column; user-select: none; }
.page-hero-text h1 { margin: 0; font-weight: 600; font-size: 1.5rem; color: var(--hero-text); }
.page-hero-text p { margin: 4px 0 0; color: rgba(255,255,255,.92); font-size: .9rem; }

/* The tickets-list hero is purely informational (title + count + new-ticket
   button) — keep it compact so the filter bar + grid get more screen. */
.tickets-master .page-hero {
    padding: 10px 18px;
    margin-bottom: 12px;
}
.tickets-master .page-hero-text h1 { font-size: 1.1rem; }
.tickets-master .page-hero-text p { font-size: .8rem; margin-top: 1px; }
.ticket-hero-title { user-select: none; }

/* Blazor's <FocusOnNavigate Selector="h1" /> programmatically focuses the
   first h1 after each route change for screen-reader announcement; that
   triggers the browser's default focus outline on our decorative hero title.
   Suppress the outline here only — keyboard focus on real interactive
   elements elsewhere is untouched. */
.page-hero-text h1:focus,
.page-hero-text h1:focus-visible,
.ticket-hero-title:focus,
.ticket-hero-title:focus-visible {
    outline: none;
    box-shadow: none;
}

.ticket-hero {
    flex-direction: column;
    align-items: stretch;
    /* Override the generic .page-hero padding — ticket detail hero only needs
       breathing room above/below the title row, not the spacious newpage-style
       padding the listing hero uses. Equal top/bottom so the title row sits
       centred when the details block is collapsed. */
    padding: 14px 18px;
    margin-bottom: 14px;
    /* No container gap: the title↔details spacing is applied on
       .ticket-hero-details.is-open instead, so a collapsed hero leaves no
       phantom gap below the title (which pushed it visually high). */
    gap: 0;
}
.ticket-hero-text { gap: 6px; }
.ticket-hero-row {
    display: grid;
    /* Equal-width side columns (1fr each) so the centre column — and thus the
       title — sits at the TRUE horizontal centre of the hero, regardless of
       the back arrow (narrow) vs the action buttons (wide) being different
       widths. With `auto 1fr auto` the title centred in a left-shifted middle
       column; `1fr auto 1fr` fixes that. */
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 12px;
}
.ticket-hero-title {
    margin: 0; font-weight: 600; font-size: 1.5rem;
    color: var(--hero-text); text-align: center;
    line-height: 1.2;
    /* For typical ticket keys (TT-DDMMYYYY-NN) the sidebar font shrink keeps
       everything on one line. For unusually long keys (e.g. TT-TROUBLE_TICKET.0003)
       we let them wrap at natural separators (-, _, .) rather than overflow. */
    overflow-wrap: anywhere;
}
.ticket-hero-back {
    color: rgba(255,255,255,.85);
    width: 32px; height: 32px; border-radius: 8px;
    display: inline-flex; align-items: center; justify-content: center;
    text-decoration: none;
    justify-self: start; /* hug the left edge of its 1fr column */
}
.ticket-hero-back:hover { background: rgba(255,255,255,.12); color: #fff; }

/* Right side of the title row: status pill + (on narrow viewports) a toggle
   button that collapses/expands the meta + stepper section underneath. */
.ticket-hero-row-end {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    justify-self: end; /* hug the right edge of its 1fr column */
}
.ticket-hero-toggle {
    width: 32px; height: 32px;
    border-radius: 8px;
    background: rgba(255,255,255,.10);
    color: #fff;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .15s ease;
    font-size: 12px;
}
.ticket-hero-toggle:hover { background: rgba(255,255,255,.22); }

/* Edit (pencil) button — same look as the toggle but always visible (the
   toggle is hidden in sidebar mode, the edit button needs to stay). */
.ticket-hero-edit {
    width: 32px; height: 32px;
    border-radius: 8px;
    background: rgba(255,255,255,.10);
    color: #fff;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .15s ease;
    font-size: 12px;
}
.ticket-hero-edit:hover { background: rgba(255,255,255,.22); }
.ticket-hero-key {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    color: rgba(255,255,255,.85); font-weight: 600;
    background: rgba(255,255,255,.10);
    padding: 3px 10px; border-radius: 999px;
    font-size: .85rem;
}
.ticket-hero .status-pill { background: rgba(255,255,255,.15); color: #fff; }

/* Dark mode: pills sitting on the teal hero get the navy accent so they
   pop against the green-teal background instead of disappearing into it. */
[data-bs-theme="dark"] .ticket-hero-key {
    background: var(--hero-accent);
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.10);
}
[data-bs-theme="dark"] .ticket-hero .status-pill {
    background: var(--hero-accent);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.10);
}
[data-bs-theme="dark"] .ticket-hero-meta-value .priority-pill {
    background: var(--hero-accent);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.15);
}
[data-bs-theme="dark"] .ticket-hero-back:hover {
    background: var(--hero-accent);
}

.ticket-hero-meta {
    display: flex; flex-wrap: wrap;
    gap: 10px 20px;
    padding: 8px 0 2px;
    border-top: 1px solid rgba(255,255,255,.10);
    margin-top: 8px;
}
.ticket-hero-meta-item { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ticket-hero-meta-label {
    font-size: .65rem; font-weight: 700;
    letter-spacing: .08em; text-transform: uppercase;
    color: rgba(255,255,255,.55);
}
.ticket-hero-meta-value {
    color: #fff; font-size: .88rem; font-weight: 500;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 260px;
    overflow-wrap: anywhere;
}
.ticket-hero-meta-value .priority-pill {
    background: rgba(255,255,255,.10);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.15);
}

/* Notify email list — inline with semicolon separators in the horizontal
   hero; stacked one-per-line in the sidebar so long addresses don't push
   the meta column wider than 340px. */
.notify-email { display: inline; }
.notify-email + .notify-email::before { content: "; "; opacity: .6; }
@media (min-width: 1100px) {
    .ticket-layout .notify-email { display: block; }
    .ticket-layout .notify-email + .notify-email::before { content: none; }
}

.ticket-hero-stepper {
    margin-top: 8px;
    /* Bottom padding must clear the step labels (name + caption) so the last
       line — the completion date / status caption — stays inside the hero
       instead of spilling just past its bottom edge. */
    padding: 14px 8px 12px;
    border-top: 1px solid rgba(255,255,255,.10);
}
.detail-grid.detail-grid-single { grid-template-columns: 1fr; }

/* Syncfusion stepper — themed for both horizontal and vertical orientations.
   The bootstrap5 theme hardcodes Bootstrap blue (#0d6efd) on .e-step,
   .e-indicator AND .e-step-indicator; we override all three plus labels. */
.ticket-hero-stepper .e-stepper .e-step-label-container .e-step-label,
.ticket-hero-stepper .e-stepper .e-step-label-container .e-step-text,
.ticket-hero-stepper .e-stepper .e-step-text {
    color: rgba(255,255,255,.85) !important;
    font-weight: 500;
}
/* Templated step content: a Template replaces Syncfusion's built-in indicator,
   so we render the ring + icon ourselves and recreate the look with the hero
   colours. Step name on top, caption (completion date / status text like
   "Assigned" / "In Queue" / "Not Started") dimmer underneath. */
.ticket-hero-stepper .ticket-step-dot {
    display: flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; border-radius: 50%;
    border: 2px solid var(--hero-step-fill);
    color: var(--hero-step-fill);
    /* Hero background so the ring masks the connector line running behind it. */
    background: var(--hero-bg);
    margin: 0 auto 0;
    font-size: 1rem;
}
/* Completed / current steps: filled ring. */
.ticket-hero-stepper .e-step-completed .ticket-step-dot,
.ticket-hero-stepper .e-step-selected .ticket-step-dot,
.ticket-hero-stepper .e-step-inprogress .ticket-step-dot {
    background: var(--hero-step-fill);
    color: var(--hero-step-fg);
}
.ticket-hero-stepper .ticket-step-name {
    display: block;
    text-align: center;
    /* Tight but never below 1 — a sub-1 line-height makes the glyph box shorter
       than the text, so the bottom of the line spills outside the hero. */
    line-height: 1.1;
    color: rgba(255,255,255,.9) !important;
    font-weight: 600;
}
.ticket-hero-stepper .ticket-step-cap {
    display: block;
    text-align: center;
    line-height: 1.15;
    color: rgba(255,255,255,.6) !important;
    font-weight: 400;
    font-size: .76rem;
    /* Pull the caption up snug under the name (the name's line-box leaves a
       little gap); negative margin keeps both glyph boxes >=1 so nothing clips. */
    margin-top: -2px;
}
/* Not-yet-started steps: grey out the name + caption so the focus stays on the
   completed / current steps. */
.ticket-hero-stepper .step-notstarted .ticket-step-name {
    color: rgba(255,255,255,.4) !important;
}
.ticket-hero-stepper .step-notstarted .ticket-step-cap {
    color: rgba(255,255,255,.3) !important;
}
.ticket-hero-stepper .e-stepper .e-step .e-step,
.ticket-hero-stepper .e-stepper .e-step .e-indicator,
.ticket-hero-stepper .e-stepper .e-step .e-step-indicator {
    background: transparent !important;
    color: var(--hero-step-fill) !important;
    border: 2px solid var(--hero-step-fill) !important;
    font-weight: 600;
    transition: transform .15s ease, box-shadow .15s ease;
}
.ticket-hero-stepper .e-stepper .e-step-completed .e-step,
.ticket-hero-stepper .e-stepper .e-step-completed .e-indicator,
.ticket-hero-stepper .e-stepper .e-step-completed .e-step-indicator,
.ticket-hero-stepper .e-stepper .e-step-inprogress .e-step,
.ticket-hero-stepper .e-stepper .e-step-inprogress .e-indicator,
.ticket-hero-stepper .e-stepper .e-step-inprogress .e-step-indicator,
.ticket-hero-stepper .e-stepper .e-step-selected .e-step,
.ticket-hero-stepper .e-stepper .e-step-selected .e-indicator,
.ticket-hero-stepper .e-stepper .e-step-selected .e-step-indicator {
    background: var(--hero-step-fill) !important;
    color: var(--hero-step-fg) !important;
    border-color: var(--hero-step-fill) !important;
}
.ticket-hero-stepper .e-stepper .e-step-selected .e-step-indicator,
.ticket-hero-stepper .e-stepper .e-step-inprogress .e-step-indicator {
    box-shadow: 0 0 0 4px rgba(0,0,0,.25), 0 4px 12px -2px rgba(0,0,0,.35) !important;
    transform: scale(1.06);
}
.ticket-hero-stepper .e-stepper .e-step-completed:not(.e-step-error) .e-text,
.ticket-hero-stepper .e-stepper .e-step-completed:not(.e-step-error) .e-label,
.ticket-hero-stepper .e-stepper .e-step-selected:not(.e-step-error) .e-text,
.ticket-hero-stepper .e-stepper .e-step-selected:not(.e-step-error) .e-label,
.ticket-hero-stepper .e-stepper .e-step-inprogress:not(.e-step-error) .e-text,
.ticket-hero-stepper .e-stepper .e-step-inprogress:not(.e-step-error) .e-label {
    color: #fff !important;
    font-weight: 600;
}
.ticket-hero-stepper .e-stepper:not(.e-steps-focus) .e-step-selected .e-step {
    box-shadow: 0 0 0 2px var(--hero-bg),
                0 0 0 4px var(--hero-step-fill),
                0 0 0 8px var(--hero-bg) !important;
}
.ticket-hero-stepper .e-stepper .e-stepper-progressbar {
    background: rgba(255,255,255,.18) !important;
}
.ticket-hero-stepper .e-stepper .e-stepper-progressbar .e-progressbar-value {
    background: var(--hero-step-fill) !important;
}
/* Connector — short thin pill between rings. */
.ticket-hero-stepper .e-stepper .e-stepper-progressbar {
    height: 3px !important;
}
.page-hero-actions { margin-left: auto; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.page-hero .e-input-group,
.page-hero .e-input-group:not(.e-disabled):not(.e-float-icon-left):not(.e-success):not(.e-warning):not(.e-error) {
    background: rgba(255,255,255,.10) !important;
    border-color: rgba(255,255,255,.25) !important;
    color: #fff !important;
}
.page-hero .e-input, .page-hero input.e-input { color: #fff !important; }
.page-hero input.e-input::placeholder { color: rgba(255,255,255,.6); }
.page-hero .e-input-group .e-input-group-icon { color: rgba(255,255,255,.75); }
.page-hero .hero-switch { color: rgba(255,255,255,.85); font-size: .85rem; display: flex; gap: 8px; align-items: center; }

.page-h1 { font-size: 1.5rem; font-weight: 600; margin: 0 0 16px; }

/* ============================================================================
 * Filter bar
 * ============================================================================ */
.filter-bar {
    display: flex; flex-wrap: wrap; gap: 24px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px 16px; margin-bottom: 16px;
    box-shadow: var(--shadow-card);
}
.filter-group { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.filter-group.is-end { margin-left: auto; }

/* Two-column filter bar: status+severity on the left, search+created on the
   right. Each column stacks its filter-groups vertically. */
.filter-bar-grid {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
}
.filter-stack {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}
.filter-stack.is-end { align-items: flex-end; }
.filter-stack.is-end .filter-group { justify-content: flex-end; }

/* Status + My tickets on one row inside the (column) stack: inline while they
   fit, wrapping My tickets to the next line when the bar gets narrow. */
.filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 10px 20px;
}
.filter-label {
    font-size: .7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--text-muted);
    /* Fixed minimum so controls line up vertically across rows even when the
       label text varies in length (STATUS vs SEVERITY, SEARCH vs CREATED). */
    min-width: 70px;
}
.segmented {
    display: inline-flex;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 2px;
}
.seg-btn {
    background: transparent; border: none; cursor: pointer;
    padding: 5px 14px; border-radius: 6px;
    font-size: .82rem; font-weight: 500;
    color: var(--text-muted);
    font-family: inherit;
}
.seg-btn:hover { color: var(--text); }
.seg-btn.active {
    background: var(--surface); color: var(--text);
    box-shadow: 0 1px 2px rgba(0,0,0,.12);
    font-weight: 600;
}

/* My-tickets toggle: when active, fill it with the brand colour so it's clearly
   "on" (vs the subtle white active state the Status segments use), making it
   obvious the list is scoped to the current user. */
.filter-group--mine .seg-btn.active {
    background: var(--primary); color: #fff;
    box-shadow: 0 1px 3px rgba(var(--s2c-primary-rgb), .4);
}
.filter-group--mine .seg-btn.active:hover { color: #fff; }

.chip-row { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.chip {
    cursor: pointer; border: 1px solid transparent;
    opacity: .55; transition: opacity .15s ease, box-shadow .15s ease;
    font-family: inherit; padding: 4px 10px;
}
.chip:hover { opacity: 1; }
.chip.active { opacity: 1; box-shadow: 0 0 0 2px rgba(var(--s2c-primary-rgb),.20); }
.chip-clear {
    background: transparent; border: none; cursor: pointer;
    color: var(--text-muted); font-size: .8rem;
    display: inline-flex; align-items: center; gap: 4px;
    font-family: inherit;
}
.chip-clear:hover { color: var(--text); }
.page-header-flat { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; }
.page-header-flat h1 { font-size: 1.5rem; font-weight: 600; margin: 0; flex: 1; }

/* Filter-bar expand/collapse toggle. On desktop/tablet it is hidden and the
   full filter bar is always shown. On mobile (≤768px, where the sidebar becomes
   the hamburger menu) only the Status segments are shown, with this chevron on
   the right to reveal Severity / Search / Created. */
.filter-expand-toggle {
    display: none;
    align-items: center; justify-content: center;
    width: 34px; height: 34px; flex: 0 0 auto;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--surface-alt); color: var(--text-muted);
    cursor: pointer; transition: color .15s ease, background-color .15s ease;
}
.filter-expand-toggle:hover { color: var(--text); }

/* Active-filter overview chips, shown only under the collapsed mobile filter
   bar (see media query). Each chip clears its own filter when clicked. */
.filter-active-summary { display: none; }
.active-filter-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px; border-radius: 999px;
    border: 1px solid var(--border); background: var(--surface-alt);
    color: var(--text); font-size: .78rem; font-family: inherit;
    cursor: pointer; transition: border-color .15s ease, background-color .15s ease;
}
/* Only shift the border on hover — NOT the background — so the per-severity
   colour (p-critical/.../p-low, applied as an extra class) survives hover. */
.active-filter-chip:hover { border-color: var(--primary); }
.active-filter-chip .fa-xmark { font-size: .7rem; opacity: .55; }
.active-filter-chip:hover .fa-xmark { opacity: 1; }
.filter-active-summary { min-width: 0; align-items: center; }

@media (max-width: 768px) {
    /* Stack the two filter columns so each spans the full width — otherwise at
       the wider end of the mobile range they sit side by side and the Status
       group only fills half the bar, leaving the toggle stranded mid-row. */
    .filter-bar-grid { flex-direction: column; align-items: stretch; }

    /* Reveal the active-filter overview only while the bar is collapsed — when
       expanded the real controls are visible, so the chips would be redundant. */
    .filter-bar:not(.is-filters-open) .filter-active-summary {
        display: flex; flex-wrap: wrap; gap: 6px;
    }

    /* Search/Created normally right-align (is-end); on mobile they should read
       left like the rest, now that their column spans the full width. */
    .filter-stack.is-end { align-items: stretch; }
    .filter-stack.is-end .filter-group { justify-content: flex-start; }

    /* Pin the chevron top-right of the WHOLE filter row and reserve its space,
       so the Status segments, active-filter chips AND the My tickets toggle all
       flow inline beside it — the chevron always stays at the far right, after
       everything, instead of being stranded between Status and My tickets. */
    .filter-row { position: relative; padding-right: 42px; }
    .filter-group--status { flex-wrap: wrap; row-gap: 6px; }
    .filter-group--status .filter-label { display: none; }
    .filter-expand-toggle { display: inline-flex; position: absolute; top: 0; right: 0; }

    /* Collapsed: show only the Status group. Hide Severity (same stack) and the
       whole Search/Created stack until the chevron expands the bar. */
    .filter-bar:not(.is-filters-open) .filter-group:not(.filter-group--status),
    .filter-bar:not(.is-filters-open) .filter-stack.is-end { display: none; }
}

/* ============================================================================
 * Grid styling (Syncfusion SfGrid)
 * ============================================================================ */
.e-grid {
    border: 1px solid var(--border) !important;
    border-radius: var(--radius) !important;
    overflow: hidden;
    box-shadow: var(--shadow-card);
}
.e-grid .e-rowcell { padding: 12px 14px !important; vertical-align: middle; }
.e-grid .e-headercell {
    background: var(--surface-alt) !important;
    color: var(--text-muted) !important;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 600;
    padding: 10px 14px !important;
}
.e-grid .e-row:hover .e-rowcell { cursor: pointer; background: var(--primary-subtle) !important; }

/* Selected row — translucent primary wash so the text stays readable.
   Syncfusion 30.x uses .e-active on the <tr> and may add .e-selectionbackground
   or .e-active on the cells depending on selection mode; we cover both. */
.e-grid .e-row.e-active > .e-rowcell,
.e-grid .e-row.e-selectionbackground > .e-rowcell,
.e-grid .e-rowcell.e-active,
.e-grid .e-rowcell.e-selectionbackground {
    background-color: rgba(var(--s2c-primary-rgb), .16) !important;
    color: var(--text) !important;
}
.e-grid .e-row.e-active:hover > .e-rowcell,
.e-grid .e-row.e-selectionbackground:hover > .e-rowcell {
    background-color: rgba(var(--s2c-primary-rgb), .22) !important;
}

/* Selected ALTERNATE (striped) rows. The altrow stripe lives in syncfusion.css,
   which loads AFTER this file and ties on specificity with the cell-level
   selection rule above — so in LIGHT mode the later stripe was overriding the
   selection wash on odd rows. These altrow-qualified selectors carry one extra
   class (.e-altrow), so the selection wins on striped rows too, whether
   Syncfusion flags the row (.e-active) or the cell (.e-rowcell.e-active). Dark
   mode is unaffected: its theme-prefixed rules in syncfusion.css still win by
   source order. */
.e-grid .e-altrow.e-active > .e-rowcell,
.e-grid .e-altrow.e-selectionbackground > .e-rowcell,
.e-grid .e-altrow > .e-rowcell.e-active,
.e-grid .e-altrow > .e-rowcell.e-selectionbackground {
    background-color: rgba(var(--s2c-primary-rgb), .16) !important;
    color: var(--text) !important;
}
.e-grid .e-altrow.e-active:hover > .e-rowcell,
.e-grid .e-altrow.e-selectionbackground:hover > .e-rowcell {
    background-color: rgba(var(--s2c-primary-rgb), .22) !important;
}

/* Row selection only — Syncfusion draws a focus box (inset shadow/outline)
   around the single clicked cell on top of the row highlight, which reads like
   the cell/column is separately selected. We select whole rows, so suppress
   the per-cell focus visual; the row wash is the only selection indicator. */
.e-grid .e-rowcell.e-focus,
.e-grid .e-rowcell.e-focused,
.e-grid.e-gridfocus .e-rowcell.e-focused,
.e-grid .e-gridcontent .e-rowcell.e-focused {
    box-shadow: none !important;
    outline: none !important;
}

.ticket-key {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    color: var(--primary); font-weight: 600;
}
.cell-subject-title { font-weight: 500; }
.cell-subject-sub { color: var(--text-muted); font-size: .8rem; margin-top: 2px; }

/* ============================================================================
 * Pills (priority + status + environment)
 * ============================================================================ */
.priority-pill, .status-pill, .env-pill {
    display: inline-flex; align-items: center;
    padding: 3px 10px; border-radius: 999px;
    font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase;
}
.p-critical { background: #fde4dc; color: #b03a16; }
.p-high     { background: #fff3cc; color: #8a5e00; }
.p-medium   { background: #e1eef5; color: #114b6e; }
.p-low      { background: #d4f4dd; color: #15643a; }

.s-open       { background: #e1eef5; color: #114b6e; }
.s-accept     { background: #d4f4dd; color: #15643a; }
.s-inqueue    { background: #fff3cc; color: #8a5e00; }
.s-notstarted { background: #eef1f3; color: #4a5560; }
.s-closed     { background: #e2e8ec; color: #4a5560; }
.s-cancelled  { background: #fde4dc; color: #b03a16; }

.env-pill {
    background: var(--surface-alt); color: var(--text);
    border: 1px solid var(--border);
    text-transform: none; letter-spacing: 0; font-weight: 500;
}
.env-pill.ext { background: #fff3cc; color: #8a5e00; border-color: #ffe0a0; }
.env-pill.int { background: #d4f4dd; color: #15643a; border-color: #b8e4c6; }

[data-bs-theme="dark"] .p-critical { background: rgba(230,83,43,.22);  color: #ffb59a; }
[data-bs-theme="dark"] .p-high     { background: rgba(238,173,0,.20);  color: #f7d27a; }
[data-bs-theme="dark"] .p-medium   { background: rgba(95,153,187,.22); color: #b8d4ec; }
[data-bs-theme="dark"] .p-low      { background: rgba(18,151,81,.22);  color: #8ce0b3; }

[data-bs-theme="dark"] .s-open       { background: rgba(95,153,187,.22); color: #b8d4ec; }
[data-bs-theme="dark"] .s-accept     { background: rgba(18,151,81,.22);  color: #8ce0b3; }
[data-bs-theme="dark"] .s-inqueue    { background: rgba(238,173,0,.20);  color: #f7d27a; }
[data-bs-theme="dark"] .s-notstarted { background: rgba(255,255,255,.08); color: var(--text-muted); }
[data-bs-theme="dark"] .s-closed     { background: rgba(255,255,255,.10); color: var(--text-muted); }
[data-bs-theme="dark"] .s-cancelled  { background: rgba(230,83,43,.22);  color: #ffb59a; }
[data-bs-theme="dark"] .env-pill.ext { background: rgba(238,173,0,.20); color: #f7d27a; border-color: rgba(238,173,0,.35); }
[data-bs-theme="dark"] .env-pill.int { background: rgba(18,151,81,.22); color: #8ce0b3; border-color: rgba(18,151,81,.35); }

.assignee { display: flex; align-items: center; gap: 8px; }
.assignee-avatar {
    width: 28px; height: 28px; border-radius: 50%;
    background: var(--primary); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: .7rem;
}

/* ============================================================================
 * Mobile (Small viewport) ticket card — Office 365-style row template used by
 * SfGrid when RowRenderingMode flips to Vertical. Each grid row becomes one
 * card with a coloured avatar on the left and stacked title / meta on the right.
 * ============================================================================ */
.e-grid .e-row .e-rowcell .ticket-mobile-card,
.ticket-mobile-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    width: 100%;
    min-width: 0;
    cursor: pointer;
    /* Match the desktop row colour so the underlying Syncfusion .e-rowcell
       (which the bootstrap5-dark theme paints near-black) never shows through. */
    background: var(--surface);
}
.ticket-mobile-avatar {
    width: 44px; height: 44px;
    border-radius: 50%;
    background: var(--primary); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: .85rem;
    flex-shrink: 0;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
}
.ticket-mobile-body {
    flex: 1;
    min-width: 0;
    display: flex; flex-direction: column;
    gap: 4px;
}
.ticket-mobile-row1 {
    display: flex; align-items: center;
    gap: 8px;
    min-width: 0;
}
.ticket-mobile-row1 .ticket-key {
    font-size: 1rem;
    font-weight: 700;
    flex-shrink: 0;
}
.ticket-mobile-row1 .status-pill {
    margin-left: auto;
    flex-shrink: 0;
}
.ticket-mobile-subject {
    font-size: .82rem;
    color: var(--text-muted);
    font-weight: 400;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ticket-mobile-row2 {
    display: flex; align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: .75rem;
    color: var(--text-muted);
}
.ticket-mobile-customer {
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 60%;
}
.ticket-mobile-date {
    margin-left: auto;
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}

/* Syncfusion's vertical row mode wraps every row cell in extra chrome — strip
   it back so our card has full control over padding/spacing. */
.e-grid .e-row.e-row-vertical .e-rowcell,
.e-grid .e-rowcell.e-templatecell:has(> .ticket-mobile-card) {
    padding: 0 !important;
    border: 0 !important;
}
.e-grid .e-row.e-row-vertical {
    border-bottom: 1px solid var(--border);
}

/* The grid wrapper is focusable (tabindex) so it can own the ArrowUp/Down keys
   in card mode — suppress the focus ring, the selected-card highlight is the
   visible cue. */
.ims-grid-wrap:focus,
.ims-grid-wrap:focus-visible { outline: none; }

/* Card-mode selection highlight — card mode has no Syncfusion .e-active row, so
   mirror the column-mode selected wash and add a left accent so the open ticket
   reads at a glance. Must out-specify AND !important-beat the alt-row striping
   in syncfusion.css (`.e-grid .e-altrow .ticket-mobile-card { background !important }`),
   otherwise the highlight vanishes on every other (striped) card. Opaque
   color-mix so it looks identical on normal and alt rows, in light and dark. */
.ims-grid-wrap .e-grid .e-row .ticket-mobile-card.is-selected,
.ims-grid-wrap .e-grid .e-altrow .ticket-mobile-card.is-selected {
    background: color-mix(in srgb, var(--primary) 18%, var(--surface)) !important;
    box-shadow: inset 3px 0 0 0 var(--primary);
}
.ims-grid-wrap .e-grid .e-row .ticket-mobile-card.is-selected:hover,
.ims-grid-wrap .e-grid .e-altrow .ticket-mobile-card.is-selected:hover {
    background: color-mix(in srgb, var(--primary) 26%, var(--surface)) !important;
}
