{ "version": 3, "sources": ["../../../node_modules/@rails/actioncable/src/adapters.js", "../../../node_modules/@rails/actioncable/src/logger.js", "../../../node_modules/@rails/actioncable/src/connection_monitor.js", "../../../node_modules/@rails/actioncable/src/internal.js", "../../../node_modules/@rails/actioncable/src/connection.js", "../../../node_modules/@rails/actioncable/src/subscription.js", "../../../node_modules/@rails/actioncable/src/subscription_guarantor.js", "../../../node_modules/@rails/actioncable/src/subscriptions.js", "../../../node_modules/@rails/actioncable/src/consumer.js", "../../../node_modules/@rails/actioncable/src/index.js", "../../../node_modules/apexcharts/dist/core.esm.js", "../../../node_modules/apexcharts/dist/apexcharts.esm.js", "../../../node_modules/numeral/numeral.js", "../../javascript/validate_rut.js", "../../javascript/dashboard/resource_visibility.js", "../../javascript/performance/load_milestones.js", "../../javascript/performance/start_load_milestones.js", "../../../node_modules/@rails/ujs/app/assets/javascripts/rails-ujs.esm.js", "../../../node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/snakeize.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable_stream_source_element.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/fetch_requests.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js", "../../javascript/config/apexcharts.js", "../../../node_modules/@hotwired/stimulus/dist/stimulus.js", "../../../node_modules/stimulus-character-counter/dist/stimulus-character-counter.mjs", "../../../node_modules/stimulus-clipboard/dist/stimulus-clipboard.mjs", "../../../node_modules/stimulus-rails-nested-form/dist/stimulus-rails-nested-form.mjs", "../../javascript/controllers/accounts_association_form_controller.js", "../../javascript/controllers/adjustment_calculator_controller.js", "../../javascript/controllers/admin/producto/aum_chart_controller.js", "../../javascript/controllers/chart_palette.js", "../../javascript/helpers/index.js", "../../javascript/toolui/dom.js", "../../javascript/controllers/admin/producto/donut_center_controller.js", "../../javascript/controllers/admin/producto/features_chart_controller.js", "../../javascript/controllers/admin/producto/funnel_bar_controller.js", "../../javascript/controllers/admin/producto/funnel_chart_controller.js", "../../javascript/controllers/admin/producto/health_chart_controller.js", "../../javascript/controllers/admin/producto/revenue_chart_controller.js", "../../javascript/controllers/admin/producto/users_chart_controller.js", "../../javascript/controllers/admin/ventas/funnel_bar_controller.js", "../../javascript/controllers/advisor_tools/chart_controller.js", "../../javascript/controllers/advisor_tools/debt_form_controller.js", "../../javascript/controllers/advisor_tools/formatted_number_controller.js", "../../javascript/controllers/advisor_tools/life_events_controller.js", "../../javascript/controllers/advisor_tools/live_form_controller.js", "../../javascript/controllers/advisor_tools/presentation_controller.js", "../../javascript/controllers/advisor_tools/range_label_controller.js", "../../javascript/controllers/advisor_tools/type_switch_controller.js", "../../javascript/controllers/agent_onboarding_controller.js", "../../javascript/controllers/ai_plan_journey_controller.js", "../../javascript/chatbot/sse.js", "../../javascript/ai_plan_journey/stream_client.js", "../../javascript/ai_plan_journey/report_sections.js", "../../javascript/chatbot/markdown.js", "../../javascript/controllers/alerts_controller.js", "../../javascript/controllers/alpaca_disclosure_form_controller.js", "../../javascript/controllers/alpaca_status_poller_controller.js", "../../javascript/controllers/analyzing_data_controller.js", "../../javascript/controllers/app_version_controller.js", "../../javascript/controllers/budgets/additional_filters_controller.js", "../../javascript/controllers/budgets/amount_form_controller.js", "../../javascript/controllers/budgets/categories_onboarding_controller.js", "../../javascript/controllers/budgets/category_panel_controller.js", "../../../node_modules/tom-select/src/contrib/microevent.ts", "../../../node_modules/tom-select/src/contrib/microplugin.ts", "../../../node_modules/@orchidjs/unicode-variants/lib/regex.ts", "../../../node_modules/@orchidjs/unicode-variants/lib/strings.ts", "../../../node_modules/@orchidjs/unicode-variants/lib/index.ts", "../../../node_modules/@orchidjs/sifter/lib/utils.ts", "../../../node_modules/@orchidjs/sifter/lib/sifter.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/contrib/highlight.ts", "../../../node_modules/tom-select/src/constants.ts", "../../../node_modules/tom-select/src/defaults.ts", "../../../node_modules/tom-select/src/getSettings.ts", "../../../node_modules/tom-select/src/tom-select.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/plugins/change_listener/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/checkbox_options/plugin.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/clear_button/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/drag_drop/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/dropdown_header/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/caret_position/plugin.ts", "../../../node_modules/tom-select/src/constants.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/dropdown_input/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/plugins/input_autogrow/plugin.ts", "../../../node_modules/tom-select/src/plugins/no_backspace_delete/plugin.ts", "../../../node_modules/tom-select/src/plugins/no_active_items/plugin.ts", "../../../node_modules/tom-select/src/constants.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/optgroup_columns/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/remove_button/plugin.ts", "../../../node_modules/tom-select/src/plugins/restore_on_backspace/plugin.ts", "../../../node_modules/tom-select/src/utils.ts", "../../../node_modules/tom-select/src/vanilla.ts", "../../../node_modules/tom-select/src/plugins/virtual_scroll/plugin.ts", "../../../node_modules/tom-select/src/tom-select.complete.ts", "../../javascript/controllers/tom_select_vnext.js", "../../javascript/controllers/budgets/category_rule_form_controller.js", "../../javascript/controllers/budgets/category_tabs_controller.js", "../../javascript/controllers/budgets/category_toggle_controller.js", "../../javascript/controllers/budgets/date_navigation_controller.js", "../../javascript/controllers/budgets/empty_period_controller.js", "../../javascript/controllers/budgets/floid_widget_controller.js", "../../javascript/controllers/budgets/inline_categories_controller.js", "../../javascript/controllers/budgets/inline_category_controller.js", "../../javascript/controllers/budgets/modal_loader_controller.js", "../../javascript/controllers/budgets/overview_controller.js", "../../javascript/controllers/budgets/period_navigation_controller.js", "../../javascript/controllers/budgets/progress_bar_controller.js", "../../javascript/controllers/budgets/spending_chart_controller.js", "../../javascript/format_numbers.js", "../../javascript/controllers/budgets/sync_status_controller.js", "../../javascript/controllers/budgets/template_form_controller.js", "../../javascript/controllers/tom_select_floating.js", "../../javascript/controllers/budgets/transaction_form_controller.js", "../../javascript/controllers/budgets/transactions_controller.js", "../../javascript/controllers/calendly_controller.js", "../../javascript/load_sdk.js", "../../javascript/controllers/carousel_controller.js", "../../javascript/controllers/cash_conversion_form_controller.js", "../../javascript/stocks_usd_amount.js", "../../javascript/controllers/cash_deposit_form_controller.js", "../../javascript/controllers/cash_movement_controller.js", "../../javascript/controllers/chart_toolbar_slider_controller.js", "../../javascript/controllers/chatbot_attachments_controller.js", "../../javascript/chatbot/attachments.js", "../../javascript/chatbot/attachment_upload.js", "../../javascript/controllers/chatbot_composer_controller.js", "../../javascript/controllers/chatbot_controller.js", "../../javascript/chatbot/rejected_message.js", "../../javascript/chatbot/vega_loader.js", "../../javascript/chatbot/stream_state.js", "../../javascript/chatbot/activity.js", "../../javascript/toolui/registry.js", "../../javascript/chatbot/history_delete_dialog.js", "../../javascript/chatbot/history.js", "../../javascript/chatbot/card_context.js", "../../javascript/charts/load_apexcharts.js", "../../../node_modules/apexcharts/dist/locales/es.json", "../../javascript/toolui/states.js", "../../javascript/toolui/base.js", "../../javascript/toolui/normalize.js", "../../javascript/toolui/components/montecarlo.js", "../../javascript/toolui/components/risk-metrics.js", "../../javascript/toolui/components/twelvedata.js", "../../javascript/toolui/components/write-intent.js", "../../javascript/toolui/html-card.js", "../../javascript/toolui/components/financial-health-preview.js", "../../javascript/toolui/components/budget-form.js", "../../javascript/toolui/components/wealth-summary.js", "../../javascript/toolui/index.js", "../../javascript/chatbot/provenance.js", "../../javascript/controllers/chatbot_follow_ups_controller.js", "../../javascript/controllers/chatbot_onboarding_controls_controller.js", "../../javascript/controllers/chatbot_question_controller.js", "../../javascript/controllers/chatbot_quick_start_controller.js", "../../javascript/controllers/chatbot_recovery_controller.js", "../../javascript/controllers/chatbot_toggle_controller.js", "../../javascript/controllers/chatbot_viewport_controller.js", "../../javascript/controllers/chatbot_voice_controller.js", "../../javascript/chatbot/voice_session.js", "../../javascript/controllers/clickable_items_controller.js", "../../javascript/controllers/client_subscription_controller.js", "../../javascript/controllers/clipboard_controller.js", "../../javascript/controllers/collapsible_panel_controller.js", "../../javascript/controllers/command_palette_controller.js", "../../../node_modules/hotkeys-js/src/utils.ts", "../../../node_modules/hotkeys-js/src/var.ts", "../../../node_modules/hotkeys-js/src/index.ts", "../../javascript/controllers/commission_tier_form_controller.js", "../../javascript/controllers/components/accordion_controller.js", "../../javascript/controllers/components/account_portfolios_controller.js", "../../javascript/controllers/components/address_controller.js", "../../javascript/controllers/components/alert_controller.js", "../../javascript/controllers/components/charts/area_controller.js", "../../javascript/controllers/components/charts/base_controller.js", "../../javascript/controllers/components/charts/bar_controller.js", "../../javascript/controllers/components/charts/datetime_area_controller.js", "../../javascript/controllers/components/charts/donut_controller.js", "../../javascript/controllers/components/charts/gauge_controller.js", "../../javascript/controllers/components/charts/radial_base_controller.js", "../../javascript/controllers/components/charts/pie_controller.js", "../../javascript/controllers/components/charts/progress_controller.js", "../../javascript/controllers/components/client_fetcher_controller.js", "../../../node_modules/@rails/request.js/src/fetch_response.js", "../../../node_modules/@rails/request.js/src/request_interceptor.js", "../../../node_modules/@rails/request.js/src/lib/utils.js", "../../../node_modules/@rails/request.js/src/fetch_request.js", "../../../node_modules/@rails/request.js/src/verbs.js", "../../javascript/controllers/components/confirm_controller.js", "../../javascript/controllers/components/counter_controller.js", "../../javascript/controllers/components/dependent_selects_controller.js", "../../javascript/controllers/components/disclosure_controller.js", "../../javascript/controllers/components/dismissible_details_controller.js", "../../javascript/controllers/components/dropdown_controller.js", "../../javascript/controllers/components/dropzone_controller.js", "../../../node_modules/dropzone/package.json", "../../../node_modules/dropzone/src/extend.ts", "../../../node_modules/dropzone/src/emitter.ts", "../../../node_modules/dropzone/src/options.ts", "../../../node_modules/dropzone/src/dropzone.ts", "../../../node_modules/@rails/activestorage/app/assets/javascripts/activestorage.esm.js", "../../javascript/controllers/components/file_drop_controller.js", "../../javascript/controllers/components/file_image_uploader_controller.js", "../../javascript/controllers/components/image_fallback_controller.js", "../../javascript/controllers/components/modal_trigger_controller.js", "../../javascript/controllers/components/nav_tab_controller.js", "../../javascript/controllers/components/number_selection_controller.js", "../../javascript/controllers/components/paginated_list_controller.js", "../../javascript/controllers/components/phones_controller.js", "../../javascript/controllers/components/plan_rows_controller.js", "../../javascript/controllers/components/portfolio_composition_controller.js", "../../javascript/controllers/components/rut_controller.js", "../../../node_modules/imask/esm/core/utils.js", "../../../node_modules/imask/esm/core/action-details.js", "../../../node_modules/imask/esm/core/holder.js", "../../../node_modules/imask/esm/masked/factory.js", "../../../node_modules/imask/esm/controls/mask-element.js", "../../../node_modules/imask/esm/controls/html-mask-element.js", "../../../node_modules/imask/esm/controls/html-input-mask-element.js", "../../../node_modules/imask/esm/controls/html-contenteditable-mask-element.js", "../../../node_modules/imask/esm/controls/input-history.js", "../../../node_modules/imask/esm/controls/input.js", "../../../node_modules/imask/esm/core/change-details.js", "../../../node_modules/imask/esm/core/continuous-tail-details.js", "../../../node_modules/imask/esm/masked/base.js", "../../../node_modules/imask/esm/masked/pattern/chunk-tail-details.js", "../../../node_modules/imask/esm/masked/pattern/cursor.js", "../../../node_modules/imask/esm/masked/pattern/fixed-definition.js", "../../../node_modules/imask/esm/masked/pattern/input-definition.js", "../../../node_modules/imask/esm/masked/regexp.js", "../../../node_modules/imask/esm/masked/pattern.js", "../../../node_modules/imask/esm/masked/range.js", "../../../node_modules/imask/esm/masked/date.js", "../../../node_modules/imask/esm/masked/dynamic.js", "../../../node_modules/imask/esm/masked/enum.js", "../../../node_modules/imask/esm/masked/function.js", "../../../node_modules/imask/esm/masked/number.js", "../../../node_modules/imask/esm/masked/pipe.js", "../../../node_modules/imask/esm/masked/repeat.js", "../../../node_modules/imask/esm/index.js", "../../javascript/controllers/components/select_group_controller.js", "../../javascript/lib/remote_form_request.js", "../../javascript/controllers/components/stepper_controller.js", "../../javascript/controllers/components/sum_validator_controller.js", "../../javascript/controllers/components/yes_no_controller.js", "../../javascript/controllers/composition_popover_controller.js", "../../javascript/controllers/confirm_submit_controller.js", "../../javascript/controllers/contracts_controller.js", "../../javascript/controllers/copilot_context_controller.js", "../../javascript/controllers/copilot_popup_controller.js", "../../javascript/controllers/copilot_start_controller.js", "../../javascript/controllers/coverage_select_all_controller.js", "../../javascript/controllers/coverage_wizard_step1_controller.js", "../../javascript/controllers/csv_download_controller.js", "../../javascript/controllers/custody_transfer_parser_controller.js", "../../javascript/controllers/dashboard/composition_controller.js", "../../javascript/dashboard/composition_layout.js", "../../javascript/dashboard/gridstack_loader.js", "../../javascript/controllers/dashboard/copilot_link_controller.js", "../../javascript/controllers/dashboard/financial_situation_controller.js", "../../javascript/charts/draw_chart.js", "../../javascript/controllers/dashboard/incomes_and_expenses_controller.js", "../../javascript/controllers/dashboard/onboarding_steps_controller.js", "../../javascript/controllers/dashboard/patrimony_controller.js", "../../javascript/controllers/dashboard_controller.js", "../../javascript/controllers/debt_reports/quiz_controller.js", "../../javascript/controllers/disclosure_controller.js", "../../javascript/controllers/education_filter_controller.js", "../../javascript/controllers/education_image_controller.js", "../../javascript/controllers/education_navigation_controller.js", "../../javascript/controllers/external_investments_controller.js", "../../javascript/controllers/feedback_tab_controller.js", "../../javascript/controllers/filter_controller.js", "../../javascript/controllers/financial_health_embed_controller.js", "../../javascript/controllers/financial_profile/amounts_controller.js", "../../javascript/controllers/financial_profile/apv_chart_controller.js", "../../../config/design_tokens.json", "../../javascript/controllers/financial_profile/apv_simulator_controller.js", "../../javascript/controllers/financial_profile/debts_controller.js", "../../javascript/controllers/financial_profile/editable_resource_errors_controller.js", "../../javascript/controllers/financial_profile/funds_controller.js", "../../javascript/controllers/financial_profile/goal_answer_controller.js", "../../javascript/controllers/financial_profile/goal_draft_controller.js", "../../javascript/controllers/financial_profile/goal_form_panel_controller.js", "../../javascript/controllers/financial_profile/goal_validation_controller.js", "../../javascript/controllers/form/inline_validation_controller.js", "../../javascript/controllers/financial_profile/items_controller.js", "../../javascript/input_utilities.js", "../../javascript/controllers/financial_profile/main_home_controller.js", "../../javascript/controllers/financial_profile/marital_status_controller.js", "../../javascript/controllers/financial_profile/monthly_payments_controller.js", "../../javascript/controllers/financial_profile/property_editor_controller.js", "../../javascript/controllers/financial_profile/rental_fill_controller.js", "../../javascript/controllers/financial_profile/retirement_errors_controller.js", "../../javascript/controllers/financial_profile/retirements_insurance_controller.js", "../../javascript/controllers/financial_profile/row_toggle_controller.js", "../../javascript/controllers/financial_profile/saving_and_investment_controller.js", "../../../node_modules/camelcase/index.js", "../../javascript/controllers/financial_profile/saving_and_investment_details_controller.js", "../../javascript/controllers/financial_profile/saving_instrument_errors_controller.js", "../../javascript/controllers/financial_reports/comparison_bar_controller.js", "../../javascript/controllers/financial_reports/donut_chart_controller.js", "../../javascript/controllers/financial_reports/gauge_chart_controller.js", "../../javascript/controllers/fit_text_controller.js", "../../javascript/controllers/form/base_controller.js", "../../javascript/controllers/form/company_rut_confirm_controller.js", "../../javascript/controllers/form/dynamic_fields_controller.js", "../../javascript/controllers/form/input_masks_controller.js", "../../javascript/controllers/form/numericality_controller.js", "../../javascript/controllers/form/person_name_controller.js", "../../javascript/controllers/form/required_inputs_controller.js", "../../javascript/controllers/form/row_with_select_controller.js", "../../javascript/controllers/form/wizard_controller.js", "../../javascript/controllers/form/wizard_required_inputs_controller.js", "../../javascript/controllers/fund_swap_controller.js", "../../javascript/controllers/graphics/indicator_chart_controller.js", "../../javascript/controllers/graphics/line_chart_controller.js", "../../javascript/controllers/graphics/risk_profile_score_controller.js", "../../javascript/controllers/internal_design_system_states_controller.js", "../../javascript/controllers/investment_proposal_form_controller.js", "../../javascript/controllers/investments/accordion_controller.js", "../../javascript/controllers/investments/account_return_controller.js", "../../javascript/controllers/investments/account_summary_download_controller.js", "../../javascript/controllers/investments/activity_movements_controller.js", "../../../node_modules/@rails/actioncable/app/assets/javascripts/actioncable.esm.js", "../../javascript/controllers/investments/alpaca_grant_form_controller.js", "../../javascript/controllers/investments/amount_adjustment_controller.js", "../../javascript/controllers/investments/anchor_prices_controller.js", "../../javascript/controllers/investments/assignment_search_controller.js", "../../javascript/controllers/investments/assignment_toggle_controller.js", "../../javascript/controllers/investments/assignments_date_controller.js", "../../javascript/controllers/investments/assignments_tabs_controller.js", "../../javascript/controllers/investments/assignments_validate_controller.js", "../../javascript/controllers/investments/batch_change_price_controller.js", "../../javascript/controllers/investments/batch_send_controller.js", "../../javascript/controllers/investments/change_price_controller.js", "../../javascript/controllers/investments/client_movements_controller.js", "../../javascript/controllers/investments/consolidated_controller.js", "../../javascript/controllers/investments/custom_portfolio_form_controller.js", "../../javascript/controllers/investments/deposit_intention_form_controller.js", "../../javascript/controllers/investments/deposit_intention_risk_input_controller.js", "../../javascript/controllers/investments/expire_movement_controller.js", "../../javascript/controllers/investments/external_account_controller.js", "../../javascript/controllers/investments/fields_for_settlement_controller.js", "../../javascript/controllers/investments/fintoc_widget_controller.js", "../../../node_modules/@fintoc/fintoc-js/src/lib/constants.ts", "../../../node_modules/@fintoc/fintoc-js/src/lib/core.ts", "../../javascript/controllers/investments/goal_asset_return_controller.js", "../../javascript/controllers/investments/goal_history_controller.js", "../../javascript/controllers/investments/manual_price_controller.js", "../../javascript/controllers/investments/movement_preview_controller.js", "../../javascript/controllers/investments/movement_selection_controller.js", "../../javascript/controllers/investments/order_splitter_controller.js", "../../javascript/controllers/investments/portfolio_product_form_controller.js", "../../javascript/controllers/investments/proposal_acceptance_controller.js", "../../javascript/controllers/investments/proposal_simulator_controller.js", "../../javascript/controllers/investments/quota_transfer_validation_controller.js", "../../javascript/controllers/investments/quota_transfers_controller.js", "../../javascript/controllers/investments/quota_updater_controller.js", "../../javascript/quota_updater_preview.js", "../../javascript/controllers/investments/quotas_movement_controller.js", "../../javascript/controllers/investments/rebalancing_cancel_modal_controller.js", "../../javascript/controllers/investments/rebalancing_dashboard_detail_controller.js", "../../javascript/controllers/investments/rebalancing_details_controller.js", "../../javascript/controllers/investments/reports_availability_controller.js", "../../javascript/controllers/investments/sale_movement_form_controller.js", "../../javascript/controllers/investments/scheduled_deposit_form_controller.js", "../../javascript/controllers/investments/sent_orders_selection_controller.js", "../../javascript/controllers/investments/simulation_panel_controller.js", "../../javascript/controllers/investments/stock_orders_sender_controller.js", "../../javascript/controllers/investments/summary_balance_controller.js", "../../javascript/controllers/investments/transactions_toggle_controller.js", "../../javascript/controllers/investments/unlock_order_controller.js", "../../javascript/controllers/investments/update_amount_controller.js", "../../javascript/controllers/investments/vector_unblock_controller.js", "../../javascript/controllers/investments/withdrawal_navigation_controller.js", "../../javascript/controllers/investor_survey/bank_accounts_controller.js", "../../javascript/controllers/investor_survey/documentations_confirm_controller.js", "../../javascript/controllers/investor_survey/documentations_controller.js", "../../javascript/controllers/investor_survey/employment_information_controller.js", "../../javascript/controllers/investor_survey/identity_card_controller.js", "../../javascript/controllers/investor_survey/pep_controller.js", "../../javascript/controllers/investor_survey/spouse_controller.js", "../../javascript/controllers/journey_conversation_controller.js", "../../javascript/controllers/last_visualization_controller.js", "../../javascript/controllers/main_controller.js", "../../javascript/controllers/budget_filter_forms.js", "../../javascript/controllers/manual_custody_form_controller.js", "../../javascript/controllers/meeting_minutes_controller.js", "../../javascript/controllers/mercadopago_card_controller.js", "../../javascript/controllers/multiple_select_with_tags_controller.js", "../../javascript/controllers/navbar_collapse_controller.js", "../../javascript/controllers/offer_banner_controller.js", "../../javascript/controllers/onboarding/invest_preferences_controller.js", "../../javascript/controllers/outgoing_destination_controller.js", "../../javascript/controllers/outgoing_lines_controller.js", "../../javascript/controllers/periodic_refresh_controller.js", "../../javascript/controllers/pill_filter_controller.js", "../../javascript/controllers/posthog_capture_controller.js", "../../javascript/controllers/posthog_gclid_controller.js", "../../javascript/controllers/posthog_session_controller.js", "../../javascript/controllers/product_tour_controller.js", "../../javascript/controllers/prop_edit_controller.js", "../../javascript/controllers/properties/new_form_controller.js", "../../javascript/controllers/properties_navigation_controller.js", "../../javascript/controllers/properties_table_controller.js", "../../javascript/controllers/real_estate_carousel_controller.js", "../../javascript/controllers/real_estate_image_controller.js", "../../javascript/controllers/real_estate_media/default_image_controller.js", "../../javascript/controllers/real_estate_media/persisted_file_controller.js", "../../javascript/controllers/real_estate_projection_controller.js", "../../javascript/lib/real_estate/projection_chart.js", "../../javascript/lib/real_estate/equity_debt_chart.js", "../../javascript/controllers/real_estate_prototype_controller.js", "../../javascript/lib/real_estate/prototype.js", "../../javascript/controllers/rebalancing_controller.js", "../../javascript/controllers/registration_form_controller.js", "../../javascript/controllers/role_conditional_fields_controller.js", "../../javascript/controllers/sales_csv_download_controller.js", "../../javascript/controllers/savings/with_goals_form_controller.js", "../../javascript/controllers/scenario_wizard_controller.js", "../../javascript/controllers/section_nav_controller.js", "../../javascript/controllers/send_movements_controller.js", "../../javascript/controllers/show_more_controller.js", "../../javascript/controllers/sidebar_controller.js", "../../javascript/controllers/stepper_collapse_controller.js", "../../javascript/controllers/stepper_controller.js", "../../javascript/controllers/stock_price_chart_controller.js", "../../javascript/controllers/stocks_explorer_controller.js", "../../javascript/controllers/stocks_search_controller.js", "../../javascript/controllers/stocks_usd_dock_controller.js", "../../javascript/controllers/stocks_usd_equity_chart_controller.js", "../../javascript/controllers/stocks_usd_movement_dialog_controller.js", "../../javascript/controllers/stocks_usd_movement_focus_controller.js", "../../javascript/controllers/stocks_usd_order_ticket_controller.js", "../../javascript/controllers/stocks_usd_position_return_controller.js", "../../javascript/controllers/stocks_usd_step_focus_controller.js", "../../javascript/controllers/stocks_usd_transfer_form_controller.js", "../../javascript/controllers/subscription_controller.js", "../../javascript/controllers/subscription_plan_benefits_controller.js", "../../javascript/controllers/subscriptions/history_controller.js", "../../javascript/controllers/tom_select_controller.js", "../../javascript/controllers/tools/patrimony_chart_controller.js", "../../javascript/controllers/tools/projection_form_controller.js", "../../javascript/controllers/tw_tooltip_controller.js", "../../javascript/controllers/user_profile/bank_account_form_controller.js", "../../javascript/controllers/user_profile/form_controller.js", "../../javascript/controllers/user_profile/navigation_preferences_controller.js", "../../javascript/controllers/user_profile/recovery_codes_controller.js", "../../javascript/controllers/user_profile/toggle_controller.js", "../../javascript/controllers/user_profile_navigation_controller.js", "../../javascript/controllers/user_profiling/debts_controller.js", "../../javascript/controllers/user_profiling/debts_kinds_controller.js", "../../javascript/controllers/user_profiling/financial_options_controller.js", "../../javascript/controllers/user_profiling/new_form_controller.js", "../../javascript/controllers/user_profiling/properties_selector_controller.js", "../../javascript/controllers/utilities/checkbox_list_controller.js", "../../javascript/controllers/utilities/entry_focus_controller.js", "../../javascript/controllers/utilities/modal_controller.js", "../../javascript/controllers/utilities/tabs_controller.js", "../../javascript/controllers/vector_search_controller.js", "../../javascript/controllers/view_toggle_controller.js", "rails:/app/app/javascript/controllers/**/*_controller.js", "../../javascript/controllers/index.js", "../../javascript/application.js"], "sourcesContent": ["export default {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined,\n}\n", "import adapters from \"./adapters\"\n\n// The logger is disabled by default. You can enable it with:\n//\n// ActionCable.logger.enabled = true\n//\n// Example:\n//\n// import * as ActionCable from '@rails/actioncable'\n//\n// ActionCable.logger.enabled = true\n// ActionCable.logger.log('Connection Established.')\n//\n\nexport default {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now())\n adapters.logger.log(\"[ActionCable]\", ...messages)\n }\n },\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting\n// revival reconnections if things go astray. Internal class, not intended for direct user manipulation.\n\nconst now = () => new Date().getTime()\n\nconst secondsSince = time => (now() - time) / 1000\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this)\n this.connection = connection\n this.reconnectAttempts = 0\n }\n\n start() {\n if (!this.isRunning()) {\n this.startedAt = now()\n delete this.stoppedAt\n this.startPolling()\n addEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`)\n }\n }\n\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now()\n this.stopPolling()\n removeEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(\"ConnectionMonitor stopped\")\n }\n }\n\n isRunning() {\n return this.startedAt && !this.stoppedAt\n }\n\n recordMessage() {\n this.pingedAt = now()\n }\n\n recordConnect() {\n this.reconnectAttempts = 0\n delete this.disconnectedAt\n logger.log(\"ConnectionMonitor recorded connect\")\n }\n\n recordDisconnect() {\n this.disconnectedAt = now()\n logger.log(\"ConnectionMonitor recorded disconnect\")\n }\n\n // Private\n\n startPolling() {\n this.stopPolling()\n this.poll()\n }\n\n stopPolling() {\n clearTimeout(this.pollTimeout)\n }\n\n poll() {\n this.pollTimeout = setTimeout(() => {\n this.reconnectIfStale()\n this.poll()\n }\n , this.getPollInterval())\n }\n\n getPollInterval() {\n const { staleThreshold, reconnectionBackoffRate } = this.constructor\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10))\n const jitterMax = this.reconnectAttempts === 0 ? 1.0 : reconnectionBackoffRate\n const jitter = jitterMax * Math.random()\n return staleThreshold * 1000 * backoff * (1 + jitter)\n }\n\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`)\n this.reconnectAttempts++\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`)\n } else {\n logger.log(\"ConnectionMonitor reopening\")\n this.connection.reopen()\n }\n }\n }\n\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt\n }\n\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold\n }\n\n disconnectedRecently() {\n return this.disconnectedAt && (secondsSince(this.disconnectedAt) < this.constructor.staleThreshold)\n }\n\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout(() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`)\n this.connection.reopen()\n }\n }\n , 200)\n }\n }\n\n}\n\nConnectionMonitor.staleThreshold = 6 // Server::Connections::BEAT_INTERVAL * 2 (missed two pings)\nConnectionMonitor.reconnectionBackoffRate = 0.15\n\nexport default ConnectionMonitor\n", "export default {\n \"message_types\": {\n \"welcome\": \"welcome\",\n \"disconnect\": \"disconnect\",\n \"ping\": \"ping\",\n \"confirmation\": \"confirm_subscription\",\n \"rejection\": \"reject_subscription\"\n },\n \"disconnect_reasons\": {\n \"unauthorized\": \"unauthorized\",\n \"invalid_request\": \"invalid_request\",\n \"server_restart\": \"server_restart\",\n \"remote\": \"remote\"\n },\n \"default_mount_path\": \"/cable\",\n \"protocols\": [\n \"actioncable-v1-json\",\n \"actioncable-unsupported\"\n ]\n}\n", "import adapters from \"./adapters\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport INTERNAL from \"./internal\"\nimport logger from \"./logger\"\n\n// Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.\n\nconst {message_types, protocols} = INTERNAL\nconst supportedProtocols = protocols.slice(0, protocols.length - 1)\n\nconst indexOf = [].indexOf\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this)\n this.consumer = consumer\n this.subscriptions = this.consumer.subscriptions\n this.monitor = new ConnectionMonitor(this)\n this.disconnected = true\n }\n\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data))\n return true\n } else {\n return false\n }\n }\n\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`)\n return false\n } else {\n const socketProtocols = [...protocols, ...this.consumer.subprotocols || []]\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`)\n if (this.webSocket) { this.uninstallEventHandlers() }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols)\n this.installEventHandlers()\n this.monitor.start()\n return true\n }\n }\n\n close({allowReconnect} = {allowReconnect: true}) {\n if (!allowReconnect) { this.monitor.stop() }\n // Avoid closing websockets in a \"connecting\" state due to Safari 15.1+ bug. See: https://github.com/rails/rails/issues/43835#issuecomment-1002288478\n if (this.isOpen()) {\n return this.webSocket.close()\n }\n }\n\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`)\n if (this.isActive()) {\n try {\n return this.close()\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error)\n }\n finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`)\n setTimeout(this.open, this.constructor.reopenDelay)\n }\n } else {\n return this.open()\n }\n }\n\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol\n }\n }\n\n isOpen() {\n return this.isState(\"open\")\n }\n\n isActive() {\n return this.isState(\"open\", \"connecting\")\n }\n\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0\n }\n\n // Private\n\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0\n }\n\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0\n }\n\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase()\n }\n }\n }\n return null\n }\n\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this)\n this.webSocket[`on${eventName}`] = handler\n }\n }\n\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {}\n }\n }\n\n}\n\nConnection.reopenDelay = 500\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) { return }\n const {identifier, message, reason, reconnect, type} = JSON.parse(event.data)\n this.monitor.recordMessage()\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true\n }\n this.monitor.recordConnect()\n return this.subscriptions.reload()\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`)\n return this.close({allowReconnect: reconnect})\n case message_types.ping:\n return null\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier)\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: true})\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: false})\n }\n case message_types.rejection:\n return this.subscriptions.reject(identifier)\n default:\n return this.subscriptions.notify(identifier, \"received\", message)\n }\n },\n\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`)\n this.disconnected = false\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\")\n return this.close({allowReconnect: false})\n }\n },\n\n close(event) {\n logger.log(\"WebSocket onclose event\")\n if (this.disconnected) { return }\n this.disconnected = true\n this.monitor.recordDisconnect()\n return this.subscriptions.notifyAll(\"disconnected\", {willAttemptReconnect: this.monitor.isRunning()})\n },\n\n error() {\n logger.log(\"WebSocket onerror event\")\n }\n}\n\nexport default Connection\n", "// A new subscription is created through the ActionCable.Subscriptions instance available on the consumer.\n// It provides a number of callbacks and a method for calling remote procedure calls on the corresponding\n// Channel instance on the server side.\n//\n// An example demonstrates the basic functionality:\n//\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\", {\n// connected() {\n// // Called once the subscription has been successfully completed\n// },\n//\n// disconnected({ willAttemptReconnect: boolean }) {\n// // Called when the client has disconnected with the server.\n// // The object will have an `willAttemptReconnect` property which\n// // says whether the client has the intention of attempting\n// // to reconnect.\n// },\n//\n// appear() {\n// this.perform('appear', {appearing_on: this.appearingOn()})\n// },\n//\n// away() {\n// this.perform('away')\n// },\n//\n// appearingOn() {\n// $('main').data('appearing-on')\n// }\n// })\n//\n// The methods #appear and #away forward their intent to the remote AppearanceChannel instance on the server\n// by calling the `perform` method with the first parameter being the action (which maps to AppearanceChannel#appear/away).\n// The second parameter is a hash that'll get JSON encoded and made available on the server in the data parameter.\n//\n// This is how the server component would look:\n//\n// class AppearanceChannel < ApplicationActionCable::Channel\n// def subscribed\n// current_user.appear\n// end\n//\n// def unsubscribed\n// current_user.disappear\n// end\n//\n// def appear(data)\n// current_user.appear on: data['appearing_on']\n// end\n//\n// def away\n// current_user.away\n// end\n// end\n//\n// The \"AppearanceChannel\" name is automatically mapped between the client-side subscription creation and the server-side Ruby class name.\n// The AppearanceChannel#appear/away public methods are exposed automatically to client-side invocation through the perform method.\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key]\n object[key] = value\n }\n }\n return object\n}\n\nexport default class Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer\n this.identifier = JSON.stringify(params)\n extend(this, mixin)\n }\n\n // Perform a channel action with the optional data passed as an attribute\n perform(action, data = {}) {\n data.action = action\n return this.send(data)\n }\n\n send(data) {\n return this.consumer.send({command: \"message\", identifier: this.identifier, data: JSON.stringify(data)})\n }\n\n unsubscribe() {\n return this.consumer.subscriptions.remove(this)\n }\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring channel subscribe command is confirmed, retrying until confirmation is received.\n// Internal class, not intended for direct user manipulation.\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions\n this.pendingSubscriptions = []\n }\n\n guarantee(subscription) {\n if(this.pendingSubscriptions.indexOf(subscription) == -1){ \n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)\n this.pendingSubscriptions.push(subscription) \n }\n else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`)\n }\n this.startGuaranteeing()\n }\n\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`)\n this.pendingSubscriptions = (this.pendingSubscriptions.filter((s) => s !== subscription))\n }\n\n startGuaranteeing() {\n this.stopGuaranteeing()\n this.retrySubscribing()\n }\n \n stopGuaranteeing() {\n clearTimeout(this.retryTimeout)\n }\n\n retrySubscribing() {\n this.retryTimeout = setTimeout(() => {\n if (this.subscriptions && typeof(this.subscriptions.subscribe) === \"function\") {\n this.pendingSubscriptions.map((subscription) => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`)\n this.subscriptions.subscribe(subscription)\n })\n }\n }\n , 500)\n }\n}\n\nexport default SubscriptionGuarantor", "import logger from \"./logger\"\nimport Subscription from \"./subscription\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\n\n// Collection class for creating (and internally managing) channel subscriptions.\n// The only method intended to be triggered by the user is ActionCable.Subscriptions#create,\n// and it should be called through the consumer like so:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n\nexport default class Subscriptions {\n constructor(consumer) {\n this.consumer = consumer\n this.guarantor = new SubscriptionGuarantor(this)\n this.subscriptions = []\n }\n\n create(channelName, mixin) {\n const channel = channelName\n const params = typeof channel === \"object\" ? channel : {channel}\n const subscription = new Subscription(this.consumer, params, mixin)\n return this.add(subscription)\n }\n\n // Private\n\n add(subscription) {\n this.subscriptions.push(subscription)\n this.consumer.ensureActiveConnection()\n this.notify(subscription, \"initialized\")\n this.subscribe(subscription)\n return subscription\n }\n\n remove(subscription) {\n this.forget(subscription)\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\")\n }\n return subscription\n }\n\n reject(identifier) {\n return this.findAll(identifier).map((subscription) => {\n this.forget(subscription)\n this.notify(subscription, \"rejected\")\n return subscription\n })\n }\n\n forget(subscription) {\n this.guarantor.forget(subscription)\n this.subscriptions = (this.subscriptions.filter((s) => s !== subscription))\n return subscription\n }\n\n findAll(identifier) {\n return this.subscriptions.filter((s) => s.identifier === identifier)\n }\n\n reload() {\n return this.subscriptions.map((subscription) =>\n this.subscribe(subscription))\n }\n\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription) =>\n this.notify(subscription, callbackName, ...args))\n }\n\n notify(subscription, callbackName, ...args) {\n let subscriptions\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription)\n } else {\n subscriptions = [subscription]\n }\n\n return subscriptions.map((subscription) =>\n (typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined))\n }\n\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription)\n }\n }\n\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`)\n this.findAll(identifier).map((subscription) =>\n this.guarantor.forget(subscription))\n }\n\n sendCommand(subscription, command) {\n const {identifier} = subscription\n return this.consumer.send({command, identifier})\n }\n}\n", "import Connection from \"./connection\"\nimport Subscriptions from \"./subscriptions\"\n\n// The ActionCable.Consumer establishes the connection to a server-side Ruby Connection object. Once established,\n// the ActionCable.ConnectionMonitor will ensure that its properly maintained through heartbeats and checking for stale updates.\n// The Consumer instance is also the gateway to establishing subscriptions to desired channels through the #createSubscription\n// method.\n//\n// The following example shows how this can be set up:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n//\n// When a consumer is created, it automatically connects with the server.\n//\n// To disconnect from the server, call\n//\n// App.cable.disconnect()\n//\n// and to restart the connection:\n//\n// App.cable.connect()\n//\n// Any channel subscriptions which existed prior to disconnecting will\n// automatically resubscribe.\n\nexport default class Consumer {\n constructor(url) {\n this._url = url\n this.subscriptions = new Subscriptions(this)\n this.connection = new Connection(this)\n this.subprotocols = []\n }\n\n get url() {\n return createWebSocketURL(this._url)\n }\n\n send(data) {\n return this.connection.send(data)\n }\n\n connect() {\n return this.connection.open()\n }\n\n disconnect() {\n return this.connection.close({allowReconnect: false})\n }\n\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open()\n }\n }\n\n addSubProtocol(subprotocol) {\n this.subprotocols = [...this.subprotocols, subprotocol]\n }\n}\n\nexport function createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url()\n }\n\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\")\n a.href = url\n // Fix populating Location properties in IE. Otherwise, protocol will be blank.\n a.href = a.href // eslint-disable-line\n a.protocol = a.protocol.replace(\"http\", \"ws\")\n return a.href\n } else {\n return url\n }\n}\n", "import adapters from \"./adapters\"\nimport Connection from \"./connection\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport Consumer, { createWebSocketURL } from \"./consumer\"\nimport INTERNAL from \"./internal\"\nimport logger from \"./logger\"\nimport Subscription from \"./subscription\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\nimport Subscriptions from \"./subscriptions\"\n\nexport {\n Connection,\n ConnectionMonitor,\n Consumer,\n INTERNAL,\n Subscription,\n Subscriptions,\n SubscriptionGuarantor,\n adapters,\n createWebSocketURL,\n logger,\n}\n\nexport function createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url)\n}\n\nexport function getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`)\n if (element) {\n return element.getAttribute(\"content\")\n }\n}\n", "var __defProp = Object.defineProperty;\nvar __defProps = Object.defineProperties;\nvar __getOwnPropDescs = Object.getOwnPropertyDescriptors;\nvar __getOwnPropSymbols = Object.getOwnPropertySymbols;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __propIsEnum = Object.prototype.propertyIsEnumerable;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __spreadValues = (a2, b) => {\n for (var prop in b || (b = {}))\n if (__hasOwnProp.call(b, prop))\n __defNormalProp(a2, prop, b[prop]);\n if (__getOwnPropSymbols)\n for (var prop of __getOwnPropSymbols(b)) {\n if (__propIsEnum.call(b, prop))\n __defNormalProp(a2, prop, b[prop]);\n }\n return a2;\n};\nvar __spreadProps = (a2, b) => __defProps(a2, __getOwnPropDescs(b));\nvar __objRest = (source, exclude) => {\n var target = {};\n for (var prop in source)\n if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)\n target[prop] = source[prop];\n if (source != null && __getOwnPropSymbols)\n for (var prop of __getOwnPropSymbols(source)) {\n if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))\n target[prop] = source[prop];\n }\n return target;\n};\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\nvar __async = (__this, __arguments, generator) => {\n return new Promise((resolve, reject) => {\n var fulfilled = (value) => {\n try {\n step(generator.next(value));\n } catch (e2) {\n reject(e2);\n }\n };\n var rejected = (value) => {\n try {\n step(generator.throw(value));\n } catch (e2) {\n reject(e2);\n }\n };\n var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);\n step((generator = generator.apply(__this, __arguments)).next());\n });\n};\n/*!\n * ApexCharts v7.9.1\n * (c) 2018-2026 ApexCharts\n */\nclass Environment {\n /**\n * Check if running in server-side rendering environment (Node.js)\n * @returns {boolean} True if in SSR/Node.js, false if in browser\n */\n static isSSR() {\n return typeof window === \"undefined\" || typeof document === \"undefined\";\n }\n /**\n * Check if running in browser environment\n * @returns {boolean} True if in browser, false if in SSR/Node.js\n */\n static isBrowser() {\n return !this.isSSR();\n }\n /**\n * Check if a specific browser API is available\n * @param {string} api - Name of the API to check (e.g., 'ResizeObserver')\n * @returns {boolean} True if API is available\n */\n static hasAPI(api) {\n if (this.isSSR()) return false;\n return typeof /** @type {any} */\n window[api] !== \"undefined\";\n }\n /**\n * Returns the global Apex config object regardless of environment.\n * In browser: window.Apex; in SSR/Node.js: global.Apex; fallback: {}.\n * @returns {any}\n */\n static getApex() {\n if (typeof window !== \"undefined\" && window.Apex) return window.Apex;\n if (typeof global !== \"undefined\" && global.Apex) return global.Apex;\n return {};\n }\n}\nconst CHAR_WIDTH_EM = 0.55;\nconst ASCENT_EM = 0.917;\nconst DESCENT_EM = 0.25;\nconst LINE_HEIGHT_EM = 1.1;\nconst DEFAULT_FONT_SIZE = 11;\nclass SSRElement {\n /**\n * @param {string} nodeName\n * @param {any} namespaceURI\n */\n constructor(nodeName, namespaceURI = null) {\n this.nodeName = nodeName;\n this.namespaceURI = namespaceURI;\n this.attributes = /* @__PURE__ */ new Map();\n this.children = [];\n this.textContent = \"\";\n this.style = {};\n this.classList = new SSRClassList();\n this.parentNode = /** @type {SSRElement | null} */\n null;\n this._ssrWidth = void 0;\n this._ssrHeight = void 0;\n this._ssrMode = void 0;\n }\n /**\n * @param {string} name\n * @param {any} value\n */\n setAttribute(name2, value) {\n this.attributes.set(name2, value);\n }\n /**\n * @param {string} name\n */\n getAttribute(name2) {\n return this.attributes.get(name2);\n }\n /**\n * @param {string} name\n */\n removeAttribute(name2) {\n this.attributes.delete(name2);\n }\n /**\n * @param {string} name\n */\n hasAttribute(name2) {\n return this.attributes.has(name2);\n }\n /**\n * @param {any} child\n */\n appendChild(child) {\n if (child && child !== this) {\n if (child.parentNode && child.parentNode !== this) {\n child.parentNode.removeChild(child);\n } else if (child.parentNode === this) {\n const index = this.children.indexOf(child);\n if (index !== -1) this.children.splice(index, 1);\n }\n child.parentNode = this;\n this.children.push(child);\n }\n return child;\n }\n /**\n * @param {any} child\n */\n removeChild(child) {\n const index = this.children.indexOf(child);\n if (index !== -1) {\n this.children.splice(index, 1);\n child.parentNode = null;\n }\n return child;\n }\n /**\n * @param {any} newNode\n * @param {any} referenceNode\n */\n insertBefore(newNode, referenceNode) {\n if (!referenceNode) {\n return this.appendChild(newNode);\n }\n if (newNode.parentNode && newNode.parentNode !== this) {\n newNode.parentNode.removeChild(newNode);\n } else if (newNode.parentNode === this) {\n const existingIndex = this.children.indexOf(newNode);\n if (existingIndex !== -1) this.children.splice(existingIndex, 1);\n }\n const index = this.children.indexOf(referenceNode);\n if (index !== -1) {\n newNode.parentNode = this;\n this.children.splice(index, 0, newNode);\n }\n return newNode;\n }\n cloneNode(deep = false) {\n const clone = new SSRElement(this.nodeName, this.namespaceURI);\n clone.textContent = this.textContent;\n this.attributes.forEach((value, key) => {\n clone.attributes.set(key, value);\n });\n Object.assign(clone.style, this.style);\n if (deep) {\n this.children.forEach((child) => {\n if (child.cloneNode) {\n clone.appendChild(child.cloneNode(true));\n }\n });\n }\n return clone;\n }\n getBoundingClientRect() {\n return {\n width: this._ssrWidth || 0,\n height: this._ssrHeight || 0,\n top: 0,\n left: 0,\n right: this._ssrWidth || 0,\n bottom: this._ssrHeight || 0,\n x: 0,\n y: 0\n };\n }\n getBBox() {\n if (this.nodeName !== \"text\" && this.nodeName !== \"tspan\") {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n const lines = this._textLines();\n const longest = lines.reduce((acc, line) => Math.max(acc, line.length), 0);\n if (!longest) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n const fontSize = parseFloat(this.attributes.get(\"font-size\")) || DEFAULT_FONT_SIZE;\n const width = longest * fontSize * CHAR_WIDTH_EM;\n const height = fontSize * (ASCENT_EM + DESCENT_EM) + (lines.length - 1) * fontSize * LINE_HEIGHT_EM;\n const anchor = this.attributes.get(\"text-anchor\");\n const x = parseFloat(this.attributes.get(\"x\")) || 0;\n const y = parseFloat(this.attributes.get(\"y\")) || 0;\n return {\n x: anchor === \"middle\" ? x - width / 2 : anchor === \"end\" ? x - width : x,\n y: y - fontSize * ASCENT_EM,\n width,\n height\n };\n }\n /**\n * Text of this element, one entry per rendered line\n * @returns {string[]}\n */\n _textLines() {\n var _a;\n const tspans = this.children.filter((child) => child.nodeName === \"tspan\");\n if (tspans.length) {\n return tspans.map((tspan) => {\n var _a2;\n return String((_a2 = tspan.textContent) != null ? _a2 : \"\");\n });\n }\n return [String((_a = this.textContent) != null ? _a : \"\")];\n }\n getRootNode() {\n let root = this;\n while (root.parentNode) {\n root = root.parentNode;\n }\n return root;\n }\n querySelector() {\n return null;\n }\n querySelectorAll() {\n return [];\n }\n getElementsByClassName() {\n return [];\n }\n addEventListener() {\n }\n removeEventListener() {\n }\n get childNodes() {\n return this.children;\n }\n toString() {\n let attrs = \"\";\n this.attributes.forEach((value, key) => {\n attrs += ` ${key}=\"${value}\"`;\n });\n if (this.children.length === 0 && !this.textContent) {\n return `<${this.nodeName}${attrs}/>`;\n }\n const childrenStr = this.children.map((c) => c.toString()).join(\"\");\n return `<${this.nodeName}${attrs}>${this.textContent}${childrenStr}`;\n }\n // Property getters/setters\n get innerHTML() {\n return this.children.map((c) => c.toString()).join(\"\");\n }\n set innerHTML(value) {\n this.children = [];\n this.textContent = value;\n }\n get outerHTML() {\n return this.toString();\n }\n get isConnected() {\n return true;\n }\n}\nclass SSRClassList {\n constructor() {\n this.classes = /* @__PURE__ */ new Set();\n }\n add(...classNames) {\n classNames.forEach((name2) => this.classes.add(name2));\n }\n remove(...classNames) {\n classNames.forEach((name2) => this.classes.delete(name2));\n }\n /**\n * @param {string} className\n */\n contains(className) {\n return this.classes.has(className);\n }\n /**\n * @param {string} className\n * @param {any} force\n */\n toggle(className, force) {\n if (force === true) {\n this.classes.add(className);\n return true;\n } else if (force === false) {\n this.classes.delete(className);\n return false;\n } else {\n if (this.classes.has(className)) {\n this.classes.delete(className);\n return false;\n } else {\n this.classes.add(className);\n return true;\n }\n }\n }\n toString() {\n return Array.from(this.classes).join(\" \");\n }\n}\nclass SSRDOMShim {\n constructor() {\n this.SVGNS = \"http://www.w3.org/2000/svg\";\n this.XLINKNS = \"http://www.w3.org/1999/xlink\";\n }\n /**\n * Create SVG element with namespace\n * @param {string} namespaceURI - Namespace URI\n * @param {string} qualifiedName - Element tag name\n * @returns {SSRElement} Mock SVG element\n */\n createElementNS(namespaceURI, qualifiedName) {\n return new SSRElement(qualifiedName, namespaceURI);\n }\n /**\n * Create text node\n * @param {string} data - Text content\n * @returns {object} Text node mock\n */\n createTextNode(data) {\n const node = {\n nodeName: \"#text\",\n nodeType: 3,\n textContent: data,\n toString() {\n return node.textContent;\n }\n };\n return node;\n }\n /**\n * Query selector (returns null in SSR)\n * @returns {null}\n */\n querySelector() {\n return null;\n }\n /**\n * Query selector all (returns empty array in SSR)\n * @returns {any[]}\n */\n querySelectorAll() {\n return [];\n }\n /**\n * Get computed style (returns empty object in SSR)\n * @returns {object}\n */\n getComputedStyle() {\n return {};\n }\n /**\n * Get bounding client rect for element\n * @param {SSRElement} element - Element to measure\n * @returns {object} Mock dimensions\n */\n getBoundingClientRect(element) {\n if (element && element.getBoundingClientRect) {\n return element.getBoundingClientRect();\n }\n return {\n width: 0,\n height: 0,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n x: 0,\n y: 0\n };\n }\n /**\n * Create mock XMLSerializer for SSR\n * @returns {object} XMLSerializer mock\n */\n createXMLSerializer() {\n return {\n /**\n * @param {Element} element\n */\n serializeToString(element) {\n return element.toString ? element.toString() : \"\";\n }\n };\n }\n /**\n * Create mock DOMParser for SSR\n * @returns {object} DOMParser mock\n */\n createDOMParser() {\n return {\n /**\n * @param {string} str\n * @param {string} _type\n */\n parseFromString(str, _type) {\n const root = new SSRElement(\"root\");\n root.innerHTML = str;\n return {\n documentElement: root\n };\n }\n };\n }\n}\nlet shim = null;\nlet xmlSerializerInstance = null;\nlet domParserInstance = null;\nclass BrowserAPIs {\n /**\n * Initialize the SSR shim if in SSR environment\n * Must be called before using other methods\n */\n static init() {\n if (Environment.isSSR() && !shim) {\n shim = new SSRDOMShim();\n }\n }\n /**\n * Create an HTML element\n * @param {string} tagName - Element tag name\n * @returns {HTMLElement} HTML element\n */\n static createElement(tagName) {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n return shim.createElementNS(null, tagName);\n }\n return document.createElement(tagName);\n }\n /**\n * Create an SVG element with namespace\n * @param {string} namespaceURI - Namespace URI\n * @param {string} qualifiedName - Element tag name\n * @returns {HTMLElement} created element\n */\n static createElementNS(namespaceURI, qualifiedName) {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n return shim.createElementNS(namespaceURI, qualifiedName);\n }\n return (\n /** @type {HTMLElement} */\n document.createElementNS(namespaceURI, qualifiedName)\n );\n }\n /**\n * Create a text node\n * @param {string} data - Text content\n * @returns {Text|object} Text node\n */\n static createTextNode(data) {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n return shim.createTextNode(data);\n }\n return document.createTextNode(data);\n }\n /**\n * Query selector\n * @param {string} selector - CSS selector\n * @returns {Element|null}\n */\n static querySelector(selector) {\n if (Environment.isSSR()) {\n return null;\n }\n return document.querySelector(selector);\n }\n /**\n * Query selector all\n * @param {string} selector - CSS selector\n * @returns {NodeList|any[]}\n */\n static querySelectorAll(selector) {\n if (Environment.isSSR()) {\n return [];\n }\n return document.querySelectorAll(selector);\n }\n /**\n * Get computed style for an element\n * @param {Element} element - Element to get styles for\n * @returns {CSSStyleDeclaration|object}\n */\n static getComputedStyle(element) {\n if (Environment.isSSR()) {\n return {};\n }\n return window.getComputedStyle(element);\n }\n /**\n * Evaluate a media query. Returns the live MediaQueryList in a browser (so\n * callers can attach a `change` listener) or null under SSR / when\n * unsupported. Facet (#13) uses this for `theme.follow: 'os'`.\n * @param {string} query\n * @returns {MediaQueryList|null}\n */\n static matchMedia(query) {\n if (Environment.isSSR() || typeof window.matchMedia !== \"function\") {\n return null;\n }\n try {\n return window.matchMedia(query);\n } catch (e2) {\n return null;\n }\n }\n /**\n * Get bounding client rect for an element\n * @param {Element} element - Element to measure\n * @returns {DOMRect|object}\n */\n static getBoundingClientRect(element) {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n return shim.getBoundingClientRect(element);\n }\n return element ? element.getBoundingClientRect() : {\n width: 0,\n height: 0,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n x: 0,\n y: 0\n };\n }\n /**\n * Get XMLSerializer instance\n * @returns {XMLSerializer|object}\n */\n static getXMLSerializer() {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n if (!xmlSerializerInstance) {\n xmlSerializerInstance = shim.createXMLSerializer();\n }\n return xmlSerializerInstance;\n }\n if (!xmlSerializerInstance) {\n xmlSerializerInstance = new XMLSerializer();\n }\n return xmlSerializerInstance;\n }\n /**\n * Get DOMParser instance\n * @returns {DOMParser|object}\n */\n static getDOMParser() {\n if (Environment.isSSR()) {\n if (!shim) this.init();\n if (!domParserInstance) {\n domParserInstance = shim.createDOMParser();\n }\n return domParserInstance;\n }\n if (!domParserInstance) {\n domParserInstance = new DOMParser();\n }\n return domParserInstance;\n }\n /**\n * Add event listener to window\n * @param {string} event - Event name\n * @param {EventListenerOrEventListenerObject} handler - Event handler\n * @param {object} options - Event options\n */\n static addWindowEventListener(event, handler, options2) {\n if (Environment.isBrowser()) {\n window.addEventListener(event, handler, options2);\n }\n }\n /**\n * Remove event listener from window\n * @param {string} event - Event name\n * @param {EventListenerOrEventListenerObject} handler - Event handler\n * @param {object} options - Event options\n */\n static removeWindowEventListener(event, handler, options2) {\n if (Environment.isBrowser()) {\n window.removeEventListener(event, handler, options2);\n }\n }\n /**\n * Request animation frame\n * @param {FrameRequestCallback} callback - Callback function\n * @returns {number|null}\n */\n static requestAnimationFrame(callback) {\n if (Environment.isBrowser()) {\n return window.requestAnimationFrame(callback);\n }\n callback(0);\n return null;\n }\n /**\n * Cancel animation frame\n * @param {number} id - Animation frame ID\n */\n static cancelAnimationFrame(id) {\n if (Environment.isBrowser() && id) {\n window.cancelAnimationFrame(id);\n }\n }\n /**\n * Check if element exists\n * @param {Element} element - Element to check\n * @returns {boolean}\n */\n static elementExists(element) {\n if (!element) return false;\n if (Environment.isSSR()) {\n return element._ssrMode === true || element.nodeName !== void 0;\n }\n return element.getRootNode ? element.getRootNode({ composed: true }) === document || element.isConnected : false;\n }\n /**\n * Get window object (or null in SSR)\n * @returns {Window|null}\n */\n static getWindow() {\n return Environment.isBrowser() ? window : null;\n }\n /**\n * Get document object (or null in SSR)\n * @returns {Document|null}\n */\n static getDocument() {\n return Environment.isBrowser() ? document : null;\n }\n /**\n * Get the shim instance (for testing purposes)\n * @returns {SSRDOMShim|null}\n */\n static _getShim() {\n return shim;\n }\n /**\n * Reset the shim instance (for testing purposes)\n */\n static _resetShim() {\n shim = null;\n xmlSerializerInstance = null;\n domParserInstance = null;\n }\n}\nconst fnIds = /* @__PURE__ */ new WeakMap();\nlet fnSeq = 0;\nlet Utils$1 = class Utils {\n /**\n * @param {*} item\n */\n static isObject(item) {\n return item && typeof item === \"object\" && !Array.isArray(item);\n }\n // Type checking that works across different window objects\n /**\n * @param {string} type\n * @param {string} val\n */\n static is(type, val) {\n return Object.prototype.toString.call(val) === \"[object \" + type + \"]\";\n }\n static isSafari() {\n return Environment.isBrowser() && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n }\n // to extend defaults with user options\n // credit: http://stackoverflow.com/questions/27936772/deep-object-merging-in-es6-es7#answer-34749873\n /**\n * @param {any} target\n * @param {any} source\n */\n static extend(target, source) {\n if (!this.isObject(target) && this.isObject(source)) {\n return this.clone(source);\n }\n const output = Object.assign({}, target);\n if (this.isObject(target) && this.isObject(source)) {\n Object.keys(source).forEach((key) => {\n if (this.isObject(source[key])) {\n if (!(key in target)) {\n Object.assign(output, {\n [key]: source[key]\n });\n } else {\n output[key] = this.extend(target[key], source[key]);\n }\n } else {\n Object.assign(output, {\n [key]: source[key]\n });\n }\n });\n }\n return output;\n }\n // A per-series shallow copy: the series OBJECTS are copied, their data arrays\n // are shared. Every internal \"mutation\" of a series' data is a property\n // REPLACEMENT (`series[i].data = []` on legend collapse, `series[i] = 0` for\n // non-axis charts, appendData's concat), and those cannot reach a copy made\n // this way because the series object was copied at capture time. This is the\n // same cheap shape `globals.initialSeries` captures, so snapshotting a config\n // stays O(n) instead of deep-cloning every point.\n /**\n * @param {any} series\n */\n static copySeriesShallow(series) {\n return Array.isArray(series) ? series.map((s2) => this.isObject(s2) ? __spreadValues({}, s2) : s2) : series;\n }\n /**\n * @param {any[]} arrToExtend\n * @param {any} resultArr\n */\n static extendArray(arrToExtend, resultArr) {\n const extendedArr = [];\n arrToExtend.map((item) => {\n extendedArr.push(Utils.extend(resultArr, item));\n });\n arrToExtend = extendedArr;\n return arrToExtend;\n }\n // If month counter exceeds 12, it starts again from 1\n /**\n * @param {number} month\n */\n static monthMod(month) {\n return month % 12;\n }\n /**\n * clone object with optional shallow copy for performance\n * @param {*} source - Source object to clone\n * @param {WeakMap} visited - Circular reference tracker\n * @param {boolean} shallow - If true, performs shallow copy (default: false)\n * @returns {*} Cloned object\n */\n static clone(source, visited = /* @__PURE__ */ new WeakMap(), shallow = false) {\n if (source === null || typeof source !== \"object\") {\n return source;\n }\n if (visited.has(source)) {\n return visited.get(source);\n }\n let cloneResult;\n if (Array.isArray(source)) {\n if (shallow) {\n cloneResult = source.slice();\n } else {\n cloneResult = [];\n visited.set(source, cloneResult);\n for (let i2 = 0; i2 < source.length; i2++) {\n cloneResult[i2] = this.clone(source[i2], visited, false);\n }\n }\n } else if (source instanceof Date) {\n cloneResult = new Date(source.getTime());\n } else {\n if (shallow) {\n cloneResult = Object.assign({}, source);\n } else {\n cloneResult = {};\n visited.set(source, cloneResult);\n for (const prop in source) {\n if (Object.prototype.hasOwnProperty.call(source, prop)) {\n cloneResult[prop] = this.clone(\n /** @type {Record} */\n source[prop],\n visited,\n false\n );\n }\n }\n }\n }\n return cloneResult;\n }\n /**\n * Shallow clone for performance when deep clone isn't needed\n * @param {*} source - Source to clone\n * @returns {*} Shallow cloned object\n */\n static shallowClone(source) {\n if (source === null || typeof source !== \"object\") {\n return source;\n }\n if (Array.isArray(source)) {\n return source.slice();\n }\n return Object.assign({}, source);\n }\n /**\n * Serialize options for an equality check, with functions included.\n *\n * `JSON.stringify` DROPS function values, so two configs differing only in a\n * callback stringify identically. The update path used that comparison to skip\n * redundant renders, which silently swallowed any update that changed only a\n * function: a new `plotOptions.unit.positions` (a whole layout), a new\n * `dataLabels.formatter`, a new custom tooltip.\n *\n * Functions are compared BY IDENTITY: the same function twice still compares\n * equal (so the skip keeps working), a different one does not. A caller who\n * passes a fresh closure on every update gets a render every time, which is\n * the safe direction to err in - the closure may capture new state.\n *\n * @param {any} options\n * @returns {string}\n */\n static stringifyForCompare(options2) {\n return JSON.stringify(options2, (_key, value) => {\n if (typeof value !== \"function\") return value;\n let id = fnIds.get(value);\n if (id === void 0) {\n id = ++fnSeq;\n fnIds.set(value, id);\n }\n return `__apx_fn_${id}`;\n });\n }\n /**\n * Fast shallow equality check for objects\n * @param {Object} obj1 - First object\n * @param {Object} obj2 - Second object\n * @returns {boolean} True if shallowly equal\n */\n static shallowEqual(obj1, obj2) {\n if (obj1 === obj2) return true;\n if (!obj1 || !obj2) return false;\n if (typeof obj1 !== \"object\" || typeof obj2 !== \"object\") {\n return obj1 === obj2;\n }\n const keys1 = Object.keys(obj1);\n const keys2 = Object.keys(obj2);\n if (keys1.length !== keys2.length) return false;\n for (const key of keys1) {\n if (\n /** @type {Record} */\n obj1[key] !== /** @type {Record} */\n obj2[key]\n )\n return false;\n }\n return true;\n }\n /**\n * @param {number} x\n */\n static log10(x) {\n return Math.log(x) / Math.LN10;\n }\n /**\n * @param {number} x\n */\n static roundToBase10(x) {\n return Math.pow(10, Math.floor(Math.log10(x)));\n }\n /**\n * @param {number} x\n * @param {number} base\n */\n static roundToBase(x, base) {\n return Math.pow(base, Math.floor(Math.log(x) / Math.log(base)));\n }\n /**\n * @param {any} val\n */\n static parseNumber(val) {\n if (typeof val === \"number\" || val === null) return val;\n return parseFloat(val);\n }\n /**\n * @param {number} num\n */\n static stripNumber(num, precision = 2) {\n return Number.isInteger(num) ? num : parseFloat(num.toPrecision(precision));\n }\n static randomId() {\n return (Math.random() + 1).toString(36).substring(4);\n }\n /**\n * @param {number} num\n */\n static noExponents(num) {\n if (num.toString().includes(\"e\")) {\n return Math.round(num);\n }\n return num;\n }\n /**\n * @param {any} element\n */\n static elementExists(element) {\n if (!element || !element.isConnected) {\n return false;\n }\n return true;\n }\n /**\n * @param {any} el\n */\n static getDimensions(el) {\n if (!el) return [0, 0];\n if (Environment.isSSR()) {\n return [el._ssrWidth || 400, el._ssrHeight || 300];\n }\n let computedStyle;\n try {\n computedStyle = getComputedStyle(el, null);\n } catch (e2) {\n return [el.clientWidth || 0, el.clientHeight || 0];\n }\n let elementWidth = el.clientWidth;\n let elementHeight = el.clientHeight;\n if (!elementWidth || !elementHeight) {\n const rect = el.getBoundingClientRect();\n elementWidth = elementWidth || rect.width;\n elementHeight = elementHeight || rect.height;\n }\n elementHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom);\n elementWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);\n return [elementWidth, elementHeight];\n }\n /**\n * @returns {any}\n * @param {any} element\n */\n static getBoundingClientRect(element) {\n if (!element) {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: 0,\n height: 0,\n x: 0,\n y: 0\n };\n }\n if (Environment.isSSR()) {\n return BrowserAPIs.getBoundingClientRect(element);\n }\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n width: element.clientWidth,\n height: element.clientHeight,\n x: rect.left,\n y: rect.top\n };\n }\n /**\n * @param {any[]} arr\n */\n static getLargestStringFromArr(arr) {\n return arr.reduce((a2, b) => {\n if (Array.isArray(b)) {\n b = b.reduce((aa, bb) => aa.length > bb.length ? aa : bb);\n }\n return a2.length > b.length ? a2 : b;\n }, 0);\n }\n // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-12342275\n static hexToRgba(hex = \"#999999\", opacity = 0.6) {\n if (hex.substring(0, 1) !== \"#\") {\n hex = \"#999999\";\n }\n const hexStr = hex.replace(\"#\", \"\");\n const h = hexStr.match(new RegExp(\"(.{\" + hexStr.length / 3 + \"})\", \"g\")) || [];\n for (let i2 = 0; i2 < h.length; i2++) {\n h[i2] = parseInt(h[i2].length === 1 ? h[i2] + h[i2] : h[i2], 16);\n }\n if (typeof opacity !== \"undefined\") h.push(opacity);\n return \"rgba(\" + h.join(\",\") + \")\";\n }\n /**\n * @param {string} rgba\n */\n static getOpacityFromRGBA(rgba) {\n return parseFloat(rgba.replace(/^.*,(.+)\\)/, \"$1\"));\n }\n /**\n * Parse a #RGB or #RRGGBB hex colour string into [r,g,b] in 0\u2013255.\n * Returns null for invalid input. Used by getContrastRatio.\n * @param {string} hex\n * @returns {[number, number, number] | null}\n */\n static parseHex(hex) {\n if (typeof hex !== \"string\") return null;\n let h = hex.trim().replace(\"#\", \"\");\n if (h.length === 3) {\n h = h.split(\"\").map((c) => c + c).join(\"\");\n }\n if (!/^[0-9a-fA-F]{6}$/.test(h)) return null;\n return [\n parseInt(h.slice(0, 2), 16),\n parseInt(h.slice(2, 4), 16),\n parseInt(h.slice(4, 6), 16)\n ];\n }\n /**\n * Relative luminance per WCAG 2.x (https://www.w3.org/TR/WCAG22/#dfn-relative-luminance).\n * @param {[number, number, number]} rgb 0\u2013255 sRGB triplet\n * @returns {number} 0.0\u20131.0\n */\n static relativeLuminance([r2, g, b]) {\n const channel = (c) => {\n const v = c / 255;\n return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n };\n return 0.2126 * channel(r2) + 0.7152 * channel(g) + 0.0722 * channel(b);\n }\n /**\n * WCAG contrast ratio between two hex colours. Returns 0 for invalid input.\n * Range: 1 (identical) \u2026 21 (#000 vs #fff).\n * WCAG AA requires \u2265 4.5 for normal text and \u2265 3.0 for large text / UI components.\n * @param {string} hex1\n * @param {string} hex2\n * @returns {number}\n */\n static getContrastRatio(hex1, hex2) {\n const rgb1 = Utils.parseHex(hex1);\n const rgb2 = Utils.parseHex(hex2);\n if (!rgb1 || !rgb2) return 0;\n const l1 = Utils.relativeLuminance(rgb1);\n const l2 = Utils.relativeLuminance(rgb2);\n const lighter = Math.max(l1, l2);\n const darker = Math.min(l1, l2);\n return (lighter + 0.05) / (darker + 0.05);\n }\n /**\n * @param {any} rgb\n */\n static rgb2hex(rgb) {\n rgb = rgb.match(\n /^rgba?[\\s+]?\\([\\s+]?(\\d+)[\\s+]?,[\\s+]?(\\d+)[\\s+]?,[\\s+]?(\\d+)[\\s+]?/i\n );\n return rgb && rgb.length === 4 ? \"#\" + (\"0\" + parseInt(rgb[1], 10).toString(16)).slice(-2) + (\"0\" + parseInt(rgb[2], 10).toString(16)).slice(-2) + (\"0\" + parseInt(rgb[3], 10).toString(16)).slice(-2) : \"\";\n }\n /**\n * @param {number} percent\n * @param {string} color\n */\n shadeRGBColor(percent, color) {\n const f = color.split(\",\"), t2 = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = parseInt(f[0].slice(4), 10), G = parseInt(f[1], 10), B = parseInt(f[2], 10);\n return \"rgb(\" + (Math.round((t2 - R) * p) + R) + \",\" + (Math.round((t2 - G) * p) + G) + \",\" + (Math.round((t2 - B) * p) + B) + \")\";\n }\n /**\n * @param {number} percent\n * @param {string} color\n */\n shadeHexColor(percent, color) {\n const f = parseInt(color.slice(1), 16), t2 = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 255, B = f & 255;\n return \"#\" + (16777216 + (Math.round((t2 - R) * p) + R) * 65536 + (Math.round((t2 - G) * p) + G) * 256 + (Math.round((t2 - B) * p) + B)).toString(16).slice(1);\n }\n // beautiful color shading blending code\n // http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors\n /**\n * @param {number} p\n * @param {string} color\n */\n shadeColor(p, color) {\n if (Utils.isColorHex(color)) {\n return this.shadeHexColor(p, color);\n } else {\n return this.shadeRGBColor(p, color);\n }\n }\n /**\n * @param {string} color\n */\n static isColorHex(color) {\n return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i.test(color);\n }\n /**\n * @param {string} color\n */\n static isCSSVariable(color) {\n if (typeof color !== \"string\") return false;\n const value = color.trim();\n return value.startsWith(\"var(\") && value.endsWith(\")\");\n }\n /**\n * @param {string} color\n */\n static getThemeColor(color) {\n if (!Utils.isCSSVariable(color)) return color;\n if (Environment.isSSR()) return color;\n const tempElem = document.createElement(\"div\");\n tempElem.style.cssText = \"position:fixed; left: -9999px; visibility:hidden;\";\n tempElem.style.color = color;\n document.body.appendChild(tempElem);\n let computedColor;\n try {\n computedColor = window.getComputedStyle(tempElem).color;\n } finally {\n if (tempElem.parentNode) {\n tempElem.parentNode.removeChild(tempElem);\n }\n }\n return computedColor;\n }\n /**\n * @param {string} color\n * @param {number} opacity\n */\n static applyOpacityToColor(color, opacity) {\n const value = Number(opacity);\n if (!Number.isFinite(value)) return color;\n if (value <= 0) return \"transparent\";\n if (value >= 1) return color;\n const percent = Math.round(value * 100);\n return `color-mix(in srgb, ${color} ${percent}%, transparent)`;\n }\n /**\n * @param {number} size\n * @param {number} dataPointsLen\n */\n static getPolygonPos(size, dataPointsLen) {\n const dotsArray = [];\n const angle = Math.PI * 2 / dataPointsLen;\n for (let i2 = 0; i2 < dataPointsLen; i2++) {\n const curPos = {};\n curPos.x = size * Math.sin(i2 * angle);\n curPos.y = -size * Math.cos(i2 * angle);\n dotsArray.push(curPos);\n }\n return dotsArray;\n }\n /**\n * @param {number} centerX\n * @param {number} centerY\n * @param {number} radius\n * @param {number} angleInDegrees\n */\n static polarToCartesian(centerX, centerY, radius, angleInDegrees) {\n const angleInRadians = (angleInDegrees - 90) * Math.PI / 180;\n return {\n x: centerX + radius * Math.cos(angleInRadians),\n y: centerY + radius * Math.sin(angleInRadians)\n };\n }\n /**\n * @param {string} str\n */\n static escapeString(str, escapeWith = \"x\") {\n let newStr = str.toString().slice();\n newStr = newStr.replace(/[` ~!@#$%^&*()|+=?;:'\",.<>{}[\\]\\\\/]/gi, escapeWith);\n return newStr;\n }\n /**\n * @param {number} val\n */\n static negToZero(val) {\n return val < 0 ? 0 : val;\n }\n /**\n * @param {any[]} arr\n * @param {number} old_index\n * @param {number} new_index\n */\n static moveIndexInArray(arr, old_index, new_index) {\n if (new_index >= arr.length) {\n let k = new_index - arr.length + 1;\n while (k--) {\n arr.push(void 0);\n }\n }\n arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);\n return arr;\n }\n /**\n * @param {string} s\n */\n static extractNumber(s2) {\n return parseFloat(s2.replace(/[^\\d.]*/g, \"\"));\n }\n /**\n * @param {any} el\n * @param {string} cls\n */\n static findAncestor(el, cls) {\n while ((el = el.parentElement) && !el.classList.contains(cls)) ;\n return el;\n }\n /**\n * @param {any} el\n * @param {Record} styles\n */\n static setELstyles(el, styles) {\n for (const key in styles) {\n if (Object.prototype.hasOwnProperty.call(styles, key)) {\n el.style[key] = styles[key];\n }\n }\n }\n // prevents JS prevision errors when adding\n /**\n * @param {number} a\n * @param {number} b\n */\n static preciseAddition(a2, b) {\n const aDecimals = (String(a2).split(\".\")[1] || \"\").length;\n const bDecimals = (String(b).split(\".\")[1] || \"\").length;\n const factor = Math.pow(10, Math.max(aDecimals, bDecimals));\n return (Math.round(a2 * factor) + Math.round(b * factor)) / factor;\n }\n /**\n * @param {any} value\n */\n static isNumber(value) {\n return !isNaN(value) && parseFloat(String(Number(value))) === value && !isNaN(parseInt(value, 10));\n }\n /**\n * @param {number} n\n */\n static isFloat(n2) {\n return Number(n2) === n2 && n2 % 1 !== 0;\n }\n /**\n * Edit distance, capped: how many single-character insertions, deletions or\n * substitutions turn `a` into `b`. Only ever asked \"is this within `max`?\",\n * so it abandons a row the moment every cell in it has passed the budget,\n * which keeps a near-miss check over a few dozen names free.\n *\n * @param {string} a\n * @param {string} b\n * @param {number} max\n * @returns {number} the distance, or `max + 1` once it is known to exceed it\n */\n static editDistance(a2, b, max) {\n if (Math.abs(a2.length - b.length) > max) return max + 1;\n let prev = Array.from({ length: b.length + 1 }, (_, j2) => j2);\n for (let i2 = 1; i2 <= a2.length; i2++) {\n const row = [i2];\n let best = i2;\n for (let j2 = 1; j2 <= b.length; j2++) {\n row[j2] = Math.min(\n prev[j2] + 1,\n row[j2 - 1] + 1,\n prev[j2 - 1] + (a2[i2 - 1] === b[j2 - 1] ? 0 : 1)\n );\n if (row[j2] < best) best = row[j2];\n }\n if (best > max) return max + 1;\n prev = row;\n }\n return prev[b.length];\n }\n /**\n * The name in `candidates` closest to `name`, or '' when nothing is close\n * enough to be worth putting in front of a reader. Case and surrounding\n * whitespace are ignored, so `Line ` finds `line`.\n *\n * Used to turn \"that option does not exist\" into \"did you mean this one\",\n * which is the difference between a message that reports a problem and one\n * that ends it.\n *\n * @param {string} name\n * @param {string[]} candidates\n * @returns {string}\n */\n static nearestName(name2, candidates) {\n const needle = String(name2).trim().toLowerCase();\n const max = needle.length > 4 ? 2 : 1;\n let best = \"\";\n let bestDist = max + 1;\n candidates.forEach((candidate) => {\n const d = Utils.editDistance(needle, candidate.toLowerCase(), max);\n if (d < bestDist) {\n bestDist = d;\n best = candidate;\n }\n });\n return bestDist <= max ? best : \"\";\n }\n static isMsEdge() {\n if (Environment.isSSR()) return false;\n const ua = window.navigator.userAgent;\n const edge = ua.indexOf(\"Edge/\");\n if (edge > 0) {\n return parseInt(ua.substring(edge + 5, ua.indexOf(\".\", edge)), 10);\n }\n return false;\n }\n //\n // Find the Greatest Common Divisor of two numbers\n //\n /**\n * @param {number} a\n * @param {number} b\n */\n static getGCD(a2, b, p = 7) {\n let factor = Math.pow(10, p - Math.floor(Math.log10(Math.max(a2, b))));\n if (factor > 1) {\n a2 = Math.round(Math.abs(a2) * factor);\n b = Math.round(Math.abs(b) * factor);\n } else {\n factor = 1;\n }\n while (b) {\n const t2 = b;\n b = a2 % b;\n a2 = t2;\n }\n return a2 / factor;\n }\n /**\n * @param {number} n\n */\n static getPrimeFactors(n2) {\n const factors = [];\n let divisor = 2;\n while (n2 >= 2) {\n if (n2 % divisor == 0) {\n factors.push(divisor);\n n2 = n2 / divisor;\n } else {\n divisor++;\n }\n }\n return factors;\n }\n /**\n * @param {number} a\n * @param {number} b\n */\n static mod(a2, b, p = 7) {\n const big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a2, b))));\n a2 = Math.round(Math.abs(a2) * big);\n b = Math.round(Math.abs(b) * big);\n return a2 % b / big;\n }\n};\nclass DateTime {\n /**\n * @param {import('../types/internal').ChartStateW} w\n */\n constructor(w) {\n this.w = w;\n this.months31 = [1, 3, 5, 7, 8, 10, 12];\n this.months30 = [2, 4, 6, 9, 11];\n this.daysCntOfYear = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n }\n /**\n * @param {any} date\n */\n isValidDate(date) {\n if (typeof date === \"number\") {\n return false;\n }\n return !isNaN(this.parseDate(date));\n }\n /**\n * @param {any} dateStr\n */\n getTimeStamp(dateStr) {\n if (isNaN(Date.parse(dateStr))) {\n return dateStr;\n }\n const utc = this.w.config.xaxis.labels.datetimeUTC;\n return !utc ? new Date(dateStr).getTime() : new Date(new Date(dateStr).toISOString().substr(0, 25)).getTime();\n }\n /**\n * @param {any} timestamp\n */\n getDate(timestamp) {\n const utc = this.w.config.xaxis.labels.datetimeUTC;\n return utc ? new Date(new Date(timestamp).toUTCString()) : new Date(timestamp);\n }\n /**\n * @param {any} dateStr - a date string, or anything isValidDate() was handed\n */\n parseDate(dateStr) {\n const parsed = Date.parse(dateStr);\n if (!isNaN(parsed)) {\n return this.getTimeStamp(dateStr);\n }\n if (typeof dateStr !== \"string\") {\n return NaN;\n }\n let output = Date.parse(dateStr.replace(/-/g, \"/\").replace(/[a-z]+/gi, \" \"));\n output = this.getTimeStamp(output);\n return output;\n }\n // This fixes the difference of x-axis labels between chrome/safari\n // Fixes #1726, #1544, #1485, #1255\n /**\n * @param {string} dateStr\n */\n parseDateWithTimezone(dateStr) {\n return Date.parse(dateStr.replace(/-/g, \"/\").replace(/[a-z]+/gi, \" \"));\n }\n // http://stackoverflow.com/questions/14638018/current-time-formatting-with-javascript#answer-14638191\n /**\n * @param {Date} date\n * @param {string} format\n */\n formatDate(date, format) {\n const locale = this.w.globals.locale;\n const utc = this.w.config.xaxis.labels.datetimeUTC;\n const MMMM = [\"\\0\", ...locale.months];\n const MMM = [\"\u0001\", ...locale.shortMonths];\n const dddd = [\"\u0002\", ...locale.days];\n const ddd = [\"\u0003\", ...locale.shortDays];\n function ii(i2, len = 2) {\n let s3 = i2 + \"\";\n while (s3.length < len) s3 = \"0\" + s3;\n return s3;\n }\n const y = utc ? date.getUTCFullYear() : date.getFullYear();\n format = format.replace(/(^|[^\\\\])yyyy+/g, \"$1\" + y);\n format = format.replace(/(^|[^\\\\])yy/g, \"$1\" + y.toString().substr(2, 2));\n format = format.replace(/(^|[^\\\\])y/g, \"$1\" + y);\n const M = (utc ? date.getUTCMonth() : date.getMonth()) + 1;\n format = format.replace(/(^|[^\\\\])MMMM+/g, \"$1\" + MMMM[0]);\n format = format.replace(/(^|[^\\\\])MMM/g, \"$1\" + MMM[0]);\n format = format.replace(/(^|[^\\\\])MM/g, \"$1\" + ii(M));\n format = format.replace(/(^|[^\\\\])M/g, \"$1\" + M);\n const d = utc ? date.getUTCDate() : date.getDate();\n format = format.replace(/(^|[^\\\\])dddd+/g, \"$1\" + dddd[0]);\n format = format.replace(/(^|[^\\\\])ddd/g, \"$1\" + ddd[0]);\n format = format.replace(/(^|[^\\\\])dd/g, \"$1\" + ii(d));\n format = format.replace(/(^|[^\\\\])d/g, \"$1\" + d);\n const H = utc ? date.getUTCHours() : date.getHours();\n format = format.replace(/(^|[^\\\\])HH+/g, \"$1\" + ii(H));\n format = format.replace(/(^|[^\\\\])H/g, \"$1\" + H);\n const h = H > 12 ? H - 12 : H === 0 ? 12 : H;\n format = format.replace(/(^|[^\\\\])hh+/g, \"$1\" + ii(h));\n format = format.replace(/(^|[^\\\\])h/g, \"$1\" + h);\n const m = utc ? date.getUTCMinutes() : date.getMinutes();\n format = format.replace(/(^|[^\\\\])mm+/g, \"$1\" + ii(m));\n format = format.replace(/(^|[^\\\\])m/g, \"$1\" + m);\n const s2 = utc ? date.getUTCSeconds() : date.getSeconds();\n format = format.replace(/(^|[^\\\\])ss+/g, \"$1\" + ii(s2));\n format = format.replace(/(^|[^\\\\])s/g, \"$1\" + s2);\n let f = utc ? date.getUTCMilliseconds() : date.getMilliseconds();\n format = format.replace(/(^|[^\\\\])fff+/g, \"$1\" + ii(f, 3));\n f = Math.round(f / 10);\n format = format.replace(/(^|[^\\\\])ff/g, \"$1\" + ii(f));\n f = Math.round(f / 10);\n format = format.replace(/(^|[^\\\\])f/g, \"$1\" + f);\n const T = H < 12 ? \"AM\" : \"PM\";\n format = format.replace(/(^|[^\\\\])TT+/g, \"$1\" + T);\n format = format.replace(/(^|[^\\\\])T/g, \"$1\" + T.charAt(0));\n const t2 = T.toLowerCase();\n format = format.replace(/(^|[^\\\\])tt+/g, \"$1\" + t2);\n format = format.replace(/(^|[^\\\\])t/g, \"$1\" + t2.charAt(0));\n let tz = -date.getTimezoneOffset();\n let K = utc || !tz ? \"Z\" : tz > 0 ? \"+\" : \"-\";\n if (!utc) {\n tz = Math.abs(tz);\n const tzHrs = Math.floor(tz / 60);\n const tzMin = tz % 60;\n K += ii(tzHrs) + \":\" + ii(tzMin);\n }\n format = format.replace(/(^|[^\\\\])K/g, \"$1\" + K);\n const day = (utc ? date.getUTCDay() : date.getDay()) + 1;\n format = format.replace(new RegExp(dddd[0], \"g\"), dddd[day]);\n format = format.replace(new RegExp(ddd[0], \"g\"), ddd[day]);\n format = format.replace(new RegExp(MMMM[0], \"g\"), MMMM[M]);\n format = format.replace(new RegExp(MMM[0], \"g\"), MMM[M]);\n format = format.replace(/\\\\(.)/g, \"$1\");\n return format;\n }\n /**\n * @param {number} minX\n * @param {number} maxX\n */\n getTimeUnitsfromTimestamp(minX, maxX) {\n const w = this.w;\n if (w.config.xaxis.min !== void 0) {\n minX = w.config.xaxis.min;\n }\n if (w.config.xaxis.max !== void 0) {\n maxX = w.config.xaxis.max;\n }\n const tsMin = this.getDate(minX);\n const tsMax = this.getDate(maxX);\n const minD = this.formatDate(tsMin, \"yyyy MM dd HH mm ss fff\").split(\" \");\n const maxD = this.formatDate(tsMax, \"yyyy MM dd HH mm ss fff\").split(\" \");\n return {\n minMillisecond: parseInt(minD[6], 10),\n maxMillisecond: parseInt(maxD[6], 10),\n minSecond: parseInt(minD[5], 10),\n maxSecond: parseInt(maxD[5], 10),\n minMinute: parseInt(minD[4], 10),\n maxMinute: parseInt(maxD[4], 10),\n minHour: parseInt(minD[3], 10),\n maxHour: parseInt(maxD[3], 10),\n minDate: parseInt(minD[2], 10),\n maxDate: parseInt(maxD[2], 10),\n minMonth: parseInt(minD[1], 10) - 1,\n maxMonth: parseInt(maxD[1], 10) - 1,\n minYear: parseInt(minD[0], 10),\n maxYear: parseInt(maxD[0], 10)\n };\n }\n /**\n * @param {number} year\n */\n isLeapYear(year) {\n return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;\n }\n /**\n * @param {number} month\n * @param {number} year\n * @param {number} subtract\n */\n calculcateLastDaysOfMonth(month, year, subtract) {\n const days = this.determineDaysOfMonths(month, year);\n return days - subtract;\n }\n /**\n * @param {number} year\n */\n determineDaysOfYear(year) {\n let days = 365;\n if (this.isLeapYear(year)) {\n days = 366;\n }\n return days;\n }\n /**\n * @param {number} year\n * @param {number} month\n * @param {number} date\n */\n determineRemainingDaysOfYear(year, month, date) {\n let dayOfYear = this.daysCntOfYear[month] + date;\n if (month > 1 && this.isLeapYear(year)) dayOfYear++;\n return dayOfYear;\n }\n /**\n * @param {number} month\n * @param {number} year\n */\n determineDaysOfMonths(month, year) {\n let days = 30;\n month = Utils$1.monthMod(month);\n switch (true) {\n case this.months30.indexOf(month) > -1:\n if (month === 2) {\n if (this.isLeapYear(year)) {\n days = 29;\n } else {\n days = 28;\n }\n }\n break;\n case this.months31.indexOf(month) > -1:\n days = 31;\n break;\n default:\n days = 31;\n break;\n }\n return days;\n }\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Pure date helpers used by the v6 single-interval TimeScale.\n // Native Date setters/getters do all rollover work (leap years, month\n // length, year crossings), eliminating the manual rollover code that was\n // the source of the historical TimeScale boundary bugs.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n /**\n * Extract calendar fields from a timestamp. Month is 0-indexed (matches\n * Date.getMonth / getUTCMonth).\n *\n * @param {number} timestamp\n * @param {boolean} isUTC\n * @returns {{ year: number, month: number, date: number, hour: number, minute: number, second: number, ms: number, weekday: number }}\n */\n getDateFields(timestamp, isUTC) {\n const d = new Date(timestamp);\n return isUTC ? {\n year: d.getUTCFullYear(),\n month: d.getUTCMonth(),\n date: d.getUTCDate(),\n hour: d.getUTCHours(),\n minute: d.getUTCMinutes(),\n second: d.getUTCSeconds(),\n ms: d.getUTCMilliseconds(),\n weekday: d.getUTCDay()\n } : {\n year: d.getFullYear(),\n month: d.getMonth(),\n date: d.getDate(),\n hour: d.getHours(),\n minute: d.getMinutes(),\n second: d.getSeconds(),\n ms: d.getMilliseconds(),\n weekday: d.getDay()\n };\n }\n /**\n * Advance a timestamp by `count` units. Native setters handle cross-month,\n * cross-year, leap-year, and DST rollover correctly.\n *\n * @param {number} timestamp\n * @param {'year'|'month'|'week'|'day'|'hour'|'minute'|'second'} unit\n * @param {number} count may be negative\n * @param {boolean} isUTC\n * @returns {number}\n */\n addInterval(timestamp, unit, count, isUTC) {\n const d = new Date(timestamp);\n if (isUTC) {\n switch (unit) {\n case \"year\":\n d.setUTCFullYear(d.getUTCFullYear() + count);\n break;\n case \"month\":\n d.setUTCMonth(d.getUTCMonth() + count);\n break;\n case \"week\":\n d.setUTCDate(d.getUTCDate() + count * 7);\n break;\n case \"day\":\n d.setUTCDate(d.getUTCDate() + count);\n break;\n case \"hour\":\n d.setUTCHours(d.getUTCHours() + count);\n break;\n case \"minute\":\n d.setUTCMinutes(d.getUTCMinutes() + count);\n break;\n case \"second\":\n d.setUTCSeconds(d.getUTCSeconds() + count);\n break;\n }\n } else {\n switch (unit) {\n case \"year\":\n d.setFullYear(d.getFullYear() + count);\n break;\n case \"month\":\n d.setMonth(d.getMonth() + count);\n break;\n case \"week\":\n d.setDate(d.getDate() + count * 7);\n break;\n case \"day\":\n d.setDate(d.getDate() + count);\n break;\n case \"hour\":\n d.setHours(d.getHours() + count);\n break;\n case \"minute\":\n d.setMinutes(d.getMinutes() + count);\n break;\n case \"second\":\n d.setSeconds(d.getSeconds() + count);\n break;\n }\n }\n return d.getTime();\n }\n /**\n * Snap a timestamp UP to the next boundary aligned with `step` units of\n * `unit`. Returns the input unchanged if already on a boundary. Alignment\n * rules per unit:\n * - second: 0/step/2*step/... seconds within a minute (step must divide 60)\n * - minute: 0/step/2*step/... minutes within an hour (step must divide 60)\n * - hour: 0/step/... hours within a day (step must divide 24)\n * - day: every day (step always 1)\n * - week: next Monday on a `step`-week stride from a fixed epoch Monday\n * - month: Jan/Apr/Jul/Oct for step=3, Jan/Jul for step=6 (step must divide 12)\n * - year: year % step === 0\n *\n * @param {number} timestamp\n * @param {'year'|'month'|'week'|'day'|'hour'|'minute'|'second'} unit\n * @param {number} step\n * @param {boolean} isUTC\n * @returns {number}\n */\n ceilToBoundary(timestamp, unit, step, isUTC) {\n const d = new Date(timestamp);\n if (isUTC) {\n switch (unit) {\n case \"second\": {\n const s2 = d.getUTCSeconds();\n const aligned = Math.ceil(s2 / step) * step;\n if (aligned === s2 && d.getUTCMilliseconds() === 0)\n return timestamp;\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(aligned);\n return d.getTime();\n }\n case \"minute\": {\n const m = d.getUTCMinutes();\n const aligned = Math.ceil(m / step) * step;\n if (aligned === m && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)\n return timestamp;\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(0);\n d.setUTCMinutes(aligned);\n return d.getTime();\n }\n case \"hour\": {\n const h = d.getUTCHours();\n const aligned = Math.ceil(h / step) * step;\n if (aligned === h && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)\n return timestamp;\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(0);\n d.setUTCMinutes(0);\n d.setUTCHours(aligned);\n return d.getTime();\n }\n case \"day\": {\n if (d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)\n return timestamp;\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(0);\n d.setUTCMinutes(0);\n d.setUTCHours(0);\n d.setUTCDate(d.getUTCDate() + 1);\n return d.getTime();\n }\n case \"week\": {\n const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1e3;\n const REF_MONDAY_UTC = Date.UTC(1970, 0, 5);\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(0);\n d.setUTCMinutes(0);\n d.setUTCHours(0);\n const startOfDay = d.getTime();\n const weeksSinceRef = Math.ceil(\n (startOfDay - REF_MONDAY_UTC) / MS_PER_WEEK\n );\n const alignedWeeks = Math.ceil(weeksSinceRef / step) * step;\n const aligned = REF_MONDAY_UTC + alignedWeeks * MS_PER_WEEK;\n if (aligned >= timestamp) return aligned;\n return aligned + step * MS_PER_WEEK;\n }\n case \"month\": {\n const m = d.getUTCMonth();\n const aligned = Math.ceil(m / step) * step;\n if (aligned === m && d.getUTCDate() === 1 && d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)\n return timestamp;\n d.setUTCMilliseconds(0);\n d.setUTCSeconds(0);\n d.setUTCMinutes(0);\n d.setUTCHours(0);\n d.setUTCDate(1);\n d.setUTCMonth(aligned);\n return d.getTime();\n }\n case \"year\": {\n const y = d.getUTCFullYear();\n const aligned = Math.ceil(y / step) * step;\n if (aligned === y && d.getUTCMonth() === 0 && d.getUTCDate() === 1 && d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)\n return timestamp;\n return Date.UTC(aligned, 0, 1);\n }\n }\n } else {\n switch (unit) {\n case \"second\": {\n const s2 = d.getSeconds();\n const aligned = Math.ceil(s2 / step) * step;\n if (aligned === s2 && d.getMilliseconds() === 0) return timestamp;\n d.setMilliseconds(0);\n d.setSeconds(aligned);\n return d.getTime();\n }\n case \"minute\": {\n const m = d.getMinutes();\n const aligned = Math.ceil(m / step) * step;\n if (aligned === m && d.getSeconds() === 0 && d.getMilliseconds() === 0)\n return timestamp;\n d.setMilliseconds(0);\n d.setSeconds(0);\n d.setMinutes(aligned);\n return d.getTime();\n }\n case \"hour\": {\n const h = d.getHours();\n const aligned = Math.ceil(h / step) * step;\n if (aligned === h && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)\n return timestamp;\n d.setMilliseconds(0);\n d.setSeconds(0);\n d.setMinutes(0);\n d.setHours(aligned);\n return d.getTime();\n }\n case \"day\": {\n if (d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)\n return timestamp;\n d.setMilliseconds(0);\n d.setSeconds(0);\n d.setMinutes(0);\n d.setHours(0);\n d.setDate(d.getDate() + 1);\n return d.getTime();\n }\n case \"week\": {\n const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1e3;\n const REF_MONDAY_LOCAL = new Date(1970, 0, 5).getTime();\n d.setMilliseconds(0);\n d.setSeconds(0);\n d.setMinutes(0);\n d.setHours(0);\n const startOfDay = d.getTime();\n const weeksSinceRef = Math.ceil(\n (startOfDay - REF_MONDAY_LOCAL) / MS_PER_WEEK\n );\n const alignedWeeks = Math.ceil(weeksSinceRef / step) * step;\n const aligned = REF_MONDAY_LOCAL + alignedWeeks * MS_PER_WEEK;\n if (aligned >= timestamp) return aligned;\n return aligned + step * MS_PER_WEEK;\n }\n case \"month\": {\n const m = d.getMonth();\n const aligned = Math.ceil(m / step) * step;\n if (aligned === m && d.getDate() === 1 && d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)\n return timestamp;\n d.setMilliseconds(0);\n d.setSeconds(0);\n d.setMinutes(0);\n d.setHours(0);\n d.setDate(1);\n d.setMonth(aligned);\n return d.getTime();\n }\n case \"year\": {\n const y = d.getFullYear();\n const aligned = Math.ceil(y / step) * step;\n if (aligned === y && d.getMonth() === 0 && d.getDate() === 1 && d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)\n return timestamp;\n return new Date(aligned, 0, 1).getTime();\n }\n }\n }\n return timestamp;\n }\n /**\n * Test whether a timestamp falls exactly on a unit boundary (start of year,\n * start of month, start of day, etc.). Used by the multi-resolution\n * formatter to upgrade a tick's display unit to a coarser scale.\n *\n * @param {number} timestamp\n * @param {'year'|'month'|'day'|'hour'|'minute'|'second'} unit\n * @param {boolean} isUTC\n * @returns {boolean}\n */\n isAtBoundary(timestamp, unit, isUTC) {\n const f = this.getDateFields(timestamp, isUTC);\n switch (unit) {\n case \"year\":\n return f.month === 0 && f.date === 1 && f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;\n case \"month\":\n return f.date === 1 && f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;\n case \"day\":\n return f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;\n case \"hour\":\n return f.minute === 0 && f.second === 0 && f.ms === 0;\n case \"minute\":\n return f.second === 0 && f.ms === 0;\n case \"second\":\n return f.ms === 0;\n }\n return false;\n }\n}\nclass Formatters {\n /**\n * @param {import('../types/internal').ChartStateW} w\n */\n constructor(w) {\n this.w = w;\n this.tooltipKeyFormat = \"dd MMM\";\n }\n /**\n * @param {Function} fn\n * @param {any} val\n * @param {any} timestamp\n * @param {any} _opts\n */\n xLabelFormat(fn, val, timestamp, _opts) {\n const w = this.w;\n if (w.config.xaxis.type === \"datetime\") {\n if (w.config.xaxis.labels.formatter === void 0) {\n if (w.config.tooltip.x.formatter === void 0) {\n const datetimeObj = new DateTime(this.w);\n return datetimeObj.formatDate(\n datetimeObj.getDate(val),\n w.config.tooltip.x.format\n );\n }\n }\n }\n return fn(val, timestamp, _opts);\n }\n /**\n * @param {any} val\n */\n defaultGeneralFormatter(val) {\n if (Array.isArray(val)) {\n return val.map((v) => {\n return v;\n });\n } else {\n return val;\n }\n }\n /**\n * @param {any} v\n * @param {ApexYAxis} yaxe\n */\n defaultYFormatter(v, yaxe) {\n const w = this.w;\n if (Utils$1.isNumber(v)) {\n if (w.globals.yValueDecimal !== 0) {\n v = v.toFixed(\n yaxe.decimalsInFloat !== void 0 ? yaxe.decimalsInFloat : w.globals.yValueDecimal\n );\n } else {\n const f = v.toFixed(0);\n v = Number(f) === v ? f : v.toFixed(1);\n }\n }\n return v;\n }\n setLabelFormatters() {\n const w = this.w;\n const fmt = w.formatters;\n const inferredNumericX = w.axisFlags.isXNumeric && w.axisFlags.dataFormatXNumeric && w.config.xaxis.type !== \"datetime\" && !w.config.xaxis.convertedCatToNumeric && !w.globals.isBarHorizontal;\n fmt.xaxisTooltipFormatter = (val) => {\n return this.defaultGeneralFormatter(val);\n };\n fmt.ttKeyFormatter = (val) => {\n return this.defaultGeneralFormatter(val);\n };\n fmt.ttZFormatter = (val) => {\n return val;\n };\n fmt.legendFormatter = (val) => {\n return this.defaultGeneralFormatter(val);\n };\n if (w.config.xaxis.labels.formatter !== void 0) {\n fmt.xLabelFormatter = w.config.xaxis.labels.formatter;\n } else {\n fmt.xLabelFormatter = (val) => {\n var _a;\n if (Utils$1.isNumber(val)) {\n if (!w.config.xaxis.convertedCatToNumeric && (w.config.xaxis.type === \"numeric\" || inferredNumericX)) {\n const ticks = (_a = w.globals.xAxisScale) == null ? void 0 : _a.result;\n if (inferredNumericX && Array.isArray(ticks) && ticks.every(Number.isInteger)) {\n return val.toFixed(0);\n }\n if (Utils$1.isNumber(w.config.xaxis.decimalsInFloat)) {\n return val.toFixed(w.config.xaxis.decimalsInFloat);\n } else {\n const diff = w.globals.maxX - w.globals.minX;\n if (diff > 0) {\n const step = diff / 10;\n const decimals = Math.max(0, -Math.floor(Math.log10(step)));\n return val.toFixed(decimals);\n }\n return val.toFixed(0);\n }\n }\n if (w.globals.isBarHorizontal) {\n const range = w.globals.maxY - w.globals.minY;\n if (range < 4) {\n return val.toFixed(1);\n }\n }\n return val.toFixed(0);\n }\n return val;\n };\n }\n if (typeof w.config.tooltip.x.formatter === \"function\") {\n fmt.ttKeyFormatter = w.config.tooltip.x.formatter;\n } else if (w.config.xaxis.labels.formatter === void 0 && inferredNumericX) {\n const xLabelFormatter = (\n /** @type {(val: any) => any} */\n fmt.xLabelFormatter\n );\n fmt.ttKeyFormatter = (val) => Number.isInteger(val) ? val.toFixed(0) : xLabelFormatter(val);\n } else {\n fmt.ttKeyFormatter = fmt.xLabelFormatter;\n }\n if (typeof w.config.xaxis.tooltip.formatter === \"function\") {\n fmt.xaxisTooltipFormatter = w.config.xaxis.tooltip.formatter;\n }\n if (Array.isArray(w.config.tooltip.y)) {\n fmt.ttVal = w.config.tooltip.y;\n } else {\n if (w.config.tooltip.y.formatter !== void 0) {\n fmt.ttVal = w.config.tooltip.y;\n }\n }\n if (w.config.tooltip.z.formatter !== void 0) {\n fmt.ttZFormatter = w.config.tooltip.z.formatter;\n }\n if (w.config.legend.formatter !== void 0) {\n fmt.legendFormatter = w.config.legend.formatter;\n }\n fmt.yLabelFormatters = [];\n w.config.yaxis.forEach((yaxe, i2) => {\n if (yaxe.labels.formatter !== void 0) {\n fmt.yLabelFormatters[i2] = yaxe.labels.formatter;\n } else if (w.config.chart.type === \"violin\") {\n const round = (v) => typeof v === \"number\" && isFinite(v) ? `${Math.round(v * 100) / 100}` : v;\n fmt.yLabelFormatters[i2] = (val) => {\n if (!w.globals.xyCharts) return val;\n return Array.isArray(val) ? val.map(round) : round(val);\n };\n } else {\n fmt.yLabelFormatters[i2] = (val) => {\n if (!w.globals.xyCharts) return val;\n if (Array.isArray(val)) {\n return val.map((v) => {\n return this.defaultYFormatter(v, yaxe);\n });\n } else {\n return this.defaultYFormatter(val, yaxe);\n }\n };\n }\n });\n return w.globals;\n }\n heatmapLabelFormatters() {\n const w = this.w;\n if (w.config.chart.type === \"heatmap\") {\n w.globals.yAxisScale[0].result = /** @type {any} */\n w.seriesData.seriesNames.slice();\n const longest = (\n /** @type {any} */\n w.seriesData.seriesNames.reduce(\n (a2, b) => a2.length > b.length ? a2 : b,\n 0\n )\n );\n w.globals.yAxisScale[0].niceMax = longest;\n w.globals.yAxisScale[0].niceMin = longest;\n }\n }\n}\nconst name = \"en\";\nconst options = { \"months\": [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"], \"shortMonths\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"], \"days\": [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"], \"shortDays\": [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"], \"toolbar\": { \"exportToSVG\": \"Download SVG\", \"exportToPNG\": \"Download PNG\", \"exportToCSV\": \"Download CSV\", \"menu\": \"Menu\", \"selection\": \"Selection\", \"selectionZoom\": \"Selection Zoom\", \"zoomIn\": \"Zoom In\", \"zoomOut\": \"Zoom Out\", \"pan\": \"Panning\", \"reset\": \"Reset Zoom\", \"measure\": \"Measure\" } };\nconst en = {\n name,\n options\n};\nclass Options {\n constructor() {\n this.yAxis = {\n show: true,\n showAlways: false,\n showForNullSeries: true,\n seriesName: void 0,\n opposite: false,\n reversed: false,\n logarithmic: false,\n logBase: 10,\n tickAmount: void 0,\n stepSize: void 0,\n forceNiceScale: false,\n alignZero: false,\n max: void 0,\n min: void 0,\n floating: false,\n decimalsInFloat: void 0,\n labels: {\n show: true,\n showDuplicates: false,\n minWidth: 0,\n maxWidth: 160,\n offsetX: 0,\n offsetY: 0,\n align: void 0,\n rotate: 0,\n padding: 20,\n style: {\n colors: [],\n fontSize: \"11px\",\n fontWeight: 400,\n fontFamily: void 0,\n cssClass: \"\"\n },\n formatter: void 0\n },\n axisBorder: {\n show: false,\n color: \"#e0e0e0\",\n width: 1,\n offsetX: 0,\n offsetY: 0\n },\n axisTicks: {\n show: false,\n color: \"#e0e0e0\",\n width: 6,\n offsetX: 0,\n offsetY: 0\n },\n title: {\n text: void 0,\n rotate: -90,\n offsetY: 0,\n offsetX: 0,\n style: {\n color: void 0,\n fontSize: \"11px\",\n fontWeight: 900,\n fontFamily: void 0,\n cssClass: \"\"\n }\n },\n tooltip: {\n enabled: false,\n offsetX: 0\n },\n crosshairs: {\n show: true,\n position: \"front\",\n stroke: {\n color: \"#b6b6b6\",\n width: 1,\n dashArray: 0\n }\n }\n };\n this.pointAnnotation = {\n id: void 0,\n x: 0,\n y: null,\n yAxisIndex: 0,\n seriesIndex: void 0,\n mouseEnter: void 0,\n mouseLeave: void 0,\n click: void 0,\n marker: {\n size: 4,\n fillColor: \"#fff\",\n strokeWidth: 2,\n strokeColor: \"#333\",\n shape: \"circle\",\n offsetX: 0,\n offsetY: 0,\n // radius: 2, // DEPRECATED\n cssClass: \"\"\n },\n label: {\n borderColor: \"#c2c2c2\",\n borderWidth: 1,\n borderRadius: 2,\n text: void 0,\n textAnchor: \"middle\",\n offsetX: 0,\n offsetY: 0,\n mouseEnter: void 0,\n mouseLeave: void 0,\n click: void 0,\n style: {\n background: \"#fff\",\n color: void 0,\n fontSize: \"11px\",\n fontFamily: void 0,\n fontWeight: 400,\n cssClass: \"\",\n padding: {\n left: 5,\n right: 5,\n top: 2,\n bottom: 2\n }\n }\n },\n customSVG: {\n // this will be deprecated in the next major version as it is going to be replaced with a better alternative below (image)\n SVG: void 0,\n cssClass: void 0,\n offsetX: 0,\n offsetY: 0\n },\n image: {\n path: void 0,\n width: 20,\n height: 20,\n offsetX: 0,\n offsetY: 0\n },\n tooltip: {\n // Show a hover tooltip over the annotation marker, like a regular\n // data point. Lets you surface richer detail than fits in the label.\n enabled: false,\n // Static tooltip content (HTML allowed; array joined with
).\n // Falls back to label.text when omitted.\n text: void 0,\n // formatter({ annotation, seriesIndex, id, w }) => string (HTML).\n // Takes precedence over `text` when provided.\n formatter: void 0,\n // 'light' | 'dark'. Falls back to the global tooltip.theme.\n theme: void 0,\n offsetX: 0,\n offsetY: 0\n }\n };\n this.yAxisAnnotation = {\n id: void 0,\n y: 0,\n y2: null,\n strokeDashArray: 1,\n fillColor: \"#c2c2c2\",\n borderColor: \"#c2c2c2\",\n borderWidth: 1,\n opacity: 0.3,\n offsetX: 0,\n offsetY: 0,\n width: \"100%\",\n yAxisIndex: 0,\n label: {\n borderColor: \"#c2c2c2\",\n borderWidth: 1,\n borderRadius: 2,\n text: void 0,\n textAnchor: \"end\",\n position: \"right\",\n offsetX: 0,\n offsetY: -3,\n mouseEnter: void 0,\n mouseLeave: void 0,\n click: void 0,\n style: {\n background: \"#fff\",\n color: void 0,\n fontSize: \"11px\",\n fontFamily: void 0,\n fontWeight: 400,\n cssClass: \"\",\n padding: {\n left: 5,\n right: 5,\n top: 2,\n bottom: 2\n }\n }\n }\n };\n this.xAxisAnnotation = {\n id: void 0,\n x: 0,\n x2: null,\n strokeDashArray: 1,\n fillColor: \"#c2c2c2\",\n borderColor: \"#c2c2c2\",\n borderWidth: 1,\n opacity: 0.3,\n offsetX: 0,\n offsetY: 0,\n label: {\n borderColor: \"#c2c2c2\",\n borderWidth: 1,\n borderRadius: 2,\n text: void 0,\n textAnchor: \"middle\",\n orientation: \"vertical\",\n position: \"top\",\n offsetX: 0,\n offsetY: 0,\n mouseEnter: void 0,\n mouseLeave: void 0,\n click: void 0,\n style: {\n background: \"#fff\",\n color: void 0,\n fontSize: \"11px\",\n fontFamily: void 0,\n fontWeight: 400,\n cssClass: \"\",\n padding: {\n left: 5,\n right: 5,\n top: 2,\n bottom: 2\n }\n }\n }\n };\n this.text = {\n x: 0,\n y: 0,\n text: \"\",\n textAnchor: \"start\",\n foreColor: void 0,\n fontSize: \"13px\",\n fontFamily: void 0,\n fontWeight: 400,\n appendTo: \".apexcharts-annotations\",\n backgroundColor: \"transparent\",\n borderColor: \"#c2c2c2\",\n borderRadius: 0,\n borderWidth: 0,\n paddingLeft: 4,\n paddingRight: 4,\n paddingTop: 2,\n paddingBottom: 2\n };\n }\n init() {\n return {\n annotations: {\n yaxis: [this.yAxisAnnotation],\n xaxis: [this.xAxisAnnotation],\n points: [this.pointAnnotation],\n texts: [],\n images: [],\n shapes: []\n },\n // Weave (#1): public plugin platform. Per-chart activation list:\n // { name, options?, order? }. Requires the Weave host to be bundled\n // (`import 'apexcharts/features/weave'`, included in the full bundle) and\n // the plugin registered via ApexCharts.registerPlugin().\n plugins: [],\n // Trellis (#22): small multiples / faceting. Requires the trellis\n // feature (`import 'apexcharts/features/trellis'`, included in the full\n // bundle). Setting `by` makes this chart a trellis HOST: the series\n // array is split into one panel per facet-key value, each panel is a\n // real chart of this chart.type, and the trellis owns everything shared\n // (scale domains, pixel-aligned plot rects, color-by-series-name, one\n // legend/title/toolbar, headers, responsive columns).\n trellis: {\n // Facet accessor: a series-object key name, or (series, i) => key.\n // Series WITHOUT the key repeat in every panel (reference series).\n by: void 0,\n // 2-D faceting (P4): row and/or column facet accessors, forming a\n // FIXED grid of every (row, column) combination in row-major order\n // (no responsive recolumning; panels shrink instead). Mutually\n // exclusive with `by`. Column labels draw once across the top, row\n // labels once down the left. Reference semantics per dimension: a\n // series with only the row key repeats across that row; only the\n // column key, down that column; neither, everywhere.\n row: void 0,\n column: void 0,\n // Missing (row, column) combinations: 'placeholder' mounts a real\n // empty panel (same scales, same geometry, a quiet \"no data\" label);\n // 'skip' keeps the slot with a tinted blank; 'hide' keeps the slot\n // with nothing at all.\n emptyPanels: \"placeholder\",\n // Tidy-row input (alternative to `series`): a row table pivoted by\n // the `by`/`x`/`y`/`seriesBy` COLUMN NAMES. Rows win over `series`\n // when both are given. Duplicate (panel, series, x) rows keep the\n // last and warn; aggregate the rows first for sums/means.\n data: void 0,\n // [{ date, region, revenue }, ...]\n x: void 0,\n // x-value column name (tidy form only)\n y: void 0,\n // y-value column name (tidy form only)\n seriesBy: void 0,\n // optional series-name column (tidy form only)\n // Layout\n columns: \"auto\",\n // 'auto' (fit minPanelWidth) | number\n minPanelWidth: 220,\n // px; drives 'auto' and the responsive collapse\n gap: 12,\n // px between cells\n aspectRatio: 1.6,\n // panel w:h when no explicit height governs\n panelHeight: void 0,\n // px; wins over aspectRatio/chart.height\n // Floor for a height-derived panel. Below ~80px a panel stops being\n // readable and Dimensions starts producing degenerate plot boxes, so\n // a grid that cannot fit its host overflows rather than shrink past\n // this. Lower it when fitting a short container matters more.\n minPanelHeight: 80,\n // px\n order: \"first-seen\",\n // | 'asc' | 'desc' | string[] | comparator\n limit: void 0,\n // render only the first N panels (warns)\n // Virtualization: 'auto' mounts only the panels intersecting the\n // viewport (plus one row) once the grid exceeds 64 panels; true\n // always virtualizes; false always renders eagerly. Unmounted cells\n // keep their header and a fixed-height skeleton (page height and\n // scroll position never shift); a panel that scrolls out is\n // destroyed with its view state stashed, and a remount restores its\n // zoom window. getPanel(key) returns null for unmounted panels.\n virtualize: \"auto\",\n // 'auto' | true | false\n // Scale resolution per channel: 'shared' | 'independent'; y also\n // takes 'independent-row' | 'independent-column' in a 2-D grid (one\n // shared domain per row/column: comparable along the group, free\n // across groups). Non-shared y still renders pixel-aligned panels\n // (the gutter pass equalizes axis widths); 'independent' and\n // 'independent-column' force their own y labels on every panel,\n // 'independent-row' keeps them on the first column (ticks are\n // identical along a row).\n scales: {\n x: \"shared\",\n y: \"shared\",\n color: \"shared\",\n size: \"shared\"\n },\n // Per-cell facet headers.\n header: {\n show: true,\n formatter: void 0,\n // (key, { dimension, index, count }) => string\n style: {\n fontSize: void 0,\n fontWeight: void 0,\n color: void 0\n }\n },\n // Axis-label policy: 'edges' shows y labels on the first column and x\n // labels on each column's bottom panel (label SPACE is always\n // reserved everywhere, so panels stay aligned); 'all' | 'none'.\n axes: {\n labels: \"edges\"\n },\n legend: \"shared\",\n // 'shared' | 'none' (per-panel legends are hidden)\n toolbar: \"shared\",\n // 'shared' | 'none' (zoom / pan / reset)\n // 'panel': tooltip card only in the hovered panel, crosshair sweeps\n // all panels. 'sync': every panel shows its own card at the hovered x.\n // 'grid': ONE card near the cursor with one row per panel at the\n // hovered x (composed from the panels' own tooltips, so every\n // formatter is honored; unmounted virtualized panels have no row).\n tooltip: \"panel\",\n zoom: \"sync\",\n // 'sync' (drag/wheel zoom moves every panel) | 'none'\n // Panel promotion: clicking a cell's header expands that panel to\n // the grid's full width, with an \"All panels\" breadcrumb back.\n // OFF by default: a trellis embedded in a page is usually read, not\n // driven, and taking over the grid on a stray header click is a large\n // surprise for an interaction nobody asked for. Opt in with\n // `promote: true`, or drive it from\n // chart.promotePanel(key) / chart.restorePanels() without it.\n promote: false,\n // Pie/donut/polarArea only: scale each panel's radius so its AREA is\n // proportional to the panel's total (equal-size pies cannot encode\n // magnitude, which is the honest objection to a pie trellis).\n radiusByTotal: false,\n // Tick-interval target for the shared nice y scale. Panels are small:\n // 3 intervals (up to ~4 labels) keeps the axis from outweighing the data.\n targetTicks: 3,\n // Per-panel option override, applied last:\n // (key, { index, seriesNames }) => partial options\n panel: void 0\n },\n chart: {\n animations: {\n // Master switch \u2014 set false to render charts without any animation.\n // Each chart type gets a tailored initial-mount animation by default:\n // line/area/rangeArea/radar: pen-stroke draw + radial fill bloom\n // bar/stacked/range/funnel: grow from baseline (+ stagger)\n // scatter/bubble: scale-up pop with overshoot\n // heatmap: diagonal-wave cell reveal\n // treemap: largest-tile-first cascade\n // pie/donut/polar/gauge: arc sweep + needle settle\n // Speed is controlled by `speed`; per-element stagger by\n // `animateGradually.enabled` / `animateGradually.delay`.\n enabled: true,\n speed: 800,\n // Cadence (#6): easing for the generic tweens (data-update value\n // transitions, path morphs, marker animate). A registered name, a\n // cubic-bezier [x1,y1,x2,y2] array, or a function (t in [0,1]).\n // 'easeInOutSine' is the historical curve, so the default is\n // behavior-neutral. The tuned initial-draw pen/pop easings are fixed.\n easing: \"easeInOutSine\",\n animateGradually: {\n // Drives per-element stagger across all chart types. When enabled,\n // bars/heatmap-cells/scatter-points/treemap-tiles reveal in\n // sequence; line/area markers fade in progressively along the\n // draw. `delay` is the requested step in ms (auto-capped per\n // chart so total stagger \u2264 ~half the animation duration).\n delay: 150,\n enabled: true\n },\n dynamicAnimation: {\n // Data-change (updateSeries) animation. Independent from the\n // initial-mount animations above.\n enabled: true,\n speed: 350,\n // Easing for data-change morphs only (same accepted forms as\n // `animations.easing`). Unset -> inherit the chart-wide easing,\n // except detected streaming scrolls (rolling window / append\n // under xaxis.range) which default to 'linear' so the window\n // slides at constant velocity instead of pulsing each tick.\n easing: void 0\n },\n chartTypeMorph: {\n // Cross-type morph (updateOptions changing chart.type). Bridges\n // the destroy+recreate flicker by sampling source + target paths\n // into N evenly-spaced perimeter points and tweening point-by-point\n // with rotation-search alignment, so the transition is always smooth\n // and non-self-intersecting even between very different shapes (bar\n // rect \u2194 pie wedge / radial arc). Supported pairs include bar \u2194\n // pie / donut / radialBar / polarArea / funnel / pyramid (plus the\n // trivial pie \u2194 donut \u2194 polarArea cases). Falls back to instant\n // snap when types or data shape are incompatible.\n enabled: true,\n speed: 600\n },\n // Honor the OS-level prefers-reduced-motion setting. When true\n // (default) and the preference is on, applyAnimationPolicy forces off\n // BOTH `enabled` and `dynamicAnimation.enabled`, so neither the\n // initial mount nor a data update animates. Setting it false also\n // puts `apexcharts-ignore-reduced-motion` on the canvas, which is how\n // the stylesheet's reduced-motion rules know to stand down too.\n respectReducedMotion: true,\n // Above this many data points, per-element morph + stagger (which\n // spins up one JS-driven animation timeline per path \u2014 three chained\n // tweens each in morphSVG) is replaced by a single GPU-composited\n // opacity fade of the whole series. Thousands of candlesticks/bars\n // otherwise jank the main thread on initial render and on every zoom.\n // The fade reuses the existing delayedElements reveal so the result\n // still animates in, just at O(1) cost instead of O(n). Set to 0 to\n // always animate per-element regardless of dataset size.\n largeDatasetThreshold: 1e3\n },\n background: \"\",\n locales: [en],\n defaultLocale: \"en\",\n // Perspectives (#10): serializable/shareable view state. Passive:\n // requires `import 'apexcharts/features/perspectives'`. serializeOptions\n // is the whitelist of function-free option paths stored in a token.\n perspectives: {\n serializeOptions: [\"theme\", \"xaxis\", \"yaxis\", \"title\", \"subtitle\"]\n },\n // Rewind (#3): undo/redo history. Opt-in (bundle + behavior): requires\n // `import 'apexcharts/features/history'` AND chart.history.enabled.\n history: {\n enabled: false,\n maxDepth: 100,\n coalesceMs: 250,\n keyboard: true\n },\n // Strata (#2): hybrid SVG+canvas series renderer. 'svg' (default) |\n // 'canvas' | 'auto'. 'auto'/'canvas' need the canvas renderer feature\n // (`import 'apexcharts/features/renderer-canvas'`); without it, or with\n // a canvas-unsupported feature (pattern/image fill, color-matrix state\n // filters), selection falls back to 'svg'. Only the series layer is\n // canvas-capable in v1; chrome stays SVG.\n renderer: \"svg\",\n rendererThreshold: 8e3,\n layers: {\n series: \"auto\",\n grid: \"svg\",\n annotations: \"svg\",\n dataLabels: \"svg\"\n },\n dropShadow: {\n enabled: false,\n enabledOnSeries: void 0,\n top: 2,\n left: 2,\n blur: 4,\n color: \"#000\",\n opacity: 0.7\n },\n events: {\n animationEnd: void 0,\n beforeMount: void 0,\n mounted: void 0,\n updated: void 0,\n click: void 0,\n mouseMove: void 0,\n mouseLeave: void 0,\n xAxisLabelClick: void 0,\n legendClick: void 0,\n markerClick: void 0,\n selection: void 0,\n dataPointSelection: void 0,\n dataPointMouseEnter: void 0,\n dataPointMouseLeave: void 0,\n beforeZoom: void 0,\n beforeResetZoom: void 0,\n zoomed: void 0,\n scrolled: void 0,\n brushScrolled: void 0,\n crossFilter: void 0,\n filterChange: void 0,\n highlightFilterChanged: void 0,\n annotationDragged: void 0,\n annotationEdited: void 0,\n annotationCreated: void 0,\n annotationStyled: void 0,\n annotationDeleted: void 0,\n measured: void 0,\n keyDown: void 0,\n keyUp: void 0\n },\n foreColor: \"#373d3f\",\n fontFamily: \"Helvetica, Arial, sans-serif\",\n height: \"auto\",\n parentHeightOffset: 15,\n redrawOnParentResize: true,\n redrawOnWindowResize: true,\n // Printing. The sheet is a layout the page itself never sees: nothing\n // measures it, no resize is reported for it, and matchMedia('print') is\n // still false while `beforeprint` runs. So a chart sized from a wide\n // screen prints at its screen width and the right-hand side falls off\n // the paper (#3352). `width` is the width, in CSS pixels, to lay the\n // chart out at for printing, and a chart already narrower than that is\n // left alone. The default suits A4 and Letter portrait with the usual\n // margins; whatever is left over is shrunk to fit by the print\n // stylesheet, so the value only has to be close.\n print: {\n enabled: true,\n width: 700\n },\n id: void 0,\n group: void 0,\n nonce: void 0,\n // Per-chart license key override for the gated premium features\n // (storyboard, link/crossfilter, ink, measure, contextMenu,\n // perspectives, history). Most specific wins: chart.license ->\n // ApexCharts.setLicense() -> window.Apex.license -> unlicensed (trial\n // watermark). Shared across the ApexCharts family. See setLicense().\n license: void 0,\n offsetX: 0,\n offsetY: 0,\n injectStyleSheet: true,\n selection: {\n enabled: false,\n type: \"x\",\n // selectedPoints: undefined, // default datapoints that should be selected automatically\n fill: {\n color: \"#24292e\",\n opacity: 0.1\n },\n stroke: {\n width: 1,\n color: \"#24292e\",\n opacity: 0.4,\n dashArray: 3\n },\n xaxis: {\n min: void 0,\n max: void 0\n },\n yaxis: {\n min: void 0,\n max: void 0\n }\n },\n sparkline: {\n enabled: false\n },\n brush: {\n enabled: false,\n autoScaleYaxis: true,\n target: void 0,\n targets: void 0\n },\n // Linked Views (#4): crossfilter / linked highlighting. Requires the\n // `link` feature. Two modes:\n // HIGHLIGHT (P1): `enabled` with no `dimension`. Charts sharing a\n // `chart.group` form a set; brushing a range (needs\n // `chart.selection.enabled`) dims out-of-range marks in place.\n // FILTER (P2): set `dimension` (its presence selects this path). Each\n // chart declares a dimension + reduction over a shared record set\n // registered with ApexCharts.crossfilter({ id, records }); clicking a\n // bucket re-aggregates the other charts. See docs/spec.\n link: {\n enabled: false,\n mode: \"highlight\",\n dimOpacity: 0.2,\n // FILTER-mode config (all optional except dimension):\n id: void 0,\n // crossfilter coordinator id (defaults to chart.group)\n dimension: void 0,\n // (row) => key; presence selects filter mode\n reduce: void 0,\n // 'count' | { sum|avg|min|max: field } | (rows)=>n\n type: void 0,\n // 'category' | 'range' (else inferred from bins)\n bins: void 0,\n // range dims: { width } | { count } | { thresholds }\n order: void 0,\n // category order: 'first-seen' | 'asc' | 'desc' | fn\n seriesName: void 0\n // axis-chart series name (default 'Count')\n },\n // Ink Layer (#7): direct-manipulation annotations. When enabled, every\n // point annotation is draggable (unless it sets draggable:false); or opt\n // in per annotation with annotations.points[].draggable. Clicking an\n // ink-managed annotation opens a floating editor card: rename inline,\n // recolor, toggle bold, step the font size, size/reshape the marker, or\n // delete the note. Axis-line annotations get separate Label and Line\n // color rows, so restyling the label chip never touches the stroke.\n // Requires the `ink` feature. Fires annotationDragged,\n // annotationEdited, annotationStyled and annotationDeleted.\n ink: {\n enabled: false,\n // Show a minimal \"add note\" tool palette; clicking it arms create\n // mode (the next plot click drops an editable, draggable annotation).\n palette: false,\n // Snap a dragged point / axis-line annotation to the nearest gridline\n // (numeric x + linear y). Undo/redo of ink edits is automatic when the\n // history (Rewind) feature is enabled.\n snap: false,\n // Accent swatches offered by the floating note editor; defaults to a\n // built-in 6-color palette when undefined.\n noteColors: void 0\n },\n // Measure ruler (#18): a measure/delta ruler. Requires the `measure`\n // feature. Hold `key` (default 'm') and drag A->B on the plot, or call\n // chart.startMeasure()/chart.stopMeasure() to arm it. The live ruler\n // reads dx, dy, %change and slope; on release it pins as a data-anchored\n // overlay that re-projects on zoom/resize. Fires `measured`.\n measure: {\n enabled: false,\n // 'span' (default): finance-style vertical band between two x-points\n // with a \"change (%) + range\" readout, endpoints snapped to the first\n // series. 'free': a diagonal ruler between two arbitrary points.\n mode: \"span\",\n key: \"m\",\n pinOnRelease: true,\n // Styling tokens. Every element also carries a stable CSS class\n // (apexcharts-measure-band / -vline / -line / -label-bg / -label,\n // group gets apexcharts-measure-up|down|flat). Colors are left\n // undefined so they resolve config -> `--apx-measure-*` CSS custom\n // property -> built-in default; set them here to force a color from JS.\n colors: {\n up: void 0,\n down: void 0,\n neutral: void 0,\n guide: void 0\n },\n band: true,\n // span mode: shaded band between the two x-positions\n guides: true,\n // span mode: vertical dashed reference lines\n markers: true,\n // endpoint dots on the series line\n // Content: value formatters and a full readout override. `label`\n // receives { from, to, dx, dy, percentChange, slope, mode } and\n // returns a string or string[] (lines).\n format: { x: void 0, y: void 0, percent: void 0 },\n label: void 0\n },\n // Radial Actions (#chrome): right-click / long-press context menu.\n // Requires the `contextMenu` feature. Each action receives the clicked\n // data coordinates, so verbs act at the point (not chart-wide like a\n // toolbar button). `items` is an ordered list of built-in ids\n // ('annotate' | 'xline' | 'yline' | 'measure') and/or custom\n // { id, label, icon, onClick(ctx, { x, y, seriesIndex, dataPointIndex,\n // clientX, clientY }) }. 'measure' is shown only when the measure tool\n // is enabled. `labels` overrides built-in text; `noteText` is the label\n // dropped by 'annotate'.\n contextMenu: {\n enabled: false,\n items: [\"annotate\", \"xline\", \"yline\", \"measure\"],\n labels: {\n annotate: void 0,\n xline: void 0,\n yline: void 0,\n measure: void 0\n },\n noteText: \"Note\",\n // 'xline' (\"Annotate here\") drops a dashed vertical LINE at the\n // clicked x; 'yline' (\"Mark this level\") a dashed horizontal line at\n // the clicked y. Lines only, never a range rectangle. Like the note,\n // a line is ink-managed when the ink feature is bundled: it opens\n // the floating editor (rename; separate Label and Line color rows,\n // so restyling the chip cannot blank the stroke; delete), drags\n // along its axis, and undoes via Rewind. `line` styles both items.\n line: {\n text: \"\",\n // label drawn on the line; empty for no label\n strokeDashArray: 4,\n color: void 0\n // undefined keeps the annotation default color\n }\n },\n stacked: false,\n stackOnlyBar: true,\n // mixed chart with stacked bars and line series - incorrect line draw #907\n stackType: \"normal\",\n // Real-time streaming mode. When enabled, appendData() bounds memory\n // automatically: each series is trimmed to `maxPoints` (when set) or\n // to the visible `xaxis.range` window plus a two-point off-screen\n // runway (so exiting segments slide off the left edge instead of\n // popping). The scroll animation itself needs no opt-in; updates\n // that continue the previous window (appendData, or updateSeries with\n // a shifted fixed-length window) always translate at constant\n // velocity; see modules/animations/StreamScroll.\n streaming: {\n enabled: false,\n maxPoints: void 0\n },\n toolbar: {\n show: true,\n offsetX: 0,\n offsetY: 0,\n tools: {\n download: true,\n selection: true,\n zoom: true,\n zoomin: true,\n zoomout: true,\n pan: true,\n reset: true,\n // Shown only when the measure ruler is active (chart.measure.enabled\n // and the `measure` feature bundled). Toggles the measure tool; set\n // false to keep the ruler key-driven only. See chart.measure.\n measure: true,\n customIcons: []\n },\n export: {\n csv: {\n filename: void 0,\n columnDelimiter: \",\",\n headerCategory: \"category\",\n headerValue: \"value\",\n categoryFormatter: void 0,\n valueFormatter: void 0\n },\n png: {\n filename: void 0\n },\n svg: {\n filename: void 0\n },\n scale: void 0,\n width: void 0,\n // An exported SVG is a standalone document: it cannot reach the\n // page's @font-face rules, so a custom font falls back to a\n // generic one in the PNG/SVG. When true, matching @font-face\n // rules are inlined as base64 data URIs. See #3617.\n embedFonts: true\n },\n autoSelected: \"zoom\"\n // accepts -> zoom, pan, selection, measure\n },\n type: \"line\",\n width: \"100%\",\n zoom: {\n enabled: true,\n type: \"x\",\n autoScaleYaxis: false,\n // Wheel and pinch zoom can both be triggered without meaning to (a\n // page scroll or a two-finger swipe over the chart), so 'auto' offers\n // them only when the viewer has a way back: the toolbar's reset\n // button. With the toolbar hidden they stay off, since a zoom nobody\n // asked for and nobody can undo is a trap. Set either to true to\n // force the gesture on regardless (for a page that supplies its own\n // reset control), or false to turn it off outright.\n allowMouseWheelZoom: \"auto\",\n // Momentum: two-finger pinch-zoom on touch devices. Zooms the x-axis\n // around the pinch centroid (matching the x-only wheel/toolbar zoom),\n // frame-by-frame rather than the 400ms wheel throttle.\n pinch: \"auto\",\n // Drag-to-zoom is deliberate, so it is not gated the way those two\n // are: it stays on with the toolbar hidden. The reset button that\n // undoes it does not, which leaves the viewer in a window with no\n // exit. So while the chart IS zoomed and nothing else on screen can\n // reset it, one reset control is drawn where the toolbar would have\n // been, and it goes when the range does. A chart nobody zooms is\n // untouched. Set false for a page that supplies its own reset (which\n // also turns off the Escape shortcut), or true to force the control\n // on whenever the chart is zoomed, even where `toolbar.tools.reset`\n // is off.\n resetControl: \"auto\",\n zoomedArea: {\n fill: {\n color: \"#90CAF9\",\n opacity: 0.4\n },\n stroke: {\n color: \"#0D47A1\",\n opacity: 0.4,\n width: 1\n }\n }\n },\n // Momentum: kinetic panning on touch. When a one-finger pan is released\n // with velocity, the chart keeps gliding and decelerates by `friction`\n // each frame, clamping (no elastic overshoot) at the data edges.\n pan: {\n inertia: true,\n friction: 0.92\n },\n accessibility: {\n enabled: true,\n description: void 0,\n announcements: {\n enabled: true\n },\n keyboard: {\n enabled: true,\n navigation: {\n enabled: true,\n wrapAround: false\n }\n }\n },\n dataReducer: {\n enabled: false,\n algorithm: \"lttb\",\n targetPoints: 250,\n threshold: 500\n }\n },\n parsing: {\n x: void 0,\n y: void 0\n },\n plotOptions: {\n line: {\n isSlopeChart: false,\n colors: {\n threshold: 0,\n colorAboveThreshold: void 0,\n colorBelowThreshold: void 0\n }\n },\n area: {\n fillTo: \"origin\"\n },\n bar: {\n horizontal: false,\n columnWidth: \"70%\",\n // should be in percent 0 - 100\n barHeight: \"70%\",\n // should be in percent 0 - 100\n distributed: false,\n borderRadius: 0,\n borderRadiusApplication: \"around\",\n // [around, end]\n // Which segments of a stack round. 'all' caps both ends of the\n // stack (baseline and far end); 'last' caps only the far end, so\n // the stack sits square on the baseline. Stacked charts only.\n borderRadiusWhenStacked: \"all\",\n // [all, last]\n rangeBarOverlap: true,\n rangeBarGroupRows: false,\n hideZeroBarsWhenGrouped: false,\n isDumbbell: false,\n dumbbellColors: void 0,\n // `chart.type: 'dumbbell'`, and any range bar drawn `isDumbbell`.\n // The connector's thickness is `barHeight` / `columnWidth`, and the\n // size of the marked ends is `markers.size`: they are the bar and its\n // markers, so they are configured as such.\n dumbbell: {\n connector: {\n // A solid colour for the join. Left undefined, the connector is a\n // gradient between the two endpoint colours, resolved per row so\n // that a row where the measures cross still runs the right way.\n color: void 0,\n // The join is context for the two marked ends, not a third mark\n // competing with them.\n opacity: 0.55\n },\n // A value written at each end of the connector. The pair of numbers\n // IS the comparison, and reading them off an axis costs the glance\n // the chart was meant to save.\n dataLabels: {\n enabled: false,\n // px clear of the marked end, outward from the connector.\n offset: 6,\n // Each label takes its own end's colour, so a value is tied to a\n // measure by more than its position.\n colorFromMarker: true,\n formatter: void 0,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 600,\n // Used when colorFromMarker is false.\n colors: void 0\n }\n },\n tooltip: {\n // Names the gap the two dots are on one row to show.\n differenceLabel: \"Difference\"\n }\n },\n isFunnel: false,\n isFunnel3d: true,\n colors: {\n ranges: [],\n backgroundBarColors: [],\n backgroundBarOpacity: 1,\n backgroundBarRadius: 0\n },\n dataLabels: {\n position: \"top\",\n // top, center, bottom\n maxItems: 100,\n hideOverflowingLabels: true,\n orientation: \"horizontal\",\n total: {\n enabled: false,\n formatter: void 0,\n offsetX: 0,\n offsetY: 0,\n style: {\n color: \"#373d3f\",\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 600\n }\n }\n }\n },\n bubble: {\n zScaling: true,\n minBubbleRadius: void 0,\n maxBubbleRadius: void 0,\n // Explicit z window for the size scale. EXPANDS the data's own z\n // extent, never clamps it, so several bubble charts can share one\n // size scale (a trellis pushes the union extent through these).\n minZ: void 0,\n maxZ: void 0\n },\n scatter: {\n // Spread overlapping points apart (\"jitter\"). Two uses, one engine:\n // - Strip plot: supply data as { x: 'Category', y: [v1, v2, ...] }.\n // Each category becomes a band and the values are scattered\n // horizontally within it. Marker styling comes from the standard\n // `markers` / `colors` config.\n // - Overplotting: ordinary { x, y } points get a small random offset\n // so dense clusters fan out. The underlying data (and tooltip\n // values) stay exact \u2014 only the drawn position moves.\n // Offsets are in axis units (x: 1 = one category step) and are\n // deterministic (stable across re-renders, SSR-safe).\n jitter: {\n enabled: false,\n x: 0,\n // max \u00B1 horizontal offset, in x-axis units\n y: 0,\n // max \u00B1 vertical offset, in y-axis units\n distributed: false,\n // single series: colour each band differently\n maxPoints: 5e3\n // per band; excess values are stride-thinned\n }\n },\n candlestick: {\n colors: {\n upward: \"#00B746\",\n downward: \"#EF403C\"\n },\n wick: {\n useFillColor: true\n }\n },\n boxPlot: {\n colors: {\n upper: \"#00E396\",\n lower: \"#008FFB\"\n },\n // Where the whiskers reach when the summary is DERIVED from raw\n // observations (a datum supplying `points` instead of a 5-number y,\n // which needs `apexcharts/features/stats`). Ignored for precomputed\n // summaries, which are drawn exactly as given.\n // 'minmax' \u2192 the extremes, so nothing is hidden\n // 'tukey' \u2192 the last observation inside 1.5 * IQR of each\n // quartile. Points beyond the fence fall outside the\n // whisker, so pair it with `points.show` or they become\n // invisible.\n whiskers: \"minmax\",\n // Optional individual observations (\"jitter\") overlaid on each box.\n // Inert unless a data point supplies a `points: number[]` array; off\n // by default so existing boxPlot charts are unchanged.\n points: {\n show: false,\n shape: \"circle\",\n // 'circle' | 'square'\n size: 2.5,\n // radius (px)\n jitter: 0.5,\n // 0..1 fraction of the box half-width to scatter within\n maxPoints: 3e3,\n // cap per box; excess is stride-thinned\n opacity: 0.9,\n // 'series-dark' (default) \u2192 a darker shade of the series colour,\n // 'series' \u2192 the series colour, or any literal colour string.\n fillColor: \"series-dark\",\n strokeColor: \"#fff\",\n strokeWidth: 1\n // Optional `colorScale` (undeclared so a user object merges cleanly)\n // colours each dot by its value: { colors, min, max, steps }\n }\n },\n violin: {\n // Multiply the density-derived half-width. 1 = density's own maxWeight\n // maps to half the category slot.\n bandwidthScale: 1,\n // Kernel density estimation, used only when the density is DERIVED\n // from raw observations (a datum supplying `points`, or a flat number\n // array as `y`, which needs `apexcharts/features/stats`). A\n // precomputed density profile is drawn exactly as given.\n // bandwidth \u2192 kernel width in value units. Unset uses Silverman's\n // rule of thumb, which takes the smaller of the\n // standard deviation and a scaled IQR so one distant\n // outlier cannot smear the curve flat. Note this is a\n // statistical parameter, unlike `bandwidthScale`\n // above, which only scales the drawn width.\n // resolution \u2192 density samples per violin (default 64).\n kde: {\n bandwidth: void 0,\n resolution: 64\n },\n // 'individual' \u2192 every violin uses the full slot width (scaled to its\n // own peak). 'group' \u2192 all violins share one scale (the densest in the\n // series), so widths stay proportional to density across categories.\n normalize: \"individual\",\n // Which side(s) of the category centerline the density is drawn on.\n // 'both' is the classic symmetric violin. 'left'/'right' (vertical\n // charts) and 'top'/'bottom' (horizontal charts) draw a half-violin:\n // the curve on that side, a straight baseline on the other. The\n // raincloud preset builds on this; a plain violin can use it too.\n side: \"both\",\n // A five-number-summary box beside the density. Drawn only when a\n // datum carries `y.summary` ([whiskerLow, q1, median, q3,\n // whiskerHigh], supplied directly or derived by a stats transform).\n // The rain/jitter layer is the outlier display, so the box draws no\n // outlier dots of its own.\n box: {\n show: false,\n width: \"15%\",\n // fraction of the slot reserved for the box lane\n // 'minmax' \u2192 whiskers at the data extremes. 'tukey' \u2192 1.5*IQR\n // fences clamped to the data. Consumed by the deriving transform;\n // a hand-supplied summary is drawn as given.\n whiskers: \"minmax\",\n strokeWidth: 1,\n // undefined \u2192 the series colour.\n fillColor: void 0,\n capWidth: 0.5\n // whisker cap length, 0..1 of the box lane width\n },\n // Individual observations (\"jitter\") overlaid on the violin shape.\n points: {\n show: true,\n shape: \"circle\",\n // 'circle' | 'square'\n size: 2.5,\n // radius (px)\n jitter: 0.5,\n // 0..1 fraction of the half-width to scatter within\n constrainToViolin: true,\n // clamp jitter to the density width at each value\n // 'center' scatters across the slot centerline (classic violin).\n // 'left'/'right'/'top'/'bottom' move the dots into their own lane\n // on that side (the raincloud \"rain\"); `constrainToViolin` is\n // ignored there because the dots no longer sit under the curve.\n position: \"center\",\n laneWidth: \"40%\",\n // fraction of the slot for the off-center lane\n maxPoints: 3e3,\n // cap per violin; excess is stride-thinned\n opacity: 0.9,\n // Default: a darker shade of each violin's own colour, with a white\n // outline. fillColor accepts 'series-dark' (default), 'series' (the\n // violin's colour as-is), or any literal colour string.\n fillColor: \"series-dark\",\n strokeColor: \"#fff\",\n strokeWidth: 1\n // Optional `colorScale` (left undeclared so a user object merges\n // cleanly) colours each dot by its value along a ramp:\n // { colors: ['#0d0887', \u2026 '#f0f921'], min, max, steps }\n }\n },\n histogram: {\n // How the bin width is chosen from the raw observations. A rule name\n // ('auto' | 'fd' | 'sturges' | 'scott' | 'rice' | 'sqrt') or a fixed\n // bin count. 'auto' takes the narrower of Freedman-Diaconis and\n // Sturges, falling back to Sturges when the IQR is 0 (which happens\n // as soon as most values are identical).\n bins: \"auto\",\n // Explicit bin width in value units. Wins over `bins` when set: use\n // it when the bin boundaries carry meaning (decades, 5-minute\n // buckets) rather than being a statistical choice.\n binWidth: void 0,\n // [min, max] to bin over, instead of the data's own extent. Lets\n // several histograms share one scale.\n range: void 0,\n // y units: 'count' (observations per bin), 'relative' (percent of\n // the series total), or 'density' (count / (n * binWidth), so the\n // total area is 1 and bins of different widths stay comparable).\n normalize: \"count\",\n // Running total across bins, i.e. a cumulative distribution.\n cumulative: false,\n // With more than one series, draw every distribution across the FULL\n // bin so they overlay, instead of dividing the bin between them. All\n // series already share one set of edges, and comparing two shapes is\n // the reason to put them on one axis; splitting the bin makes the\n // columns stop touching, which reads as a clustered bar chart rather\n // than a distribution. Set false for side-by-side bars.\n //\n // An overlay is unreadable opaque, so it also softens the fill and\n // drops the bin separator stroke. Both remain overridable.\n overlap: true\n },\n heatmap: {\n // Cell shape. 'circle' and 'diamond' are inscribed in the cell box;\n // 'hexagon' is a honeycomb tilemap: alternate rows offset by half a\n // cell so the hexagons tessellate (categorical layout only; a\n // numeric/datetime x axis falls back to rect). Non-rect shapes\n // ignore `radius` and always render as SVG (the canvas renderer's\n // cell store is rect-only, so it declines them like image fills).\n shape: \"rect\",\n // Cell corner radius; applies to the rect shape only.\n radius: 2,\n enableShades: true,\n shadeIntensity: 0.5,\n reverseNegativeShade: false,\n distributed: false,\n useFillColorAsStroke: false,\n colorScale: {\n inverse: false,\n ranges: [],\n min: void 0,\n max: void 0,\n // Replaces the default categorical legend with a continuous\n // gradient stripe + a hover indicator arrow. Honors\n // `chart.legend.position` (top / right / bottom / left).\n gradientLegend: {\n enabled: false,\n // Strip length along the legend's long axis. Accepts a number\n // (pixels) or a percentage string. For top/bottom placement the\n // percentage is resolved against the chart's SVG width; for\n // left/right placement, against the SVG height.\n width: \"70%\",\n height: \"70%\",\n thickness: 12,\n // Alignment of the strip within the legend area:\n // - top/bottom: 'start' = left, 'center', 'end' = right\n // - left/right: 'start' = top, 'center', 'end' = bottom\n align: \"center\",\n // Number of gradient stops sampled from the shade function when\n // no explicit `ranges` are provided.\n stops: 16,\n // Show min/max labels at the ends of the strip.\n showLabels: true,\n // Show a value tooltip next to the arrow when hovering a cell.\n showHoverValue: true,\n labelStyle: {\n fontSize: \"11px\",\n fontFamily: void 0,\n colors: void 0\n },\n arrow: {\n size: 8,\n color: void 0\n // falls back to chart.foreColor\n },\n formatter: void 0\n // (val) => string, for min/max + hover value\n }\n }\n },\n waterfall: {\n // `chart.type: 'waterfall'`. See features/waterfall.\n colors: {\n // Up is good, down is bad: the one convention a waterfall is read\n // by, so it is a default rather than something to configure. A\n // datum's own `fillColor` still wins.\n positive: \"#00A86F\",\n negative: \"#FF4560\",\n // The running-total bars (`isSubtotal` / `isTotal`) take the\n // series colour from the active palette, so they stay distinct\n // from the steps AND follow the theme. Name a colour to override.\n subtotal: void 0,\n total: void 0\n },\n connectors: {\n // The segments joining each bar's finish to the next one's start.\n // Without them the floating columns read as unrelated bars.\n show: true,\n // Falls back to grid.borderColor, so it is theme-aware.\n color: void 0,\n strokeWidth: 1,\n strokeDashArray: 3\n }\n },\n streamgraph: {\n // `chart.type: 'streamgraph'`. See features/streamgraph.\n //\n // Where the baseline goes:\n // 'wiggle' \u2014 minimize the total weighted slope of the bands, so\n // the thick ones stay level (the classic form)\n // 'silhouette' \u2014 centre the stack on one horizontal line\n // 'zero' \u2014 an ordinary stacked area, on the zero line\n // 'expand' \u2014 each column normalized to its own total, so the\n // chart reads as composition rather than volume\n offset: \"wiggle\",\n // The order the bands stack in, bottom first:\n // 'inside-out' \u2014 the series that peak earliest sit in the middle,\n // later peaks fan outward to whichever side is\n // currently thinner. The middle moves least under a\n // wiggle baseline, so this is what keeps a\n // streamgraph readable\n // 'inverse' \u2014 the series order, reversed\n // 'none' \u2014 the series order as given\n order: \"inside-out\",\n hover: {\n // Hovering a band fades the others, which is the surface's only\n // acknowledgement that it can be used.\n //\n // It fades the OTHERS rather than marking the hovered one because\n // the bands touch edge to edge and leave no room to mark anything:\n // a drop shadow falls onto both neighbours, and an edge stroke is\n // centred on a boundary the band SHARES. Fading needs no room, and\n // it leaves the hovered band's colour exactly as it was.\n show: true,\n // What the other bands drop to. Below ~0.5 the hovered band stops\n // reading as picked out.\n opacity: 0.35\n },\n labels: {\n // The series name written on the band itself, where that band is\n // thickest. On by default: a drifting band is much easier to find\n // by its own label than by matching a colour to a key, and the\n // legend is then free to be the thing you click rather than the\n // only place the names appear.\n show: true,\n // A band narrower than this many pixels is left unlabelled rather\n // than given a name truncated past the point of being a name.\n minWidth: 24,\n // The bounds `fontSize: 'auto'` scales between, in px.\n minFontSize: 9,\n maxFontSize: 30,\n style: {\n // 'auto' sizes each name to the band it sits on, which is the\n // convention of the form and the reason a streamgraph reads at a\n // glance: a chart's whole claim is that thickness is quantity,\n // and one fixed size states that claim in the same voice for a\n // band carrying half the total and one carrying a rounding\n // error. Give a literal ('12px') to draw every name the same.\n fontSize: \"auto\",\n fontFamily: void 0,\n fontWeight: 600,\n // Per-series override. By default each label takes black or\n // white, whichever reads on its own band.\n colors: void 0\n }\n }\n },\n funnel: {\n // 'rectangle' preserves the existing centered-rectangle funnel\n // geometry. 'trapezoid' produces continuous sloped sides between\n // consecutive stages (each stage's bottom width matches the next\n // stage's top width).\n shape: \"rectangle\",\n // For shape: 'trapezoid' only \u2014 what to do with the last stage's\n // bottom edge: 'flat' (parallel sides) or 'taper' (taper to a point).\n lastShape: \"flat\"\n },\n treemap: {\n enableShades: true,\n shadeIntensity: 0.5,\n distributed: false,\n reverseNegativeShade: false,\n useFillColorAsStroke: false,\n borderRadius: 4,\n dataLabels: {\n format: \"scale\",\n // scale | truncate\n // Skip a tile's label when it would render below this size.\n //\n // With `format: 'scale'` the font size follows the tile's area, so\n // on a dense treemap most tiles ask for text a few pixels tall,\n // which nobody can read. Drawing it is not free: each label has to\n // be built and measured against the DOM, and on a 10k-tile chart\n // that was the entire render cost (~7.5s, versus ~0.1s once the\n // unreadable ones are skipped).\n //\n // The default sits below the smallest label any bundled sample\n // draws, so it only ever removes text that was already illegible.\n // Set 0 to draw a label on every tile regardless of size.\n minFontSize: 4\n },\n colorScale: {\n inverse: false,\n ranges: [],\n min: void 0,\n max: void 0,\n // Colour a tile by a SECOND metric, independent of the value that\n // sizes it (area = how big, colour = how it did). Reads\n // `datum.colorValue` unless this names another key or supplies an\n // accessor `(datum, {seriesIndex, dataPointIndex, w}) => number`.\n colorValue: void 0,\n // Continuous interpolation between colour stops. Active as soon as\n // any datum carries a colour metric; `enabled: false` opts out and\n // `true` forces it on. `ranges` is unaffected and still applies\n // wherever it is set.\n gradient: {\n enabled: void 0,\n // Domain. Defaults to the extent of the colour metric.\n min: void 0,\n max: void 0,\n // The value the middle colour is pinned to. Defaults to 0 when\n // the domain straddles zero (a diverging metric), else none.\n midpoint: void 0,\n // With a midpoint, balance the domain around it so equal moves\n // in either direction read as equally saturated.\n symmetric: true,\n // Low -> mid -> high. Two colours make a sequential ramp.\n colors: void 0,\n // Explicit `[{ value, color }]` stops; overrides colors/midpoint.\n stops: void 0\n },\n // Continuous colour legend: a gradient strip with end labels and a\n // hover indicator, in place of the categorical legend. Same options\n // as the heatmap's.\n gradientLegend: {\n enabled: false,\n width: \"70%\",\n height: \"70%\",\n thickness: 12,\n align: \"center\",\n stops: 16,\n showLabels: true,\n showHoverValue: true,\n labelStyle: {\n fontSize: \"11px\",\n fontFamily: void 0,\n colors: void 0\n },\n arrow: {\n size: 8,\n color: void 0\n },\n formatter: void 0\n }\n },\n // Arbitrary-depth treemap: a datum may carry `children`.\n nested: {\n // Parent containers appear on their own as soon as the data is\n // nested; `false` forces the flat two-level layout.\n enabled: void 0,\n // Read `drilldown: ''` ids as extra levels instead of as a\n // click target for the drilldown feature. Off by default, because\n // on a treemap that id has always meant \"descend on click\".\n drilldownAsLevels: false\n },\n // How a parent is drawn once the data is nested. Per-level overrides\n // go in `levels` below.\n parents: {\n // 'auto' (default): on when the data carries `children`.\n show: \"auto\",\n // Inset between a parent's edge and the children inside it.\n padding: 4,\n fill: void 0,\n fillOpacity: 1,\n borderColor: void 0,\n borderWidth: 1,\n borderRadius: void 0,\n hover: {\n show: true,\n color: void 0,\n width: 2\n },\n header: {\n show: true,\n height: 22,\n // Skip the strip on tiles too narrow to show a name.\n minWidth: 40,\n align: \"left\",\n offsetX: 0,\n offsetY: 0,\n showValue: false,\n // (name, { value, depth, seriesIndex, node, w }) => string\n formatter: void 0,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 600,\n color: void 0,\n background: void 0,\n cssClass: \"\"\n }\n },\n tooltip: {\n // ({ name, value, depth, leafCount, percentOfParent,\n // percentOfTotal, node, w }) => html\n formatter: void 0\n }\n },\n // Per-depth overrides of `parents`, indexed from the outermost group\n // actually drawn (0 = the series, or the first authored level when a\n // single series is unwrapped).\n levels: [],\n // Click a group to fill the canvas with it; a breadcrumb goes back.\n // Ignored when the drilldown feature is active on the same chart:\n // both navigate the hierarchy, and drilldown owns the click there.\n zoom: {\n enabled: false,\n // Overrides `drilldown.breadcrumb` for this chart only. Same shape\n // (show / position / separator / rootLabel / offsetX / offsetY /\n // formatter), so a zoomed treemap and a drilled-in chart present\n // the same affordance without importing the drilldown feature.\n breadcrumb: void 0\n },\n seriesTitle: {\n show: true,\n offsetY: 1,\n offsetX: 1,\n borderColor: \"#000\",\n borderWidth: 1,\n borderRadius: 2,\n style: {\n background: \"rgba(0, 0, 0, 0.6)\",\n color: \"#fff\",\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 400,\n cssClass: \"\",\n padding: {\n left: 6,\n right: 6,\n top: 2,\n bottom: 2\n }\n }\n }\n },\n unit: {\n // 'grouped' (each category is its own cluster, laid out in a row) |\n // 'packed' (one blob; categories coloured + sorted, minority centred) |\n // 'columns' (each category is a vertical bar built from stacked dots) |\n // 'grid' (one lattice of cells filled in category order - a waffle /\n // part-to-whole square \"pie\"; `chart.type:'waffle'` presets this) |\n // 'scatter' (units on real value axes: a beeswarm, or a 2D\n // value-value scatter - see the `scatter` block below) |\n // 'arc' (a semicircular fan) |\n // 'custom' (positions come from `positions` below).\n layout: \"grouped\",\n // `layout: 'custom'` only. The layout provider: either a function\n // `(objects, rect) => [{id, x, y, r?}]` returning plot pixels, or the\n // name of one registered with `ApexCharts.registerUnitLayout`.\n //\n // This is the whole extension point. A layout is objects in,\n // positions out; it knows nothing about animation, because the engine\n // already tweens position, radius and colour and already keeps each\n // mark's identity across a relayout. So an arrangement this file\n // cannot know about - a country silhouette, a hex grid, a timeline, a\n // projection handed over by ApexMaps - is a plugin, not a core edit.\n //\n // `objects` carries one entry per mark: {id, index, seriesIndex,\n // dataPointIndex, label, value, datum, r}. `id` is the datum's own\n // id/name when the per-unit object form supplies one, so a provider\n // can address a specific unit rather than a positional slot.\n //\n // A mark whose id the provider omits animates out; ids matching no\n // mark are ignored.\n positions: void 0,\n // Update transition, controlling which previous dot each new dot\n // tweens from. 'group' (default): keyed per category, so dots stay in\n // their group and category-level enters/exits fade. 'flow': keyed by\n // global order, so the anonymous crowd migrates across a regroup (the\n // circles-to-bars effect). 'identity': keyed by each datum's id/name,\n // so a SPECIFIC unit migrates across any regroup/relayout keeping its\n // colour and size (needs the object form with unique ids/names).\n transition: \"group\",\n // What ONE unit looks like. Independent of `layout`, which is where\n // the units go: `positions:'heart'` with `shape:'pictogram'` arranges\n // glyphs into a heart, and every other pairing is equally valid.\n //\n // 'circle' | 'square' | 'image' (a raster / multi-colour icon,\n // fetched) | 'pictogram' (a vector glyph, drawn - see `pictogram`).\n shape: \"circle\",\n // Icon used when shape:'image'. Each unit renders this icon at the\n // given size. Set `tint:true` to recolour a monochrome icon to the\n // category colour (or a per-unit fillColor) so the pictogram matches\n // the legend; leave it off for multi-colour icons that should keep\n // their own colours.\n //\n // Prefer `shape:'pictogram'` for a monochrome glyph. Tinting an\n // needs an SVG filter per colour, and a filter forces an\n // offscreen surface PER ELEMENT on every paint: measured on this\n // repo's cost lab, 2000 tinted icons cost ~10x what 2000 drawn\n // glyphs cost, and the gather drops frames well before 2000.\n image: {\n src: void 0,\n width: 20,\n height: 20,\n tint: false\n },\n // `shape: 'pictogram'`. A glyph is DRAWN, not fetched: one per\n // unit, filled in that unit's own colour, so it needs no request, no\n // decode and no recolour filter.\n //\n // `mark` is the glyph: the name of one registered with\n // `ApexCharts.registerUnitMark`, a `{path, viewBox?, fillRule?}`\n // object, raw path data, or an ARRAY (one per series). A single datum\n // overrides all of it with its own `mark`, exactly as `fillColor`\n // overrides the category colour - so one crowd can mix glyphs.\n //\n // There is deliberately no size here. A glyph is fitted to the box\n // the dot itself would have occupied, so `size` and `spacing` size a\n // pictogram exactly as they size a dot and swapping circle ->\n // pictogram never re-flows the chart. `fit` picks which side of the\n // glyph binds to that box, `scale` nudges glyphs that read light, and\n // `padding` (0..0.9 of the pitch) opens the lattice up.\n //\n // One caveat worth knowing: a filled glyph is hit-tested over its\n // INK, not its box, so the tooltip tracks the glyph exactly - it\n // closes in the gap between a person's legs and reopens on the next\n // glyph. Chunky glyphs therefore both read and BEHAVE better than\n // fine ones; a hairline glyph reads as flickery while sweeping a\n // crowd. There is no portable fix (`pointer-events: bounding-box` is\n // Chrome only).\n pictogram: {\n mark: void 0,\n fit: \"contain\",\n // 'contain' (longest side) | 'width' | 'height'\n scale: 1,\n padding: 0,\n fallback: \"circle\"\n // drawn when a mark cannot be resolved\n },\n // dot radius in px, or 'auto' to size dots so the largest cluster\n // fits its allotted box.\n size: \"auto\",\n // The 'columns' layout can size its dots independently of `size`\n // (which the circle layouts / storyboard beats often pin to a\n // constant so dots do not resize while migrating). 'inherit' uses\n // `size`; 'auto' sizes the dots to fill the plot height; a number\n // pins a columns-only size. Circle / square only (image icons keep\n // their intrinsic size).\n columns: {\n size: \"inherit\"\n },\n // The 'grid' (waffle) layout: one lattice of cells filled in category\n // order. `columns` = cells per row. `total` (optional) fixes the cell\n // budget - e.g. 100 for a percentage waffle - and largest-remainder\n // allocates the cells to categories; leave it undefined for one cell\n // per unit (respects unitValue / maxUnits). `fillFrom` picks the first\n // row: 'bottom' (default) or 'top'.\n //\n // `split:true` switches to SMALL MULTIPLES: one mini-waffle per\n // category, arranged in a near-square trellis (or `tileColumns` per\n // row). Each tile then has `total` cells (default 100) and fills a\n // fraction equal to the category's value over `max` (default = the\n // largest count, so the leader fills its tile; set `max:100` with\n // percentage data for true \"of 100\" tiles). The unfilled cells show as\n // a faint `trackColor` backdrop, and each tile gets its own label.\n grid: {\n columns: 10,\n total: void 0,\n fillFrom: \"bottom\",\n // small-multiple (one waffle per category) mode + its knobs:\n split: false,\n // tiles per row; undefined = auto (near-square).\n tileColumns: void 0,\n // value -> filled-cell denominator; undefined = the largest count.\n max: void 0,\n // colour of the empty \"track\" cells; undefined = a neutral grey.\n trackColor: void 0\n },\n // The 'scatter' layout places each unit on real value axes (needs the\n // object-form data). Two modes via `y`:\n // - `y:'lanes'` (default): a BEESWARM. X is the per-unit value axis,\n // Y is a category lane. `spread:'swarm'` packs dots off the centre\n // line so equal values do not overlap; 'jitter' scatters randomly.\n // - `y:'value'`: a 2D value-value scatter. X = each datum's `x`, Y =\n // each datum's `y`, on two numeric axes; category = colour.\n // `sizeRange:[min,max]` turns dots into BUBBLES scaled (by area) from\n // each datum's `sizeField` (default 'z') - a bubble scatter / bubble\n // beeswarm. `tickAmount`/`xMin`/`xMax`/`xTitle`/`xFormatter` control the\n // X axis; the `y*` twins the Y axis (2D only); `laneLabelWidth` the\n // lane-label gutter (lanes mode); `gridlines` the grid.\n scatter: {\n y: \"lanes\",\n spread: \"swarm\",\n // Beeswarm orientation (1D lanes mode only): 'horizontal' lays the\n // value on the X axis with category lanes stacked on Y (default);\n // 'vertical' lays the value on the Y axis with category lanes as\n // columns across X. Ignored for the 2D value-value scatter (y:'value').\n orientation: \"horizontal\",\n tickAmount: 5,\n xMin: void 0,\n xMax: void 0,\n xTitle: void 0,\n // (value) => string\n xFormatter: void 0,\n yTickAmount: 5,\n yMin: void 0,\n yMax: void 0,\n yTitle: void 0,\n // (value) => string\n yFormatter: void 0,\n // bubble sizing: datum key for the size value + [minR, maxR] in px.\n sizeField: \"z\",\n sizeRange: void 0,\n laneLabelWidth: void 0,\n gridlines: true\n },\n // Opt-in bubble sizing: scale each dot's radius by its per-unit value\n // (needs the object-form data). Circle shape only; the lattice is\n // spaced for the largest bubble so dots never overlap.\n sizeByValue: {\n enabled: false,\n // radius (px) for the largest value, or 'auto' to fit the largest\n // bubble to the plot like uniform auto-sizing.\n maxRadius: \"auto\",\n // radius (px) for the smallest value; defaults to ~35% of maxRadius.\n minRadius: void 0,\n // 'area' (bubble AREA proportional to value) | 'linear'.\n scale: \"area\"\n },\n // packing gap factor between spiral shells (1 = dots touch).\n spacing: 1.05,\n // corner radius for shape:'square'.\n borderRadius: 0,\n // How marks move between layouts on an update, and where entering\n // marks come from.\n //\n // `motion`: 'spring' settles each mark on a damped spring, so a\n // gather interrupted by the next update carries the marks' velocity\n // into it instead of restarting them from a standstill - which is\n // what a dragged slider or a scrubbed storyboard does on almost every\n // frame. 'tween' runs the fixed-duration ease below instead. 'auto'\n // (the default) is spring, unless `easing` was set to something other\n // than the default, so an explicit curve keeps working without having\n // to set `motion` as well.\n //\n // `spring`: 'crisp' (default) | 'gentle' (softer, for large reflows)\n // | 'snappy' (faster, a hint of settle). Scaled by\n // `chart.animations.speed`, which stretches the spring in time\n // without making it bouncier.\n //\n // `easing` (tween only): 'outCubic' (default: decelerate to a stop) |\n // 'inOutCubic' (accelerate gently out of rest, weighted travel) |\n // 'outBack' (overshoot each mark past its slot and spring back - a\n // per-mark settle), with `overshoot` tuning the spring strength.\n //\n // `enter`: where a fresh / appearing mark animates FROM - 'burst'\n // (default: fly out from the cluster centre) | 'fade' (materialise in\n // place) | 'rise' (fade in while drifting gently up into the slot).\n //\n // Colour, radius and opacity always stay on the out-cubic, under\n // either motion (a back ease overshoots past 1, which would push RGB\n // channels / radii out of range; and the spring's rest thresholds are\n // absolute, so they are far too coarse for a 0..1 quantity).\n gather: {\n motion: \"auto\",\n spring: \"crisp\",\n easing: \"outCubic\",\n overshoot: 1.70158,\n enter: \"burst\"\n },\n // The 'arc' layout arranges marks as a PARLIAMENT / hemicycle: seats in\n // concentric arced rows across an annulus, filled in category order so\n // each category is a contiguous wedge (the classic seating chart). Angles\n // use the radialBar convention (0 = top, clockwise); the default sweep is\n // a top semicircle (a full circle = startAngle 0, endAngle 360).\n // `innerRadiusRatio` is the donut hole (inner radius / outer); `rows`\n // fixes the number of seat rows, or 'auto' to size the dots as large as\n // fit. Like 'packed' the legend carries the category names (no per-wedge\n // labels).\n arc: {\n startAngle: -90,\n endAngle: 90,\n innerRadiusRatio: 0.4,\n rows: \"auto\"\n },\n // 1 dot represents this many units of value (waffle scaling).\n unitValue: 1,\n // safety cap on total dots; counts scale down proportionally above it.\n maxUnits: 5e3,\n // packed layout: order categories smallest-first so the minority\n // group nests in the centre of the blob.\n sortByGroup: true,\n clusterLabels: {\n show: true,\n // Label placement relative to the cluster/bar: 'top' (default) or\n // 'bottom'. A 'bottom' label is always straight; the curved arc\n // (below) rides the top crown only.\n position: \"top\",\n curved: true,\n fontSize: \"13px\",\n fontFamily: void 0,\n fontWeight: 600,\n // defaults to the cluster's own colour when undefined.\n color: void 0,\n offsetY: 0,\n // (name, { seriesIndex, value, percent, w }) => string.\n // Return \"\\n\"-separated text to split an outer label over lines.\n formatter: void 0,\n // Outer (name) labels, as pie/donut draw them: the label sits in the\n // margin beside the shape and a leader line joins it to the colour\n // band it names, so the crowd needs no legend to be read.\n //\n // `layout: 'custom'` only, and best on a silhouette whose categories\n // stack vertically (the default row ordering): those alternate down\n // the left and right gutters. A column-ordered shape sends each\n // label to the side its own band sits on.\n //\n // The margin is taken off BOTH sides so the shape stays centred,\n // which means turning this on makes the silhouette a little smaller.\n external: {\n show: false,\n connector: {\n show: true,\n width: 1.5,\n // defaults to the band's own colour when undefined.\n color: void 0,\n // air between the band's outermost dot and the line's bend.\n gap: 8,\n // length of the run out to the label.\n length: 22\n },\n offsetX: 0,\n offsetY: 0\n }\n },\n tooltip: {\n // Per-unit tooltip body. Each dot carries its category (seriesIndex)\n // and its index within that category (dataPointIndex), so the\n // formatter can look up per-unit data and return a string/HTML.\n // ({ seriesName, seriesIndex, dataPointIndex, count, unitValue,\n // color, w }) => string\n // Default: \"# of \".\n formatter: void 0\n }\n },\n radialBar: {\n inverseOrder: false,\n startAngle: 0,\n endAngle: 360,\n offsetX: 0,\n offsetY: 0,\n // Gauge sub-shape. 'arc' (default) renders the existing filled\n // value-arc gauge; 'needle' replaces the value-arc with a rotating\n // pointer/needle. Bands and ticks are independent and work for both\n // shapes.\n shape: \"arc\",\n // Value-to-angle mapping. Defaults to the existing 0..100 range\n // used by radialBar. Override for gauges that need a custom domain\n // (e.g. min: 0, max: 240 for a speedometer).\n min: 0,\n max: 100,\n // Threshold bands rendered as colored arc segments along the gauge\n // arc (e.g. [{from:0,to:30,color:'#FF4560'}, ...]). Bands draw\n // behind the value-arc and tick marks. Set to [] (default) to\n // disable.\n bands: [],\n bandsStyle: {\n // % of arc radius. Slightly less than the value-arc stroke so\n // the value-arc reads on top by default.\n strokeWidth: \"40%\",\n // px gap between consecutive bands.\n gap: 0,\n // Hide the track when bands cover the full range; the bands\n // themselves act as the visual backdrop.\n hideTrackWhenPresent: true\n },\n // Tick marks rendered along (outside) the gauge arc.\n ticks: {\n show: false,\n major: {\n count: 11,\n length: 10,\n width: 2,\n color: \"#666\",\n // 'inside' draws ticks from `radius - length` to `radius`;\n // 'outside' draws from `radius` to `radius + length`.\n placement: \"outside\"\n },\n minor: {\n count: 4,\n // minor ticks BETWEEN each pair of major ticks\n length: 5,\n width: 1,\n color: \"#999\",\n placement: \"outside\"\n },\n labels: {\n show: false,\n offset: 6,\n fontSize: \"11px\",\n fontFamily: void 0,\n fontWeight: 400,\n color: \"#666\",\n /** @param {number} v */\n formatter(v) {\n return String(v);\n }\n }\n },\n // Needle/dial configuration. Only applies when `shape: 'needle'`.\n needle: {\n color: \"#333\",\n // Needle length as a % of the gauge radius (string like '85%')\n // or as an absolute px number.\n length: \"85%\",\n // px width of the needle line at the base.\n baseWidth: 4,\n // px width of the needle tip (tapered if smaller than baseWidth).\n tipWidth: 1,\n // px offset from the geometric arc center on Y. Positive values\n // push the needle base down (toward the chord midpoint of a\n // \u2229-shape gauge); negative pushes up. The needle rotates around\n // this shifted point.\n offsetY: 0,\n // When true, also render the filled value-arc alongside the\n // needle. Default false preserves the previous needle-only\n // behavior. Useful for gauges that want a progress ring plus a\n // pointer indicator.\n showValueArc: false,\n animation: {\n enabled: true,\n duration: 800,\n easing: \"ease-out\"\n }\n },\n hollow: {\n margin: 5,\n size: \"50%\",\n background: \"transparent\",\n image: void 0,\n imageWidth: 150,\n imageHeight: 150,\n imageOffsetX: 0,\n imageOffsetY: 0,\n imageClipped: true,\n position: \"front\",\n // Optional stroke around the hollow ring. Combined with\n // `strokeDasharray` this produces a dashed indicator circle\n // around the value text \u2014 useful for gauge designs where the\n // value sits inside its own boundary.\n stroke: void 0,\n strokeWidth: 1,\n strokeDasharray: void 0,\n dropShadow: {\n enabled: false,\n top: 0,\n left: 0,\n blur: 3,\n color: \"#000\",\n opacity: 0.5\n }\n },\n track: {\n show: true,\n startAngle: void 0,\n endAngle: void 0,\n background: \"#f2f2f2\",\n strokeWidth: \"97%\",\n opacity: 1,\n margin: 5,\n // margin is in pixels\n dropShadow: {\n enabled: false,\n top: 0,\n left: 0,\n blur: 3,\n color: \"#000\",\n opacity: 0.5\n }\n },\n dataLabels: {\n show: true,\n name: {\n show: true,\n fontSize: \"16px\",\n fontFamily: void 0,\n fontWeight: 600,\n color: void 0,\n offsetY: 0,\n /**\n * @param {any} val\n */\n formatter(val) {\n return val;\n }\n },\n value: {\n show: true,\n fontSize: \"14px\",\n fontFamily: void 0,\n fontWeight: 400,\n color: void 0,\n offsetY: 16,\n /**\n * @param {any} val\n */\n formatter(val) {\n return val + \"%\";\n }\n },\n total: {\n show: false,\n label: \"Total\",\n fontSize: \"16px\",\n fontWeight: 600,\n fontFamily: void 0,\n color: void 0,\n /**\n * @param {import('../../types/internal').ChartStateW} w\n */\n formatter(w) {\n return (\n /**\n * @param {number} a\n * @param {number} b\n */\n w.globals.seriesTotals.reduce((a2, b) => a2 + b, 0) / w.seriesData.series.length + \"%\"\n );\n }\n }\n },\n barLabels: {\n enabled: false,\n offsetX: 0,\n offsetY: 0,\n useSeriesColors: true,\n fontFamily: void 0,\n fontWeight: 600,\n fontSize: \"16px\",\n /**\n * @param {any} val\n */\n formatter(val) {\n return val;\n },\n onClick: void 0\n }\n },\n pie: {\n customScale: 1,\n offsetX: 0,\n offsetY: 0,\n startAngle: 0,\n endAngle: 360,\n expandOnClick: true,\n // How far a clicked slice slides out of the pie (px), measured along\n // its own mid-angle. The slice is translated, not redrawn at a bigger\n // radius, so its shape and the quantity it encodes are unchanged and\n // a gap opens between it and the rest of the pie. The inner\n // percentage label (and the outer name label, when enabled) ride\n // along with it. Ignored for polarArea, where the radius is the\n // value, and in a drilldown pie/donut, where a click navigates (the\n // slice would slide out only to be discarded by the drill, and\n // states.active takes the click feedback back over). Set 0 to keep\n // the slice in place.\n expandOffset: 10,\n // Hover outline: a translucent band traced just outside the rim of\n // the hovered slice, so the slice keeps its own colour instead of\n // being lightened. Takes the place of the states.hover filter for\n // pie / donut / polarArea, and is skipped entirely when\n // states.hover.filter.type is 'none' (that stays the way to turn all\n // hover feedback off). Applies to pie, donut and polarArea.\n hoverOutline: {\n show: true,\n size: 8,\n // band thickness (px)\n // Extra clearance between the slice rim and the band (px), ON TOP\n // of the slice stroke: the band always starts at the outer edge of\n // the stroke, never under it. Default 0, because a stroke is\n // normally present (stroke.width defaults to 2) and already reads\n // as the separation. Any gap beyond that and the band stops\n // belonging to its slice and starts reading as a ring of its own.\n gap: 0,\n opacity: 0.3,\n // band opacity, over the slice colour\n color: void 0\n // defaults to the hovered slice's colour\n },\n // Rounds the corners of each slice (in px). Applies to pie, donut and\n // polarArea (all rendered by the Pie module). 0 = sharp corners\n // (default, unchanged behavior). The value is clamped per slice so\n // opposing corner fillets never cross on thin/narrow slices.\n borderRadius: 0,\n // Gap between adjacent slices (in px). Applies to pie, donut and\n // polarArea. 0 = slices touch (default). Each slice is inset\n // symmetrically, so its mid-angle (data label + hit region) is kept.\n spacing: 0,\n dataLabels: {\n // These are the percentage values which are displayed on slice\n offset: 0,\n // offset by which labels will move outside\n minAngleToShowLabel: 10,\n // External (outer) labels: render the category/series name outside\n // the slice, joined to it by a leader (connector) line, so users\n // don't have to map legend colors back to slices. The percentage\n // keeps rendering inside the slice (governed by dataLabels.enabled).\n // Pie + donut only; ignored for polarArea (radial length already\n // encodes the value there).\n external: {\n show: false,\n // master switch for the external (outer) labels\n offsetX: 0,\n offsetY: 0,\n fontSize: void 0,\n // falls back to dataLabels.style.fontSize\n fontFamily: void 0,\n // falls back to dataLabels.style.fontFamily\n fontWeight: void 0,\n // falls back to dataLabels.style.fontWeight\n color: void 0,\n // defaults to chart.foreColor (readable text)\n /**\n * Return a string (single line) or an array of strings (stacked\n * lines, e.g. [name, percent + '%']).\n * @param {string} name\n * @param {{ seriesIndex: number, percent: number, value: number, w: any }} opts\n * @returns {string | string[]}\n */\n formatter: void 0,\n connector: {\n show: true,\n width: 1,\n color: void 0,\n // defaults to the slice color\n length: 16,\n // horizontal run after the radial elbow (px)\n gap: 6\n // radial gap from slice edge to the elbow point (px)\n }\n }\n },\n donut: {\n size: \"65%\",\n background: \"transparent\",\n labels: {\n // These are the inner labels appearing inside donut\n show: false,\n name: {\n show: true,\n fontSize: \"16px\",\n fontFamily: void 0,\n fontWeight: 600,\n color: void 0,\n offsetY: -10,\n /**\n * @param {any} val\n */\n formatter(val) {\n return val;\n }\n },\n value: {\n show: true,\n fontSize: \"20px\",\n fontFamily: void 0,\n fontWeight: 400,\n color: void 0,\n offsetY: 10,\n /**\n * @param {any} val\n */\n formatter(val) {\n return val;\n }\n },\n total: {\n show: false,\n showAlways: false,\n label: \"Total\",\n fontSize: \"16px\",\n fontWeight: 400,\n fontFamily: void 0,\n color: void 0,\n /**\n * @param {import('../../types/internal').ChartStateW} w\n */\n formatter(w) {\n return w.globals.seriesTotals.reduce((a2, b) => a2 + b, 0);\n }\n }\n }\n }\n },\n polarArea: {\n rings: {\n strokeWidth: 1,\n strokeColor: \"#e8e8e8\"\n },\n spokes: {\n strokeWidth: 1,\n connectorColors: \"#e8e8e8\"\n }\n },\n icicle: {\n // Icicle (cartesian partition). One band per hierarchy level, each\n // child cell nested inside its parent's extent along the value axis.\n // Opt-in: `import ApexCharts from 'apexcharts/icicle'`.\n //\n // Which way the tree grows from the root. 'down' (default) puts the\n // root band on top; 'up' puts it at the bottom and is the flame-graph\n // orientation; 'right'/'left' grow sideways.\n direction: \"down\",\n // Thickness of one depth band. 'equal' divides the depth axis by the\n // deepest visible level; a number is px; a '%' string is a share of\n // the depth axis. A fixed size keeps its thickness through a zoom.\n levelSize: \"equal\",\n // How many levels to draw, counting the focused one. 'auto' (default)\n // draws the whole tree: labels already hide themselves once a band is\n // thinner than a line of text, so a deep tree degrades to an honest\n // dense shape rather than to nonsense. Set a number for very deep\n // trees (a call stack, say) to keep the top levels readable; branches\n // cut that way are marked, and clicking one zooms in to reveal them.\n maxDepth: \"auto\",\n // Gap between adjacent cells and corner rounding, both px, same\n // semantics as plotOptions.pie.spacing / .borderRadius.\n spacing: 1,\n borderRadius: 0,\n // How a branch that bottoms out before the deepest level is drawn.\n // 'stop' (default) ends the leaf at its own band and leaves the\n // deeper bands empty, so the white space below a branch shows how\n // deep it goes: that stepped silhouette is what makes an icicle\n // readable as a hierarchy. 'extend' stretches the leaf to the far\n // edge instead, which fills the plot and reads like a treemap.\n leaf: \"stop\",\n // Partition of a parent's extent among its children: 'normalize'\n // splits by each child's share of its siblings (safe for any data);\n // 'strict' expects children to sum to the parent's value.\n partition: \"normalize\",\n // Sibling order within a parent. 'none' keeps data order, 'value' is\n // descending by size, 'name' is alphabetical \u2014 the flame-graph\n // convention, which holds a frame in the same place across profiles\n // so two runs can be compared by eye.\n sort: \"none\",\n // Each depth level is tinted this much lighter than its parent\n // (0 = keep the parent colour, 1 = white). A per-node `color` wins.\n // Default 0: a branch carries ONE hue at every depth and the gaps do\n // the separating, which is what lets the eye follow a branch down.\n // Per-depth shading instead reads as nested boxes, i.e. a treemap.\n tint: 0,\n // Click a cell to zoom into that branch (a breadcrumb walks back).\n // Set false to disable.\n zoomOnClick: true,\n // What a zoom actually changes, the partition equivalent of\n // chart.zoom.type. 'value' (default) rescales the VALUE axis only:\n // the branch stretches to fill the width and every level stays\n // exactly where it was, so the reader keeps their bearings and the\n // ancestors stay on screen as context. 'both' also re-bands the DEPTH\n // axis, promoting the branch to the top level so its subtree fills\n // the whole plot, which uses the space better and moves everything.\n // Not named 'x'/'y': `direction` swaps which screen axis is which.\n zoomType: \"value\",\n dataLabels: {\n show: true,\n // Hide the label on any cell shorter than this (px) along the\n // reading direction, so narrow cells do not overflow.\n minSizeToShow: 30,\n // 'left' | 'center' | 'right', along the reading direction. Centred\n // by default so a band reads as one unit; a flame graph usually\n // wants 'left', because a reader scans the left edge of the stack.\n align: \"center\",\n // 'auto' (default) turns the label a quarter turn on a cell taller\n // than it is wide, which is where a flat label would be clipped by\n // the band while the value axis has room to spare. 'always' turns\n // every label for a uniform look, but note that a turned label\n // reads across the BAND THICKNESS, so it suits short names and\n // costs labels on wide shallow bands. 'never' keeps them all flat.\n rotate: \"auto\",\n showValue: false,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 400,\n colors: void 0\n }\n }\n },\n sunburst: {\n // Sunburst / nested pie-donut (hierarchical radial). Rings go from the\n // centre hole outward, one per hierarchy level; each child arc is\n // nested inside its parent's angular wedge.\n offsetX: 0,\n offsetY: 0,\n startAngle: 0,\n endAngle: 360,\n // Centre hole radius, as a % of the max radius (like donut size).\n innerSize: \"15%\",\n // Corner rounding + inter-arc gap (px), same semantics as the pie\n // family (see plotOptions.pie.borderRadius / .spacing).\n borderRadius: 0,\n spacing: 1,\n // How a branch that bottoms out before the deepest level is drawn:\n // 'extend' stretches the leaf arc out to the rim (default, matches\n // d3); 'stop' leaves the outer rings empty behind it.\n leaf: \"extend\",\n // Angular partition of a parent's wedge among its children:\n // 'normalize' splits by each child's share of its siblings (safe for\n // any data); 'strict' expects children to sum to the parent's value.\n partition: \"normalize\",\n // Each depth level is tinted this much lighter than its parent colour\n // (0 = keep parent colour, 1 = white). A per-node `color` overrides.\n tint: 0.14,\n // Click a wedge to zoom into that branch (its subtree fills the\n // chart; a breadcrumb walks back). Click the focused inner ring to\n // zoom out. Set false to disable.\n zoomOnClick: true,\n dataLabels: {\n show: true,\n // Hide the label on any arc narrower than this (degrees), so tiny\n // wedges do not overflow with text.\n minAngleToShow: 8,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 400,\n colors: void 0\n }\n }\n },\n radar: {\n size: void 0,\n offsetX: 0,\n offsetY: 0,\n polygons: {\n // strokeColor: '#e8e8e8', // should be deprecated in the minor version i.e 3.2\n strokeWidth: 1,\n strokeColors: \"#e8e8e8\",\n connectorColors: \"#e8e8e8\",\n fill: {\n colors: void 0\n }\n }\n }\n },\n colors: void 0,\n dataLabels: {\n enabled: true,\n enabledOnSeries: void 0,\n /**\n * @param {any} val\n */\n formatter(val) {\n return val !== null ? val : \"\";\n },\n textAnchor: \"middle\",\n distributed: false,\n // Nudge data labels apart when they land on each other, across series\n // as well as within one. ON by default: a label sitting on top of\n // another one is never what the chart meant to say, and the pass is a\n // no-op on a chart whose labels already clear each other, so the cost\n // of leaving it on is one measuring pass. Set false for the old\n // behaviour, or an object to override:\n // gap clear space left between two separated labels (px)\n // maxShift how far a label may travel from its own mark; defaults\n // to about one label's own size along that axis\n // hide drop a label that still collides after both have spent\n // their budget, later-drawn first. Off by default: this\n // pass runs on every chart, and silently deleting a value\n // is worse than the overlap it set out to fix.\n // Labels separate along the VALUE axis, so a horizontal bar's move\n // left/right and everything else moves up/down. Rotated labels are\n // avoided but never moved, and radial types (pie, radar, ...) are left\n // to their own placement.\n avoidOverlap: true,\n offsetX: 0,\n offsetY: 0,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 600,\n colors: void 0\n },\n background: {\n enabled: true,\n foreColor: \"#fff\",\n backgroundColor: void 0,\n borderRadius: 2,\n padding: 4,\n opacity: 0.9,\n borderWidth: 1,\n borderColor: \"#fff\",\n dropShadow: {\n enabled: false,\n top: 1,\n left: 1,\n blur: 1,\n color: \"#000\",\n opacity: 0.8\n }\n },\n dropShadow: {\n enabled: false,\n top: 1,\n left: 1,\n blur: 1,\n color: \"#000\",\n opacity: 0.8\n },\n // Ride data labels to their new position on a data-change update\n // instead of snapping. ON by default: the bars, the markers and the\n // axis ticks all already reflow on one clock, so a label that jumps to\n // its final slot on the first frame is the odd one out, it arrives\n // several hundred ms before the bar it belongs to. Speed/easing follow\n // chart.animations.dynamicAnimation, and a label that has not moved is\n // a per-label no-op. Bar/column only.\n animate: {\n enabled: true\n },\n // Count the numeric value up/down from its previous value on update,\n // like countUp.js. Off by default. The dataLabels.formatter runs each\n // frame, so number formatting (decimals, separators, prefixes) is\n // preserved. Bar/column only.\n countUp: {\n enabled: false\n }\n },\n fill: {\n type: \"solid\",\n colors: void 0,\n // array of colors\n opacity: 0.85,\n gradient: {\n shade: \"dark\",\n type: \"horizontal\",\n shadeIntensity: 0.5,\n gradientToColors: void 0,\n inverseColors: true,\n opacityFrom: 1,\n opacityTo: 1,\n stops: [0, 50, 100],\n colorStops: []\n },\n image: {\n src: [],\n width: void 0,\n // optional\n height: void 0\n // optional\n },\n pattern: {\n style: \"squares\",\n // String | Array of Strings\n width: 6,\n height: 6,\n strokeWidth: 2\n }\n },\n forecastDataPoints: {\n count: 0,\n fillOpacity: 0.5,\n strokeWidth: void 0,\n dashArray: 4\n },\n // Draws each value faded and a part of it solid in front (the part\n // comes as `highlight` on a point or `highlightData` on a series, or\n // in `data`, one per slice or ring, on a circle; a one-value row reads\n // as that value).\n // Needs `import 'apexcharts/features/highlight-filter'`.\n highlightFilter: {\n enabled: true,\n data: void 0,\n fadeOpacity: 0.2,\n outline: { width: 1, opacity: 1 },\n enter: \"whole\",\n axis: \"extend\",\n dataLabels: { value: \"part\", total: \"part\" },\n tooltip: { show: true, share: false, formatter: void 0 },\n line: { dashArray: 4 },\n pie: { encoding: \"radius\" },\n // indicator unset: 'arc' on every ring (the whole faded on its\n // track, the part solid in front from the same start), or 'needle'\n // where the gauge draws its own needle (plotOptions.radialBar.shape\n // 'needle'). 'lanes' (opt-in) splits each band in two, the whole\n // light outside, the part solid inside. Unset needle keys fall back\n // to plotOptions.radialBar.needle; unset, lanes.opacity (the whole\n // lane's strength) is 0.45.\n radialBar: { indicator: void 0, needle: {} }\n },\n grid: {\n show: true,\n borderColor: \"#e0e0e0\",\n strokeDashArray: 0,\n position: \"back\",\n xaxis: {\n lines: {\n show: false\n }\n },\n yaxis: {\n lines: {\n show: true\n }\n },\n row: {\n colors: void 0,\n // takes as array which will be repeated on rows\n opacity: 0.5\n },\n column: {\n colors: void 0,\n // takes an array which will be repeated on columns\n opacity: 0.5\n },\n padding: {\n top: 0,\n right: 10,\n bottom: 0,\n left: 12\n }\n },\n labels: [],\n drilldown: {\n // Opt-in. When false, the Drilldown feature module stays inert even if\n // it was imported. Requires `import 'apexcharts/features/drilldown'`.\n enabled: false,\n // Child levels referenced by a data point's `drilldown: ''` field.\n // Each: { id, name?, data, chart?, xaxis?, yaxis?, colors?, plotOptions? }\n series: [],\n breadcrumb: {\n show: true,\n position: \"top-left\",\n // 'top-left' | 'top-right'\n separator: \" / \",\n rootLabel: \"All\",\n offsetX: 0,\n offsetY: 0\n // formatter: (label, { index, depth }) => label,\n },\n // Animation is delegated to the chart's update pipeline; `enabled`\n // gates whether the drill transition animates at all.\n animation: {\n enabled: true,\n // Anchor the drill transition at the clicked point: the child unfolds\n // outward from it (and settles back on drill-up) instead of the chart\n // simply re-rendering. A gentle scale layered on the SVG; opt-in.\n zoomFromPoint: false,\n // Base duration (ms) of the transition, used only when zoomFromPoint\n // is true. The fade-out phase runs a little shorter than this.\n speed: 260\n },\n // Optional async resolver, called when a drillable point has no inline\n // match in `series`. Receives ({ id, point, seriesIndex, dataPointIndex })\n // and returns a level (or a promise of one). A throw, a rejection, or a\n // resolved value without a `data` array leaves the chart exactly where\n // it was and fires `drillDownError` - a failed fetch is ordinary, not\n // a reason to strand the view.\n // onDrillDown: undefined,\n // Overlay shown while an async level resolves. `text` is optional: with\n // none, the spinner shows alone (and carries 'Loading' as its\n // accessible name), which keeps the default free of any language.\n loading: {\n show: true\n // text: 'Loading\u2026',\n },\n // Cache levels resolved by `onDrillDown`, keyed by id, so drilling back\n // down a branch does not re-fetch it. Call `chart.drillDown` module's\n // clearCache() when the data behind an already-drilled chart changes.\n cache: true,\n // The dot that marks a drillable point on a line/area chart drawn\n // without markers. A bar, slice, tile or cell is already a visible,\n // clickable mark; a line point is not, so without this the chart would\n // give no sign that anything can be opened. Only drillable points get\n // one, which is what makes them read as openable. Set `show: false` to\n // supply your own affordance (turning `markers.size` on, for instance).\n // Omitted colours inherit the series marker defaults.\n marker: {\n show: true,\n size: 6,\n // shape: undefined, // 'circle' | 'square' | 'rect'\n // fillColor: undefined, // defaults to the series colour\n strokeColor: \"#fff\"\n }\n },\n legend: {\n show: true,\n showForSingleSeries: false,\n showForNullSeries: true,\n showForZeroSeries: true,\n floating: false,\n position: \"bottom\",\n // whether to position legends in 1 of 4\n // direction - top, bottom, left, right\n horizontalAlign: \"center\",\n // when position top/bottom, you can specify whether to align legends left, right or center\n inverseOrder: false,\n fontSize: \"12px\",\n fontFamily: void 0,\n fontWeight: 400,\n width: void 0,\n height: void 0,\n formatter: void 0,\n tooltipHoverFormatter: void 0,\n offsetX: -20,\n offsetY: 4,\n customLegendItems: [],\n clusterGroupedSeries: true,\n clusterGroupedSeriesOrientation: \"vertical\",\n labels: {\n colors: void 0,\n useSeriesColors: false\n },\n markers: {\n size: 7,\n fillColors: void 0,\n strokeWidth: 1,\n shape: void 0,\n offsetX: 0,\n offsetY: 0,\n customHTML: void 0,\n onClick: void 0\n },\n itemMargin: {\n horizontal: 5,\n vertical: 4\n },\n onItemClick: {\n toggleDataSeries: true\n },\n onItemHover: {\n highlightDataSeries: true\n }\n },\n markers: {\n discrete: [],\n size: 0,\n colors: void 0,\n strokeColors: \"#fff\",\n strokeWidth: 2,\n strokeOpacity: 0.9,\n strokeDashArray: 0,\n fillOpacity: 1,\n shape: \"circle\",\n offsetX: 0,\n offsetY: 0,\n showNullDataPoints: true,\n onClick: void 0,\n onDblClick: void 0,\n hover: {\n size: void 0,\n sizeOffset: 3\n },\n // OPT-IN (0 = off). Above this many points in a series, that series'\n // markers are drawn as ONE path element per marker size, carrying a\n // subpath per point, instead of one element per point. Each per-point\n // element costs a node, ~16 attribute writes and an appendChild, which\n // is why markers dominate a large render: 2000 of them take 15ms of an\n // 18ms render, and batched they take 1ms.\n //\n // This covers the markers `showNullDataPoints` adds implicitly, not\n // just the ones asked for: every point beside a null is isolated and\n // gets its own dot, so a 2000-point series with half its values null\n // built ~1000 elements even at markers.size 0. Batched that render goes\n // from 15ms to 3.7ms, and 5000 points from 37ms to 5.9ms. Those dots\n // are a different size from the configured ones, hence one path per\n // size rather than one per series.\n //\n // Off by default because it is NOT pixel-identical where markers\n // overlap, and above ~1000 points in a normal-width chart they always\n // do. One path is rasterized as a single region, so overlapping markers\n // lose their individual outlines: all the fills paint, then all the\n // strokes, and the seams between neighbours disappear. Dense clusters\n // read flatter (measured 1-9% of pixels, scaling with density). Sparse\n // markers that do not touch are unaffected.\n //\n // Only applies where markers are already non-interactive and uniform (a\n // plain line/area with the default sweep tooltip, no discrete markers,\n // no per-point colours, no marker click handlers, no dataPointSelection\n // handler). A batched series has no `.apexcharts-marker` nodes, so the\n // hover dot is served by the tooltip's own marker (the same one\n // markers.size: 0 charts use), the keyboard focus ring lands on that\n // marker, and the per-marker reveal / stream ride is replaced by the\n // series-level fade.\n largeDatasetThreshold: 0\n },\n noData: {\n text: void 0,\n align: \"center\",\n offsetX: 0,\n offsetY: 0,\n style: {\n color: void 0,\n fontSize: \"14px\",\n fontFamily: void 0\n }\n },\n responsive: [],\n // breakpoints should follow ascending order 400, then 700, then 1000\n series: void 0,\n states: {\n hover: {\n filter: {\n type: \"lighten\",\n value: 0.15\n }\n },\n active: {\n allowMultipleDataPointsSelection: false,\n filter: {\n type: \"darken\",\n value: 0.35\n }\n }\n },\n title: {\n text: void 0,\n align: \"left\",\n margin: 5,\n offsetX: 0,\n offsetY: 0,\n floating: false,\n style: {\n fontSize: \"14px\",\n fontWeight: 900,\n fontFamily: void 0,\n color: void 0\n }\n },\n subtitle: {\n text: void 0,\n align: \"left\",\n margin: 5,\n offsetX: 0,\n offsetY: 30,\n floating: false,\n style: {\n fontSize: \"12px\",\n fontWeight: 400,\n fontFamily: void 0,\n color: void 0\n }\n },\n stroke: {\n show: true,\n curve: \"smooth\",\n // \"smooth\" / \"straight\" / \"monotoneCubic\" / \"stepline\" / \"linestep\"\n lineCap: \"butt\",\n // round, butt , square\n width: 2,\n colors: void 0,\n // array of colors\n dashArray: 0,\n // single value or array of values\n fill: {\n type: \"solid\",\n colors: void 0,\n // array of colors\n opacity: 0.85,\n gradient: {\n shade: \"dark\",\n type: \"horizontal\",\n shadeIntensity: 0.5,\n gradientToColors: void 0,\n inverseColors: true,\n opacityFrom: 1,\n opacityTo: 1,\n stops: [0, 50, 100],\n colorStops: []\n }\n }\n },\n tooltip: {\n enabled: true,\n enabledOnSeries: void 0,\n shared: true,\n hideEmptySeries: false,\n followCursor: false,\n // when disabled, the tooltip will show on top of the series instead of mouse position\n intersect: false,\n // when enabled, tooltip will only show when user directly hovers over point\n inverseOrder: false,\n // Keeps custom tooltip content clickable; when enabled, it overrides\n // followCursor because a cursor-trailing tooltip cannot be entered.\n interactive: false,\n arrow: true,\n // One tight line instead of a card: the x label sits inline before\n // the value, the marker goes, the padding and font shrink. For panels\n // a normal card would cover (small multiples, sparklines, tiles). A\n // single-series chart drops the series-name label too; with several\n // series the names stay, because they are what tells the rows apart.\n compact: false,\n custom: void 0,\n fillSeriesColor: false,\n theme: \"light\",\n cssClass: \"\",\n style: {\n fontSize: \"12px\",\n fontFamily: void 0,\n background: void 0\n },\n onDatasetHover: {\n highlightDataSeries: false\n },\n x: {\n // x value\n show: true,\n format: \"dd MMM\",\n // dd/MM, dd MMM yy, dd MMM yyyy\n formatter: void 0\n // a custom user supplied formatter function\n },\n y: {\n formatter: void 0,\n title: {\n /**\n * @param {string} seriesName\n */\n formatter(seriesName) {\n return seriesName ? seriesName + \": \" : \"\";\n }\n }\n },\n z: {\n formatter: void 0,\n title: \"Size: \"\n },\n marker: {\n show: true,\n fillColors: void 0\n },\n items: {\n display: \"flex\"\n },\n fixed: {\n enabled: false,\n position: \"topRight\",\n // topRight, topLeft, bottomRight, bottomLeft\n offsetX: 0,\n offsetY: 0\n }\n },\n xaxis: {\n type: \"category\",\n categories: [],\n convertedCatToNumeric: false,\n // internal property which should not be altered outside\n offsetX: 0,\n offsetY: 0,\n overwriteCategories: void 0,\n labels: {\n show: true,\n rotate: -45,\n rotateAlways: false,\n hideOverlappingLabels: true,\n trim: false,\n minHeight: void 0,\n maxHeight: 120,\n showDuplicates: true,\n style: {\n colors: [],\n fontSize: \"12px\",\n fontWeight: 400,\n fontFamily: void 0,\n cssClass: \"\"\n },\n offsetX: 0,\n offsetY: 0,\n format: void 0,\n formatter: void 0,\n // custom formatter function which will override format\n datetimeUTC: true,\n datetimeFormatter: {\n // Base format per interval unit. TimeScale.formatDates folds in\n // coarser context automatically when the data range spans it\n // (e.g. month-scale across years \u2192 'MMM yyyy', hour-scale across\n // days \u2192 'dd MMM HH:mm'). Customizing a base format that already\n // includes the higher-unit token disables the auto-expansion for\n // that level.\n year: \"yyyy\",\n month: \"MMM\",\n day: \"dd MMM\",\n hour: \"HH:mm\",\n minute: \"HH:mm\",\n second: \"HH:mm:ss\"\n }\n },\n group: {\n groups: [],\n style: {\n colors: [],\n fontSize: \"12px\",\n fontWeight: 400,\n fontFamily: void 0,\n cssClass: \"\"\n }\n },\n axisBorder: {\n show: true,\n color: \"#e0e0e0\",\n width: \"100%\",\n height: 1,\n offsetX: 0,\n offsetY: 0\n },\n axisTicks: {\n show: true,\n color: \"#e0e0e0\",\n height: 6,\n offsetX: 0,\n offsetY: 0\n },\n stepSize: void 0,\n tickAmount: void 0,\n tickPlacement: \"on\",\n min: void 0,\n max: void 0,\n range: void 0,\n floating: false,\n decimalsInFloat: void 0,\n position: \"bottom\",\n title: {\n text: void 0,\n offsetX: 0,\n offsetY: 0,\n style: {\n color: void 0,\n fontSize: \"12px\",\n fontWeight: 900,\n fontFamily: void 0,\n cssClass: \"\"\n }\n },\n crosshairs: {\n show: true,\n width: 1,\n // tickWidth/barWidth or an integer\n position: \"back\",\n opacity: 0.9,\n stroke: {\n color: \"#b6b6b6\",\n width: 1,\n dashArray: 3\n },\n fill: {\n type: \"solid\",\n // solid, gradient\n color: \"#B1B9C4\",\n gradient: {\n colorFrom: \"#D8E3F0\",\n colorTo: \"#BED1E6\",\n stops: [0, 100],\n opacityFrom: 0.4,\n opacityTo: 0.5\n }\n },\n dropShadow: {\n enabled: false,\n left: 0,\n top: 0,\n blur: 1,\n opacity: 0.8\n }\n },\n tooltip: {\n enabled: false,\n offsetY: 0,\n formatter: void 0,\n style: {\n fontSize: \"12px\",\n fontFamily: void 0\n }\n }\n },\n yaxis: this.yAxis,\n theme: {\n mode: \"\",\n palette: \"palette1\",\n // If defined, it will overwrite globals.colors variable\n // Facet (#13): read `--apx-*` CSS design tokens from the cascade\n // (accent/fore/grid/surface + series-1..N). true (default) reads any\n // present (absence is a no-op); false disables. Tokens top the\n // resolution chain below explicit config. Tokens are re-read on every\n // render; call chart.refreshTokens() to pick up a runtime CSS change\n // that does not itself trigger a render.\n tokens: true,\n // Facet (#13): 'os' follows prefers-color-scheme + prefers-contrast\n // reactively (SSR-safe, cleaned up on destroy). false disables.\n follow: false,\n // 'os' | false\n // Facet (#13): a theme registered via ApexCharts.registerTheme(name, def)\n name: \"\",\n // '' | registered theme name\n monochrome: {\n // monochrome allows you to select just 1 color and fill out the rest with light/dark shade (intensity can be selected)\n enabled: false,\n color: \"#008FFB\",\n shadeTo: \"light\",\n shadeIntensity: 0.65\n },\n accessibility: {\n colorBlindMode: \"\"\n // '' | 'deuteranopia' | 'protanopia' | 'tritanopia' | 'highContrast'\n }\n }\n };\n }\n}\nconst RESERVED_TYPES = [\"icicle\"];\nconst TYPE_ALIASES = {\n funnel: \"bar\",\n pyramid: \"bar\",\n gauge: \"radialBar\",\n waffle: \"unit\",\n histogram: \"bar\",\n waterfall: \"rangeBar\",\n dumbbell: \"rangeBar\",\n streamgraph: \"rangeArea\",\n raincloud: \"violin\",\n // `column` is the name half the world uses for a vertical bar chart, and the\n // combo path has always accepted it on `series[].type`. On `chart.type` it\n // used to fall through every dispatch and die inside the renderer (#5325),\n // so it is spelled out here as what it has always meant.\n column: \"bar\"\n};\nconst XY_TYPES = [\n \"line\",\n \"area\",\n \"bar\",\n \"rangeBar\",\n \"rangeArea\",\n \"candlestick\",\n \"boxPlot\",\n \"violin\",\n \"scatter\",\n \"bubble\"\n];\nconst AXIS_ONLY_TYPES = [\"radar\", \"heatmap\", \"treemap\"];\nconst NON_AXIS_TYPES = [\n \"pie\",\n \"donut\",\n \"polarArea\",\n \"radialBar\",\n \"unit\",\n \"sunburst\",\n \"icicle\"\n];\nconst BUILTIN_TYPES = [\n ...XY_TYPES,\n ...AXIS_ONLY_TYPES,\n ...NON_AXIS_TYPES\n];\nconst AXIS_TYPES = [...XY_TYPES, ...AXIS_ONLY_TYPES];\nconst SOLO_TYPES = [...AXIS_ONLY_TYPES, ...NON_AXIS_TYPES];\nconst TYPE_OWNED = \"_apexOwnedByType\";\nconst ownedBy = (types, fn) => {\n const marked = (\n /** @type {any} */\n fn\n );\n marked[TYPE_OWNED] = types;\n return fn;\n};\nconst TYPE_OWNED_PATHS = [\n // What the tooltip reads and how it resolves a hover. `custom` is the sharp\n // one: each built-in reads globals only its own type fills.\n \"tooltip.custom\",\n \"tooltip.shared\",\n \"tooltip.intersect\",\n \"tooltip.followCursor\",\n // Whether values are written on the marks, and how they are phrased. A pie's\n // percentage formatter handed a treemap a category name.\n \"dataLabels.enabled\",\n \"dataLabels.formatter\",\n \"plotOptions.bar.dataLabels.position\",\n // A box plot's outlier markers are hit targets; a violin draws none.\n \"markers.size\",\n // The violin layers a raincloud rearranges: which side the density is on,\n // whether the box lane exists and how its whiskers are computed, and where\n // the jitter sits. All decide what is drawn, so they hand over when the\n // type changes (violin <-> raincloud) instead of a raincloud's half-body\n // surviving into a plain violin.\n \"plotOptions.violin.side\",\n \"plotOptions.violin.box.show\",\n \"plotOptions.violin.box.whiskers\",\n \"plotOptions.violin.points.position\",\n // Hover and select feedback, off by design on the types that draw their own.\n \"states.hover.filter.type\",\n \"states.active.filter.type\",\n // Axis chrome that exists to be pointed at.\n \"xaxis.crosshairs.width\",\n \"xaxis.tickPlacement\",\n \"xaxis.tooltip.enabled\",\n // Interaction the type either supports or does not: a violin's categories\n // cannot be range-zoomed, and an index-keyed summary animates as churn.\n \"chart.zoom.enabled\",\n \"chart.animations.dynamicAnimation.enabled\"\n];\nconst readPath = (obj, path) => {\n let cur = (\n /** @type {any} */\n obj\n );\n for (const key of path.split(\".\")) {\n if (cur == null || typeof cur !== \"object\") return void 0;\n cur = cur[key];\n }\n return cur;\n};\nconst writePath = (obj, path, value) => {\n const keys = path.split(\".\");\n const last = keys.pop();\n let cur = (\n /** @type {any} */\n obj\n );\n for (const key of keys) {\n if (cur[key] == null || typeof cur[key] !== \"object\") cur[key] = {};\n cur = cur[key];\n }\n if (value === void 0) delete cur[\n /** @type {string} */\n last\n ];\n else cur[\n /** @type {string} */\n last\n ] = value;\n};\nconst typeOpts = (type, config) => {\n var _a, _b;\n const base = (\n /** @type {Record} */\n TYPE_ALIASES[type]\n );\n return {\n chart: {\n type: base || type,\n requestedType: base ? type : void 0,\n // Stacking belongs to the chart, not to its type, so both sides see it.\n stacked: (_a = config.chart) == null ? void 0 : _a.stacked\n },\n plotOptions: {\n bar: { isFunnel: type === \"funnel\" || type === \"pyramid\" },\n histogram: (_b = config.plotOptions) == null ? void 0 : _b.histogram\n },\n // The histogram's defaults read the series to decide whether overlaid bins\n // share a tooltip. Both sides are asked with the series the chart has now.\n series: config.series,\n yaxis: [{ title: {}, labels: {}, axisBorder: {}, axisTicks: {} }]\n };\n};\nconst isUntouched = (current, fromDefault) => {\n if (typeof current === \"function\") {\n if (Array.isArray(\n /** @type {any} */\n current[TYPE_OWNED]\n )) return true;\n return typeof fromDefault === \"function\" && String(current) === String(fromDefault);\n }\n if (typeof fromDefault === \"function\") return current === void 0;\n if (current === fromDefault) return true;\n try {\n return JSON.stringify(current) === JSON.stringify(fromDefault);\n } catch (e2) {\n return false;\n }\n};\nconst getRangeValues = ({\n isTimeline,\n seriesIndex,\n dataPointIndex,\n y1,\n y2,\n w\n}) => {\n var _a;\n let start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex];\n let end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex];\n let ylabel = w.labelData.labels[dataPointIndex];\n let seriesName = w.config.series[seriesIndex].name ? w.config.series[seriesIndex].name : \"\";\n const yLbFormatter = w.formatters.ttKeyFormatter;\n const yLbTitleFormatter = w.config.tooltip.y.title.formatter;\n const opts = {\n w,\n seriesIndex,\n dataPointIndex,\n start,\n end\n };\n if (typeof yLbTitleFormatter === \"function\") {\n seriesName = yLbTitleFormatter(seriesName, opts);\n }\n if ((_a = w.config.series[seriesIndex].data[dataPointIndex]) == null ? void 0 : _a.x) {\n ylabel = w.config.series[seriesIndex].data[dataPointIndex].x;\n }\n if (!isTimeline) {\n if (w.config.xaxis.type === \"datetime\") {\n const xFormat = new Formatters(w);\n ylabel = xFormat.xLabelFormat(\n w.formatters.ttKeyFormatter,\n ylabel,\n ylabel,\n {\n i: void 0,\n dateFormatter: new DateTime(w).formatDate,\n w\n }\n );\n }\n }\n if (typeof yLbFormatter === \"function\") {\n ylabel = yLbFormatter(ylabel, opts);\n }\n if (Number.isFinite(y1) && Number.isFinite(y2)) {\n start = y1;\n end = y2;\n }\n let startVal = \"\";\n let endVal = \"\";\n const color = w.globals.colors[seriesIndex];\n if (w.config.tooltip.x.formatter === void 0) {\n if (w.config.xaxis.type === \"datetime\") {\n const datetimeObj = new DateTime(w);\n startVal = datetimeObj.formatDate(\n datetimeObj.getDate(start),\n w.config.tooltip.x.format\n );\n endVal = datetimeObj.formatDate(\n datetimeObj.getDate(end),\n w.config.tooltip.x.format\n );\n } else {\n startVal = start;\n endVal = end;\n }\n } else {\n startVal = w.config.tooltip.x.formatter(start);\n endVal = w.config.tooltip.x.formatter(end);\n }\n return { start, end, startVal, endVal, ylabel, color, seriesName };\n};\nconst buildRangeTooltipHTML = (opts) => {\n let { color, seriesName, ylabel, start, end, seriesIndex, dataPointIndex } = opts;\n const formatter = opts.w.globals.tooltip.tooltipLabels.getFormatters(seriesIndex);\n start = formatter.yLbFormatter(start);\n end = formatter.yLbFormatter(end);\n const val = formatter.yLbFormatter(\n opts.w.seriesData.series[seriesIndex][dataPointIndex]\n );\n let valueHTML = \"\";\n const rangeValues = `\n ${start}\n - \n ${end}\n `;\n if (opts.w.globals.comboCharts) {\n if (opts.w.config.series[seriesIndex].type === \"rangeArea\" || opts.w.config.series[seriesIndex].type === \"rangeBar\") {\n valueHTML = rangeValues;\n } else {\n valueHTML = `${val}`;\n }\n } else {\n valueHTML = rangeValues;\n }\n return '
' + (seriesName ? seriesName : \"\") + '
' + ylabel + \": \" + valueHTML + \"
\";\n};\nclass Defaults {\n /**\n * @param {Record} opts\n */\n constructor(opts) {\n this.opts = opts;\n }\n /**\n * The defaults a chart type chooses for itself, which is the same pick\n * Config.init makes on the initial render. Shared with the update path so\n * that \"what does type X want\" has one answer and cannot drift between the\n * two. Modes layered on top of a type (brush, slope, sparkline) are not\n * included: they belong to the chart, not to its type, and a type change does\n * not disturb them.\n *\n * @param {Record} opts a config, read for the type and for the\n * flags that pick a variant of it\n * @returns {Record}\n */\n static forType(opts) {\n var _a, _b;\n const defaults = new Defaults(opts);\n const chartTypes = BUILTIN_TYPES;\n const requestedType = opts.chart.requestedType;\n let chartDefaults;\n if (requestedType === \"funnel\" || requestedType === \"pyramid\") {\n chartDefaults = /** @type {any} */\n defaults[requestedType]();\n } else if (requestedType === \"gauge\") {\n chartDefaults = defaults.gauge();\n } else if (requestedType === \"histogram\") {\n chartDefaults = defaults.histogram();\n } else if (requestedType === \"waterfall\") {\n chartDefaults = defaults.waterfall();\n } else if (requestedType === \"dumbbell\") {\n chartDefaults = defaults.dumbbell();\n } else if (requestedType === \"streamgraph\") {\n chartDefaults = defaults.streamgraph();\n } else if (requestedType === \"raincloud\") {\n chartDefaults = defaults.raincloud();\n } else if (chartTypes.indexOf(opts.chart.type) !== -1) {\n chartDefaults = /** @type {any} */\n defaults[opts.chart.type]();\n } else {\n chartDefaults = defaults.line();\n }\n if ((_b = (_a = opts.plotOptions) == null ? void 0 : _a.bar) == null ? void 0 : _b.isFunnel) {\n chartDefaults = defaults.funnel();\n }\n if (opts.chart.stacked && opts.chart.type === \"bar\") {\n chartDefaults = defaults.stackedBars();\n }\n return chartDefaults;\n }\n /**\n * Re-choose the type-owned leaves (see TYPE_OWNED_PATHS) after\n * `updateOptions({ chart: { type } })` moved the chart from one type to\n * another, so the chart behaves as the type it now is.\n *\n * A leaf is only handed over when it still holds exactly what `fromType`\n * chose for it. That single test covers every way a value can be the user's\n * instead of ours: set at construction, set by an earlier update, or set by\n * this very update. `options` is consulted too, so an explicit ask in the\n * same call wins even when it happens to equal the outgoing default.\n *\n * @param {Record} config the merged w.config, mutated in place\n * @param {string} fromType the type (or requested alias) before this update\n * @param {Record} [options] this update's payload\n */\n static handOverTypeDefaults(config, fromType, options2) {\n const toType = config.chart.requestedType || config.chart.type;\n if (!fromType || fromType === toType) return;\n const base = new Options().init();\n const from = Utils$1.extend(\n base,\n Defaults.forType(typeOpts(fromType, config))\n );\n const to = Utils$1.extend(base, Defaults.forType(typeOpts(toType, config)));\n for (const path of TYPE_OWNED_PATHS) {\n if (options2 && readPath(options2, path) !== void 0) continue;\n const fromDefault = readPath(from, path);\n const toDefault = readPath(to, path);\n if (fromDefault === void 0 && toDefault === void 0) continue;\n if (!isUntouched(readPath(config, path), fromDefault)) continue;\n writePath(config, path, toDefault);\n }\n }\n hideYAxis() {\n this.opts.yaxis[0].show = false;\n this.opts.yaxis[0].title.text = \"\";\n this.opts.yaxis[0].axisBorder.show = false;\n this.opts.yaxis[0].axisTicks.show = false;\n this.opts.yaxis[0].floating = true;\n }\n line() {\n return {\n dataLabels: {\n enabled: false\n },\n stroke: {\n width: 5,\n curve: \"straight\"\n },\n markers: {\n size: 0,\n hover: {\n sizeOffset: 6\n }\n },\n xaxis: {\n crosshairs: {\n width: 1\n }\n }\n };\n }\n /**\n * @param {Record} defaults\n */\n sparkline(defaults) {\n this.hideYAxis();\n const ret = {\n grid: {\n show: false,\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n },\n legend: {\n show: false\n },\n xaxis: {\n labels: {\n show: false\n },\n tooltip: {\n enabled: false\n },\n axisBorder: {\n show: false\n },\n axisTicks: {\n show: false\n }\n },\n chart: {\n toolbar: {\n show: false\n },\n zoom: {\n enabled: false\n }\n },\n dataLabels: {\n enabled: false\n }\n };\n return Utils$1.extend(defaults, ret);\n }\n slope() {\n this.hideYAxis();\n return {\n chart: {\n toolbar: {\n show: false\n },\n zoom: {\n enabled: false\n }\n },\n dataLabels: {\n enabled: true,\n /**\n * @param {any} val\n * @param {Record} opts\n */\n formatter(val, opts) {\n const seriesName = opts.w.config.series[opts.seriesIndex].name;\n return val !== null ? seriesName + \": \" + val : \"\";\n },\n background: {\n enabled: false\n },\n offsetX: -5\n },\n grid: {\n xaxis: {\n lines: {\n show: true\n }\n },\n yaxis: {\n lines: {\n show: false\n }\n }\n },\n xaxis: {\n position: \"top\",\n labels: {\n style: {\n fontSize: 14,\n fontWeight: 900\n }\n },\n tooltip: {\n enabled: false\n },\n crosshairs: {\n show: false\n }\n },\n markers: {\n size: 8,\n hover: {\n sizeOffset: 1\n }\n },\n legend: {\n show: false\n },\n tooltip: {\n shared: false,\n intersect: true,\n followCursor: true\n },\n stroke: {\n width: 5,\n curve: \"straight\"\n }\n };\n }\n bar() {\n return {\n chart: {\n stacked: false\n },\n plotOptions: {\n bar: {\n dataLabels: {\n position: \"center\"\n }\n }\n },\n dataLabels: {\n style: {\n colors: [\"#fff\"]\n },\n background: {\n enabled: false\n }\n },\n stroke: {\n width: 0,\n lineCap: \"square\"\n },\n fill: {\n opacity: 0.85\n },\n legend: {\n markers: {\n shape: \"square\"\n }\n },\n tooltip: {\n shared: false,\n intersect: true\n },\n xaxis: {\n tooltip: {\n enabled: false\n },\n tickPlacement: \"between\",\n crosshairs: {\n width: \"barWidth\",\n position: \"back\",\n fill: {\n type: \"gradient\"\n },\n dropShadow: {\n enabled: false\n },\n stroke: {\n width: 0\n }\n }\n }\n };\n }\n funnel() {\n this.hideYAxis();\n return __spreadProps(__spreadValues({}, this.bar()), {\n chart: {\n animations: {\n speed: 800,\n animateGradually: {\n enabled: false\n }\n }\n },\n plotOptions: {\n bar: {\n horizontal: true,\n borderRadiusApplication: \"around\",\n borderRadius: 0,\n dataLabels: {\n position: \"center\"\n }\n }\n },\n grid: {\n show: false,\n padding: {\n left: 0,\n right: 0\n }\n },\n xaxis: {\n labels: {\n show: false\n },\n tooltip: {\n enabled: false\n },\n axisBorder: {\n show: false\n },\n axisTicks: {\n show: false\n }\n }\n });\n }\n pyramid() {\n return this.funnel();\n }\n gauge() {\n const base = this.radialBar();\n return __spreadProps(__spreadValues({}, base), {\n plotOptions: {\n radialBar: {\n startAngle: -135,\n endAngle: 135,\n hollow: {\n margin: 0,\n size: \"60%\"\n },\n track: {\n background: \"#e7e7e7\",\n strokeWidth: \"100%\",\n margin: 5\n },\n dataLabels: {\n name: {\n show: false\n },\n value: {\n show: true,\n fontSize: \"32px\",\n fontWeight: 600,\n // Placed as the gauge is drawn (see Radial.draw): 8, or on the\n // needle shape below where the needle reaches.\n offsetY: void 0\n }\n }\n }\n }\n });\n }\n waterfall() {\n var _a;\n const range = this.rangeBar();\n return __spreadProps(__spreadValues({}, range), {\n chart: {\n stacked: false,\n // A waterfall is a fixed set of named steps, not a window onto a\n // continuum: there is nothing to zoom into, and a horizontal one would\n // otherwise inherit the timeline range bar's zoom toolbar.\n zoom: {\n enabled: false\n },\n animations: {\n // The bars ARE a left-to-right sequence, so the staggered reveal\n // traces the walk instead of implying an order that is not there.\n // (A timeline range bar turns this off; a waterfall wants it.)\n animateGradually: {\n enabled: true\n }\n }\n },\n plotOptions: __spreadProps(__spreadValues({}, range.plotOptions), {\n bar: __spreadProps(__spreadValues(\n {},\n /** @type {any} */\n range.plotOptions.bar\n ), {\n // Narrower than a plain bar's 70%, because the gaps are load-bearing\n // here: the connectors are drawn in them. Both orientations, so a\n // horizontal waterfall's connectors have room too.\n columnWidth: \"60%\",\n barHeight: \"60%\"\n })\n }),\n dataLabels: __spreadProps(__spreadValues(\n {},\n /** @type {any} */\n range.dataLabels\n ), {\n // The step is the whole point of a waterfall, so it is written on the\n // bar by default. The inherited range formatter already reports\n // `end - start`, which is the delta for a step bar and the sum for a\n // subtotal / total bar.\n enabled: true,\n // No chip behind the label. A waterfall is usually a dense row of\n // steps, and a chip per label is a second rectangle competing with the\n // bar it names.\n background: {\n enabled: false\n },\n style: __spreadProps(__spreadValues(\n {},\n /** @type {any} */\n (_a = range.dataLabels) == null ? void 0 : _a.style\n ), {\n // Small steps are normal in a waterfall, and a label wider or taller\n // than its bar gets placed OUTSIDE it. The range column's white ink\n // is then white text on the chart background, so the two smallest\n // steps of a P&L bridge simply vanished. Following `chart.foreColor`\n // instead keeps the label readable off the bar in either theme, and\n // legible enough over an increase/decrease/total bar.\n colors: [\n /** @param {any} opts */\n (opts) => opts.w.config.chart.foreColor\n ]\n })\n }),\n legend: {\n // A waterfall is one series, so the legend would show a single swatch\n // named after it, and clicking it empties the chart. The legend a\n // waterfall actually wants names the KINDS of bar (increase, decrease,\n // total), which is not something the series legend can express.\n show: false\n },\n tooltip: {\n shared: false,\n intersect: true,\n followCursor: false\n // Deliberately no `custom`: the range-column tooltip reads out\n // \"start - end\", which is a span the data never claims. The ordinary\n // tooltip is correct once the value it prints is the step, which\n // TooltipLabels.formatYValue takes from `w.waterfallData.values`.\n }\n });\n }\n histogram() {\n var _a, _b, _c, _d;\n const overlaid = Array.isArray((_a = this.opts) == null ? void 0 : _a.series) && this.opts.series.length > 1 && ((_d = (_c = (_b = this.opts) == null ? void 0 : _b.plotOptions) == null ? void 0 : _c.histogram) == null ? void 0 : _d.overlap) !== false;\n return __spreadProps(__spreadValues({}, this.bar()), {\n chart: {\n stacked: false,\n // The bins are the summary: they are chosen once from the whole sample\n // and do NOT re-derive from the visible window, so zooming only\n // magnifies bars while hiding the rest of the distribution the shape is\n // read against. Off by default, mirroring heatmap and violin; users can\n // opt back in with chart.zoom.enabled: true.\n zoom: {\n enabled: false\n },\n animations: {\n // The bars of a histogram are one shape, not N independent\n // categories, so revealing them one by one reads as a sequence that\n // is not in the data. The distribution rises as a whole instead.\n animateGradually: {\n enabled: false\n }\n }\n },\n plotOptions: {\n bar: {\n // Bins are adjacent by definition, so the columns touch: a gap\n // between them would read as a gap in the data. Rounded corners are\n // dropped for the same reason (they shave area off each bar, and a\n // histogram's whole claim is that area is proportional to count).\n columnWidth: \"100%\",\n borderRadius: 0,\n dataLabels: {\n position: \"top\"\n }\n }\n },\n dataLabels: {\n enabled: false\n },\n fill: overlaid ? { opacity: 0.65 } : {},\n // A hairline separator keeps the bin boundaries readable once the columns\n // touch, the same treatment heatmap cells get.\n stroke: overlaid ? { show: false } : {\n show: true,\n width: 1,\n colors: [\"#fff\"]\n },\n xaxis: {\n type: \"numeric\",\n // The axis carries bin midpoints; the range is what people read, and\n // the tooltip already states it.\n tooltip: {\n enabled: false\n }\n },\n tooltip: {\n // Overlaid bars share a bin, so hovering one has to report both\n // distributions: the comparison is the whole point of stacking them on\n // one axis.\n shared: overlaid,\n intersect: false,\n x: {\n formatter: (val, opts) => {\n var _a2, _b2;\n const edges = (_b2 = (_a2 = opts == null ? void 0 : opts.w) == null ? void 0 : _a2.histogramData) == null ? void 0 : _b2.edges;\n const k = opts == null ? void 0 : opts.dataPointIndex;\n if (!Array.isArray(edges) || typeof k !== \"number\" || k < 0) {\n return String(val);\n }\n const lo = edges[k];\n const hi = edges[k + 1];\n if (lo === void 0 || hi === void 0) return String(val);\n const fmt = (v) => Number.isInteger(v) ? String(v) : v.toFixed(2);\n return `${fmt(lo)} to ${fmt(hi)}`;\n }\n }\n }\n });\n }\n candlestick() {\n return {\n stroke: {\n width: 1\n },\n fill: {\n opacity: 1\n },\n dataLabels: {\n enabled: false\n },\n tooltip: {\n shared: true,\n custom: ownedBy(\n [\"candlestick\"],\n ({ seriesIndex, dataPointIndex, w }) => {\n return this._getBoxTooltip(\n w,\n seriesIndex,\n dataPointIndex,\n [\"Open\", \"High\", \"\", \"Low\", \"Close\"],\n \"candlestick\"\n );\n }\n )\n },\n states: {\n active: {\n filter: {\n type: \"none\"\n }\n }\n },\n xaxis: {\n crosshairs: {\n width: 1\n }\n }\n };\n }\n boxPlot() {\n return {\n // No dynamicAnimation override any more: box plot updates used to be\n // switched off here (2021), since nothing captured a box's previous shape\n // and every update snapped. Boxes now morph from their own previous\n // shape, keyed by datum, like candlesticks and bars.\n stroke: {\n width: 1,\n colors: [\"#24292e\"]\n },\n dataLabels: {\n enabled: false\n },\n tooltip: {\n shared: true,\n custom: ownedBy(\n [\"boxPlot\"],\n ({ seriesIndex, dataPointIndex, w }) => {\n return this._getBoxTooltip(\n w,\n seriesIndex,\n dataPointIndex,\n [\"Minimum\", \"Q1\", \"Median\", \"Q3\", \"Maximum\"],\n \"boxPlot\"\n );\n }\n )\n },\n markers: {\n size: 7,\n strokeWidth: 1,\n strokeColors: \"#111\"\n },\n xaxis: {\n crosshairs: {\n width: 1\n }\n }\n };\n }\n violin() {\n return {\n chart: {\n // Violins are a per-category distribution plot (discrete category\n // x-axis), so range zooming/panning is meaningless \u2014 off by default.\n zoom: {\n enabled: false\n },\n animations: {\n dynamicAnimation: {\n enabled: false\n }\n }\n },\n stroke: {\n width: 1,\n colors: [\"#24292e\"]\n },\n fill: {\n opacity: 0.7\n },\n dataLabels: {\n enabled: false\n },\n tooltip: {\n shared: true,\n custom: ownedBy(\n [\"violin\"],\n ({ seriesIndex, dataPointIndex, w }) => {\n return this._getViolinTooltip(w, seriesIndex, dataPointIndex);\n }\n )\n },\n states: {\n active: {\n filter: {\n type: \"none\"\n }\n }\n },\n xaxis: {\n crosshairs: {\n width: 1\n }\n }\n };\n }\n raincloud() {\n var _a, _b, _c;\n const base = this.violin();\n const horizontal = ((_c = (_b = (_a = this.opts) == null ? void 0 : _a.plotOptions) == null ? void 0 : _b.bar) == null ? void 0 : _c.horizontal) === true;\n return __spreadProps(__spreadValues({}, base), {\n plotOptions: {\n violin: {\n side: horizontal ? \"top\" : \"right\",\n box: {\n show: true,\n // Tukey fences over minmax: the canonical raincloud box, and safe\n // here precisely because the rain draws every observation, so\n // nothing beyond the whiskers is hidden.\n whiskers: \"tukey\"\n },\n points: {\n position: horizontal ? \"bottom\" : \"left\",\n // Fill most of the rain lane; the lane is the dots' whole home,\n // unlike the centered violin scatter that shares it with the body.\n jitter: 0.85\n }\n }\n },\n tooltip: __spreadProps(__spreadValues({}, base.tooltip), {\n custom: ownedBy(\n [\"raincloud\"],\n ({ seriesIndex, dataPointIndex, w }) => {\n return this._getRaincloudTooltip(w, seriesIndex, dataPointIndex);\n }\n )\n })\n });\n }\n rangeBar() {\n const handleTimelineTooltip = (opts) => {\n const { color, seriesName, ylabel, startVal, endVal } = getRangeValues(__spreadProps(__spreadValues({}, opts), {\n isTimeline: true\n }));\n return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {\n color,\n seriesName,\n ylabel,\n start: startVal,\n end: endVal\n }));\n };\n const handleRangeColumnTooltip = (opts) => {\n const { color, seriesName, ylabel, start, end } = getRangeValues(opts);\n return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {\n color,\n seriesName,\n ylabel,\n start,\n end\n }));\n };\n return {\n chart: {\n animations: {\n animateGradually: false\n }\n },\n stroke: {\n width: 0,\n lineCap: \"square\"\n },\n plotOptions: {\n bar: {\n borderRadius: 0,\n dataLabels: {\n position: \"center\"\n }\n }\n },\n dataLabels: {\n enabled: false,\n /**\n * @param {any} val\n */\n formatter(val, { seriesIndex, dataPointIndex, w }) {\n const getVal = () => {\n const start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex];\n const end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex];\n return end - start;\n };\n if (w.globals.comboCharts) {\n if (w.config.series[seriesIndex].type === \"rangeBar\" || w.config.series[seriesIndex].type === \"rangeArea\") {\n return getVal();\n } else {\n return val;\n }\n } else {\n return getVal();\n }\n },\n background: {\n enabled: false\n },\n style: {\n colors: [\"#fff\"]\n }\n },\n markers: {\n size: 10\n },\n tooltip: {\n shared: false,\n followCursor: true,\n custom: ownedBy(\n [\"rangeBar\"],\n /** @param {Record} opts */\n (opts) => {\n if (opts.w.config.plotOptions && opts.w.config.plotOptions.bar && opts.w.config.plotOptions.bar.horizontal) {\n return handleTimelineTooltip(opts);\n } else {\n return handleRangeColumnTooltip(opts);\n }\n }\n )\n },\n xaxis: {\n tickPlacement: \"between\",\n tooltip: {\n enabled: false\n },\n crosshairs: {\n stroke: {\n width: 0\n }\n }\n }\n };\n }\n dumbbell() {\n const range = this.rangeBar();\n const endpointRow = (name2, color, value) => '
' + name2 + ' ' + value + \"
\";\n const handleDumbbellTooltip = (opts) => {\n var _a;\n const { w, dataPointIndex, seriesIndex } = opts;\n const dumbbell = w.dumbbellData;\n if (!dumbbell || dumbbell.form !== \"series\") {\n const { color, seriesName, ylabel: ylabel2, start, end } = getRangeValues(opts);\n return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {\n color,\n seriesName,\n ylabel: ylabel2,\n start,\n end\n }));\n }\n const values = dumbbell.values[dataPointIndex] || [];\n const formatter = w.globals.tooltip.tooltipLabels.getFormatters(seriesIndex);\n const ylabel = (_a = w.labelData.labels[dataPointIndex]) != null ? _a : \"\";\n let rows = \"\";\n const shown = [];\n for (let k = 0; k < values.length; k++) {\n if (values[k] === null || dumbbell.hidden.indexOf(k) !== -1) continue;\n shown.push(values[k]);\n rows += endpointRow(\n dumbbell.names[k],\n w.globals.colors[k],\n formatter.yLbFormatter(values[k])\n );\n }\n const gap = shown.length === 2 ? '
' + w.config.plotOptions.bar.dumbbell.tooltip.differenceLabel + ': ' + formatter.yLbFormatter(Math.abs(shown[1] - shown[0])) + \"
\" : \"\";\n return '
' + ylabel + \"
\" + rows + gap + \"
\";\n };\n return __spreadProps(__spreadValues({}, range), {\n chart: {\n stacked: false,\n // A dumbbell is a fixed set of named rows, not a window onto a\n // continuum: there is nothing to zoom into, and a horizontal one would\n // otherwise inherit the timeline range bar's zoom toolbar.\n zoom: {\n enabled: false\n }\n },\n plotOptions: __spreadProps(__spreadValues({}, range.plotOptions), {\n bar: __spreadProps(__spreadValues(\n {},\n /** @type {any} */\n range.plotOptions.bar\n ), {\n // The connector, not a bar: thin enough that the marked ends are what\n // the eye lands on, thick enough to read as a join at a glance.\n barHeight: 6,\n columnWidth: 6,\n dumbbell: {\n dataLabels: {\n // The two values ARE the comparison, so they are written at the\n // ends by default. The centred range label a range bar would draw\n // reads out `end - start` over the connector, which is the one\n // number a dumbbell can already be seen to say.\n enabled: true\n }\n }\n })\n }),\n dataLabels: __spreadProps(__spreadValues(\n {},\n /** @type {any} */\n range.dataLabels\n ), {\n enabled: false\n }),\n legend: {\n // Two named measures, which is exactly what the series legend is for.\n // (The `y: [lo, hi]` form has one series and no endpoint names; that is\n // what `legend.customLegendItems` is for.)\n show: true,\n position: \"bottom\",\n horizontalAlign: \"left\",\n markers: {\n // Echoes the marked ends rather than the connector.\n shape: \"circle\"\n }\n },\n tooltip: {\n shared: false,\n intersect: true,\n followCursor: false,\n custom: ownedBy([\"rangeBar\"], handleDumbbellTooltip)\n }\n });\n }\n /**\n * The connector's thickness, for any range bar drawn `isDumbbell`.\n *\n * Written into the opts rather than returned as defaults because it applies\n * to the flag wherever it is set, not only to `chart.type: 'dumbbell'`.\n *\n * @param {Record} opts\n */\n dumbbellSizing(opts) {\n var _a, _b;\n if (!((_a = opts.plotOptions.bar) == null ? void 0 : _a.barHeight)) {\n opts.plotOptions.bar.barHeight = 2;\n }\n if (!((_b = opts.plotOptions.bar) == null ? void 0 : _b.columnWidth)) {\n opts.plotOptions.bar.columnWidth = 2;\n }\n return opts;\n }\n area() {\n return {\n stroke: {\n width: 4,\n fill: {\n type: \"solid\",\n gradient: {\n inverseColors: false,\n shade: \"light\",\n type: \"vertical\",\n opacityFrom: 0.65,\n opacityTo: 0.5,\n stops: [0, 100, 100]\n }\n }\n },\n fill: {\n type: \"gradient\",\n gradient: {\n inverseColors: false,\n shade: \"light\",\n type: \"vertical\",\n opacityFrom: 0.65,\n opacityTo: 0.5,\n stops: [0, 100, 100]\n }\n },\n markers: {\n size: 0,\n hover: {\n sizeOffset: 6\n }\n },\n tooltip: {\n followCursor: false\n }\n };\n }\n rangeArea() {\n const handleRangeAreaTooltip = (opts) => {\n const { color, seriesName, ylabel, start, end } = getRangeValues(opts);\n return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {\n color,\n seriesName,\n ylabel,\n start,\n end\n }));\n };\n return {\n stroke: {\n curve: \"straight\",\n width: 0\n },\n fill: {\n type: \"solid\",\n opacity: 0.6\n },\n markers: {\n size: 0\n },\n states: {\n hover: {\n filter: {\n type: \"none\"\n }\n },\n active: {\n filter: {\n type: \"none\"\n }\n }\n },\n tooltip: {\n intersect: false,\n shared: true,\n followCursor: true,\n custom: ownedBy(\n [\"rangeArea\"],\n /** @param {Record} opts */\n (opts) => handleRangeAreaTooltip(opts)\n )\n }\n };\n }\n streamgraph() {\n const range = this.rangeArea();\n const handleStreamTooltip = (opts) => {\n var _a;\n const { w, dataPointIndex, seriesIndex } = opts;\n const data = w.streamgraphData;\n if (!data || !Array.isArray(data.order)) {\n const { color, seriesName, ylabel: ylabel2, start, end } = getRangeValues(opts);\n return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {\n color,\n seriesName,\n ylabel: ylabel2,\n start,\n end\n }));\n }\n const { ylabel } = getRangeValues(opts);\n const active = (() => {\n const d = w.streamgraphData;\n const svg = w.dom.baseEl && w.dom.baseEl.querySelector(\".apexcharts-svg\");\n const clientY = w.interact && w.interact.clientY;\n const span = w.globals.maxY - w.globals.minY;\n if (!svg || clientY == null || !span || !isFinite(span)) {\n return seriesIndex;\n }\n const rect = svg.getBoundingClientRect();\n const zoom = w.globals.svgWidth ? rect.width / w.globals.svgWidth : 1;\n const py = (clientY - rect.top) / (zoom || 1) - w.layout.translateY;\n const h = w.layout.gridHeight;\n const yPx = (v) => {\n var _a2;\n const frac = (v - w.globals.minY) / span;\n return ((_a2 = w.config.yaxis[0]) == null ? void 0 : _a2.reversed) ? frac * h : h - frac * h;\n };\n let nearest = seriesIndex;\n let gap = Infinity;\n for (let i2 = 0; i2 < d.order.length; i2++) {\n const k = d.order[i2];\n const lo = d.lows[k] && d.lows[k][dataPointIndex];\n const hi = d.highs[k] && d.highs[k][dataPointIndex];\n if (lo == null || hi == null) continue;\n const a2 = yPx(hi);\n const b = yPx(lo);\n const top = Math.min(a2, b);\n const bottom = Math.max(a2, b);\n if (py >= top && py <= bottom) return k;\n const dist = py < top ? top - py : py - bottom;\n if (dist < gap) {\n gap = dist;\n nearest = k;\n }\n }\n return nearest;\n })();\n const configured = w.formatters.ttVal !== void 0;\n const bandValue = (k, v) => {\n if (configured) {\n const f = w.globals.tooltip.tooltipLabels.getFormatters(k);\n if (typeof f.yLbFormatter === \"function\") return f.yLbFormatter(v);\n }\n if (Number.isInteger(v)) return String(v);\n return String(Number(v.toFixed(6)));\n };\n let rows = \"\";\n let total = 0;\n for (let i2 = data.order.length - 1; i2 >= 0; i2--) {\n const k = data.order[i2];\n const v = (_a = data.values[k]) == null ? void 0 : _a[dataPointIndex];\n if (v == null || !isFinite(v)) continue;\n total += v;\n rows += '
' + data.names[k] + ' ' + bandValue(k, v) + \"
\";\n }\n const totalRow = data.offset === \"expand\" ? \"\" : '
Total ' + bandValue(seriesIndex, total) + \"
\";\n return '
' + ylabel + \"
\" + rows + totalRow + \"
\";\n };\n return __spreadProps(__spreadValues({}, range), {\n chart: {\n stacked: false\n },\n stroke: {\n // monotoneCubic, not `smooth`. `smooth` sets its control points at a\n // fixed fraction of the x gap without consulting the slope on either\n // side, which puts an inflection at EVERY point: a band that simply\n // declines (18, 9, 0) is drawn as a run of little S-curves, so it\n // appears to stall and dip repeatedly on the way down. On a stack of\n // twenty bands that invented wobble is most of what the reader sees.\n // Fritsch-Carlson is shape preserving \u2014 where the data is monotone the\n // curve is monotone \u2014 so a falling band reads as one continuous fall.\n curve: \"monotoneCubic\",\n // Bands meet edge to edge, so any stroke at all draws a seam down the\n // middle of every boundary and doubles it at the two outer edges.\n width: 0\n },\n fill: {\n type: \"solid\",\n // A streamgraph reads as one continuous surface, so the bands are\n // opaque: at range-area's 0.6 the grid shows through and the boundaries\n // between neighbours turn into a third, muddier colour.\n opacity: 1\n },\n dataLabels: {\n // One label per point on a stacked surface is unreadable at any real\n // series count. The names go on the bands instead\n // (plotOptions.streamgraph.labels).\n enabled: false\n },\n grid: {\n // There is nothing to measure against, so gridlines only add noise\n // behind an opaque surface. The x ruler stays: the whole point of the\n // form is *when* the mix changed.\n //\n // `padding` is deliberately left alone. Zeroing it so the surface\n // bleeds to the plot edges is tempting and costs almost nothing\n // visually, but it puts the first and last category label half outside\n // the SVG, so a category streamgraph starts with an axis reading \"19\"\n // where it should read \"2019\".\n yaxis: { lines: { show: false } }\n },\n markers: {\n size: 0,\n // A streamgraph has no data points to hit, only bands. The inherited\n // `sizeOffset` grows a size-0 marker to 3px on hover, which puts a dot\n // on a band BOUNDARY \u2014 a place that is not a value in either band.\n hover: {\n size: 0,\n sizeOffset: 0\n }\n },\n tooltip: {\n intersect: false,\n shared: false,\n followCursor: true,\n custom: ownedBy(\n [\"streamgraph\"],\n /** @param {Record} opts */\n (opts) => handleStreamTooltip(opts)\n )\n },\n legend: {\n // On, even though the band labels already name every band in place.\n // The legend and the labels are not doing the same job: a label says\n // WHICH band this is, and the legend is the only thing on the chart you\n // can CLICK. Dropping it to avoid saying six names twice took the one\n // control a streamgraph really wants with it \u2014 pulling a band out and\n // watching the baseline re-solve under it is most of what there is to\n // do here, and there was no way to ask for it.\n //\n // It also covers the bands too thin to hold a name, which are exactly\n // the ones a reader most needs named.\n show: true,\n position: \"top\",\n horizontalAlign: \"center\"\n }\n });\n }\n /**\n * @param {Record} defaults\n */\n brush(defaults) {\n const ret = {\n chart: {\n toolbar: {\n autoSelected: \"selection\",\n show: false\n },\n zoom: {\n enabled: false\n }\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n width: 1\n },\n tooltip: {\n enabled: false\n },\n xaxis: {\n tooltip: {\n enabled: false\n }\n }\n };\n return Utils$1.extend(defaults, ret);\n }\n /**\n * @param {Record} opts\n */\n stacked100(opts) {\n opts.dataLabels = opts.dataLabels || {};\n opts.yaxis.forEach((yaxe, index) => {\n opts.yaxis[index].min = 0;\n opts.yaxis[index].max = 100;\n });\n if (opts.dataLabels.formatter) return opts;\n const percent = (val) => {\n if (typeof val === \"number\") {\n return val ? val.toFixed(0) + \"%\" : val;\n }\n return val;\n };\n const plain = (val) => val !== null ? val : \"\";\n const chartType = opts.chart.type;\n const isBarSeries = (s2) => s2.type ? s2.type === \"bar\" || s2.type === \"column\" : chartType === \"bar\" || chartType === \"column\";\n const hasBars = (opts.series || []).some(isBarSeries);\n opts.dataLabels.formatter = (val, ctx) => {\n var _a, _b, _c;\n const barIndices = (_c = (_b = (_a = ctx == null ? void 0 : ctx.w) == null ? void 0 : _a.globals) == null ? void 0 : _b.columnSeries) == null ? void 0 : _c.i;\n const isBarLabel = barIndices ? barIndices.includes(ctx == null ? void 0 : ctx.seriesIndex) : hasBars;\n if (isBarLabel) return percent(val);\n return plain(val);\n };\n return opts;\n }\n stackedBars() {\n const barDefaults = this.bar();\n return __spreadProps(__spreadValues({}, barDefaults), {\n plotOptions: __spreadProps(__spreadValues({}, barDefaults.plotOptions), {\n bar: __spreadProps(__spreadValues({}, barDefaults.plotOptions.bar), {\n borderRadiusApplication: \"end\"\n })\n })\n });\n }\n // This function removes the left and right spacing in chart for line/area/scatter if xaxis type = category for those charts by converting xaxis = numeric. Numeric/Datetime xaxis prevents the unnecessary spacing in the left/right of the chart area\n /**\n * @param {Record} opts\n */\n convertCatToNumeric(opts) {\n opts.xaxis.convertedCatToNumeric = true;\n return opts;\n }\n /**\n * @param {Record} opts\n * @param {any[]} [cats] the category names, when they are not in `opts`\n */\n convertCatToNumericXaxis(opts, cats) {\n opts.xaxis.type = \"numeric\";\n opts.xaxis.labels = opts.xaxis.labels || {};\n opts.xaxis.labels.formatter = opts.xaxis.labels.formatter || /**\n * @param {any} val\n */\n function(val) {\n return Utils$1.isNumber(val) ? Math.floor(val) : val;\n };\n const defaultFormatter = opts.xaxis.labels.formatter;\n let labels = opts.xaxis.categories && opts.xaxis.categories.length ? opts.xaxis.categories : opts.labels;\n if (cats && cats.length) {\n labels = cats.map((c) => {\n return Array.isArray(c) ? c : String(c);\n });\n }\n if (labels && labels.length) {\n const names = labels;\n const format = function(val) {\n if (!Utils$1.isNumber(val)) return defaultFormatter(val);\n const label = names[Math.floor(val) - 1];\n return label === void 0 ? \"\" : defaultFormatter(label);\n };\n format.categoryNames = names;\n opts.xaxis.labels.formatter = format;\n }\n opts.xaxis.categories = [];\n opts.labels = [];\n opts.xaxis.tickAmount = opts.xaxis.tickAmount || \"dataPoints\";\n return opts;\n }\n bubble() {\n return {\n dataLabels: {\n style: {\n colors: [\"#fff\"]\n }\n },\n tooltip: {\n shared: false,\n intersect: true\n },\n xaxis: {\n crosshairs: {\n width: 0\n }\n },\n fill: {\n type: \"solid\",\n gradient: {\n shade: \"light\",\n inverse: true,\n shadeIntensity: 0.55,\n opacityFrom: 0.4,\n opacityTo: 0.8\n }\n }\n };\n }\n scatter() {\n return {\n dataLabels: {\n enabled: false\n },\n tooltip: {\n shared: false,\n intersect: true\n },\n markers: {\n size: 6,\n strokeWidth: 1,\n hover: {\n sizeOffset: 2\n }\n }\n };\n }\n heatmap() {\n return {\n chart: {\n stacked: false,\n // A heatmap is a fixed grid: zooming/panning only distorts the cells\n // and (on a datetime axis) collapses the month labels to repeats, so\n // it is off by default, mirroring treemap. Users can opt back in with\n // chart.zoom.enabled: true.\n zoom: {\n enabled: false\n }\n },\n fill: {\n opacity: 1\n },\n dataLabels: {\n style: {\n colors: [\"#fff\"]\n }\n },\n stroke: {\n colors: [\"#fff\"]\n },\n tooltip: {\n // Anchor the tooltip above the hovered cell with a downward arrow\n // (flipping below near the top edge), the same treatment horizontal\n // bars get, rather than trailing the cursor. Opt back into the old\n // behavior with tooltip.followCursor: true.\n followCursor: false,\n marker: {\n show: false\n },\n x: {\n show: false\n }\n },\n legend: {\n position: \"top\",\n markers: {\n shape: \"square\"\n }\n },\n grid: {\n padding: {\n right: 20\n }\n }\n };\n }\n treemap() {\n return {\n chart: {\n zoom: {\n enabled: false\n }\n },\n dataLabels: {\n style: {\n fontSize: 14,\n fontWeight: 600,\n colors: [\"#fff\"]\n }\n },\n stroke: {\n show: true,\n width: 2,\n colors: [\"#fff\"]\n },\n legend: {\n show: false\n },\n fill: {\n opacity: 1,\n gradient: {\n stops: [0, 100]\n }\n },\n tooltip: {\n followCursor: true,\n x: {\n show: false\n }\n },\n grid: {\n padding: {\n left: 0,\n right: 0\n }\n },\n xaxis: {\n crosshairs: {\n show: false\n },\n tooltip: {\n enabled: false\n },\n // A treemap has no x axis to read: the tiles are the whole plot, and\n // the ticks mark data-point positions that mean nothing here. One tick\n // per row is invisible at a dozen rows and a solid comb under the plot\n // at several hundred, so they are off by default. Set\n // `xaxis.axisTicks.show: true` to bring them back.\n axisTicks: {\n show: false\n }\n }\n };\n }\n unit() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n show: false,\n width: 0\n },\n fill: {\n opacity: 1\n },\n tooltip: {\n followCursor: true,\n x: {\n show: false\n }\n },\n legend: {\n show: true,\n position: \"bottom\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n icicle() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n dataLabels: {\n style: {\n colors: [\"#fff\"]\n }\n },\n stroke: {\n colors: [\"#fff\"]\n },\n fill: {\n opacity: 1\n },\n // Off by default: every cell carries its own label, so a legend repeats\n // what the chart already says. It also only lines up with the colours\n // when the tree has several roots, because the palette is applied to the\n // shallowest level that branches. A multi-root icicle can turn it on.\n legend: {\n show: false,\n position: \"bottom\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n sunburst() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n dataLabels: {\n style: {\n colors: [\"#fff\"]\n },\n dropShadow: {\n enabled: true\n }\n },\n stroke: {\n colors: [\"#fff\"]\n },\n fill: {\n opacity: 1\n },\n // Unlike pie, sunburst keeps the STANDARD themed tooltip (light/dark).\n // Slice-coloured tooltips (fillSeriesColor) wash out here because child\n // arcs are tinted toward white per depth; users can still opt in.\n legend: {\n position: \"right\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n pie() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n plotOptions: {\n pie: {\n donut: {\n labels: {\n show: false\n }\n }\n }\n },\n dataLabels: {\n /**\n * The share of the whole, as a percentage. Guarded because a config\n * survives a chart-type change: a pie that becomes a treemap hands\n * this same default a category NAME, and a default of ours must not\n * throw on a value it was never designed for.\n * @param {any} val\n */\n formatter(val) {\n return typeof val === \"number\" ? val.toFixed(1) + \"%\" : val;\n },\n style: {\n colors: [\"#fff\"]\n },\n background: {\n enabled: false\n },\n dropShadow: {\n enabled: true\n }\n },\n stroke: {\n colors: [\"#fff\"]\n },\n fill: {\n opacity: 1,\n gradient: {\n shade: \"light\",\n stops: [0, 100]\n }\n },\n tooltip: {\n theme: \"dark\",\n fillSeriesColor: true\n },\n legend: {\n position: \"right\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n donut() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n dataLabels: {\n /**\n * The share of the whole, as a percentage. Guarded because a config\n * survives a chart-type change: a pie that becomes a treemap hands\n * this same default a category NAME, and a default of ours must not\n * throw on a value it was never designed for.\n * @param {any} val\n */\n formatter(val) {\n return typeof val === \"number\" ? val.toFixed(1) + \"%\" : val;\n },\n style: {\n colors: [\"#fff\"]\n },\n background: {\n enabled: false\n },\n dropShadow: {\n enabled: true\n }\n },\n stroke: {\n colors: [\"#fff\"]\n },\n fill: {\n opacity: 1,\n gradient: {\n shade: \"light\",\n shadeIntensity: 0.35,\n stops: [80, 100],\n opacityFrom: 1,\n opacityTo: 1\n }\n },\n tooltip: {\n theme: \"dark\",\n fillSeriesColor: true\n },\n legend: {\n position: \"right\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n polarArea() {\n return {\n chart: {\n toolbar: {\n show: false\n }\n },\n dataLabels: {\n /**\n * The share of the whole, as a percentage. Guarded because a config\n * survives a chart-type change: a pie that becomes a treemap hands\n * this same default a category NAME, and a default of ours must not\n * throw on a value it was never designed for.\n * @param {any} val\n */\n formatter(val) {\n return typeof val === \"number\" ? val.toFixed(1) + \"%\" : val;\n },\n enabled: false\n },\n stroke: {\n show: true,\n width: 2\n },\n fill: {\n opacity: 0.7\n },\n tooltip: {\n theme: \"dark\",\n fillSeriesColor: true\n },\n legend: {\n position: \"right\"\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n radar() {\n this.opts.yaxis[0].labels.offsetY = this.opts.yaxis[0].labels.offsetY ? this.opts.yaxis[0].labels.offsetY : 6;\n return {\n dataLabels: {\n enabled: false,\n style: {\n fontSize: \"11px\"\n }\n },\n stroke: {\n width: 2\n },\n markers: {\n size: 5,\n strokeWidth: 1,\n strokeOpacity: 1\n },\n fill: {\n opacity: 0.2\n },\n tooltip: {\n shared: false,\n intersect: true,\n followCursor: true\n },\n grid: {\n show: false,\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n },\n xaxis: {\n labels: {\n formatter: (val) => val,\n style: {\n colors: [\"#a8a8a8\"],\n fontSize: \"11px\"\n }\n },\n tooltip: {\n enabled: false\n },\n crosshairs: {\n show: false\n }\n }\n };\n }\n radialBar() {\n return {\n chart: {\n animations: {\n dynamicAnimation: {\n enabled: true,\n speed: 800\n }\n },\n toolbar: {\n show: false\n }\n },\n stroke: {\n // Radial value arcs are stroked open arcs; square/round caps would\n // extend the stroke half a stroke-width past each endpoint, making\n // the \"starting edge\" visibly stick out past the geometric arc.\n // Butt cap is the only one that aligns with the arc's true angular\n // span. Without this, a chart that previously was a bar (whose\n // defaults set lineCap='square') would carry that cap across into\n // the radial render after a type morph.\n lineCap: \"butt\"\n },\n fill: {\n gradient: {\n shade: \"dark\",\n shadeIntensity: 0.4,\n inverseColors: false,\n type: \"diagonal2\",\n opacityFrom: 1,\n opacityTo: 1,\n stops: [70, 98, 100]\n }\n },\n legend: {\n show: false,\n position: \"right\"\n },\n tooltip: {\n enabled: false,\n fillSeriesColor: true\n },\n grid: {\n padding: {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }\n }\n };\n }\n /**\n * @param {import('../../types/internal').ChartStateW} w\n * @param {number} seriesIndex\n * @param {number} dataPointIndex\n * @param {any[]} labels\n * @param {string} chartType\n */\n _getBoxTooltip(w, seriesIndex, dataPointIndex, labels, chartType) {\n const o2 = w.candleData.seriesCandleO[seriesIndex][dataPointIndex];\n const h = w.candleData.seriesCandleH[seriesIndex][dataPointIndex];\n const m = w.candleData.seriesCandleM[seriesIndex][dataPointIndex];\n const l2 = w.candleData.seriesCandleL[seriesIndex][dataPointIndex];\n const c = w.candleData.seriesCandleC[seriesIndex][dataPointIndex];\n const _si = (\n /** @type {Record} */\n w.config.series[seriesIndex]\n );\n if (_si.type && _si.type !== chartType) {\n return `
\n ${_si.name ? _si.name : \"series-\" + (seriesIndex + 1)}: ${w.seriesData.series[seriesIndex][dataPointIndex]}\n
`;\n } else {\n return `
${labels[0]}: ` + o2 + `
${labels[1]}: ` + h + \"
\" + (m ? `
${labels[2]}: ` + m + \"
\" : \"\") + `
${labels[3]}: ` + l2 + `
${labels[4]}: ` + c + \"
\";\n }\n }\n /**\n * Shared tooltip for a violin: distribution value range and observation\n * count. Per-point hover is intentionally unsupported (jitter renders as a\n * single path), so the tooltip summarizes the violin as a whole.\n *\n * @param {import('../../types/internal').ChartStateW} w\n * @param {number} seriesIndex\n * @param {number} dataPointIndex\n */\n _getViolinTooltip(w, seriesIndex, dataPointIndex) {\n var _a, _b, _c;\n const minV = (_a = w.violinData.seriesViolinMin[seriesIndex]) == null ? void 0 : _a[dataPointIndex];\n const maxV = (_b = w.violinData.seriesViolinMax[seriesIndex]) == null ? void 0 : _b[dataPointIndex];\n const pts = ((_c = w.violinData.seriesViolinPoints[seriesIndex]) == null ? void 0 : _c[dataPointIndex]) || [];\n const name2 = (\n /** @type {Record} */\n w.config.series[seriesIndex].name || \"series-\" + (seriesIndex + 1)\n );\n return `
${name2}
Min: ${minV}
Max: ${maxV}
Observations: ${pts.length}
`;\n }\n /**\n * Shared tooltip for a raincloud: the five-number summary its box draws,\n * plus the observation count. Falls back to the violin tooltip when a datum\n * carries no summary (precomputed density without a sample).\n *\n * @param {import('../../types/internal').ChartStateW} w\n * @param {number} seriesIndex\n * @param {number} dataPointIndex\n */\n _getRaincloudTooltip(w, seriesIndex, dataPointIndex) {\n var _a, _b;\n const summary = (_a = w.violinData.seriesViolinSummary[seriesIndex]) == null ? void 0 : _a[dataPointIndex];\n if (!summary) {\n return this._getViolinTooltip(w, seriesIndex, dataPointIndex);\n }\n const pts = ((_b = w.violinData.seriesViolinPoints[seriesIndex]) == null ? void 0 : _b[dataPointIndex]) || [];\n const name2 = (\n /** @type {Record} */\n w.config.series[seriesIndex].name || \"series-\" + (seriesIndex + 1)\n );\n const fmt = (v) => {\n if (!isFinite(v)) return String(v);\n const r2 = Math.round(v);\n return Math.abs(v - r2) < 1e-6 ? String(r2) : String(Number(v.toFixed(2)));\n };\n const [lo, q1, med, q3, hi] = summary;\n return `
${name2}
Whisker high: ${fmt(hi)}
Q3: ${fmt(q3)}
Median: ${fmt(med)}
Q1: ${fmt(q1)}
Whisker low: ${fmt(lo)}
Observations: ${pts.length}
`;\n }\n}\nconst REGISTRY_KEY$1 = \"__apexcharts_registry__\";\nconst CUSTOM_KEY = \"__apexcharts_custom_types__\";\nif (!/** @type {any} */\nglobalThis[REGISTRY_KEY$1]) {\n globalThis[REGISTRY_KEY$1] = {};\n}\nconst MISSING_KEY = \"__apexcharts_missing_types__\";\nif (!/** @type {any} */\nglobalThis[CUSTOM_KEY]) {\n globalThis[CUSTOM_KEY] = /* @__PURE__ */ new Set();\n}\nif (!/** @type {any} */\nglobalThis[MISSING_KEY]) {\n globalThis[MISSING_KEY] = /* @__PURE__ */ new Set();\n}\nfunction getRegistry$1() {\n return (\n /** @type {any} */\n globalThis[REGISTRY_KEY$1]\n );\n}\nfunction getCustomTypes() {\n return (\n /** @type {any} */\n globalThis[CUSTOM_KEY]\n );\n}\nfunction markCustom(name2) {\n getCustomTypes().add(name2);\n}\nfunction isCustom(name2) {\n return getCustomTypes().has(name2);\n}\nfunction hasChartClass(type) {\n return !!getRegistry$1()[type];\n}\nfunction unregister(name2) {\n delete getRegistry$1()[name2];\n getCustomTypes().delete(name2);\n}\nfunction register(typeMap) {\n Object.assign(getRegistry$1(), typeMap);\n}\nfunction getChartClass(type) {\n const Cls = getRegistry$1()[type];\n if (!Cls) {\n const optIn = RESERVED_TYPES.includes(type);\n const message = `ApexCharts: chart type \"${type}\" is not registered. Bundler: import 'apexcharts/${type}'. Script tag: add