/* BFF page/feature styles. Design tokens live in
   _content/TSO.TimeView.Shared.Components/tv-tokens.css and the post-theme layer (brand primary,
   element defaults, .tv-btn hierarchy) in tv-theme.css — both loaded from App.razor. */

/* Shared wrapper for the list-style pages (entity lists, the DMS lists and editor, global
   search). It deliberately adds no horizontal or top padding: .content above already supplies
   the page gutter, and a second copy here is what pushed the entity list's sticky top bar a
   gutter further right — and a gutter lower — than every other page's, since EntityDetail and
   TimeRegSchema render their top bar straight into .content. Only the trailing gap below the
   grid belongs to this wrapper.

   Defined once here rather than in a per-page <style> block: it was declared identically in
   four of them, so correcting one would silently have left the other three behind. */
.tv-item-list-page {
    padding-block: 0 var(--tv-space-4);
}

/* State borders for summary/KPI cards. These four class names are used across the dashboard, the
   landing page and the organisation hierarchy page, and were documented as an existing mechanism,
   but no stylesheet ever defined them — so every "state border" in the app silently rendered as
   no border at all. Defined here against the Tier-2 indicator tokens, next to the other globals
   the components assume exist.

   Good and Neutral are deliberately borderless: they are the absence of a problem, and marking
   them is what made every card on a page shout equally loudly. The tokens are kept for callers
   that want the colour, but the border is reserved for states that need attention. */
.card-border-warning,
.card-border-bad {
    border-left: 4px solid;
}

.card-border-warning {
    border-left-color: var(--indicator-warning);
}

.card-border-bad {
    border-left-color: var(--indicator-bad);
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid var(--color-danger);
}

.validation-message {
    color: var(--color-danger);
}

.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;
}

/* Gør knappen til referencepunkt for placering */
.e-btn.timeregistrationSchemaLinkToTimereg {
    position: relative !important;
    overflow: visible !important; /* Vigtigt: så badget ikke bliver klippet af */
}

/* Placer badget helt oppe i højre hjørne */
.custom-inline-dot {
    position: absolute !important;
    top: -5px; /* Dette virker allerede hos dig */
    /* NYE RETTELSER: */
    right: -7px !important; /* Prøv en høj værdi for at se effekten */
    left: auto !important; /* Vigtigt: fjerner eventuel låsning til venstre side */
    width: 13px !important;
    height: 16px !important;
    background-color: lightgray !important;
    display: flex !important;
    justify-content: center;
    align-items: center;
    margin: 0 !important;
    padding: 0 !important; /* Fjern din padding-bottom: 14px hvis muligt */
    color: black !important;
}

/* Row-level status chips in the scheduler. These previously painted themselves from the
   --approval-* *period* tokens while TimeRegStatusColors.cs painted the same statuses from its own
   System.Drawing hexes — so the class rendered amber where the C# constant said orange. Both now
   read the --timereg-row-* group. */
.employeeDraftColor {
    background-color: var(--timereg-row-draft) !important;
    color: var(--tv-on-accent) !important;
}

.timeregDoneNotApprovedColor {
    background-color: var(--timereg-row-done) !important;
    color: var(--tv-on-accent) !important;
}

.timeregManagementApprovedColor {
    background-color: var(--timereg-row-approved) !important;
    color: var(--tv-on-accent) !important;
}

.timeregManagementDeniedColor {
    background-color: var(--timereg-row-denied) !important;
    color: var(--tv-on-accent) !important;
}

.customTextAlignCenter {
    text-align: center !important;
}

.text-red {
    color: red !important;
}

.text-green {
    color: green !important;
}

/* Planning row markers -------------------------------------------------------------------------
   Global rather than component-scoped, because the same markers are rendered by more than one
   component. Blazor CSS isolation rewrites a .razor.css selector to match only its own component, so
   a shared marker needs a copy per component - and PlanRowsGrid never got one for .planning-restricted,
   which left the restricted label in "Min plan" (the view that actually ships) with no styling at all,
   while MyPlanGrid.razor.css carried a copy that matched nothing. One definition here removes both the
   duplication and that class of bug.

   Both markers put their glyph and label beside the name rather than behind it: no single text colour
   clears WCAG AA against every --indicator-* value the themes resolve to, so a coloured fill with a
   label on top cannot be made accessible in both themes at once. */
.planning-restricted {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--planning-restricted);
    font-style: italic;
}

.planning-restricted-icon {
    font-size: 1rem;
}

.planning-inactive-customer {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--planning-inactive-customer, hotpink);
}

.planning-inactive-customer-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.planning-inactive-customer-icon {
    font-size: 1rem;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Global search (app bar + results panel + /search page)

   Lives here rather than in scoped component CSS because the box and the results
   panel are two components that share one visual surface: Blazor scoped styles do
   not cross a component boundary, so keeping them together avoids a ::deep chain
   whose specificity has to be maintained by hand.
   ───────────────────────────────────────────────────────────────────────────── */

/* Syncfusion's app bar sets `overflow: hidden` on `.e-appbar`, which clips anything taller than
   the 48px bar. That silently swallows the search results panel whole — the box accepts input,
   queries the API and renders the panel, but none of it is ever painted, so the feature reads as
   completely dead. Two class names beat Syncfusion's single-class rule, so no `!important`.
   Applied via an opt-in class rather than to `.e-appbar` globally, so only the bar that hosts an
   overflowing popup gives up its clipping. */
.e-appbar.appbar-allows-overflow {
    overflow: visible;
}

.global-search {
    position: relative;
    display: flex;
    align-items: center;
    /* Takes what it can up to a readable width, then stops: a search box as wide as
       the window makes the app bar look empty and the results panel unreadably wide. */
    flex: 0 1 26rem;
    min-width: 0;
    margin-inline: .5rem;
}

.global-search__field {
    display: flex;
    align-items: center;
    gap: .25rem;
    width: 100%;
    padding: .125rem .5rem;
    border: 1px solid var(--tv-search-field-border);
    border-radius: 1rem;
    background: var(--tv-search-surface);
}

.global-search__field:focus-within {
    border-color: var(--tv-accent);
}

.global-search__icon,
.global-search__shortcut {
    flex: none;
    opacity: .7;
}

.global-search__shortcut {
    font-size: .75rem;
    padding: .0625rem .25rem;
    border: 1px solid var(--tv-search-border);
    border-radius: .25rem;
    white-space: nowrap;
}

.global-search__input {
    flex: 1 1 auto;
    min-width: 0;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    padding: .25rem 0;
}

.global-search__input:focus {
    outline: none;
}

/* The browser's own clear affordance would sit beside ours and do something subtly
   different (it does not tell Blazor the value changed). */
.global-search__input::-webkit-search-cancel-button {
    display: none;
}

.global-search__clear,
.global-search__close,
.global-search-trigger {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    min-height: 2rem;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
}

.global-search__clear:hover,
.global-search__close:hover,
.global-search-trigger:hover {
    background: var(--tv-search-hover);
}

/* ── Mobile overlay ── */

.global-search--overlay {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 1200;
    flex-direction: column;
    align-items: stretch;
    flex: none;
    margin: 0;
    padding: .5rem;
    background: var(--tv-search-surface);
}

.global-search--overlay .global-search__panel {
    position: static;
    width: auto;
    max-height: calc(100vh - 4rem);
    border: none;
    box-shadow: none;
}

/* ── Results panel ── */

.global-search__panel {
    position: absolute;
    top: calc(100% + var(--tv-space-2));
    left: 0;
    width: min(34rem, 90vw);
    max-height: min(30rem, 70vh);
    overflow-y: auto;
    z-index: 1100;
    border: 1px solid var(--tv-search-field-border);
    border-radius: var(--tv-default-border-radius);
    background: var(--tv-search-surface);
    box-shadow: var(--tv-shadow-flyout-hover);
}

/* Group headers stick while their rows scroll past, so a long "Dokumenter" list still says what
   it is when the user is halfway down it. The solid surface matters: without it rows bleed
   through the header. */
.global-search-group__header {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--tv-space-2);
    padding: var(--tv-space-2) var(--tv-space-3) var(--tv-space-1);
    background: var(--tv-search-surface);
}

.global-search-group + .global-search-group .global-search-group__header {
    border-top: 1px solid var(--tv-search-border);
}

.global-search-group__heading {
    font-size: var(--tv-text-meta);
    font-weight: var(--tv-weight-strong);
    line-height: var(--tv-leading-tight);
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--tv-search-muted);
}

.global-search-group__more,
.global-search__all {
    border: none;
    border-radius: 1rem;
    background: transparent;
    color: var(--tv-accent);
    font: inherit;
    font-size: var(--tv-text-meta);
    font-weight: var(--tv-weight-medium);
    line-height: var(--tv-leading-tight);
    cursor: pointer;
    padding: .125rem var(--tv-space-2);
}

.global-search-group__more:hover,
.global-search__all:hover {
    background: color-mix(in srgb, var(--tv-accent) 12%, transparent);
}

/* Underline the label rather than the button, so the muted hint line below it is not decorated
   too. Text decoration propagates to descendants and cannot be removed by the child, so this has
   to be targeted rather than undone. */
.global-search__all:hover .global-search__all-label {
    text-decoration: underline;
}

.global-search__all {
    display: block;
    width: 100%;
    border-radius: 0;
    text-align: center;
    padding: var(--tv-space-2);
    border-top: 1px solid var(--tv-search-border);
}

/* Second line on the show-all button, naming what the deep search adds. Muted and smaller so the
   button still reads as one action rather than two competing ones. */
.global-search__all-hint {
    display: block;
    margin-top: .125rem;
    font-size: .6875rem;
    color: var(--tv-search-muted);
}

.global-search-group__items {
    list-style: none;
    margin: 0;
    padding: 0 var(--tv-space-1) var(--tv-space-1);
}

.global-search-item {
    display: flex;
    align-items: center;
    gap: var(--tv-space-3);
    padding: var(--tv-space-2) var(--tv-space-3);
    border-radius: calc(var(--tv-default-border-radius) - .125rem);
    cursor: pointer;
}

.global-search-item:hover {
    background: var(--tv-search-hover);
}

.global-search-item--active,
.global-search-item--active:hover {
    /* An inset marker rather than an outline: the row is inside a scrolling panel, and an
       outline would be clipped at the top and bottom edges. The tint is accent-derived so the
       keyboard row is distinguishable from a plain mouse hover. */
    background: color-mix(in srgb, var(--tv-accent) 10%, transparent);
    box-shadow: inset .1875rem 0 0 0 var(--tv-accent);
}

/* The type glyph gets a disc so a row has a visual anchor at scan speed; the disc, not the glyph,
   carries the tint so the icon stays legible on both themes. */
.global-search-item__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 1.875rem;
    height: 1.875rem;
    border-radius: 50%;
    background: var(--tv-surface-alt);
    color: var(--tv-accent);
    font-size: 1rem;
}

.global-search-item__text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.global-search-item__title,
.global-search-item__subtitle {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: var(--tv-leading-tight);
}

.global-search-item__title {
    font-weight: var(--tv-weight-medium);
}

.global-search-item__subtitle {
    margin-top: .125rem;
    font-size: var(--tv-text-meta);
    color: var(--tv-search-muted);
}

/* Trailing metadata as pills, so "Emne" and the matched-in-content glyph look placed rather than
   abandoned at the far edge of the row. */
.global-search-item__status,
.global-search-item__badge {
    display: inline-flex;
    align-items: center;
    flex: none;
    gap: var(--tv-space-1);
    padding: .125rem var(--tv-space-2);
    border: 1px solid var(--tv-search-border);
    border-radius: 1rem;
    background: var(--tv-surface-alt);
    font-size: var(--tv-text-meta);
    line-height: var(--tv-leading-tight);
}

.global-search-item__badge {
    color: var(--tv-accent);
    border-color: transparent;
    background: color-mix(in srgb, var(--tv-accent) 12%, transparent);
}

/* Demoted hits are dimmed rather than removed. The status label beside them says why, so a
   low-ranked result reads as a decision instead of a bug — colour alone is never the signal. */
.global-search-item--demoted .global-search-item__title,
.global-search-item--demoted .global-search-item__icon {
    color: var(--tv-search-muted);
}

/* ── States and notices ── */

.global-search-state,
.global-search-notice {
    display: flex;
    align-items: flex-start;
    gap: var(--tv-space-3);
    padding: var(--tv-space-4) var(--tv-space-3);
    font-size: var(--tv-text-body);
}

.global-search-state > .mdi,
.global-search-notice > .mdi {
    flex: none;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--tv-accent);
}

.global-search-state--error,
.global-search-state--error > .mdi {
    color: var(--indicator-bad);
}

.global-search-state__hint {
    margin-top: var(--tv-space-1);
    font-size: var(--tv-text-meta);
    color: var(--tv-search-muted);
}

.global-search-notice {
    padding-block: var(--tv-space-2);
    border-top: 1px solid var(--tv-search-border);
    background: var(--tv-surface-alt);
    font-size: var(--tv-text-meta);
    color: var(--tv-search-muted);
}

.global-search__sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Full-screen page ──
   Everything below is scoped to the page (`--page`) so the dropdown keeps its compact rendering.
   The page fills the content column like every entity list does; the card and band treatment is
   borrowed from EntityDetail so the screens a user moves between look like siblings. */

/* Lives in the TopBar's right zone; the bar owns the layout, this only lets the chips wrap. */
.global-search-page__filters {
    flex-wrap: wrap;
}

.global-search-page .top-bar {
    margin-bottom: var(--tv-space-4);
}

.global-search-chip {
    border: 1px solid var(--tv-search-field-border);
    border-radius: 1rem;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--tv-text-body);
    padding: var(--tv-space-1) var(--tv-space-3);
    cursor: pointer;
}

.global-search-chip:hover {
    background: var(--tv-search-hover);
}

.global-search-chip--active,
.global-search-chip--active:hover {
    border-color: var(--tv-accent);
    background: var(--tv-accent);
    color: var(--tv-on-accent);
}

/* Each type is a card whose header is the same brand band EntityDetail draws over its form
   sections — one vocabulary for "this is a section" across the app. The band carries its own
   foreground because a brand fill does not track the theme (see app.css `--tv-form-section-*`). */
.global-search-results--page .global-search-group {
    overflow: hidden;
    margin-bottom: var(--tv-space-4);
    border: 1px solid var(--tv-search-border);
    border-radius: var(--tv-default-border-radius);
    background: var(--tv-surface);
}

.global-search-results--page .global-search-group__header {
    position: static;
    justify-content: flex-start;
    padding: var(--tv-space-2) var(--tv-space-4);
    border-top: none;
    background: var(--tv-form-section-header-surface);
    color: var(--tv-form-section-header-fg);
}

.global-search-results--page .global-search-group__heading {
    font-size: var(--tv-text-section);
    text-transform: none;
    letter-spacing: 0;
    color: inherit;
}

/* Outlined in the band's own foreground: an accent or neutral pill would vanish on brand blue. */
.global-search-group__count {
    font-size: var(--tv-text-meta);
    font-weight: var(--tv-weight-strong);
    line-height: 1;
    padding: .125rem .5rem;
    border-radius: 1rem;
    border: 1px solid currentColor;
    opacity: .85;
}

.global-search-results--page .global-search-group__items {
    padding: 0;
}

/* Full-width rows divide with hairlines instead of the popover's floating rounded rows. */
.global-search-results--page .global-search-item {
    padding: var(--tv-space-2) var(--tv-space-4);
    border-radius: 0;
}

.global-search-results--page .global-search-item + .global-search-item {
    border-top: 1px solid var(--tv-search-border);
}

.global-search-results--page .global-search-item__icon {
    width: 2.25rem;
    height: 2.25rem;
    font-size: 1.125rem;
}

.global-search-results--page .global-search-notice,
.global-search-results--page .global-search-state {
    padding: var(--tv-space-3) var(--tv-space-4);
    border: 1px solid var(--tv-search-border);
    border-radius: var(--tv-default-border-radius);
    background: var(--tv-surface);
}

/* The spinner glyph only spins if something tells it to; MDI ships the class, not the motion. */
@keyframes global-search-spin {
    to { transform: rotate(360deg); }
}

.global-search-state .mdi-spin {
    animation: global-search-spin 1s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .global-search-state .mdi-spin {
        animation: none;
    }
}
