body,
html,
#cesiumContainer {
    width: 100%;
    height: 100%;
    overflow: hidden;
    margin: 0;
    padding: 0;
}

/* ============================================================
   RTL (Hebrew) Label Fix for MudBlazor Input Controls

   Issue 1: Hebrew labels overlap with the control border lines
   because the label background doesn't properly mask the border.

   Issue 2: Hebrew labels appear on the left side instead of right.
   Labels need to be positioned on the right for RTL languages.

   Solution: Add proper background, padding, and RTL positioning.
   ============================================================ */

/* Fix for Outlined variant input labels (MudTextField, MudNumericField, MudSelect) */
.mud-input-label-outlined {
    background-color: var(--mud-palette-surface) !important;
    padding-left: 6px !important;
    padding-right: 6px !important;
}

/* RTL specific adjustments - position label on the RIGHT side with margin from edge */
[dir="rtl"] .mud-input-label-outlined {
    left: auto !important;
    right: 12px !important;
    padding-left: 8px !important;
    padding-right: 8px !important;
    transform-origin: top right !important;
}

/* RTL label in shrunk/floated state (when focused or has value) */
[dir="rtl"] .mud-input-label-outlined.mud-shrink {
    transform: translate(0, -9px) scale(0.75) !important;
    right: 12px !important;
}

/* Ensure label has correct background in dark theme */
.mud-theme-dark .mud-input-label-outlined {
    background-color: var(--mud-palette-surface) !important;
}

/* Fix for input controls inside MudPaper or MudCard */
.mud-paper .mud-input-label-outlined,
.mud-card .mud-input-label-outlined {
    background-color: var(--mud-palette-background) !important;
}

/* Fix label positioning for shrunk state (when label moves to top) */
.mud-input-label-outlined.mud-input-label-inputcontrol {
    background-color: inherit;
    padding-left: 6px;
    padding-right: 6px;
}

/* RTL fix for shrunk labels */
[dir="rtl"] .mud-input-label-outlined.mud-input-label-inputcontrol {
    left: auto !important;
    right: 12px !important;
    padding-left: 8px;
    padding-right: 8px;
}

/* Additional fix for fieldset legend (alternative label implementation) */
.mud-input-outlined .mud-input-outlined-border legend {
    padding-left: 4px;
    padding-right: 4px;
}

[dir="rtl"] .mud-input-outlined .mud-input-outlined-border legend {
    margin-left: auto !important;
    margin-right: 8px !important;
    padding-left: 6px;
    padding-right: 6px;
    text-align: right;
}

/* Fix for MudSelect dropdown labels */
.mud-select .mud-input-label-outlined {
    background-color: var(--mud-palette-surface) !important;
    padding-left: 6px !important;
    padding-right: 6px !important;
}

[dir="rtl"] .mud-select .mud-input-label-outlined {
    left: auto !important;
    right: 12px !important;
}

/* Fix for disabled inputs - ensure label background matches */
.mud-input-control.mud-disabled .mud-input-label-outlined {
    background-color: var(--mud-palette-surface) !important;
}

/* Fix for focused state */
.mud-input-control-input-container:focus-within .mud-input-label-outlined {
    background-color: var(--mud-palette-surface) !important;
}

/* Ensure proper z-index for label to appear above border */
.mud-input-label {
    z-index: 1;
}

/* Fix for MudNumericField spinner buttons area */
.mud-input-adornment {
    z-index: 0;
}

/* RTL fix for input text alignment */
[dir="rtl"] .mud-input-control input,
[dir="rtl"] .mud-input-control textarea {
    text-align: right !important;
}

/* RTL fix for numeric field - keep numbers LTR but align right */
[dir="rtl"] .mud-input-control input[type="number"],
[dir="rtl"] .mud-input-control input[inputmode="decimal"],
[dir="rtl"] .mud-input-control input[inputmode="numeric"] {
    direction: ltr;
    text-align: right !important;
}

/* RTL fix for input adornments (icons, buttons) */
[dir="rtl"] .mud-input-adornment-start {
    margin-left: 8px !important;
    margin-right: 0 !important;
}

[dir="rtl"] .mud-input-adornment-end {
    margin-left: 0 !important;
    margin-right: 8px !important;
}

/* RTL fix for MudNumericField spin buttons */
[dir="rtl"] .mud-numeric-field .mud-input-adornment {
    order: -1;
}

/* ============================================================
   MudBlazor Dialog Animation Override

   Replace the default scale/grow animation with a smoother
   fade in/out effect for less aggressive appearance.
   Disables all scale transforms and transitions on dialogs.
   ============================================================ */

/* Fade in animation for dialog appearance */
@keyframes dialog-fade-in {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* Completely disable MudBlazor dialog scale animations */
.mud-dialog,
.mud-dialog-container,
.mud-dialog-content,
.mud-dialog-content-body,
.mud-paper.mud-dialog {
    transform: none !important;
    transition: opacity 0.2s ease-out !important;
    animation: dialog-fade-in 0.2s ease-out !important;
}

/* Override the backdrop/overlay animation */
.mud-overlay,
.mud-overlay-dialog {
    transition: opacity 0.15s ease-out !important;
    animation: dialog-fade-in 0.15s ease-out !important;
}

/* Disable any MudBlazor default dialog transitions that cause scale effect */
.mud-dialog-container .mud-dialog,
.mud-dialog-container .mud-paper {
    transform: none !important;
    transform-origin: center center !important;
}

/* ============================================================
   Non-blocking GEOMETRY EDITOR dialogs (point / polyline / polygon)

   PointEditorComp / PolylineEditorComp / PolygonEditorComp are shown
   while the user must keep clicking the Cesium globe to set or add
   vertices. Their backdrop is made transparent and click-through so
   the map behind the (draggable) dialog stays interactive. The dialog
   card itself keeps pointer events. Hosts open them with
   BackgroundClass="polygon-editor-no-backdrop".
   ============================================================ */
.mud-overlay.polygon-editor-no-backdrop,
.polygon-editor-no-backdrop .mud-overlay-scrim {
    background: transparent !important;
    pointer-events: none !important;
}

.mud-dialog-container:has(.polygon-editor),
.mud-dialog-container:has(.polyline-editor),
.mud-dialog-container:has(.point-editor) {
    pointer-events: none !important;
}

.mud-dialog-container .mud-dialog:has(.polygon-editor),
.mud-dialog-container .mud-dialog:has(.polyline-editor),
.mud-dialog-container .mud-dialog:has(.point-editor) {
    pointer-events: auto !important;
}

/* Target the dialog wrapper that may have scale transitions */
.mud-dialog-width-full,
.mud-dialog-width-xs,
.mud-dialog-width-sm,
.mud-dialog-width-md,
.mud-dialog-width-lg,
.mud-dialog-width-xl,
.mud-dialog-width-xxl {
    transform: none !important;
    animation: dialog-fade-in 0.2s ease-out !important;
}

/* Ensure draggable dialogs also use fade animation */
.draggable-dialog,
.draggable-dialog .mud-dialog,
.draggable-dialog .mud-paper {
    transform: none !important;
    animation: dialog-fade-in 0.2s ease-out !important;
}

/* ============================================================
   RTL (Hebrew) Dialog Close Button Fix

   In RTL mode, the dialog close button (X) should appear on
   the LEFT side of the dialog title bar, not the right side.
   MudBlazor uses "mud-button-close" class for the close button.
   ============================================================ */

/* RTL fix for dialog title - make it relative for absolute positioning of close button */
[dir="rtl"] .mud-dialog-title {
    position: relative !important;
    display: flex !important;
    flex-direction: row !important;
}

/* Target MudBlazor's close button class specifically - move to left */
[dir="rtl"] .mud-dialog-title > .mud-button-close,
[dir="rtl"] .mud-dialog-title > button.mud-button-close {
    position: absolute !important;
    left: 8px !important;
    right: auto !important;
    top: 50% !important;
    transform: translateY(-50%) !important;
    order: -1 !important;
}

/* Also target any icon button that's a direct child of dialog title */
[dir="rtl"] .mud-dialog-title > .mud-icon-button {
    position: absolute !important;
    left: 8px !important;
    right: auto !important;
    top: 50% !important;
    transform: translateY(-50%) !important;
}

/* Ensure title content has proper margin in RTL to avoid overlap with close button */
[dir="rtl"] .mud-dialog-title .dialog-title-bar,
[dir="rtl"] .mud-dialog-title-content {
    margin-left: 48px !important;
    margin-right: 0 !important;
    padding-right: 8px !important;
}

/* Fix for dialog header layout in RTL - add padding for close button space */
[dir="rtl"] .mud-dialog .mud-dialog-title {
    padding-left: 48px !important;
    padding-right: 16px !important;
}

/* ============================================================
   RTL (Hebrew) Progress Bar Direction Fix

   In RTL mode, progress bars should fill from right to left
   instead of left to right.
   ============================================================ */

/* Reverse progress bar fill direction for RTL */
[dir="rtl"] .mud-progress-linear-bar {
    transform-origin: right !important;
}

/* Override the default left-to-right animation */
[dir="rtl"] .mud-progress-linear-bars {
    direction: rtl;
}

/* Ensure the progress bar container respects RTL */
[dir="rtl"] .mud-progress-linear {
    direction: rtl;
}

/* Fix for determinate progress bars in RTL */
[dir="rtl"] .mud-progress-linear-bar.mud-progress-linear-bar-1-determinate {
    transform-origin: right center !important;
}

/* ============================================================
   MapLibre Location Picking Mode - Crosshair Cursor

   This CSS is placed in the global stylesheet (not scoped) to ensure
   it applies to dynamically created MapLibre canvas elements.
   The picking-location-mode class is added via JavaScript when
   location picking is enabled.
   ============================================================ */

/* Force crosshair cursor on MapLibre canvas during location picking */
.picking-location-mode,
.picking-location-mode canvas,
.maplibregl-canvas-container.picking-location-mode,
.maplibregl-canvas.picking-location-mode {
    cursor: crosshair !important;
}

/* Also target any child elements */
.picking-location-mode * {
    cursor: crosshair !important;
}

/* ============================================================
   Global Location Picking Mode - Body-level Crosshair Cursor

   When body has 'location-picking-active' class, force crosshair
   on ALL elements except the dialog controls themselves.
   This ensures the cursor shows correctly even when hovering
   over overlay elements.
   ============================================================ */

/* Force crosshair on body and all descendants when picking is active */
body.location-picking-active,
body.location-picking-active * {
    cursor: crosshair !important;
}

/* Exception: Dialog controls should maintain normal cursor for usability */
body.location-picking-active .mud-dialog,
body.location-picking-active .mud-dialog *,
body.location-picking-active .dialog-picking-location .mud-dialog,
body.location-picking-active .dialog-picking-location .mud-dialog * {
    cursor: default !important;
}

body.location-picking-active .mud-button,
body.location-picking-active .mud-icon-button,
body.location-picking-active .mud-input-slot,
body.location-picking-active .mud-select,
body.location-picking-active .mud-radio {
    cursor: pointer !important;
}

/* ============================================================
   MudBlazor Select Dropdown Icon Size Constraints

   CRITICAL FIX: Constrain all images within MudSelect components
   to prevent huge icons from breaking dialog layout.

   Issue: Icons in hazard/team type selects were displaying at
   full size (200px+) instead of being constrained to 24x24px.

   Solution: Global CSS rules with !important to forcefully
   override all other styles and constrain image dimensions.
   ============================================================ */

/* Constrain ALL images within MudSelect components */
.mud-select img,
.mud-select-item img,
.mud-input-control img,
.mud-list-item img {
    max-width: 24px !important;
    max-height: 24px !important;
    width: auto !important;
    height: auto !important;
    object-fit: contain !important;
    flex-shrink: 0 !important;
}

/* Specific constraint for select-item-icon class */
.select-item-icon,
img.select-item-icon,
.mud-select .select-item-icon,
.mud-select-item .select-item-icon,
.mud-list-item .select-item-icon {
    width: 24px !important;
    height: 24px !important;
    max-width: 24px !important;
    max-height: 24px !important;
    min-width: 24px !important;
    min-height: 24px !important;
    object-fit: contain !important;
    flex-shrink: 0 !important;
}

/* Constrain images within the selected value display */
.mud-input-control .mud-input-slot img,
.mud-select .mud-select-input img {
    max-width: 24px !important;
    max-height: 24px !important;
    width: 24px !important;
    height: 24px !important;
    object-fit: contain !important;
}

/* Constrain images within dropdown popover */
.mud-popover img,
.mud-menu img,
.mud-list img {
    max-width: 24px !important;
    max-height: 24px !important;
    object-fit: contain !important;
}

/* ------------------------------------------------------------
   RTL nested-menu chevron.

   MudBlazor's nested <MudMenu> renders a ChevronRight glyph in
   .mud-menu-submenu-icon and does NOT flip it for right-to-left.
   In Hebrew the submenu opens to the LEFT, so the arrow must point
   left too. Menu popovers render on <body> (outside the tool's own
   dir container), but <html dir="rtl"> is set app-wide, so this
   document-level selector reaches them. Rotate rather than swap the
   icon so no C#/markup change is needed.
   ------------------------------------------------------------ */
[dir="rtl"] .mud-menu-submenu-icon {
    transform: scaleX(-1);
}

/* Additional safety - constrain ALL images within dialogs */
.mud-dialog img.select-item-icon,
.mud-dialog .mud-select img,
.mud-dialog .mud-list-item img {
    max-width: 24px !important;
    max-height: 24px !important;
    width: 24px !important;
    height: 24px !important;
    object-fit: contain !important;
    flex-shrink: 0 !important;
}

/* ============================================================
   Dialog Width and Layout Improvements

   Ensure all dialogs have proper minimum width and spacing
   for a comfortable user experience.
   ============================================================ */

/* Ensure dialogs have proper minimum width */
.mud-dialog {
    min-width: 420px !important;
}

/* Dialog content should have proper padding */
.mud-dialog-content {
    padding: 20px 24px !important;
}

/* Dialog actions should have proper padding */
.mud-dialog-actions {
    padding: 16px 24px !important;
    gap: 12px !important;
}

/* Form fields in dialogs should have proper spacing */
.mud-dialog .mud-input-control {
    margin-bottom: 16px !important;
}

/* Last form field shouldn't have bottom margin */
.mud-dialog .mud-input-control:last-of-type {
    margin-bottom: 0 !important;
}

/* ============================================================
   Application Header Styling Improvements

   Enhanced styling for the main application header with better
   typography, visual hierarchy, and professional appearance.
   ============================================================ */

/* Main header container */
.c4i-header {
    display: flex !important;
    justify-content: space-between !important;
    align-items: center !important;
    padding: 10px 24px !important;
    background: linear-gradient(135deg, rgba(13, 27, 42, 0.95) 0%, rgba(21, 101, 192, 0.25) 100%) !important;
    border-bottom: 1px solid rgba(33, 150, 243, 0.4) !important;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3) !important;
    min-height: 64px !important;
    backdrop-filter: blur(8px) !important;
}

/* Header left section with icon and title */
.header-left {
    display: flex !important;
    align-items: center !important;
    gap: 14px !important;
    flex: 1 !important;
    min-width: 0 !important;
}

/* Header icon styling */
.header-icon {
    color: #66BB6A !important;
    filter: drop-shadow(0 0 6px rgba(102, 187, 106, 0.6)) !important;
    font-size: 2rem !important;
}

/* Title container */
.header-title {
    display: flex !important;
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 3px !important;
    min-width: 0 !important;
    flex-shrink: 0 !important;
}

/* Main title text */
.title-main {
    font-size: 1.25rem !important;
    font-weight: 700 !important;
    color: rgba(255, 255, 255, 0.98) !important;
    white-space: nowrap !important;
    letter-spacing: 0.4px !important;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5) !important;
    line-height: 1.3 !important;
}

/* Subtitle text */
.title-sub {
    font-size: 0.8125rem !important;
    font-weight: 500 !important;
    color: rgba(33, 150, 243, 0.9) !important;
    white-space: nowrap !important;
    letter-spacing: 0.3px !important;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) !important;
    line-height: 1.2 !important;
}

/* Header menu container */
.header-menu {
    display: flex !important;
    align-items: center !important;
    gap: 4px !important;
    margin-left: 24px !important;
    padding-left: 24px !important;
    border-left: 1px solid rgba(33, 150, 243, 0.35) !important;
}

/* Menu item buttons - simplified styling */
.header-menu .menu-item,
.header-menu .mud-button-root {
    color: rgba(255, 255, 255, 0.9) !important;
    font-size: 0.875rem !important;
    font-weight: 500 !important;
    padding: 6px 12px !important;
    border-radius: 4px !important;
    transition: all 0.2s ease !important;
}

/* Menu item hover state */
.header-menu .menu-item:hover,
.header-menu .mud-button-root:hover {
    background: rgba(33, 150, 243, 0.15) !important;
    color: rgba(255, 255, 255, 1) !important;
}

/* Menu item active state */
.header-menu .menu-item:active,
.header-menu .mud-button-root:active {
    background: rgba(33, 150, 243, 0.25) !important;
}

/* Menu spacing */
.header-menu .mud-menu {
    margin: 0 3px !important;
}

/* ============================================================
   Side Panel Width Constraints

   Prevent side panels from growing wider when in-panel editors
   are opened. Lock panels to their defined widths.
   ============================================================ */

/* Left and right panel width constraints */
.panel-left,
.panel-right {
    width: 378px !important;
    min-width: 342px !important;
    max-width: 378px !important;
    flex-shrink: 0 !important;
    flex-grow: 0 !important;
}

/* Collapsed panel state */
.panel-left.panel-collapsed,
.panel-right.panel-collapsed {
    width: 40px !important;
    min-width: 40px !important;
    max-width: 40px !important;
}

/* Ensure panel content doesn't force expansion */
.panel-left .panel-content,
.panel-right .panel-content {
    overflow-x: hidden !important;
    max-width: 100% !important;
}

/* Ensure all children respect panel width */
.panel-left *,
.panel-right * {
    max-width: 100% !important;
    box-sizing: border-box !important;
}

/* ============================================================
   MudBlazor Layout - Full Viewport Height Fix

   Make MudLayout and MudMainContent fill the entire viewport
   so child components can use height: 100% properly.
   ============================================================ */

/* MudLayout must be a flex container filling viewport */
.mud-layout {
    display: flex !important;
    flex-direction: column !important;
    height: 100vh !important;
    min-height: 100vh !important;
}

/* MudMainContent must fill remaining space after AppBar */
.mud-main-content {
    flex: 1 1 auto !important;
    display: flex !important;
    flex-direction: column !important;
    min-height: 0 !important; /* Critical for flex children to shrink */
    overflow: hidden !important;
}

/* Ensure direct children of MudMainContent fill the space */
/* IMPORTANT: Only target page content, not dialogs/overlays/popups */
.mud-main-content > .c4i-container,
.mud-main-content > div:not(.mud-overlay):not(.mud-popover-provider):not(.mud-dialog-provider):not(.mud-snackbar-provider) {
    flex: 1 1 auto;
    min-height: 0;
}

/* ============================================================
   Hide Panel Collapse Buttons

   Remove collapse/expand buttons from side panels.
   ============================================================ */

.panel-collapse-btn,
.panel-collapse-btn-right {
    display: none !important;
}

/* ============================================================
   FIX INPUT CONTROL HEIGHTS IN DIALOGS

   Issue: Input controls (MudSelect, MudTextField, MudNumericField)
   in dialogs have insufficient height, causing text truncation.

   Solution: Force minimum heights on all input controls globally
   to ensure proper text display without truncation.
   ============================================================ */

/* MudSelect - Fix dropdown height */
.mud-select,
.mud-input-control .mud-select {
    min-height: 40px !important;  /* Reduced from 56px */
}

.mud-select .mud-input-control-input-container {
    min-height: 40px !important;  /* Reduced from 56px */
    display: flex !important;
    align-items: center !important;
}

.mud-select-input {
    min-height: 40px !important;  /* Reduced from 56px */
    display: flex !important;
    align-items: center !important;
    padding-top: 8px !important;   /* Reduced from 16px */
    padding-bottom: 8px !important; /* Reduced from 16px */
    padding-left: 14px !important;
    padding-right: 14px !important;
    line-height: 1.1 !important;
}

/* Fix for selected value text in MudSelect */
.mud-select .mud-input-text,
.mud-select-input .mud-input-text {
    line-height: 1.1 !important;
    padding: 0 !important;
}

/* Ensure select content wrapper doesn't clip text */
.mud-select .mud-input-control,
.mud-select .mud-input {
    overflow: visible !important;
}

/* MudTextField - Fix text input height */
.mud-input-control .mud-input-root {
    min-height: 40px !important;  /* Reduced from 56px */
}

.mud-input-control input[type="text"],
.mud-input-control textarea {
    padding-top: 8px !important;   /* Reduced from 16px */
    padding-bottom: 8px !important; /* Reduced from 16px */
    min-height: 24px !important;
    line-height: 1.1 !important;
    height: auto !important;
}

/* Fix MudBlazor input elements to prevent text clipping */
.mud-input-root input,
.mud-input input,
.mud-input-outlined input {
    padding: 16px 14px !important;
    line-height: 1.1 !important;
    height: auto !important;
    min-height: 24px !important;
    width: 100% !important;
    box-sizing: border-box !important;
}

/* Ensure text is vertically centered */
.mud-input-root-text,
.mud-input-root {
    display: flex !important;
    align-items: center !important;
    width: 100% !important;
}

/* Fix horizontal text overflow - allow scrolling */
.mud-input-slot input,
.mud-input-control input,
.mud-select-input {
    overflow-x: auto !important;
    overflow-y: hidden !important;
    white-space: nowrap !important;
    text-overflow: clip !important;
}

/* Ensure input containers take full width */
.mud-input-control,
.mud-input-outlined,
.mud-input-slot {
    width: 100% !important;
}

/* MudNumericField - Fix numeric input height */
.mud-input-control input[type="number"],
.mud-input-control input[inputmode="decimal"],
.mud-input-control input[inputmode="numeric"] {
    padding-top: 16px !important;
    padding-bottom: 16px !important;
    min-height: 24px !important;
}

/* All outlined variant inputs */
.mud-input-outlined .mud-input-root,
.mud-input-outlined .mud-input-control-input-container {
    min-height: 56px !important;
}

/* Fix outlined variant fieldset to accommodate taller inputs */
.mud-input-outlined .mud-input-outlined-border {
    min-height: 56px !important;
}

/* Ensure outlined inputs have proper internal height */
.mud-input-outlined .mud-input-slot,
.mud-input-outlined .mud-input {
    min-height: 56px !important;
    display: flex !important;
    align-items: center !important;
}

/* Prevent overflow clipping in outlined inputs */
.mud-input-outlined {
    overflow: visible !important;
}

.mud-input-outlined .mud-input-root {
    overflow: visible !important;
}

/* Ensure the input slot container has proper height */
.mud-input-slot {
    min-height: 56px !important;
    display: flex !important;
    align-items: center !important;
}

/* Fix for input control containers */
.mud-input-control-input-container {
    min-height: 56px !important;
    display: flex !important;
    align-items: center !important;
}

/* Fix label positioning to not overlap with taller inputs */
.mud-input-label-outlined {
    top: -9px !important;
}

.mud-input-label-outlined.mud-shrink {
    transform: translateY(-9px) scale(0.75) !important;
}

/* Fix select items in dropdown to have proper height */
.mud-list-item {
    min-height: 48px !important;
    padding-top: 8px !important;
    padding-bottom: 8px !important;
}

.mud-list-item-text {
    line-height: 1.1 !important;
    display: flex !important;
    align-items: center !important;
}

/* Limit dropdown popover max height to prevent it from being too tall */
.mud-popover-content,
.mud-list {
    max-height: 300px !important;
    overflow-y: auto !important;
}

/* Specific fix for MudSelect dropdown */
.mud-select .mud-popover .mud-list {
    max-height: 300px !important;
    overflow-y: auto !important;
}

.mud-popover.mud-popover-open .mud-list {
    max-height: 300px !important;
    overflow-y: auto !important;
}

/* Ensure icons in select items are properly aligned */
.mud-list-item .select-item-icon {
    margin-right: 12px !important;
}

[dir="rtl"] .mud-list-item .select-item-icon {
    margin-right: 0 !important;
    margin-left: 12px !important;
}

/* ============================================================
   FIX ADDRESS INPUT FIELD WIDTH IN LOCATION COMPONENTS

   Issue: Address input fields are too narrow and text gets truncated.

   Solution: Ensure address text fields in location controls have
   adequate minimum width to display full addresses.
   ============================================================ */

/* Address input field in location controls should expand to fill available space */
.location-controls-row .mud-input-control,
.location-controls-row .mud-text-field {
    flex: 1 1 auto !important;
    min-width: 250px !important;
}

/* Ensure the address field doesn't shrink below usable width */
.location-controls-row .mud-input-root {
    width: 100% !important;
}

/* Dialog-specific fix for location input rows */
.mud-dialog .location-controls-row {
    width: 100% !important;
}

.mud-dialog .location-controls-row .mud-text-field,
.mud-dialog .location-controls-row .mud-input-control {
    flex: 1 1 auto !important;
    min-width: 250px !important;
    max-width: 100% !important;
}

/* Ensure buttons don't shrink the text field */
.location-controls-row .mud-button-root {
    flex-shrink: 0 !important;
}

/* ============================================================
   DRAGGABLE DIALOG CRITICAL FIX

   MudBlazor renders dialogs at document body level, outside
   component scope. Scoped CSS (::deep) doesn't work there.
   These global styles ensure draggable dialogs work properly.

   Issue: Dialog has computed position:static instead of fixed,
   and pointer-events are blocked.
   ============================================================ */

/* CRITICAL: Draggable dialogs MUST use fixed positioning for dragging */
.mud-dialog.draggable-dialog {
    position: fixed !important;
    margin: 0 !important;
    transform: none !important;
    pointer-events: auto !important;
    z-index: 1400 !important;
}

/* Ensure the container doesn't block positioning */
.mud-dialog-container .mud-dialog.draggable-dialog {
    position: fixed !important;
    margin: 0 !important;
    transform: none !important;
}

/* Dialog title must receive pointer events for dragging */
.draggable-dialog .mud-dialog-title {
    pointer-events: auto !important;
    cursor: move !important;
    user-select: none !important;
}

/* Dialog title bar (custom class) must receive pointer events */
.draggable-dialog .dialog-title-bar {
    pointer-events: auto !important;
    cursor: move !important;
    user-select: none !important;
}

/* Dialog content and actions must receive pointer events */
.draggable-dialog .mud-dialog-content {
    pointer-events: auto !important;
}

.draggable-dialog .mud-dialog-actions {
    pointer-events: auto !important;
}

/* Buttons inside dialog must be clickable */
.draggable-dialog button,
.draggable-dialog .mud-button-root,
.draggable-dialog .mud-icon-button {
    pointer-events: auto !important;
    cursor: pointer !important;
}

/* MudBlazor focus trap elements should not block interactions */
.draggable-dialog .mud-focus-trap,
.draggable-dialog .mud-focus-trap-child-container {
    pointer-events: auto !important;
}

/* Ensure overlay allows clicks through to dialog */
.mud-overlay-dialog {
    pointer-events: auto !important;
}

/* The overlay scrim should allow clicks to pass to dialog */
.mud-overlay-scrim {
    pointer-events: auto !important;
}

/* Ensure the dialog container itself has pointer events */
.mud-dialog-container {
    pointer-events: auto !important;
}

/* The dialog-center class container should have pointer events */
.mud-dialog-center {
    pointer-events: auto !important;
}

/* CRITICAL: MudBlazor overlay structure fix
   The mud-overlay element wraps everything and can block events */
.mud-overlay {
    pointer-events: auto !important;
}

/* Ensure the skip-overlay elements don't block */
.mud-skip-overlay-section,
.mud-skip-overlay-positioning {
    pointer-events: auto !important;
}

/* ============================================================
   CRITICAL FIX: MudBlazor Focus Trap Elements
   MudBlazor adds elements with class "fixed pointer-events-none"
   that block ALL interactions with the dialog.
   ============================================================ */

/* The focus trap helper divs should not receive pointer events */
.mud-focus-trap .fixed.pointer-events-none,
.mud-dialog-container .fixed.pointer-events-none,
.mud-overlay-dialog .fixed.pointer-events-none {
    pointer-events: none !important;
    z-index: -1 !important;  /* Push them behind everything */
}

/* Global override for pointer-events-none class inside dialogs */
.mud-overlay-dialog .pointer-events-none {
    pointer-events: none !important;
}

/* But ensure the actual dialog and its contents ARE clickable */
.mud-dialog-container .mud-dialog,
.mud-dialog-container .mud-dialog * {
    pointer-events: auto !important;
}

/* Ensure focus trap child container passes events through */
.mud-focus-trap-child-container,
.mud-focus-trap-child-container * {
    pointer-events: auto !important;
}

/* The dialog itself must be above all focus trap elements */
.mud-dialog.draggable-dialog {
    z-index: 1500 !important;
    position: relative !important;
}

/* Ensure the overlay scrim is BEHIND the dialog, not on top */
.mud-overlay-scrim {
    z-index: 1300 !important;
}

/* The focus trap elements should not block clicks to the dialog */
.mud-focus-trap {
    pointer-events: none !important;
}

.mud-focus-trap > * {
    pointer-events: auto !important;
}

/* ============================================================
   MudBlazor Warning Color Override

   Change the default bright yellow warning color to a darker
   orange for better contrast with white text on chips and buttons.

   MudBlazor default warning: #FFC107 (bright yellow)
   New warning color: #E65100 (deep orange)
   ============================================================ */

/* Override MudChip with Warning color - solid filled variant */
.mud-chip.mud-chip-color-warning,
.mud-chip-warning {
    background-color: #E65100 !important;
    color: #FFFFFF !important;
}

/* Override MudChip with Warning color - outlined variant */
.mud-chip.mud-chip-color-warning.mud-chip-outlined {
    background-color: transparent !important;
    border-color: #E65100 !important;
    color: #E65100 !important;
}

/* Override MudChip with Warning color - text variant */
.mud-chip.mud-chip-color-warning.mud-chip-variant-text {
    background-color: rgba(230, 81, 0, 0.1) !important;
    color: #E65100 !important;
}

/* Hover states for warning chips */
.mud-chip.mud-chip-color-warning:hover {
    background-color: #BF360C !important;
}

.mud-chip.mud-chip-color-warning.mud-chip-outlined:hover {
    background-color: rgba(230, 81, 0, 0.1) !important;
}

/* Override warning color CSS variable for broader coverage */
:root {
    --mud-palette-warning: #E65100 !important;
    --mud-palette-warning-text: #FFFFFF !important;
    --mud-palette-warning-lighten: #FF6D00 !important;
    --mud-palette-warning-darken: #BF360C !important;
}

/* ============================================================
   Snackbar Border Visibility Enhancement

   Add a border around snackbar messages to make them more visible.
   The border color matches the text color for each severity level.
   ============================================================ */

/* Base snackbar border style */
.mud-snackbar {
    border-width: 1px !important;
    border-style: solid !important;
}

/* Normal/Default snackbar - use text primary color */
.mud-snackbar.mud-alert-text-normal {
    border-color: var(--mud-palette-text-primary) !important;
}

/* Info snackbar - blue border */
.mud-snackbar.mud-alert-text-info {
    border-color: var(--mud-palette-info) !important;
}

/* Success snackbar - green border */
.mud-snackbar.mud-alert-text-success {
    border-color: var(--mud-palette-success) !important;
}

/* Warning snackbar - orange border */
.mud-snackbar.mud-alert-text-warning {
    border-color: var(--mud-palette-warning) !important;
}

/* Error snackbar - red border */
.mud-snackbar.mud-alert-text-error {
    border-color: var(--mud-palette-error) !important;
}

/* ============================================================
   Snackbar Text Contrast — foreground adopted per background

   Snackbars use Variant.Filled (see Program.cs
   SnackbarConfiguration.SnackbarVariant = Variant.Filled), so the
   background is the severity/colour fill and the message text has to
   be picked per fill rather than left at MudBlazor's blanket white:

     GREEN   (success)             -> purple text
     BLUE    (info / primary)      -> white text
     MAGENTA (secondary / warning-
              free accent fills)   -> white text

   Green is the only fill bright enough to swallow white text, so it
   is the one that flips to the app purple; the darker blue and
   magenta fills keep white, which is the readable choice on them.

   Each rule covers the snackbar root, the message element, and any
   markup nested inside a message, so a call site passing rich content
   cannot leak the inherited colour back in.
   ============================================================ */

/* ---- GREEN background -> PURPLE text ---- */
.mud-snackbar.mud-alert-filled-success,
.mud-snackbar.mud-alert-filled-success .mud-snackbar-content-message,
.mud-snackbar.mud-alert-filled-success .mud-alert-message,
.mud-snackbar.mud-alert-filled-success .mud-snackbar-content-message * {
    color: var(--mud-palette-primary) !important;
}

.mud-snackbar.mud-alert-filled-success .mud-icon-root,
.mud-snackbar.mud-alert-filled-success .mud-button-root {
    color: var(--mud-palette-primary) !important;
    fill: var(--mud-palette-primary) !important;
}

/* ---- BLUE background -> WHITE text ---- */
.mud-snackbar.mud-alert-filled-info,
.mud-snackbar.mud-alert-filled-info .mud-snackbar-content-message,
.mud-snackbar.mud-alert-filled-info .mud-alert-message,
.mud-snackbar.mud-alert-filled-info .mud-snackbar-content-message *,
.mud-snackbar.mud-alert-filled-primary,
.mud-snackbar.mud-alert-filled-primary .mud-snackbar-content-message,
.mud-snackbar.mud-alert-filled-primary .mud-alert-message,
.mud-snackbar.mud-alert-filled-primary .mud-snackbar-content-message * {
    color: #FFFFFF !important;
}

.mud-snackbar.mud-alert-filled-info .mud-icon-root,
.mud-snackbar.mud-alert-filled-info .mud-button-root,
.mud-snackbar.mud-alert-filled-primary .mud-icon-root,
.mud-snackbar.mud-alert-filled-primary .mud-button-root {
    color: #FFFFFF !important;
    fill: #FFFFFF !important;
}

/* ---- MAGENTA background -> WHITE text ---- */
.mud-snackbar.mud-alert-filled-secondary,
.mud-snackbar.mud-alert-filled-secondary .mud-snackbar-content-message,
.mud-snackbar.mud-alert-filled-secondary .mud-alert-message,
.mud-snackbar.mud-alert-filled-secondary .mud-snackbar-content-message *,
.mud-snackbar.mud-alert-filled-tertiary,
.mud-snackbar.mud-alert-filled-tertiary .mud-snackbar-content-message,
.mud-snackbar.mud-alert-filled-tertiary .mud-alert-message,
.mud-snackbar.mud-alert-filled-tertiary .mud-snackbar-content-message * {
    color: #FFFFFF !important;
}

.mud-snackbar.mud-alert-filled-secondary .mud-icon-root,
.mud-snackbar.mud-alert-filled-secondary .mud-button-root,
.mud-snackbar.mud-alert-filled-tertiary .mud-icon-root,
.mud-snackbar.mud-alert-filled-tertiary .mud-button-root {
    color: #FFFFFF !important;
    fill: #FFFFFF !important;
}

/* ============================================================
   Green LABELS -> PURPLE text (same contrast rule as snackbars)

   The rule above fixes toasts, but the identical problem shows up on
   every other green-filled label: the tier chip on /account ("Premium"),
   the app-bar trial chip, PAID badges in the billing table, and green
   MudAlerts. MudBlazor fills those with the bright success green and
   puts blanket white on top, which is exactly the combination that
   reads poorly — so they take the app purple here too.

   Scoped to FILLED greens only. A Variant.Text / Variant.Outlined chip
   has a transparent background and already draws its label IN green;
   forcing purple there would hurt rather than help.

   The DARK purple #4a148c is used rather than --mud-palette-primary
   (#7E6FFF): the palette purple is light and sits too close to the
   green in luminance to be legible on it. #4a148c is the same value
   the yearly-discount pill on /pricing already uses on its green fill,
   so the two green labels stay consistent.
   ============================================================ */
.mud-chip.mud-chip-filled.mud-chip-color-success,
.mud-chip.mud-chip-filled.mud-chip-color-success *,
.mud-alert.mud-alert-filled-success,
.mud-alert.mud-alert-filled-success .mud-alert-message,
.mud-alert.mud-alert-filled-success .mud-alert-message *,
.mud-badge.mud-badge-filled.mud-badge-color-success,
.mud-button-filled.mud-button-filled-success,
.mud-button-filled.mud-button-filled-success * {
    color: #4a148c !important;
    font-weight: 600;
}

.mud-chip.mud-chip-filled.mud-chip-color-success .mud-icon-root,
.mud-alert.mud-alert-filled-success .mud-icon-root,
.mud-button-filled.mud-button-filled-success .mud-icon-root {
    color: #4a148c !important;
    fill: #4a148c !important;
}

/* ============================================================
   MudTabs — Segmented "pill" tab bar (app-wide)

   Restyle every MudTabs header into the segmented pill control
   shown in the design: a rounded, bordered container holding the
   tab buttons; the ACTIVE tab is a filled purple rounded pill with
   white text; inactive tabs are transparent with muted text. The
   default MudBlazor sliding underline indicator is hidden in favour
   of the pill fill.

   Global (unscoped) so it reaches every tool's MudTabs regardless of
   the per-tool Class name (lostool-tabs, camtool-tabs, gbtool-tabs,
   cd-tabs, climate-tabs, drone-chart-tabs, …).

   DOM (this MudBlazor version, verified in the live browser):
     .mud-tabs-tabbar               (header bar — border/margin/pill container)
       > .mud-tabs-tabbar-content
           > .mud-tabs-tabbar-wrapper   (flex row — the actual tab track)
               > .mud-tooltip-root       (per-tab wrapper — the flex ITEM; display:block, grow:0 by default)
                   > .mud-tab
   (.mud-tabs-tabbar-inner wraps the content element — it is NOT the tab track.)
   NOTE: NOT .mud-tabs-toolbar (that older class name matches nothing
   here — earlier rules on it were silently dead). The flex item that
   must grow is the .mud-tooltip-root wrapper (a direct child of
   .mud-tabs-tabbar-wrapper), not .mud-tab directly.
   ============================================================ */

/* The header bar becomes the rounded, bordered pill container.

   It spans the FULL horizontal extent of the hosting panel and carries a
   margin all around so it reads as a distinct control, separated from the
   surrounding editor content / the purple tool header above it
   (matches the reference design). */
.mud-tabs .mud-tabs-tabbar {
    background-color: var(--mud-palette-surface) !important;
    border: 1px solid var(--mud-palette-lines-default, rgba(126, 111, 255, 0.35)) !important;
    border-radius: 10px !important;
    padding: 4px !important;
    margin: 8px !important;
    /* Full-width strip: box-sizing keeps the 8px side margins honest so the
       bordered container never overflows its panel and forces a scrollbar. */
    width: auto !important;
    box-sizing: border-box !important;
    min-height: 0 !important;
    box-shadow: inset 0 0 0 1px rgba(126, 111, 255, 0.12) !important;
}

/* The intermediate content/inner elements must pass full width through so
   the wrapper (the real tab track) can span the whole strip.
   min-height:0 is REQUIRED — MudBlazor defaults .mud-tabs-tabbar-inner to
   min-height:48px, which would force the whole strip ~48px tall regardless
   of the compact pill height below. */
.mud-tabs .mud-tabs-tabbar-content,
.mud-tabs .mud-tabs-tabbar-inner {
    width: 100% !important;
    display: flex !important;
    flex: 1 1 auto !important;
    min-width: 0 !important;
    min-height: 0 !important;
    align-items: center !important;
}

/* The wrapper is the flex row that actually holds the per-tab items. */
.mud-tabs .mud-tabs-tabbar-wrapper {
    gap: 6px !important;
    min-height: 0 !important;
    width: 100% !important;
    display: flex !important;
    flex: 1 1 auto !important;
    align-items: center !important;
}

/* The per-tab wrapper (tooltip root) is the real flex item inside the track;
   grow it to an equal share so its child pill fills that share. Default is
   display:block / flex-grow:0, so it must be overridden to distribute. */
.mud-tabs .mud-tabs-tabbar-wrapper > .mud-tooltip-root {
    flex: 1 1 0 !important;
    min-width: 0 !important;
    min-height: 0 !important;
    display: flex !important;
}

/* Each tab is a rounded, self-contained pill button that grows to fill the
   equal share handed to it by its wrapper.

   Height: MudBlazor's default .mud-tab is 48px tall — too tall next to the
   compact ChatBot toggle strip (~32px item). Pin an explicit height (both
   height AND min-height, or the 48px default min wins) so the pill matches
   the ChatBot toggle-group height. */
.mud-tabs .mud-tab {
    border-radius: 8px !important;
    height: 32px !important;
    min-height: 32px !important;
    min-width: 0 !important;
    flex: 1 1 0 !important;
    width: 100% !important;
    margin: 0 !important;
    padding: 2px 16px !important;
    text-transform: uppercase !important;
    font-weight: 600 !important;
    letter-spacing: 0.4px !important;
    color: var(--mud-palette-text-secondary) !important;
    opacity: 1 !important;
    transition: background-color 0.15s ease, color 0.15s ease !important;
}

/* Icon + label INLINE inside the pill (ChatBotComp toggle style: a small
   icon immediately before the text).

   MudBlazor already lays the tab out as inline-flex with the icon element
   (.mud-tab-icon-text) followed by the text node — there is NO .mud-tab-content
   wrapper. So we only need to (a) keep it centered (my .mud-tab rules set
   align-items via the flex host) and (b) size the icon down + tighten its
   margin to match the ChatBot toggle's Size.Small icon (default margin is 8px). */
.mud-tabs .mud-tab {
    align-items: center !important;
    justify-content: center !important;
}

.mud-tabs .mud-tab .mud-tab-icon-text {
    margin-right: 6px !important;
    margin-inline-end: 6px !important;
    margin-inline-start: 0 !important;
}

.mud-tabs .mud-tab .mud-tab-icon-text .mud-icon-root,
.mud-tabs .mud-tab .mud-tab-icon-text.mud-icon-root {
    font-size: 1.15rem !important;
    width: 1.15rem !important;
    height: 1.15rem !important;
}

/* Hover state on inactive tabs: subtle purple tint. */
.mud-tabs .mud-tab:hover {
    background-color: rgba(126, 111, 255, 0.12) !important;
    color: var(--mud-palette-text-primary) !important;
}

/* ACTIVE tab: solid purple fill + white text (the highlighted pill). */
.mud-tabs .mud-tab.mud-tab-active,
.mud-tabs .mud-tab.mud-tab-active:hover {
    background-color: var(--mud-palette-primary) !important;
    color: #ffffff !important;
    box-shadow: 0 2px 6px rgba(126, 111, 255, 0.45) !important;
}

/* Icon inside the active tab follows the white text colour. */
.mud-tabs .mud-tab.mud-tab-active .mud-icon-root {
    color: #ffffff !important;
}

/* Hide the default sliding underline indicator — the pill fill replaces it. */
.mud-tabs .mud-tab-slider {
    display: none !important;
}

/* ============================================================
   GreenBuildingTool center tab strip (Map / CAD switcher)

   This is a CUSTOM strip (two MudButtons in a .gbtool-center-tabs div,
   NOT a MudTabs) above the central panel. Its own scoped .razor.css was
   not reliably reaching the browser (fingerprinted _content bundle
   staleness), leaving the buttons content-width and crammed at the left.
   Style it here in the reliably-served global sheet so the two buttons
   distribute evenly across the full panel width, consistent with the
   app-wide pill tab bar above.
   ============================================================ */
.gbtool-center-tabs {
    display: flex !important;
    gap: 6px !important;
    padding: 4px 8px !important;
    align-items: center !important;
}

/* Each button grows to an equal share of the strip width. */
.gbtool-center-tabs > .mud-button-root {
    flex: 1 1 0 !important;
    min-width: 0 !important;
}


/* ============================================================
   HOME LANDING PAGE (modern SaaS look, theme-aware)

   Lives in this global sheet rather than HomePage.razor.css because
   scoped-CSS edits do not reliably reach the browser after a rebuild
   (stale fingerprinted _content bundle) - the same reason the
   GreenBuilding tab strip above is styled here.

   Palette note: there is no background photo. The page takes its surface
   colour from the active MudBlazor theme via the --gv-* variables defined
   on .gv-home (light) and .geoview-theme-dark .gv-home (dark). Tool/domain
   cards are opaque, bordered and elevated with a 3D drop shadow so they sit
   above the surface. The hero and AI band keep their deep-ink glass so the
   teal/blue accents still read in either theme.
   All sizes use clamp()/grid so the page reflows down to ~360px phones.
   ============================================================ */

/* ============================================================
   THEME-AWARE PALETTE
   ------------------------------------------------------------
   The landing page has no background photo any more: it adapts to the
   active MudBlazor theme. The default (light) variables live on .gv-home;
   the dark overrides live under .geoview-theme-dark (the class MainLayout
   stamps on MudLayout). Everything downstream — cards, headings, footer —
   reads these variables, so a single override block flips the whole page.
   ============================================================ */
.gv-home {
    /* Light theme (default) */
    --gv-ink: #0d1b2a;
    --gv-mute: #4b5f75;
    --gv-dim: #7b8ea3;
    --gv-signal: #0f9c86;
    --gv-signal-2: #2a72c8;
    --gv-violet: #6f5bd6;
    --gv-cyan: #0097a7;
    --gv-line: rgba(13, 27, 42, 0.16);

    /* Page surface + card surface (opaque now that there is no photo behind). */
    --gv-surface: #f4f6f9;
    --gv-card-bg: #ffffff;
    --gv-card-border: rgba(13, 27, 42, 0.16);
    /* 3D drop shadow that lifts each card above the page surface. */
    --gv-card-shadow: 0 2px 4px rgba(13, 27, 42, 0.08), 0 10px 24px -12px rgba(13, 27, 42, 0.28);
    --gv-card-shadow-hover: 0 6px 12px rgba(13, 27, 42, 0.12), 0 22px 40px -14px rgba(13, 27, 42, 0.42);

    position: relative;
    /* Escape MudMainContent's padding so the surface is truly full-bleed. */
    margin: -8px;
    min-height: calc(100vh - 50px);
    color: var(--gv-ink);
    background: var(--gv-surface);
    overflow-x: hidden;
}

/* ---------- dark-theme overrides ---------- */
.geoview-theme-dark .gv-home {
    --gv-ink: #eaf1f8;
    --gv-mute: #a8bdd2;
    --gv-dim: #7f93a8;
    --gv-signal: #3fe6c4;
    --gv-signal-2: #5cb0ff;
    --gv-violet: #a99bf0;
    --gv-cyan: #4fd6e6;
    --gv-line: rgba(255, 255, 255, 0.14);

    --gv-surface: #10161d;
    --gv-card-bg: #1a222c;
    --gv-card-border: rgba(255, 255, 255, 0.12);
    /* Deeper shadow + subtle top highlight reads as "raised" on a dark ground. */
    --gv-card-shadow: 0 2px 4px rgba(0, 0, 0, 0.45), 0 12px 28px -12px rgba(0, 0, 0, 0.65);
    --gv-card-shadow-hover: 0 6px 14px rgba(0, 0, 0, 0.55), 0 24px 46px -14px rgba(0, 0, 0, 0.75);
}

.gv-content {
    position: relative;
    z-index: 2;
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 clamp(16px, 4vw, 32px);
}

/* ---------- shared section rhythm ---------- */
.gv-section {
    padding: clamp(48px, 7vw, 88px) 0;
}

/* The page now opens directly with the intro paragraph, so the first section
   needs far less top padding than a mid-page one. */
.gv-section-top {
    padding-top: clamp(32px, 4vw, 56px);
}

/* Sections that follow the intro: the intro already supplies the breathing room
   above, so these only need the standard gap between blocks. */
.gv-section-tight {
    padding-top: 0;
}

/* Opening "what is GeoView" paragraph — the first thing on the page, so it is
   set larger than the ordinary section lede. */
.gv-intro {
    color: var(--gv-ink);
    max-width: 68ch;
    font-size: clamp(18px, 2.1vw, 22px);
    line-height: 1.6;
    margin: 0;
}

.gv-eyebrow {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 12px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gv-signal);
    margin-bottom: 16px;
}

.gv-eyebrow::before {
    content: "";
    width: 26px;
    height: 1px;
    background: var(--gv-signal);
    flex: 0 0 26px;
}

.gv-eyebrow-c {
    justify-content: center;
}

/* The page's largest headings ("What Is GeoView ?", "Four Zones, One Map",
   "Explore Our Tools") are cyan. The smaller uppercase category titles stay
   purple, so the two heading levels read as distinct tiers. */
.gv-h2 {
    font-weight: 700;
    font-size: clamp(26px, 4.4vw, 44px);
    line-height: 1.08;
    letter-spacing: -0.025em;
    max-width: 22ch;
    margin: 0 0 18px;
    color: var(--gv-cyan);
}

.gv-h2-tight {
    max-width: 18ch;
}

/* "Explore Our Tools" — the page's main heading now that the hero is gone. */
.gv-h2-tools {
    font-size: clamp(32px, 5vw, 52px);
    margin-bottom: 6px;
}

.gv-h2-c {
    margin-inline: auto;
    text-align: center;
}

.gv-sec-lede {
    color: var(--gv-mute);
    max-width: 62ch;
    font-size: clamp(15px, 1.6vw, 17px);
    line-height: 1.62;
    margin: 0;
}

.gv-sec-lede-c {
    margin-inline: auto;
    text-align: center;
}

/* ---------- hero ---------- */
.gv-hero {
    display: flex;
    align-items: center;
    min-height: clamp(520px, 78vh, 760px);
    padding: clamp(32px, 6vw, 64px) 0;
}

/* Deep ink glass: the neon-ish accents from the reference design need a dark
   ground to read against, while the map still shows through. */
.gv-hero-panel {
    width: 100%;
    background: linear-gradient(155deg, rgba(9, 20, 33, 0.90), rgba(12, 28, 45, 0.82));
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 18px;
    padding: clamp(28px, 5vw, 60px);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 30px 80px -30px rgba(6, 18, 30, 0.65);
    color: #eaf1f8;
}

.gv-status {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 11.5px;
    letter-spacing: 0.04em;
    color: #8fa6bd;
    margin-bottom: 26px;
}

.gv-live {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: #3fe6c4;
}

.gv-pulse {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #3fe6c4;
    animation: gv-pulse 2s infinite;
}

@keyframes gv-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(63, 230, 196, 0.5); }
    70%  { box-shadow: 0 0 0 9px rgba(63, 230, 196, 0); }
    100% { box-shadow: 0 0 0 0 rgba(63, 230, 196, 0); }
}

.gv-sep {
    color: #4a5e73;
}

.gv-h1 {
    font-weight: 700;
    font-size: clamp(34px, 6.2vw, 72px);
    line-height: 1.02;
    letter-spacing: -0.03em;
    margin: 0 0 22px;
    color: #f2f7fb;
}

.gv-em {
    background: linear-gradient(100deg, #3fe6c4, #5cb0ff);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.gv-lede {
    font-size: clamp(15px, 1.9vw, 19px);
    line-height: 1.6;
    color: #a8bdd2;
    max-width: 56ch;
    margin: 0 0 32px;
}

/* ---------- buttons ---------- */
.gv-cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
}

.gv-cta-c {
    justify-content: center;
}

.gv-btn {
    display: inline-block;
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 13px;
    padding: 14px 26px;
    border-radius: 4px;
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, color 0.2s ease;
    /* Comfortable tap target on phones. */
    min-height: 46px;
    line-height: 1.4;
}

.gv-btn-p {
    background: linear-gradient(100deg, #3fe6c4, #4aa8ff);
    color: #06131f;
    font-weight: 600;
}

.gv-btn-p:hover {
    transform: translateY(-2px);
    box-shadow: 0 14px 34px -12px rgba(63, 230, 196, 0.9);
    color: #06131f;
}

.gv-btn-s {
    border-color: rgba(255, 255, 255, 0.28);
    color: #e6eef6;
}

.gv-btn-s:hover {
    border-color: #3fe6c4;
    color: #3fe6c4;
}

/* Secondary button on the LIGHT closing section needs dark-on-light instead. */
.gv-close .gv-btn-s {
    border-color: rgba(13, 27, 42, 0.30);
    color: var(--gv-ink);
}

.gv-close .gv-btn-s:hover {
    border-color: var(--gv-signal);
    color: var(--gv-signal);
}

/* ---------- hero stats ---------- */
.gv-hero-stats {
    display: flex;
    flex-wrap: wrap;
    gap: clamp(20px, 4vw, 40px);
    margin-top: 40px;
}

.gv-hv {
    font-size: clamp(22px, 3vw, 28px);
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: #3fe6c4;
}

.gv-hv small {
    font-size: 0.55em;
    color: #a8bdd2;
    margin-left: 2px;
}

.gv-hk {
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 10.5px;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: #7d93a9;
    margin-top: 4px;
}

/* ---------- four domains ---------- */
.gv-domains {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-top: 44px;
}

.gv-dom {
    background: rgba(255, 255, 255, 0.72);
    border: 1px solid var(--gv-line);
    border-radius: 12px;
    padding: 24px 22px 26px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}

.gv-dom:hover {
    transform: translateY(-4px);
    border-color: rgba(15, 156, 134, 0.55);
    box-shadow: 0 18px 38px -18px rgba(13, 27, 42, 0.45);
}

.gv-dom-idx {
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 11px;
    color: var(--gv-dim);
}

.gv-dom .gv-dom-icon {
    font-size: 34px !important;
    width: 34px;
    height: 34px;
    color: var(--gv-signal);
    margin: 14px 0 10px;
}

.gv-dom-title {
    font-weight: 700;
    font-size: 18px;
    margin: 0 0 7px;
    color: var(--gv-ink);
}

.gv-dom-desc {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--gv-mute);
    margin: 0;
}

/* ---------- platform capabilities ---------- */
.gv-caps {
    margin-top: 40px;
    background: rgba(255, 255, 255, 0.70);
    border: 1px solid var(--gv-line);
    border-radius: 14px;
    padding: 6px clamp(18px, 3vw, 32px);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

.gv-cap-row {
    display: grid;
    grid-template-columns: 46px 1fr;
    gap: 16px;
    padding: 22px 0;
    border-top: 1px solid var(--gv-line);
    transition: padding-inline-start 0.22s ease;
}

.gv-cap-row:first-child {
    border-top: none;
}

.gv-cap-row:hover {
    padding-inline-start: 8px;
}

.gv-cap-n {
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 13px;
    color: var(--gv-signal);
    padding-top: 2px;
}

.gv-cap-title {
    font-weight: 700;
    font-size: 17px;
    margin: 0 0 5px;
    color: var(--gv-ink);
}

.gv-cap-desc {
    font-size: 14px;
    line-height: 1.55;
    color: var(--gv-mute);
    margin: 0;
}

/* ---------- four domains ---------- */
/* Four across on desktop, collapsing to two then one; the tool grid's auto-fit
   would leave a lone card stranded on a second row at some widths, so the
   domain row uses explicit breakpoints to keep the four balanced. */
.gv-domain-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-top: clamp(24px, 3vw, 34px);
}

@media (max-width: 1080px) {
    .gv-domain-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 560px) {
    .gv-domain-grid {
        grid-template-columns: 1fr;
    }
}

/* Same elevated card as the tool catalogue, but static — domains are not
   clickable, so there is no hover lift or pointer cursor. */
.gv-domain-card {
    background: var(--gv-card-bg);
    border: 1px solid var(--gv-card-border);
    border-radius: 12px;
    padding: 22px;
    box-shadow: var(--gv-card-shadow);
}

.gv-domain-card .gv-tool-icon {
    font-size: 28px !important;
    width: 28px;
    height: 28px;
    color: var(--gv-violet);
    flex: 0 0 28px;
}

/* ---------- tool catalogue ---------- */
.gv-cat {
    margin-top: 42px;
}

.gv-cat-title {
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: clamp(20px, 2.4vw, 26px);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gv-violet);
    margin-bottom: 18px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--gv-line);
}

/* auto-fit keeps cards a comfortable width and collapses to one column on
   phones with no extra breakpoint. */
.gv-tool-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 16px;
}

.gv-tool-card {
    background: var(--gv-card-bg);
    border: 1px solid var(--gv-card-border);
    border-radius: 12px;
    padding: 22px;
    cursor: pointer;
    /* Clips the full-bleed screenshot to the card's rounded corners. */
    overflow: hidden;
    /* Grid rows stretch every card to the tallest in the row. Laying the card out
       as a column and pushing the screenshot to the top keeps the name + blurb
       aligned across a row even when some tools have no screenshot at all. */
    display: flex;
    flex-direction: column;
    /* Elevated above the page surface with a 3D drop shadow. */
    box-shadow: var(--gv-card-shadow);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

/* Pin the text block to the bottom of the card so a screenshot-less card's text
   lines up with its neighbours' rather than floating at the top of a tall cell. */
.gv-tool-card .gv-tool-head {
    margin-top: auto;
}

.gv-tool-card:hover,
.gv-tool-card:focus-visible {
    transform: translateY(-4px);
    border-color: var(--gv-violet);
    box-shadow: var(--gv-card-shadow-hover);
    outline: none;
}

/* Screenshot of the tool, shown above the card's icon + name + blurb. The image
   is language-specific (the code-behind picks the English/Hebrew capture from the
   UI culture), so it must never be mirrored under RTL — `direction: ltr` keeps the
   frame laid out left-to-right inside the Hebrew page.
   The fixed aspect ratio keeps every card in a row the same height regardless of
   the source capture's dimensions; `object-fit: cover` crops rather than distorts,
   and the top-anchored position keeps each tool's control panel (always at the top
   of the capture) in frame. */
.gv-tool-shot {
    direction: ltr;
    aspect-ratio: 16 / 9;
    /* Never let the flex column squeeze the frame out of its aspect ratio. */
    flex: 0 0 auto;
    margin: -22px -22px 18px;
    border-bottom: 1px solid var(--gv-card-border);
    border-radius: 12px 12px 0 0;
    overflow: hidden;
    background: var(--gv-card-border);
}

.gv-tool-shot img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    transition: transform 0.25s ease;
}

/* Captures whose content sits on the LEFT (a documentation sidebar, say) leave the
   right half of a 16:9 crop empty when centred — anchor those top-left instead. */
.gv-tool-shot-left img {
    object-position: top left;
}

/* Subtle zoom that pairs with the card's own hover lift. */
.gv-tool-card:hover .gv-tool-shot img,
.gv-tool-card:focus-visible .gv-tool-shot img {
    transform: scale(1.04);
}

.gv-tool-head {
    display: flex;
    align-items: center;
    gap: 10px;
}

.gv-tool-card .gv-tool-icon {
    font-size: 28px !important;
    width: 28px;
    height: 28px;
    color: var(--gv-violet);
    flex: 0 0 28px;
}

.gv-tool-name {
    font-weight: 600;
    font-size: 19px;
    color: var(--gv-ink);
}

.gv-tool-usage {
    font-size: 16px;
    line-height: 1.55;
    color: var(--gv-mute);
    margin: 12px 0 0;
}

/* ---------- AI core band ---------- */
.gv-band {
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 16px;
    overflow: hidden;
    background: linear-gradient(150deg, rgba(9, 20, 33, 0.92), rgba(12, 28, 45, 0.86));
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 30px 80px -34px rgba(6, 18, 30, 0.6);
}

.gv-band-l {
    padding: clamp(28px, 4vw, 52px);
}

.gv-band .gv-h2 {
    color: #f2f7fb;
}

.gv-band .gv-sec-lede {
    color: #a8bdd2;
}

.gv-band-r {
    border-inline-start: 1px solid rgba(255, 255, 255, 0.10);
    background: rgba(4, 12, 20, 0.55);
    padding: clamp(20px, 3vw, 32px);
    overflow-x: auto;
}

.gv-term {
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 12.5px;
    line-height: 1.9;
    color: #8fa6bd;
    margin: 0;
    white-space: pre;
    /* The transcript is LTR terminal output even in a Hebrew UI. */
    direction: ltr;
    text-align: left;
}

.gv-term .gv-c { color: #62798f; }
.gv-term .gv-g { color: #3fe6c4; }
.gv-term .gv-a { color: #f5b263; }
.gv-term .gv-b { color: #5cb0ff; }

.gv-cur {
    display: inline-block;
    width: 8px;
    height: 14px;
    background: #3fe6c4;
    vertical-align: -2px;
    animation: gv-blink 1.1s steps(1) infinite;
}

@keyframes gv-blink {
    50% { opacity: 0; }
}

/* ---------- closing CTA ---------- */
.gv-close {
    text-align: center;
    padding-block: clamp(56px, 9vw, 104px);
}

/* Halves the vertical rhythm around the dedication panel: the gap above comes
   from the intro section's bottom padding and the gap below from this section's
   own, so both are pulled up by 50% via a negative top margin plus a halved
   bottom padding. Scoped to this one section — `.gv-section` itself is shared
   by every block on the page. */
.gv-section-dedication {
    margin-top: calc(clamp(48px, 7vw, 88px) / -2);
    padding-bottom: calc(clamp(48px, 7vw, 88px) / 2);
}

/* ---------- dedication (in memory of Alex Rosenblit) ----------
   A quiet panel between the intro and the tool catalogue. The candle is drawn
   in CSS — an emoji would render as a different glyph on every platform and
   could not follow the theme. `flex-direction: row` plus logical padding keeps
   it correct in RTL (Hebrew) without a separate rule. */
.gv-dedication {
    display: flex;
    align-items: center;
    gap: 18px;
    max-width: 76ch;
    padding: 18px 22px;
    border: 1px solid var(--gv-card-border);
    border-radius: 12px;
    background: var(--gv-card-bg);
    box-shadow: var(--gv-card-shadow);
}

/* Takes the leftover width so the photo is pushed to the far edge, leaving the
   candle and the portrait bracketing the text. */
.gv-dedication-text {
    flex: 1 1 auto;
    margin: 0;
    color: var(--gv-mute);
    font-size: clamp(15px, 1.6vw, 17px);
    line-height: 1.6;
    font-style: italic;
}

/* Alex's memorial portrait — a 3:4 photo kept small enough to read as an inline
   keepsake rather than a hero image. */
/* The anchor is the flex child, so it carries the sizing; `line-height: 0` stops
   the inline image from adding descender space below it. */
.gv-dedication-photo-link {
    flex: 0 0 auto;
    display: block;
    line-height: 0;
    border-radius: 4px;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.gv-dedication-photo-link:hover,
.gv-dedication-photo-link:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}

/* Sized to match the candle's 46px height so the two bracket the text as a
   matched pair; the 3:4 portrait sets its own width from that. */
.gv-dedication-photo {
    display: block;
    width: auto;
    height: 46px;
    border-radius: 4px;
    border: 1px solid var(--gv-card-border);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}

/* `nowrap` keeps "Alex Rosenblit" on one line — the panel is narrow enough that
   the two words would otherwise split across a line break mid-name. */
.gv-dedication-link {
    color: var(--gv-signal-2);
    font-style: normal;
    font-weight: 700;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    white-space: nowrap;
}

.gv-dedication-link:hover,
.gv-dedication-link:focus-visible {
    color: var(--gv-cyan);
}

/* ---------- CSS candle ----------
   28px tall: a rounded wax body with a teardrop flame above it. The flame is a
   rotated square with three of four corners rounded, which gives the classic
   pointed-top / round-bottom silhouette. */
.gv-candle {
    position: relative;
    flex: 0 0 20px;
    width: 20px;
    height: 46px;
}

.gv-candle-body {
    position: absolute;
    bottom: 0;
    left: 3px;
    width: 14px;
    height: 26px;
    border-radius: 4px 4px 3px 3px;
    background: linear-gradient(180deg, #fdf3dc 0%, #f0dcae 55%, #d8bf85 100%);
    box-shadow: inset -3px 0 4px -2px rgba(13, 27, 42, 0.35);
}

/* The wick, drawn as the body's top edge. */
.gv-candle-body::before {
    content: "";
    position: absolute;
    top: -4px;
    left: 6px;
    width: 2px;
    height: 5px;
    border-radius: 1px;
    background: #4a3b2a;
}

.gv-candle-flame {
    position: absolute;
    top: 2px;
    left: 6px;
    width: 8px;
    height: 14px;
    border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
    background: radial-gradient(ellipse at 50% 75%, #fff6d0 0%, #ffd257 42%, #ff9a1f 74%, rgba(255, 116, 0, 0.65) 100%);
    box-shadow: 0 0 10px 3px rgba(255, 170, 40, 0.55), 0 0 22px 8px rgba(255, 140, 0, 0.22);
    transform-origin: 50% 100%;
    animation: gv-candle-flicker 2.4s ease-in-out infinite;
}

@keyframes gv-candle-flicker {
    0%, 100% { transform: scale(1, 1) rotate(-1deg); opacity: 0.95; }
    30%      { transform: scale(0.94, 1.06) rotate(1.5deg); opacity: 1; }
    55%      { transform: scale(1.05, 0.95) rotate(-1.5deg); opacity: 0.9; }
    78%      { transform: scale(0.97, 1.04) rotate(0.5deg); opacity: 1; }
}

/* ---------- footer ---------- */
.gv-foot {
    border-top: 1px solid var(--gv-line);
    padding: 34px 0 44px;
}

.gv-foot-brand {
    font-weight: 700;
    font-size: 17px;
    color: var(--gv-ink);
    margin-bottom: 10px;
}

.gv-foot-bot {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 10px;
    font-family: 'IBM Plex Mono', ui-monospace, 'Consolas', monospace;
    font-size: 11px;
    color: var(--gv-dim);
}

/* ============================================================
   RESPONSIVE - tablet then phone
   ============================================================ */

@media (max-width: 960px) {
    .gv-domains {
        grid-template-columns: 1fr 1fr;
    }

    .gv-band {
        grid-template-columns: 1fr;
    }

    .gv-band-r {
        border-inline-start: none;
        border-top: 1px solid rgba(255, 255, 255, 0.10);
    }
}

@media (max-width: 600px) {
    .gv-domains {
        grid-template-columns: 1fr;
    }

    .gv-hero {
        min-height: 0;
    }

    /* On a phone the candle and photo would squeeze the sentence into a narrow
       ragged column, so both shrink and the padding/gap tighten. The order stays
       candle → text → photo, so the two still bracket the text. */
    .gv-dedication {
        gap: 10px;
        padding: 14px 14px;
    }

    /* Tracks the phone-sized candle (34px) so the pair stays matched. */
    .gv-dedication-photo {
        width: auto;
        height: 34px;
    }

    .gv-candle {
        flex-basis: 14px;
        width: 14px;
        height: 34px;
    }

    .gv-candle-body {
        left: 2px;
        width: 10px;
        height: 19px;
    }

    .gv-candle-body::before {
        left: 4px;
    }

    .gv-candle-flame {
        top: 1px;
        left: 4px;
        width: 6px;
        height: 11px;
    }

    /* Full-width CTAs are far easier to hit on a phone. */
    .gv-cta-row .gv-btn {
        flex: 1 1 100%;
        text-align: center;
    }

    .gv-hero-stats {
        gap: 18px 28px;
    }

    .gv-cap-row {
        grid-template-columns: 34px 1fr;
        gap: 12px;
    }

    .gv-foot-bot {
        flex-direction: column;
    }
}

/* Respect reduced-motion for the pulse, caret and hover lifts. */
@media (prefers-reduced-motion: reduce) {
    .gv-pulse,
    .gv-cur,
    .gv-candle-flame {
        animation: none;
    }

    .gv-dom,
    .gv-tool-card,
    .gv-tool-shot img,
    .gv-btn,
    .gv-cap-row,
    .gv-dedication-photo-link {
        transition: none;
    }

    .gv-dom:hover,
    .gv-tool-card:hover,
    .gv-tool-card:hover .gv-tool-shot img,
    .gv-btn-p:hover,
    .gv-dedication-photo-link:hover {
        transform: none;
    }
}



/* ============================================================
   APP-BAR HEIGHT SYNC
   ============================================================
   MainLayout forces the MudAppBar to 50px, but MudBlazor keeps offsetting
   everything below it (clipped drawers, main content) by the untouched
   --mud-appbar-height (64px) — which left a visible gap between the app bar
   and the top of the nav drawer. Re-point the variable at the real height so
   the drawer, the ChatBot drawer and the main content all line up.
   ============================================================ */

.mud-layout {
    --mud-appbar-height: 50px;
}

.mud-appbar.mud-appbar-fixed-top {
    height: 50px;
    min-height: 50px;
}

/* ============================================================
   APP-BAR BRAND — globe mark + product name
   ============================================================
   The mark sits left of the title and links home. Sized off the 50px app bar
   (see MudAppBar Style in MainLayout): 34px leaves a comfortable margin above
   and below without the bar growing. The source PNG is square with a
   transparent background, so no per-theme variant is needed — it reads against
   both the light and dark app-bar palettes.
   ============================================================ */

.gv-appbar-logo {
    height: 34px;
    width: auto;
    display: block;
    /* Never let a slow/failed image load reflow the whole bar. */
    flex: 0 0 auto;
}

/* The brand is a link; keep it inheriting the bar's text colour rather than
   MudBlazor's link colour, and suppress the hover underline on the title. */
.gv-appbar-brand,
.gv-appbar-brand:hover {
    text-decoration: none;
    color: inherit;
}

/* RTL (Hebrew): the bar mirrors, so the brand's start-margin must flip. The
   ml-3 utility on the element is physical-left, which lands on the wrong side
   under dir="rtl". */
[dir="rtl"] .gv-appbar-brand.ml-3 {
    margin-left: 0 !important;
    margin-right: 12px !important;
}

/* ============================================================
   APP-BAR BUTTONS — 3D bordered chips
   ============================================================
   The top row mixes clickable buttons (Plans / Team / Logout) with plain
   text labels (User: / License:). With the default flat Text variant the two
   are visually indistinguishable. Give the ACTIONS a raised, bordered look —
   a border plus a subtle top-light / bottom-shadow bevel — so it is obvious
   at a glance which items are buttons. Theme-aware via the .geoview-theme-*
   class MainLayout stamps on .mud-layout.
   ============================================================ */

.gv-appbar-btn.mud-button-root {
    border: 1px solid var(--gv-appbar-btn-border, rgba(255, 255, 255, 0.25));
    border-radius: 6px;
    padding-left: 10px;
    padding-right: 10px;
    margin-left: 4px;
    background: var(--gv-appbar-btn-bg, rgba(255, 255, 255, 0.06));
    box-shadow:
        inset 0 1px 0 var(--gv-appbar-btn-light, rgba(255, 255, 255, 0.25)),
        inset 0 -1px 0 var(--gv-appbar-btn-dark, rgba(0, 0, 0, 0.35)),
        0 1px 2px rgba(0, 0, 0, 0.35);
    transition: background-color .12s ease, box-shadow .12s ease, transform .05s ease;
}

.gv-appbar-btn.mud-button-root:hover {
    background: var(--gv-appbar-btn-bg-hover, rgba(255, 255, 255, 0.14));
    box-shadow:
        inset 0 1px 0 var(--gv-appbar-btn-light, rgba(255, 255, 255, 0.35)),
        inset 0 -1px 0 var(--gv-appbar-btn-dark, rgba(0, 0, 0, 0.35)),
        0 2px 4px rgba(0, 0, 0, 0.4);
}

/* Pressed: sink the bevel so the button reads as "pushed in". */
.gv-appbar-btn.mud-button-root:active {
    transform: translateY(1px);
    box-shadow:
        inset 0 1px 2px rgba(0, 0, 0, 0.45),
        0 0 0 rgba(0, 0, 0, 0);
}

/* Light theme: the app bar is near-white, so a dark border + darker bevel reads
   the raised edge correctly against it. */
.geoview-theme-light .gv-appbar-btn.mud-button-root {
    --gv-appbar-btn-border: rgba(0, 0, 0, 0.22);
    --gv-appbar-btn-bg: rgba(0, 0, 0, 0.03);
    --gv-appbar-btn-bg-hover: rgba(0, 0, 0, 0.08);
    --gv-appbar-btn-light: rgba(255, 255, 255, 0.9);
    --gv-appbar-btn-dark: rgba(0, 0, 0, 0.18);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.9),
        inset 0 -1px 0 rgba(0, 0, 0, 0.18),
        0 1px 2px rgba(0, 0, 0, 0.18);
}

/* The logout button is wrapped in an inline <form>; keep the wrapper tight so
   the button's margin does the spacing, not the form. */
.gv-appbar-logout-form {
    display: inline;
}

/* The clipped drawers are positioned from the top of the viewport, so they need
   the same 50px offset for both their start edge and their height. */
.mud-drawer.mud-drawer-clipped-always,
.mud-drawer.mud-drawer-clipped-docked {
    top: 50px;
    height: calc(100% - 50px);
}


/* ============================================================
   DISPLAY MODE — Desktop / Laptop / Tablet / Phone
   ============================================================
   The app-bar display-mode menu caps how many tool panels may sit
   side-by-side: DESKTOP unbounded, LAPTOP 3, TABLET 2, PHONE 1.

   GENERIC, panel-name-agnostic. Every tool marks each of its columns
   with a zero-based data-gv-panel index (DOM/left-to-right order) and
   its container with data-gv-panels="<count>". The panel COUNT and
   meaning vary per tool: a map tool has 4 (tool|map|results|chat),
   TeachingTool/CoordinateConverter have 3 (no map), MapExplorer inserts
   a PROPS column, SandboxTool a THEORY column, ChangeDetection has 3.

   The visible set is a WINDOW over the tool's panels. MainLayout stamps
   the chosen mode and the window's first index onto <body> as
   data-display-mode / data-first-panel, and the rules below hide any
   panel whose data-gv-panel index falls OUTSIDE the window
   [first, first + capacity). Because the selectors key off the generic
   data-gv-panel attribute rather than a hand-maintained class list, a
   NEW tool needs no CSS change — it just stamps the attributes.

   These rules live HERE, globally, on purpose: Blazor scoped CSS would
   reach only one tool. The panel container/columns are plain flex from
   each tool's own scoped stylesheet; only the windowing lives here.
   ============================================================ */

/* ---- Panel hiding -------------------------------------------------
   display:none rather than visibility:hidden so a hidden panel is taken
   out of the flex sizing entirely and the survivors get the full width.
   Each block reads: "in this mode, with the window starting at F, hide
   every panel whose index is not one of [F .. F+capacity-1]". The
   :not() chain keeps the survivors; indices are listed up to 7, which
   comfortably exceeds any real tool's panel count.                     */

/* PHONE — window width 1: show only the panel at data-first-panel. */
body[data-display-mode="PHONE"][data-first-panel="0"] [data-gv-panel]:not([data-gv-panel="0"]),
body[data-display-mode="PHONE"][data-first-panel="1"] [data-gv-panel]:not([data-gv-panel="1"]),
body[data-display-mode="PHONE"][data-first-panel="2"] [data-gv-panel]:not([data-gv-panel="2"]),
body[data-display-mode="PHONE"][data-first-panel="3"] [data-gv-panel]:not([data-gv-panel="3"]),
body[data-display-mode="PHONE"][data-first-panel="4"] [data-gv-panel]:not([data-gv-panel="4"]),
body[data-display-mode="PHONE"][data-first-panel="5"] [data-gv-panel]:not([data-gv-panel="5"]),

/* TABLET — window width 2: show data-first-panel and its right neighbour. */
body[data-display-mode="TABLET"][data-first-panel="0"] [data-gv-panel]:not([data-gv-panel="0"]):not([data-gv-panel="1"]),
body[data-display-mode="TABLET"][data-first-panel="1"] [data-gv-panel]:not([data-gv-panel="1"]):not([data-gv-panel="2"]),
body[data-display-mode="TABLET"][data-first-panel="2"] [data-gv-panel]:not([data-gv-panel="2"]):not([data-gv-panel="3"]),
body[data-display-mode="TABLET"][data-first-panel="3"] [data-gv-panel]:not([data-gv-panel="3"]):not([data-gv-panel="4"]),
body[data-display-mode="TABLET"][data-first-panel="4"] [data-gv-panel]:not([data-gv-panel="4"]):not([data-gv-panel="5"]),
body[data-display-mode="TABLET"][data-first-panel="5"] [data-gv-panel]:not([data-gv-panel="5"]):not([data-gv-panel="6"]),

/* LAPTOP — window width 3: show data-first-panel and its two right neighbours. */
body[data-display-mode="LAPTOP"][data-first-panel="0"] [data-gv-panel]:not([data-gv-panel="0"]):not([data-gv-panel="1"]):not([data-gv-panel="2"]),
body[data-display-mode="LAPTOP"][data-first-panel="1"] [data-gv-panel]:not([data-gv-panel="1"]):not([data-gv-panel="2"]):not([data-gv-panel="3"]),
body[data-display-mode="LAPTOP"][data-first-panel="2"] [data-gv-panel]:not([data-gv-panel="2"]):not([data-gv-panel="3"]):not([data-gv-panel="4"]),
body[data-display-mode="LAPTOP"][data-first-panel="3"] [data-gv-panel]:not([data-gv-panel="3"]):not([data-gv-panel="4"]):not([data-gv-panel="5"]),
body[data-display-mode="LAPTOP"][data-first-panel="4"] [data-gv-panel]:not([data-gv-panel="4"]):not([data-gv-panel="5"]):not([data-gv-panel="6"]) {
    display: none !important;
}

/* ---- Splitters ----------------------------------------------------
   A splitter sits between two panels. When one of the pair is hidden the
   handle would be left dangling against the container edge, so hide every
   splitter in the restricted modes. Dragging is a desktop affordance
   anyway — the panels no longer share the screen the same way. The
   fixed (non-drag) dividers (e.g. Sandbox's theory/editor divider) are
   covered too since they carry .panel-splitter or a *-divider class.    */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) :is(.panel-splitter, .cd-splitter, .sbxtool-fixed-divider) {
    display: none !important;
}

/* ---- Panel sizing in restricted modes -----------------------------
   The per-tool stylesheets pin desktop min-widths and, for chat columns, a
   fixed width. Those columns cannot fit a phone or tablet viewport, so any
   panel visible in a restricted mode is relaxed to share the width evenly.
   Keyed on the generic data-gv-panel marker so it applies to every tool.
   !important is needed because a previous splitter drag leaves INLINE
   width/min-width/max-width on the panel, which would otherwise win. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) [data-gv-panel] {
    flex: 1 1 0 !important;
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    /* The desktop width transition would animate on every tab switch. */
    transition: none !important;
}

/* A chat panel that the tool collapsed (app-bar chat button) carries the
   .collapsed class, which zeroes all three widths with !important. When the
   user has explicitly tabbed TO the chat panel it must win that fight. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) [data-gv-panel].collapsed {
    opacity: 1 !important;
    border-inline-start-width: 1px;
    pointer-events: auto !important;
}

/* ---- Panel INNER content in restricted modes ----------------------
   The rule above relaxes the PANELS themselves, but a panel's contents keep
   their own desktop minimums and can still force the panel wider than the
   viewport — the panel shrinks, its child does not, and the page scrolls
   sideways. The shared geometry editors are the live example
   (Tools/Common/*EditorComp: .point-editor / .polygon-editor / .shape-editor
   pin min-width 320-360px), and any future panel content that pins a
   several-hundred-px minimum would do the same on a ~380px phone.

   So: inside a visible panel, in a restricted mode, nothing may impose a
   horizontal minimum. min-width:auto on a flex/grid CHILD is the other half
   of this — the default `min-width:auto` refuses to shrink a flex item below
   its content, which is what turns a wide table or a long unbroken string
   into page-level overflow.

   Deliberately broad (`*`) and generic: like the windowing rules above, a NEW
   tool must need no CSS change. It only relaxes MINIMUMS — it does not set
   width/max-width/flex, so desktop-tuned proportions inside a panel are
   unaffected, inner scroll containers can still be wider than their box, and
   this whole block is inert in DESKTOP mode.

   MudBlazor popovers, menus and dialogs are unaffected: their providers render
   at the layout root, outside any [data-gv-panel] subtree. The 48px collapsed
   icon rails are set ON the panel elements, not on descendants, so `*` does not
   reach them either. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) [data-gv-panel] * {
    min-width: 0 !important;
}

/* A wide table or a long unbroken token (a WKT string, a file path, a URL in a
   chat bubble) cannot shrink below its content, so it pushes the panel out even
   with the minimums cleared. Let such content scroll INSIDE its own box rather
   than widening the page — the same containment rule the rest of the app uses
   for wide content. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) [data-gv-panel] :is(table, pre) {
    display: block;
    overflow-x: auto;
}

/* A left panel collapsed to its 48px icon rail on desktop would waste most
   of the column at these widths, so let it fill instead. Only the collapse
   affects width here — the .collapsed rule above already restores it. */

/* ---- Panel VERTICAL SCROLLING in restricted modes -----------------
   On a phone or tablet a panel is far shorter than its content, and most tool
   panels pin `overflow: hidden` in their own stylesheet (correct on desktop,
   where each panel is tall and its inner regions scroll themselves). The result
   on a small screen is content that is simply UNREACHABLE: the LOS tool's
   panels report scrollHeight == clientHeight with overflow-y hidden, and the
   /admin tree ran 1158px of content inside an 844px box with overflow-y
   visible. Neither scrolls, by touch or by wheel.

   So in the restricted modes only, a visible panel scrolls itself. Keyed on the
   generic data-gv-panel marker, exactly like the windowing and sizing rules
   above, so a NEW tool needs no CSS of its own.

   -webkit-overflow-scrolling gives iOS Safari momentum scrolling; without it a
   panel scrolls but feels stuck, which reads as "not scrollable".

   touch-action: pan-y tells the browser a one-finger vertical drag is a scroll
   and may be handled off the main thread. It is deliberately NOT applied to the
   map/globe panels below, which need the raw touch stream for pan and pinch.

   overscroll-behavior: contain stops a scroll that reaches the panel's end from
   chaining to the page and "pulling" the whole layout — the effect that makes a
   mobile panel feel like it is fighting the user. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"]) [data-gv-panel] {
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    touch-action: pan-y;
}

/* A canvas-backed panel (Cesium globe, MapLibre map) consumes touch itself for
   pan/zoom/pinch. Forcing pan-y there would steal the horizontal and pinch
   gestures and break the map, so those panels keep touch-action:auto and do not
   scroll — they size to their box.

   The canvas is nested DEEP (Cesium renders into
   .cesium-viewer > .cesium-widget > canvas), so these are DESCENDANT selectors,
   not child selectors: a `> canvas` form matched nothing and left the globe
   panels on pan-y, which is exactly the gesture breakage this rule prevents. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"])
[data-gv-panel]:has(canvas, .cesium-viewer, .cesium-widget, .maplibregl-map, .maplibregl-canvas-container) {
    overflow-y: hidden !important;
    touch-action: auto;
}

/* The inner scroll regions a tool defines (a tree, a results list, a form
   column) must scroll on touch too. They already carry overflow auto/scroll
   from their own stylesheet; this only adds the touch affordances, so it cannot
   change which element scrolls or how the desktop layout behaves. */
body:is([data-display-mode="LAPTOP"], [data-display-mode="TABLET"], [data-display-mode="PHONE"])
[data-gv-panel] :is([style*="overflow"], .gv-tree, .gv-detail, .gv-acct-scroll, .pricing-tree, .mud-table-container, .mud-list) {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
}

/* The STATIC-SSR pages (/admin) never receive data-display-mode: that attribute
   is stamped from JS through a Blazor circuit, and those pages have none. The
   rules above therefore cannot reach them, yet /admin is exactly where the
   overflow was measured (1158px of tree inside an 844px box, unreachable).

   So gate the same behaviour on the VIEWPORT for panels that carry no display
   mode. Scoped with :not([data-display-mode]) on <body> so it never
   double-applies with the mode-driven rules, and never affects desktop. */
@media (max-width: 1280px) {
    body:not([data-display-mode]) [data-gv-panel] {
        overflow-y: auto !important;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-y: contain;
        touch-action: pan-y;
    }

    body:not([data-display-mode]) [data-gv-panel]:has(canvas, .cesium-viewer, .cesium-widget, .maplibregl-map, .maplibregl-canvas-container) {
        overflow-y: hidden !important;
        touch-action: auto;
    }
}

/* ---- Panel tab strip ----------------------------------------------
   Rendered by MainLayout directly above the tool content, and only in the
   restricted modes. It selects which panel anchors the visible window. */
.gv-panel-tabs {
    display: flex;
    flex: 0 0 auto;
    gap: 2px;
    padding: 2px 4px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background-color: var(--mud-palette-surface);
    overflow-x: auto;
    /* A horizontal scroll must never turn into a vertical one. */
    overflow-y: hidden;
}

.gv-panel-tabs > button {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    /* 44px is the minimum comfortable touch target. */
    min-height: 40px;
    padding: 4px 10px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--mud-palette-text-secondary);
    font: inherit;
    font-size: 0.8rem;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.gv-panel-tabs > button:hover {
    background: var(--mud-palette-action-default-hover);
}

/* The anchor tab. box-shadow rather than border-bottom so the button does
   not change height when it becomes active. */
.gv-panel-tabs > button.active {
    color: var(--mud-palette-primary);
    box-shadow: inset 0 -2px 0 0 var(--mud-palette-primary);
}

/* A tab whose panel is visible as part of the window but is not the anchor
   — shown dimmer than the anchor but brighter than an off-screen one, so
   the current window is legible at a glance. */
.gv-panel-tabs > button.in-window:not(.active) {
    color: var(--mud-palette-text-primary);
    background: var(--mud-palette-action-default-hover);
}

/* On a phone the labels are dropped: four of them will not fit, and the
   icons alone identify the panels. */
body[data-display-mode="PHONE"] .gv-panel-tabs > button > span {
    display: none;
}

/* The strip is a layout row inside MudMainContent. The generic "fill the space"
   rule above (.mud-main-content > div:not(...)) also matches the strip (it is a
   <div>) and, with its four :not() clauses, outweighs a plain
   ".mud-main-content > .gv-panel-tabs" on specificity — so the strip was flex-
   growing to share the column height. On tool pages a tall map hides this, but on
   short pages (e.g. /admin) the strip ballooned to ~120px. !important keeps the
   strip at its natural height on every page. align-items:flex-start likewise stops
   the buttons stretching to the strip's height if it ever grows. */
.mud-main-content > .gv-panel-tabs {
    flex: 0 0 auto !important;
    align-items: flex-start;
}

/* ---- Display-mode menu items -------------------------------------- */

.display-mode-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}

/* Fixed-width check column keeps every label on the same left edge. */
.display-mode-check {
    width: 20px;
    min-width: 20px;
}

.display-mode-icon {
    opacity: 0.75;
}

/* The "max panels" hint, pushed to the trailing edge. */
.display-mode-hint {
    margin-inline-start: auto;
    padding-inline-start: 12px;
    opacity: 0.6;
    font-size: 0.75rem;
}

/* ============================================================
   AUTH PAGES (/login, /register, /account/forgot, /account/reset,
   /verified, /verify-required) — the scrolling box
   ------------------------------------------------------------
   These pages use EmptyLayout, so they sit directly inside
   MudMainContent, which is pinned to the viewport height and
   carries `overflow: hidden !important` (see .mud-main-content
   above), on top of `html, body { height:100%; overflow:hidden }`
   at the top of this file. Nothing between them declared a
   scrolling box, so anything below the fold was simply
   unreachable — on an iPhone the "create account" link at the
   bottom of /login could not be scrolled to at all.

   This class IS that scrolling box. Two parts, both required:

   1. overflow-y:auto + min-height:0 — min-height:0 is what lets a
      flex child shrink below its content and actually overflow;
      without it the box grows to fit and never scrolls.

   2. align-items:flex-start, NOT center. Centering is the second
      half of the bug: once the card is taller than the viewport,
      centre alignment overflows it EQUALLY in both directions and
      a flex container cannot scroll back past its start edge, so
      the top of the card (language toggle, username field) becomes
      permanently unreachable. Starting at the top and using
      `margin:auto` on the child keeps the card optically centred
      while it still fits, and degrades to top-aligned + fully
      scrollable when it does not.

   height:100% (not 100vh) so the box follows MudMainContent's real
   height instead of the raw viewport — on mobile Safari the URL
   bar makes 100vh taller than the visible area, which would re-hide
   the last ~60px behind the browser chrome.

   -webkit-overflow-scrolling gives iOS momentum scrolling; the
   overscroll-behavior stops a scroll at the end of the card from
   chaining into a rubber-band on the page behind it.
   ============================================================ */

.gv-auth-scroll {
    display: flex;
    justify-content: center;
    align-items: flex-start; /* never center — see note 2 above */
    height: 100%;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    /* Breathing room at both ends, and safe-area padding so the card
       clears the iPhone notch / home indicator in landscape. */
    padding: 24px 16px calc(24px + env(safe-area-inset-bottom, 0px));
    padding-left: calc(16px + env(safe-area-inset-left, 0px));
    padding-right: calc(16px + env(safe-area-inset-right, 0px));

    /* Keep the scrollbar permanently visible rather than letting the browser fade
       it in only while scrolling. On the login page the card can be taller than the
       viewport (globe + screenshot strip + call to action), and an auto-hiding bar
       gave no hint that there was anything below the fold — it read as content
       simply being cut off. */
    scrollbar-width: thin;
    scrollbar-color: var(--mud-palette-primary, #7e6fff) transparent;
}

/* WebKit/Blink equivalent of the scrollbar-color/width pair above. */
.gv-auth-scroll::-webkit-scrollbar { width: 10px; }
.gv-auth-scroll::-webkit-scrollbar-track { background: rgba(255,255,255,.05); }
.gv-auth-scroll::-webkit-scrollbar-thumb {
    background: var(--mud-palette-primary, #7e6fff);
    border-radius: 5px;
    border: 2px solid transparent;
    background-clip: content-box;
}

/* Optically centres the card while it fits, top-aligns it when it
   does not. `margin:auto` on a flex child absorbs free space on all
   sides, but unlike align-items:center it yields to the scroll
   container instead of overflowing past its start edge. */
.gv-auth-scroll > * {
    margin: auto;
    /* A flex child defaults to min-height:auto, which refuses to
       shrink and would push the card's own bottom out of reach. */
    min-height: 0;
    flex: 0 0 auto;
}

/* ============================================================
   ACCOUNT PAGE (/account) — 4-panel layout
   ------------------------------------------------------------
   Global (not component-scoped) on purpose: the .gv-acct-root
   element is the component's OWN root, so a "::deep" rule in a
   co-located .razor.css would compile to "[b-hash] .gv-acct-root"
   and never match — ::deep needs a scoped ANCESTOR. These live
   here alongside the other panel layouts instead.

   The [data-gv-panels] row is what the generic Display-Mode
   rules above window: Desktop 4 / Laptop 3 / Tablet 2 / Phone 1,
   chosen by the app-bar mode selector + panel tab strip. No
   media queries here deliberately — a width rule would fight
   the selector rather than follow it.
   ============================================================ */

.gv-acct-root { display: flex; gap: 12px; align-items: stretch; width: 100%; padding: 8px 4px; }
.gv-acct-panel { flex: 1 1 0; min-width: 0; display: flex; }
/* max-height caps the card so .gv-acct-scroll below actually has an overflow to
   scroll; without it the card grows to its content and the inner box never
   scrolls — which is what pushed panel 0 off the top of the viewport. */
.gv-acct-card { width: 100%; display: flex; flex-direction: column; min-width: 0;
                max-height: calc(100vh - 130px); }

/* Each panel scrolls independently so a long billing history never
   drives the page height (and never pushes a sibling panel off-screen). */
.gv-acct-scroll { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

/* read-only label/value rows */
.gv-acct-row { display: flex; gap: 8px; padding: 5px 0;
               border-bottom: 1px solid var(--mud-palette-divider, #8882); font-size: 0.84rem; }
.gv-acct-row-lbl { flex: 0 0 45%; opacity: 0.7; }
/* "anywhere" would split an e-mail mid-word (…gmail. / com) even when the whole
   value would fit on the next line; break-word only breaks when there is no other
   option, so the address stays readable in a narrow panel. */
/* direction/text-align: the stored values are English-only — see the LTR block below. */
.gv-acct-row-val { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; font-weight: 500;
                   direction: ltr; text-align: left; }

/* tier hero block */
.gv-acct-hero { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.gv-acct-hero-note { opacity: 0.75; }

/* ------------------------------------------------------------
   English-only data entry (LTR).

   Every stored account value — username, display name, e-mail,
   organization name, tax id — is English-only (see the note at
   the top of each editable panel, shared with /register). Under
   the Hebrew UI the page direction is RTL, which would otherwise
   right-align these values and, worse, reorder punctuation in an
   address (user@host.com rendering as com.host@user). Forcing
   direction + text-align on the fields themselves keeps them
   readable and matches the dir="ltr" inputs on /register.

   The read-only value column gets the same treatment so panel 0
   agrees with the editable panels beside it. Labels/helper text
   are deliberately NOT touched: those are UI chrome and stay in
   the user's own language and direction.

   !important is required, not cosmetic: the global RTL rule above
   ("[dir=rtl] .mud-input-control input { text-align: right !important }")
   would otherwise win and right-align these fields in the Hebrew UI.

   NOTE — do NOT set `direction: ltr` here. Setting `direction` on the
   input re-places its BOX inside the RTL control: the field detaches
   from its floating label (measured: e-mail input at x=749..902 while
   its label sat at 1030..1068) and the value renders out from under
   the label. `unicode-bidi: plaintext` leaves the box alone and only
   governs how the TEXT inside flows, which is what we want.

   BUT plaintext alone is not enough. It resolves each line's direction
   from that line's FIRST STRONG character, and it anchors the line to
   the edge implied by the INHERITED direction — which is rtl here. So
   "acctverify1" in a dir=rtl input flowed from the RIGHT edge despite
   text-align: left, leaving the value visibly offset from the box (the
   username / full-name fields; type=email happened to inherit ltr from
   MudBlazor's own "mud-ltr" wrapper, which is why only those two looked
   wrong). `direction: ltr` is therefore set on the input BELOW as well
   — verified not to move the box by one pixel (each field's left/width
   measured identical before and after). The box displacement described
   above came from the hidden-slot bug fixed further down, not from
   `direction`.
   ------------------------------------------------------------ */
[dir="rtl"] .gv-acct-root .mud-input-control input,
[dir="rtl"] .gv-acct-root .mud-input-control textarea,
.gv-acct-root .mud-input-control input,
.gv-acct-root .mud-input-control textarea {
    direction: ltr !important;
    text-align: left !important;
    /* The <input> IS the .mud-input-slot flex item (MudBlazor puts those classes on the input
       itself, there is no inner wrapper), and as flex: 0 1 auto it collapses to the intrinsic
       width of its size=20 attribute instead of filling the control. */
    flex: 1 1 auto;
    width: 100% !important;
}

/* MudBlazor renders a SECOND .mud-input-slot div next to the input and hides it with an inline
   style="display:none". The global ".mud-input-slot { display: flex !important }" rule earlier
   in this file overrides that inline style, resurrecting the hidden div as a real flex item —
   it then claims ~164px of the 317px row and squeezes the actual input down to ~152px. Most
   visible on a type=email field, which MudBlazor also marks "mud-ltr", parking the squeezed
   input at the left edge of an RTL control, away from its floating label.
   Re-hiding the empty slot gives the input the full row back. */
.gv-acct-root div.mud-input-slot[style*="display:none"] {
    display: none !important;
}

/* ------------------------------------------------------------
   Account fields — uniform floated labels.

   MudBlazor only floats an outlined field's label above the border
   once that field HOLDS A VALUE (it adds .mud-shrink). On this page
   that means a half-filled form shows two different label styles at
   once: the username / full-name / e-mail labels sit on the border,
   while the empty password and tax-id labels sit inside the box. The
   rules below pin every field to the floated position so they all
   match, regardless of content.

   The transform and the legend padding are copied from the values
   MudBlazor itself computes for a shrunk dense-outlined field
   (measured: matrix(0.75,0,0,0.75,14,-6), legend padding 0 5px), so
   this reproduces the real shrink state rather than approximating it.

   The legend is what cuts the notch in the outline for the floated
   label to sit in. MudBlazor collapses it with `width: 0` (NOT
   max-width) on an unshrunk field, so it must be re-opened with
   `width: auto` — overriding only max-width leaves the notch closed
   and the label then sits on top of an unbroken border.
   ------------------------------------------------------------ */
.gv-acct-root .mud-input-control .mud-input-label-outlined {
    transform: translate(14px, -6px) scale(0.75) !important;
    pointer-events: none;
}

.gv-acct-root .mud-input-control fieldset legend {
    width: auto !important;
    max-width: 1000px !important;
    padding: 0 5px !important;
}

/* Pinning the label up means EVERY field now needs headroom for it, not just the ones that
   happened to hold a value. Without this the floated label overlaps whatever sits above:
   measured, the "שינוי סיסמה" sub-heading ended at y=442 while the first password field's
   label started at y=437.

   The label rides 13px above its own box, and several fields carry a helper note UNDER them
   ("לא ניתן לשנות את שם המשתמש", "משמש לשחזור סיסמה…"), which is what the next field's label
   would otherwise run into. 28px keeps a clear band between one field's note and the next
   field's floated label instead of letting them touch. */
.gv-acct-root .mud-input-control {
    margin-top: 28px !important;
}

/* The helper note belongs to the field ABOVE it — pull it in tight so the generous gap above
   reads as separation between fields, not as a gap between a field and its own note. */
.gv-acct-root .mud-input-helper-text {
    margin-top: 2px;
}

.gv-acct-cta { margin-top: 16px; }
.gv-acct-muted { opacity: 0.5; }
.gv-acct-link { color: var(--mud-palette-primary, #7e6fff); text-decoration: none; font-size: 0.82rem; }
.gv-acct-link:hover { text-decoration: underline; }

/* billing table — scrolls inside its own box so the page never scrolls sideways */
.gv-acct-tablewrap { overflow-x: auto; }
.gv-acct-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.gv-acct-table th { text-align: start; font-weight: 600; opacity: 0.75; padding: 6px 8px;
                    border-bottom: 1px solid var(--mud-palette-divider, #8882); white-space: nowrap; }
.gv-acct-table td { padding: 6px 8px; border-bottom: 1px solid var(--mud-palette-divider, #8881);
                    white-space: nowrap; }

/* COMPACT text fields on the account page.
   The global "All outlined variant inputs" block far above forces min-height:56px
   !important on .mud-input-slot / .mud-input-control-input-container / the fieldset
   border, which MudBlazor's own Margin.Dense cannot beat. Those globals exist for the
   tool forms, so rather than weaken them we override them for THIS page only — the
   account page is a dense read/edit form, not a touch-target-heavy tool panel.
   Selector carries .gv-acct-panel for specificity; !important is required to win
   against the equally-!important global. */
.gv-acct-panel .mud-input-outlined .mud-input-root,
.gv-acct-panel .mud-input-outlined .mud-input-control-input-container,
.gv-acct-panel .mud-input-outlined .mud-input-outlined-border,
.gv-acct-panel .mud-input-outlined .mud-input-slot,
.gv-acct-panel .mud-input-outlined .mud-input,
.gv-acct-panel .mud-input-slot,
.gv-acct-panel .mud-input-control-input-container { min-height: 34px !important; }

.gv-acct-panel .mud-input-slot { padding-top: 5px !important; padding-bottom: 5px !important;
                                 font-size: 0.82rem; text-overflow: ellipsis; }

/* Seat the floating label ON the shorter border line. -12px lifts it clear of the
   fieldset and into the helper text of the field ABOVE; -7px keeps it straddling its
   own border, and the opaque background stops the border striking through the text. */
.gv-acct-panel .mud-input-label-outlined { top: -7px !important; font-size: 0.72rem;
                                           background: var(--mud-palette-surface, #1e1e2d);
                                           padding: 0 4px; }

/* A long e-mail must not be clipped mid-address in a 345px panel. */
.gv-acct-panel .mud-input-slot input { text-overflow: ellipsis; min-width: 0; }

/* Tighten the gap between a field, its helper text, and the next field. */
.gv-acct-panel .mud-input-control { margin-bottom: 6px; }
.gv-acct-panel .mud-input-helper-text { margin-top: 1px; font-size: 0.68rem; line-height: 1.25; }

/* =========================================================================
   CHART RUN BAR  (ToolRunBarComp)
   A duplicate of a tool's Run/Stop button, pinned below the chart it drives.
   The primary button lives in the LEFT editor panel, which the restricted
   Display Modes (TABLET / PHONE) hide whenever the chart is the visible
   panel — so on a phone the process could be watched or started, never both.
   This bar closes that gap: press Run and watch the Plotly chart update in
   place, without tabbing back to the editor.

   Global rather than a scoped .razor.css: the bar is a flex SIBLING of the
   chart inside each tool's panel div, so it has to size itself against a
   layout owned by the host tool's stylesheet. Keyed on a generic class, so a
   new tool adopting the component needs zero CSS.
   ========================================================================= */

.gv-chart-run-bar {
    /* flex:0 0 auto — the chart above keeps all the stretch; this bar is
       exactly as tall as its content and never squeezes the plot away. */
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-top: 1px solid var(--mud-palette-lines-default, #8883);
    background-color: var(--mud-palette-surface, transparent);
}

/* A comfortable touch target — this bar exists FOR touch devices, where the
   36px Material default is below the 44px recommended minimum. */
.gv-chart-run-bar .gv-chart-run-button {
    flex: 0 0 auto;
    min-height: 40px;
    min-width: 104px;
}

/* Status / step counter fills the remainder and truncates rather than
   wrapping, so the bar stays one line tall at any panel width. */
.gv-chart-run-status {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.78rem;
    line-height: 1.2;
    opacity: 0.85;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The live "step / total" readout, emphasised over the idle status text. */
.gv-chart-run-progress {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--mud-palette-info, inherit);
}

/* On a phone the bar is the primary control, so give the button the width and
   let the status sit under it rather than competing for the same line. */
body[data-display-mode="PHONE"] .gv-chart-run-bar {
    flex-wrap: wrap;
    padding: 8px;
}

body[data-display-mode="PHONE"] .gv-chart-run-bar .gv-chart-run-button {
    flex: 1 1 100%;
    min-height: 44px;
}

/* =========================================================================
   THEORY TAB  (ToolTheoryPanelComp)
   Each tool's left panel ends with a THEORY tab that permanently displays the
   tool's theory page in an iframe, with English/Hebrew switch buttons. This
   replaced a centred floating window, which was unusable on small screens.

   Lives in the GLOBAL stylesheet rather than a scoped .razor.css because
   scoped-CSS edits do not reliably reach the browser in this project.
   ========================================================================= */

/* Fill the MudTabPanel body. The chain of ancestors between the tab panel and
   this div are all flex/blocks with no explicit height, so the iframe would
   collapse to its default 150px without stretching each level. */
.tool-theory-tab {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;                    /* lets the iframe shrink inside the flex column */
}

/* The MudTabPanel that hosts the theory tab must itself stretch, and must not
   add its own padding — the iframe supplies the page's own margins. */
.mud-tab-panel:has(> .tool-theory-tab),
.mud-tabs-panels:has(.tool-theory-tab) {
    height: 100%;
    min-height: 0;
    padding: 0;
}

/* Language switch strip. flex:0 0 auto so it keeps its height and the iframe
   takes all remaining space (the panel tab-strip stretch bug otherwise applies
   here too). */
.tool-theory-tab-bar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default, #34344a);
}

/* The theory page. min-height:0 is required for a flex child to shrink below
   its content height; without it the iframe overflows the panel. */
.tool-theory-tab-frame {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    border: 0;
    background: #fff;
}

/* -----------------------------------------------------------------
   NAV-MENU SEARCH HIT (orange)
   -----------------------------------------------------------------
   Lives here, in the GLOBAL sheet, and not in NavMenu.razor.css, because
   scoped CSS cannot reach these elements at all:

   - MudNavLink puts its Class= on the wrapper <div class="mud-nav-item">,
     while the paintable surface is the inner <a class="mud-nav-link">, so
     ".mud-nav-link.nav-search-match" asks for two classes that are never on
     the same element and matches nothing.
   - Scoped rules compile to "[b-<scope>] .x", which needs a scoped ANCESTOR.
     The rows sit inside MudNavMenu's own <nav>/<div> chrome and MudBlazor
     stamps no scope id on any of it, so nothing in a row's ancestry carries
     the attribute. ":root ::deep .x" does not rescue it either — Blazor
     compiles that to ":root[b-<scope>] .x", putting the attribute ON <html>,
     which never has it. Both attempts produced a completely unstyled hit.

   ORANGE deliberately, not the menu purple: purple is already the "Menu"
   caption, MudBlazor's active-link colour and the dark-theme primary accent,
   so a purple hit blended into the chrome and was indistinguishable from the
   currently-open page. Orange is unused elsewhere in the nav.

   Light value darkened for contrast on the light surface; dark value
   brightened to stay legible on the near-black panel. */
.mud-nav-item.nav-search-match {
    --nav-search-hit: #e06c00;
}

@media (prefers-color-scheme: dark) {
    .mud-nav-item.nav-search-match {
        --nav-search-hit: #ff9d3f;
    }
}

/* The in-app theme toggle stamps the theme on the root and must win over the
   OS preference in both directions. */
:root.mud-theme-dark .mud-nav-item.nav-search-match {
    --nav-search-hit: #ff9d3f;
}

:root.mud-theme-light .mud-nav-item.nav-search-match {
    --nav-search-hit: #e06c00;
}

/* The row. Descendant combinator, not child: a LOCKED (tier-gated) entry
   renders inside a MudTooltip, which can sit between wrapper and link.
   Locked rows are highlighted too — a tool the user cannot open yet is still
   a search hit worth showing them. */
.mud-nav-item.nav-search-match .mud-nav-link {
    background: color-mix(in srgb, var(--nav-search-hit) 22%, transparent);
    /* Start-edge bar, so a hit stays findable among several highlighted rows
       and when the row is also the currently-active one. */
    box-shadow: inset 3px 0 0 0 var(--nav-search-hit);
}

[dir="rtl"] .mud-nav-item.nav-search-match .mud-nav-link {
    box-shadow: inset -3px 0 0 0 var(--nav-search-hit);
}

/* Label and icon. !important because MudBlazor sets the colour directly on
   these elements for active and disabled rows — without it a locked or
   currently-active hit keeps its grey/primary colour. Tinting the label alone
   leaves a hit looking half-marked next to a default-grey icon. */
.mud-nav-item.nav-search-match .mud-nav-link-text {
    font-weight: 600;
    color: var(--nav-search-hit) !important;
}

.mud-nav-item.nav-search-match .mud-nav-link-icon {
    color: var(--nav-search-hit) !important;
}

/* =================================================================
   Application guided tour — Hebrew mirror of the Resume glyph.

   The Pause/Resume control shows a play triangle while paused. That triangle
   points the way playback advances, so in Hebrew it must point LEFT, matching
   the Next chevron and the direction the countdown bar fills. Material ships
   no left-facing PlayArrow, so the glyph is mirrored here.

   This rule lives in the app-wide stylesheet rather than in
   AppTourOverlayComp.razor.css because the icon is rendered by the MudButton
   CHILD component: Blazor scoped CSS only rewrites selectors against elements
   the owning component emits itself, so a scoped rule matched nothing.

   Scoped to the paused state via the class the component adds, so the
   symmetrical Pause bars are never flipped.
   ================================================================= */
.gv-apptour-play-rtl svg {
    transform: scaleX(-1);
}

/* -----------------------------------------------------------------
   Application tour — keep confirmation dialogs ABOVE the spotlight.

   walkthrough_helper.js paints its dimmer/spotlight host at z-index 20000
   (callout 20001), far above MudBlazor's default dialog layer (~1400). The
   Abort confirmation is raised by the tour itself, so without this it would
   be rendered UNDERNEATH the tour's own dimmer — visible only as a darkened,
   unclickable shape, leaving the tour looking frozen.

   Applied only while a tour is running (body class set by the overlay), so
   ordinary dialogs elsewhere in the app keep MudBlazor's normal stacking.

   Raising the CONTAINER alone is not enough, and this is the subtle part. Inside it
   MudBlazor renders the scrim wrapper (.mud-overlay-dialog) AFTER the card, and the
   card itself is position:static — so its own z-index is inert and the scrim always
   painted on top of it. The buttons were then unreachable: every click and hover at
   their centre hit the scrim instead, which is exactly what made the confirmation
   look greyed out and dead.

   So the card must be given a stacking context of its own (position:relative) and be
   lifted ABOVE the scrim, rather than trying to push the scrim down around it.
   ----------------------------------------------------------------- */
body.gv-apptour-running .mud-dialog-container,
body.gv-apptour-running .mud-popover-provider {
    z-index: 20050 !important;
}

body.gv-apptour-running .mud-overlay-dialog {
    z-index: 20040 !important;
}

/* position:relative is load-bearing, not cosmetic — .mud-dialog is static by default,
   and a z-index on a static element is ignored entirely. */
body.gv-apptour-running .mud-dialog-container .mud-dialog {
    position: relative !important;
    z-index: 20060 !important;
}

/* The tour's dimmer panels carry pointer-events:auto so clicks outside the spotlight
   are swallowed while stepping. A dialog on top is the modal layer and owns the input,
   so stand the panels down while one is open and let the dialog's own scrim block. */
body.gv-apptour-running:has(.mud-dialog-container) #gv-walkthrough-overlay * {
    pointer-events: none !important;
}

/* The callout sits at an inline z-index of 20001, so it would otherwise show THROUGH
   the scrim of the dialog it just raised. !important is required to outrank that
   inline style, not decorative. */
body.gv-apptour-running:has(.mud-dialog-container) .gv-wt-callout {
    z-index: 20030 !important;
}

/* ==========================================================================
   In-button progress fill — ButtonProgressComp

   App-wide rather than scoped to the component, for the same reason the tour's
   RTL play glyph is: the HOST here is a MudButton, an element this component
   does not itself emit, so Blazor's scoped-CSS rewriting would not match it.

   COLOUR CONTRACT: the track is the button's own colour and the indicator is a
   translucent WHITE overlay of it. That is the determinate-progress convention
   in Material, Fluent and Carbon — the control starts as plain primary and
   FILLS toward completion. An earlier version darkened the consumed portion,
   which read backwards (the button appeared to drain) and turned muddy over a
   purple primary instead of brighter.
   ========================================================================== */

.gv-btnprog-host {
    /* Anchor for the absolutely-positioned fill, and clip it to the rounded corners. */
    position: relative;
    overflow: hidden;
}

/* Keep the label above the fill, which is painted behind it. */
.gv-btnprog-label {
    position: relative;
    z-index: 1;
}

.gv-btnprog {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 0;
    /* 0.32 alpha: enough to separate filled from unfilled at a glance, low enough
       that the button still reads as its own colour and the label keeps contrast
       against both halves. The brighter 0.90 edge marks the boundary crisply. */
    background: linear-gradient(
        to right,
        rgba(255, 255, 255, 0.32) 0%,
        rgba(255, 255, 255, 0.32) calc(100% - 2px),
        rgba(255, 255, 255, 0.90) calc(100% - 2px));
    transform-origin: left center;
    transform: scaleX(0);
    animation-name: gv-btnprog-fill;
    animation-timing-function: linear;
    animation-fill-mode: forwards;
    /* animation-duration (or a static transform, in manual mode) is set inline. */
    pointer-events: none;
}

/* RTL: the bar grows from the right edge, the direction Hebrew reads — so the
   gradient's bright leading edge moves to the left end to stay at the FRONT of
   the fill rather than trailing behind it. */
.gv-btnprog-rtl {
    left: auto;
    right: 0;
    transform-origin: right center;
    background: linear-gradient(
        to left,
        rgba(255, 255, 255, 0.32) 0%,
        rgba(255, 255, 255, 0.32) calc(100% - 2px),
        rgba(255, 255, 255, 0.90) calc(100% - 2px));
}

@keyframes gv-btnprog-fill {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}

/* Respect a reduced-motion preference: a static half-fill still signals that the
   action is timed, without the moving animation. */
@media (prefers-reduced-motion: reduce) {
    .gv-btnprog {
        animation: none;
        transform: scaleX(0.5);
    }
}
