h1:focus {
    outline: none;
}

/* MudBlazor 9.1's MudDatePicker popover paper ships with overflow-x:hidden, which clips
   the rightmost weekday columns whenever the paper sizes itself narrower than the 310px
   calendar grid it wraps. Surfaced in PBI 69's schedule sub-dialog (PickerVariant.Dialog
   inside a modal), but the same clip can affect inline popovers in narrow form contexts.
   Minimal-impact fix: just remove the overflow clip so the paper grows to the natural
   width of its content. No width-force — MudBlazor's own 310px min-width is already
   right; the bug was that the clip prevented that width from showing. Global rule
   because the popover paper renders at the popover-provider level (separate DOM tree
   from any specific picker instance), so scoped-CSS approaches can't reach it. */
.mud-picker-popover-paper {
    overflow-x: visible !important;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* EasySong custom styles */

.login-card {
    border-radius: 12px !important;
}

.social-login-btn {
    text-transform: none !important;
    font-weight: 500;
    border-color: #ddd !important;
    color: #333 !important;
}

.social-login-btn:hover {
    background-color: #f5f5f5 !important;
}

/* ===== Direct Licensing theme tokens ===== */
:root {
    --dl-side-publishing: #7c3aed;
    --dl-side-master: #2563eb;
}

/* ===== Direct Licensing Styles ===== */

/* Request list item hover state */
.dl-list-item:hover {
    background: var(--mud-palette-action-default-hover) !important;
}

/* Filter dropdown popovers — wider than the input so option text isn't cut off */
.dl-filter-popover {
    min-width: 240px;
}
.dl-filter-popover .mud-list-item-text {
    white-space: normal;
    word-break: break-word;
}

/* Split pane scrollable panels */
.dl-ticket {
    min-height: 0;
}

/* Timeline styling */
.dl-ticket .mud-timeline {
    padding-left: 0;
}

/* Properties and Customer/Milestones sidebars sticky positioning */
@media (min-width: 960px) {
    .dl-ticket .mud-grid > .mud-item:first-child,
    .dl-ticket .mud-grid > .mud-item:last-child {
        position: sticky;
        top: 0;
        align-self: flex-start;
    }
}

/* Compact property-field inputs to match caption-sized labels */
.pf-compact .mud-input-control {
    margin-top: 0 !important;
}
.pf-compact .mud-input,
.pf-compact .mud-select-input {
    font-size: 0.75rem !important;
    padding-top: 4px !important;
    padding-bottom: 4px !important;
}
.pf-compact .mud-input-slot {
    font-size: 0.75rem !important;
}
.pf-compact .mud-input-slot:has(textarea) {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}
.pf-compact .mud-input-control .mud-input-label {
    display: none;
}

/* Workflow pipeline responsive */
.dl-pipeline {
    overflow-x: auto;
    scrollbar-width: thin;
}

/* PBI 57 — accounting-style currency display. Tabular figures give every digit equal
   width so decimal points line up across stacked values; right-alignment makes amounts
   of different magnitudes ($165.00 vs $4,345.00) align on the decimal. Applied to
   read-only money values and to dashboard fee grid cells. */
.usd-amount {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    text-align: right;
}

/* Right-align the numeric text inside financial entry fields so a stacked column of
   inputs reads like a ledger — decimals line up under each other, matching the
   read-only .usd-amount values. Targets the inner <input> of a MudNumericField. */
.usd-field input {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* The trailing "USD" adornment: add a gap so it doesn't butt against the number, and
   match its size to the digits. In the compact PropertyField context (.pf-compact) the
   input text is shrunk to 0.75rem but the adornment is not — bring it down to match so
   "500.00 USD" reads as one consistent unit. */
.usd-field .mud-input-adornment-end {
    margin-left: 0.75em;
    padding-left: 0.25em;
}
.pf-compact .usd-field .mud-input-adornment-end,
.pf-compact .usd-field .mud-input-adornment-end * {
    font-size: 0.75rem;
}

/* PBI 88: visual cue applied to a Missing Fields chip's target anchor when the chip
   is clicked. Distinct from MudBlazor's per-field error styling so the agent's eye is
   drawn to the specific chip target even on a page already showing validation errors.

   Lifecycle is split between CSS and JS:
     - CSS @keyframes field-anchor-pulse runs once (0.6s) on class-add for a quick
       attention "pop" from no-shadow to the steady glow.
     - After the pulse, the steady outline + box-shadow remain (no animation loop)
       until missingFieldsInterop.scrollAndFocus removes the class at HIGHLIGHT_DURATION_MS
       (currently 2.5s). The fade-out is the transition triggered by class removal. */
.field-anchor-highlight {
    outline: 2px solid var(--mud-palette-error, #d32f2f);
    outline-offset: 4px;
    border-radius: 4px;
    box-shadow: 0 0 16px 2px rgba(211, 47, 47, 0.45);
    animation: field-anchor-pulse 0.6s ease-out 1;
    transition: outline-color 0.3s ease-out, box-shadow 0.3s ease-out;
}

@keyframes field-anchor-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(211, 47, 47, 0.6); }
    100% { box-shadow: 0 0 16px 2px rgba(211, 47, 47, 0.45); }
}

/* PBI 133: make the note add/inline-edit text boxes user-resizable so a long note can be
   dragged open and read in full while editing, instead of being trapped in a fixed scrolling
   window. Shared by the Project Notes boxes (ProjectDetail) and the Requests Add-note box
   (RequestTicketView) via the .resizable-note-field class. MudTextField renders its <textarea>
   in MudBlazor's own markup, so a scoped/::deep rule from the page can't cleanly reach it —
   same reason the picker rule at the top of this file is global. We match the textarea by
   element (not an internal MudBlazor class) so the rule survives MudBlazor markup changes;
   .resizable-note-field is only ever set on note fields, so the descendant textarea is
   unambiguous. resize:vertical adds the drag grip and keeps width under layout control;
   !important overrides MudBlazor's base textarea resize:none. The component's Lines= sets the
   starting height (AC: compact default when empty); min-height is a fixed ~3-line drag-shrink
   floor (independent of Lines) so the box can't be collapsed to a sliver. */
.resizable-note-field textarea {
    resize: vertical !important;
    min-height: 64px !important;
}

/* ===== Bug 245: workspace tab overflow dropdown =====
   The "all open tabs" popover is rendered through MudPopoverProvider (teleported to the page root,
   a separate DOM subtree), so these rules must be global — a component-scoped rule can't reach the
   popover paper or its content. Same reason as the picker rule at the top of this file. The overflow
   *button* and click-away *overlay* render inline in TabStrip and are styled there
   (TabStrip.razor.css). */
.tab-strip-overflow-popover {
    min-width: 280px;
    max-width: 360px;
    border-radius: 8px;
    overflow: hidden;
}

.tab-strip-overflow-header {
    padding: 10px 14px 6px;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

.tab-strip-overflow-search {
    padding: 2px 12px 6px;
}

.tab-strip-overflow-list {
    max-height: 420px;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 4px 0 6px;
    scrollbar-width: thin;
    outline: none;
}

.tab-strip-overflow-empty {
    padding: 12px 16px;
    font-size: 0.8rem;
    color: var(--mud-palette-text-disabled);
}

.tab-strip-overflow-item {
    display: flex;
    align-items: stretch;
    border-left: 2px solid transparent;
    transition: background-color 100ms ease;
}

.tab-strip-overflow-item:hover,
.tab-strip-overflow-item:focus-within {
    background: var(--mud-palette-action-default-hover);
}

.tab-strip-overflow-item-active {
    background: var(--mud-palette-action-default-hover);
    border-left-color: var(--mud-palette-primary);
}

/* Primary action fills the row and is a real <button>, so keyboard activation and focus come for
   free — no hand-rolled key handling, no clickable div. Reset the native button chrome. */
.tab-strip-overflow-item-activate {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 4px 8px 12px;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.tab-strip-overflow-item-icon {
    flex: 0 0 auto;
    color: var(--mud-palette-text-secondary);
}

.tab-strip-overflow-item-active .tab-strip-overflow-item-icon {
    color: var(--mud-palette-primary);
}

/* Flex column; as flex items the <span> children blockify, so text-overflow:ellipsis works. */
.tab-strip-overflow-item-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.tab-strip-overflow-item-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
}

.tab-strip-overflow-item-active .tab-strip-overflow-item-title {
    font-weight: 600;
}

.tab-strip-overflow-item-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.tab-strip-overflow-item-subtitle {
    font-size: 0.72rem;
    color: var(--mud-palette-text-disabled);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Dirty dot inside the overflow list — re-declared globally because the scoped
   .tab-strip-dirty-dot can't reach the teleported popover. Mirrors the strip's dot. */
.tab-strip-overflow-item .tab-strip-dirty-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--mud-palette-warning);
}

.tab-strip-overflow-item-close {
    flex: 0 0 auto;
    align-self: center;
    margin-right: 8px;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 3px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--mud-palette-text-secondary);
    opacity: 0.5;
    transition: opacity 100ms ease, background-color 100ms ease;
}

.tab-strip-overflow-item:hover .tab-strip-overflow-item-close,
.tab-strip-overflow-item-close:hover,
.tab-strip-overflow-item-close:focus-visible {
    opacity: 1;
}

.tab-strip-overflow-item-close:hover {
    background: var(--mud-palette-action-default-hover);
    color: var(--mud-palette-text-primary);
}

/* ===== UI/UX review (chore/2026-07-16): accessibility baseline ===== */

/* One consistent keyboard-focus ring. :focus-visible shows it only for keyboard navigation (never
   on mouse click), and the brand primary keeps it legible on both light and dark surfaces. MudBlazor
   components manage their own focus states; this covers the plain interactive elements — anchors,
   hand-rolled <button>s, the Home hub cards — that otherwise fell back to a browser default outline
   often invisible against tinted backgrounds. */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
    border-radius: 4px;
}

/* PBI 172 — explainer "(i)" affordance (InfoTooltip). The global [tabindex]:focus-visible rule
   above already gives it the keyboard focus ring; this only nudges the icon into optical alignment
   with the caption text beside it and warms it on hover/focus so it reads as interactive. */
.info-tooltip {
    vertical-align: middle;
    margin-left: 2px;
    border-radius: 50%;
    transition: color 0.12s ease;
}

.info-tooltip:hover .mud-icon-root,
.info-tooltip:focus-visible .mud-icon-root {
    color: var(--mud-palette-primary) !important;
}

/* PBI 172 — Next Follow-Up color key swatches. The key lives inside a tooltip (its content is
   portaled to the popover provider at the document root), so this is not scoped to a page wrapper. */
.fu-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    display: inline-block;
}

/* Honour the OS "reduce motion" preference: users prone to motion sickness (or who simply find
   movement distracting) get near-instant state changes instead of the hover lifts, tab transitions,
   and missing-field pulse. State still changes — only the animation is removed. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* PBI 338 — global "Send feedback" FAB, pinned above page content. z-index sits below MudBlazor's
   dialog/snackbar layers (1400+) so the open dialog and toasts still overlay it.
   PBI 150 — pinned bottom-LEFT (was bottom-right) per request. Snackbars default to top-right, so the
   corner is otherwise clear. */
.feedback-fab {
    position: fixed;
    left: 24px;
    bottom: 24px;
    z-index: 1300;
}

/* PBI 100 — global-search dropdown rows. Global (not scoped) CSS because the popover content is
   teleported out of the component's DOM subtree by MudPopoverProvider, where a .razor.css scope
   attribute selector is brittle. */
.gs-section {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
    padding: 8px 16px 2px;
}

.gs-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 16px;
    cursor: pointer;
}

.gs-row:hover {
    background-color: var(--mud-palette-action-default-hover);
}

.gs-row-icon {
    flex: 0 0 auto;
    opacity: 0.7;
}

.gs-row-text {
    flex: 1 1 auto;
    min-width: 0;
}

.gs-row-title,
.gs-row-sub {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gs-row-time {
    flex: 0 0 auto;
    white-space: nowrap;
    margin-left: 8px;
}

.gs-all-results {
    font-weight: 500;
}

.gs-disabled {
    opacity: 0.5;
    pointer-events: none;
}

/* PBI 100 / PBI 170 — free-text search match highlight. Amber background with a forced dark-navy
   foreground so contrast holds in BOTH light and dark themes (≈10:1, well past WCAG AA) and the
   colour never collides with the status/outcome badges (red/blue/black/grey). Both fg and bg are set
   explicitly so the browser's default <mark> styling (which would inherit the theme text colour and
   wash out in dark mode) is overridden. */
mark.es-hl {
    background-color: #ffd54f;
    color: #1f2d3d;
    padding: 0 1px;
    border-radius: 2px;
}

/* "matched in {field}" hint line under a row's identity cell — small, muted, wraps its own highlight. */
.es-hint {
    display: block;
    font-size: 0.72rem;
    line-height: 1.2;
    opacity: 0.75;
    margin-top: 2px;
    white-space: normal;
}
