/* ═════════════════════════════════════════════════════════════════════════
   BORDERS EVERYWHERE, SQUARE CORNERS EVERYWHERE

   Loaded LAST (after style.css, auth_popup.css, measure.css and
   ui_mobile_popups.css) so it wins on source order. Two promises:

     1. EVERY UI ELEMENT AND POPUP CONTAINER CARRIES A VISIBLE 1px LINE.
        style.css already reserves the border WIDTH almost everywhere - the
        "No borders" pass further up that file turned the tokens
        (--ui_grid_line, --color_border_*, --popup_border_dark) transparent
        and dropped `border: none` on the rest, without changing widths.
        Every box in the app is border-box, so switching those lines back on
        eats into the element's existing box rather than growing it: the 48px
        module stays a true 48px and nothing shifts by a pixel.

     2. NOTHING RECTANGULAR IS ROUNDED.
        A blanket `border-radius: 0` covers every element, pseudo-element and
        token consumer at once - including the ~104 rules reading --rad-4 and
        the pill radii (34px / 999px / 20px) baked in as literals. The
        elements that are genuinely CIRCLES (compass rings, map markers,
        marker action buttons, geolocate pulse, toggle knobs, circular close
        buttons) are listed back in explicitly below and keep their 50%.

   To revert: remove this file and its <link> in index.html. No rule in any
   other stylesheet was touched.
   ═════════════════════════════════════════════════════════════════════════ */

:root {
  /* the one line the whole UI is drawn with. Same value style.css's own
     "one 1px line on every surface" block chose, promoted here so every
     border token in the app resolves to it and the chrome cannot drift into
     two different border colours. */
  --ui_border_visible: rgba(255, 255, 255, 0.85);
  --ui_border_visible_soft: rgba(255, 255, 255, 0.45);

  /* every border token style.css turned transparent, switched back on */
  --ui_grid_line: var(--ui_border_visible);
  --color_border_primary: var(--ui_border_visible);
  --color_border_secondary: var(--ui_border_visible_soft);
  --color_border_focus: var(--ui_border_visible);
  --color_border_active: var(--ui_border_visible);
  --popup_border_dark: var(--ui_border_visible);
  --panel-border: var(--ui_border_visible);
  --panel-border-alpha: var(--ui_border_visible);
  --accent-border: var(--ui_border_visible);

  /* radius tokens zeroed at the source, so the ~130 rules that read them
     resolve to 0 without needing the blanket below to fight them */
  --rad-4: 0px;
  --rad-2: 0px;
  --ui_border_radius_none: 0px;
  --ui_border_radius_small: 0px;
  --cs_border_radius_none: 0px;
  --cs_border_radius_soft: 0px;
  --cs_border_radius_standard: 0px;
}


:root {
  /* ── Circular radii in pixels, never percentages ──────────────────────────
     A percentage radius is measured against the element's own box, so the
     same declaration means a different number of pixels on every element it
     touches and there is no way to tune one without touching all of them. A
     pixel value is the number itself.

     34px on the app's 48px module is a full circle: border-radius clamps
     when the radii on one edge exceed its length, so 34+34=68 on a 48px edge
     scales both to 24 - exactly half, exactly round - while staying a single
     number that can be dialled down for a softer corner without recomputing
     anything.

     The larger token is for the elements that must stay round at a size the
     stylesheet does not fix: the compass rings size themselves off the
     viewport. There is no single pixel value that is half of a variable box,
     so this one is simply larger than any of them and clamps to half
     whatever the box turns out to be - still a pixel value, no percentages. */
  --radius_circle_48: 34px;
  --radius_circle_any: 4096px;
  --radius_pill: 999px;
}


/* ═════════════════════════════════════════════════════════════════════════
   1. SQUARE CORNERS
   ═════════════════════════════════════════════════════════════════════════ */

/* Blanket. Catches the literal pill radii (34px, 999px, 20px, 12px, 10px,
   9px, 6px, 4px), the scoped --rad-4 redefinitions that a :root override
   cannot reach, and any inline border-radius set from script. */
*,
*::before,
*::after {
  border-radius: 0 !important;
}

/* The exceptions: things that are actually circles,
not rounded rectangles.
   Anything below is a ring,
dial,
disc,
marker,
knob or circular icon
   button - squaring these would not "remove a rounded edge",
it would
   change what the element IS. */
.cs_navbar_button_container_uniform,
.search_div,
.top-nav-inner .search_div,
.top-nav-inner .search_back_button,
.top-nav-inner .crosshair_feature_mode_btn,
.top-nav-inner .compass_popup_back_button,
.compass_popup_rotate_button,
.nav-group > .mini_map_toggle,
.nav-group > .compass_toggle,
.nav-group > .crosshair_toggle,
.custom_marker,
.map_marker,
.search_result_marker,
/* the footstep route's numbered step markers - the same 48px disc as
   .custom_marker directly above, and circular for the same reason: a step
   number reads as a stop on a route only when it sits inside a circle */
.cs_travel_step_marker,
.cs_marker_action_button,
.cs_measurement_marker_circular,
.cs_project_marker_circular,
.cs_qr_share_modal_close,
/* the shoe-size and screenshot popups' close buttons, matching
   .cs_qr_share_modal_close above - same chrome, same shape */
.cs_shoe_size_modal_close,
.cs_map_shot_modal_close,
.cs_feature_popup_card_close,
#feature-pointer-button {
  border-radius: var(--radius_circle_48) !important;
}

/* sized by the layout or the viewport rather than by the 48px module, so
   there is no fixed half-width to name - this token is larger than any of
   them and clamps to half whatever the box is. */
.geolocate_toggle_ring,
.geolocate_toggle.tracking_active::before,
.geolocate_toggle.geolocate_toggle_pulse::after,
.mini_compass_container,
.compass_dial,
.compass_dial::before,
.needle_center,
.cs_points_square_tick,
.user_location_pulse_ring,
.user_location_heading_ring,
.user_location_heading_end_badge,
.marker_direction_degree_label,
.marker_cardinal_label,
.cs_marker_direction_value_input,
.cs_marker_monochromatic_glow_ring,
.cs_marker_dark_radial_overlay,
.cs_marker_outer_semi_ring,
.cs_measurement_marker_circular.state_dragging.selected_marker::before,
.cs_measurement_marker_circular.state_dragging.selected_marker::after,
.cs_project_marker_circular.cluster-marker .cluster-count,
.crosshair_feature_preview,
.large_compass_container,
.large_compass_outermost_ring,
.large_compass_outer_ring,
.large_compass_inner_ring,
.large_compass_center_circle,
.large_compass_innermost_circle,
.large_compass_dial,
.large_compass_dial::before,
.large_compass_dial::after,
.large_needle_north_indicator,
.large_needle_south_indicator,
.large_needle_center,
.cs_compass_outer_ring,
.cs_compass_viewport_circle,
.cs_compass_center_circle,
.cs_compass_inner_center_circle,
.cs_compass_medium_circle,
.cs_compass_large_circle,
.cs_compass_small_circle,
.speed_limit_sign,
.speed_limit_sign.loading .speed_limit_value::after,
.sliding_menu_switch::after,
#offscreen-pointer {
  border-radius: var(--radius_circle_any) !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   2. UNDO THE "NO BORDERS" PASS

   style.css's section "1. No borders" sets `border-color: transparent
   !important` across every panel, popup, rail and their descendants. Same
   selector list, same specificity, later in the cascade - so this wins and
   the reserved 1px lines become visible again. border-style is forced to
   solid in the same rule because ~94 of those elements were also given
   `border: none`, which zeroes the style, not just the colour.
   ═════════════════════════════════════════════════════════════════════════ */

.side-panel,
.side-panel *,
.sliding_menu,
.sliding_menu *,
.control_panel,
.control_panel *,
.view_controls_panel,
.view_controls_panel *,
.overlay_panel,
.overlay_panel *,
.filemanager_panel,
.filemanager_panel *,
.bottom_popup_container,
.bottom_popup_container *,
.search_popup,
.search_popup *,
.cs_feature_profile_popup,
.cs_feature_profile_popup *,
.cs_panel_container_expandable,
.cs_panel_container_expandable *,
.top_nav_container,
.top_nav_container *,
.left_nav_sidebar,
.left_nav_sidebar *,
.footer_nav_bar,
.footer_nav_bar *,
.nav_sidebar_top_box,
.nav_sidebar_top_box *,
.nav_sidebar_bottom_box,
.nav_sidebar_bottom_box *,
.floating_fullscreen_btn,
.mini_map_container,
.mini_map_container *,
.altitude_scale_dom,
.altitude_scale_dom *,
.control_button,
.cs_input_bar,
.cs_input_bar * {
  border-color: var(--ui_border_visible);
}

/* Glyphs, text runs and layout shims inside those containers are not UI
   elements in their own right - a border on every <span> and <svg> would
   draw a box around each icon and each word. They keep the border colour
   above (harmless, they have no border width) but are excluded from the
   box-drawing rules in section 3. */


/* ═════════════════════════════════════════════════════════════════════════
   3. A BOX AROUND EVERY UI ELEMENT AND POPUP CONTAINER
   ═════════════════════════════════════════════════════════════════════════ */

/* ── 3a. Popup / panel / modal / bar containers ───────────────────────────
   Every floating or docked surface the app opens over the map. */
.side-panel,
.sliding_menu,
.sliding_menu_content,
.control_panel,
.control_panel_grid,
.view_controls_panel,
.view_controls_content,
.overlay_panel,
.overlay_panel_content,
.overlay_export_modal,
.filemanager_panel,
.filemanager_panel_content,
.filemanager_modal,
.bottom_popup_container,
.bottom_popup,
.search_popup,
.search_container,
.search_results_container,
.cs_feature_profile_popup,
.cs_feature_popup_card,
.cs_panel_container_expandable,
.cs_panel_content_scrollable,
.cs_measurement_panels_container,
.cs_measurement_panel_expandable,
.cs_input_bar,
.cs_qr_share_modal,
.cs_qr_share_modal_content,
.cs_toolbar_controls_container,
.crosshair_feature_toolbar,
.crosshair_feature_readout,
.compass_popup_container,
.marker_direction_nav_bar,
.marker_travel_panel,
.mini_map_container,
.mini_map_controls_navbar,
.compass_controls_navbar,
.crosshair_controls_navbar,
.nav_undo_redo_group,
.top_nav_container,
.left_nav_sidebar,
.footer_nav_bar,
.nav_sidebar_top_box,
.nav_sidebar_bottom_box,
.altitude_scale,
.altitude_scale_dom,
.ruler_dom_container,
.rotation_pill,
.zoom_pill,
.speedometer_widget,
.speed_limit_overlay,
.coordinates_container,
.cs_autocomplete_container,
.user_dropdown,
.user_dropdown_header,
.auth_modal,
.auth_form_container,
.toast-container,
.maplibregl-popup-content,
.maplibregl-ctrl-group,
#map_error_container,
#info_container {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}

/* ── 3b. Header / footer / tab strips inside those containers ─────────────
   A popup's chrome rows are elements in their own right, not decoration. */
.panel-header,
.panel-tabs,
.panel-tab,
.panel-content,
.sliding_menu_header,
.sliding_menu_item,
.view_controls_header,
.view_controls_tab,
.vc_control_block,
.vc_input_row,
.vc_distance_row,
.overlay_panel_header,
.overlay_item_header,
.overlay_item_content,
.overlay_item_footer,
.overlay_stats,
.overlay_export_section,
.overlay_export_option,
.overlay_upload_area,
.filemanager_panel_header,
.filemanager_panel_tabs,
.filemanager_panel_tab,
.filemanager_modal_header,
.filemanager_modal_content,
.filemanager_modal_actions,
.filemanager_modal_field,
.filemanager_upload_area,
.filemanager_active_project,
.filemanager_export_section,
.fm_file_upload_area,
.cs_panel_header_collapsible,
.cs_panel_header_container_sticky,
.cs_measurement_panel_header,
.cs_measurement_panel_content,
.cs_measurement_section_container,
.cs_popup_content_area,
.cs_category_header,
.cs_category_content_wrapper,
.cs_service_sub_panel,
.cs_service_sub_panel_header,
.cs_service_sub_panel_content,
.auth_modal_header,
.auth_tabs,
.auth_tab,
.auth_input_group,
.auth_quick_actions,
.auth_oauth_actions,
.features-nav-container,
.features-nav,
.layers-source-nav,
.layer-category-layers,
.gis_stat_row,
.gis_info_note,
.search_recent_header {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}

/* ── 3c. Rows and list items ──────────────────────────────────────────────
   Anything that reads as one selectable line in a list. */
.search_result_item,
.top-nav-inner .search_result_item,
.layer-item,
.layer-category-arrow-box,
.layer-category-checkbox-box,
.nav_div,
.nav_list_item,
.user_dropdown_item,
.cs_autocomplete_item,
.cs_autocomplete_empty,
.cs_layer_list_container > *,
.cs_crosshair_distance_unit_option,
.gis_stat_value,
.overlay_item,
.filemanager_file_item,
.feature-icon {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}

/* ── 3d. Controls ─────────────────────────────────────────────────────────
   Every button, field, select and toggle in the app chrome. Scoped to the
   chrome roots plus the named control classes so map-canvas marks (markers,
   labels, rings, the map itself) are not swept in. */
button,
input:not([type="range"]):not([type="checkbox"]):not([type="radio"]),
select,
textarea,
.control_button,
.nav-scroll-btn,
.mini_zoom_btn,
.mini_layers_btn,
.mini_map_corner_btn,
.nav_undo_redo_btn,
.bottom_nav_button,
.footer_nav_bar .bottom_nav_button,
.menu_button,
.cs_popup_close_btn,
.cs_close_panel_button,
.cs_search_toggle_button,
.cs_settings_button,
.cs_search_submit_button,
.cs_search_clear_button,
.cs_search_input_field,
.cs_search_input_wrapper,
.cs_select_dropdown_input,
.cs_checkbox_container,
.cs_expansion_arrow_container,
.cs_icon_container_uniform,
.cs_popup_collapse_btn,
.cs_points_folder_caret,
.cs_points_folder_ungroup,
.search_input,
.clear_search,
.search_submit,
.search_back_button,
.indicator_input,
.vc_input_btn,
.vc_input_field,
.vc_action_btn,
.vc_select_field,
.vc_reset_btn,
.vc_distance_select,
.vc_angle_input,
.overlay_item_btn,
.overlay_export_toggle,
.overlay_gamepad_reset_btn,
.filemanager_add_btn,
.filemanager_modal_btn,
.filemanager_modal_input,
.fm_new_project_btn,
.gis_share_buttons .gis_widget_btn,
.auth_submit_btn,
.auth_quick_btn,
.auth_oauth_btn,
.auth_modal_close,
.user_auth_button,
.sliding_menu_close,
.view_controls_close,
.overlay_panel_close,
.filemanager_panel_close,
.filemanager_modal_close,
.features-nav-button,
.layers-source-nav-button,
.sliding_menu_switch,
.floating_fullscreen_btn,
.crosshair_feature_mode_btn,
.crosshair_feature_toolbar_done {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}

/* Sidebar tool buttons. style.css scopes these behind a doubled
   #left_nav_sidebar#left_nav_sidebar selector to force `border: none`, so
   the same doubled ID is needed here to outrank it. */
#left_nav_sidebar#left_nav_sidebar .nav-group > *,
#left_nav_sidebar#left_nav_sidebar .nav-scroll-btn,
#left_nav_sidebar#left_nav_sidebar .mini_map_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .mini_map_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .compass_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .compass_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .crosshair_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .crosshair_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .nav_undo_redo_group,
#left_nav_sidebar#left_nav_sidebar .nav_undo_redo_group > *,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_top_box,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_top_box > *,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_bottom_box,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_bottom_box > * {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}

/* Top bar cells, same doubled-selector reason. */
.top_bar_lead .control_button,
.top_bar_trail .control_button,
.top_bar_logo,
.top_bar_account_slot > * {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}


/* ═════════════════════════════════════════════════════════════════════════
   4. NOT UI CHROME - LEFT ALONE

   Marks drawn ON the map, pure-layout wrappers with no surface of their own,
   and the scrims behind modals. Each of these would read as a stray
   rectangle floating over the map if it were given a line, so the rules
   above are undone for them here rather than being written around them.
   ═════════════════════════════════════════════════════════════════════════ */

#map,
.maplibregl-canvas-container,
.maplibregl-canvas,
.menu_overlay,
.auth_modal_overlay,
.filemanager_modal_overlay,
.cs_compass_overlay_container,
.cs_compass_overlay_container > *,
.cs_compass_indicators_container,
.cs_compass_bottom_indicators_container,
.cs_compass_north_south_line_container,
.crosshair_dom_container,
.crosshair_element,
.grid_overlay_container,
.large_compass_overlay,
.geolocate_toggle_rotator,
.nav-scroll-fade-left,
.nav-scroll-fade-right,
.cs_loading_container,
.cs_progress_bar_container,
.filemanager_progress_bar_container {
  border: none !important;
}

/* Marks drawn ON the map are not swept into the rules above - a marker's
   ring is part of the mark, not app chrome, so it is not repainted with the
   chrome line. Their own uniform 48px / 1px-ring / dark-fill treatment is
   section 9 at the bottom of this file.

   The one thing on the map that IS chrome is the MapLibre popup bubble. */
.maplibregl-popup-content {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
}

/* Icons, glyphs and text runs are content inside a bordered element, not
   elements that get their own box. */
.left_nav_sidebar i,
.left_nav_sidebar svg,
.left_nav_sidebar span:not(.control_button),
#left_nav_sidebar#left_nav_sidebar i,
#left_nav_sidebar#left_nav_sidebar svg,
#left_nav_sidebar#left_nav_sidebar span,
.top_nav_container i,
.top_nav_container svg,
.footer_nav_bar i,
.footer_nav_bar svg,
button > i,
button > svg,
button > span {
  border: none !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   5. THE TOP-BAR FAMILY

   style.css writes this group as `.top-nav-inner <child> { border: none
   !important }` - two classes deep, so a single-class rule in section 3
   loses to it even with !important. Repeated here at matching depth. The
   circular members (search icon, back buttons, mode pills) get their line
   too; only their radius is exempt, not their border.
   ═════════════════════════════════════════════════════════════════════════ */

.top_nav_container.top-nav,
.top_nav_container.top-nav.fading_border,
.top_nav_container.top-nav .top_nav,
.top-nav-inner,
.top-nav-inner .nav-view,
.top-nav-inner .fading_border,
.top-nav-inner .search_container,
.top-nav-inner .search_container.full-width,
.top-nav-inner .search_results_container,
.top-nav-inner .search_result_item,
.top-nav-inner .search_input,
.top-nav-inner .search_input:focus,
.top-nav-inner .search_div,
.top-nav-inner .search_back_button,
.top-nav-inner .clear_search,
.top-nav-inner .crosshair_feature_toolbar,
.top-nav-inner .crosshair_feature_toolbar.full-width,
.top-nav-inner .crosshair_feature_mode_btn,
.top-nav-inner .compass_popup_container,
.top-nav-inner .compass_popup_container.full-width,
.top-nav-inner .compass_popup_back_button,
.top-nav-inner .compass_popup_rotate_button {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}


/* ═════════════════════════════════════════════════════════════════════════
   6. THE ACTIVE CROSSHAIR PAIR

   style.css lifts .crosshair_toggle.active and the .add_marker beside it out
   of the rail - 38px inside a 48px cell with 5px of margin - and drops their
   borders so the floating pair does not read as still ruled to the column.
   They are the two most prominent controls in the app while the crosshair is
   on, so they get the line back here. Geometry is untouched: the rule sets
   only border, and border-box means the 1px eats into the 38px rather than
   growing it, so the 48px column pitch still holds.
   ═════════════════════════════════════════════════════════════════════════ */

#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active,
#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active + .add_marker {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-style: solid !important;
  box-sizing: border-box;
}


/* ═════════════════════════════════════════════════════════════════════════
   7. ONE LINE BETWEEN NEIGHBOURS, NOT TWO

   Section 3 gives every cell in the tool rail its own four-sided box. In a
   vertical stack that puts TWO 1px lines between every neighbouring pair -
   one cell's bottom against the next cell's top - so the column reads as a
   2px seam every 48px, and the nested groups (undo/redo, the mini-map zoom
   pair) stack a third line on top of that where a group's box sits 1px
   outside its own children's.

   Each cell therefore draws its TOP line only, and the cell below draws the
   next one: any two neighbours share exactly one rule. The rail's own box
   still closes the column at the left, right and bottom, so nothing is left
   open by dropping the bottom edges inside it.
   ═════════════════════════════════════════════════════════════════════════ */

/* Written against the same selector shapes sections 3 and 8 use rather than
   as one `#left_nav_sidebar#left_nav_sidebar *` sweep: those rules name a
   class (and the crosshair rule names three), so a bare universal selector
   at the same id depth loses to them and the bottom edges survived. Matching
   their specificity and coming later in the file is what actually wins. */
#left_nav_sidebar#left_nav_sidebar *,
#left_nav_sidebar#left_nav_sidebar .nav-group > *,
#left_nav_sidebar#left_nav_sidebar .nav-scroll-btn,
#left_nav_sidebar#left_nav_sidebar .cs_navbar_scroll_button,
#left_nav_sidebar#left_nav_sidebar .nav_undo_redo_group > *,
#left_nav_sidebar#left_nav_sidebar .mini_map_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .mini_zoom_controls > *,
#left_nav_sidebar#left_nav_sidebar .compass_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .crosshair_controls_navbar > *,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_top_box > *,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_bottom_box > *,
#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active {
  border-bottom: none !important;
}

/* A group that its own children exactly fill draws no box: the children's
   lines already describe it, and a box 1px outside them is the doubled edge
   this section exists to remove. */
#left_nav_sidebar#left_nav_sidebar .nav_undo_redo_group,
#left_nav_sidebar#left_nav_sidebar .mini_map_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .mini_zoom_controls,
#left_nav_sidebar#left_nav_sidebar .compass_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .crosshair_controls_navbar,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_top_box,
#left_nav_sidebar#left_nav_sidebar .nav_sidebar_bottom_box {
  border: none !important;
}

/* The rail's own top edge is the top bar's bottom border - the two are
   flush, so drawing both is the same doubled line one cell down. */
.left_nav_sidebar,
#left_nav_sidebar#left_nav_sidebar {
  border-top: none !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   8. THE CROSSHAIR / ADD-MARKER PAIR STACKS AS ONE

   style.css lifts these two out of the rail while the crosshair is on: 38px
   inside a 48px cell with 5px of margin all round, which reads as two small
   boxes floating apart from each other and from the column.

   They go back to the rail's own 48px module with no margin, so they sit
   flush - and the lower one (add marker) drops its border entirely, so the
   pair is described by a single outline rather than by two. The crosshair
   button's top line still separates the pair from the tool above it; there
   is no line between the two, which is what makes them read as one control
   stacked on itself rather than as two neighbours.
   ═════════════════════════════════════════════════════════════════════════ */

#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active,
#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active + .add_marker {
  width: var(--ui_element_uniform_width, 48px) !important;
  min-width: var(--ui_element_uniform_width, 48px) !important;
  max-width: var(--ui_element_uniform_width, 48px) !important;
  height: var(--ui_element_uniform_height, 48px) !important;
  min-height: var(--ui_element_uniform_height, 48px) !important;
  max-height: var(--ui_element_uniform_height, 48px) !important;
  margin: 0 !important;
}

#left_nav_sidebar#left_nav_sidebar .nav-group > .crosshair_toggle.active + .add_marker {
  border: none !important;
}


/* ── 8b. The buttons inside a collapsed group ─────────────────────────────
   Section 7 clears the box on the group wrappers, on the grounds that their
   children's lines already describe them. That holds for .nav_undo_redo_group,
   whose buttons are its direct children - but the mini-map zoom pair and the
   compass rotate/reset trio sit one level deeper, inside a .mini_zoom_controls
   wrapper, so clearing the wrapper left them with no line of their own and
   the rail showed a blank 96px / 144px block where those controls are.

   They are named here at the same doubled-id depth style.css uses to force
   `border: none` on this group, and take the rail's own top-line-only rule. */
#left_nav_sidebar#left_nav_sidebar .mini_zoom_controls > *,
#left_nav_sidebar#left_nav_sidebar .mini_map_controls_navbar .mini_zoom_btn,
#left_nav_sidebar#left_nav_sidebar .compass_controls_navbar .mini_zoom_btn,
#left_nav_sidebar#left_nav_sidebar .crosshair_controls_navbar .mini_zoom_btn {
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-bottom: none !important;
  box-sizing: border-box;
}

/* The mini compass needle's own container is a glyph holder filling the
   compass button, not a cell of the rail - its stray bottom border drew a
   line straight across the middle of that button. */
#left_nav_sidebar#left_nav_sidebar .mini_compass_container,
#left_nav_sidebar#left_nav_sidebar .mini_compass_needle {
  border: none !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   9. EVERY MARKER IS THE SAME 48px DISC

   The markers had drifted into three different treatments: 48px discs with a
   2px white ring for placemark/search/project, a 48px ring for the action
   buttons with no border at all, and an 18px dot for the geolocate marker -
   parked at top/left 15px inside its own 48px .user_location_scale_wrapper,
   which is why it read as a quarter the size of everything else on the map.

   All of them now use the module the rest of the app is built on: a 48px
   square box, a 1px ring, and one semi-transparent dark fill.

   The fill is deliberately ONE colour rather than the old per-type blue /
   red / green. What a marker IS stays legible through its glyph, which is
   opaque white on every type; what the fill has to do is let the basemap and
   any feature underneath keep showing through, and four different tints of
   that did not distinguish anything the icon was not already saying. The
   type accents are not gone from the app - the geolocate pulse ring, its
   heading line and the points-list icons all still carry theirs.
   ═════════════════════════════════════════════════════════════════════════ */

:root {
  /* one fill for every mark on the map. Same alpha the measurement markers
     (measure.css) already used, which is the treatment the others are being
     brought into line with. */
  --map_marker_fill_dark: rgba(6, 6, 6, 0.55);
  /* consumed as `border: var(--map_marker_border)` by the marker rules in
     style.css - was 2px */
  --map_marker_border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible);
}

.custom_marker,
.map_marker,
.search_result_marker,
.custom_marker.user-marker,
.custom_marker.placemark-marker,
.cs_project_marker_circular,
.cs_project_marker_circular.cluster-marker,
.cs_measurement_marker_circular,
.cs_marker_action_button {
  width: var(--ui_element_uniform_width, 48px) !important;
  min-width: var(--ui_element_uniform_width, 48px) !important;
  max-width: var(--ui_element_uniform_width, 48px) !important;
  height: var(--ui_element_uniform_height, 48px) !important;
  min-height: var(--ui_element_uniform_height, 48px) !important;
  max-height: var(--ui_element_uniform_height, 48px) !important;
  background: var(--map_marker_fill_dark) !important;
  background-color: var(--map_marker_fill_dark) !important;
  background-image: none !important;
  border: var(--ui_border_uniform_width, 1px) solid var(--ui_border_visible) !important;
  border-radius: var(--radius_circle_48) !important;
  box-sizing: border-box !important;
}

/* The geolocate marker was an 18px dot pinned 15px in from the top-left of
   its 48px wrapper - that offset is what centred the small dot, so it has to
   go with the size, or a 48px marker sits 15px down-right of the coordinate
   it is marking. */
.custom_marker.user-marker {
  top: 0 !important;
  left: 0 !important;
}

/* its glyph scales with it: the arrowhead was 6px inside an 18px dot, which
   is a speck inside a 48px one. 16px matches the 16-20px glyph every other
   marker carries. */
.custom_marker.user-marker::before {
  width: 16px !important;
  height: 16px !important;
}
.custom_marker.user-marker .user_location_marker_triangle_svg {
  width: 20px !important;
  height: 20px !important;
}

/* Hover/selected/dragging states restyle a marker that already has its ring
   and fill from the base rule - they keep their own accent, at 1px. */
.custom_marker.cs_marker_project_selected,
.map_marker.cs_marker_project_selected,
.search_result_marker.cs_marker_project_selected,
.cs_project_marker_circular.state_selected {
  border-width: var(--ui_border_uniform_width, 1px) !important;
}

/* the cluster badge is a count chip riding on the marker, not a marker */
.cs_project_marker_circular.cluster-marker .cluster-count {
  width: 28px !important;
  min-width: 28px !important;
  max-width: 28px !important;
  height: 28px !important;
  min-height: 28px !important;
  max-height: 28px !important;
  background: var(--text-color, #ffffff) !important;
}


/* (Section 10 held the bracket and graduation rules for the ruler's four
   crosshair arms. The arms are gone - section 15 replaced them with the 5x5
   grid - so the rules went with them rather than being left to match
   selectors that no elements carry any more.) */


/* ═════════════════════════════════════════════════════════════════════════
   11. ONE CENTRE, AND CHROME ON TOP OF EVERY MAP OVERLAY

   ── The centre ──
   #map fills the viewport and the chrome is painted over it, so the map's
   own centre - what map.getCenter() projects to, where the crosshair drops a
   feature, what a popup opens on - is the VIEWPORT centre. The crosshair,
   the ruler and the grid overlay all agree on it.

   The compass overlay did not. Its original rule set left:48px right:48px,
   symmetric on purpose ("so the container's own 50% center still lands
   exactly on the true viewport center - matching map.getCenter(), the
   crosshair, and new-marker placement"). The pass that moved the scrolling
   top navbar into the left sidebar rewrote that to left:<sidebar> right:0,
   which is not symmetric: it pushed the container's centre 24px to the
   right of the map's on a 1440px window, and every ring, bar and indicator
   inside it went with it. Restoring the symmetry puts all of it back on the
   map's own centre - and going to 0/0 rather than back to 48/48 also lets
   the overlay's cross-section lines run the full width of the screen.

   ── The z-order ──
   The chrome sat at z-index 1000 while the ruler arms are at 10000 and the
   grid overlay at 10100, so those lines drew straight over the sidebar and
   the top bar. Lifting the chrome above every map overlay means a line can
   extend to the true edge of the map - which is the viewport edge - and
   still be hidden the moment it reaches the rails, instead of being cut
   short of them or painted across them. The same lift keeps the rails out
   of the dimming a modal scrim applies to the map behind it.
   ═════════════════════════════════════════════════════════════════════════ */

.cs_compass_overlay_container {
  left: 0 !important;
  right: 0 !important;
}

/* Above .ruler_dom_container (20200), the grid overlay (10100), the ruler
   arms (10000) and the modal scrims. The rails are the app frame: nothing
   drawn on the map goes over them. */
.top_nav_container,
.top_nav_container.top-nav,
#left_nav_sidebar,
.left_nav_sidebar,
.footer_nav_bar,
.nav_sidebar_top_box,
.nav_sidebar_bottom_box,
.top_bar_lead,
.top_bar_trail {
  z-index: 30000 !important;
}

/* The overlays that do run to the edges - the compass cross-sections - may
   now reach them: the rails cover their own strips. (The ruler's four arms
   used to be sized here too; they no longer exist.) */
.cs_compass_cross_section_horizontal {
  left: 0 !important;
  right: 0 !important;
  width: auto !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   12. COMPASS FACE: THE INDICATOR RING AND ITS INSCRIBED TRIANGLE

   The overlay's existing rings (viewport / small / centre circle) are all
   smaller than the indicator column, so the cardinal cells at the very top
   and bottom sat outside every one of them - the face read as a stack of
   boxes with some loose circles behind it rather than as a compass.

   This ring is exactly as tall as the container, which is exactly the span
   from the top edge of the topmost indicator to the bottom edge of the
   bottommost one, so it closes around all of them. aspect-ratio keeps it a
   true circle rather than an ellipse at any window proportion, and it is
   centred with the same translate every other ring here uses, so it shares
   the one centre section 11 put back on the map's own.

   The triangle is inscribed in that same circle - its three vertices lie ON
   the ring, apex up - so the two read as one figure.
   ═════════════════════════════════════════════════════════════════════════ */

/* The selector is written at the same depth as section 4's
   `.cs_compass_overlay_container > * { border: none !important }` - that rule
   names two classes and clears the border on every direct child of the
   overlay, which this ring is, so a single-class rule loses to it even with
   !important and the ring rendered with no border at all. */
.cs_compass_overlay_container > .cs_compass_indicator_ring,
.cs_compass_indicator_ring {
  position: absolute;
  top: 50%;
  left: 50%;
  height: 100%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  /* Opaque white rather than the chrome's 0.85 line. This ring is drawn ON
     the map, where a translucent hairline disappears into pale parcel fill.
     It used to carry a doubled drop-shadow halo for that reason; section 16
     takes the halo off every map overlay and gives them all one scrim to
     read against instead, so the stroke here is just solid white. */
  border: var(--ui_border_uniform_width, 1px) solid #ffffff !important;
  /* the variable-size token: this ring is as tall as the overlay, so its
     half-width is a viewport measurement, not a number this file can name */
  border-radius: var(--radius_circle_any) !important;
  background: transparent;
  pointer-events: none;
  box-sizing: border-box;
  /* under the indicator cells, which are opaque, so the ring passes behind
     them rather than drawing a line across their faces */
  z-index: 1;
}

.cs_compass_indicator_triangle_svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.cs_compass_indicator_triangle {
  fill: none;
  /* opaque white over the overlay's scrim - no halo; see section 16 */
  stroke: #ffffff;
  /* the viewBox is 100 units across and the element is ~800px wide, so a
     1-unit stroke would render ~8px thick - vector-effect keeps it at a real
     1px on screen at whatever size the ring ends up */
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}


/* ═════════════════════════════════════════════════════════════════════════
   13. THE SAME SINGLE-SEAM RULE, EVERYWHERE ELSE

   Section 7 collapsed the doubled lines inside the tool rail. The same three
   shapes of doubling were left everywhere else in the chrome, found by
   walking every bordered element on screen and reporting any pair whose
   edges land within 2px of each other:

     1. NESTED BOXES that exactly fill each other. .top_nav_container,
        .top-nav-inner and #nav-main all occupy 0,0,1440,48 - three boxes,
        three borders, 1px apart. Only the outermost draws.

     2. DOCKED EDGES. The top bar's bottom border sits at y=48, and so does
        the top border of everything hanging off it - the rail's scroll
        button, the fullscreen toggle, the ruler's unit bar, the compass's
        top indicator. The bar's line is the one between them; the things
        below drop theirs.

     3. STACKS AND ROWS. The compass indicator column and the top bar's own
        cells each drew a full box per cell, so every neighbour pair showed
        two lines. One line per pair: later siblings drop the edge they share
        with the one before.

   The 48px module is what makes this land on a grid rather than just look
   tidy - every cell above is already a 48px multiple, so collapsing the
   shared edges leaves one continuous 1px lattice with no half-pixel or
   double-width seams in it.
   ═════════════════════════════════════════════════════════════════════════ */

/* 1. nested boxes - the outermost surface is the one that draws.

   Written with .top-nav doubled onto the container because section 5 gives
   this same group its border through `.top_nav_container.top-nav .top_nav`,
   which is three classes deep - a two-class rule here loses to it however
   late it comes in the file, and #nav-main kept its box. */
.top_nav_container.top-nav .top-nav-inner,
.top_nav_container.top-nav .nav-view,
.top_nav_container.top-nav .top_nav,
.top_nav_container.top-nav .top-nav-inner .nav-view,
.indicator_input_container {
  border: none !important;
}

/* 2. docked under the top bar - the bar's own bottom border is the seam */
.top_nav_container + *,
#left_nav_sidebar .cs_navbar_scroll_button:first-child,
#left_nav_sidebar#left_nav_sidebar .cs_navbar_scroll_button:first-child,
.floating_fullscreen_btn,
.cs_crosshair_ruler_unit_bar,
.cs_crosshair_ruler_unit_bar .cs_measurement_ruler_unit_select,
.cs_compass_top_circle,
.cs_compass_top_circle .indicator_input,
#cardinal_indicator {
  border-top: none !important;
}

/* 3a. vertical stacks: a cell after another drops the edge they share.

   The compass indicators are one continuous 48px column, but they are split
   across three containers (.cs_compass_top_circle, then the middle and
   bottom indicator groups), so a `> * + *` rule cannot see the seam between
   one container's last cell and the next container's first. Every indicator
   therefore drops its TOP edge and keeps its bottom: the seams come out
   single wherever the column is cut, the top of the column is closed by the
   top bar's own line, and the bottom by the last cell's.

   Named by id, not by .indicator_input: style.css's own grid-line block
   lists these six by id, so a class rule here never reaches them. */
#cardinal_indicator,
#azimuth_indicator,
#bearing_indicator,
#bottom_azimuth_indicator,
#bottom_bearing_indicator,
#bottom_cardinal_indicator,
.indicator_input,
.cs_compass_indicators_container > * + *,
.cs_compass_bottom_indicators_container > * + *,
.vc_control_block + .vc_control_block,
.vc_input_row + .vc_input_row,
.sliding_menu_item + .sliding_menu_item,
.search_result_item + .search_result_item,
.user_dropdown_item + .user_dropdown_item,
.cs_autocomplete_item + .cs_autocomplete_item,
.layer-item + .layer-item,
.auth_input_group + .auth_input_group,
.overlay_export_option + .overlay_export_option,
.gis_stat_row + .gis_stat_row,
.filemanager_modal_field + .filemanager_modal_field {
  border-top: none !important;
}

/* 3b. horizontal rows: same, on the vertical seam */
.top_bar_lead > * + *,
.top_bar_trail > * + *,
.top_bar_lead + .top_bar_logo,
#menu_button_left + #top_bar_logo,
.panel-tabs > * + *,
.auth_tabs > * + *,
.filemanager_panel_tabs > * + *,
.view_controls_tabs > * + *,
.features-nav > * + *,
.layers-source-nav > * + *,
.footer_nav_bar > * + *,
.filemanager_modal_actions > * + *,
.auth_quick_actions > * + * {
  border-left: none !important;
}

/* the toast strip is a transient message rail pinned along the bottom edge,
   not a surface - it was drawing a border down the whole right side of the
   tool rail */
.toast-container {
  border: none !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   14. MARKER RADIUS: ROUND DISCS, PILL LABELS

   Section 9 made every marker and every marker action button the same 48px
   disc, and section 1's blanket keeps rectangles square - but the blanket
   also flattened the small text chips that hang off a marker (its name, its
   coordinate readout, the heading degree badge, the label chip drawn by
   .custom_marker::after). A square caption under a round marker is the one
   place where the square-corners rule fights the thing it is attached to.

   So the map's own marks get their own rule, one step apart from the chrome:
   anything DISC-shaped stays a full circle, and anything that is a strip of
   text stays a pill. Nothing on the map is a square-cornered box.
   ═════════════════════════════════════════════════════════════════════════ */

.marker_coord_label,
.marker_name_label,
.custom_marker::after,
.map_marker::after,
.search_result_marker::after,
.cs_project_marker_circular::after,
.user_location_heading_degree_text,
.cs_measurement_marker_label,
.cs_marker_label_chip {
  border-radius: var(--radius_pill) !important;
}

/* and the discs stay discs - restated here at marker depth so a later
   rectangle rule can never square one of them off */
.custom_marker,
.map_marker,
.search_result_marker,
.custom_marker.user-marker,
.custom_marker.placemark-marker,
.cs_project_marker_circular,
.cs_project_marker_circular.cluster-marker,
.cs_measurement_marker_circular,
.cs_marker_action_button {
  border-radius: var(--radius_circle_48) !important;
}

/* sized by the layout or the viewport rather than by the 48px module, so
   there is no fixed half-width to name - this token is larger than any of
   them and clamps to half whatever the box is. */
.cs_project_marker_circular.cluster-marker .cluster-count,
.cs_marker_outer_semi_ring,
.cs_marker_monochromatic_glow_ring,
.cs_marker_dark_radial_overlay,
.user_location_pulse_ring,
.user_location_heading_ring,
.user_location_heading_end_badge,
.marker_direction_degree_label,
.marker_cardinal_label,
.cs_marker_direction_value_input {
  border-radius: var(--radius_circle_any) !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   15. THE RULER IS A GRID WITH NESTED BRACKETS

   Replaces the four crosshair arms. An arm running to the edge of the screen
   measured a distance nobody was trying to measure - you cannot lay the edge
   of the viewport along a building. A block of known cells can be: the grid
   is the app's own 48px module, five across and five down, sitting on the
   map centre, and the three brackets under it read that same block at three
   scales - one cell, the middle three, all five.

   All three brackets hang from the GRID'S BOTTOM EDGE and reach different
   depths, rather than being stacked one under the next. That is what makes
   them nest: the eye follows three side ticks down from the same line and
   sees 1 / 3 / 5 as three readings of one object, not as three separate
   measurements that happen to be near each other.

   Everything is white at full opacity over the tint below, and the bracket
   rules are dashed so they read as dimension lines rather than as more grid.
   ═════════════════════════════════════════════════════════════════════════ */

:root {
  /* the ruler's own ink - deliberately not --ui_border_visible (0.85), which
     is the chrome's line. These are drawn over the tint and want to be the
     brightest thing on screen. */
  --ruler_stroke: #ffffff;
  --ruler_cell: 48px;
}

/* ── the tint ──
   Dark enough to give the white strokes one consistent ground instead of
   whatever the basemap is under them; light enough that every road, label
   and parcel under it is still legible. It is a tint, not a mask. */
.cs_ruler_scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.28);
  pointer-events: none;
  z-index: 0;
}

/* ── the 5x5 grid ── */
.cs_ruler_grid {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--ruler_cell) * 5);
  height: calc(var(--ruler_cell) * 5);
  transform: translate(-50%, -50%);
  display: grid;
  grid-template-columns: repeat(5, var(--ruler_cell));
  grid-template-rows: repeat(5, var(--ruler_cell));
  gap: 0;
  pointer-events: none;
  z-index: 2;
  /* the grid closes its own right and bottom; each cell draws only its top
     and left, so no interior line is drawn twice - a 2px seam at 48px pitch
     is very visible, and doubled lines are what the rest of this file exists
     to remove */
  border-right: 1px solid var(--ruler_stroke);
  border-bottom: 1px solid var(--ruler_stroke);
}

.cs_ruler_grid_cell {
  width: var(--ruler_cell);
  height: var(--ruler_cell);
  box-sizing: border-box;
  border-top: 1px solid var(--ruler_stroke);
  border-left: 1px solid var(--ruler_stroke);
  background: transparent;
}

/* ── ruler edges: tick marks inside the grid ──
   The SVG in index.html is the grid's own 240px box, laid over the cells.
   Minor ticks every 9.6px (a fifth of a cell) stand in from all four edges;
   the cell lines themselves are the major marks. Same ink as every other
   stroke in this overlay. */
.cs_ruler_ticks {
  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--ruler_cell) * 5);
  height: calc(var(--ruler_cell) * 5);
  overflow: visible;
  fill: var(--ruler_stroke);
  pointer-events: none;
  z-index: 1;
}

/* ── the cell tints: three rings, lighter towards the middle ──
   The 16 outer cells carry a 30% white tint, the 8 cells of the inner ring
   10%, and the centre cell none - so the block reads as a frame closing in
   on the map centre, and the cell the 1-cell bracket measures is the one
   patch of map left completely untouched. Background alpha rather than
   opacity, so the cell lines on top stay full white.

   Written from least to most specific in source order: every cell 10%, the
   outer ring over it at 30%, the centre cleared last. :nth-child counts the
   tick SVG too (it is the 26th child), which is why each selector is
   limited to .cs_ruler_grid_cell. */
.cs_ruler_grid > .cs_ruler_grid_cell {
  background: rgba(255, 255, 255, 0.1);
}
.cs_ruler_grid > .cs_ruler_grid_cell:nth-child(-n + 5),
.cs_ruler_grid > .cs_ruler_grid_cell:nth-child(n + 21),
.cs_ruler_grid > .cs_ruler_grid_cell:nth-child(5n + 1),
.cs_ruler_grid > .cs_ruler_grid_cell:nth-child(5n) {
  background: rgba(255, 255, 255, 0.3);
}
.cs_ruler_grid > .cs_ruler_grid_cell_centre {
  background: transparent;
}


/* ── the six brackets: three down, three up ──
   Anchored on the grid's bottom and top edges, centred on the map centre,
   each reaching further out than the last. Three borders only - two side
   ticks and the dimension rule between them, open on the side the grid is
   on: the standard dimension bracket, mirrored.

   The DOWN set reads in the unit picked in the ruler's own unit bar. The UP
   set reads the same three spans in the other measuring system - metric
   under an imperial selection, imperial under a metric one (see
   RULER_COUNTERPART_UNIT in script.js). The same block of map therefore
   carries both systems at once, so a span read as "18.3 m" below is read as
   "60.0 ft" above without touching the unit picker. */
.cs_ruler_spans {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 3;
}
.cs_ruler_span {
  position: absolute;
  /* the grid's bottom edge: half the grid, measured from the map centre */
  top: calc(var(--ruler_cell) * 2.5);
  left: 50%;
  transform: translateX(-50%);
  box-sizing: border-box;
  border-left: 1px dashed var(--ruler_stroke);
  border-right: 1px dashed var(--ruler_stroke);
  border-bottom: 1px dashed var(--ruler_stroke);
}

/* the mirrored set: hung off the grid's TOP edge and opening downward, so
   its dimension rule is the top border rather than the bottom one */
.cs_ruler_span_up {
  top: auto;
  bottom: calc(var(--ruler_cell) * 2.5);
  border-bottom: none;
  border-top: 1px dashed var(--ruler_stroke);
}

.cs_ruler_span_1 {
  width: var(--ruler_cell);
  height: 40px;
}
.cs_ruler_span_3 {
  width: calc(var(--ruler_cell) * 3);
  height: 80px;
}
.cs_ruler_span_5 {
  width: calc(var(--ruler_cell) * 5);
  height: 120px;
}

/* ── arrowheads on the ends of every dimension rule ──
   A dashed rule between two ticks says "something spans this"; it does not
   say which direction the reading is taken in, and at the 1-cell width the
   two side ticks are close enough together to read as a small box rather
   than as a measurement. Outward-pointing arrowheads at both ends are the
   drafting convention for exactly that, and they make the three nested
   brackets read as three measurements rather than three boxes.

   Solid, not dashed: the dashes are what distinguishes a dimension line
   from the grid, and an arrowhead is a filled mark in every drawing
   standard that uses one. 4px half-height centres each head on the 1px
   rule it terminates. */
.cs_ruler_span::before,
.cs_ruler_span::after {
  content: "";
  position: absolute;
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  /* the rule is the bottom border, so the head hangs just past the padding
     box to sit centred on it */
  bottom: -4.5px;
}
.cs_ruler_span::before {
  left: 0;
  border-right: 8px solid var(--ruler_stroke);
}
.cs_ruler_span::after {
  right: 0;
  border-left: 8px solid var(--ruler_stroke);
}
/* mirrored set: the rule is the top border */
.cs_ruler_span_up::before,
.cs_ruler_span_up::after {
  bottom: auto;
  top: -4.5px;
}

/* ── the reading sits just outside its own dimension rule ──
   Each reading rests against the OUTER side of the rule it belongs to -
   under the rule for the brackets below the grid, on top of it for the
   brackets above - so no dashed line ever runs through a number. Outside is
   also the side no other bracket reaches: every bracket's side ticks stop
   at its own rule, and the next bracket out is 40px further on, so a
   reading can be as wide as its text needs without crossing anything.

   top/bottom: 100% puts the reading's edge on the inside of the rule's
   border, so the extra 1px clears the rule itself.

   Clear background, no chip, no text-shadow halo: a halo is a blur, and a
   blurred black edge on white 12px type at map scale reads as a thickened,
   softer glyph. */
.cs_ruler_span_value {
  position: absolute;
  left: 50%;
  top: calc(100% + 1px);
  bottom: auto;
  transform: translateX(-50%);
  font: 600 12px/1 "Segoe UI", -apple-system, BlinkMacSystemFont, Arial,
    sans-serif;
  color: var(--ruler_stroke);
  white-space: nowrap;
  padding: 2px 4px;
  background: transparent;
  text-shadow: none;
  z-index: 1;
}
.cs_ruler_span_up .cs_ruler_span_value {
  top: auto;
  bottom: calc(100% + 1px);
  transform: translateX(-50%);
}

/* ── every stroke and every reading this overlay draws is white, solid and
      fully opaque, over the one scrim ──
   The old arms painted themselves with backdrop-filter: invert(), which is
   what you need when there is no controlled ground under the line. There is
   one now - .cs_ruler_scrim, and only that one - so the strokes can simply
   be white: brighter, steadier, and the same colour over every part of the
   map. Nothing here carries a shadow of any kind; the scrim is the contrast,
   and a shadow would only blur the edge the scrim exists to sharpen. */
#cs_measurement_ruler_wrap .cs_ruler_grid,
#cs_measurement_ruler_wrap .cs_ruler_grid_cell,
#cs_measurement_ruler_wrap .cs_ruler_span {
  border-color: var(--ruler_stroke) !important;
  opacity: 1 !important;
}
#cs_measurement_ruler_wrap .cs_ruler_span_value {
  opacity: 1 !important;
}
/* the wrap used to paint --overlay_bg_dark of its own UNDER .cs_ruler_scrim's
   0.28 - two tints stacked, so the map read darker than either was written
   to make it. The scrim is the overlay; the wrap is just the box. */
#cs_measurement_ruler_wrap {
  background: transparent !important;
  /* and it drops the 1px box style.css's grid-line pass gave it: the wrap is
     the full viewport, so that border was a line drawn around the whole
     screen - not a measurement, and the one stroke in this overlay that is
     not part of the ruler */
  border: none !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   16. NO SHADOWS ON ANYTHING DRAWN OVER THE MAP

   Every map overlay in this app had picked up its own way of separating a
   white line from whatever was under it: a doubled drop-shadow halo on the
   compass ring, a four-way text-shadow on the ruler's readings, box-shadow
   outlines elsewhere. Each works, and stacked they fight - a halo is a blur,
   and a blurred dark edge against a 1px white stroke widens the stroke and
   softens both of its sides. At map scale that reads as a second, fuzzier
   line just outside the real one.

   One mechanism instead, for all of them: a scrim under the overlay gives
   the strokes a single known ground, and everything drawn on top of it is
   solid white at full opacity. Contrast comes from the strokes being bright
   over a controlled ground, not from each stroke carrying its own outline.
   ═════════════════════════════════════════════════════════════════════════ */

#cs_measurement_ruler_wrap,
#cs_measurement_ruler_wrap *,
#cs_measurement_ruler_wrap *::before,
#cs_measurement_ruler_wrap *::after,
.cs_compass_overlay_container,
.cs_compass_overlay_container *,
.cs_compass_overlay_container *::before,
.cs_compass_overlay_container *::after,
.crosshair_dom_container,
.crosshair_dom_container *,
.altitude_scale_dom,
.altitude_scale_dom * {
  box-shadow: none !important;
  text-shadow: none !important;
}

/* filter: drop-shadow() is the other halo mechanism in play - it is not a
   box-shadow, so the rule above does not reach it. Named separately rather
   than blanket-cleared with `filter: none` on the whole subtree, because
   that would also clear any non-shadow filter an overlay legitimately uses. */
.cs_compass_overlay_container > .cs_compass_indicator_ring,
.cs_compass_indicator_ring,
.cs_compass_indicator_triangle,
.cs_compass_indicator_n,
.cs_compass_indicator_s {
  filter: none !important;
}

/* the ring and its inscribed triangle: one 1px solid white stroke each, and
   exactly one. The ring had the drop-shadow pair cleared just above; the
   width is restated here as a literal 1px so it cannot follow
   --ui_border_uniform_width to 2 and come out as a doubled line. */
.cs_compass_overlay_container > .cs_compass_indicator_ring,
.cs_compass_indicator_ring {
  border: 1px solid #ffffff !important;
  border-width: 1px !important;
  border-style: solid !important;
  opacity: 1;
}
.cs_compass_indicator_triangle {
  fill: none;
  stroke: #ffffff;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-opacity: 1;
}

/* the north-south line was 2px - a double-width stroke in a chrome whose
   every other line is 1px */
.cs_compass_north_south_line {
  width: 1px;
}

/* ── the cardinals ride the same circle the indicator column ends on ──
   .cs_compass_north_south_line_container sized itself calc(100dvh - 136px)
   tall, from the days the overlay was inset 68px top and bottom. The overlay
   is inset 48px now, so the container came out 40px shorter than the box it
   sits in and its N and S badges landed 20px INSIDE the top and bottom cells
   of the fixed indicator column - overlapping them by more than half a cell
   at north-up, and off the indicator ring at every other bearing.

   At 100% the container is exactly the overlay's height, which is exactly
   .cs_compass_indicator_ring's diameter, so the two badges sit on the ring
   itself: at north-up they land dead on the top and bottom cardinal cells,
   and as the map rotates they track around the same circle the column's
   outer edges touch. */
.cs_compass_north_south_line_container {
  height: 100% !important;
  min-height: 0 !important;
}
.cs_compass_north_south_line {
  height: 100% !important;
  min-height: 0 !important;
}


/* ═════════════════════════════════════════════════════════════════════════
   17. ONE TINT, AT ONE STRENGTH, WITH EVERY SHAPE ON TOP OF IT

   Three overlays were each darkening the map by their own amount, and in two
   places they were stacking: the ruler's wrap painted --overlay_bg_dark and
   .cs_ruler_scrim painted another 0.28 on top of it, and the altitude column
   ran 0.6 behind its ticks with 0.5 boxes at either end of it. Stacked tints
   compound - two 0.3s are a 0.51 - so the map under them went from "dimmed"
   to "gone", which defeats the reason for tinting at all: the tint exists to
   give a white 1px stroke a consistent ground, and a stroke over a basemap
   nobody can read is a stroke measuring nothing.

   One value everywhere instead - 0.3 - applied once per overlay. Roads,
   labels and parcels stay legible through it, and every line, tick and
   reading drawn over it stays solid white at full opacity.

   The second half of this is z-order. The ruler's wrap is fixed at 9999 and
   its scrim fills the viewport, so with the ruler on, the altitude column
   (z-index 9) and the compass overlay (10) were being tinted along with the
   map - they are chrome drawn over the map, not map. Both are lifted clear
   of that scrim here, and stay below the 30000 rails, which still occlude
   everything drawn on the map.
   ═════════════════════════════════════════════════════════════════════════ */

.cs_ruler_scrim {
  background: rgba(0, 0, 0, 0.3);
}
/* the altitude column is the one exception - 0.6, so its small labels
   stay readable over a busy basemap */
.altitude_scale_background,
.altitude_scale_title_box,
.altitude_value_box {
  background: rgba(0, 0, 0, 0.6) !important;
}

/* above .cs_ruler_scrim (inside the ruler wrap's 9999), below the rails.

   .large_compass_overlay is named alongside its own container because it is
   position:fixed with a z-index of its own, which opens a stacking context:
   every z-index inside it, the container's included, is resolved against
   that parent and not against the page. Lifting only the container would
   have moved it within an overlay that still sat at 10. */
.altitude_scale_dom,
.large_compass_overlay,
.cs_compass_overlay_container {
  z-index: 10060 !important;
}
/* and everything either of them actually draws is solid, not tinted */
.altitude_tick_major,
.altitude_tick_minor,
.altitude_tick_label,
.altitude_current_marker,
.altitude_title,
.altitude_unit,
.altitude_current_value,
.altitude_current_unit,
.cs_compass_indicator_ring,
.cs_compass_indicator_triangle_svg,
.cs_compass_indicator_triangle,
.cs_compass_indicator_n,
.cs_compass_indicator_s,
.cs_compass_cross_section_horizontal,
.cs_compass_cross_section_vertical,
.indicator_input {
  opacity: 1 !important;
}


/* ── the unit picker is the head of the ruler ──
   On the grid's own column and exactly as wide as the grid (5 cells,
   240px), so it reads as the ruler's caption: the unit it names is the unit
   the downward readings are in, and the upward ones are the other system
   (see rulerCounterpartUnit()).

   Fixed 96px from the top of the screen - two cells down, one clear cell
   under the 48px top bar - rather than hung off the grid, so it holds the
   same place whatever the viewport height. */
.cs_crosshair_ruler_unit_bar {
  position: fixed;
  top: 96px;
  left: 50%;
  transform: translateX(-50%);
  /* the grid's own width */
  width: calc(var(--ruler_cell) * 5);
  height: 48px;
  /* over the crosshair lines (10050), which run through the screen centre
     and so straight through this control */
  z-index: 10055;
  pointer-events: auto;
}
.cs_crosshair_ruler_unit_bar .cs_measurement_ruler_unit_select,
#cs_measurement_ruler_unit_select {
  width: 100%;
  height: 48px;
  box-sizing: border-box;
  /* opaque, like every reading this overlay prints: the scrim is the only
     translucent layer here, and a semi-transparent control sitting on the
     scrim would be a second tint over the same patch of map */
  background-color: #000000 !important;
  background-image: none !important;
  color: var(--ruler_stroke);
  /* it is no longer docked under the top bar, so it closes its own box -
     section 13's "docked edges" rule had dropped this top border */
  border: 1px solid var(--ruler_stroke) !important;
  border-top: 1px solid var(--ruler_stroke) !important;
  border-radius: 0 !important;
}
.cs_crosshair_ruler_unit_bar .cs_measurement_ruler_select_arrow {
  color: var(--ruler_stroke);
}
