{"id":362629,"date":"2026-09-03T13:01:17","date_gmt":"2026-09-03T13:01:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/arts-color-switcher-for-elementor-dark-mode-color-switching-on-scroll\/"},"modified":"2026-09-03T13:00:55","modified_gmt":"2026-09-03T13:00:55","slug":"color-switcher-for-elementor","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/color-switcher-for-elementor\/","author":23271239,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1","requires":"6.0","requires_php":"8.0","requires_plugins":null,"header_name":"Arts Color Switcher for Elementor \u2013 Dark Mode & Color Switching on Scroll","header_author":"Artem Semkin","header_description":"Scroll-triggered color theme switching for Elementor \u2014 give Global Colors an Alt value and morph the whole page palette between sections.","assets_banners_color":"474747","last_updated":"2026-09-03 13:00:55","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/buymeacoffee.com\/artemsemkin","header_plugin_uri":"https:\/\/artemsemkin.com\/plugins\/color-switcher-for-elementor\/","header_author_uri":"https:\/\/artemsemkin.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":30,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"artemsemkin","date":"2026-09-03 13:00:55","revision":3679752}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3679748,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3679748,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3679748,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.jpg":{"filename":"banner-1544x500.jpg","revision":3679748,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":3679748,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3679753,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"landingPage\":\"\\\/?page_id=9931\",\"preferredVersions\":{\"php\":\"8.1\",\"wp\":\"latest\"},\"features\":{\"networking\":true},\"login\":true,\"steps\":[{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"elementor\"},\"options\":{\"activate\":true}},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"artem-semkin-header-engine-for-elementor\"},\"options\":{\"activate\":true}},{\"step\":\"installTheme\",\"themeData\":{\"resource\":\"wordpress.org\\\/themes\",\"slug\":\"hello-elementor\"},\"options\":{\"activate\":true}},{\"step\":\"writeFile\",\"path\":\"\\\/wordpress\\\/wp-content\\\/color-switcher-for-elementor-demo-seed.php\",\"data\":\"<?php\\n\\\/**\\n * The wp.org Live Preview page \\u2014 the shop window, not the harness.\\n *\\n * `demo-page.php` is the mechanism fixture the e2e suite pins (element ids,\\n * zone counts, a 50% scrub handle). This one has one job instead: convince a\\n * stranger who pressed \\\"Live Preview\\\" that the plugin is worth installing. The\\n * two are deliberately separate files so neither constrains the other.\\n *\\n * Built from Elementor containers and free widgets only \\u2014 no Custom CSS (Pro)\\n * and no HTML widget. Every colour is a Global Color, which is not a\\n * restriction here but the whole argument: link a colour, and it turns.\\n *\\n * Idempotent: re-running replaces the page, re-applies the palette, and reuses\\n * the SVG attachments rather than accumulating them.\\n *\\n * Runs in two contexts:\\n *   wp eval-file dev\\\/seed\\\/preview-page.php --user=1     (dev site)\\n *   the blueprint's runPHP step                          (Playground, wp.org)\\n *\\\/\\n\\n\\\/\\\/ No WP_CLI guard: Playground executes this through runPHP, where WP_CLI is\\n\\\/\\\/ undefined \\u2014 the guard other seeds carry is exactly what made the shipped\\n\\\/\\\/ blueprint land on a 404.\\nif ( ! defined( 'ABSPATH' ) ) {\\n\\treturn;\\n}\\n\\nuse Elementor\\\\Plugin as Elementor;\\n\\n\\\/\\\/ Single source of truth for the page id: the blueprint's landingPage is\\n\\\/\\\/ generated from this define, so the seeded page and the URL cannot drift.\\ndefine( 'ACS_PREVIEW_DEMO_PAGE_ID', 9931 );\\n\\n\\\/\\\/ runPHP has no session, and Document::save() refuses without one \\u2014 the kit\\n\\\/\\\/ silently keeps its stock palette and the whole demo renders inert. Under\\n\\\/\\\/ `wp eval-file --user=1` a user is already set and this is a no-op.\\nif ( ! get_current_user_id() ) {\\n\\twp_set_current_user( 1 );\\n}\\n\\n\\\/\\\/ Elementor otherwise hijacks the first request with its onboarding wizard,\\n\\\/\\\/ which in Playground is the visitor's first impression of the plugin.\\nupdate_option( 'elementor_onboarded', true );\\ndelete_transient( 'elementor_activation_redirect' );\\n\\n\\\/**\\n * The palette: six roles, each with the Alt value this plugin exists to add.\\n * Lifted from the plugin's own wp.org icon so the listing and the preview read\\n * as one product.\\n *\\\/\\n$acspv_colors = array(\\n\\tarray(\\n\\t\\t'_id'       => 'acssurf',\\n\\t\\t'title'     => 'Surface',\\n\\t\\t'color'     => '#EDEDF2',\\n\\t\\t'color_alt' => '#17171C',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'       => 'acspnl',\\n\\t\\t'title'     => 'Panel',\\n\\t\\t'color'     => '#FFFFFF',\\n\\t\\t'color_alt' => '#20202A',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'       => 'acsink',\\n\\t\\t'title'     => 'Ink',\\n\\t\\t'color'     => '#23232B',\\n\\t\\t'color_alt' => '#F4F4F7',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'       => 'acsmut',\\n\\t\\t'title'     => 'Muted',\\n\\t\\t'color'     => '#6E6E7C',\\n\\t\\t'color_alt' => '#9B9BAC',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'       => 'acsacc',\\n\\t\\t'title'     => 'Accent',\\n\\t\\t'color'     => '#4F46E5',\\n\\t\\t'color_alt' => '#14B8A6',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'       => 'acsline',\\n\\t\\t'title'     => 'Hairline',\\n\\t\\t'color'     => '#D9D9E1',\\n\\t\\t'color_alt' => '#2F2F3B',\\n\\t),\\n);\\n\\n\\\/**\\n * Global Fonts. The four system rows are overridden rather than custom rows\\n * added, so anything on the page that never binds a font still inherits these.\\n * Both families are in Elementor's Google list (includes\\\/fonts.php), and it is\\n * the KIT's stylesheet that carries the literal family and therefore enqueues\\n * them \\u2014 a widget bound through __globals__ only ever emits a var().\\n *\\\/\\n$acspv_fonts = array(\\n\\tarray(\\n\\t\\t'_id'                    => 'primary',\\n\\t\\t'title'                  => 'Primary',\\n\\t\\t'typography_typography'  => 'custom',\\n\\t\\t'typography_font_family' => 'Bricolage Grotesque',\\n\\t\\t'typography_font_weight' => '600',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'                    => 'secondary',\\n\\t\\t'title'                  => 'Secondary',\\n\\t\\t'typography_typography'  => 'custom',\\n\\t\\t'typography_font_family' => 'Bricolage Grotesque',\\n\\t\\t'typography_font_weight' => '600',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'                    => 'text',\\n\\t\\t'title'                  => 'Text',\\n\\t\\t'typography_typography'  => 'custom',\\n\\t\\t'typography_font_family' => 'Instrument Sans',\\n\\t\\t'typography_font_weight' => '400',\\n\\t),\\n\\tarray(\\n\\t\\t'_id'                    => 'accent',\\n\\t\\t'title'                  => 'Accent',\\n\\t\\t'typography_typography'  => 'custom',\\n\\t\\t'typography_font_family' => 'Instrument Sans',\\n\\t\\t'typography_font_weight' => '500',\\n\\t),\\n);\\n\\n$acspv_kit    = Elementor::$instance->kits_manager->get_active_kit();\\n$acspv_kit_id = (int) $acspv_kit->get_main_id();\\n\\nif ( ! $acspv_kit_id ) {\\n\\tElementor::$instance->kits_manager->create_new_kit( 'Color Switcher Preview' );\\n\\t$acspv_kit    = Elementor::$instance->kits_manager->get_active_kit();\\n\\t$acspv_kit_id = (int) $acspv_kit->get_main_id();\\n}\\n\\n\\\/\\\/ Upsert rather than replace: Elementor's own four stock colours are referenced\\n\\\/\\\/ by the theme and by widget defaults, and dropping them breaks unrelated CSS.\\n$acspv_kit_settings = get_post_meta( $acspv_kit_id, '_elementor_page_settings', true );\\n$acspv_kit_settings = is_array( $acspv_kit_settings ) ? $acspv_kit_settings : array();\\n$acspv_existing     = isset( $acspv_kit_settings['custom_colors'] ) && is_array( $acspv_kit_settings['custom_colors'] )\\n\\t? $acspv_kit_settings['custom_colors']\\n\\t: array();\\n\\nforeach ( $acspv_colors as $acspv_row ) {\\n\\t$acspv_found = false;\\n\\n\\tforeach ( $acspv_existing as $acspv_i => $acspv_old ) {\\n\\t\\tif ( is_array( $acspv_old ) && isset( $acspv_old['_id'] ) && $acspv_old['_id'] === $acspv_row['_id'] ) {\\n\\t\\t\\t$acspv_existing[ $acspv_i ] = $acspv_row;\\n\\t\\t\\t$acspv_found                = true;\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t}\\n\\n\\tif ( ! $acspv_found ) {\\n\\t\\t$acspv_existing[] = $acspv_row;\\n\\t}\\n}\\n\\n$acspv_kit_settings['custom_colors']         = $acspv_existing;\\n$acspv_kit_settings['system_typography']     = $acspv_fonts;\\n$acspv_kit_settings['default_generic_fonts'] = 'sans-serif';\\n\\nupdate_post_meta( $acspv_kit_id, '_elementor_page_settings', wp_slash( $acspv_kit_settings ) );\\n\\nif ( class_exists( '\\\\Elementor\\\\Core\\\\Files\\\\CSS\\\\Post' ) ) {\\n\\t\\\\Elementor\\\\Core\\\\Files\\\\CSS\\\\Post::create( $acspv_kit_id )->delete();\\n}\\n\\n\\\/**\\n * Writes an SVG into uploads and hands back its URL.\\n *\\n * Deliberately URL-only, with no attachment: the Alt control falls back to the\\n * stored URL when there is no id (the same shape `alt-images-page.php` uses and\\n * the e2e suite proves), and Elementor's image widget prints a plain <img> for\\n * an id-less value. Registering attachments would drag in SVG mime handling and\\n * hand-written metadata for no visible gain on a page whose job is to look\\n * right, not to exercise a code path.\\n *\\n * @return string Public URL of the written file.\\n *\\\/\\n$acspv_asset = static function ( string $filename, string $markup ): string {\\n\\t$acspv_dir = wp_upload_dir();\\n\\n\\tif ( ! empty( $acspv_dir['error'] ) ) {\\n\\t\\treturn '';\\n\\t}\\n\\n\\t$acspv_path = trailingslashit( $acspv_dir['path'] ) . $filename;\\n\\n\\tif ( false === file_put_contents( $acspv_path, $markup ) ) { \\\/\\\/ phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents\\n\\t\\treturn '';\\n\\t}\\n\\n\\treturn trailingslashit( $acspv_dir['url'] ) . $filename;\\n};\\n\\n\\\/\\\/ Artwork is drawn twice on purpose: an image cannot interpolate, so the pair\\n\\\/\\\/ swaps at the settled ends rather than morphing. That is the plugin's own\\n\\\/\\\/ documented behaviour, and it is what an author has to design for.\\n$acspv_still = static function ( string $bg, string $acc, string $ink, string $body ): string {\\n\\treturn sprintf(\\n\\t\\t'<svg xmlns=\\\"http:\\\/\\\/www.w3.org\\\/2000\\\/svg\\\" viewBox=\\\"0 0 200 150\\\" width=\\\"200\\\" height=\\\"150\\\">'\\n\\t\\t. '<rect width=\\\"200\\\" height=\\\"150\\\" fill=\\\"%1$s\\\"\\\/>%2$s<\\\/svg>',\\n\\t\\t$bg,\\n\\t\\tstr_replace( array( '{ACC}', '{INK}' ), array( $acc, $ink ), $body )\\n\\t);\\n};\\n\\n$acspv_body_a = '<circle cx=\\\"70\\\" cy=\\\"75\\\" r=\\\"40\\\" fill=\\\"{ACC}\\\"\\\/><rect x=\\\"106\\\" y=\\\"35\\\" width=\\\"62\\\" height=\\\"80\\\" rx=\\\"10\\\" fill=\\\"{INK}\\\"\\\/>';\\n$acspv_body_b = '<path d=\\\"M22 128 100 22l78 106Z\\\" fill=\\\"{INK}\\\"\\\/><circle cx=\\\"100\\\" cy=\\\"94\\\" r=\\\"24\\\" fill=\\\"{ACC}\\\"\\\/>';\\n$acspv_body_c = '<path d=\\\"M30 118V52a34 34 0 0 1 34-34v100Z\\\" fill=\\\"{ACC}\\\"\\\/><rect x=\\\"104\\\" y=\\\"18\\\" width=\\\"30\\\" height=\\\"100\\\" rx=\\\"15\\\" fill=\\\"{INK}\\\"\\\/><rect x=\\\"150\\\" y=\\\"48\\\" width=\\\"30\\\" height=\\\"70\\\" rx=\\\"15\\\" fill=\\\"{ACC}\\\"\\\/>';\\n\\n\\\/**\\n * The plugin's mark, frozen into its two states.\\n *\\n * `.wordpress-org\\\/icon.svg` animates: it cycles between a light and a dark\\n * interior on a 5.6s loop, which is right for a listing tile and wrong for a\\n * site header, where it reads as a logo switching itself for no reason. The\\n * geometry here is that file's, with the keyframes' two endpoints pinned as\\n * static fills \\u2014 so the pair the animation moves between becomes the pair the\\n * Alt-image swap moves between, and the mark now follows the page instead of\\n * ignoring it.\\n *\\\/\\n$acspv_mark = static function ( string $page, string $ink, string $acc, string $trk, string $knob, int $shift ): string {\\n\\treturn sprintf(\\n\\t\\t'<svg xmlns=\\\"http:\\\/\\\/www.w3.org\\\/2000\\\/svg\\\" width=\\\"256\\\" height=\\\"256\\\" viewBox=\\\"0 0 256 256\\\" role=\\\"img\\\" aria-label=\\\"Arts Color Switcher for Elementor\\\">'\\n\\t\\t. '<defs><linearGradient id=\\\"p\\\" x1=\\\"0\\\" y1=\\\"256\\\" x2=\\\"256\\\" y2=\\\"0\\\" gradientUnits=\\\"userSpaceOnUse\\\">'\\n\\t\\t. '<stop offset=\\\"0\\\" stop-color=\\\"#333333\\\"\\\/><stop offset=\\\"1\\\" stop-color=\\\"#111111\\\"\\\/><\\\/linearGradient>'\\n\\t\\t. '<clipPath id=\\\"w\\\"><rect x=\\\"26\\\" y=\\\"42\\\" width=\\\"204\\\" height=\\\"172\\\" rx=\\\"26\\\"\\\/><\\\/clipPath><\\\/defs>'\\n\\t\\t. '<rect width=\\\"256\\\" height=\\\"256\\\" rx=\\\"54\\\" fill=\\\"url(#p)\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"0.75\\\" y=\\\"0.75\\\" width=\\\"254.5\\\" height=\\\"254.5\\\" rx=\\\"53.25\\\" fill=\\\"none\\\" stroke=\\\"#FFFFFF\\\" stroke-opacity=\\\"0.06\\\"\\\/>'\\n\\t\\t. '<g clip-path=\\\"url(#w)\\\">'\\n\\t\\t. '<rect x=\\\"26\\\" y=\\\"42\\\" width=\\\"204\\\" height=\\\"172\\\" fill=\\\"%1$s\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"46\\\" y=\\\"66\\\" width=\\\"88\\\" height=\\\"14\\\" rx=\\\"7\\\" fill=\\\"%2$s\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"158\\\" y=\\\"62\\\" width=\\\"44\\\" height=\\\"22\\\" rx=\\\"11\\\" fill=\\\"%4$s\\\"\\\/>'\\n\\t\\t. '<circle cx=\\\"%6$d\\\" cy=\\\"73\\\" r=\\\"8\\\" fill=\\\"%5$s\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"46\\\" y=\\\"100\\\" width=\\\"164\\\" height=\\\"56\\\" rx=\\\"12\\\" fill=\\\"%3$s\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"46\\\" y=\\\"172\\\" width=\\\"112\\\" height=\\\"9\\\" rx=\\\"4\\\" fill=\\\"%2$s\\\"\\\/>'\\n\\t\\t. '<rect x=\\\"46\\\" y=\\\"190\\\" width=\\\"86\\\" height=\\\"9\\\" rx=\\\"4\\\" fill=\\\"%2$s\\\"\\\/>'\\n\\t\\t. '<\\\/g>'\\n\\t\\t. '<rect x=\\\"26\\\" y=\\\"42\\\" width=\\\"204\\\" height=\\\"172\\\" rx=\\\"26\\\" fill=\\\"none\\\" stroke=\\\"#FFFFFF\\\" stroke-opacity=\\\"0.12\\\"\\\/><\\\/svg>',\\n\\t\\t$page,\\n\\t\\t$ink,\\n\\t\\t$acc,\\n\\t\\t$trk,\\n\\t\\t$knob,\\n\\t\\t169 + ( 22 * $shift )\\n\\t);\\n};\\n\\n$acspv_url = array(\\n\\t'logo'     => $acspv_asset( 'acs-preview-logo.svg', $acspv_mark( '#EDEDF2', '#23232B', '#4F46E5', '#23232B', '#EDEDF2', 0 ) ),\\n\\t'logo_alt' => $acspv_asset( 'acs-preview-logo-alt.svg', $acspv_mark( '#17171C', '#FFFFFF', '#0D9488', '#4F46E5', '#FFFFFF', 1 ) ),\\n\\t'a'        => $acspv_asset( 'acs-preview-a.svg', $acspv_still( '#E5E5EE', '#4F46E5', '#23232B', $acspv_body_a ) ),\\n\\t'a_alt'    => $acspv_asset( 'acs-preview-a-alt.svg', $acspv_still( '#1C1C24', '#14B8A6', '#F4F4F7', $acspv_body_a ) ),\\n\\t'b'        => $acspv_asset( 'acs-preview-b.svg', $acspv_still( '#E5E5EE', '#4F46E5', '#23232B', $acspv_body_b ) ),\\n\\t'b_alt'    => $acspv_asset( 'acs-preview-b-alt.svg', $acspv_still( '#1C1C24', '#14B8A6', '#F4F4F7', $acspv_body_b ) ),\\n\\t'c'        => $acspv_asset( 'acs-preview-c.svg', $acspv_still( '#E5E5EE', '#4F46E5', '#23232B', $acspv_body_c ) ),\\n\\t'c_alt'    => $acspv_asset( 'acs-preview-c-alt.svg', $acspv_still( '#1C1C24', '#14B8A6', '#F4F4F7', $acspv_body_c ) ),\\n);\\n\\n\\\/* ------------------------------------------------------------------------- *\\n * Value-shape helpers. Elementor's control families each take a different\\n * array shape, and mixing them up fails silently \\u2014 the rule is simply not\\n * emitted, with no error anywhere.\\n * ------------------------------------------------------------------------- *\\\/\\n\\n\\\/** Box shape: padding, margin, border-width, border-radius. *\\\/\\nfunction acspv_box( string $top, string $right, string $bottom, string $left, string $unit = 'px' ): array {\\n\\treturn array(\\n\\t\\t'unit'     => $unit,\\n\\t\\t'top'      => $top,\\n\\t\\t'right'    => $right,\\n\\t\\t'bottom'   => $bottom,\\n\\t\\t'left'     => $left,\\n\\t\\t'isLinked' => false,\\n\\t);\\n}\\n\\n\\\/** Gap shape \\u2014 column\\\/row, not a box and not a slider. *\\\/\\nfunction acspv_gap( int $px ): array {\\n\\treturn array(\\n\\t\\t'unit'     => 'px',\\n\\t\\t'column'   => (string) $px,\\n\\t\\t'row'      => (string) $px,\\n\\t\\t'isLinked' => true,\\n\\t);\\n}\\n\\n\\\/** Slider shape. The vestigial `sizes` key is what Elementor itself writes. *\\\/\\nfunction acspv_size( float $size, string $unit = 'px' ): array {\\n\\treturn array(\\n\\t\\t'unit'  => $unit,\\n\\t\\t'size'  => $size,\\n\\t\\t'sizes' => array(),\\n\\t);\\n}\\n\\n\\\/**\\n * The custom unit passes an arbitrary CSS value straight through, which is how\\n * the design's clamp() type scale and ch-based measures ship with no Custom CSS.\\n *\\\/\\nfunction acspv_css( string $value ): array {\\n\\treturn array(\\n\\t\\t'unit' => 'custom',\\n\\t\\t'size' => $value,\\n\\t);\\n}\\n\\n\\\/* ------------------------------------------------------------------------- *\\n * Element helpers. Each exists to defeat one Elementor default that would\\n * otherwise leak into the design.\\n * ------------------------------------------------------------------------- *\\\/\\n\\n\\\/** Deterministic ids, so a re-seed produces the same tree and diffs cleanly. *\\\/\\nfunction acspv_id(): string {\\n\\tstatic $acspv_n = 0;\\n\\t++$acspv_n;\\n\\n\\treturn sprintf( 'acspv%03d', $acspv_n );\\n}\\n\\n\\\/**\\n * Merges settings while keeping `__globals__` a union rather than letting the\\n * later array replace the whole map \\u2014 one element carries exactly one\\n * `__globals__`, so a naive array_merge silently drops every earlier binding.\\n *\\\/\\nfunction acspv_merge( array $base, array $extra ): array {\\n\\t$acspv_globals = array_merge(\\n\\t\\tisset( $base['__globals__'] ) ? $base['__globals__'] : array(),\\n\\t\\tisset( $extra['__globals__'] ) ? $extra['__globals__'] : array()\\n\\t);\\n\\n\\t$acspv_merged = array_merge( $base, $extra );\\n\\n\\tif ( $acspv_globals ) {\\n\\t\\t$acspv_merged['__globals__'] = $acspv_globals;\\n\\t}\\n\\n\\treturn $acspv_merged;\\n}\\n\\n\\\/**\\n * Structural container. The explicit zero padding and gap are load-bearing:\\n * the kit ships a default container padding and a 20px --widgets-spacing that\\n * would otherwise appear between every element on the page.\\n *\\\/\\nfunction acspv_row( array $settings, array $children = array() ): array {\\n\\t$acspv_settings = acspv_merge(\\n\\t\\tarray(\\n\\t\\t\\t'content_width' => 'full',\\n\\t\\t\\t'padding'       => acspv_box( '0', '0', '0', '0' ),\\n\\t\\t\\t'flex_gap'      => acspv_gap( 0 ),\\n\\t\\t),\\n\\t\\t$settings\\n\\t);\\n\\n\\t\\\/\\\/ Elementor's own mobile rule is `.e-con.e-flex { --width: 100% }`, which\\n\\t\\\/\\\/ silently overrides a declared width below 768px \\u2014 a fixed-size circle\\n\\t\\\/\\\/ keeps its min-height, stretches to the viewport, and renders as an\\n\\t\\\/\\\/ ellipse. A per-breakpoint value outranks it, so a width declared once is\\n\\t\\\/\\\/ honoured everywhere.\\n\\tif ( isset( $acspv_settings['width'] ) ) {\\n\\t\\tforeach ( array( 'width_tablet', 'width_mobile' ) as $acspv_bp ) {\\n\\t\\t\\tif ( ! isset( $acspv_settings[ $acspv_bp ] ) ) {\\n\\t\\t\\t\\t$acspv_settings[ $acspv_bp ] = $acspv_settings['width'];\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\n\\treturn array(\\n\\t\\t'id'       => acspv_id(),\\n\\t\\t'elType'   => 'container',\\n\\t\\t'settings' => $acspv_settings,\\n\\t\\t'elements' => $children,\\n\\t);\\n}\\n\\n\\\/** A page section: boxed to the measure, with the vertical rhythm. *\\\/\\nfunction acspv_section( string $anchor, array $settings, array $children ): array {\\n\\treturn acspv_row(\\n\\t\\tacspv_merge(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'_element_id'    => $anchor,\\n\\t\\t\\t\\t'content_width'  => 'boxed',\\n\\t\\t\\t\\t'boxed_width'    => acspv_size( 1120 ),\\n\\t\\t\\t\\t'overflow'       => 'hidden',\\n\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t'padding'        => acspv_box( '110', '24', '110', '24' ),\\n\\t\\t\\t\\t'padding_tablet' => acspv_box( '80', '24', '80', '24' ),\\n\\t\\t\\t\\t'padding_mobile' => acspv_box( '56', '20', '56', '20' ),\\n\\t\\t\\t),\\n\\t\\t\\t$settings\\n\\t\\t),\\n\\t\\t$children\\n\\t);\\n}\\n\\n\\\/** The 50\\\/50 the design uses three times. Grid, so both halves share a row. *\\\/\\nfunction acspv_split( array $left, array $right, int $gap = 72 ): array {\\n\\treturn acspv_row(\\n\\t\\tarray(\\n\\t\\t\\t'container_type'           => 'grid',\\n\\t\\t\\t'grid_columns_grid'        => array(\\n\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t'size' => 2,\\n\\t\\t\\t),\\n\\t\\t\\t'grid_columns_grid_tablet' => array(\\n\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t'size' => 1,\\n\\t\\t\\t),\\n\\t\\t\\t'grid_rows_grid'           => acspv_css( 'auto' ),\\n\\t\\t\\t'grid_gaps'                => acspv_gap( $gap ),\\n\\t\\t\\t'grid_gaps_tablet'         => acspv_gap( 40 ),\\n\\t\\t\\t'grid_gaps_mobile'         => acspv_gap( 28 ),\\n\\t\\t\\t'grid_align_items'         => 'center',\\n\\t\\t),\\n\\t\\tarray( $left, $right )\\n\\t);\\n}\\n\\nfunction acspv_widget( string $type, array $settings ): array {\\n\\treturn array(\\n\\t\\t'id'         => acspv_id(),\\n\\t\\t'elType'     => 'widget',\\n\\t\\t'widgetType' => $type,\\n\\t\\t'settings'   => $settings,\\n\\t\\t'elements'   => array(),\\n\\t);\\n}\\n\\n\\\/** Display type. Sizes carry clamp() through the custom unit. *\\\/\\nfunction acspv_heading( string $text, string $tag, string $size, array $extra = array() ): array {\\n\\treturn acspv_widget(\\n\\t\\t'heading',\\n\\t\\tacspv_merge(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'title'                     => $text,\\n\\t\\t\\t\\t'header_size'               => $tag,\\n\\t\\t\\t\\t'typography_typography'     => 'custom',\\n\\t\\t\\t\\t'typography_font_size'      => acspv_css( $size ),\\n\\t\\t\\t\\t'typography_line_height'    => acspv_css( '1.08' ),\\n\\t\\t\\t\\t'typography_letter_spacing' => acspv_size( -0.022, 'em' ),\\n\\t\\t\\t\\t\\\/\\\/ Family named directly rather than bound to the Global Font.\\n\\t\\t\\t\\t\\\/\\\/ A global-linked typography group rewrites EVERY field in the\\n\\t\\t\\t\\t\\\/\\\/ group to that global's vars, so binding it here would throw\\n\\t\\t\\t\\t\\\/\\\/ away the size and line-height below and leave the browser\\n\\t\\t\\t\\t\\\/\\\/ defaults. The kit still carries the families, which is what\\n\\t\\t\\t\\t\\\/\\\/ enqueues the webfonts.\\n\\t\\t\\t\\t'typography_font_family'    => 'Bricolage Grotesque',\\n\\t\\t\\t\\t'__globals__'               => array( 'title_color' => 'globals\\\/colors?id=acsink' ),\\n\\t\\t\\t),\\n\\t\\t\\t$extra\\n\\t\\t)\\n\\t);\\n}\\n\\n\\\/** Muted body copy, held to a readable measure. *\\\/\\nfunction acspv_body( string $text, string $size = '1.0625rem', array $extra = array() ): array {\\n\\treturn acspv_widget(\\n\\t\\t'heading',\\n\\t\\tacspv_merge(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'title'                  => $text,\\n\\t\\t\\t\\t'header_size'            => 'p',\\n\\t\\t\\t\\t'typography_typography'  => 'custom',\\n\\t\\t\\t\\t'typography_font_size'   => acspv_css( $size ),\\n\\t\\t\\t\\t'typography_line_height' => acspv_css( '1.65' ),\\n\\t\\t\\t\\t'_element_width'         => 'initial',\\n\\t\\t\\t\\t'_element_custom_width'  => acspv_css( 'min(56ch, 100%)' ),\\n\\t\\t\\t\\t'typography_font_family' => 'Instrument Sans',\\n\\t\\t\\t\\t'__globals__'            => array( 'title_color' => 'globals\\\/colors?id=acsmut' ),\\n\\t\\t\\t),\\n\\t\\t\\t$extra\\n\\t\\t)\\n\\t);\\n}\\n\\n\\\/** A solid block of one Global Color \\u2014 the hero graphic is made of these. *\\\/\\nfunction acspv_shape( string $color, array $settings ): array {\\n\\treturn acspv_row(\\n\\t\\tacspv_merge(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'background_background' => 'classic',\\n\\t\\t\\t\\t'__globals__'           => array( 'background_color' => 'globals\\\/colors?id=' . $color ),\\n\\t\\t\\t),\\n\\t\\t\\t$settings\\n\\t\\t)\\n\\t);\\n}\\n\\n\\\/* ------------------------------------------------------------------------- *\\n * The page\\n * ------------------------------------------------------------------------- *\\\/\\n\\n\\\/\\\/ Header. `arts_header_position` of '' is Top (fixed overlay) \\u2014 the empty\\n\\\/\\\/ string is a real value here, not \\\"unset\\\". `arts_header_sticky_global_colors`\\n\\\/\\\/ is deliberately left empty: a global remapped there stops responding to Alt\\n\\\/\\\/ for as long as the header is stuck, which is the one documented conflict\\n\\\/\\\/ between these two plugins.\\n$acspv_header = acspv_row(\\n\\tarray(\\n\\t\\t'_title'                => 'Header',\\n\\t\\t'flex_direction'        => 'row',\\n\\t\\t'flex_justify_content'  => 'space-between',\\n\\t\\t'flex_align_items'      => 'center',\\n\\t\\t'flex_gap'              => acspv_gap( 28 ),\\n\\t\\t'flex_wrap_mobile'      => 'nowrap',\\n\\t\\t'padding'               => acspv_box( '14', '32', '14', '32' ),\\n\\t\\t'padding_mobile'        => acspv_box( '10', '14', '10', '14' ),\\n\\t\\t'background_background' => 'classic',\\n\\t\\t'border_border'         => 'solid',\\n\\t\\t'border_width'          => acspv_box( '0', '0', '1', '0' ),\\n\\t\\t'arts_header_enabled'   => 'yes',\\n\\t\\t'arts_header_position'  => '',\\n\\t\\t'arts_header_on_scroll' => 'sticky',\\n\\t\\t'__globals__'           => array(\\n\\t\\t\\t'background_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t'border_color'     => 'globals\\\/colors?id=acsline',\\n\\t\\t),\\n\\t),\\n\\tarray(\\n\\t\\tacspv_row(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'flex_direction'   => 'row',\\n\\t\\t\\t\\t'flex_align_items' => 'center',\\n\\t\\t\\t\\t'flex_gap'         => acspv_gap( 10 ),\\n\\t\\t\\t\\t'width'            => acspv_css( 'auto' ),\\n\\t\\t\\t\\t'flex_wrap_mobile' => 'nowrap',\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t\\t'image',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'image'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'             => $acspv_url['logo'],\\n\\t\\t\\t\\t\\t\\t\\t'id'              => '',\\n\\t\\t\\t\\t\\t\\t\\t'arts_cs_alt_url' => $acspv_url['logo_alt'],\\n\\t\\t\\t\\t\\t\\t\\t'arts_cs_alt_id'  => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'image_size'     => 'full',\\n\\t\\t\\t\\t\\t\\t'width'          => acspv_size( 30 ),\\n\\t\\t\\t\\t\\t\\t'_element_width' => 'auto',\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_heading(\\n\\t\\t\\t\\t\\t'Arts Color Switcher for Elementor',\\n\\t\\t\\t\\t\\t'p',\\n\\t\\t\\t\\t\\t'0.9375rem',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'typography_font_weight'      => '600',\\n\\t\\t\\t\\t\\t\\t'typography_font_size_mobile' => acspv_size( 11 ),\\n\\t\\t\\t\\t\\t\\t'typography_line_height'      => acspv_css( '1.2' ),\\n\\t\\t\\t\\t\\t\\t'typography_letter_spacing'   => acspv_size( -0.01, 'em' ),\\n\\t\\t\\t\\t\\t\\t'_element_width'              => 'auto',\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\n\\t\\t\\\/\\\/ Free Elementor has no menu widget. Icon List is the closest real one:\\n\\t\\t\\\/\\\/ an actual <ul>, inline layout, and \\u2014 the part that matters here \\u2014\\n\\t\\t\\\/\\\/ separate resting and hover colours, both bindable to Global Colors.\\n\\t\\tacspv_widget(\\n\\t\\t\\t'icon-list',\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'view'                        => 'inline',\\n\\t\\t\\t\\t'link_click'                  => 'inline',\\n\\t\\t\\t\\t'space_between'               => acspv_size( 30 ),\\n\\t\\t\\t\\t'icon_list'                   => array(\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'_id'           => 'acsnav1',\\n\\t\\t\\t\\t\\t\\t'text'          => 'Toggle',\\n\\t\\t\\t\\t\\t\\t'link'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'         => '#acs-toggle',\\n\\t\\t\\t\\t\\t\\t\\t'is_external' => '',\\n\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'selected_icon' => array(\\n\\t\\t\\t\\t\\t\\t\\t'value'   => '',\\n\\t\\t\\t\\t\\t\\t\\t'library' => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'_id'           => 'acsnav2',\\n\\t\\t\\t\\t\\t\\t'text'          => 'Colors',\\n\\t\\t\\t\\t\\t\\t'link'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'         => '#acs-colors',\\n\\t\\t\\t\\t\\t\\t\\t'is_external' => '',\\n\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'selected_icon' => array(\\n\\t\\t\\t\\t\\t\\t\\t'value'   => '',\\n\\t\\t\\t\\t\\t\\t\\t'library' => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'_id'           => 'acsnav3',\\n\\t\\t\\t\\t\\t\\t'text'          => 'Images',\\n\\t\\t\\t\\t\\t\\t'link'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'         => '#acs-images',\\n\\t\\t\\t\\t\\t\\t\\t'is_external' => '',\\n\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'selected_icon' => array(\\n\\t\\t\\t\\t\\t\\t\\t'value'   => '',\\n\\t\\t\\t\\t\\t\\t\\t'library' => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'_id'           => 'acsnav4',\\n\\t\\t\\t\\t\\t\\t'text'          => 'On scroll',\\n\\t\\t\\t\\t\\t\\t'link'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'         => '#acs-scroll',\\n\\t\\t\\t\\t\\t\\t\\t'is_external' => '',\\n\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'selected_icon' => array(\\n\\t\\t\\t\\t\\t\\t\\t'value'   => '',\\n\\t\\t\\t\\t\\t\\t\\t'library' => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\t'hide_mobile'                 => 'hidden-mobile',\\n\\t\\t\\t\\t'icon_typography_typography'  => 'custom',\\n\\t\\t\\t\\t'icon_typography_font_family' => 'Instrument Sans',\\n\\t\\t\\t\\t'icon_typography_font_weight' => '500',\\n\\t\\t\\t\\t'icon_typography_font_size'   => acspv_size( 15 ),\\n\\t\\t\\t\\t'text_color_hover_transition' => acspv_size( 0.2, 's' ),\\n\\t\\t\\t\\t'_element_width'              => 'auto',\\n\\t\\t\\t\\t'__globals__'                 => array(\\n\\t\\t\\t\\t\\t'text_color'       => 'globals\\\/colors?id=acsmut',\\n\\t\\t\\t\\t\\t'text_color_hover' => 'globals\\\/colors?id=acsacc',\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\n\\t\\t\\\/\\\/ Buttons skin, three states, no words. The plugin ships monitor\\\/sun\\\/moon\\n\\t\\t\\\/\\\/ icons of its own, so clearing the labels is all \\\"icons only\\\" takes.\\n\\t\\tacspv_widget(\\n\\t\\t\\t'arts-color-switcher-toggle',\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'_skin'          => 'buttons',\\n\\t\\t\\t\\t'buttons_style'  => 'joined',\\n\\t\\t\\t\\t'mode'           => 'cycle',\\n\\t\\t\\t\\t'buttons_icons'  => 'yes',\\n\\t\\t\\t\\t'label_system'   => '',\\n\\t\\t\\t\\t'label_default'  => '',\\n\\t\\t\\t\\t'label_alt'      => '',\\n\\t\\t\\t\\t'_element_width' => 'auto',\\n\\t\\t\\t\\t'__globals__'    => array(\\n\\t\\t\\t\\t\\t'icon_color'        => 'globals\\\/colors?id=acsmut',\\n\\t\\t\\t\\t\\t'icon_color_hover'  => 'globals\\\/colors?id=acsink',\\n\\t\\t\\t\\t\\t'icon_color_active' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t'indicator_color'   => 'globals\\\/colors?id=acsacc',\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n\\\/\\\/ Hero. The graphic on the right is built from containers rather than an image\\n\\\/\\\/ so that it morphs continuously with the scalar like everything else \\u2014 an\\n\\\/\\\/ image could only swap at the settled ends.\\n$acspv_hero_card = acspv_row(\\n\\tarray(\\n\\t\\t'background_background' => 'classic',\\n\\t\\t'border_border'         => 'solid',\\n\\t\\t'border_width'          => acspv_box( '1', '1', '1', '1' ),\\n\\t\\t'border_radius'         => acspv_box( '30', '30', '30', '30' ),\\n\\t\\t'padding'               => acspv_box( '22', '22', '22', '22' ),\\n\\t\\t'z_index'               => 5,\\n\\t\\t'__globals__'           => array(\\n\\t\\t\\t'background_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t'border_color'     => 'globals\\\/colors?id=acsline',\\n\\t\\t),\\n\\t),\\n\\tarray(\\n\\t\\tacspv_row(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'background_background' => 'classic',\\n\\t\\t\\t\\t'border_radius'         => acspv_box( '18', '18', '18', '18' ),\\n\\t\\t\\t\\t'padding'               => acspv_box( '22', '22', '26', '22' ),\\n\\t\\t\\t\\t'flex_direction'        => 'column',\\n\\t\\t\\t\\t'flex_gap'              => acspv_gap( 22 ),\\n\\t\\t\\t\\t'__globals__'           => array( 'background_color' => 'globals\\\/colors?id=acssurf' ),\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t\\\/\\\/ Title bar row: a dot, a bar, and a switch that is only ever a picture of one.\\n\\t\\t\\t\\tacspv_row(\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'flex_direction'       => 'row',\\n\\t\\t\\t\\t\\t\\t'flex_justify_content' => 'space-between',\\n\\t\\t\\t\\t\\t\\t'flex_align_items'     => 'center',\\n\\t\\t\\t\\t\\t\\t'flex_gap'             => acspv_gap( 12 ),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\tacspv_row(\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t'flex_direction'   => 'row',\\n\\t\\t\\t\\t\\t\\t\\t\\t'flex_align_items' => 'center',\\n\\t\\t\\t\\t\\t\\t\\t\\t'flex_gap'         => acspv_gap( 10 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'width'            => acspv_css( 'auto' ),\\n\\t\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t'acsacc',\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'width'         => acspv_size( 18 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 18 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '50', '50', '50', '50', '%' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t'acsink',\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'width'         => acspv_size( 104 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 12 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '6', '6', '6', '6' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t'acsline',\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t'width'            => acspv_size( 62 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'min_height'       => acspv_size( 26 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'border_radius'    => acspv_box( '13', '13', '13', '13' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'padding'          => acspv_box( '4', '4', '4', '4' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'flex_direction'   => 'row',\\n\\t\\t\\t\\t\\t\\t\\t\\t'flex_align_items' => 'center',\\n\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t'acsacc',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 112 ),\\n\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '16', '16', '16', '16' ),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_row(\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 14 ),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t'acsink',\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t'width'         => acspv_size( 62, '%' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 12 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '6', '6', '6', '6' ),\\n\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t'acsmut',\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t'width'         => acspv_size( 44, '%' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 12 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '6', '6', '6', '6' ),\\n\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t\\t'acsline',\\n\\t\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t\\t'width'         => acspv_size( 27, '%' ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'min_height'    => acspv_size( 12 ),\\n\\t\\t\\t\\t\\t\\t\\t\\t'border_radius' => acspv_box( '6', '6', '6', '6' ),\\n\\t\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n$acspv_hero = acspv_section(\\n\\t'acs-top',\\n\\tarray(\\n\\t\\t'padding'        => acspv_box( '170', '24', '110', '24' ),\\n\\t\\t'padding_tablet' => acspv_box( '140', '24', '80', '24' ),\\n\\t\\t'padding_mobile' => acspv_box( '96', '20', '56', '20' ),\\n\\t),\\n\\tarray(\\n\\t\\tacspv_split(\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 22 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_heading( 'A dark mode you actually designed.', 'h1', 'clamp(2.7rem, 5.6vw, 4.4rem)', array() ),\\n\\t\\t\\t\\t\\tacspv_body( 'Every Global Color gets a second swatch. Visitors move between the palette you built for day and the one you built for night \\u2014 not one a filter guessed by inverting your site.', '1.1875rem', array( '_element_custom_width' => acspv_css( 'min(48ch, 100%)' ) ) ),\\n\\t\\t\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t\\t\\t'button',\\n\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t'text'                   => 'Four ways to place it',\\n\\t\\t\\t\\t\\t\\t\\t'link'                   => array(\\n\\t\\t\\t\\t\\t\\t\\t\\t'url'         => '#acs-toggle',\\n\\t\\t\\t\\t\\t\\t\\t\\t'is_external' => '',\\n\\t\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t\\t'button_type'            => '',\\n\\t\\t\\t\\t\\t\\t\\t'border_radius'          => acspv_box( '10', '10', '10', '10' ),\\n\\t\\t\\t\\t\\t\\t\\t'text_padding'           => acspv_box( '13', '20', '13', '20' ),\\n\\t\\t\\t\\t\\t\\t\\t'typography_typography'  => 'custom',\\n\\t\\t\\t\\t\\t\\t\\t'typography_font_size'   => acspv_size( 15 ),\\n\\t\\t\\t\\t\\t\\t\\t'typography_font_weight' => '500',\\n\\t\\t\\t\\t\\t\\t\\t'typography_font_family' => 'Instrument Sans',\\n\\t\\t\\t\\t\\t\\t\\t'background_background'  => 'classic',\\n\\t\\t\\t\\t\\t\\t\\t'_element_width'         => 'auto',\\n\\t\\t\\t\\t\\t\\t\\t'__globals__'            => array(\\n\\t\\t\\t\\t\\t\\t\\t\\t'background_color'  => 'globals\\\/colors?id=acsacc',\\n\\t\\t\\t\\t\\t\\t\\t\\t'button_text_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t\\t\\t'button_background_hover_color' => 'globals\\\/colors?id=acsink',\\n\\t\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray( 'flex_direction' => 'column' ),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_shape(\\n\\t\\t\\t\\t\\t\\t'acsacc',\\n\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t'position'              => 'absolute',\\n\\t\\t\\t\\t\\t\\t\\t'_offset_orientation_h' => 'end',\\n\\t\\t\\t\\t\\t\\t\\t'_offset_x_end'         => acspv_size( -26 ),\\n\\t\\t\\t\\t\\t\\t\\t'_offset_y'             => acspv_size( -34 ),\\n\\t\\t\\t\\t\\t\\t\\t'width'                 => acspv_size( 118 ),\\n\\t\\t\\t\\t\\t\\t\\t'min_height'            => acspv_size( 118 ),\\n\\t\\t\\t\\t\\t\\t\\t'border_radius'         => acspv_box( '50', '50', '50', '50', '%' ),\\n\\t\\t\\t\\t\\t\\t\\t'z_index'               => 0,\\n\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t$acspv_hero_card,\\n\\t\\t\\t\\t)\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n\\\/** One skin cell: its name, the live control, and where you would put it. *\\\/\\nfunction acspv_skin( string $name, string $skin, string $note, array $extra = array() ): array {\\n\\treturn acspv_row(\\n\\t\\tarray(\\n\\t\\t\\t'background_background' => 'classic',\\n\\t\\t\\t'border_border'         => 'solid',\\n\\t\\t\\t'border_width'          => acspv_box( '1', '1', '1', '1' ),\\n\\t\\t\\t'border_radius'         => acspv_box( '14', '14', '14', '14' ),\\n\\t\\t\\t'padding'               => acspv_box( '26', '24', '26', '24' ),\\n\\t\\t\\t'flex_direction'        => 'column',\\n\\t\\t\\t'flex_align_items'      => 'flex-start',\\n\\t\\t\\t'flex_gap'              => acspv_gap( 18 ),\\n\\t\\t\\t'__globals__'           => array(\\n\\t\\t\\t\\t'background_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t'border_color'     => 'globals\\\/colors?id=acsline',\\n\\t\\t\\t),\\n\\t\\t),\\n\\t\\tarray(\\n\\t\\t\\tacspv_body(\\n\\t\\t\\t\\t$name,\\n\\t\\t\\t\\t'0.6875rem',\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'typography_font_weight'    => '600',\\n\\t\\t\\t\\t\\t'typography_text_transform' => 'uppercase',\\n\\t\\t\\t\\t\\t'typography_letter_spacing' => acspv_size( 0.12, 'em' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t'arts-color-switcher-toggle',\\n\\t\\t\\t\\tacspv_merge(\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'_skin'          => $skin,\\n\\t\\t\\t\\t\\t\\t'_element_width' => 'auto',\\n\\t\\t\\t\\t\\t\\t'__globals__'    => array(\\n\\t\\t\\t\\t\\t\\t\\t'icon_color'         => 'globals\\\/colors?id=acsmut',\\n\\t\\t\\t\\t\\t\\t\\t'icon_color_hover'   => 'globals\\\/colors?id=acsink',\\n\\t\\t\\t\\t\\t\\t\\t'icon_color_active'  => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t\\t'indicator_color'    => 'globals\\\/colors?id=acsacc',\\n\\t\\t\\t\\t\\t\\t\\t'label_color'        => 'globals\\\/colors?id=acsmut',\\n\\t\\t\\t\\t\\t\\t\\t'label_color_active' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ The open list is drawn by the platform, so the chosen\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ row takes the indicator fill and needs its own text\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ colour or it renders dark-on-accent.\\n\\t\\t\\t\\t\\t\\t\\t'list_color'         => 'globals\\\/colors?id=acsink',\\n\\t\\t\\t\\t\\t\\t\\t'list_color_active'  => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t\\t'list_background'    => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t$extra\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_body( $note, '0.875rem' ),\\n\\t\\t)\\n\\t);\\n}\\n\\n$acspv_skins = acspv_section(\\n\\t'acs-toggle',\\n\\tarray(),\\n\\tarray(\\n\\t\\tacspv_split(\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'container_type'           => 'grid',\\n\\t\\t\\t\\t\\t'grid_columns_grid'        => array(\\n\\t\\t\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t\\t\\t'size' => 2,\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t'grid_columns_grid_mobile' => array(\\n\\t\\t\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t\\t\\t'size' => 1,\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t'grid_rows_grid'           => acspv_css( 'auto' ),\\n\\t\\t\\t\\t\\t'grid_gaps'                => acspv_gap( 14 ),\\n\\t\\t\\t\\t\\t'grid_gaps_mobile'         => acspv_gap( 12 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_skin( 'Icon', 'icon', 'A header corner, where there is room for one control.' ),\\n\\t\\t\\t\\t\\tacspv_skin( 'Switch', 'switch', 'Reads as a setting. At home in a footer or a preferences row.' ),\\n\\t\\t\\t\\t\\tacspv_skin(\\n\\t\\t\\t\\t\\t\\t'Buttons',\\n\\t\\t\\t\\t\\t\\t'buttons',\\n\\t\\t\\t\\t\\t\\t'Joined or separate, words or icons or both.',\\n\\t\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t\\t'mode'                        => 'cycle',\\n\\t\\t\\t\\t\\t\\t\\t'buttons_style'               => 'joined',\\n\\t\\t\\t\\t\\t\\t\\t'buttons_icons'               => '',\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ \\\"System\\\" cannot shrink below its own content, so it\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ overflows its 1fr column while the travelling mark\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ stays a uniform 1\\\/N and clips the word. \\\"Auto\\\" is the\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ width class of the other two, so the columns equalise\\n\\t\\t\\t\\t\\t\\t\\t\\\/\\\/ and the mark lines up with them.\\n\\t\\t\\t\\t\\t\\t\\t'label_system'                => 'Auto',\\n\\t\\t\\t\\t\\t\\t\\t'label_typography_typography' => 'custom',\\n\\t\\t\\t\\t\\t\\t\\t'label_typography_font_size'  => acspv_size( 13 ),\\n\\t\\t\\t\\t\\t\\t\\t'option_padding'              => acspv_box( '6', '12', '6', '12' ),\\n\\t\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\tacspv_skin( 'Dropdown', 'dropdown', 'The platform\\u2019s own picker \\u2014 the safe choice on mobile.', array( 'mode' => 'cycle' ) ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 20 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_heading( 'Four shapes, one behaviour.', 'h2', 'clamp(2rem, 3.6vw, 3rem)', array() ),\\n\\t\\t\\t\\t\\tacspv_body( 'Widget or shortcode \\u2014 it drops into a header, a footer, or a menu. Leave a visitor on System and the site keeps tracking their own device.', '1.1875rem' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n\\\/** A feature card: icon in its own column, text in the other. *\\\/\\nfunction acspv_card( string $icon, string $title, string $note ): array {\\n\\treturn acspv_row(\\n\\t\\tarray(\\n\\t\\t\\t'background_background' => 'classic',\\n\\t\\t\\t'border_border'         => 'solid',\\n\\t\\t\\t'border_width'          => acspv_box( '1', '1', '1', '1' ),\\n\\t\\t\\t'border_radius'         => acspv_box( '14', '14', '14', '14' ),\\n\\t\\t\\t'padding'               => acspv_box( '22', '22', '22', '22' ),\\n\\t\\t\\t'flex_direction'        => 'row',\\n\\t\\t\\t'flex_align_items'      => 'flex-start',\\n\\t\\t\\t'flex_gap'              => acspv_gap( 16 ),\\n\\t\\t\\t'__globals__'           => array(\\n\\t\\t\\t\\t'background_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t'border_color'     => 'globals\\\/colors?id=acsline',\\n\\t\\t\\t),\\n\\t\\t),\\n\\t\\tarray(\\n\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t'icon',\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'selected_icon'  => array(\\n\\t\\t\\t\\t\\t\\t'value'   => $icon,\\n\\t\\t\\t\\t\\t\\t'library' => 'fa-solid',\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t'view'           => 'default',\\n\\t\\t\\t\\t\\t'size'           => acspv_size( 20 ),\\n\\t\\t\\t\\t\\t'_element_width' => 'auto',\\n\\t\\t\\t\\t\\t'__globals__'    => array( 'primary_color' => 'globals\\\/colors?id=acsacc' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 6 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_heading( $title, 'h3', '1.0625rem', array( 'typography_line_height' => acspv_css( '1.35' ) ) ),\\n\\t\\t\\t\\t\\tacspv_body( $note, '0.9375rem' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t)\\n\\t);\\n}\\n\\n$acspv_colors_section = acspv_section(\\n\\t'acs-colors',\\n\\tarray(),\\n\\tarray(\\n\\t\\tacspv_split(\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 20 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_heading( 'Nothing to rebuild. Your widgets already reference the colors.', 'h2', 'clamp(2rem, 3.6vw, 3rem)', array() ),\\n\\t\\t\\t\\t\\tacspv_body( 'This menu, the buttons, the borders, the icons \\u2014 none configured twice. They point at Global Colors, and the plugin re-points those.', '1.1875rem' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t\\tacspv_row(\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'flex_direction' => 'column',\\n\\t\\t\\t\\t\\t'flex_gap'       => acspv_gap( 14 ),\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\tacspv_card( 'fas fa-adjust', 'Two swatches, one row', 'An Alt value sits beside every Global Color in Site Settings. Same picker, same screen.' ),\\n\\t\\t\\t\\t\\tacspv_card( 'fas fa-sliders-h', 'Adopt it one color at a time', 'A color with no Alt keeps its original, so a live site can go dark over a week, not a weekend.' ),\\n\\t\\t\\t\\t\\tacspv_card( 'fas fa-bolt', 'No flash on load', 'Open a page set to dark and it arrives dark. No white blink before the colors catch up.' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n\\\/** One swapping still. Both files are drawn by hand above, light and dark. *\\\/\\nfunction acspv_still_widget( string $url, string $alt_url ): array {\\n\\treturn acspv_row(\\n\\t\\tarray(\\n\\t\\t\\t'border_border' => 'solid',\\n\\t\\t\\t'border_width'  => acspv_box( '1', '1', '1', '1' ),\\n\\t\\t\\t'border_radius' => acspv_box( '14', '14', '14', '14' ),\\n\\t\\t\\t'overflow'      => 'hidden',\\n\\t\\t\\t'__globals__'   => array( 'border_color' => 'globals\\\/colors?id=acsline' ),\\n\\t\\t),\\n\\t\\tarray(\\n\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t'image',\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'image'      => array(\\n\\t\\t\\t\\t\\t\\t'url'             => $url,\\n\\t\\t\\t\\t\\t\\t'id'              => '',\\n\\t\\t\\t\\t\\t\\t'arts_cs_alt_url' => $alt_url,\\n\\t\\t\\t\\t\\t\\t'arts_cs_alt_id'  => '',\\n\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t'image_size' => 'full',\\n\\t\\t\\t\\t\\t'width'      => acspv_size( 100, '%' ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t),\\n\\t\\t)\\n\\t);\\n}\\n\\n$acspv_images = acspv_section(\\n\\t'acs-images',\\n\\tarray( 'flex_gap' => acspv_gap( 44 ) ),\\n\\tarray(\\n\\t\\tacspv_row(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'flex_direction'   => 'column',\\n\\t\\t\\t\\t'flex_align_items' => 'center',\\n\\t\\t\\t\\t'flex_gap'         => acspv_gap( 18 ),\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\tacspv_heading(\\n\\t\\t\\t\\t\\t'Give an image a second file and it switches with the rest.',\\n\\t\\t\\t\\t\\t'h2',\\n\\t\\t\\t\\t\\t'clamp(2rem, 3.6vw, 3rem)',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'align'                 => 'center',\\n\\t\\t\\t\\t\\t\\t'_element_width'        => 'initial',\\n\\t\\t\\t\\t\\t\\t\\\/\\\/ px, not ch: the wrapper this lands on inherits the body\\n\\t\\t\\t\\t\\t\\t\\\/\\\/ font-size, so a ch measure on a display face is ~4x tight.\\n\\t\\t\\t\\t\\t\\t'_element_custom_width' => acspv_css( 'min(660px, 100%)' ),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_body(\\n\\t\\t\\t\\t\\t'Screenshots on white, diagrams, product shots, a logo drawn in black \\u2014 artwork made for a light page rarely survives a dark one. Each takes its own night version.',\\n\\t\\t\\t\\t\\t'1.1875rem',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'align'                 => 'center',\\n\\t\\t\\t\\t\\t\\t'_element_custom_width' => acspv_css( 'min(54ch, 100%)' ),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t\\tacspv_row(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'container_type'           => 'grid',\\n\\t\\t\\t\\t'grid_columns_grid'        => array(\\n\\t\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t\\t'size' => 3,\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\t'grid_columns_grid_mobile' => array(\\n\\t\\t\\t\\t\\t'unit' => 'fr',\\n\\t\\t\\t\\t\\t'size' => 1,\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\t'grid_rows_grid'           => acspv_css( 'auto' ),\\n\\t\\t\\t\\t'grid_gaps'                => acspv_gap( 22 ),\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\tacspv_still_widget( $acspv_url['a'], $acspv_url['a_alt'] ),\\n\\t\\t\\t\\tacspv_still_widget( $acspv_url['b'], $acspv_url['b_alt'] ),\\n\\t\\t\\t\\tacspv_still_widget( $acspv_url['c'], $acspv_url['c_alt'] ),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n\\\/**\\n * A shape drifting through the closing section. Absolute positioning is free\\n * on containers (`position`, unprefixed \\u2014 the underscore-prefixed twin is the\\n * widget key), so these need no CSS and, being Global Colors, they morph along\\n * with the page rather than sitting inert.\\n *\\\/\\nfunction acspv_drift( string $color, string $side, float $x, float $y, int $size, bool $ring = false ): array {\\n\\t\\\/\\\/ Sized for a 1440px canvas; at 390px the same circles swamp the column and\\n\\t\\\/\\\/ cut through the headline, so each one steps down with the breakpoint.\\n\\t$acspv_tablet = (int) round( $size * 0.7 );\\n\\t$acspv_mobile = (int) round( $size * 0.42 );\\n\\n\\t$acspv_settings = array(\\n\\t\\t'position'              => 'absolute',\\n\\t\\t'_offset_orientation_h' => 'end' === $side ? 'end' : 'start',\\n\\t\\t'_offset_y'             => acspv_size( $y, '%' ),\\n\\t\\t'width'                 => acspv_size( $size ),\\n\\t\\t'width_tablet'          => acspv_size( $acspv_tablet ),\\n\\t\\t'width_mobile'          => acspv_size( $acspv_mobile ),\\n\\t\\t'min_height'            => acspv_size( $size ),\\n\\t\\t'min_height_tablet'     => acspv_size( $acspv_tablet ),\\n\\t\\t'min_height_mobile'     => acspv_size( $acspv_mobile ),\\n\\t\\t'border_radius'         => acspv_box( '50', '50', '50', '50', '%' ),\\n\\t\\t'z_index'               => 0,\\n\\t);\\n\\n\\t$acspv_settings[ 'end' === $side ? '_offset_x_end' : '_offset_x' ] = acspv_size( $x, '%' );\\n\\n\\tif ( $ring ) {\\n\\t\\t\\\/\\\/ A ring is the same circle with its fill dropped and a thick border \\u2014\\n\\t\\t\\\/\\\/ no extra element, and the border takes a Global Color too.\\n\\t\\treturn acspv_row(\\n\\t\\t\\tacspv_merge(\\n\\t\\t\\t\\t$acspv_settings,\\n\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t'border_border'       => 'solid',\\n\\t\\t\\t\\t\\t'border_width'        => acspv_box( '13', '13', '13', '13' ),\\n\\t\\t\\t\\t\\t'border_width_mobile' => acspv_box( '6', '6', '6', '6' ),\\n\\t\\t\\t\\t\\t'__globals__'         => array( 'border_color' => 'globals\\\/colors?id=' . $color ),\\n\\t\\t\\t\\t)\\n\\t\\t\\t)\\n\\t\\t);\\n\\t}\\n\\n\\treturn acspv_shape( $color, $acspv_settings );\\n}\\n\\n\\\/\\\/ The closer. Tall on purpose: the morph is meant to be felt on the way in\\n\\\/\\\/ rather than noticed, so the viewport handles sit apart and it scrubs.\\n$acspv_closer = acspv_row(\\n\\tarray(\\n\\t\\t'_element_id'          => 'acs-scroll',\\n\\t\\t'min_height'           => acspv_size( 210, 'vh' ),\\n\\t\\t'min_height_tablet'    => acspv_size( 180, 'vh' ),\\n\\t\\t'min_height_mobile'    => acspv_size( 150, 'vh' ),\\n\\t\\t'overflow'             => 'hidden',\\n\\t\\t'flex_direction'       => 'column',\\n\\t\\t'flex_justify_content' => 'center',\\n\\t\\t'padding'              => acspv_box( '0', '24', '0', '24' ),\\n\\t\\t'arts_cs_enabled'      => 'switch',\\n\\t\\t'arts_cs_viewport'     => array(\\n\\t\\t\\t'unit'  => '%',\\n\\t\\t\\t'sizes' => array(\\n\\t\\t\\t\\t'start' => 0,\\n\\t\\t\\t\\t'end'   => 100,\\n\\t\\t\\t),\\n\\t\\t),\\n\\t),\\n\\tarray(\\n\\t\\t\\\/\\\/ Kept clear of the 30-70% band, where the centred text sits. They are\\n\\t\\t\\\/\\\/ already behind it \\u2014 a hit-test across the headline returns the H2 at\\n\\t\\t\\\/\\\/ every point \\u2014 but a saturated ring immediately behind a glyph reads\\n\\t\\t\\\/\\\/ as a collision whatever the stacking order says, and on a phone the\\n\\t\\t\\\/\\\/ column is narrow enough that there is nowhere for the eye to escape.\\n\\t\\tacspv_drift( 'acsacc', 'start', -6, 4, 190 ),\\n\\t\\tacspv_drift( 'acsink', 'end', 4, 13, 110 ),\\n\\t\\tacspv_drift( 'acsacc', 'end', -4, 23, 230, true ),\\n\\t\\tacspv_drift( 'acsmut', 'start', 5, 71, 90 ),\\n\\t\\tacspv_drift( 'acsacc', 'start', -3, 79, 160 ),\\n\\t\\tacspv_drift( 'acsline', 'end', 10, 87, 120 ),\\n\\t\\tacspv_drift( 'acsink', 'start', 42, 94, 130 ),\\n\\t\\tacspv_row(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'content_width'    => 'boxed',\\n\\t\\t\\t\\t'boxed_width'      => acspv_size( 640 ),\\n\\t\\t\\t\\t'flex_direction'   => 'column',\\n\\t\\t\\t\\t'flex_align_items' => 'center',\\n\\t\\t\\t\\t'flex_gap'         => acspv_gap( 20 ),\\n\\t\\t\\t\\t'z_index'          => 5,\\n\\t\\t\\t),\\n\\t\\t\\tarray(\\n\\t\\t\\t\\tacspv_heading(\\n\\t\\t\\t\\t\\t'A section can switch the page on its own, as you scroll into it.',\\n\\t\\t\\t\\t\\t'h2',\\n\\t\\t\\t\\t\\t'clamp(2rem, 3.6vw, 3rem)',\\n\\t\\t\\t\\t\\tarray( 'align' => 'center' )\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_body(\\n\\t\\t\\t\\t\\t'A dark interlude in a light story \\u2014 a case study, a gallery, a quote from a founder \\u2014 and then back again.',\\n\\t\\t\\t\\t\\t'1.0625rem',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'align'                 => 'center',\\n\\t\\t\\t\\t\\t\\t'_element_custom_width' => acspv_css( 'min(46ch, 100%)' ),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\tacspv_widget(\\n\\t\\t\\t\\t\\t'button',\\n\\t\\t\\t\\t\\tarray(\\n\\t\\t\\t\\t\\t\\t'text'                   => 'Download Plugin',\\n\\t\\t\\t\\t\\t\\t'link'                   => array(\\n\\t\\t\\t\\t\\t\\t\\t'url'         => 'https:\\\/\\\/wordpress.org\\\/plugins\\\/color-switcher-for-elementor\\\/',\\n\\t\\t\\t\\t\\t\\t\\t'is_external' => 'on',\\n\\t\\t\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'selected_icon'          => array(\\n\\t\\t\\t\\t\\t\\t\\t'value'   => 'fab fa-wordpress',\\n\\t\\t\\t\\t\\t\\t\\t'library' => 'fa-brands',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t\\t'icon_align'             => 'left',\\n\\t\\t\\t\\t\\t\\t'icon_indent'            => acspv_size( 9 ),\\n\\t\\t\\t\\t\\t\\t'align'                  => 'center',\\n\\t\\t\\t\\t\\t\\t'border_radius'          => acspv_box( '10', '10', '10', '10' ),\\n\\t\\t\\t\\t\\t\\t'text_padding'           => acspv_box( '14', '22', '14', '22' ),\\n\\t\\t\\t\\t\\t\\t'typography_typography'  => 'custom',\\n\\t\\t\\t\\t\\t\\t'typography_font_size'   => acspv_size( 15 ),\\n\\t\\t\\t\\t\\t\\t'typography_font_weight' => '500',\\n\\t\\t\\t\\t\\t\\t'typography_font_family' => 'Instrument Sans',\\n\\t\\t\\t\\t\\t\\t'background_background'  => 'classic',\\n\\t\\t\\t\\t\\t\\t'_element_width'         => 'auto',\\n\\t\\t\\t\\t\\t\\t'__globals__'            => array(\\n\\t\\t\\t\\t\\t\\t\\t'background_color'  => 'globals\\\/colors?id=acsacc',\\n\\t\\t\\t\\t\\t\\t\\t'button_text_color' => 'globals\\\/colors?id=acspnl',\\n\\t\\t\\t\\t\\t\\t\\t'button_background_hover_color' => 'globals\\\/colors?id=acsink',\\n\\t\\t\\t\\t\\t\\t),\\n\\t\\t\\t\\t\\t)\\n\\t\\t\\t\\t),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n$acspv_footer = acspv_row(\\n\\tarray(\\n\\t\\t'_title'           => 'Footer',\\n\\t\\t'border_border'    => 'solid',\\n\\t\\t'border_width'     => acspv_box( '1', '0', '0', '0' ),\\n\\t\\t'padding'          => acspv_box( '46', '32', '52', '32' ),\\n\\t\\t'flex_direction'   => 'column',\\n\\t\\t'flex_align_items' => 'center',\\n\\t\\t'flex_gap'         => acspv_gap( 8 ),\\n\\t\\t'__globals__'      => array( 'border_color' => 'globals\\\/colors?id=acsline' ),\\n\\t),\\n\\tarray(\\n\\t\\tacspv_heading( 'Arts Color Switcher for Elementor', 'h3', '1.0625rem', array( 'align' => 'center' ) ),\\n\\t\\tacspv_body(\\n\\t\\t\\t'Designed by Artem Semkin',\\n\\t\\t\\t'0.8125rem',\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'align'       => 'center',\\n\\t\\t\\t\\t'link'        => array(\\n\\t\\t\\t\\t\\t'url'         => 'https:\\\/\\\/artemsemkin.com',\\n\\t\\t\\t\\t\\t'is_external' => 'on',\\n\\t\\t\\t\\t\\t'nofollow'    => '',\\n\\t\\t\\t\\t),\\n\\t\\t\\t\\t'__globals__' => array( 'title_hover_color' => 'globals\\\/colors?id=acsacc' ),\\n\\t\\t\\t)\\n\\t\\t),\\n\\t)\\n);\\n\\n$acspv_data = array( $acspv_header, $acspv_hero, $acspv_skins, $acspv_colors_section, $acspv_images, $acspv_closer, $acspv_footer );\\n\\n\\\/* ------------------------------------------------------------------------- *\\n * Persist\\n * ------------------------------------------------------------------------- *\\\/\\n\\n$acspv_slug          = 'color-switcher-preview';\\n$acspv_existing_page = get_page_by_path( $acspv_slug, OBJECT, 'page' );\\n\\nif ( $acspv_existing_page ) {\\n\\twp_delete_post( $acspv_existing_page->ID, true );\\n}\\n\\n$acspv_page_id = wp_insert_post(\\n\\tarray(\\n\\t\\t'import_id'   => ACS_PREVIEW_DEMO_PAGE_ID,\\n\\t\\t'post_title'  => 'Color Switcher',\\n\\t\\t'post_name'   => $acspv_slug,\\n\\t\\t'post_type'   => 'page',\\n\\t\\t'post_status' => 'publish',\\n\\t)\\n);\\n\\n\\\/\\\/ Canvas twice on purpose: the page setting is what Elementor's own panel\\n\\\/\\\/ reads, `_wp_page_template` is what WordPress's template loader reads. Setting\\n\\\/\\\/ only one of them leaves the theme's header and footer on the page.\\nupdate_post_meta( $acspv_page_id, '_elementor_edit_mode', 'builder' );\\nupdate_post_meta( $acspv_page_id, '_elementor_template_type', 'wp-page' );\\nupdate_post_meta( $acspv_page_id, '_elementor_version', ELEMENTOR_VERSION );\\nupdate_post_meta( $acspv_page_id, '_elementor_data', wp_slash( wp_json_encode( $acspv_data, JSON_UNESCAPED_UNICODE ) ) );\\nupdate_post_meta(\\n\\t$acspv_page_id,\\n\\t'_elementor_page_settings',\\n\\tarray(\\n\\t\\t'template'              => 'elementor_canvas',\\n\\t\\t'hide_title'            => 'yes',\\n\\t\\t\\\/\\\/ The document's own surface. Without this the page keeps the theme's\\n\\t\\t\\\/\\\/ white behind everything: harmless-looking in the light palette, and\\n\\t\\t\\\/\\\/ in the dark one it strands near-white headings on a white page.\\n\\t\\t'background_background' => 'classic',\\n\\t\\t'__globals__'           => array( 'background_color' => 'globals\\\/colors?id=acssurf' ),\\n\\t)\\n);\\nupdate_post_meta( $acspv_page_id, '_wp_page_template', 'elementor_canvas' );\\n\\n\\\/\\\/ No `arts_cs_page_theme`: the preview opens in the visitor's own device theme,\\n\\\/\\\/ which is both the best first impression and a free demonstration of Auto.\\n\\nupdate_option( 'page_on_front', $acspv_page_id );\\nupdate_option( 'show_on_front', 'page' );\\nupdate_option( 'blogname', 'Color Switcher' );\\nupdate_option( 'blogdescription', '' );\\n\\n\\\/\\\/ Generated CSS never diffs itself, and the editor prefers a newer autosave\\n\\\/\\\/ over raw meta \\u2014 a re-seed shows the previous page without both of these.\\nif ( class_exists( '\\\\Elementor\\\\Core\\\\Files\\\\CSS\\\\Post' ) ) {\\n\\t\\\\Elementor\\\\Core\\\\Files\\\\CSS\\\\Post::create( $acspv_page_id )->delete();\\n}\\n\\ndelete_post_meta( $acspv_page_id, '_elementor_element_cache' );\\n\\nforeach ( wp_get_post_revisions( $acspv_page_id, array( 'fields' => 'ids' ) ) as $acspv_revision_id ) {\\n\\twp_delete_post_revision( $acspv_revision_id );\\n}\\n\\nElementor::$instance->files_manager->clear_cache();\\n\\nif ( defined( 'WP_CLI' ) && WP_CLI ) {\\n\\tWP_CLI::success( 'Preview page seeded: ' . get_permalink( $acspv_page_id ) );\\n}\\n\"},{\"step\":\"runPHP\",\"code\":\"<?php require_once '\\\/wordpress\\\/wp-load.php'; require '\\\/wordpress\\\/wp-content\\\/color-switcher-for-elementor-demo-seed.php';\"},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"color-switcher-for-elementor\"},\"options\":{\"activate\":true}}]}"}},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3679748,"resolution":"1","location":"assets","locale":"","width":1520,"height":1520},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3679748,"resolution":"2","location":"assets","locale":"","width":1520,"height":1520},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3679748,"resolution":"3","location":"assets","locale":"","width":1520,"height":1520},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3679748,"resolution":"4","location":"assets","locale":"","width":1520,"height":1520},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3679748,"resolution":"5","location":"assets","locale":"","width":1520,"height":1520}},"screenshots":{"1":"Every Elementor Global Color gains an Alt swatch in Site Settings \u2013 the second palette dark mode and the scroll effect both switch to.","2":"Dark mode logos and images: each image control gains an Alt picker, background images and hover states included.","3":"Mark any section to switch colors on scroll. The Viewport range decides where \u2013 handles together for an instant flip, apart to interpolate with scroll position.","4":"The Color Switcher widget is a dark mode toggle in four shapes: an icon, a switch, a row of buttons, or a dropdown.","5":"Style the toggle in the panel: layout, two states or three, labels, icons, and colors you link to your Global Colors."}},"plugin_section":[],"plugin_tags":[173231,222930,76538,163960,250933],"plugin_category":[],"plugin_contributors":[241532],"plugin_business_model":[],"class_list":["post-362629","plugin","type-plugin","status-publish","hentry","plugin_tags-dark-mode","plugin_tags-dark-mode-toggle","plugin_tags-elementor","plugin_tags-night-mode","plugin_tags-scroll-effects","plugin_contributors-artemsemkin","plugin_committers-artemsemkin"],"banners":{"banner":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/banner-772x250.jpg?rev=3679748","banner_2x":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/banner-1544x500.jpg?rev=3679748","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/icon.svg?rev=3679748","icon":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/icon.svg?rev=3679748","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/screenshot-1.png?rev=3679748","caption":"Every Elementor Global Color gains an Alt swatch in Site Settings \u2013 the second palette dark mode and the scroll effect both switch to."},{"src":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/screenshot-2.png?rev=3679748","caption":"Dark mode logos and images: each image control gains an Alt picker, background images and hover states included."},{"src":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/screenshot-3.png?rev=3679748","caption":"Mark any section to switch colors on scroll. The Viewport range decides where \u2013 handles together for an instant flip, apart to interpolate with scroll position."},{"src":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/screenshot-4.png?rev=3679748","caption":"The Color Switcher widget is a dark mode toggle in four shapes: an icon, a switch, a row of buttons, or a dropdown."},{"src":"https:\/\/ps.w.org\/color-switcher-for-elementor\/assets\/screenshot-5.png?rev=3679748","caption":"Style the toggle in the panel: layout, two states or three, labels, icons, and colors you link to your Global Colors."}],"raw_content":"<!--section=description-->\n<p>Scroll into a section and the page changes its colors \u2013 background, headings, body text, buttons, borders, icons, all together, like the lights dimming in a room. The same mechanism doubles as a real dark mode for Elementor: drop in the toggle widget and visitors switch between two palettes you designed, not one a filter guessed by inverting your site.<\/p>\n\n<p>It works by extending something you already use. Every Global Color in Site Settings gets a second \"Alt\" swatch next to it \u2013 the same color picker, one row, no new screen. Fill it in for the colors that should change, mark the sections that should switch on scroll, place the toggle where visitors should find it. And there's no Pro version: this is the whole thing.<\/p>\n\n<p>Two things to know before you install. This changes what your visitors see \u2013 it is not a dark skin for wp-admin. And it turns the colors you linked to Global Colors: that linkage is the whole mechanism, so a hex typed straight into a widget stays where it is. Sites built the way Elementor intends have little to do; sites full of hand-typed colors have some linking to do first.<\/p>\n\n<h4>Nothing to rebuild<\/h4>\n\n<p>Your widgets already reference Global Colors. That's the entire integration \u2013 the plugin re-points those same colors, so anything linked to them turns automatically, including sections you never touched. A color with no Alt value keeps its original, which means you can adopt this on an existing site one color at a time.<\/p>\n\n<h4>Change colors on scroll<\/h4>\n\n<p>A marked section shows the alternative palette while it is on screen, and the page returns to its own palette by itself once the section has passed \u2013 nothing has to be marked as \"the normal one\".<\/p>\n\n<p>One control decides where that happens: a range over the viewport with two handles. Put both handles together and the switch is instant; move them apart and the colors interpolate continuously with scroll position across that band. The default \u2013 both at the top \u2013 turns the page once the section has scrolled up to fill the screen, the way it reads in the portfolio themes this effect comes from. A section holds the page for as long as its own height, so sections shorter than the screen want their handles moved down. Whether a section switches at all is per-device, so an effect can run on desktop and stay off on phones.<\/p>\n\n<h4>Works inside horizontal scroll sections<\/h4>\n\n<p>A section pinned by Arts Horizontal Scroll travels sideways while its vertical position stands still, so marking one of its panels works the way you would expect. The Viewport control keeps its meaning too \u2013 it just reads across the screen instead of down it: how far the panel travels before the colors change.<\/p>\n\n<h4>A dark mode toggle, four shapes<\/h4>\n\n<p>Drop the Color Switcher widget anywhere \u2013 or use the <code>[arts_color_switcher_toggle]<\/code> shortcode in a menu or footer \u2013 and visitors pick a side: an icon, a switch, a row of buttons, or a dropdown. Their choice is remembered, and it travels with them from page to page.<\/p>\n\n<p>Everything but the switch can offer two states or three, and the third is \"follow the system\": a visitor who picks it keeps tracking their device's light and dark setting for as long as they leave it there \u2013 change the system setting and the site changes with it. Two states can still be undone: press once to pin a palette, press again to release it, and the visitor ends up exactly where they started, which a toggle that can only ever store a choice cannot do.<\/p>\n\n<h4>Dark pages, light pages, or follow the device<\/h4>\n\n<p>Each page opens one of three ways, set under Page Settings. Left alone, it follows the visitor's device \u2013 the same dark mode setting their phone binds to their own sunrise and sunset. Or you can pin it: Default colors for a page that must stay light for everyone, Alt colors for one that must start dark. A pinned page is rendered server-side, so there is no flash of the wrong colors and it works with JavaScript disabled.<\/p>\n\n<p>A marked section always shows the opposite of whatever the page starts in, so on a dark page the marked sections are the light interludes. That holds for a visitor whose device turned the page dark too \u2013 the contrast survives wherever the page begins.<\/p>\n\n<h4>Dark mode logos and images<\/h4>\n\n<p>Color is only half of a dark page. A logo drawn for a light background disappears on a dark one, and no palette can rescue it \u2013 that needs a different file.<\/p>\n\n<p>So every image control grows a second picker. Open the image you already chose and there is a \"Choose Alt Image\" button beside it: point it at the white version of your logo and that version appears whenever the alternative palette is on. Background images work the same way \u2013 a section's, a widget's, and the hover state of either. Nothing moves to a new screen, and an image without an Alt simply keeps what it has.<\/p>\n\n<h4>Built on modern CSS<\/h4>\n\n<p>Colors interpolate in the OKLab color space through CSS custom properties, so midpoints look right instead of muddy. Scroll-bound switching uses native CSS scroll-driven animations where the browser supports them \u2013 no JavaScript runs per frame \u2013 and falls back to a scroll-timeline polyfill in Firefox. The editor shows the real thing: scroll the canvas and the colors turn exactly as they do on the frontend. In browsers with customizable selects (Chrome, Edge), the Dropdown toggle's options open as a styled, animated list you can design from the widget; everywhere else the platform's own picker keeps working.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin. The free Elementor plugin is the only requirement.<\/li>\n<li>Open Site Settings \u2192 Global Colors and fill in the \"Alt\" swatch next to any color.<\/li>\n<li>Edit a page, select a Container, and set \"Flip colors in this section\" to Yes under Color Switcher.<\/li>\n<li>Scroll the canvas \u2013 the page turns as the section comes into view.<\/li>\n<li>For a dark mode toggle, drop the Color Switcher widget into your header or footer.<\/li>\n<li>To swap a logo or a background image too, open its image control and use \"Choose Alt Image\".<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20need%20elementor%20pro%3F\"><h3>Does it need Elementor Pro?<\/h3><\/dt>\n<dd><p>No \u2013 the free Elementor is enough.<\/p><\/dd>\n<dt id=\"does%20this%20add%20a%20dark%20mode%20toggle%3F\"><h3>Does this add a dark mode toggle?<\/h3><\/dt>\n<dd><p>Yes. Drop the Color Switcher widget anywhere \u2013 or the <code>[arts_color_switcher_toggle]<\/code> shortcode in a menu or footer \u2013 and pick one of four shapes: an icon, a switch, a row of buttons, or a dropdown. A visitor's choice is remembered across pages, and until they make one the page opens on whatever their device asks for \u2013 or on the palette you pinned, if you pinned one.<\/p><\/dd>\n<dt id=\"how%20is%20this%20different%20from%20other%20dark%20mode%20plugins%3F\"><h3>How is this different from other dark mode plugins?<\/h3><\/dt>\n<dd><p>Most dark mode plugins generate the dark version for you: a CSS filter or a script inverts whatever your site happens to be, and you exclude the parts it gets wrong. This plugin generates nothing. You design the second palette yourself, in the same Global Colors picker you designed the first one in, and only what you linked changes. That is more work than a filter on day one, and it is the reason the result looks designed rather than inverted ever after. It is also why the switch is cheap: the colors are computed in CSS, nothing rewrites your HTML, and the same mechanism turns whole sections as visitors scroll \u2013 which a filter cannot do at all.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20colors%20i%20didn%27t%20set%20an%20alt%20value%20for%3F\"><h3>What happens to colors I didn't set an Alt value for?<\/h3><\/dt>\n<dd><p>They stay exactly as they are. Partial adoption is expected \u2013 set alternatives only for the colors that should change.<\/p><\/dd>\n<dt id=\"what%20will%20not%20follow%20the%20switch%3F\"><h3>What will not follow the switch?<\/h3><\/dt>\n<dd><p>Colors that are not Global Colors: a hex typed into a widget, an inline <code>style<\/code> attribute, or a color supplied by a dynamic tag. Embedded content you do not control \u2013 YouTube, maps, third-party forms \u2013 keeps its own colors, and WordPress itself renders oEmbeds on a white background regardless of your theme. Printing resets the colors to your default palette, because light text on paper does not print; Alt images are not reset, so a page printed while the alternative palette is on keeps its alternative images.<\/p>\n\n<p>Images do follow, but only where you hand them something to follow with: pick an Alt image on the control and it swaps. Inline SVG drawn with <code>currentColor<\/code> follows for free and needs no second file at all, which is usually the right answer for a single-color logo. Anything that has to re-theme itself in JavaScript can listen for the <code>arts-cs:change<\/code> event.<\/p><\/dd>\n<dt id=\"will%20hardcoded%20colors%20switch%3F\"><h3>Will hardcoded colors switch?<\/h3><\/dt>\n<dd><p>No. Only colors linked to Elementor's Global Colors follow the switch, which is the same rule that makes the rest of Site Settings work. The same goes for a color supplied by a dynamic tag: Elementor resolves a dynamic tag to a literal value when the page renders, so those behave like a typed-in color rather than a linked one.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20my%20other%20plugins%3F\"><h3>Does it work with my other plugins?<\/h3><\/dt>\n<dd><p>Anything that takes its colors from Global Colors follows the switch, whoever drew it \u2013 a cursor, a lightbox's chrome, a device mockup's frame. That is the whole point of routing through Elementor's own colors instead of inventing a palette.<\/p>\n\n<p>Two specifics worth knowing. Sections pinned by Arts Horizontal Scroll are supported: mark a panel and the page turns as that panel crosses the screen. And if a plugin re-declares a Global Color on a smaller part of the page \u2013 Arts Header for Elementor does this for its sticky bar \u2013 that closer declaration wins there, so the pinned bar keeps the color it was given instead of following the page.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20elementor%27s%20new%20editor%3F\"><h3>Does it work with Elementor's new editor?<\/h3><\/dt>\n<dd><p>Not with its new elements yet, and it is worth knowing why before you build a page out of them. Elementor's atomic elements do not read Global Colors at all \u2013 they take their colors from a separate list of variables that is stored and named its own way. Alt values live on Global Colors, so an element built the new way has nothing to follow and keeps its colors while the rest of the page turns.<\/p>\n\n<p>Everything built the way Elementor has always worked is unaffected, and the two can share a page. Elementor still ships the new system as alpha and the way it stores those variables has already changed once, so we would rather wait for it to settle than guess at it and break your site later.<\/p><\/dd>\n<dt id=\"can%20my%20logo%20change%20with%20dark%20mode%3F\"><h3>Can my logo change with dark mode?<\/h3><\/dt>\n<dd><p>Yes. Every image control gains a \"Choose Alt Image\" button next to the one you already use \u2013 pick the alternative file there and it appears whenever the other palette is on. Background images work the same way, hover states included.<\/p>\n\n<p>The button shows up once at least one Global Color has an Alt value. Until then there is no second palette for an image to belong to, so there is nothing for the button to do.<\/p>\n\n<p>Give the alternative the same dimensions as the original. The layout keeps the original's box, so a file with a different shape will be stretched into it.<\/p>\n\n<p>If your logo is a single-color SVG you may not need this at all: an inline SVG drawn with <code>currentColor<\/code> already follows the palette the way text does.<\/p><\/dd>\n<dt id=\"do%20galleries%20and%20carousels%20swap%20their%20images%3F\"><h3>Do galleries and carousels swap their images?<\/h3><\/dt>\n<dd><p>No. Those hold many images behind one control, so there is no way to say which alternative belongs to which. What this covers is single-image widgets \u2013 Image, Image Box, the Site Logo widget \u2013 and background images.<\/p>\n\n<p>One place has no Alt picker: the logo in Site Settings \u2192 Site Identity. Use the Site Logo widget in your header template instead, which does.<\/p><\/dd>\n<dt id=\"can%20i%20schedule%20dark%20mode%20for%20night%20time%3F\"><h3>Can I schedule dark mode for night time?<\/h3><\/dt>\n<dd><p>No, and not as an oversight. A schedule lives on the server, which has one clock and one timezone; the people reading your site do not. Night in Chicago is the middle of the afternoon in Manila, so a server-side schedule is simply wrong for most of your visitors most of the time.<\/p>\n\n<p>Their own devices already solve this, and solve it properly: dark mode on a modern phone or laptop follows that person's real sunrise and sunset, wherever they happen to be. A visitor who picks \"System\" on the toggle gets exactly that.<\/p><\/dd>\n<dt id=\"i%20styled%20the%20toggle%20with%20my%20own%20css.%20will%20an%20update%20break%20it%3F\"><h3>I styled the toggle with my own CSS. Will an update break it?<\/h3><\/dt>\n<dd><p>Not if you style it through the documented hooks. Every skin's root carries the class <code>js-arts-cs-toggle<\/code> and a <code>data-arts-cs-toggle<\/code> attribute naming the skin, and <code>&lt;html&gt;<\/code> carries <code>data-arts-cs<\/code> for the current palette and <code>data-arts-cs-pref<\/code> for the visitor's stored choice. Those names are fixed and will not change. The inner markup is not a promise.<\/p><\/dd>\n<dt id=\"does%20it%20work%20behind%20a%20page%20cache%3F\"><h3>Does it work behind a page cache?<\/h3><\/dt>\n<dd><p>Yes. A visitor's palette choice lives in a cookie, and a small inline script applies it to <code>&lt;html&gt;<\/code> before first paint. The cached HTML is identical for every visitor \u2013 Cloudflare, object caching, whatever you run \u2013 and each visitor still sees their own choice with no flash of the wrong colors.<\/p><\/dd>\n<dt id=\"can%20several%20sections%20switch%20on%20one%20page%3F\"><h3>Can several sections switch on one page?<\/h3><\/dt>\n<dd><p>Yes \u2013 mark as many as you like. Each one turns the page while it is on screen and hands the colors back when it leaves. To keep a run of sections switched together, mark the container that holds them instead of each one. Sections that spread their change across a scroll distance take turns: only one can be doing so at any moment, so if two of them are on screen together the later one in the page decides.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<p>Initial release.<\/p>","raw_excerpt":"Dark mode toggle and scroll-triggered color switching for Elementor. Every Global Color gets an Alt value; the whole page follows \u2013 images too.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/362629","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=362629"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/artemsemkin"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=362629"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=362629"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=362629"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=362629"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=362629"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=362629"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}