
/* Responsive Design */
@media (max-width: 640px) {
  .desktop-only {
    display: none !important;
  }
  .tablet-only {
    display: none !important;
  }
  .mobile-hidden {
    display: none !important;
  }
}
@media (min-width: 640px) and (max-width: 1024px) {
  .mobile-only{
    display: none !important;
  }
  .desktop-only {
    display: none !important;
  }
  .tablet-hidden {
    display: none !important;
  }
}
@media (min-width: 1025px) {
  .mobile-only {
    display: none !important;
  }
  .tablet-only {
    display: none !important;
  }
  .desktop-hidden {
    display: none !important;
  }
}

h1:focus {
    outline: none;
}

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

/* Drag-to-scroll cursor helpers for desktop: only show grab if horizontally scrollable */
.table-wrapper.h-scrollable {
  cursor: grab;
}
.table-wrapper.h-scrollable.drag-scrolling {
  cursor: grabbing !important;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
    font-size: var(--fs-xs);
    color: #374151; /* text-gray-700 */
    padding: 0.125rem 0.8rem; /* px-1 py-0.5 */
    border-radius: 0.8rem; /* rounded */
    border: 1px solid #e8e8e8;
    background: #f7f7f7;
}

/* Canonical form-control surface — the single source of truth for input styling. `.prefixed-input`
   (a div wrapping a grayed prefix + a borderless input; see Components/Shared/PrefixedTextInput) opts
   into the identical look by joining these selectors, so these values live in exactly one place. */
input, textarea, select, .prefixed-input {
    width: 100%;
    padding: 10px 12px;
    font-weight: normal;
    font-size: var(--fs-sm);
    outline: none;
    border-radius: 10px;
    background: #eef3f8;
    border: 1px solid transparent;
    transition: all 0.2s;
    box-sizing: border-box;
}
input:focus, textarea:focus, select:focus, .prefixed-input:focus-within {
    background: #fff;
    border-color: color-mix(in srgb, var(--accent-color) 45%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 16%, transparent);
}
input[disabled], textarea[disabled], select[disabled], .prefixed-input.disabled {
    background: #e9edf2;
}
input::placeholder, textarea::placeholder {
    color: #8695a5;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    appearance: textfield;
}
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 2.75rem;
  height: 1.5rem;
  border-radius: 999px;
  background: #d1d5db;
  border: 1px solid #c7cdd6;
  position: relative;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease;
  padding: 0;
}

input[type="checkbox"]::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 2px;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  background: #fff;
  transform: translateY(-50%);
  transition: transform 0.2s ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

input[type="checkbox"]:checked {
  background: var(--primary-color);
  border-color: var(--primary-color);
}

input[type="checkbox"]:checked::before {
  transform: translate(1.2rem, -50%);
}

input[type="checkbox"]:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.filterbg {
    position: absolute;
    z-index: -1;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    content: '';
    background: linear-gradient(100deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0) 100%);
    box-shadow: 0px -10px 10px inset rgba(0, 0, 0, 0.1);
}

html.sidebar-open,
body.sidebar-open {
    overflow: hidden;
    overscroll-behavior: none;
}

/* ── Navigation progress ────────────────────────────────────────────────────────────────────────────
   Driven by wwwroot/js/nav-progress.js, hosted in App.razor outside <Routes> so the per-navigation
   teardown of the whole .app subtree cannot take it with it. Global rather than scoped for the same
   reason — there is no component to scope it to. */
#nav-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 9998; /* under toasts (9999), over the error UI's neighbours */
    pointer-events: none;
}

.nav-progress-bar {
    height: 100%;
    width: 100%;
    transform: scaleX(0);
    transform-origin: 0 50%;
    background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
    box-shadow: 0 0 8px rgba(13, 108, 172, 0.5);
    /* Matches the trickle interval so the creep reads as continuous motion rather than steps. */
    transition: transform 200ms ease-out;
}

/* The final jump to 100% is quick, then the whole bar fades rather than snapping away. */
.nav-progress-bar.is-done {
    transition: transform 120ms ease-out, opacity 220ms ease 120ms;
    opacity: 0;
}

/* Dimming the outgoing page says "this content is stale" and, just as usefully, stops a second link
   being clicked while the first navigation is still in flight. Applied ~150ms in, so a fast response
   never flashes it. */
.app[data-navigating] .main {
    opacity: 0.6;
    pointer-events: none;
    transition: opacity 180ms ease;
}

@media (prefers-reduced-motion: reduce) {
    .nav-progress-bar {
        transition: none;
    }

    .app[data-navigating] .main {
        transition: none;
    }
}

/* ── Dialog placeholder shell ───────────────────────────────────────────────────────────────────────
   Painted by wwwroot/js/dialog-shell.js in the same frame as the click, and torn down the moment the
   real DialogInstance renders. Global rather than scoped: the host div lives in App.razor outside the
   Blazor root (so it survives the routed subtree being rebuilt), which scoped CSS cannot reach.
   Values are kept in step with DialogInstance.razor.css and LoadingText.razor.css so the handover to
   the real dialog is not a visible jump. */
body.dialog-shell-open {
    overflow: hidden;
}

/* Exactly DialogInstance's .modal-backdrop values. The real backdrop renders on top of this one for
   the frame before the observer tears it down, so any difference in colour would show as a flicker. */
.dialog-shell-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    z-index: 500;
    width: 100vw;
    animation: dialog-fadein 0.2s;
}

/* Handing over to the real dialog: fade out across the same 200ms its own backdrop fades in, so the
   page never brightens between the two scrims. Clicks stop landing here at once — the real dialog is
   already arriving and must own them. */
#dialog-shell[data-closing] .dialog-shell-backdrop {
    animation: none;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
}

@keyframes dialog-fadein {
    from { opacity: 0; }
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .dialog-shell-backdrop {
        animation: none;
    }

    #dialog-shell[data-closing] .dialog-shell-backdrop {
        transition: none;
    }
}
/* ── Import / Export ────────────────────────────────────────────────────────────────────────────────
   Global rather than scoped: the export tree, the import review and the conflict diff are four
   components that share one visual language, and Blazor's scoped CSS does not cross component
   boundaries. */

.exchange-body {
    padding: 1rem 1.25rem;
    overflow-y: auto;
    max-height: 60dvh;
}

.exchange-hint {
    margin: 0 0 1rem;
    color: var(--text-secondary, #555);
    font-size: 0.9rem;
    line-height: 1.5;
}

.exchange-footer {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.75rem 1.25rem;
    border-top: 1px solid var(--border-color, #e3e3e3);
}

.exchange-footer-actions {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
}

.exchange-toggle {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--text-secondary, #555);
    cursor: pointer;
}

/* Relation tree */

.relation-tree {
    list-style: none;
    margin: 0;
    padding: 0;
}

.relation-tree.nested {
    /* A rail rather than deep indentation: nesting stays readable without running out of width. */
    margin-left: 0.6rem;
    padding-left: 0.9rem;
    border-left: 2px solid var(--border-color, #e3e3e3);
}

.relation-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.35rem 0.25rem;
    border-radius: var(--border-radius, 6px);
    cursor: pointer;
}

.relation-row:hover {
    background: var(--hover-color, rgba(0, 0, 0, 0.04));
}

.relation-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.relation-count {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--text-secondary, #666);
    background: var(--surface-alt, rgba(0, 0, 0, 0.05));
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
}

.relation-tag {
    flex: 0 0 auto;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #666);
    border: 1px solid var(--border-color, #ddd);
    border-radius: 999px;
    padding: 0 0.4rem;
}

.relation-group-toggle {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.35rem 0.25rem;
    background: none;
    border: 0;
    font: inherit;
    color: var(--text-secondary, #555);
    cursor: pointer;
}

.relation-loading {
    padding: 0.25rem 0 0.25rem 1.5rem;
}

/* Import picker */

.import-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 2rem 1rem;
    border: 2px dashed var(--border-color, #d5d5d5);
    border-radius: var(--border-radius, 8px);
    color: var(--text-secondary, #666);
    cursor: pointer;
    text-align: center;
}

.import-drop i {
    font-size: 1.75rem;
}

.import-error {
    margin-top: 0.75rem;
    color: var(--danger-color, #b3261e);
    font-size: 0.875rem;
}

.import-success {
    color: var(--success-color, #2e7d32);
    font-weight: 500;
}

/* Import review */

.import-summary,
.import-bulk {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.import-bulk {
    font-size: 0.875rem;
    color: var(--text-secondary, #555);
}

.import-chip {
    font-size: 0.78rem;
    border-radius: 999px;
    padding: 0.1rem 0.6rem;
    white-space: nowrap;
}

.import-chip.new       { background: rgba(46, 125, 50, 0.12);  color: #2e7d32; }
.import-chip.unchanged { background: rgba(0, 0, 0, 0.06);      color: #555; }
.import-chip.conflict  { background: rgba(237, 108, 2, 0.14);  color: #b35400; }
.import-chip.blocked   { background: rgba(179, 38, 30, 0.12);  color: #b3261e; }

.import-warning {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: #b35400;
    margin: 0 0 0.5rem;
}

.import-group {
    border: 1px solid var(--border-color, #e3e3e3);
    border-radius: var(--border-radius, 8px);
    margin-bottom: 0.6rem;
    overflow: hidden;
}

.import-group-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.55rem 0.75rem;
    background: var(--surface-alt, rgba(0, 0, 0, 0.02));
    border: 0;
    font: inherit;
    cursor: pointer;
    text-align: left;
}

.import-group-name {
    font-weight: 500;
}

.import-group-counts {
    display: flex;
    gap: 0.35rem;
    margin-left: auto;
    flex-wrap: wrap;
}

.import-rows {
    list-style: none;
    margin: 0;
    padding: 0;
}

.import-row {
    border-top: 1px solid var(--border-color, #eee);
    padding: 0.4rem 0.75rem;
}

.import-row-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.import-row-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.import-row-reason {
    font-size: 0.8rem;
    color: #b3261e;
}

.import-row-toggle,
.import-row-bullet {
    width: 1.25rem;
    flex: 0 0 auto;
    background: none;
    border: 0;
    color: var(--text-secondary, #777);
    cursor: pointer;
}

.import-row-empty {
    padding: 0.6rem 0.75rem;
    font-size: 0.85rem;
    color: var(--text-secondary, #666);
}

.import-failures,
.import-stats {
    margin: 0.5rem 0 0;
    padding-left: 1.1rem;
    font-size: 0.875rem;
}

/* Conflict diff */

.conflict-diff {
    width: 100%;
    margin: 0.5rem 0 0.25rem;
    border-collapse: collapse;
    font-size: 0.85rem;
    /* Wide content scrolls inside its own box rather than pushing the dialog sideways. */
    display: block;
    overflow-x: auto;
}

.conflict-diff th,
.conflict-diff td {
    padding: 0.3rem 0.5rem;
    text-align: left;
    border-bottom: 1px solid var(--border-color, #eee);
    vertical-align: top;
}

.conflict-diff th {
    font-weight: 500;
    color: var(--text-secondary, #666);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.conflict-field  { width: 26%; }
.conflict-choice { width: 6rem; text-align: center; }

/* The struck-through side is the one being discarded, so the choice reads at a glance. */
.conflict-diff tr.takes-incoming .conflict-current {
    text-decoration: line-through;
    color: var(--text-secondary, #999);
}

.conflict-diff tr.keeps-current .conflict-incoming {
    text-decoration: line-through;
    color: var(--text-secondary, #999);
}

/* Settings blocks */

.settings-block {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 1rem 0;
    border-bottom: 1px solid var(--border-color, #eee);
}

.settings-block-text {
    flex: 1 1 auto;
}

.settings-block-text h3 {
    margin: 0 0 0.25rem;
    font-size: 0.95rem;
}

.settings-block-text p {
    margin: 0;
    font-size: 0.875rem;
    color: var(--text-secondary, #555);
    line-height: 1.5;
}
