/* ============================================================
   TKL Design System — CSS Custom Properties & Utilities
   ============================================================ */

/* Inter laddas från css/inter.css (självvärd) — länkas före den här filen i App.razor.
   Tidigare @import mot fonts.googleapis.com togs bort: blockerad i fastlandskina och
   render-blockerande, dessutom serialiserad efter att app.css hunnit laddas. */

/* ---- Light Mode ---- */
:root {
  /* Backgrounds & surfaces */
  --background:       210 20% 98%;
  --foreground:       215 25% 15%;
  --card:             0 0% 100%;
  --card-foreground:  215 25% 15%;
  --popover:          0 0% 100%;
  --popover-foreground: 215 25% 15%;

  /* Primary — TKL Teal */
  --primary:          199 89% 35%;
  --primary-foreground: 0 0% 100%;

  /* Secondary */
  --secondary:        210 15% 93%;
  --secondary-foreground: 215 25% 25%;

  /* Muted */
  --muted:            210 15% 96%;
  --muted-foreground: 215 15% 45%;

  /* Accent (teal light) */
  --accent:           199 89% 95%;
  --accent-foreground: 199 89% 25%;

  /* Semantic */
  --destructive:      0 84% 60%;
  --destructive-foreground: 0 0% 100%;
  --success:          142 76% 36%;
  --success-foreground: 0 0% 100%;
  --warning:          38 92% 50%;
  --warning-foreground: 0 0% 100%;

  /* Borders & inputs */
  --border:           214 20% 90%;
  --input:            214 20% 90%;
  --ring:             199 89% 35%;

  /* Border-radius */
  --radius:           0.5rem;

  /* TKL Brand */
  --tkl-navy:         215 50% 20%;
  --tkl-teal:         199 89% 35%;
  --tkl-teal-light:   199 70% 50%;
  --tkl-green:        142 76% 36%;
  --tkl-red:          0 84% 60%;
  --tkl-orange:       38 92% 50%;

  /* Transport types */
  --transport-express:   10 75% 55%;
  --transport-truck:     215 55% 30%;
  --transport-train:     195 70% 45%;
  --transport-air:       25 85% 55%;
  --transport-sea:       210 70% 55%;
  --transport-logistics: 270 60% 55%;
  --transport-other:     210 15% 60%;

  /* Sidebar */
  --sidebar-background:          215 50% 15%;
  --sidebar-foreground:          210 20% 95%;
  --sidebar-primary:             199 89% 55%;
  --sidebar-primary-foreground:  0 0% 100%;
  --sidebar-accent:              215 50% 22%;
  --sidebar-accent-foreground:   210 20% 95%;
  --sidebar-border:              215 40% 25%;
  --sidebar-ring:                199 89% 55%;
}

/* ---- Dark Mode ---- */
.dark {
  --background:       215 50% 8%;
  --foreground:       210 20% 95%;

  --card:             215 45% 12%;
  --card-foreground:  210 20% 95%;

  --popover:          215 45% 12%;
  --popover-foreground: 210 20% 95%;

  --primary:          199 89% 50%;
  --primary-foreground: 215 50% 10%;

  --secondary:        215 40% 18%;
  --secondary-foreground: 210 20% 90%;

  --muted:            215 40% 15%;
  --muted-foreground: 215 15% 55%;

  --accent:           199 50% 18%;
  --accent-foreground: 199 89% 70%;

  --destructive:      0 70% 50%;
  --destructive-foreground: 0 0% 100%;

  --success:          142 70% 45%;
  --success-foreground: 0 0% 100%;

  --warning:          38 90% 55%;
  --warning-foreground: 0 0% 100%;

  --border:           215 40% 20%;
  --input:            215 40% 20%;
  --ring:             199 89% 50%;

  --sidebar-background:         215 50% 6%;
  --sidebar-foreground:         210 20% 95%;
  --sidebar-primary:            199 89% 55%;
  --sidebar-primary-foreground: 0 0% 100%;
  --sidebar-accent:             215 50% 12%;
  --sidebar-accent-foreground:  210 20% 95%;
  --sidebar-border:             215 40% 15%;
  --sidebar-ring:               199 89% 55%;
}

/* ---- Body Reset ---- */
body {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.875rem;
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---- Select .input-field — custom arrow (beats Tailwind Preflight via specificity 0,1,1 > 0,0,1) ----
   Tailwind Preflight already sets appearance:none + background-image:none on all selects.
   We restore the SVG arrow only for .input-field selects using a more specific selector. ---- */
select.input-field {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path fill='%236b7280' d='M6 8L1 3h10z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.625rem center;
  padding-right: 2rem;
}

.dark select.input-field {
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path fill='%239ca3af' d='M6 8L1 3h10z'/></svg>");
}

/* ---- Scrollbar — Dark mode global ---- */
.dark {
  scrollbar-width: thin;
  scrollbar-color: hsl(215 40% 30%) transparent;
}

.dark *::-webkit-scrollbar { width: 8px; height: 8px; }
.dark *::-webkit-scrollbar-track { background: transparent; }
.dark *::-webkit-scrollbar-thumb {
  background: hsl(215 40% 28%);
  border-radius: 9999px;
  border: 2px solid transparent;
  background-clip: content-box;
}
.dark *::-webkit-scrollbar-thumb:hover {
  background: hsl(199 60% 35%);
  border: 2px solid transparent;
  background-clip: content-box;
}

/* ---- .scrollbar-thin utility (light + dark) ---- */
.scrollbar-thin::-webkit-scrollbar { width: 8px; height: 8px; }
.scrollbar-thin::-webkit-scrollbar-track { background: transparent; border-radius: 4px; }
.scrollbar-thin::-webkit-scrollbar-thumb {
  background: hsl(var(--muted-foreground) / 0.3);
  border-radius: 4px;
  transition: background 0.2s;
}
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
  background: hsl(var(--muted-foreground) / 0.5);
}
.scrollbar-thin {
  scrollbar-width: thin;
  scrollbar-color: hsl(var(--muted-foreground) / 0.3) transparent;
}

/* ---- .page-viewport: the page owns its scrolling instead of the document ---- */
/* Opt-in, for a page laid out as a flex column with a footer last: the page is exactly as
   tall as <main>'s content box, so nothing spills below the fold and the footer is always
   on screen.

   2.25rem is MainLayout's `p-6` on <main> (1.125rem top + bottom with the scaled padding
   scale in tailwind.config.js) — if that padding changes, change it here too. The alternative was converting the shell to `h-screen` + `min-h-0`,
   which moves every other page's scroll container from the document to <main>; not worth
   it for one page.

   dvh second so it wins where supported — on mobile 100vh is the *largest* viewport and
   would push the footer under the browser toolbar. A browser that doesn't know dvh drops
   that declaration and keeps the vh one. Two declarations for one property can't be
   ordered from a class attribute, which is why this isn't an `h-[...]` utility; and
   tailwind.css loads after this file, so never put an `h-*` utility on the same element. */
.page-viewport {
  height: calc(100vh - 2.25rem);
  height: calc(100dvh - 2.25rem);
}

/* ---- Text Gradient ---- */
.text-gradient {
  background: linear-gradient(to right, hsl(var(--primary)), hsl(var(--tkl-teal-light)));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ---- Semantic trend colors ---- */
.trend-up   { color: hsl(var(--success)); }
.trend-down { color: hsl(var(--destructive)); }

/* ---- Transport / Status badge utilities ---- */
.transport-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 0.9375rem;
}
.transport-sea     { background: hsl(var(--transport-sea) / 0.15);     color: hsl(var(--transport-sea));     }
.transport-air     { background: hsl(var(--transport-air) / 0.15);     color: hsl(var(--transport-air));     }
.transport-road    { background: hsl(var(--success) / 0.15);           color: hsl(var(--success));           }
.transport-rail    { background: hsl(var(--warning) / 0.15);           color: hsl(var(--warning));           }
.transport-cancelled { background: hsl(var(--destructive) / 0.15);    color: hsl(var(--destructive));       }
.transport-default { background: hsl(var(--muted-foreground) / 0.15); color: hsl(var(--muted-foreground)); }

/* ---- Button system (matches shadcn/ui spec) ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3125rem;
  white-space: nowrap;
  border-radius: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.125rem;
  height: 2rem;
  padding: 0 0.625rem;
  transition: all 150ms ease;
  cursor: pointer;
  border: 1px solid transparent;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
.btn:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }

/* Suppress focus ring when FocusOnNavigate programmatically focuses the page heading */
h1:focus:not(:focus-visible) { outline: none; }

.btn-primary {
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
}
.btn-primary:hover { background: hsl(var(--primary) / 0.9); }

.btn-outline {
  border-color: hsl(var(--border));
  background: transparent;
  color: hsl(var(--foreground));
}
.btn-outline:hover { background: hsl(var(--muted)); }

.btn-ghost {
  background: transparent;
  color: hsl(var(--foreground));
}
.btn-ghost:hover { background: hsl(var(--muted)); }

.btn-destructive {
  background: hsl(var(--destructive));
  color: hsl(var(--destructive-foreground));
}
.btn-destructive:hover { background: hsl(var(--destructive) / 0.9); }

.btn-success {
  background: hsl(var(--success));
  color: hsl(var(--success-foreground));
}
.btn-success:hover { background: hsl(var(--success) / 0.9); }

.btn-sm { height: 1.75rem; padding: 0 0.4375rem; font-size: 0.6875rem; }
.btn-icon { height: 2rem; width: 2rem; padding: 0; }

/* ---- Input / Label system ---- */
.input-field {
  width: 100%;
  height: 2rem;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  font-size: 0.8125rem;
  border-radius: 0.375rem;
  border: 1px solid hsl(var(--input));
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.input-field::placeholder { color: hsl(var(--muted-foreground)); }
.input-field:focus {
  outline: none;
  border-color: hsl(var(--ring));
  box-shadow: 0 0 0 2px hsl(var(--ring) / 0.25);
}
.input-field:disabled { opacity: 0.5; cursor: not-allowed; }

/* Textareas using .input-field should auto-grow with content, not use fixed 2rem height */
textarea.input-field {
  height: auto;
  min-height: 2rem;
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
  line-height: 1.4;
  resize: vertical;
  field-sizing: content;
}

/* padding-right for select.input-field is set above in the custom arrow block */

.input-label {
  display: block;
  font-size: 0.6875rem;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
  margin-bottom: 0.125rem;
}

/* ---- Number input — hide spinners ---- */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
input[type="number"] { -moz-appearance: textfield; }

/* ---- PWA / Notch support ---- */
@supports (padding-top: env(safe-area-inset-top)) {
  body { padding-bottom: env(safe-area-inset-bottom); }
  header.sticky { padding-top: env(safe-area-inset-top); }
}

/* ============================================================
   Blazor framework styles
   ============================================================ */

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

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* Validation styles */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid hsl(var(--success));
}

.invalid {
    outline: 1px solid hsl(var(--destructive));
}

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

/* ============================================================
   QuickGrid — match design tokens (header bg, padding, hover)
   ============================================================ */
.quickgrid {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8125rem;
}

.quickgrid th {
    background-color: hsl(var(--muted));
    color: hsl(var(--muted-foreground));
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid hsl(var(--border));
    text-align: left;
    white-space: nowrap;
}

.quickgrid td {
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid hsl(var(--border));
    color: hsl(var(--foreground));
    vertical-align: middle;
    transition: background-color 0.12s ease;
}

.quickgrid tbody tr:last-child td {
    border-bottom: none;
}

/* QuickGrid pads a short last page with empty rows up to ItemsPerPage. */
.quickgrid tbody tr:empty {
    display: none;
}

.quickgrid tbody tr:has(+ tr:empty) td {
    border-bottom: none;
}

.quickgrid tbody tr:hover td {
    background-color: hsl(var(--muted));
}

/* Sort indicator: make the column-header button blend in */
.quickgrid th button.col-title {
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.quickgrid th button.col-title:hover {
    color: hsl(var(--foreground));
}

/* ---- Resizable table columns (widths handled by wwwroot/js/table-columns.js) ---- */
/* The JS switches the table to `table-layout: fixed` and writes px widths into the
   <colgroup>. A cell can therefore no longer widen its column, so it wraps instead — see
   the cell rules below. */
.resizable-table th[data-col-key] {
    position: relative;
}

.resizable-table .col-resize-handle {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    width: 7px;
    cursor: col-resize;
    user-select: none;
    touch-action: none;
    z-index: 10;
}

.resizable-table .col-resize-handle::after {
    content: "";
    position: absolute;
    top: 20%;
    bottom: 20%;
    right: 3px;
    width: 2px;
    border-radius: 1px;
    background: hsl(var(--border));
    transition: background 0.12s ease;
}

.resizable-table .col-resize-handle:hover::after {
    background: hsl(var(--primary));
    top: 8%;
    bottom: 8%;
}

/* A column only ever gets as wide as its content needs, up to the cap in
   table-columns.js. Past that the value wraps rather than being clipped, so the whole
   thing stays readable — `overflow-wrap: anywhere` because reference strings like
   PO104013/103826/... offer no spaces to break on. The cell renderers'
   `whitespace-nowrap` is what keeps a value on one line while the column still fits it,
   so it has to be overridden here rather than removed there. */
.resizable-table td[data-col-cell] {
    overflow: hidden;
}

.resizable-table td[data-col-cell] > *,
.resizable-table td[data-col-cell] > .flex > span {
    max-width: 100%;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Opt out of the wrapping above for a line that is better clipped than wrapped — Route,
   which already stacks origin over destination, so wrapping both turns one row into four.
   Set by RenderFlagWithText, and only together with a `title` on the span: the tooltip is
   what makes the clipped tail reachable, so neither ships without the other. Placed after
   the rule above rather than made more specific — the two selectors tie on specificity and
   source order decides. */
.resizable-table td[data-col-cell] > .cell-truncate > span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The open column-filter row lives inside the header cell. Left visible during a
   measurement the column would come out as wide as the filter input rather than as wide as
   its values, and that width is cached for the rest of the page's life. */
.resizable-table.is-measuring [data-col-filter-row] {
    display: none;
}

/* table-columns.js adds this while it measures a column's natural width. Cells go back on
   one line for the duration, so the width that comes out is the width the value needs
   unwrapped — measuring them in their wrapped state would just return whatever the
   browser had already squeezed them into. Removed again in the same frame, so it never
   paints. */
.resizable-table.is-measuring td[data-col-cell] > *,
.resizable-table.is-measuring td[data-col-cell] > .flex > span {
    max-width: none;
    white-space: nowrap;
    overflow-wrap: normal;
}

body.col-resizing {
    cursor: col-resize;
    user-select: none;
}

/* Dragging a header sideways to move its column — wwwroot/js/table-column-reorder.js.
   The insertion bar rides on the header cell's ::before, which is free: the resize handle
   is a child span with its own ::after, and the header's bottom rule is an inset shadow. */
.resizable-table th[data-col-key] [data-col-drag] {
    cursor: grab;
}

body.col-dragging,
body.col-dragging .resizable-table th[data-col-key] [data-col-drag] {
    cursor: grabbing;
}

body.col-dragging {
    user-select: none;
}

.resizable-table th[data-col-key].col-drop-before::before,
.resizable-table th[data-col-key].col-drop-after::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    border-radius: 1px;
    background: hsl(var(--primary));
    /* The bar overhangs the neighbouring header, which is painted after this one on the
       right-hand edge. Above both the resize handle (z-index: 10) and the z-20 a header gets
       while its filter row is open, or that neighbour's background covers it. */
    z-index: 25;
}

.resizable-table th[data-col-key].col-drop-before::before {
    left: -1px;
}

.resizable-table th[data-col-key].col-drop-after::before {
    right: -1px;
}

/* SideDrawer. Blazor adds the panel to the DOM already in its final position, so a CSS
   *transition* has no starting frame to animate from and would never run. A keyframe
   animation does run on insert, which is why the slide-in lives here rather than as
   Tailwind `transition-transform` + a toggled `translate-x-full`. No Tailwind utility sets
   `animation`, so nothing in tailwind.css overrides these despite winning on load order. */
@keyframes tkl-drawer-in {
    from { transform: translateX(100%); }
    to   { transform: translateX(0); }
}

@keyframes tkl-drawer-backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.tkl-drawer-panel {
    animation: tkl-drawer-in 200ms cubic-bezier(0.32, 0.72, 0, 1);
}

.tkl-drawer-backdrop {
    animation: tkl-drawer-backdrop-in 200ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .tkl-drawer-panel,
    .tkl-drawer-backdrop {
        animation: none;
    }
}

/* ---- Drop-a-file-on-a-shipment-row highlight ---- */
/* wwwroot/js/shipment-row-drop.js toggles this class while a file drag is over the row. It is
   plain CSS rather than a Tailwind utility on purpose: the class is added at runtime, and the
   Tailwind CLI text-scans the source, so a `dark:` utility named only in JS would be absent
   from tailwind.css and the highlight would silently do nothing. See CLAUDE.md. */
tr.tkl-row-drop-active > td {
    background-color: hsl(var(--primary) / 0.1);
}

/* The outline goes on the row rather than a border on the cells: a border would shift every
   column by a pixel and make the whole table jump as the pointer moves between rows. */
tr.tkl-row-drop-active {
    outline: 2px dashed hsl(var(--primary));
    outline-offset: -2px;
}
