/* Custom overrides kept separate from legacy custom.css */
.ticket-form-feedback-summary {
    display: inline-flex;
    margin-left: auto;
}

.ticket-form-feedback-summary__label {
    font-size: 1.2rem;
    font-weight: 500;
    line-height: 1.2;
}

.ticket-timeline-marker-row {
    margin: 0 0 2.4rem;
    width: 100%;
    padding: 1rem .4rem;
    gap: 1rem;
}

.ticket-timeline-marker-row.alert.alert-info {
    background: var(--info);
    border: 1px solid var(--info-status);
    border-radius: 1.2rem;

}

.ticket-timeline-marker-row.alert.alert-success {
    background: rgba(var(--green-status-rgb), 0.12);
    border: 1px solid rgba(var(--green-status-rgb), 0.45);
    border-radius: 1.2rem;

}

.ticket-timeline-marker-row.alert.alert-danger {
    background: rgba(var(--red-status-rgb), 0.12);
    border: 1px solid rgba(var(--red-status-rgb), 0.45);
    border-radius: 1.2rem;

}

.ticket-timeline-banner__body {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    min-width: 0;
    flex: 1 1 auto;
}

.ticket-timeline-banner__content {
    display: grid;
    gap: 0.55rem;
    min-width: 0;
    flex: 1 1 auto; 
}

.ticket-timeline-banner__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    color: currentColor;
    margin-top: 0.1rem;
}

.ticket-timeline-banner__icon svg {
    width: 1.75rem;
    height: 1.75rem;
}

.ticket-timeline-banner__text {
    margin: 0;
    min-width: 0;
    color: inherit;
    font-size: 1.4rem;
    line-height: 1.4;
    flex: 1 1 auto;
}

.ticket-timeline-banner__comment {
    color: inherit;
    font-size: 1.35rem;
    line-height: 1.55;
}

.checklist-editor--root-only {
    border-color: #c1d3a3;
    background: var(--private);
}

.checklist-editor--scoped .checklist-editor__header {
    flex-wrap: wrap;
}

.checklist-editor__summary {
    display: grid;
    gap: 0.35rem;
}

.checklist-editor__scope {
    font-size: 1.25rem;
    line-height: 1.4;
}

.checklist-editor__visibility-control {
    display: grid;
    gap: 0.35rem;
    color: #5f7085;
    font-size: 1.2rem;
    font-weight: 600;
}


.checklist-editor--scoped .checklist-editor__group {
    display: grid;
    gap: 1rem;
    padding: 1.2rem;
    border: 1px solid #d8e2eb;
    border-radius: 1rem;
    background: var(--checklist-group-bg, #fff);
}

.checklist-editor--scoped .checklist-editor__group--private {
    --checklist-group-bg: var(--private);
}

.checklist-editor--scoped .checklist-editor__group--internal {
    --checklist-group-bg: var(--internal);
}

.checklist-editor--scoped .checklist-editor__group--public {
    --checklist-group-bg: #ffffff;
    border-color: #d8e2eb;
}

.checklist-editor--scoped .checklist-editor__group-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.checklist-editor--scoped .checklist-editor__group-summary {
    display: grid;
    gap: 0.25rem;
}

.checklist-editor--scoped .checklist-editor__group-title {
    margin: 0;
    color: var(--primary-color);
    font-size: 1.35rem;
    font-weight: 900;
}
.checklist-editor--scoped .checklist-editor__list {
    gap: 0.8rem;
}

.checklist-editor--scoped .checklist-editor__edit-line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(14rem, 16rem) auto;
    gap: 0.9rem;
    align-items: center;
    min-width: 0;
}

.checklist-editor--scoped .checklist-editor__remove-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    white-space: nowrap;
}

.checklist-editor--scoped .checklist-editor__remove-btn svg {
    width: 1.4rem;
    height: 1.4rem;
}

@media (max-width: 640px) {
    .checklist-editor__header {
        align-items: flex-start;
        flex-direction: column;
    }

    .checklist-editor--scoped .checklist-editor__group-header {
        flex-direction: column;
    }

    .checklist-editor--scoped .checklist-editor__actions {
        align-items: stretch;
    }

    .checklist-editor__visibility-control,
    .checklist-editor__visibility-select {
        width: 100%;
    }

    .checklist-editor--scoped .checklist-editor__edit-line {
        grid-template-columns: minmax(0, 1fr);
    }
}

.ticket-comment-row--agent .ticket-comment-notice-row {
    justify-content: flex-end;
}

.ticket-comment-row--customer .ticket-comment-notice-row {
    justify-content: flex-start;
}

.ticket-comment-notice {
    width: min(72rem, 100%);
    margin: 0;
    padding: 0.9rem 1.2rem;
    border: 1px solid transparent;
    border-radius: 1.2rem;
    gap: 1rem;
}

.ticket-comment-notice .form-group-note__label {
    font-size: 1.2rem;
    line-height: 1.4;
}

.ticket-comment-notice p {
    color: var(--text-grey);
    font-size: 1.3rem;
    line-height: 1.45;
}

/* A queued reply: on the ticket, email waiting for the desk to open. The clock
   pulses so a reply dated in the future reads as not yet sent. */
.ticket-comment-queued {
    align-items: center;
    flex-wrap: wrap;
}

.ticket-comment-queued__actions {
    margin-left: auto;
}

.ticket-comment-queued__clock {
    animation: ticket-comment-queued-pulse 2s ease-in-out infinite;
}

@keyframes ticket-comment-queued-pulse {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: 0.35;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ticket-comment-queued__clock {
        animation: none;
    }
}


.ticket-alert-burst-badge {
    background-color: rgba(var(--amber-status-rgb), 0.14);
    border: 1px solid rgba(var(--amber-status-rgb), 0.7);
    border-radius: 999px;
    color: var(--amber-status);
    cursor: help;
    font-size: 1.15rem;
    font-weight: 900;
    line-height: 1;
    margin-left: 0.55rem;
    margin-right: 0;
    margin-top: 0;
    min-width: 0;
    padding: 0.3rem 0.7rem;
    vertical-align: middle;
}

/* Suspended queue: flag machine-generated mail (helpdesk acks, auto-replies)
   so an agent doesn't release it back onto the ticket. Mirrors the amber
   ticket-alert-burst-badge treatment above. */
.suspended-auto-badge {
    align-items: center;
    background-color: rgba(var(--amber-status-rgb), 0.14);
    border: 1px solid rgba(var(--amber-status-rgb), 0.7);
    border-radius: 999px;
    color: var(--amber-status);
    cursor: help;
    display: inline-flex;
    font-size: 1.1rem;
    font-weight: 700;
    gap: 0.3rem;
    line-height: 1;
    margin: 0 0 0.35rem 0;
    min-width: 0;
    padding: 0.25rem 0.6rem;
    white-space: nowrap;
}

.suspended-reason-automated {
    color: var(--amber-status);
}

/* External-change banner ("X added a comment"): nudge the heading + comment
   preview up from 1.4rem so the copy is comfortably legible. Scoped to the
   banner so the draft-refreshed notice, which reuses --warning, is untouched. */
.external-change-banner {
    font-size: 1.5rem;
}

.external-change-banner .ticket-dirty-summary__label {
    font-size: 1.5rem;
}

/* default.css renders `.btn-outline.btn-warning` with amber text, but the
   element also matches `.btn.btn-warning` which fills it with the same amber —
   so the button label is gold-on-gold and invisible. Restore a legible outline:
   transparent fill, amber border (kept from default.css), navy label; fill on
   hover/focus. */
.external-change-banner .btn-outline.btn-warning {
    background-color: transparent;
    color: var(--primary-color);
}

.external-change-banner .btn-outline.btn-warning:hover,
.external-change-banner .btn-outline.btn-warning:focus {
    background-color: var(--amber-status);
    color: var(--white-text);
}

/* The draft-refreshed notice is a body sentence, not a short heading: drop the
   __label's font-weight: 900 so it reads as normal text. Scoped to this notice
   so the shared external-change banner keeps its bold heading. */
.ticket-draft-refreshed-notice .ticket-dirty-summary__label {
    font-weight: 400;
}

.ticket-comments-search {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0;
}

.ticket-comments-search .search-filter-input {
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
}

.ticket-comments-search .btn {
    flex: 0 0 auto;
}

.ticket-comments-search + .form-group-note {
    padding: 1rem 1.4rem;
    margin-top: 0;
    margin-bottom: 0;
    font-size: 1.3rem;
}

.comments-wrap .ticket-comments-search {
    margin-bottom: 2rem;
}

    .comments-wrap .ticket-comments-search + .form-group-note {
        margin-top: -1.25rem;
        margin-bottom: 2rem;
}
.partner-directory-table th,
.partner-directory-table td {
    vertical-align: top;
}

.partner-directory-contact-line + .partner-directory-contact-line {
    margin-top: 0.45rem;
}

.audit-index__card {
    border: 1px solid #d6dde5;
    border-radius: 0.75rem;
    color: inherit;
    display: grid;
    gap: 0.35rem;
    padding: 1rem;
    text-decoration: none;
}

.audit-index__card:hover {
    border-color: #86a4c1;
}

.audit-index__card span {
    color: #5d7288;
}

.report-grid {
    margin-top: 1.5rem;
}


.report-export-btn[disabled] {
    opacity: 0.75;
    cursor: wait;
}

.report-export-btn.is-busy {
    box-shadow: inset 0 0 0 999px rgba(7, 53, 79, 0.08);
}

.user-links__pill {
    align-items: center;
    background: #f3f7fb;
    border: 1px solid #d6dde5;
    border-radius: 999px;
    color: var(--primary-color);
    display: inline-flex;
    gap: 0.45rem;
    line-height: 1;
    padding: 0.35rem 0.75rem;
}

.user-links__pill:hover {
    background: #e7eef6;
}

.user-links__pill-close {
    font-size: 1rem;
    line-height: 1;
}

.user-links__third-party-panel {
    background: #f6f9fc;
    border: 1px solid #d6dde5;
    border-radius: 0.5rem;
    display: grid;
    gap: 0.55rem;
    margin-top: 0.65rem;
    padding: 0.75rem;
}

.user-links__preview {
    background: var(--white-background);
    border: 1px solid #d6dde5;
    border-radius: 0.45rem;
    padding: 0.65rem 0.75rem;
}

.user-links__preview p {
    margin: 0.2rem 0;
}

.user-links__muted {
    color: #5f748a;
    display: inline-block;
    font-size: 0.95rem;
}

.audit-tool__filter {
    display: grid;
    gap: 0.35rem;
    min-width: 18rem;
}

.audit-tool__list,
.audit-tool__summary {
    flex: 1 1 24rem;
}

.audit-tool__organisation {
    align-items: flex-start;
    display: grid;
    gap: 0.5rem;
    grid-template-columns: 1.25rem minmax(0, 1fr);
    padding: 0.15rem 0;
}

.audit-tool__organisation--selected {
    font-weight: 600;
}

.audit-tool__organisation small {
    color: #5d7288;
    display: block;
    font-weight: 400;
}

.audit-tool__preview {
    background: #f6f9fc;
    border: 1px solid #d6dde5;
    border-radius: 0.5rem;
    margin-top: 1rem;
    padding: 0.75rem;
}

.audit-tool__preview-header {
    margin-bottom: 0.35rem;
}

.audit-tool__preview p {
    margin: 0.2rem 0;
}

.domain-links__list {
    display: grid;
    gap: 0.2rem;
    margin-top: 0.5rem;
}

.domain-links__list-item {
    align-items: flex-start;
    color: var(--primary-color);
    display: grid;
    gap: 0.5rem;
    grid-template-columns: 1.25rem minmax(0, 1fr);
    padding: 0;
}

.domain-links__list-item-check {
    display: flex;
    justify-content: center;
    padding-top: 0.1rem;
}

.domain-links__list-item input {
    margin-top: 0.2rem;
}

.domain-links__list-item-marker {
    color: #7cb342;
    display: inline-block;
    font-size: 0.9rem;
    line-height: 1.4;
    margin-top: 0.05rem;
}

.domain-links__list-item-body {
    display: grid;
}

.domain-links__list-item--mapped {
    font-weight: 600;
}

.domain-links__preview {
    background: #f6f9fc;
    border: 1px solid #d6dde5;
    border-radius: 0.5rem;
    margin-top: 0.75rem;
    padding: 0.75rem;
}

.domain-links__preview-header {
    margin-bottom: 0.35rem;
}

.domain-links__preview p {
    margin: 0.2rem 0;
}

.organisation-unassigned__error {
    color: var(--red-status);
}

.ticket-list__sla-beta-notice {
    margin: 18px 0 20px;
    padding: 16px 18px;
    border: 1px solid rgba(var(--amber-status-rgb), 0.55);
    border-radius: 12px;
    background: rgba(var(--amber-status-rgb), 0.12);
    color: var(--primary-color);
    font-size: 14px;
    line-height: 1.65;
}

.ticket-list__sla-beta-notice strong {
    display: block;
    margin-bottom: 10px;
    font-size: 15px;
}

.ticket-list__sla-beta-notice-copy {
    display: block;
}

.ticket-list__sla-beta-notice a {
    color: #6f348f;
    font-weight: 600;
    text-decoration: underline;
}

.ticket-list-title-actions__buttons {
    gap: 12px;
    margin-left: auto;
}

/* The row spaces itself with `gap`, so the gauge drops .pill's own left margin
   and sits the same 12px from the first button as the buttons do from each
   other. Everything else about it is the standard pill. */
.ticket-list-sla-gauge {
    margin-left: 0;
}

.form-group-note--note {
    background-color: var(--info-status-tint);
}

.form-group-note--warning {
    background-color: var(--amber-status-tint);
}

.form-group-note--description {
    background-color: transparent;
}

.form-group-note--description .form-group-note__subtle {
    font-style: italic;
}

/* The full-width identity banners share one box, which is what stacks the label
   above the text. --out-of-office was added to the contact card without being
   added here, so it alone fell back to the bare .form-group-note — label inline,
   no padding, square corners — sitting directly above an identically-toned Note
   (Shaun, 2026-09-14). */
.form-group-note--out-of-office:not(.form-group-note--card):not(.form-group-note--compact),
.form-group-note--note:not(.form-group-note--card):not(.form-group-note--compact),
.form-group-note--warning:not(.form-group-note--card):not(.form-group-note--compact) {
    border: 1px solid transparent;
    border-radius: 1.2rem;
    padding: 1.2rem 1.4rem;
}

.form-group-note--out-of-office:not(.form-group-note--card):not(.form-group-note--compact).d-flex,
.form-group-note--note:not(.form-group-note--card):not(.form-group-note--compact).d-flex,
.form-group-note--warning:not(.form-group-note--card):not(.form-group-note--compact).d-flex {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.6rem;
}

.form-group-note--out-of-office:not(.form-group-note--card):not(.form-group-note--compact),
.form-group-note--note:not(.form-group-note--card):not(.form-group-note--compact) {
    border-color: var(--info-status);
}

.form-group-note--warning:not(.form-group-note--card):not(.form-group-note--compact) {
    border-color: var(--amber-status);
}

.form-group-note--out-of-office:not(.form-group-note--card):not(.form-group-note--compact) p,
.form-group-note--note:not(.form-group-note--card):not(.form-group-note--compact) p,
.form-group-note--warning:not(.form-group-note--card):not(.form-group-note--compact) p {
    flex: 1 1 auto;
    min-width: 0;
}

/* The requester's own out-of-office reply, quoted under the banner's status line. As a
   plain paragraph beneath it the status read as the reply's first sentence (Shaun, 2026-10-05). */
.form-group-note__reply {
    border-left: 2px solid var(--info-status);
    padding-left: 1rem;
}

/* CC recipient review notices stack beneath the CC field rather than beside it */
.email-recipient-field {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.form-field-description {
    background-color: color-mix(in srgb, var(--grey-status) 40%, white);
}

.partner-directory-stats-cell {
    min-width: 28rem;
}

.partner-directory-stat {
    display: inline-flex;
    align-items: baseline;
    gap: 0.45rem;
    padding: 0.35rem 0.85rem;
    border: 1px solid var(--input-border);
    border-radius: 999px;
    background: var(--input-bg);
    color: var(--text-grey);
    font-size: 1.25rem;
    line-height: 1.3;
}

.partner-directory-stat strong {
    color: var(--tertiary-color-text);
    font-size: 1.4rem;
    font-weight: 900;
}

legend.ticket-reply-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    margin-bottom: 0.6rem;
    padding: 0;
    line-height: 1.2;
}

.partner-directory-stats__subtle {
    margin: 0.7rem 0 0;
    color: var(--text-grey);
    font-size: 1.25rem;
    line-height: 1.45;
}

@media (max-width: 900px) {
    .partner-directory-stats-cell {
        min-width: 22rem;
    }
}



.ticket-workspace-tab__status {
    align-items: center;
    display: inline-flex;
    flex: 0 0 auto;
    height: 1.35rem;
    justify-content: center;
    position: relative;
    width: 1.35rem;
}

.ticket-workspace-tab__status .ticket-workspace-tab__dirty {
    background: var(--amber-status);
    height: 0.9rem;
    left: 50%;
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 0.9rem;
    z-index: 0;
}



.ticket-workspace-pane .dropup .dropdown-menu > li > .dropdown-item {
    background-color: transparent;
    border: 0;
    color: inherit;
    text-align: left;
    width: 100%;
}

.ticket-workspace-panel {
    transform: translateY(0) scale(1);
    transform-origin: top center;
}



.ticket-workspace-shell--minimising .ticket-workspace-backdrop {
    opacity: 0 !important;
    pointer-events: none;
    visibility: hidden;
}

.ticket-workspace-panel.is-minimising {
    opacity: 0;
    pointer-events: none;
    transform: translateY(2.8rem) scale(0.985);
}

.ticket-workspace-shell--minimising .ticket-workspace-panel {
    opacity: 0 !important;
    pointer-events: none;
    transform: translateY(2.8rem) scale(0.985);
    visibility: hidden;
}

body:has(.ticket-workspace-shell.ticket-workspace-shell--has-bar) {
    overflow-x: hidden;
    padding-bottom: var(--ticket-workspace-bar-height, 6.4rem);
}

body:has(.ticket-workspace-shell):not(:has(.ticket-workspace-shell.ticket-workspace-shell--has-bar)) {
    padding-bottom: 0;
}

@media screen and (min-width: 700px) {
    body:has(.ticket-workspace-shell.ticket-workspace-shell--has-bar) > .d-flex {
        min-height: calc(100vh + var(--ticket-workspace-bar-height, 6.4rem));
        align-items: stretch;
    }

    body:has(.ticket-workspace-shell):not(:has(.ticket-workspace-shell.ticket-workspace-shell--has-bar)) > .d-flex {
        min-height: 100vh;
    }

    body:has(.ticket-workspace-shell.ticket-workspace-shell--has-bar) .sidebar {
        min-height: 100%;
    }
}

/* Shared Floating-UI tooltip (resources/js/tooltip.js), replacing
   bootstrap.Tooltip. Positioned via inline transform; visibility eased on the
   .app-tooltip--show class the JS toggles. */
.app-tooltip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100600;
    max-width: 28rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.4rem;
    background: #0d1117;
    color: #fff;
    font-size: 1.2rem;
    line-height: 1.4;
    pointer-events: none;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
    opacity: 0;
    transition: opacity 0.12s ease;
}

.app-tooltip--show {
    opacity: 1;
}

/* The "Submit as…" split-button menu is now opened by Alpine (the .show class
   on the <ul>), replacing bootstrap.Dropdown + Popper. Popper used to set the
   menu's base inset that the legacy -38px transform was tuned against; with it
   gone, place the dropup menu directly above the split button explicitly. */
.btn-group.dropup .dropdown-menu.show {
    bottom: 100%;
    top: auto;
    left: 0;
    right: auto;
    transform: none !important;
    margin-bottom: 0.4rem;

}

/* AIison's toggle is a plain header button (navigation-menu.blade.php) and her
   shell — now the panel alone — is mounted at layout level (layouts/app.blade.php),
   not inside `.settings-nav`. Two consequences:

   1. The settings-nav stacking context (z-index:1000) no longer needs dropping
      for the panel to climb above the ticket-workspace overlay (z-index:1060):
      the shell's own z-index:1100 resolves at the root.
   2. The panel no longer clears a floating toggle beneath it, so the
      `bottom: 4.85rem` (4.25rem on mobile) offset custom.css gives it is gone. */
.aiison-chat-panel {
    bottom: 0;
}

@media (max-width: 640px) {
    .aiison-chat-panel {
        bottom: 0;
    }
}

/* The ticket-workspace bar used to leave a 6.7rem left gap (and the mobile
   tabs-wrap a 5.8rem one) to clear the floating chat button. With the toggle
   in the header, the tabs can use that space. */
.ticket-workspace-bar {
    padding-left: 1.2rem;
}

.ticket-workspace-shell:not(.ticket-workspace-shell--has-bar) .ticket-workspace-bar {
    display: none !important;
}

.ticket-workspace-minimise-ghost-backdrop,
.ticket-workspace-minimise-ghost-panel {
    pointer-events: none;
    position: fixed;
    will-change: opacity, transform;
    z-index: 1061;
}

.ticket-workspace-minimise-ghost-backdrop {
    inset: 0;
    transition: opacity 0.18s ease;
}

.ticket-workspace-minimise-ghost-panel {
    transition: opacity 0.18s ease, transform 0.22s ease;
    transform: translateY(0) scale(1);
    transform-origin: top center;
}

.ticket-workspace-minimise-ghost-backdrop.is-animating {
    opacity: 0 !important;
}

.ticket-workspace-minimise-ghost-panel.is-animating {
    opacity: 0;
    transform: translateY(2.8rem) scale(0.985);
}

.ticket-table .ticket-presence-col .eye-idle {
    color: rgba(74, 93, 112, 0.65);
    opacity: 0.8;
}

.ticket-table .ticket-presence-col .eye-idle path {
    fill: currentColor;
}

/* Opt the SLA cell out of `.no-wrap-ellipsis-table`'s td truncation — the cell
   only contains the fixed-size SLA pill (plus a position:fixed popover that's
   already out of flow), so ellipsis has nothing useful to truncate and was
   surfacing as a stray "…" after the pill. */
.ticket-sla-col {
    overflow: visible;
}

.ticket-reference-link {
    cursor: pointer;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/*
 * Ticket workspace pane: header action buttons + sticky form button-wrap.
 *
 * The header has two action buttons (minimise and close). custom.css originally
 * styled the circle via `.ticket-workspace-pane__header .btn-close`, which only
 * matches the close button. The minimise button no longer carries the btn-close
 * class so we re-target the same circle styling at the shared modifier class.
 *
 * The form button-wrap (Submit/Cancel/Close) was previously commented out in
 * custom.css, leaving the buttons floating at the natural bottom of a long
 * scrolling form. Restore sticky positioning so they stay visible while the
 * pane scrolls.
 */
.ticket-workspace-pane__header .ticket-workspace-pane__action-btn {
    background: transparent;
    border: 1px solid var(--primary-color);
    border-radius: 50%;
    color: var(--primary-color);
    flex: 0 0 auto;
    height: 3.4rem;
    line-height: 1;
    padding: 0;
    width: 3.4rem;
}

.ticket-workspace-pane__action-btn {
    font-size: 1.4rem;
}

.ticket-workspace-pane__action-btn svg {
    height: 1.4rem;
    width: 1.4rem;
}
/*
.ticket-workspace-pane .form-content {
    padding: 1.8rem 2rem 1.2rem;
}

.ticket-workspace-pane .form-content-view,
.ticket-workspace-pane .form-content-edit,
.ticket-workspace-pane .form-content-create {
    padding-bottom: 1.2rem;
}
*/
/* Read-only ticket state: opt out of default.css's blanket
   `.form-content-view { opacity: .7 }` so labels, headings, comments and meta
   stay crisp in view/show. The fade is now opt-in per element via
   `.readonly-opacity` (applied in ticket-form.blade.php to the read-only field
   displays and the disabled Department/Type/Priority toggle groups). The
   `form-content-view` class stays on the wrapper, so default.css's `.btn-group`
   greying still applies. Adrian: the cleaner end-state is to delete the
   `.form-content-view{opacity:.7}` rule from default.css and drop this override. */
.ticket-workspace-pane .form-content-view {
    opacity: 1;
}

.ticket-form-inline-link[disabled] {
    opacity: 0.7;
    cursor: default;
    text-decoration: none;
    pointer-events: none;
}

.ticket-form-inline-link[disabled]:hover {
    color: var(--text-grey-light);
}

.ticket-settings-card .ticket-settings-field {
    display: grid;
    gap: 1.4rem;
    margin-bottom: 2rem;
}

.ticket-settings-card .ticket-settings-field__main {
    margin-bottom: 0;
    min-width: 0;
}

.ticket-settings-card .ticket-settings-field__info {
    align-content: start;
    border: 1px solid rgba(var(--amber-status-rgb), 0.55);
    border-radius: 1.2rem;
    display: grid;
    gap: 0.75rem;
    margin: 0;
    overflow-wrap: anywhere;
    padding: 1.4rem 1.6rem;
}

.ticket-settings-card .ticket-settings-field__info .form-group-note__label {
    font-size: 1.15rem;
    letter-spacing: 0.05em;
    margin: 0;
    text-transform: uppercase;
}

.ticket-settings-card .ticket-settings-field__info p {
    color: var(--text-grey);
    font-size: 1.3rem;
    line-height: 1.55;
    margin: 0;
}

.ticket-settings-card .ticket-settings-field__info code {
    overflow-wrap: anywhere;
    white-space: normal;
}

@media (min-width: 992px) {
    .ticket-settings-card .ticket-settings-field--with-info {
        align-items: start;
        grid-template-columns: minmax(0, 1fr) minmax(24rem, 30rem);
    }
}

.ticket-comment-stack > .ticket-comment-email-link {
    text-align: left;
}


.project-tickets-grid .modal-dialog {
    max-width: 1200px;
}

.project-tickets-grid td {
    vertical-align: top;
}

.project-tickets-grid textarea {
    resize: none;
    min-height: 0;
    height: auto;
    overflow: hidden;
    padding-top: 0.45rem;
    padding-bottom: 0.45rem;
    line-height: 1.5;
}

.spin svg,
.spin {
    animation: spin 1s linear infinite;
}
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* ── Round icon button fix ── */

.icon-btn-round {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.icon-btn-round svg {
    width: 1.6rem;
    height: 1.6rem;
}


.badge--project:not(.hidden) + .badge {
    margin-left: 0.3rem;
}

.badge--project:last-child,
.badge--project:has(+ .badge.hidden) {
    margin-right: calc(27px + 0.3rem);
}

.ticket-comment pre,
.ticket-comment code {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: anywhere;
    max-width: 100%;
}

.ticket-comment table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
}

.ticket-row--linkable {
    cursor: pointer;
}

.ticket-row--linkable:hover {
    background-color: var(--input-bg);
}

.tab-separator {
    color: var(--text-grey-light);
    padding: 0 0.2rem;
    pointer-events: none;
    user-select: none;
}


.badge--project-label {
    display: inline-block;
    font-size: inherit;
    font-weight: 600;
    padding: 0.1rem 0.5rem;
    border-radius: 0.3rem;
    border: 1px solid var(--text-grey-light);
    color: var(--text-grey-mid);
    vertical-align: baseline;
    margin-left: 0.4rem;
    white-space: nowrap;
}

/* ── Project task progress bar ── */

.project-task-progress {
    position: relative;
    min-width: 8rem;
    height: 2rem;
    background: var(--primary-color-tint);
    border-radius: 0.4rem;
    overflow: hidden;
}

.project-task-progress .progress-bar {
    background: var(--secondary-color);
    height: 100%;
    min-width: 2px;
    transition: width 0.3s ease;
}

.project-task-progress--empty {
    opacity: 0.4;
}

.project-task-progress::after {
    content: attr(data-label);
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-grey);
    pointer-events: none;
}

/* ── Team phone number row ── */

.grid-row-phone-number {
    display: grid;
    grid-template-columns: 1fr 1.5fr auto;
    gap: 0.8rem;
    align-items: start;
    margin-bottom: 0.6rem;
}

.grid-row-phone-number .form-group {
    margin-bottom: 0;
}

/* ── Project overdue indicator ── */

.project-overdue-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.8rem;
    border-radius: 0.4rem;
    background: var(--red-tint);
    color: var(--red-status);
    font-size: 1.2rem;
    font-weight: 600;
}

/* ── Project description & checklist show-mode styling ── */

.project-description-readonly {
    white-space: pre-line;
    background: var(--input-bg);
    border-radius: 0.8rem;
    padding: 1.2rem 1.4rem;
    font-size: 1.5rem;
    line-height: 1.6;
    color: var(--text-grey);
}

.checklist-editor {
    background: var(--input-bg);
    border: none;
}

/* Activity log */
.activity-log-wrap {
    margin-top: 0.5rem;
}

.activity-log-wrap .stacked-card-item {
    font-size: 1.3rem;
    line-height: 1.5;
}

.activity-log-wrap .stacked-card-item .form-group-note__subtle {
    font-size: 1.2rem;
}

.activity-log-value {
    font-weight: 500;
}

.activity-log-value--from {
    text-decoration: line-through;
    opacity: 0.65;
}

.activity-log-source {
    font-style: italic;
}

.activity-log-changes {
    list-style: disc;
    margin: 0.25rem 0 0 1.25rem;
    padding: 0;
    font-size: 1.3rem;
}

.activity-log-changes li {
    margin-bottom: 0.15rem;
}

.comments-wrap > [role="tablist"],
.comments-wrap > .d-flex > [role="tablist"] {
    margin-bottom: 0;
}

.comments-wrap > .d-flex {
    margin-bottom: 1.5rem;
}

/* Activity log truncation notice */
.activity-log-truncated-notice {
    text-align: center;
    color: #888;
    font-size: 1.2rem;
    padding: 1rem 0 0;
    margin: 0;
}

/* Activity log pagination (ticket form) */
.activity-log-pagination {
    padding: 1rem 0 0;
}

/* Additional-issue inline form on a comment action row */
.additional-issue-form {
    flex-basis: 100%;
    width: 100%;
    margin-top: 0.75rem;
    padding: 0.75rem;
    background: #f6f9fc;
    border: 1px solid #d9e2ec;
    border-radius: 6px;
}

.additional-issue-form__label {
    margin: 0 0 0.5rem;
    font-size: 1.2rem;
    font-weight: 600;
    color: #334e68;
}

.additional-issue-form__loading {
    margin: 0;
    font-size: 1.3rem;
    color: #52606d;
}

.additional-issue-form__actions {
    margin-top: 0.5rem;
}



/* External change surfacing: per-field markers, new-comment flash.
   The banner itself reuses the .ticket-dirty-summary--warning pattern. */


.external-change-field {
    position: relative;
    box-shadow: inset 3px 0 0 0 var(--amber-status);
    transition: box-shadow 150ms ease-out;
}

.external-change-marker {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: rgba(var(--amber-status-rgb), 0.16);
    border: 1px solid rgba(var(--amber-status-rgb), 0.55);
    color: var(--amber-status);
    font-size: 1.1rem;
    font-weight: 500;
    line-height: 1.3;
    vertical-align: middle;
}

.external-change-marker--conflict {
    background: rgba(var(--red-status-rgb), 0.12);
    border-color: rgba(var(--red-status-rgb), 0.45);
    color: var(--red-status);
}


.external-change-marker__accept:hover,
.external-change-marker__dismiss:hover {
    text-decoration: underline;
}

.new-comment-flash {
    animation: new-comment-flash-fade 10s ease-out forwards;
    box-shadow: inset 3px 0 0 0 var(--amber-status);
    background: rgba(var(--amber-status-rgb), 0.18);
    border-radius: 4px;
}

@keyframes new-comment-flash-fade {
    0% {
        background: rgba(var(--amber-status-rgb), 0.35);
    }
    70% {
        background: rgba(var(--amber-status-rgb), 0.18);
    }
    100% {
        background: transparent;
        box-shadow: none;
    }
}

.badge-new-comment {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: var(--amber-status);
    color: #ffffff;
    border-radius: 999px;
    font-size: 1.05rem;
    font-weight: 500;
    line-height: 1.3;
}

.ticket-feedback-option label {
    padding: 1.5rem 1.25rem;
}

.ticket-feedback-option label strong {
    font-size: 1.35rem;
    margin-bottom: 0;
}

.ticket-secret-card textarea {
    width: 100%;
    min-height: 140px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.95rem;
}

.ticket-secret-payload {
    display: block;
    width: 100%;
    max-width: 100%;
    margin: 1rem 0;
    padding: 0.9rem 1rem;
    background: #f6f6f6;
    border: 1px solid #ddd;
    border-radius: 6px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.95rem;
    white-space: pre-wrap;
    word-break: break-all;
}

.ticket-secret-reveal-btn {
    display: inline-block;
    padding: 0.15rem 0.75rem;
    margin: 0 0.15rem;
    background: #111827;
    color: #ffffff;
    border: none;
    border-radius: 999px;
    font-weight: 600;
    font-size: 0.9em;
    cursor: pointer;
}

.ticket-secret-reveal-btn:hover {
    background: #374151;
}

.ticket-comment-flash {
    animation: ticket-comment-flash-fade 3s ease-out forwards;
}

@keyframes ticket-comment-flash-fade {
    0% {
        background-color: rgba(var(--amber-status-rgb), 0.35);
        box-shadow: 0 0 0 3px rgba(var(--amber-status-rgb), 0.55);
    }
    100% {
        background-color: transparent;
        box-shadow: 0 0 0 3px rgba(var(--amber-status-rgb), 0);
    }
}



/* Three-state matrix cell: tick / cross / clock. Renders as a glyph
   rather than a coloured square so it reads as "ran / failed / waiting"
   at a glance without the viewer needing to learn a colour key. */
.ce-matrix-dot {
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 16px;
    font-size: 14px;
    text-align: center;
    vertical-align: middle;
    background: transparent;
}

.ce-matrix-dot--ok {
    color: var(--green-status);
    font-weight: 900;
}
.ce-matrix-dot--ok::before {
    content: '\2713';   /* ✓ check mark */
    display: block;
}

.ce-matrix-dot--alert {
    color: var(--red-status);
    font-weight: 900;
}
.ce-matrix-dot--alert::before {
    content: '\2715';   /* ✕ light multiplication sign */
    display: block;
}

.ce-matrix-dot--waiting {
    color: #7a8a9a;
    font-size: 14px;
    font-weight: 900;
}
.ce-matrix-dot--waiting::before {
    content: '\29D6'; /* ⧖ white hourglass — script still pending */
    display: block;
}

.ce-matrix-dot--expired {
    color: #7a3b4a;
    font-size: 14px;
    font-weight: 900;
}
.ce-matrix-dot--expired::before {
    content: '\29D7'; /* ⧗ black hourglass — dispatch window passed without running */
    display: block;
}


/* Cyber Essentials findings drilldown (offcanvas) */
.ce-drilldown { padding-top: 4px; }

.ce-drill-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 12px;
}

.ce-drill-row {
    border: 1px solid #d6dee8;
    border-radius: 8px;
    background: #ffffff;
    overflow: hidden;
}

.ce-drill-row__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 14px;
    border: none;
    background: #f7fafc;
    color: inherit;
    font-size: 1.4rem;
    text-align: left;
    cursor: pointer;
}

.ce-drill-row__header:hover { background: #edf2f7; }

.ce-drill-row__bar {
    display: flex;
    align-items: stretch;
    background: #f7fafc;
    border-bottom: 1px solid transparent;
}

.ce-drill-row__bar .ce-drill-row__header {
    flex: 1;
    background: transparent;
}

.ce-drill-row__actions {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border-left: 1px solid #e1e7ee;
}

.ce-drill-row__actions .btn {
    font-size: 1.2rem;
    padding: 4px 10px;
    white-space: nowrap;
}

/* Top toolbar: help text on the left, "Re-run all" + "…" button cluster
   on the right. The CE drilldown lives inside a narrow offcanvas; without
   a `flex-wrap: wrap` the help text collapses into a tall single-column
   tower and the trigger gets squeezed. */
.ce-drill-toolbar {
    gap: 8px 16px;
}

.ce-drill-toolbar .help-text {
    flex: 1 1 240px;
    min-width: 0;
}

.ce-drill-actions,
.ce-drill-row-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/* Floating-popover "More actions" cluster — mirrors the ticket-list
   suspended-more-actions pattern. The popover content is positioned by
   floating-popovers.js (off-screen at -9999px until .is-open flips it in)
   so the menu can escape the narrow offcanvas without being clipped. */
.ce-more-actions {
    position: relative;
    display: inline-flex;
    z-index: 5;
}

.ce-more-actions.is-open {
    z-index: 300;
}

.ce-more-trigger {
    min-width: 36px;
    padding-left: 0.65rem;
    padding-right: 0.65rem;
    text-align: center;
    letter-spacing: 0.06em;
    line-height: 1;
}

.ce-more-menu {
    position: fixed;
    left: -9999px;
    top: -9999px;
    z-index: 301;
    min-width: 220px;
    padding: 8px;
    border: 1px solid var(--input-border);
    border-radius: var(--radius-sm);
    background: var(--white-text);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
    display: none;
    flex-direction: column;
    gap: 6px;
}

.ce-more-actions.is-open .ce-more-menu {
    display: flex;
}

.ce-drill-row__chevron {
    color: #5f7085;
    font-size: 1.3rem;
    margin-left: 10px;
}

.ce-drill-panel__body {
    padding: 12px 14px 14px;
    border-top: 1px solid #edf1f5;
}

.ce-drill-panel__meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 8px 16px;
    margin: 0 0 12px;
}

.ce-drill-panel__meta div { margin: 0; }
.ce-drill-panel__meta dt {
    color: #5f7085;
    font-size: 1.2rem;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.ce-drill-panel__meta dd { margin: 2px 0 0; color: var(--primary-color); font-size: 1.35rem; }


.ce-drill-evidence {
    margin: 0;
    padding: 8px 10px;
    max-height: 320px;
    overflow: auto;
    background: #0f1d2b;
    color: #e6eef6;
    border-radius: 6px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 1.2rem;
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-word;
}

.ce-drill-evidence {
    max-height: 160px;
    background: #f3f6fa;
    color: var(--primary-color);
}

.ce-drill-errors {
    margin: 0;
    padding-left: 18px;
    color: #9f2d2d;
    font-size: 1.3rem;
}

/* Pending badge with spinner (findings tabs + drilldowns) */
.ce-pending-badge {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 2px 10px 2px 6px;
    border-radius: 999px;
    background: rgba(4, 175, 218, 0.12);
    color: #046b88;
    font-size: 1.25rem;
    font-weight: 600;
}

.ce-pending-badge__spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(4, 175, 218, 0.35);
    border-top-color: #046b88;
    border-radius: 50%;
    animation: ce-pending-spin 0.9s linear infinite;
}

@keyframes ce-pending-spin {
    to { transform: rotate(360deg); }
}

.ce-drill-row__connectivity {
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 1.2rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: lowercase;
}

.ce-drill-row__connectivity--online {
    background: rgba(var(--green-status-rgb), 0.18);
    color: #2f5f1c;
}

.ce-unreachable-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    background: #edf1f5;
    color: #5f7085;
    font-size: 1.25rem;
    font-weight: 600;
}

.ce-removed-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    background: #f1e3e7;
    color: #7a3b4a;
    font-size: 1.25rem;
    font-weight: 600;
    text-decoration: line-through;
}

.ce-device-row--removed td:first-child {
    text-decoration: line-through;
    color: #7a3b4a;
}

.ce-check-bar__item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 140px;
}

.ce-check-bar__label {
    font-size: 1.1rem;
    font-weight: 900;

}

.ce-check-bar__value {
    color: var(--primary-color);
    font-size: 1.4rem;
}

.ce-check-bar__action {
    margin-left: auto;
}

.table-filter-row th {
    font-weight: normal;
}

[x-cloak] {
    display: none !important;
}

.ticket-bulk-actions-group {
    display: inline-flex;
    margin-right: 24px;
    vertical-align: top;
}

.ticket-bulk-actions-group.is-empty {
    display: none;
}

.ticket-bulk-actions-group__count {
    font-size: 1.4rem;
    font-weight: 600;
    color: var(--text-grey);
    white-space: nowrap;
}

/* Cyber Essentials finding cards (agent-friendly view) */
.ce-finding-counts {
    margin: 4px 0 12px;
}

.ce-finding-counts__item {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 4px 10px 4px 8px;
    border-radius: 999px;
    background: #edf1f5;
    color: var(--primary-color);
    font-size: 1.2rem;
    font-weight: 600;
}

.ce-finding-counts__item--alert {
    background: rgba(var(--red-status-rgb, 212, 78, 78), 0.14);
    color: #8a1f2a;
}

.ce-finding-counts__item--warning {
    background: rgba(var(--amber-status-rgb, 242, 172, 58), 0.18);
    color: #7a4600;
}

.ce-finding-counts__item--ok {
    background: rgba(var(--green-status-rgb, 92, 168, 87), 0.16);
    color: #265c23;
}

.ce-finding-counts__item--unknown {
    background: #e3e7ec;
    color: #4a5b73;
}

.ce-finding-counts__num {
    font-size: 1.5rem;
    font-weight: 900;
}

.ce-finding-list {
    list-style: none;
    margin: 0 0 12px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ce-finding-card {
    padding: 12px 14px;
    border: 1px solid #dde4ec;
    border-left: 4px solid #c0cad5;
    border-radius: 8px;
    background: #ffffff;
}

.ce-finding-card--fail {
    border-left-color: #d44e4e;
    background: #fff7f7;
}

.ce-finding-card--warning {
    border-left-color: #f2ac3a;
    background: #fffaf1;
}

.ce-finding-card--manual_review {
    border-left-color: #6a7b93;
    background: #f7f9fc;
}

.ce-finding-card--pass {
    border-left-color: #5ca857;
}

.ce-finding-card--not_applicable {
    border-left-color: #b5bec9;
    background: #fafbfd;
}

.ce-finding-card__header {
    margin-bottom: 6px;
}

.ce-finding-card__title {
    color: #0f2235;
    font-size: 1.4rem;
    font-weight: 600;
}

.ce-finding-card__chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(4, 175, 218, 0.12);
    color: #046b88;
    font-size: 1.2rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

/* Warning variant of the control-area chip — same soft-tint-plus-darker-text
 * shape as the base cyan chip, in the CE amber (#f2ac3a). Used for the
 * "Reverted since last audit" chip so it reads as a warning, not a neutral
 * label. */
.ce-finding-card__chip--warning {
    background: rgba(242, 172, 58, 0.16);
    color: #8a5a10;
}

.ce-finding-card__status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.ce-finding-card__status-meta {
    color: #5f7085;
    font-size: 1.2rem;
    font-style: italic;
}

.ce-finding-facts {
    margin: 0 0 10px;
    padding: 10px 12px;
    border: 1px solid #e3e8ef;
    border-radius: 6px;
    background: #fbfcfe;
    display: grid;
    gap: 6px 16px;
}

.ce-finding-facts__row {
    display: grid;
    grid-template-columns: 190px 1fr;
    gap: 8px 16px;
    align-items: start;
    padding: 2px 0;
}

.ce-finding-facts__row dt {
    color: #5f7085;
    font-size: 1.2rem;
    font-weight: 900;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin: 0;
}

.ce-finding-facts__row dd {
    margin: 0;
    color: var(--primary-color);
    font-size: 1.3rem;
    word-break: break-word;
}

.ce-finding-facts__row--ok dd > span:first-child { color: #265c23; font-weight: 600; }
.ce-finding-facts__row--alert dd > span:first-child { color: #8a1f2a; font-weight: 600; }
.ce-finding-facts__row--warning dd > span:first-child { color: #7a4600; font-weight: 600; }
.ce-finding-facts__row--neutral dd > span:first-child { color: var(--primary-color); }

.ce-finding-facts__items {
    margin: 4px 0 0;
    padding-left: 16px;
    color: var(--primary-color);
    font-size: 1.25rem;
    line-height: 1.55;
}

.ce-finding-facts__items li + li { margin-top: 2px; }

.ce-finding-card__note {
    margin: 0 0 10px;
    padding: 8px 10px;
    border-left: 3px solid #c0cad5;
    background: #f4f7fb;
    color: #34495f;
    font-size: 1.2rem;
    line-height: 1.5;
}

.ce-finding-card__remediation {
    margin: 0 0 8px;
    padding: 8px 10px;
    border: 1px dashed #c7a24a;
    border-radius: 6px;
    background: #fff8e5;
}

.ce-finding-card__remediation--done {
    border-style: solid;
    border-color: var(--green-status);
    background:  var(--green-status-tint);
}

.ce-finding-card__remediation-label {
    color: #7a4600;
    font-size: 1.2em;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-bottom: 4px;
}

.ce-finding-card__remediation--done .ce-finding-card__remediation-label {
    color: #265c23;
}

.ce-finding-card__remediation-value {
    display: block;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 1.25rem;
    color: var(--primary-color);
    word-break: break-word;
    white-space: pre-wrap;
    background: transparent;
    padding: 0;
}

.ce-finding-card__raw {
    margin: 6px 0 6px;
}

.ce-finding-card__raw > summary {
    cursor: pointer;
    font-size: 1.2rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 2px 0;
}

.ce-finding-card__raw[open] > summary { margin-bottom: 4px; }

.ce-finding-card__meta {
    margin-top: 4px;
    font-size: 1.1rem;
}

.ce-finding-card__meta code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 1.2rem;
    background: transparent;
    padding: 0;
}

.ce-passed-details {
    margin: 8px 0 12px;
    border: 1px solid #dde4ec;
    border-radius: 8px;
    background: #fbfcfe;
}

.ce-passed-details[open] { padding-bottom: 8px; }

.ce-passed-details > summary {
    cursor: pointer;
    padding: 10px 14px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: var(--primary-color);
    font-size: 1.3rem;
    font-weight: 600;
    list-style: none;
}

.ce-passed-details > summary::-webkit-details-marker { display: none; }

.ce-passed-details__chevron {
    font-size: 1.2rem;
    transition: transform 0.15s ease;
}

.ce-passed-details[open] .ce-passed-details__chevron {
    transform: rotate(90deg);
}

.ce-passed-details > .ce-finding-list {
    margin: 0 12px 0;
}

.ce-raw-details {
    margin-top: 12px;
}

.ce-raw-details > summary {
    cursor: pointer;
    color: #5f7085;
    font-size: 1.2rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.ce-raw-details[open] > summary { margin-bottom: 6px; }

/* Cyber Essentials environmental-failure statuses (access_denied / timeout /
   error). These are "couldn't run" signals from the audit scripts — distinct
   from pass/fail compliance verdicts. See scripts/datto_rmm/PREFLIGHT_SPEC.md.
   Reuses the existing brand-status palette (amber / info / grey) rather than
   introducing new hues — back-to-basics colour discipline. */

/* Inline status badges on finding cards */
.ce-env-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 10px 2px 8px;
    border-radius: 999px;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.4;
}

.ce-env-badge__icon {
    display: inline-flex;
    align-items: center;
    font-size: 1.3rem;
    line-height: 1;
}



/* timeout — info family (cyan, investigate daemon / probe health) */
.ce-env-badge--timeout {
    color: var(--info-status);
    border: 1px solid var(--info-status);
}

/* error — grey family (no signal, script-side exception worth engineer review) */
.ce-env-badge--error {
    background: color-mix(in srgb, var(--grey-status) 40%, white);
    color: var(--primary-color);
    border: 1px solid var(--grey-status);
}

/* Counts strip variants — match ce-finding-counts__item--ok/alert/warning */
.ce-finding-counts__item--denied {
    background: var(--amber-status-tint);
    color: var(--amber-status);
}

.ce-finding-counts__item--timeout {
    background: var(--info-status-tint);
    color: var(--info-status);
}

.ce-finding-counts__item--error {
    background: color-mix(in srgb, var(--grey-status) 40%, white);
    color: var(--primary-color);
}

/* Finding-card border-left variants — match ce-finding-card--fail/warning */
.ce-finding-card--access_denied {
    border-left-color: var(--amber-status);
    background: var(--amber-status-tint);
}

.ce-finding-card--timeout {
    border-left-color: var(--info-status);
    background: var(--info-status-tint);
}

.ce-finding-card--error {
    border-left-color: var(--grey-status);
    background: color-mix(in srgb, var(--grey-status) 30%, white);
}

/* "Could not assess" details block — uses the amber tint (most env failures
   are permissions-denied, which dominate the section's visual signal). */
.ce-env-details {
    background: var(--amber-status-tint);
}

/* Drilldown row status marker — matches existing status-marker-ok/alert
   convention. Driven by the $rowStatus = 'denied' branch in the two
   drilldown blade views. */
.status-marker-denied {
    color: var(--amber-status);
}

.status-marker-denied:before {
    background-color: var(--amber-status);
}

/* Summary tiles — surfaced only when env-status counts are non-zero. */
.ce-summary-tile--denied {
    background: var(--amber-status-tint);
}

.ce-summary-tile--denied .ce-summary-tile__value {
    color: var(--amber-status);
}

.ce-summary-tile--timeout {
    background: var(--info-status-tint);
    border-color: var(--info-status);
}

.ce-summary-tile--timeout .ce-summary-tile__value {
    color: var(--info-status);
}

.ce-summary-tile--error {
    background: color-mix(in srgb, var(--grey-status) 40%, white);
    border-color: var(--grey-status);
}

.ce-summary-tile--error .ce-summary-tile__value {
    color: var(--primary-color);
}

/* Software catalogue queue */
.sc-queue-table td {
    vertical-align: middle;
}

.sc-queue-actions .form-control-sm {
    font-size: 1.2rem;
    padding: 4px 8px;
}

.sc-status {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 1.15rem;
    font-weight: 600;
    text-transform: capitalize;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.sc-status--ambiguous_review_needed { background: #fff4d6; color: #7a4600; }
.sc-status--no_upstream_data        { background: #edf1f5; color: #5f7085; }
.sc-status--unmapped                { background: #e3e7ec; color: #4a5b73; }
.sc-status--auto_mapped             { background: rgba(var(--green-status-rgb, 92, 168, 87), 0.16); color: #265c23; }
.sc-status--manually_mapped         { background: rgba(4, 175, 218, 0.14); color: #046b88; }

.sc-device-count {
    display: inline-block;
    min-width: 36px;
    padding: 2px 8px;
    border-radius: 999px;
    background: #edf1f5;
    color: var(--primary-color);
    font-weight: 600;
    text-align: center;
}

.sc-version-row > td {
    background: #f7fafc;
    border-top: 1px solid #d6dee8;
}

.sc-version-editor {
    padding: 8px 4px;
}

.sc-version-table {
    margin-top: 6px;
    background: #ffffff;
}

.sc-version-table th, .sc-version-table td {
    padding: 6px 10px;
}



/* Updated-column author indicators (added beyond agent/requester/waiting in custom.css) */
.ticket-updated-indicator--ai {
    color: var(--green-status);
}

.ticket-updated-indicator--partner {
    color: var(--amber-status);
}


.home-team-card {
    grid-template-rows: 3rem auto 1fr;
}

.home-team-card__header {
    min-height: 3rem;
}

.home-team-card__meta {
    align-self: end;
}

.home-team-card--add {
    align-content: stretch;
    opacity: 0.5;
    transition: opacity 0.15s ease;
}

.ticket-comment-automation-badge {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    margin-left: 0.25rem;
    border-radius: 0.25rem;
    background: linear-gradient(90deg, #e0d4ff, #c7d8ff);
    color: #3b2c7a;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    vertical-align: 0.05em;
    border: 1px solid #b9a7ee;
    cursor: help;
}



.btn-outline-priority-urgent {
    border: 1px solid var(--primary-color);
    color: var(--red-status);
    background-color: var(--white-bg);
    font-weight: 600;
}

.btn-outline-priority-urgent:hover {
    background-color: rgba(var(--red-status-rgb), 0.08);
    color: var(--red-status);
}

.btn-check:checked + .btn-outline-priority-urgent {
    background-color: var(--red-status);
    color: var(--white-text);
}

.btn-outline-priority-high {
    border: 1px solid var(--primary-color);
    color: var(--amber-status);
    background-color: var(--white-bg);
    font-weight: 600;
}

.btn-outline-priority-high:hover {
    background-color: rgba(var(--amber-status-rgb), 0.08);
    color: var(--amber-status);
}

.btn-check:checked + .btn-outline-priority-high {
    background-color: var(--amber-status);
    color: var(--white-text);
}

.ticket-settings-css-editor .CodeMirror {
    border: 1px solid #d1d5db;
    border-radius: 0.375rem;
    height: auto;
    min-height: 8rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 1rem;
    line-height: 1.5;
}

.ticket-settings-css-editor .CodeMirror-scroll {
    min-height: 8rem;
}

.ticket-filter-field-spinner {
    top: 50%;
    right: 22px;
    width: 14px;
    height: 14px;
    margin-top: -7px;
    border: 2px solid var(--light-grey);
    border-top-color: var(--text-grey);
    border-radius: 50%;
    animation: lw-loading-spin .8s linear infinite;
    pointer-events: none;
    z-index: 2;
}

/* ===== Organisational chart (assets/users → Organisational chart tab) ===== */

.organisation-chart-wrap {
    overflow: visible;
}

/* Kill the legacy default.css rule that pins overflow-y: scroll on every
   .organisation-chart:first-of-type (which is every nested chart too). */
.organisation-chart-wrap .organisation-chart {
    overflow: visible;
}

.organisation-chart,
.organisation-chart ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.organisation-chart li {
    margin: 0;
    padding: 0;
    font-size: 1.3rem;
    flex: none;
}

.organisation-chart li small,
.organisation-chart-unlinked__list .card small {
    display: block;
    margin-top: 2px;
    font-size: 1.2rem;
    color: var(--text-grey, #64748b);
}

.organisation-chart li .card {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 200px;
    max-width: 240px;
    padding: 0.75rem 1rem;
    border-radius: 10px;
    margin: 0;
    text-align: left;
    position: relative;
    z-index: 1;
}

.organisation-chart li .card > img,
.organisation-chart-unlinked__list .card > img {
    flex: none;
    width: 40px;
    height: 40px;
    margin: 0;
    border-radius: 50%;
    object-fit: cover;
}

.organisation-chart li .card > span,
.organisation-chart-unlinked__list .card > span {
    flex: 1;
    min-width: 0;
    word-break: break-word;
}

.organisation-chart li .card a,
.organisation-chart li .card .tel-link {
    margin-right: 4px;
}

/* Connector line colour (single source of truth) */
.organisation-chart-wrap {
    --org-line: #cbd5e1;
    --org-line-size: 2px;
    --org-line-gap: 1.75rem;
}

/* ----- Outer row: roots ----- */
.organisation-chart-wrap > .organisation-chart {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: flex-start;
    gap: 3rem;
    flex-wrap: wrap;
    overflow: visible;
}

.organisation-chart-wrap > .organisation-chart > li {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* ----- Level 2: direct reports of a root → horizontal row with connectors ----- */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: flex-start;
    flex-wrap: nowrap;
    position: relative;
    padding-top: var(--org-line-gap);
    margin-top: 0;
    max-width: none;
}

/* Vertical drop from parent card into the child row */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: var(--org-line-size);
    height: var(--org-line-gap);
    background: var(--org-line);
    transform: translateX(-50%);
}

.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li {
    position: relative;
    padding: var(--org-line-gap) 1rem 0 1rem;
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* Horizontal sibling bar */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: var(--org-line-size);
    background: var(--org-line);
}

.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li:first-child::before {
    left: 50%;
}

.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li:last-child::before {
    right: 50%;
}

.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li:only-child::before {
    display: none;
}

/* Vertical stub from sibling bar down to each card */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li::after {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: var(--org-line-size);
    height: var(--org-line-gap);
    background: var(--org-line);
    transform: translateX(-50%);
}

/* ----- Level 3+: vertical chain (one card per row, spine + stub) ----- */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    align-self: center;
    flex-wrap: nowrap;
    position: relative;
    margin-top: 0;
    padding: var(--org-line-gap) 0 0 1.5rem;
    max-width: none;
}

/* Top L-connector — vertical drops from the parent card's centre */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart::before,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: var(--org-line-size);
    height: calc(var(--org-line-gap) - 2px);
    background: var(--org-line);
    transform: translateX(-1px);
}

/* Top L-connector — horizontal from the spine across to the parent centre */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart::after,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart::after {
    content: '';
    position: absolute;
    top: calc(var(--org-line-gap) - 2px);
    left: 1.5rem;
    width: calc(50% - 1.5rem);
    height: var(--org-line-size);
    background: var(--org-line);
}

.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart > li,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart > li {
    position: relative;
    padding: 0.5rem 0 0.5rem 1.5rem;
    display: block;
    align-self: stretch;
}

/* Per-li spine fragment (drawn behind the card so the chain reads as one line) */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart > li::after,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart > li::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: var(--org-line-size);
    background: var(--org-line);
    transform: translateX(-1px);
    z-index: 0;
}

/* Last child (and only child): spine stops at its midpoint so it doesn't overshoot */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart > li:last-child::after,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart > li:last-child::after {
    bottom: calc(50% - 1px);
}

/* Horizontal stub from spine to each card */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart > li::before,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart > li::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    width: 1.5rem;
    height: var(--org-line-size);
    background: var(--org-line);
    transform: translateY(-50%);
    z-index: 0;
}

/* Cards inside a vertical chain — left-aligned, capped width */
.organisation-chart-wrap > .organisation-chart > li > .organisation-chart > li > .organisation-chart > li > .card,
.organisation-chart-wrap .organisation-chart .organisation-chart .organisation-chart > li > .card {
    display: inline-flex;
    width: auto;
    max-width: 240px;
    margin: 0;
}

/* ===== Unlinked users (users with no parent_id and no children) ===== */

.organisation-chart-unlinked {
    margin-top: 3rem;
    padding: 2rem 1rem 0 1rem;
    border-top: 1px solid var(--light-grey, #e2e8f0);
}

.organisation-chart-unlinked__title {
    margin: 0 0 0.25rem 0;
    font-size: 1.6rem;
    font-weight: 600;
}

.organisation-chart-unlinked__hint {
    margin: 0 0 1.25rem 0;
    font-size: 1.3rem;
    color: var(--text-grey, #64748b);
}

.organisation-chart-unlinked__list {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.organisation-chart-unlinked__list > li {
    margin: 0;
    padding: 0;
}

.organisation-chart-unlinked__list .card {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
    padding: 0.75rem 1rem;
    border-radius: 10px;
    margin: 0;
    font-size: 1.3rem;
}

/* --- QBR — top-of-page audit summary ---
 * Two stacked rows: the overall score gauge sits on its own with a
 * short explanation paragraph, then the six-up control breakdown
 * row beneath it. Each breakdown tile links to that pillar's
 * drill-down page so partners can scan + click straight to the
 * offending devices.
 */
.qbr-audit-overall {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding: 1.25rem 1.5rem;
    margin: 1.25rem 0 1rem;
    background: var(--tint-background);
    border-radius: 6px;
}

@media (max-width: 640px) {
    .qbr-audit-overall { flex-direction: column; align-items: flex-start; gap: 1rem; }
}

/* 5-column breakdown (one gauge per CE pillar). Auto-fit so the
 * layout still balances if a pillar is omitted (e.g. User access
 * gauge skipped when M365 isn't connected). No utility class exists
 * for 5-col, so this is a custom rule. */
.qbr-audit-breakdown {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0.75rem;
    margin: 0 0 1.25rem;
}
@media (max-width: 900px) {
    .qbr-audit-breakdown { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 540px) {
    .qbr-audit-breakdown { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.qbr-audit-breakdown__tile-sub {
    color: var(--primary-color);
    font-weight: 500;
}


/* QBR drill-down modals need much more width than the Jetstream
 * default (.jetstream-modal > div:last-child {max-width: 500px}) to
 * fit the device / ticket / user tables. The :has() override targets
 * only modals whose content slot opts in via .qbr-modal-wide.
 *
 * Size to content rather than a fixed cap: the Jetstream panel is
 * `sm:w-full`, so a fixed max-width makes every wide modal that exact
 * width and forces wide tables (e.g. the OAuth-scopes list) into a
 * horizontal scrollbar. `fit-content` lets the panel grow with its
 * content — wide tables get the room they need, narrow ones stay
 * compact — bounded by a min-width (so sparse modals aren't cramped)
 * and a max-width (so it doesn't sprawl on very large monitors). The
 * inner .table-wrap remains as a last-resort scroll for content that
 * can't fit even at the cap. */
.jetstream-modal:has(.modal-wide) > div:last-child {
    width: fit-content !important;
    min-width: min(700px, 95vw) !important;
    max-width: min(1600px, 95vw) !important;
}

/* The shared modal shell's wide size (openModalComponent(..., { size: 'wide' })).
 * The default dialog is capped at 870px, which leaves a table's last column —
 * usually the one you act on — off the right edge behind a scrollbar. */
#modal .modal-dialog.modal-dialog--wide {
    max-width: min(1320px, 96vw);
}

/* The row a modal was opened about (the OAuth app an alert named): the same
 * amber pop as a comment that arrived while the ticket was open
 * (.new-comment-flash), painted on the cells because a table row's own
 * background and inset shadow don't paint reliably across browsers. */
tr.modal-focus-row > td {
    animation: modal-focus-row-fade 10s ease-out forwards;
}

tr.modal-focus-row > td:first-child {
    animation-name: modal-focus-row-fade-edge;
}

@keyframes modal-focus-row-fade {
    0% { background: rgba(var(--amber-status-rgb), 0.35); }
    70% { background: rgba(var(--amber-status-rgb), 0.18); }
    100% { background: transparent; }
}

@keyframes modal-focus-row-fade-edge {
    0% { background: rgba(var(--amber-status-rgb), 0.35); box-shadow: inset 3px 0 0 0 var(--amber-status); }
    70% { background: rgba(var(--amber-status-rgb), 0.18); box-shadow: inset 3px 0 0 0 var(--amber-status); }
    100% { background: transparent; box-shadow: none; }
}

.shadow-saas-approve-btn {
    white-space: nowrap;
}

.shadow-saas-focus-missing {
    margin: 0 0 1.5rem;
    padding: 0.9rem 1.1rem;
    border-left: 3px solid var(--amber-status);
    background: rgba(var(--amber-status-rgb), 0.12);
    border-radius: 4px;
}

/* Modal loading/saving overlay — matches the ticket-form loading overlay
 * (.lw-loading-overlay base: translucent dark dim so the form stays visible
 * through it + a centred spinner pill) for a consistent look across the app.
 * The form stays in the DOM (wire:loading.remove removed from the form), so
 * the dim + spinner reads as "working", and the overlay blocks interaction. */
/* Glimmer skeleton shown in the modal body while content loads (mirrors a
 * form), in place of a dim+spinner overlay on open. */
.common-modal-loading {
    display: flex;
    flex-direction: column;
    gap: 1.2rem;
    padding: 1.5rem 2rem 2rem;
}
.common-modal-loading__field {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}



/* While the cover is up, hide the real header/body so the modal is sized by the
   skeleton (stable width) and the previous modal's content is never revealed. */
#modal.lw-modal-loading .modal-content > .modal-header,
#modal.lw-modal-loading .modal-content > .modal-body {
    display: none;
}

/* Session-expiry warning is non-dismissable and blocks the page; lock scroll
   behind it. bootstrap.Modal used to add body.modal-open for this — now that the
   modal is class-toggled (no bootstrap), reproduce the scroll-lock here. */
body.session-expiry-open {
    overflow: hidden;
}



/* Muted separator in the Home tablist dividing the core tabs from the
   Agent Health / Microsoft 365 group. Not a tab (aria-hidden in markup). */
[role="tablist"] li.tab-divider {
    user-select: none;
}





/* ── Datto freshness badge (livewire/devices/datto-freshness-badge) ──
   "Updated X ago" + Refresh control shown on any surface backed by Datto
   data. Reuses the shared `spin` keyframe defined above. */


.datto-freshness__status--refreshing {
    color: var(--text-grey);
    font-style: italic;
}
.datto-freshness__spinner {
    width: 12px;
    height: 12px;
    border: 2px solid var(--light-grey);
    border-top-color: var(--text-grey);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}
.datto-freshness__refresh {

    padding: 0.1rem 0.5rem;
    font-size: 11px;
    line-height: 1.4;
    cursor: pointer;
}



/* Leaflet site-planning map on the home dashboard. Leaflet needs an explicit
 * height on its container or the map collapses to 0px and tiles never show. */
.site-map {
    height: 600px;
    width: 100%;
    border-radius: 8px;
    margin-top: 1rem;
}

/* Cyber Essentials — client-facing per-device readiness grid (CE dashboard
 * Overview tab). Composes the existing .pill / *-bg-tint utilities; only the
 * round status dot, the cell padding and the grid's centred alignment are
 * bespoke. Dot colours reuse the site status palette (saturated solids, not
 * the light card tints) so a row of five reads at a glance. */
.ce-readiness-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}
/* Queued / error dot states are emitted by ce-device-readiness.blade.php and
   live-matrix.blade.php but previously had no definition, rendering invisible
   white-on-white glyphs. Queued reads informational (work in flight); error
   shares the amber "needs a human" tone with review — the ⚠ glyph keeps the
   two distinguishable. */
.ce-readiness-dot--queued {
    background: var(--info-status);
}
.ce-readiness-dot--error {
    background: var(--amber-status);
}
/* Accepted = the control holds on a documented, expiring human acceptance
   (ce_finding_reviews) rather than a clean technical pass — green, but with
   an amber ring so it never silently reads as plain compliant. */
.ce-readiness-dot--accepted {
    background: var(--green-status);
    box-shadow: 0 0 0 2px var(--amber-status);
}
.ce-readiness__legend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* Workload bar — INTERIM baseline (Adrian on leave); refine to house style.
   Structure from workload-dashboard.blade.php: track + fill, fill width set inline
   (the datum), band colour via the --rag modifier reusing the status tokens. */
.workload-bar {
    display: block;
    width: 100%;
    max-width: 160px;
    height: 0.6rem;
    margin-top: 0.4rem;
    background: var(--grey-status-tint, #e9edf2);
    border-radius: 999px;
    overflow: hidden;
}
.workload-bar__fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--grey-status, #64748b);
}
.workload-bar__fill--info { background: var(--info-status, #00a1d4); }
.workload-bar__fill--pass { background: var(--green-status, #16a34a); }
.workload-bar__fill--review { background: var(--amber-status, #d97706); }
.workload-bar__fill--action { background: var(--red-status, #dc2626); }
.workload-bar__fill--not_assessed { background: var(--grey-status, #64748b); }
/* Workload drill-down charts — INTERIM (Adrian on leave); refine to house style.
   Responsive wrap grid so the Workload/Load/Pressure/Touches/Solved cards stack
   instead of forcing a horizontal scrollbar, and the SVGs scale to their cell
   (viewBox already set) rather than overflowing at their fixed 320px width. */
.workload-chart {
    min-width: 0;
}
.workload-chart .workload-sparkline {
    width: 100%;
    height: auto;
    max-width: 100%;
}
/* My Work single-person workload — INTERIM (Adrian on leave); refine to house style. */
.workload-solo__headline {
    margin: 0.5rem 0 0.75rem;
    font-size: 1.15rem;
}
.workload-bar--solo {
    max-width: 360px;
    height: 0.8rem;
}
/* Cap the single-person view so it doesn't stretch edge-to-edge on wide
   monitors, and pack the summary tiles into a responsive grid instead of the
   flex row that left big gaps. INTERIM (Adrian on leave). */
.workload-solo-wrap {
    max-width: 960px;
}
.workload-stat-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1rem;
}
.workload-stat-cards .sla-summary-item {
    min-width: 0;
}
/* Away agents on the workload table — their Load/Pressure is a standing queue,
   not active work, so the row is faded and the state is overlaid with "Away".
   INTERIM (Adrian on leave); refine to house style. */
.workload-away {
    position: relative;
    display: flex;
    align-items: center;
    min-width: 160px;
    min-height: 1.2rem;
}
.workload-away .workload-bar {
    margin-top: 0;
    opacity: 0.4;
}
.workload-away__tag {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.78rem;
    color: var(--text-grey, #64748b);
}



.news-feed__empty {
    padding: 2.4rem 1.6rem;
    font-size: 1.3rem;
    color: var(--text-grey);
    opacity: .7;
    text-align: center;
}


/* Jetstream-style modal panels (components/modal.blade.php — x-dialog-modal /
   x-confirmation-modal) render at @stack('modals'), OUTSIDE <main>, and don't
   carry Bootstrap's .modal-dialog class. So neither `main { font-size:1.6rem }`
   nor default.css's `main ul li / .modal-dialog ul li { font-size:1.5rem }`
   reaches them — and with html at 62.5% (1rem = 10px) any text without a
   global tag rule (bullets especially; p/h1/h2 are covered) inherits the bare
   10px root. Mirror main's baseline and bullet sizing so modal text reads
   exactly like page text. */
.modal-panel {
    font-size: 1.6rem;
}
.modal-panel ul li,
.modal-panel ol li {
    font-size: 1.5rem;
    line-height: 140%;
    margin-bottom: .1rem;
}

/* Pinned-box lists (startup items, failed runs): the rows carry their own
   checkboxes and buttons — a native bullet beside them is the same
   double-marker noise the findings digest had. */
.ticket-dirty-summary .standard-list {
    list-style: none;
    margin-left: 0;
}

/* Ticket-number copy in the pane header: the number fades and a tick lays over
   it, instead of the "Copied" pill default.css/custom.css style for this
   button. Scoped to the --tick modifier because the offcanvas header shares
   `.ticket-workspace-ticket-copy` and keeps the pill.

   Overlaid with `inset`, the same shape as .workload-away__tag above, rather
   than a centring translate — the pill needed one and it was forever fighting
   Alpine's transition helper for ownership of `transform`. Here the only
   transform is the entrance scale, so nothing can be clobbered mid-flight.

   The tick is currentColor, and default.css already turns the button
   --green-status while .is-copied is on it. The number recedes to
   --text-grey-light — a theme token, never an opacity: a shade is always one
   of the declared colour variables (Adrian, 2026-09-11), so it stays on the
   palette and reads the same on every background.

   Both `text-decoration` rules undo default.css. Its .is-copied underline is a
   second marker for the event the tick already reports, and its :hover/:focus
   underline is drawn by the button, so the receded child cannot cancel it —
   it has to be switched off at the level that draws it. Equal specificity to
   the default.css rule for the first, higher for the second; custom2.css
   loads last, so neither needs !important. */
.ticket-workspace-ticket-copy--tick .ticket-workspace-ticket-copy__value {
    transition: color 0.16s ease;
}

.ticket-workspace-ticket-copy--tick.is-copied .ticket-workspace-ticket-copy__value {
    color: var(--text-grey-light);
    text-decoration: none;
}

.ticket-workspace-ticket-copy--tick.is-copied:hover,
.ticket-workspace-ticket-copy--tick.is-copied:focus {
    text-decoration: none;
}

.ticket-workspace-ticket-copy--tick .ticket-workspace-ticket-copy__tick {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    animation: ticket-copy-tick-in 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.ticket-workspace-ticket-copy--tick .ticket-workspace-ticket-copy__tick svg {
    width: 1.15em;
    height: 1.15em;
}

.ticket-workspace-ticket-copy--tick .ticket-workspace-ticket-copy__tick.ticket-copy-tick-leave {
    transition: opacity 0.2s ease;
}

.ticket-workspace-ticket-copy--tick .ticket-workspace-ticket-copy__tick.ticket-copy-tick-leave-end {
    opacity: 0;
}

@keyframes ticket-copy-tick-in {
    from {
        opacity: 0;
        transform: scale(0.6);
    }

    to {
        opacity: 1;
        transform: scale(1);
    }
}

/* Ticket list: a ticked row wears a selected wash so a selection is readable
   at a glance rather than only from the 16px box at the far left.

   Driven off `:checked` with `:has()` rather than a server-rendered class so it
   lands on the same frame as the tick: the boxes are `wire:model.live`, and the
   page toggle sets `.checked` straight on the DOM from ticket-list-state.js
   without a render at all, so a class from the Blade would lag or never arrive.

   Every colour is a theme token (Adrian, 2026-09-11: no opacity or rgba to
   derive a shade). The P1/P2 rows already carry `.critical-bg-tint` /
   `.warning-bg-tint`, so a ticked one steps up to that colour's `-tint-strong`
   token — the theme's own "more of the same colour" — and keeps its priority
   signal, where a single grey would have replaced it. The `tr.<class>` rules
   out-rank the plain one by exactly that class.

   Scoped by `> td` rather than `tbody >` because the ticket table has no
   explicit `<tbody>` (rows follow `</thead>` straight out of the @forelse), and
   the select-all cell in the head is a `th` — so the td keeps the wash off the
   header row without leaning on the parser's implicit tbody. */
.ticket-table tr:has(> td.ticket-select-col input[type=checkbox]:checked) {
    background-color: var(--primary-color-tint);
}

.ticket-table tr.critical-bg-tint:has(> td.ticket-select-col input[type=checkbox]:checked) {
    background-color: var(--red-status-tint-strong);
}

.ticket-table tr.warning-bg-tint:has(> td.ticket-select-col input[type=checkbox]:checked) {
    background-color: var(--amber-status-tint-strong);
}

/* ── Ticket notices ──────────────────────────────────────────────────────────
   One box for every notice on a ticket (components/ticket-notice.blade.php),
   in either of its two placements. The internals are the timeline banner's
   above; only the outer spacing differs. An inline row keeps
   .ticket-timeline-marker-row's margins so it sits in the thread like the
   comments around it. The pinned stack lives inside the form's 2rem gutter,
   which used to come from an mx-2 wrapper on every partial, and the bottom
   margin the device boxes had (1.6rem) — closer than mb-2's 2rem so a stack
   reads as one group, but not so close that two boxes touch. A panel notice
   sits in a tab's own padded content (the Actions caution on the Device,
   Microsoft 365 and Google tabs), so it takes the box but not the gutter,
   which indented it from everything else on the tab; the caller's margin
   utility spaces it. */
.ticket-notice--pinned,
.ticket-notice--panel {
    padding: 1.2rem 1.6rem;
    gap: 1.2rem;
}

.ticket-notice--pinned {
    margin: 0 2rem 1.6rem;
}

/* Whatever a notice offers to press sits top-right and keeps its own height —
   a bare button as a flex child stretched to the full height of a three-line
   finding. The dismiss cross is a plain icon button in the notice's own ink;
   hover dims the whole control rather than painting a shade. */
.ticket-notice__actions {
    align-self: flex-start;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.8rem;
}

.ticket-notice__dismiss {
    appearance: none;
    background: none;
    border: 0;
    padding: 0.2rem;
    margin: -0.2rem -0.2rem 0 0;
    color: inherit;
    cursor: pointer;
    line-height: 0;
    border-radius: 0.4rem;
}

.ticket-notice__dismiss:hover,
.ticket-notice__dismiss:focus-visible {
    opacity: 0.7;
}

.ticket-notice__dismiss svg {
    width: 1.6rem;
    height: 1.6rem;
}

/* A P1/P2 ticket still at New flashes its N badge towards the priority
   colour so it stands out from the rest of the list. Animated values win
   over default.css's .badge-new background without raising specificity. */
@keyframes badge-new-flash-critical {
    50% { background-color: var(--red-status); }
}
@keyframes badge-new-flash-warning {
    50% { background-color: var(--amber-status); }
}
.badge-new--flash-critical {
    animation: badge-new-flash-critical 1.2s ease-in-out infinite;
}
.badge-new--flash-warning {
    animation: badge-new-flash-warning 1.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .badge-new--flash-critical { animation: none; background-color: var(--red-status); }
    .badge-new--flash-warning { animation: none; background-color: var(--amber-status); }
}

/* A Device tab check's options are a label beside a full-width field.
   default.css gives `.device-tools > div` word-break: break-word, which lets a
   word's minimum width fall to one character, so flex squeezed the label
   until "Remove" broke as "Remov / e". The field gives way instead. */
.device-tools .d-flex > label {
    flex-shrink: 0;
}

/* The ticket list's "#" copies the ticket number. On hover or keyboard
   focus the "#" is hidden in place, keeping its width, and a copy icon lays
   over its box; on a copy a tick takes the icon's place, as the pane
   header's copy does. Nothing is in flow but the "#", so the digits beside
   it never move. The copy icon is drawn edge to edge, so it is sized to the
   "#"'s own width rather than 1em, or it would crowd the first digit. The
   svg rules are raised to beat `.id-td-wrap svg`, which sizes and spaces
   the icons that used to sit in this cell. */
.ticket-id-hash {
    position: relative;
}
.ticket-id-hash:hover .ticket-id-hash__mark,
.ticket-id-hash:focus-visible .ticket-id-hash__mark,
.ticket-id-hash.is-copied .ticket-id-hash__mark {
    visibility: hidden;
}
.ticket-id-hash__copy,
.ticket-id-hash__tick {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.ticket-id-hash__copy {
    visibility: hidden;
}
.ticket-id-hash:hover .ticket-id-hash__copy,
.ticket-id-hash:focus-visible .ticket-id-hash__copy {
    visibility: visible;
}
.ticket-id-hash.is-copied .ticket-id-hash__copy {
    visibility: hidden;
}
.ticket-id-hash__tick {
    animation: ticket-copy-tick-in 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.id-td-wrap .ticket-id-hash__copy svg {
    width: .8em;
    height: .8em;
    margin-right: 0;
}
.id-td-wrap .ticket-id-hash__tick svg {
    width: 1em;
    height: 1em;
    margin-right: 0;
}

/* The sidebar New count flashes towards red (a P1 waiting) or amber (a P2
   waiting). ticket-alerts.js swaps this in for .success-bg, whose !important
   background would otherwise beat the animation. */
@keyframes badge-flash-emergency {
    0%, 100% { background-color: var(--green-status); border-color: var(--green-status); }
    50% { background-color: var(--red-status); border-color: var(--red-status); }
}
@keyframes badge-flash-warning {
    0%, 100% { background-color: var(--green-status); border-color: var(--green-status); }
    50% { background-color: var(--amber-status); border-color: var(--amber-status); }
}
.badge.badge-flash-emergency {
    color: #fff;
    animation: badge-flash-emergency 1.2s ease-in-out infinite;
}
.badge.badge-flash-warning {
    color: #fff;
    animation: badge-flash-warning 1.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .badge.badge-flash-emergency { animation: none; background-color: var(--red-status); border-color: var(--red-status); }
    .badge.badge-flash-warning { animation: none; background-color: var(--amber-status); border-color: var(--amber-status); }
}

/* Suggested documents on the ticket: each row is an 18px icon against 15px
   text, and an inline SVG sits its BOTTOM on the baseline - so the icon rode
   ~4px above the title's cap height, grew the line box, and left the bullet
   and the title both looking dropped beneath it. text-bottom hangs it from the
   descender instead, which puts its centre on the text's and the bullet's and
   keeps the line box at its natural height. Scoped here rather than on .svg-18,
   which the ticket list also uses. */
.ticket-suggested-documents ul.standard-list svg {
    vertical-align: text-bottom;
}

/* The Alerts gate (/service/alerts) takes New's columns, but New's widths are
   scoped to .service-new, so without these the action cell fell back to the
   5.8rem default and the "Waiting for …" pill pushed the row off the right
   edge. Its action cell holds that pill, Take it and the View button: 327px
   at the widest label ("Waiting for 59 seconds") once the buttons shed their
   3rem padding below; at the 270px it had before Take it, the button sat off
   the right edge. Any slack here is a visible gap before the pill on every
   row, so the width stays at the need. */
.service-alerts .ticket-table-wrap .ticket-actions-col--new,
.service-alerts .ticket-table-wrap .ticket-row-actions--new {
    width: 330px;
    min-width: 330px;
}

/* Approvals had no width of its own at all, so its cell fell back to the same
   5.8rem default with the park pill, Release or Approve, Greylist and View
   inside it. The widest row — the "No active support agreement" pill with
   Release, Greylist and View — needs 465px. */
.service-approvals .ticket-table-wrap .ticket-actions-col--new,
.service-approvals .ticket-table-wrap .ticket-row-actions--new {
    width: 470px;
    min-width: 470px;
}

/* custom.css floors every ticket table at 156rem below a 1700px window, sized
   for My Work's Updated and Assignee columns. Alerts and Approvals carry
   neither, so on a ~1530px card the floor alone scrolled the table sideways
   and pushed the actions off screen. Their columns' own widths already keep
   them from being crushed; past that the table scrolls as any table does. */
@media screen and (max-width: 1699px) {
    .service-alerts .ticket-table-wrap .ticket-table,
    .service-approvals .ticket-table-wrap .ticket-table {
        min-width: 0;
    }
}

/* New's action cell holds Take it beside Greylist, Delete and View — one
   button more than the 310px custom.css (loaded before this file) sized it
   for, which was already full. Widening alone did not fit them: `table .btn`
   pads every button 3rem a side (btn-compact is a no-op — its compiled rule
   is `btn.btn-compact`), so the three text buttons alone carried 180px of
   padding and View went off the right edge. */
.service-new .ticket-table-wrap .ticket-actions-col--new,
.service-new .ticket-table-wrap .ticket-row-actions--new {
    width: 400px;
    min-width: 400px;
}

/* The padding trim, on every button-row cell (New, Alerts, Approvals): the
   widths above are measured at this padding. */
.ticket-table-wrap .ticket-row-actions--new .btn:not(.icon-btn-round) {
    padding-left: 1.6rem;
    padding-right: 1.6rem;
}

/* The action cell holds only fixed-size controls, so `.no-wrap-ellipsis-table`'s
   td truncation has nothing useful to cut — the same opt-out as .ticket-sla-col
   above. On the lists whose cell is View alone (Search, My Work) the column is
   6.6rem with 4.6rem of it padding, so the 35px button overflowed its 20px
   content box and every row ended in a clipped button and a stray "…". */
.ticket-table-wrap .ticket-action-cell {
    overflow: visible;
}

.service-alerts .ticket-table-wrap .ticket-subject-cell {
    width: 28%;
    max-width: 420px;
}

.service-alerts .ticket-table-wrap .ticket-truncate-cell {
    max-width: 150px;
}

.service-alerts .ticket-table-wrap .ticket-filter-select-col--partner,
.service-alerts .ticket-table-wrap .ticket-filter-select-col--team,
.service-alerts .ticket-table-wrap .ticket-filter-select-col--requester {
    min-width: 140px;
}

.service-alerts .ticket-table-wrap .table-filter-row .ticket-filter-select-col--partner,
.service-alerts .ticket-table-wrap .table-filter-row .ticket-filter-select-col--team,
.service-alerts .ticket-table-wrap .table-filter-row .ticket-filter-select-col--requester {
    min-width: 132px;
}

/* Datto freshness as a round refresh button inside the field it refreshes
   (DattoFreshnessBadge, icon mode). Same size idle or spinning, so the form
   does not jump; the age is in its tooltip. */
.datto-freshness__icon-glyph--spinning {
    animation: spin 0.8s linear infinite;
}
.datto-freshness__icon--stale {
    color: var(--amber-status);
}

/* The same spin for the refresh button any lazy or server-searched select
   draws beside itself (x-virtual-select), and for the Datto badge while the
   Device field's own option list loads. wire:loading puts the class on the
   button, or on the field wrapper where the glyph is inside a nested
   component it cannot reach. Replaces the "Loading..." row that appeared
   under the field and pushed everything below it down. */
/* The Device field wraps the whole select in its own flex row beside the
   Datto refresh button, so the select's outer wrapper must take the
   remaining width, as the widget does in the fields that draw their own. */
.button-input > .vs-field-wrap {
    flex: 1 1 auto;
    min-width: 0;
}

.vs-refresh--loading svg,
.vs-field-loading .datto-freshness__icon svg {
    animation: spin 0.8s linear infinite;
}

/* The device pickers' online dot (livewire/devices/field): green online, red
   offline, before the hostname, with the description line indented to match
   — the library's own layout for a multi-select's checkbox. The option is a
   wrapping flex row, so the dot shares the hostname's line. */
.vscomp-option.device-option::before {
    content: "";
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    margin-right: 1rem;
    border-radius: 100%;
    background-color: var(--red-status);
}

.vscomp-option.device-option--online::before {
    background-color: var(--green-status);
}

.vscomp-option.device-option .vscomp-option-text {
    width: calc(100% - 2rem);
}

.vscomp-option.device-option .vscomp-option-description {
    padding-left: 2rem;
}

/* Hardware modal (livewire/devices/hardware-modal). Each section is its own
   table, so without fixed widths every section sized its value column to its
   own content and nothing lined up. Key-value tables share one grid; the
   sections get air between them so a heading is not read as the last row. */
.hardware-modal section + section {
    margin-top: 2.4rem;
}
.hardware-modal h3 {
    margin-bottom: 0.8rem;
}
.hardware-modal table.hardware-facts {
    table-layout: fixed;
    width: 100%;
}
.hardware-modal table.hardware-facts th {
    width: 30%;
}
.hardware-modal table.hardware-facts td.td-alert-icon {
    width: 4rem;
}
.hardware-modal table.hardware-facts input {
    max-width: 100%;
}

/* Fieldsets. A <fieldset> names one question for a screen reader: a radio
   or checkbox group, or a few fields on one topic, under the <legend> that
   asks it. A section of a page is a <section> with a heading instead. */

/* Browsers give a fieldset min-inline-size: min-content, so a table, an
   editor toolbar or a nowrap button row inside one widened the page on a
   phone instead of scrolling in its own box. */
fieldset {
    min-width: 0;
}

/* A fieldset standing in for a field's .form-group keeps that field's look:
   square corners (the amber changed-elsewhere bar is an inset shadow), and a
   legend that reads as the <label> it replaced. The offcanvas styles a bare
   legend as a section heading, which suits a section and not a question; a
   legend given .fieldheader keeps the label look there too, as it has
   everywhere else. */
fieldset.form-group {
    border-radius: 0;
}

.offcanvas-body .form-content > fieldset.form-group {
    padding-bottom: 0;
}

.offcanvas fieldset.form-group > legend,
.service-body .offcanvas fieldset.form-group > legend,
.offcanvas legend.fieldheader,
.service-body .offcanvas legend.fieldheader {
    font-size: 1.5rem;
    font-weight: 500;
    color: var(--text-grey);
    margin-bottom: 0.8rem;
}

.offcanvas fieldset.form-group > legend span {
    font-weight: 400;
    font-size: 1.2rem;
    color: var(--text-grey-light);
    padding-left: 4px;
    font-style: italic;
}

.ticket-workspace-panel fieldset.form-group > legend span {
    font-size: 1.2rem;
    padding-left: 1px;
    font-style: italic;
}

/* A legend holding a heading (GOV.UK's pattern for a group already titled by
   one) leaves the look to the heading, so the page reads as it did. */
legend:has(> :is(h2, h3, h4)),
.offcanvas legend:has(> :is(h2, h3, h4)),
.service-body .offcanvas legend:has(> :is(h2, h3, h4)) {
    margin-bottom: 0;
    color: inherit;
    font: inherit;
}

/* The QR tag sheet renders in the guest layout, which has no fieldset reset.
   Its fieldsets are grids or flex rows, and a rendered legend is neither's
   item, so it takes the row gap as a margin. */
fieldset.device-tag-sheet-inline {
    border: 0;
    padding: 0;
    margin: 0;
}

.device-tag-sheet-fieldset > legend,
.device-tag-sheet-inline > legend {
    padding: 0;
    margin-bottom: 0.75rem;
}

/* Device jobs in flight (device-work-banner.blade.php): the job's state is its
   bullet, the way the findings digest under it uses the RAG dot. The list
   swaps its dot for a ring drawn over the spot where the dot sits, so every
   line stays in one column: a still, dashed ring while the job waits its turn
   or a stated time, the CE pending pill's spinner once the machine has started
   it. A grey dot read as "offline" beside the spinner, not "queued". */
.status-bullet-list li.status-marker-waiting::before {
    content: "";
    left: -33px;
    top: 3px;
    width: 12px;
    height: 12px;
    border: 2px dashed var(--info-status);
    border-radius: 50%;
}
.status-bullet-list li.status-marker-running::before {
    content: "";
    left: -33px;
    top: 3px;
    width: 12px;
    height: 12px;
    border: 2px solid var(--info-status-tint-strong);
    border-top-color: var(--info-status);
    border-radius: 50%;
    animation: ce-pending-spin 0.9s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
    .status-bullet-list li.status-marker-running::before {
        animation: none;
    }
}

/* A call the customer asked for that nobody has answered with a time (#545):
   the phone in the ticket list's status cell jiggles until a reply names one.
   Only the requested state moves; an agreed call is static and a missed one
   is already red. With motion off, the red fill carries the signal alone. */
@keyframes ticket-call-slot-jiggle {
    0%, 60%, 100% { transform: rotate(0); }
    10% { transform: rotate(-14deg); }
    20% { transform: rotate(12deg); }
    30% { transform: rotate(-9deg); }
    40% { transform: rotate(6deg); }
    50% { transform: rotate(-3deg); }
}
.ticket-call-slot--requested {
    animation: ticket-call-slot-jiggle 1.6s ease-in-out infinite;
    transform-origin: 50% 50%;
}
@media (prefers-reduced-motion: reduce) {
    .ticket-call-slot--requested {
        animation: none;
    }
}

/* QR tag sheet modal (x-qr-sheet-modal). Above the app chrome, which stacks
   as high as 100501. These rules were pushed from the component's own
   @push('styles'); a component rendered by a Livewire update pushes into a
   stack no layout echoes, so they live here, where every page loads them.
   The closed state is Alpine's x-show, so there is no [hidden] rule. */
.qr-sheet-modal { position: fixed; inset: 0; z-index: 100600; display: flex; padding: 2.5vh 2.5vw; }
.qr-sheet-modal-backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, .55); }
.qr-sheet-modal-panel {
    position: relative; display: flex; flex-direction: column; overflow: hidden;
    width: min(1600px, 100%); height: 100%; margin: auto;
    background: #fff; border-radius: .75rem; box-shadow: 0 20px 50px rgba(15, 23, 42, .35);
}
.qr-sheet-modal-bar {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex: 0 0 auto;
    padding: .75rem 1.25rem; border-bottom: 1px solid #e2e8f0;
}
.qr-sheet-modal-close {
    width: 2.25rem; height: 2.25rem; border: 1px solid #e2e8f0; border-radius: 50%;
    background: #fff; color: #0f172a; font-size: 1.4rem; line-height: 1; cursor: pointer;
}
.qr-sheet-modal-close:hover { background: #f1f5f9; }
.qr-sheet-modal-frame { flex: 1 1 auto; width: 100%; border: 0; }

/* A suppression press wears its whole sentence — the label is the consent
   (Shaun, 28 Sep 2026) — so it wraps inside the modal and the register's
   table cell where default.css's .btn would run off the edge. */
.btn-sentence {
    white-space: normal;
    text-align: left;
}

/* <x-datetime-picker> (resources/js/datetime-picker.js). Without these the
   calendar's 42 days and the 36 hour and minute buttons run on as one line of
   bare text, with nothing to show which is chosen or which is today. */
.datetime-picker__panel { width: max-content; max-width: calc(100vw - 16px); }
.datetime-picker__grid { display: grid; grid-template-columns: repeat(7, 3.4rem); gap: .2rem; margin-bottom: .8rem; text-align: center; }
.datetime-picker__grid--time { grid-template-columns: repeat(6, 3.4rem); }
.datetime-picker__weekday { font-size: 1.2rem; color: var(--text-grey-mid); }
.datetime-picker__cell { padding: .5rem 0; border: 1px solid transparent; border-radius: 6px; background: none; font: inherit; font-size: 1.3rem; color: inherit; cursor: pointer; }
.datetime-picker__cell:hover { background-color: var(--primary-color-tint); }
.datetime-picker__cell--outside { color: var(--text-grey-light); }
.datetime-picker__cell--today { border-color: var(--primary-color); color: var(--primary-color); font-weight: 700; }
.datetime-picker__cell[aria-pressed="true"] { background-color: var(--primary-color); color: var(--primary-btn-text); }

/* A list of label/value fields, as the SaaS Alerts suppression screen lays a
   rule out. default.css already makes a <dl> a two-column grid, but under
   body's line-height of 1 a value that wraps sets its lines touching, and an
   unbroken address in the value column pushes the grid past its container. */
.field-list { grid-template-columns: max-content minmax(0, 1fr); gap: 6px 16px; line-height: 1.4; }

/* A date field as wide as a date, so two can share a line with "to" between
   them. Every date input is width:100% in default.css, under a selector that
   outranks a bare class, hence the element in this one. */
input.input-date-compact { width: 13.5rem; }

/* A card with a light edge, for one that sits on a white modal or page where
   .card's own shadow does not show. .stacked-card's edge is the dark text
   grey, and .border draws nothing without a tint class beside it. */
.card.card-outlined { border: 1px solid var(--light-grey); box-shadow: none; }

/* A small button with an icon keeps .btn-sm's padding: default.css gives every
   .btn:has(.bi) .5em, which outranks .btn-sm. The icon sits at text height so
   the button is no taller than a plain .btn-sm beside it. */
.btn-sm:has(.bi) { padding: .5rem; }
.btn-sm .bi { width: 1em; height: 1em; vertical-align: -.125em; }
