/* The Sneat auth theme (lib/sneat) computes every primary-colored control (buttons, focus
   rings, checked checkboxes, links) from these CSS variables via color-mix(), so retargeting
   just the variables keeps the app's existing blue instead of Sneat's default violet without
   touching any of Sneat's layout/spacing rules. --bs-primary/-rgb are the same in both
   Bootstrap themes, so they're set unconditionally at :root. The three derived variants
   (text-emphasis/bg-subtle/border-subtle) DO differ between themes and must be scoped to
   [data-bs-theme="light"] only, NOT :root - :root always matches regardless of the current
   theme attribute, so an unscoped rule here would clobber Bootstrap's own correct
   [data-bs-theme="dark"] values (light-mode-appropriate navy text / pale-blue background would
   otherwise bleed into dark mode). #0d6efd is Bootstrap's own stock primary, so its built-in
   dark-theme variants already match without needing a dark override here. */
:root {
    --bs-primary: #0d6efd;
    --bs-primary-rgb: 13, 110, 253;
}

[data-bs-theme="light"] {
    --bs-primary-text-emphasis: #052c65;
    --bs-primary-bg-subtle: #cfe2ff;
    --bs-primary-border-subtle: #9ec5fe;
}

.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
}

.brand-image.fas {
    font-size: 1.4rem;
    line-height: 2.5rem;
}

.small-box .icon {
    opacity: 0.4;
}

.table-responsive-card {
    overflow-x: auto;
}

/* The card-body wrapping a data-table is padding-free (p-0) so the table itself sits flush
   with the card edges, but DataTables' own length/info/pagination controls render inside that
   same card-body and inherit the zero padding too — pushing them flush left/right instead of
   sitting inset like the rest of the card's content. Those controls sit in Bootstrap .row cells
   whose gutter padding and the row's own negative margin cancel out to zero net inset by
   design, so instead of fighting that cancellation, add an explicit margin directly on
   DataTables' own "start"/"end" position classes — additive on top of the row/column box model,
   so it can't be cancelled out the same way. Leaves the table's own row (marked with
   DataTables' "dt-layout-table" class) untouched so it still spans edge-to-edge. */
.table-responsive-card .dt-layout-start {
    margin-left: 1.25rem !important;
}
.table-responsive-card .dt-layout-end {
    margin-right: 1.25rem !important;
}
.table-responsive-card .dt-layout-row:last-child {
    padding-bottom: 0.75rem;
}

.required-asterisk::after {
    content: " *";
    color: #dc3545;
}

/* Dashboard interactivity & animation --------------------------------- */

@keyframes dash-fade-up {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes dash-pulse-scale {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.18); }
}

@keyframes dash-blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.25; }
}

.dashboard-page .dash-in {
    opacity: 0;
    animation: dash-fade-up 0.5s ease-out forwards;
    animation-delay: calc(var(--dash-delay, 0) * 60ms);
}

.dashboard-page .dash-hover {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.dashboard-page .dash-hover:hover {
    transform: translateY(-4px);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.12);
}

.dashboard-page .small-box,
.dashboard-page .info-box {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.dashboard-page .small-box:hover,
.dashboard-page .info-box:hover {
    transform: translateY(-3px);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}

.dashboard-page .dash-pulse {
    display: inline-block;
    animation: dash-pulse-scale 2.4s ease-in-out infinite;
}

.dashboard-page .dash-pulse-dot {
    font-size: 0.55rem;
    animation: dash-blink 1.6s ease-in-out infinite;
}

.dashboard-page .progress-bar.dash-bar {
    transition: width 1s cubic-bezier(0.22, 1, 0.36, 1);
}

.dashboard-page .dash-table tbody tr {
    transition: background-color 0.15s ease, transform 0.15s ease;
}

.dashboard-page .dash-table tbody tr:hover {
    transform: translateX(2px);
}

.dashboard-page [data-days] {
    transition: all 0.15s ease;
}

/* Row action buttons (Edit/Delete etc. in table listings) -------------- */

.table-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.table-actions .btn {
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.table-actions .btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.12);
}

@media (prefers-reduced-motion: reduce) {
    .dashboard-page .dash-in {
        opacity: 1;
        animation: none;
    }

    .dashboard-page .dash-pulse,
    .dashboard-page .dash-pulse-dot {
        animation: none;
    }

    .dashboard-page .dash-hover:hover,
    .dashboard-page .small-box:hover,
    .dashboard-page .info-box:hover,
    .dashboard-page .dash-table tbody tr:hover {
        transform: none;
    }

    .table-actions .btn:hover {
        transform: none;
    }
}

/* A Select2 dropdown sitting beside a button (e.g. the "add new customer/supplier/product" "+")
   in a flex row. Select2 sets an inline width:100% and its nowrap text gives the box a large
   automatic minimum width, so a long selected value stopped it shrinking and pushed the button
   under the neighbouring column. Let the box shrink (its text is ellipsized) and keep the button. */
.d-flex > .select2-container {
    flex: 1 1 0;
    min-width: 0;
}

.d-flex > .select2-container ~ .btn {
    flex-shrink: 0;
}

/* Line-item tables on the invoice/transfer/adjustment Create & Edit pages. Fixed layout means a
   long product name is truncated inside its Select2 box instead of widening the Product column
   and squeezing the number columns; below the min-width the card scrolls sideways instead.
   Product takes whatever width the fixed-width columns leave. */
.line-items-table {
    table-layout: fixed;
    min-width: 760px;
}

.line-items-table .select2-container {
    max-width: 100%;
}

.line-items-table .select2-selection__rendered,
.line-items-table .line-total,
.line-items-table .category-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Shimmer / skeleton loading ------------------------------------------------
   One animated gradient used for every "data is loading" placeholder: the page-level skeleton
   shown while a page loads or a link/form navigates away (#pageSkeleton in _Layout), the
   skeleton table rows AJAX tables show while fetching (skeletonRows() in site.js), and any
   element given the .shimmer class while its own value is being fetched. Colors come from
   per-theme variables so the sheen stays subtle in dark mode and visible in light mode. */
:root,
[data-bs-theme="light"] {
    --skeleton-base: rgba(0, 0, 0, 0.07);
    --skeleton-shine: rgba(255, 255, 255, 0.75);
}

[data-bs-theme="dark"] {
    --skeleton-base: rgba(255, 255, 255, 0.07);
    --skeleton-shine: rgba(255, 255, 255, 0.16);
}

@keyframes skeleton-shimmer {
    from { background-position: 150% 0; }
    to { background-position: -50% 0; }
}

.skeleton,
.shimmer {
    background-color: var(--skeleton-base) !important;
    background-image: linear-gradient(90deg, transparent 0%, var(--skeleton-shine) 50%, transparent 100%) !important;
    background-repeat: no-repeat !important;
    background-size: 50% 100% !important;
    animation: skeleton-shimmer 1.3s ease-in-out infinite;
}

.skeleton {
    display: block;
    border-radius: 0.375rem;
    height: 0.9rem;
}

/* An input/element marked .shimmer keeps its size but hides its text/placeholder. */
.shimmer {
    color: transparent !important;
    border-color: transparent !important;
}
.shimmer::placeholder {
    color: transparent !important;
}

.skeleton-row td {
    padding-top: 0.85rem !important;
    padding-bottom: 0.85rem !important;
}
.skeleton-row:nth-child(3n + 2) .skeleton { width: 70%; }
.skeleton-row:nth-child(3n) .skeleton { width: 85%; }

.skeleton-bubble {
    width: 60%;
    padding: 0.6rem 0.9rem;
    border-radius: 0.375rem;
}
.skeleton-bubble .skeleton + .skeleton { margin-top: 0.45rem; }

/* Page-level skeleton: hidden normally; while <html> has .page-loading it replaces the content
   area (the real content is hidden, not removed, so nothing re-initializes). .page-loading is
   set in <head> on first paint and cleared once scripts have initialized the page, and set
   again when a link/form navigates away until the next page arrives. */
.page-skeleton {
    display: none;
}

html.page-loading .page-skeleton {
    display: block;
    animation: dash-fade-up 0.25s ease-out;
}

/* visibility (not display:none) so DataTables/Chart.js can still measure widths while they
   initialize underneath; taken out of flow so the skeleton sits where the content will be. */
.app-content {
    position: relative;
}
html.page-loading .app-content > .container-fluid:not(.page-skeleton) {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    visibility: hidden;
    pointer-events: none;
}

html.page-ready .app-content > .container-fluid:not(.page-skeleton) {
    animation: page-content-in 0.3s ease-out;
}

@keyframes page-content-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

.page-skeleton .skeleton-stat {
    height: 5.5rem;
    border-radius: 0.5rem;
}
.page-skeleton .skeleton-title { height: 1.1rem; width: 30%; }
.page-skeleton .skeleton-button { height: 2rem; width: 7rem; }

@media (prefers-reduced-motion: reduce) {
    .skeleton,
    .shimmer {
        animation-duration: 2.5s;
    }
    html.page-loading .page-skeleton,
    html.page-ready .app-content > .container-fluid:not(.page-skeleton) {
        animation: none;
    }
}

@media print {
    .page-skeleton { display: none !important; }
    html.page-loading .app-content > .container-fluid:not(.page-skeleton) { position: static !important; visibility: visible !important; }
}

/* Page header toolbar: one right-aligned row on wide screens; tidy equal-width grid below xl */
.toolbar-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .5rem; margin-top: .5rem; }
.toolbar-actions > form { margin: 0; display: flex; }
.toolbar-actions .btn { display: inline-flex; align-items: center; justify-content: center; gap: .4rem; white-space: nowrap; width: 100%; }
@media (min-width: 1200px) {
    .toolbar-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; margin-top: 0; }
    .toolbar-actions > form { display: inline-flex; }
    .toolbar-actions .btn { width: auto; }
}
