/* ============================================
   SHARED FORM COMPONENT STYLES
   Used by: Transport, TimeRegistrationEdit, RouteCalculator, and other form components
   
   This file contains common patterns shared across multiple form components:
   - CSS Custom Properties (Design Tokens) with rem/em units
   - Modern CSS functions (clamp, min, max) for responsive design
   - User zoom support (WCAG 2.1 compliant)
   - Validation messages
   - Button containers
   - Dark mode support
   - Accessibility features (high contrast, touch targets, keyboard navigation)
   ============================================ */

/* ============================================
   CSS CUSTOM PROPERTIES (DESIGN TOKENS)
   All values use rem for user zoom support
   ============================================ */
:root {
    /* ===== Semantic Colors ===== */
    --tv-danger: #dc2626;
    --tv-success: #166534;
    --tv-info: #0ea5e9;
    --tv-focus-ring: #3b82f6;     /* blue-500 */
    --tv-focus-ring-shadow: rgba(59, 130, 246, .35);
    
    /* ===== Spacing Scale - rem units for zoom support ===== */
    --tv-spacing-xs: 0.25rem;   /* 4px */
    --tv-spacing-sm: 0.5rem;    /* 8px */
    --tv-spacing-md: 0.625rem;  /* 10px */
    --tv-spacing-lg: 0.75rem;   /* 12px */
    --tv-spacing-xl: 1rem;      /* 16px */
    --tv-spacing-2xl: 1.25rem;  /* 20px */
    --tv-spacing-3xl: 1.5rem;   /* 24px */
    --tv-spacing-4xl: 2rem;     /* 32px */
    --tv-spacing-5xl: 2.5rem;   /* 40px */

    /* ===== Form Row Spacing ===== */
    --tv-form-row-gap: 0.75rem;       /* 12px - gap between fields in a row */
    --tv-form-row-spacing: 0.5rem;    /* 8px  - margin-bottom between rows */
    --tv-field-grid-gap: 16px;        /* gap used by .tv-responsive-field-grid, both axes */
    
    /* ===== Border Radius ===== */
    --tv-radius-sm: 0.25rem;  /* 4px */
    --tv-radius-md: 0.375rem; /* 6px */
    --tv-radius-lg: 0.5rem;   /* 8px */
    
    /* ===== Touch Targets (WCAG 2.1 Compliance) ===== */
    --tv-touch-target-min: 2.75rem;        /* 44px - WCAG 2.1 Level AA */
    --tv-touch-target-accessible: 3rem;    /* 48px - WCAG 2.1 Level AAA */
    
    /* ===== Neutral Surfaces =====
       Deliberately achromatic and semi-transparent so a single value reads correctly on both
       light and dark backgrounds — it tints whatever sits behind it rather than asserting a
       colour of its own. */
    --tv-group-surface: rgba(127, 127, 127, 0.10);   /* grouped sub-form background */
    --tv-group-border: rgba(127, 127, 127, 0.18);    /* grouped sub-form outline */
    --tv-derived-surface: rgba(127, 127, 127, 0.14); /* computed, read-only field */
    --tv-hover-surface: rgba(127, 127, 127, 0.15);   /* icon-button hover */

    /* ===== Muted Text ===== */
    --tv-text-muted: #6c757d;
    --tv-text-primary: #212529;

    /* ===== Font Sizes ===== */
    --tv-font-xs: 0.75rem;   /* 12px */
    --tv-font-sm: 0.8125rem; /* 13px */
    --tv-font-md: 0.875rem;  /* 14px */
    --tv-font-base: 0.9375rem; /* 15px */
    --tv-font-lg: 1rem;      /* 16px */
}

/* Dark mode color adjustments.
   Only the text colours need inverting — the neutral surfaces above are transparent greys and
   already work either way. */
.tv-theme-dark {
    --tv-danger: #f87171;
    --tv-success: #34d399;
    --tv-info: #38bdf8;
    --tv-focus-ring: #60a5fa;
    --tv-focus-ring-shadow: rgba(96, 165, 250, .45);
    --tv-text-muted: #9ca3af;
    --tv-text-primary: #e5e7eb;
}

@media (prefers-color-scheme: dark) {
    :root {
        --tv-danger: #f87171;
        --tv-success: #34d399;
        --tv-info: #38bdf8;
        --tv-focus-ring: #60a5fa;
        --tv-focus-ring-shadow: rgba(96, 165, 250, .45);
        --tv-text-muted: #9ca3af;
        --tv-text-primary: #e5e7eb;
    }
}

/* ============================================
   LABELS AND REQUIRED INDICATORS
   ============================================ */

.required-indicator {
    color: var(--tv-danger);
}

/* ============================================
   FOCUS STATES
   ============================================ */

.e-btn:focus,
.sf-button:focus {
    outline: 0.125rem solid var(--tv-focus-ring); /* 2px */
    box-shadow: 0 0 0 0.1875rem var(--tv-focus-ring-shadow); /* 3px */
}

/* ============================================
   VALIDATION MESSAGES
   Consistent error messaging across all form components
   ============================================ */

.validation-message,
.form-validation-message {
    color: var(--tv-danger);
    font-size: var(--tv-font-xs);
    margin-top: var(--tv-spacing-xs);
    display: block;
    line-height: 1.4;
}

/* High contrast mode validation messages */
@media (forced-colors: active) {
    .validation-message,
    .form-validation-message {
        color: CanvasText;
    }
}

/* ============================================
   VALIDATION SUMMARY BOX
   Consolidated error summary shown after a save attempt
   ============================================ */

.validation-summary {
    background-color: #fee2e2;
    border: 0.0625rem solid var(--tv-danger);
    border-radius: var(--tv-radius-md);
    padding: var(--tv-spacing-md) var(--tv-spacing-lg);
    margin-bottom: var(--tv-spacing-xl);
    color: var(--tv-danger);
    font-size: var(--tv-font-sm);
}

.validation-summary ul {
    margin: var(--tv-spacing-xs) 0 0 var(--tv-spacing-xl);
    padding: 0;
}

@media (prefers-color-scheme: dark) {
    .validation-summary {
        background-color: rgba(248, 113, 113, 0.15);
    }
}

@media (forced-colors: active) {
    .validation-summary {
        border: 0.125rem solid CanvasText;
        background-color: Canvas;
        color: CanvasText;
    }
}

/* ============================================
   BUTTON CONTAINERS
   Shared pattern for form action buttons with fluid spacing
   ============================================ */

.form-button-container,
.form-actions,
.button-container,
.dialog-footer {
    display: flex;
    gap: clamp(0.625rem, 1.5vw, 0.75rem); /* 10px ? 12px */
    justify-content: flex-end;
    margin-top: clamp(1rem, 2vw, 2rem); /* 16px ? 32px */
    flex-wrap: wrap;
}

/* Mobile: Stack buttons vertically */
@media (max-width: 47.9375em) { /* 767px / 16 = 47.9375em */
    .form-button-container,
    .form-actions,
    .button-container,
    .dialog-footer {
        flex-direction: column-reverse;
        gap: var(--tv-spacing-md);
        margin-top: var(--tv-spacing-xl);
    }
}

/* ============================================
   BOTTOM-ALIGNED BUTTONS
   For inline form controls (checkboxes, etc.)
   ============================================ */

.bottom-button,
.form-inline-button {
    align-self: end;
}

/* ============================================
   FORM FIELD SPACING
   Consistent fluid spacing between form fields
   ============================================ */

.form-field,
.form-row > div {
    margin-bottom: clamp(1rem, 2vw, 1.25rem); /* 16px ? 20px */
}

/* Remove margin on last child */
.form-field:last-child {
    margin-bottom: 0;
}

/* Grid layouts: Remove margin (use gap instead) */
@media (min-width: 64em) { /* 1024px / 16 = 64em */
    .form-grid .form-field,
    .form-grid > div {
        margin-bottom: 0;
    }
}

/* ============================================
   RESPONSIVE CONTAINER WIDTH
   Single fluid constraint instead of 5 media queries
   ============================================ */

.form-container-responsive {
    max-width: min(100%, 87.5rem); /* 1400px / 16 = 87.5rem */
    padding: clamp(1rem, 2vw, 2.5rem); /* 16px ? 40px */
    margin: 0 auto;
}

/* ============================================
   2-COLUMN GRID UTILITY
   Responsive 2-column layout with fluid gap
   ============================================ */

.form-grid-2col {
    display: flex;
    flex-direction: column;
    gap: clamp(1rem, 2vw, 1.5rem); /* 16px ? 24px */
}

@media (min-width: 64em) { /* 1024px / 16 = 64em */
    .form-grid-2col {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: clamp(1.25rem, 2vw, 2.5rem); /* 20px ? 40px */
        column-gap: clamp(1.5rem, 3vw, 2.5rem); /* 24px ? 40px */
    }
}

/* Full-width items in 2-column grid */
.form-grid-2col .full-width,
.form-grid-2col .span-all {
    grid-column: 1 / -1;
}

/* ============================================
   ACCORDION STYLING (SYNCFUSION)
   Consistent fluid accordion spacing
   ============================================ */

.e-accordion {
    margin-top: var(--tv-form-row-spacing, 0.5rem);
}

.e-accordion .e-acrdn-panel .e-acrdn-content {
    padding: var(--tv-spacing-xs, 0.25rem);
}

/* Mobile: Reduced spacing */
@media (max-width: 47.9375em) { /* 767px / 16 = 47.9375em */
    .e-accordion .e-acrdn-item {
        margin-bottom: var(--tv-spacing-sm);
    }
}

/* ============================================
   SYNCFUSION AUTOCOMPLETE/DROPDOWN POPUP FIX
   Prevents popup from extending beyond the input width
   The popup is rendered in a portal at document root,
   so we need global CSS rules to constrain it.
   
   Using high specificity selectors to override Syncfusion's
   inline styles set via JavaScript.
   ============================================ */

/* 
   APPROACH: Use CSS attribute selectors to target popups by their 
   inline style width and override with max-width constraint.
   Syncfusion sets width inline, but max-width can still constrain it.
*/

/* CSS variable for popup max-width - can be set on parent container */
:root {
    --tv-popup-max-width: 100%;
}

/* 
   e-popup-constrained class: Apply to SfAutoComplete CssClass to enable
   popup width constraints. This ensures the popup doesn't extend beyond
   the viewport or its parent container.
*/

/* High specificity: Target the popup wrapper and content */
body .e-popup.e-ddl.e-popup-open,
body .e-popup.e-autocomplete.e-popup-open,
body .e-popup.e-dropdownbase.e-popup-open,
body .e-popup.e-timepicker.e-popup-open,
html body .e-popup.e-ddl,
html body .e-popup.e-autocomplete,
html body .e-popup.e-dropdownbase,
html body .e-popup.e-timepicker {
    max-width: 100vw !important;
    box-sizing: border-box !important;
    overflow-x: hidden !important;
}

/*
   KEY FIX: Constrain the popup's Syncfusion-set inline width with max-width
   (max-width takes precedence over width when max-width is smaller).
   Deliberately NO `width: auto` here: that would discard the inline width
   (= the input's width) and shrink-wrap the popup around its widest item,
   which defeats text-overflow ellipsis on single-line items — the popup
   grows to fit the text (up to the cap) instead of truncating it.
*/
body .e-popup.e-ddl[style*="width"],
body .e-popup.e-autocomplete[style*="width"],
body .e-popup.e-dropdownbase[style*="width"],
body .e-popup.e-timepicker[style*="width"] {
    min-width: 0 !important;
    max-width: min(var(--tv-popup-max-width, 100%), 100vw) !important;
}

/* ============================================
   SYNCFUSION TIMEPICKER POPUP FIX
   TimePicker popup has a different structure than autocomplete.
   These rules constrain the time selection popup to prevent it
   from extending to the screen edge.
   ============================================ */

/* Target the TimePicker popup specifically */
body .e-timepicker.e-popup,
body .e-timepicker-wrapper .e-popup,
html body .e-popup.e-timepicker {
    width: auto !important;
    min-width: 10rem !important; /* Minimum width for time values */
    max-width: min(20rem, 100vw - 1rem) !important; /* Cap at reasonable width */
    box-sizing: border-box !important;
}

/* Target TimePicker popup when opened with inline width style */
body .e-timepicker.e-popup[style*="width"],
body div.e-popup.e-control.e-timepicker[style*="width"] {
    width: auto !important;
    min-width: 10rem !important;
    max-width: min(20rem, 100vw - 1rem) !important;
}

/* Target the inner time list container */
body .e-timepicker.e-popup .e-content,
body .e-timepicker.e-popup .e-list-parent,
body .e-timepicker.e-popup .e-ul {
    max-width: 100% !important;
    overflow-x: hidden !important;
    box-sizing: border-box !important;
}

/* Target time list items */
body .e-timepicker.e-popup .e-list-item,
body .e-timepicker.e-popup li.e-list-item {
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    max-width: 100% !important;
}

/* Mobile: Ensure time picker popup fits within viewport */
@media (max-width: 47.9375em) { /* 767px / 16 = 47.9375em */
    body .e-timepicker.e-popup,
    body .e-timepicker.e-popup[style*="width"],
    html body .e-popup.e-timepicker {
        max-width: calc(100vw - 1rem) !important;
        width: auto !important;
    }
}

/* Target the inner list container with high specificity */
body .e-popup.e-ddl .e-content.e-dropdownbase,
body .e-popup.e-autocomplete .e-content.e-dropdownbase,
body .e-popup.e-ddl .e-dropdownbase.e-content,
body .e-popup.e-autocomplete .e-dropdownbase.e-content,
html body .e-popup .e-content {
    max-width: 100% !important;
    overflow-x: hidden !important;
    box-sizing: border-box !important;
}

/* ============================================
   HIGH CONTRAST MODE (ACCESSIBILITY)
   Windows High Contrast Mode support
   ============================================ */

@media (forced-colors: active) {
    /* Ensure visible borders */
    .form-container,
    .transport-container,
    .time-registration-container {
        border: 0.0625rem solid CanvasText; /* 1px */
        padding: var(--tv-spacing-sm);
    }
    
    /* Ensure visible button borders */
    .form-button-container .e-btn,
    .button-container .e-btn,
    .dialog-footer .e-btn {
        border: 0.125rem solid ButtonText; /* 2px */
    }
    
    /* Ensure text is visible */
    .form-label {
        color: CanvasText;
    }
}

/* ============================================
   LOADING STATE
   Shared spinner + label pattern used by EntityDetailPage, EntityListPage, EntityDetail
   ============================================ */

.tv-loading-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 500px;
    gap: 16px;
}

.tv-loading-text {
    font-size: 1.1rem;
    color: var(--e-primary);
}

/* ============================================
   ALERT BANNERS
   Shared .tv-alert + modifier pattern
   ============================================ */

.tv-alert {
    padding: 12px 16px;
    border-radius: var(--tv-radius-sm, 4px);
    margin-bottom: 8px;
    /* The modifiers below pin light background colours, so the foreground must be pinned too:
       inheriting it left near-white text on a cream background under the dark theme. */
    color: var(--tv-alert-fg, #212529);
}

.tv-alert-warning {
    background-color: #fff8e1;
    border-left: 4px solid #ffc107;
}

.tv-alert-info {
    background-color: #e3f2fd;
    border-left: 4px solid #2196f3;
}

/* ============================================
   UTILITY CLASSES
   ============================================ */

/* Spacing utilities */
.mt-sm { margin-top: var(--tv-spacing-sm); }
.mt-md { margin-top: var(--tv-spacing-md); }
.mt-lg { margin-top: var(--tv-spacing-lg); }
.mt-xl { margin-top: var(--tv-spacing-xl); }
.mt-2xl { margin-top: var(--tv-spacing-2xl); }

.mb-sm { margin-bottom: var(--tv-spacing-sm); }
.mb-md { margin-bottom: var(--tv-spacing-md); }
.mb-lg { margin-bottom: var(--tv-spacing-lg); }
.mb-xl { margin-bottom: var(--tv-spacing-xl); }
.mb-2xl { margin-bottom: var(--tv-spacing-2xl); }

/* Gap utilities */
.gap-sm { gap: var(--tv-spacing-sm); }
.gap-md { gap: var(--tv-spacing-md); }
.gap-lg { gap: var(--tv-spacing-lg); }
.gap-xl { gap: var(--tv-spacing-xl); }
.gap-2xl { gap: var(--tv-spacing-2xl); }

/* Text utilities */
.text-error { color: var(--tv-danger); }
.text-success { color: var(--tv-success); }
.text-info { color: var(--tv-info); }

/* ============================================
   PRINT STYLES
   Form printing support
   ============================================ */

@media print {
    /* Hide interactive elements */
    .form-button-container,
    .button-container,
    .dialog-footer,
    .bottom-button,
    .e-spin-overlay {
        display: none;
    }
    
    /* Ensure proper page breaks */
    .form-container,
    .time-registration-container,
    .transport-container,
    .outlays-container {
        page-break-inside: avoid;
    }
    
    /* High contrast for printing */
    .form-section {
        border: 0.0625rem solid #000; /* 1px */
        background: white;
    }
}

/* ============================================
   REDUCED MOTION (ACCESSIBILITY)
   Respect user's motion preferences
   ============================================ */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ============================================
   RESPONSIVE FIELD GRID
   Usage: class="tv-responsive-field-grid" style="--tv-grid-columns: N;"
   where N is a *ceiling* on the column count — normally
   DeviceBreakpoint.ToFieldColumnCount(), clamped to the number of fields so a short
   row is not spread out. The actual count follows the container width.
   Override --tv-field-min-width on a single grid to change where columns break.
   ============================================ */
.tv-responsive-field-grid {
    --tv-field-min-width: 14rem;
    display: grid;
    /* Fluid, but capped. The second max() term is the width one track would have if the
       container were split into exactly --tv-grid-columns equal columns; while it is the
       larger of the two, auto-fill can fit no more than that many tracks, which is what
       enforces the ceiling. Once the container narrows enough that it drops below
       --tv-field-min-width the minimum takes over and the column count falls off
       continuously instead of in breakpoint-sized steps. min(100%, ...) keeps a container
       narrower than one field from overflowing. */
    grid-template-columns: repeat(auto-fill, minmax(min(100%, max(var(--tv-field-min-width), (100% - (var(--tv-grid-columns, 1) - 1) * var(--tv-field-grid-gap, 16px)) / var(--tv-grid-columns, 1))), 1fr));
    gap: var(--tv-field-grid-gap, 16px);
    width: 100%;
    align-items: start;
}
.tv-responsive-field-grid > * { width: 100%; }

/* Collection editors (DynamicDataGrid) span all columns — they render as full-width grids */
.tv-responsive-field-grid > *:has(.tv-dynamic-datagrid) {
    grid-column: 1 / -1;
}

/* Custom-fields editors span all columns — they render their own inner responsive grid */
.tv-responsive-field-grid > *:has(.custom-field-input) {
    grid-column: 1 / -1;
}

/* Section editors (registered via CustomPropertyEditorRegistry.RegisterSection) own several
   related properties and lay them out themselves, so they span all columns. */
.tv-responsive-field-grid > *:has(.tv-entity-section) {
    grid-column: 1 / -1;
}

/* ============================================
   CUSTOMER INVOICE ADDRESSING SECTION
   Section editor owning the mutually exclusive invoice-address choice
   ============================================ */

.customer-invoice-address {
    display: flex;
    flex-direction: column;
    gap: var(--tv-spacing-md, 1rem);
}

.customer-invoice-address-choice {
    display: flex;
    flex-direction: column;
    gap: var(--tv-spacing-xs, 0.25rem);
}

.customer-invoice-address-label {
    font-weight: 600;
    margin-bottom: var(--tv-spacing-xs, 0.25rem);
}

/* Read-only preview of the address an invoice would actually carry. Bordered rather than filled,
   so it reads as informational and stays legible on both the light and dark themes. */
.customer-invoice-address-preview {
    padding: var(--tv-spacing-sm, 0.5rem) var(--tv-spacing-md, 1rem);
    border: 1px solid var(--tv-border-color, rgba(128, 128, 128, 0.35));
    border-radius: var(--tv-radius-sm, 4px);
}

.customer-invoice-address-preview-heading {
    font-weight: 600;
    margin-bottom: var(--tv-spacing-xs, 0.25rem);
}

.customer-invoice-address-empty {
    font-style: italic;
    opacity: 0.75;
}

/* Inline edit toggle: switches a derived field to hand-entered (e.g. transport km).
   Sits inside the field wrapper so it reads as belonging to that input. */
/* Inner row holding the km editor and its override pencil. Deliberately NOT also a .form-field:
   that class sets flex-direction: column, which would lay this out vertically and (with
   align-items: flex-end) right-align the input at content width instead of filling. */
.transport-distance-field {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    gap: var(--tv-spacing-xs, 0.25rem);
}

.transport-distance-field > :first-child {
    flex: 1;
    min-width: 0;
}

/* ============================================
   DERIVED (COMPUTED) FIELDS
   A value produced by the app rather than typed by the user. Syncfusion renders read-only
   inputs almost identically to editable ones — especially in dark themes — so without this
   there is no way to tell whether a number is yours or the system's.
   Background only: the text itself stays at full contrast, because a derived value is still
   something the user needs to read and check.
   ============================================ */

.tv-field-derived .e-input-group,
.tv-field-derived.e-input-group,
.tv-field-derived .e-control-wrapper {
    background-color: var(--tv-derived-surface, rgba(127, 127, 127, 0.14));
}

.tv-field-derived input {
    cursor: default;
}

/* Hint beneath a field, e.g. flagging that km was hand-entered. */
.tv-field-hint {
    font-size: var(--tv-font-xs);
    color: var(--tv-text-muted, #6c757d);
    margin-top: var(--tv-spacing-xs);
    line-height: 1.3;
}

@media (forced-colors: active) {
    /* Background carries no meaning in forced-colors, so fall back to a visible border. */
    .tv-field-derived .e-input-group,
    .tv-field-derived.e-input-group,
    .tv-field-derived .e-control-wrapper {
        border: 0.125rem dashed CanvasText;
    }
}

/* Square icon button sized to sit on the input's own line rather than the wrapper's bottom
   edge, and tall enough to be a comfortable hit target. The floating label occupies space
   above the input, so the row is aligned flex-end and the button's height is matched to the
   Syncfusion input rather than left to shrink to the glyph. */
.tv-inline-edit-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    /* Matches the Syncfusion textbox height so the two line up on the same baseline. */
    height: 2rem;
    width: 2rem;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Without this the glyph inherits the form's small font and reads as an artefact. */
    font-size: 1.125rem;
    line-height: 1;
    /* Nudges the icon off the input's bottom border onto its vertical centre. */
    margin-bottom: 0.25rem;
    color: var(--tv-text-muted, #6c757d);
    border-radius: var(--tv-radius-sm, 0.25rem);
}

.tv-inline-edit-toggle:hover {
    background: var(--tv-hover-surface, rgba(127, 127, 127, 0.15));
    color: var(--tv-text-primary, #212529);
}

/* Pressed = the field is currently hand-entered. */
.tv-inline-edit-toggle[aria-pressed="true"] {
    color: var(--color-sf-primary, #0d6efd);
}

.tv-inline-edit-toggle:focus-visible {
    outline: 2px solid var(--color-sf-primary, #0d6efd);
    outline-offset: 2px;
}
