color-options.php

I’ll build this as a reusable WordPress theme options module for inc/options/color-options.php, focused on Customizer color controls, CSS variables, sanitization, presets, gradients, dark mode, Gutenberg/editor support, and front-end output.

Below is an advanced inc/options/color-options.php file for your rx theme. It adds many color features using the WordPress Customizer, CSS variables, live preview support, dark mode options, gradients, button colors, header/footer colors, link colors, border colors, form colors, block editor palette support, and front-end dynamic CSS.

Create this file:

mkdir -p inc/options
touch inc/options/color-options.php

Then paste this full code inside:

<?php
/**
 * RX Theme Color Options
 *
 * File: inc/options/color-options.php
 *
 * Advanced color customization system for RX Theme.
 *
 * Features:
 * - WordPress Customizer color options
 * - Global CSS variables
 * - Light and dark mode color sets
 * - Header, footer, sidebar, card, form, button, link, border colors
 * - Gradient options
 * - Preset color palette
 * - Gutenberg editor color palette support
 * - Dynamic inline CSS output
 * - Sanitization helpers
 * - Live preview support
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'RX_Color_Options' ) ) :

final class RX_Color_Options {

	/**
	 * Theme option prefix.
	 *
	 * @var string
	 */
	const PREFIX = 'rx_';

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_action( 'customize_register', array( $this, 'register_customizer_options' ) );
		add_action( 'customize_preview_init', array( $this, 'customizer_live_preview' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_dynamic_colors' ), 30 );
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_dynamic_colors' ), 30 );
		add_action( 'after_setup_theme', array( $this, 'register_editor_color_palette' ), 20 );
		add_action( 'wp_head', array( $this, 'print_color_scheme_meta' ), 1 );
	}

	/**
	 * Default color values.
	 *
	 * @return array
	 */
	public static function defaults() {
		return array(

			/*
			|--------------------------------------------------------------------------
			| Base Colors
			|--------------------------------------------------------------------------
			*/
			'color_primary'              => '#2563eb',
			'color_primary_hover'        => '#1d4ed8',
			'color_primary_light'        => '#dbeafe',
			'color_primary_dark'         => '#1e40af',

			'color_secondary'            => '#0f766e',
			'color_secondary_hover'      => '#115e59',
			'color_secondary_light'      => '#ccfbf1',
			'color_secondary_dark'       => '#134e4a',

			'color_accent'               => '#f97316',
			'color_accent_hover'         => '#ea580c',
			'color_accent_light'         => '#ffedd5',
			'color_accent_dark'          => '#c2410c',

			/*
			|--------------------------------------------------------------------------
			| Body / Text
			|--------------------------------------------------------------------------
			*/
			'color_body_bg'              => '#ffffff',
			'color_body_text'            => '#111827',
			'color_body_text_muted'      => '#6b7280',
			'color_heading'              => '#0f172a',
			'color_paragraph'            => '#374151',
			'color_selection_bg'         => '#2563eb',
			'color_selection_text'       => '#ffffff',

			/*
			|--------------------------------------------------------------------------
			| Links
			|--------------------------------------------------------------------------
			*/
			'color_link'                 => '#2563eb',
			'color_link_hover'           => '#1d4ed8',
			'color_link_visited'         => '#7c3aed',
			'color_link_underline'       => '#93c5fd',

			/*
			|--------------------------------------------------------------------------
			| Header
			|--------------------------------------------------------------------------
			*/
			'color_header_bg'            => '#ffffff',
			'color_header_text'          => '#111827',
			'color_header_link'          => '#111827',
			'color_header_link_hover'    => '#2563eb',
			'color_header_border'        => '#e5e7eb',
			'color_header_top_bg'        => '#0f172a',
			'color_header_top_text'      => '#ffffff',

			/*
			|--------------------------------------------------------------------------
			| Navigation
			|--------------------------------------------------------------------------
			*/
			'color_nav_bg'               => '#ffffff',
			'color_nav_link'             => '#111827',
			'color_nav_link_hover'       => '#2563eb',
			'color_nav_active'           => '#2563eb',
			'color_nav_dropdown_bg'      => '#ffffff',
			'color_nav_dropdown_text'    => '#111827',
			'color_nav_dropdown_hover'   => '#eff6ff',

			/*
			|--------------------------------------------------------------------------
			| Footer
			|--------------------------------------------------------------------------
			*/
			'color_footer_bg'            => '#0f172a',
			'color_footer_text'          => '#cbd5e1',
			'color_footer_heading'       => '#ffffff',
			'color_footer_link'          => '#bfdbfe',
			'color_footer_link_hover'    => '#ffffff',
			'color_footer_border'        => '#1e293b',
			'color_footer_bottom_bg'     => '#020617',
			'color_footer_bottom_text'   => '#94a3b8',

			/*
			|--------------------------------------------------------------------------
			| Buttons
			|--------------------------------------------------------------------------
			*/
			'color_button_bg'            => '#2563eb',
			'color_button_text'          => '#ffffff',
			'color_button_hover_bg'      => '#1d4ed8',
			'color_button_hover_text'    => '#ffffff',
			'color_button_border'        => '#2563eb',

			'color_button_secondary_bg'         => '#0f766e',
			'color_button_secondary_text'       => '#ffffff',
			'color_button_secondary_hover_bg'   => '#115e59',
			'color_button_secondary_hover_text' => '#ffffff',

			'color_button_outline_text'   => '#2563eb',
			'color_button_outline_border' => '#2563eb',
			'color_button_outline_hover_bg' => '#2563eb',
			'color_button_outline_hover_text' => '#ffffff',

			/*
			|--------------------------------------------------------------------------
			| Cards / Containers
			|--------------------------------------------------------------------------
			*/
			'color_card_bg'              => '#ffffff',
			'color_card_text'            => '#111827',
			'color_card_border'          => '#e5e7eb',
			'color_card_shadow'          => 'rgba(15, 23, 42, 0.08)',
			'color_box_bg'               => '#f9fafb',
			'color_box_border'           => '#e5e7eb',

			/*
			|--------------------------------------------------------------------------
			| Sidebar / Widgets
			|--------------------------------------------------------------------------
			*/
			'color_sidebar_bg'           => '#ffffff',
			'color_sidebar_text'         => '#374151',
			'color_sidebar_heading'      => '#111827',
			'color_sidebar_link'         => '#2563eb',
			'color_sidebar_link_hover'   => '#1d4ed8',
			'color_widget_bg'            => '#ffffff',
			'color_widget_border'        => '#e5e7eb',

			/*
			|--------------------------------------------------------------------------
			| Forms
			|--------------------------------------------------------------------------
			*/
			'color_input_bg'             => '#ffffff',
			'color_input_text'           => '#111827',
			'color_input_placeholder'    => '#9ca3af',
			'color_input_border'         => '#d1d5db',
			'color_input_focus_border'   => '#2563eb',
			'color_input_focus_shadow'   => 'rgba(37, 99, 235, 0.20)',
			'color_label_text'           => '#374151',

			/*
			|--------------------------------------------------------------------------
			| Tables
			|--------------------------------------------------------------------------
			*/
			'color_table_header_bg'      => '#f3f4f6',
			'color_table_header_text'    => '#111827',
			'color_table_border'         => '#e5e7eb',
			'color_table_stripe_bg'      => '#f9fafb',
			'color_table_hover_bg'       => '#eff6ff',

			/*
			|--------------------------------------------------------------------------
			| Alerts
			|--------------------------------------------------------------------------
			*/
			'color_success'              => '#16a34a',
			'color_success_bg'           => '#dcfce7',
			'color_warning'              => '#d97706',
			'color_warning_bg'           => '#fef3c7',
			'color_danger'               => '#dc2626',
			'color_danger_bg'            => '#fee2e2',
			'color_info'                 => '#0284c7',
			'color_info_bg'              => '#e0f2fe',

			/*
			|--------------------------------------------------------------------------
			| Medical / Health Brand Colors
			|--------------------------------------------------------------------------
			*/
			'color_medical_blue'         => '#0284c7',
			'color_medical_green'        => '#059669',
			'color_medical_red'          => '#dc2626',
			'color_medical_purple'       => '#7c3aed',
			'color_medical_soft_bg'      => '#f0f9ff',

			/*
			|--------------------------------------------------------------------------
			| Breadcrumb / Pagination
			|--------------------------------------------------------------------------
			*/
			'color_breadcrumb_text'      => '#6b7280',
			'color_breadcrumb_link'      => '#2563eb',
			'color_pagination_bg'        => '#ffffff',
			'color_pagination_text'      => '#111827',
			'color_pagination_border'    => '#e5e7eb',
			'color_pagination_active_bg' => '#2563eb',
			'color_pagination_active_text' => '#ffffff',

			/*
			|--------------------------------------------------------------------------
			| Code / Pre
			|--------------------------------------------------------------------------
			*/
			'color_code_bg'              => '#f3f4f6',
			'color_code_text'            => '#be123c',
			'color_pre_bg'               => '#0f172a',
			'color_pre_text'             => '#e5e7eb',

			/*
			|--------------------------------------------------------------------------
			| Gradients
			|--------------------------------------------------------------------------
			*/
			'gradient_primary_start'     => '#2563eb',
			'gradient_primary_end'       => '#7c3aed',
			'gradient_secondary_start'   => '#0f766e',
			'gradient_secondary_end'     => '#06b6d4',
			'gradient_accent_start'      => '#f97316',
			'gradient_accent_end'        => '#ef4444',
			'gradient_hero_start'        => '#eff6ff',
			'gradient_hero_end'          => '#ffffff',

			/*
			|--------------------------------------------------------------------------
			| Dark Mode
			|--------------------------------------------------------------------------
			*/
			'dark_color_body_bg'         => '#020617',
			'dark_color_body_text'       => '#e5e7eb',
			'dark_color_heading'         => '#ffffff',
			'dark_color_paragraph'       => '#cbd5e1',
			'dark_color_card_bg'         => '#0f172a',
			'dark_color_card_border'     => '#1e293b',
			'dark_color_header_bg'       => '#020617',
			'dark_color_header_text'     => '#ffffff',
			'dark_color_footer_bg'       => '#020617',
			'dark_color_footer_text'     => '#cbd5e1',
			'dark_color_input_bg'        => '#0f172a',
			'dark_color_input_text'      => '#e5e7eb',
			'dark_color_input_border'    => '#334155',

			/*
			|--------------------------------------------------------------------------
			| Controls
			|--------------------------------------------------------------------------
			*/
			'enable_dark_mode'           => false,
			'enable_system_dark_mode'    => true,
			'enable_color_css_variables' => true,
			'enable_editor_palette'      => true,
			'color_preset'               => 'default',
		);
	}

	/**
	 * Color labels for Customizer.
	 *
	 * @return array
	 */
	private function color_fields() {
		return array(
			'color_primary'                    => __( 'Primary Color', 'rx-theme' ),
			'color_primary_hover'              => __( 'Primary Hover Color', 'rx-theme' ),
			'color_primary_light'              => __( 'Primary Light Color', 'rx-theme' ),
			'color_primary_dark'               => __( 'Primary Dark Color', 'rx-theme' ),

			'color_secondary'                  => __( 'Secondary Color', 'rx-theme' ),
			'color_secondary_hover'            => __( 'Secondary Hover Color', 'rx-theme' ),
			'color_secondary_light'            => __( 'Secondary Light Color', 'rx-theme' ),
			'color_secondary_dark'             => __( 'Secondary Dark Color', 'rx-theme' ),

			'color_accent'                     => __( 'Accent Color', 'rx-theme' ),
			'color_accent_hover'               => __( 'Accent Hover Color', 'rx-theme' ),
			'color_accent_light'               => __( 'Accent Light Color', 'rx-theme' ),
			'color_accent_dark'                => __( 'Accent Dark Color', 'rx-theme' ),

			'color_body_bg'                    => __( 'Body Background', 'rx-theme' ),
			'color_body_text'                  => __( 'Body Text', 'rx-theme' ),
			'color_body_text_muted'            => __( 'Muted Text', 'rx-theme' ),
			'color_heading'                    => __( 'Heading Text', 'rx-theme' ),
			'color_paragraph'                  => __( 'Paragraph Text', 'rx-theme' ),
			'color_selection_bg'               => __( 'Selection Background', 'rx-theme' ),
			'color_selection_text'             => __( 'Selection Text', 'rx-theme' ),

			'color_link'                       => __( 'Link Color', 'rx-theme' ),
			'color_link_hover'                 => __( 'Link Hover Color', 'rx-theme' ),
			'color_link_visited'               => __( 'Visited Link Color', 'rx-theme' ),
			'color_link_underline'             => __( 'Link Underline Color', 'rx-theme' ),

			'color_header_bg'                  => __( 'Header Background', 'rx-theme' ),
			'color_header_text'                => __( 'Header Text', 'rx-theme' ),
			'color_header_link'                => __( 'Header Link', 'rx-theme' ),
			'color_header_link_hover'          => __( 'Header Link Hover', 'rx-theme' ),
			'color_header_border'              => __( 'Header Border', 'rx-theme' ),
			'color_header_top_bg'              => __( 'Header Top Background', 'rx-theme' ),
			'color_header_top_text'            => __( 'Header Top Text', 'rx-theme' ),

			'color_nav_bg'                     => __( 'Navigation Background', 'rx-theme' ),
			'color_nav_link'                   => __( 'Navigation Link', 'rx-theme' ),
			'color_nav_link_hover'             => __( 'Navigation Link Hover', 'rx-theme' ),
			'color_nav_active'                 => __( 'Navigation Active Link', 'rx-theme' ),
			'color_nav_dropdown_bg'            => __( 'Dropdown Background', 'rx-theme' ),
			'color_nav_dropdown_text'          => __( 'Dropdown Text', 'rx-theme' ),
			'color_nav_dropdown_hover'         => __( 'Dropdown Hover Background', 'rx-theme' ),

			'color_footer_bg'                  => __( 'Footer Background', 'rx-theme' ),
			'color_footer_text'                => __( 'Footer Text', 'rx-theme' ),
			'color_footer_heading'             => __( 'Footer Heading', 'rx-theme' ),
			'color_footer_link'                => __( 'Footer Link', 'rx-theme' ),
			'color_footer_link_hover'          => __( 'Footer Link Hover', 'rx-theme' ),
			'color_footer_border'              => __( 'Footer Border', 'rx-theme' ),
			'color_footer_bottom_bg'           => __( 'Footer Bottom Background', 'rx-theme' ),
			'color_footer_bottom_text'         => __( 'Footer Bottom Text', 'rx-theme' ),

			'color_button_bg'                  => __( 'Button Background', 'rx-theme' ),
			'color_button_text'                => __( 'Button Text', 'rx-theme' ),
			'color_button_hover_bg'            => __( 'Button Hover Background', 'rx-theme' ),
			'color_button_hover_text'          => __( 'Button Hover Text', 'rx-theme' ),
			'color_button_border'              => __( 'Button Border', 'rx-theme' ),

			'color_button_secondary_bg'        => __( 'Secondary Button Background', 'rx-theme' ),
			'color_button_secondary_text'      => __( 'Secondary Button Text', 'rx-theme' ),
			'color_button_secondary_hover_bg'  => __( 'Secondary Button Hover Background', 'rx-theme' ),
			'color_button_secondary_hover_text'=> __( 'Secondary Button Hover Text', 'rx-theme' ),

			'color_button_outline_text'        => __( 'Outline Button Text', 'rx-theme' ),
			'color_button_outline_border'      => __( 'Outline Button Border', 'rx-theme' ),
			'color_button_outline_hover_bg'    => __( 'Outline Button Hover Background', 'rx-theme' ),
			'color_button_outline_hover_text'  => __( 'Outline Button Hover Text', 'rx-theme' ),

			'color_card_bg'                    => __( 'Card Background', 'rx-theme' ),
			'color_card_text'                  => __( 'Card Text', 'rx-theme' ),
			'color_card_border'                => __( 'Card Border', 'rx-theme' ),
			'color_box_bg'                     => __( 'Box Background', 'rx-theme' ),
			'color_box_border'                 => __( 'Box Border', 'rx-theme' ),

			'color_sidebar_bg'                 => __( 'Sidebar Background', 'rx-theme' ),
			'color_sidebar_text'               => __( 'Sidebar Text', 'rx-theme' ),
			'color_sidebar_heading'            => __( 'Sidebar Heading', 'rx-theme' ),
			'color_sidebar_link'               => __( 'Sidebar Link', 'rx-theme' ),
			'color_sidebar_link_hover'         => __( 'Sidebar Link Hover', 'rx-theme' ),
			'color_widget_bg'                  => __( 'Widget Background', 'rx-theme' ),
			'color_widget_border'              => __( 'Widget Border', 'rx-theme' ),

			'color_input_bg'                   => __( 'Input Background', 'rx-theme' ),
			'color_input_text'                 => __( 'Input Text', 'rx-theme' ),
			'color_input_placeholder'          => __( 'Input Placeholder', 'rx-theme' ),
			'color_input_border'               => __( 'Input Border', 'rx-theme' ),
			'color_input_focus_border'         => __( 'Input Focus Border', 'rx-theme' ),
			'color_label_text'                 => __( 'Label Text', 'rx-theme' ),

			'color_table_header_bg'            => __( 'Table Header Background', 'rx-theme' ),
			'color_table_header_text'          => __( 'Table Header Text', 'rx-theme' ),
			'color_table_border'               => __( 'Table Border', 'rx-theme' ),
			'color_table_stripe_bg'            => __( 'Table Stripe Background', 'rx-theme' ),
			'color_table_hover_bg'             => __( 'Table Hover Background', 'rx-theme' ),

			'color_success'                    => __( 'Success Color', 'rx-theme' ),
			'color_success_bg'                 => __( 'Success Background', 'rx-theme' ),
			'color_warning'                    => __( 'Warning Color', 'rx-theme' ),
			'color_warning_bg'                 => __( 'Warning Background', 'rx-theme' ),
			'color_danger'                     => __( 'Danger Color', 'rx-theme' ),
			'color_danger_bg'                  => __( 'Danger Background', 'rx-theme' ),
			'color_info'                       => __( 'Info Color', 'rx-theme' ),
			'color_info_bg'                    => __( 'Info Background', 'rx-theme' ),

			'color_medical_blue'               => __( 'Medical Blue', 'rx-theme' ),
			'color_medical_green'              => __( 'Medical Green', 'rx-theme' ),
			'color_medical_red'                => __( 'Medical Red', 'rx-theme' ),
			'color_medical_purple'             => __( 'Medical Purple', 'rx-theme' ),
			'color_medical_soft_bg'            => __( 'Medical Soft Background', 'rx-theme' ),

			'color_breadcrumb_text'            => __( 'Breadcrumb Text', 'rx-theme' ),
			'color_breadcrumb_link'            => __( 'Breadcrumb Link', 'rx-theme' ),
			'color_pagination_bg'              => __( 'Pagination Background', 'rx-theme' ),
			'color_pagination_text'            => __( 'Pagination Text', 'rx-theme' ),
			'color_pagination_border'          => __( 'Pagination Border', 'rx-theme' ),
			'color_pagination_active_bg'       => __( 'Pagination Active Background', 'rx-theme' ),
			'color_pagination_active_text'     => __( 'Pagination Active Text', 'rx-theme' ),

			'color_code_bg'                    => __( 'Inline Code Background', 'rx-theme' ),
			'color_code_text'                  => __( 'Inline Code Text', 'rx-theme' ),
			'color_pre_bg'                     => __( 'Code Block Background', 'rx-theme' ),
			'color_pre_text'                   => __( 'Code Block Text', 'rx-theme' ),

			'gradient_primary_start'           => __( 'Primary Gradient Start', 'rx-theme' ),
			'gradient_primary_end'             => __( 'Primary Gradient End', 'rx-theme' ),
			'gradient_secondary_start'         => __( 'Secondary Gradient Start', 'rx-theme' ),
			'gradient_secondary_end'           => __( 'Secondary Gradient End', 'rx-theme' ),
			'gradient_accent_start'            => __( 'Accent Gradient Start', 'rx-theme' ),
			'gradient_accent_end'              => __( 'Accent Gradient End', 'rx-theme' ),
			'gradient_hero_start'              => __( 'Hero Gradient Start', 'rx-theme' ),
			'gradient_hero_end'                => __( 'Hero Gradient End', 'rx-theme' ),

			'dark_color_body_bg'               => __( 'Dark Body Background', 'rx-theme' ),
			'dark_color_body_text'             => __( 'Dark Body Text', 'rx-theme' ),
			'dark_color_heading'               => __( 'Dark Heading Text', 'rx-theme' ),
			'dark_color_paragraph'             => __( 'Dark Paragraph Text', 'rx-theme' ),
			'dark_color_card_bg'               => __( 'Dark Card Background', 'rx-theme' ),
			'dark_color_card_border'           => __( 'Dark Card Border', 'rx-theme' ),
			'dark_color_header_bg'             => __( 'Dark Header Background', 'rx-theme' ),
			'dark_color_header_text'           => __( 'Dark Header Text', 'rx-theme' ),
			'dark_color_footer_bg'             => __( 'Dark Footer Background', 'rx-theme' ),
			'dark_color_footer_text'           => __( 'Dark Footer Text', 'rx-theme' ),
			'dark_color_input_bg'              => __( 'Dark Input Background', 'rx-theme' ),
			'dark_color_input_text'            => __( 'Dark Input Text', 'rx-theme' ),
			'dark_color_input_border'          => __( 'Dark Input Border', 'rx-theme' ),
		);
	}

	/**
	 * Register Customizer settings and controls.
	 *
	 * @param WP_Customize_Manager $wp_customize Customizer object.
	 * @return void
	 */
	public function register_customizer_options( $wp_customize ) {

		$wp_customize->add_panel(
			'rx_color_panel',
			array(
				'title'       => __( 'RX Color System', 'rx-theme' ),
				'description' => __( 'Advanced color options for the RX Theme.', 'rx-theme' ),
				'priority'    => 30,
			)
		);

		$sections = array(
			'rx_color_global_section' => array(
				'title'       => __( 'Global Brand Colors', 'rx-theme' ),
				'description' => __( 'Primary, secondary, accent, and base brand colors.', 'rx-theme' ),
				'priority'    => 10,
			),
			'rx_color_text_section' => array(
				'title'       => __( 'Body and Text Colors', 'rx-theme' ),
				'description' => __( 'Background, headings, paragraph, muted text, and selection colors.', 'rx-theme' ),
				'priority'    => 20,
			),
			'rx_color_link_section' => array(
				'title'       => __( 'Link Colors', 'rx-theme' ),
				'description' => __( 'Normal, hover, visited, and underline link colors.', 'rx-theme' ),
				'priority'    => 30,
			),
			'rx_color_header_section' => array(
				'title'       => __( 'Header Colors', 'rx-theme' ),
				'description' => __( 'Header, top bar, border, and header link colors.', 'rx-theme' ),
				'priority'    => 40,
			),
			'rx_color_nav_section' => array(
				'title'       => __( 'Navigation Colors', 'rx-theme' ),
				'description' => __( 'Menu, active menu, dropdown, and hover colors.', 'rx-theme' ),
				'priority'    => 50,
			),
			'rx_color_footer_section' => array(
				'title'       => __( 'Footer Colors', 'rx-theme' ),
				'description' => __( 'Footer background, text, headings, links, and bottom bar.', 'rx-theme' ),
				'priority'    => 60,
			),
			'rx_color_button_section' => array(
				'title'       => __( 'Button Colors', 'rx-theme' ),
				'description' => __( 'Primary, secondary, and outline button colors.', 'rx-theme' ),
				'priority'    => 70,
			),
			'rx_color_content_section' => array(
				'title'       => __( 'Cards, Boxes, Sidebar and Widgets', 'rx-theme' ),
				'description' => __( 'Content containers, cards, sidebar, and widget colors.', 'rx-theme' ),
				'priority'    => 80,
			),
			'rx_color_form_section' => array(
				'title'       => __( 'Form Colors', 'rx-theme' ),
				'description' => __( 'Input, textarea, select, placeholder, border, and focus colors.', 'rx-theme' ),
				'priority'    => 90,
			),
			'rx_color_table_section' => array(
				'title'       => __( 'Table Colors', 'rx-theme' ),
				'description' => __( 'Table header, border, stripe, and hover colors.', 'rx-theme' ),
				'priority'    => 100,
			),
			'rx_color_status_section' => array(
				'title'       => __( 'Status and Medical Colors', 'rx-theme' ),
				'description' => __( 'Success, warning, danger, info, and medical brand colors.', 'rx-theme' ),
				'priority'    => 110,
			),
			'rx_color_extra_section' => array(
				'title'       => __( 'Breadcrumb, Pagination and Code Colors', 'rx-theme' ),
				'description' => __( 'Breadcrumb, pagination, inline code, and code block colors.', 'rx-theme' ),
				'priority'    => 120,
			),
			'rx_color_gradient_section' => array(
				'title'       => __( 'Gradient Colors', 'rx-theme' ),
				'description' => __( 'Hero, primary, secondary, and accent gradient colors.', 'rx-theme' ),
				'priority'    => 130,
			),
			'rx_color_dark_section' => array(
				'title'       => __( 'Dark Mode Colors', 'rx-theme' ),
				'description' => __( 'Dark mode and system dark mode color settings.', 'rx-theme' ),
				'priority'    => 140,
			),
			'rx_color_advanced_section' => array(
				'title'       => __( 'Advanced Color Controls', 'rx-theme' ),
				'description' => __( 'Color presets, CSS variables, and editor palette options.', 'rx-theme' ),
				'priority'    => 150,
			),
		);

		foreach ( $sections as $section_id => $section ) {
			$wp_customize->add_section(
				$section_id,
				array(
					'title'       => $section['title'],
					'description' => $section['description'],
					'panel'       => 'rx_color_panel',
					'priority'    => $section['priority'],
				)
			);
		}

		$defaults = self::defaults();
		$fields   = $this->color_fields();

		foreach ( $fields as $key => $label ) {
			$section = $this->get_section_for_color_key( $key );

			$wp_customize->add_setting(
				self::PREFIX . $key,
				array(
					'default'           => isset( $defaults[ $key ] ) ? $defaults[ $key ] : '',
					'type'              => 'theme_mod',
					'sanitize_callback' => array( $this, 'sanitize_color_value' ),
					'transport'         => 'postMessage',
				)
			);

			$wp_customize->add_control(
				new WP_Customize_Color_Control(
					$wp_customize,
					self::PREFIX . $key,
					array(
						'label'       => $label,
						'section'     => $section,
						'settings'    => self::PREFIX . $key,
						'description' => sprintf(
							/* translators: %s: color option key */
							__( 'CSS variable: --rx-%s', 'rx-theme' ),
							esc_html( str_replace( '_', '-', $key ) )
						),
					)
				)
			);
		}

		/*
		|--------------------------------------------------------------------------
		| Preset selector
		|--------------------------------------------------------------------------
		*/
		$wp_customize->add_setting(
			self::PREFIX . 'color_preset',
			array(
				'default'           => $defaults['color_preset'],
				'type'              => 'theme_mod',
				'sanitize_callback' => array( $this, 'sanitize_color_preset' ),
				'transport'         => 'refresh',
			)
		);

		$wp_customize->add_control(
			self::PREFIX . 'color_preset',
			array(
				'label'       => __( 'Color Preset', 'rx-theme' ),
				'description' => __( 'Choose a starter color style. Individual color settings can still override it.', 'rx-theme' ),
				'section'     => 'rx_color_advanced_section',
				'type'        => 'select',
				'choices'     => $this->color_preset_choices(),
			)
		);

		/*
		|--------------------------------------------------------------------------
		| Boolean toggles
		|--------------------------------------------------------------------------
		*/
		$boolean_controls = array(
			'enable_dark_mode' => array(
				'label'       => __( 'Enable Manual Dark Mode Class Support', 'rx-theme' ),
				'description' => __( 'Adds support for body.rx-dark-mode or html.rx-dark-mode.', 'rx-theme' ),
				'section'     => 'rx_color_dark_section',
			),
			'enable_system_dark_mode' => array(
				'label'       => __( 'Enable System Dark Mode', 'rx-theme' ),
				'description' => __( 'Uses dark colors when the visitor device prefers dark mode.', 'rx-theme' ),
				'section'     => 'rx_color_dark_section',
			),
			'enable_color_css_variables' => array(
				'label'       => __( 'Enable CSS Color Variables', 'rx-theme' ),
				'description' => __( 'Outputs global --rx-* CSS variables in the front end.', 'rx-theme' ),
				'section'     => 'rx_color_advanced_section',
			),
			'enable_editor_palette' => array(
				'label'       => __( 'Enable Block Editor Color Palette', 'rx-theme' ),
				'description' => __( 'Registers the RX color palette inside Gutenberg editor.', 'rx-theme' ),
				'section'     => 'rx_color_advanced_section',
			),
		);

		foreach ( $boolean_controls as $key => $control ) {
			$wp_customize->add_setting(
				self::PREFIX . $key,
				array(
					'default'           => isset( $defaults[ $key ] ) ? $defaults[ $key ] : false,
					'type'              => 'theme_mod',
					'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
					'transport'         => 'refresh',
				)
			);

			$wp_customize->add_control(
				self::PREFIX . $key,
				array(
					'label'       => $control['label'],
					'description' => $control['description'],
					'section'     => $control['section'],
					'type'        => 'checkbox',
				)
			);
		}
	}

	/**
	 * Decide which Customizer section a color belongs to.
	 *
	 * @param string $key Color key.
	 * @return string
	 */
	private function get_section_for_color_key( $key ) {
		if ( 0 === strpos( $key, 'gradient_' ) ) {
			return 'rx_color_gradient_section';
		}

		if ( 0 === strpos( $key, 'dark_' ) ) {
			return 'rx_color_dark_section';
		}

		if (
			false !== strpos( $key, 'primary' ) ||
			false !== strpos( $key, 'secondary' ) ||
			false !== strpos( $key, 'accent' )
		) {
			return 'rx_color_global_section';
		}

		if (
			false !== strpos( $key, 'body' ) ||
			false !== strpos( $key, 'heading' ) ||
			false !== strpos( $key, 'paragraph' ) ||
			false !== strpos( $key, 'selection' )
		) {
			return 'rx_color_text_section';
		}

		if ( false !== strpos( $key, 'link' ) && false === strpos( $key, 'header' ) && false === strpos( $key, 'footer' ) && false === strpos( $key, 'sidebar' ) ) {
			return 'rx_color_link_section';
		}

		if ( false !== strpos( $key, 'header' ) ) {
			return 'rx_color_header_section';
		}

		if ( false !== strpos( $key, 'nav' ) || false !== strpos( $key, 'dropdown' ) ) {
			return 'rx_color_nav_section';
		}

		if ( false !== strpos( $key, 'footer' ) ) {
			return 'rx_color_footer_section';
		}

		if ( false !== strpos( $key, 'button' ) ) {
			return 'rx_color_button_section';
		}

		if (
			false !== strpos( $key, 'card' ) ||
			false !== strpos( $key, 'box' ) ||
			false !== strpos( $key, 'sidebar' ) ||
			false !== strpos( $key, 'widget' )
		) {
			return 'rx_color_content_section';
		}

		if (
			false !== strpos( $key, 'input' ) ||
			false !== strpos( $key, 'placeholder' ) ||
			false !== strpos( $key, 'label' )
		) {
			return 'rx_color_form_section';
		}

		if ( false !== strpos( $key, 'table' ) ) {
			return 'rx_color_table_section';
		}

		if (
			false !== strpos( $key, 'success' ) ||
			false !== strpos( $key, 'warning' ) ||
			false !== strpos( $key, 'danger' ) ||
			false !== strpos( $key, 'info' ) ||
			false !== strpos( $key, 'medical' )
		) {
			return 'rx_color_status_section';
		}

		return 'rx_color_extra_section';
	}

	/**
	 * Color preset choices.
	 *
	 * @return array
	 */
	private function color_preset_choices() {
		return array(
			'default'       => __( 'Default Blue Medical', 'rx-theme' ),
			'green_health'  => __( 'Green Health', 'rx-theme' ),
			'purple_care'   => __( 'Purple Care', 'rx-theme' ),
			'red_emergency' => __( 'Red Emergency', 'rx-theme' ),
			'dark_clinic'   => __( 'Dark Clinic', 'rx-theme' ),
			'soft_clean'    => __( 'Soft Clean', 'rx-theme' ),
		);
	}

	/**
	 * Preset color values.
	 *
	 * @return array
	 */
	public static function presets() {
		return array(
			'default' => array(
				'color_primary'         => '#2563eb',
				'color_secondary'       => '#0f766e',
				'color_accent'          => '#f97316',
				'color_body_bg'         => '#ffffff',
				'color_heading'         => '#0f172a',
			),
			'green_health' => array(
				'color_primary'         => '#059669',
				'color_primary_hover'   => '#047857',
				'color_primary_light'   => '#d1fae5',
				'color_secondary'       => '#0284c7',
				'color_accent'          => '#84cc16',
				'color_link'            => '#059669',
				'color_button_bg'       => '#059669',
				'color_button_hover_bg' => '#047857',
			),
			'purple_care' => array(
				'color_primary'         => '#7c3aed',
				'color_primary_hover'   => '#6d28d9',
				'color_primary_light'   => '#ede9fe',
				'color_secondary'       => '#2563eb',
				'color_accent'          => '#ec4899',
				'color_link'            => '#7c3aed',
				'color_button_bg'       => '#7c3aed',
				'color_button_hover_bg' => '#6d28d9',
			),
			'red_emergency' => array(
				'color_primary'         => '#dc2626',
				'color_primary_hover'   => '#b91c1c',
				'color_primary_light'   => '#fee2e2',
				'color_secondary'       => '#0f766e',
				'color_accent'          => '#f97316',
				'color_link'            => '#dc2626',
				'color_button_bg'       => '#dc2626',
				'color_button_hover_bg' => '#b91c1c',
			),
			'dark_clinic' => array(
				'color_primary'         => '#38bdf8',
				'color_primary_hover'   => '#0ea5e9',
				'color_body_bg'         => '#020617',
				'color_body_text'       => '#e5e7eb',
				'color_heading'         => '#ffffff',
				'color_card_bg'         => '#0f172a',
				'color_card_border'     => '#1e293b',
				'color_header_bg'       => '#020617',
				'color_footer_bg'       => '#020617',
			),
			'soft_clean' => array(
				'color_primary'         => '#0284c7',
				'color_primary_hover'   => '#0369a1',
				'color_primary_light'   => '#e0f2fe',
				'color_secondary'       => '#14b8a6',
				'color_accent'          => '#f59e0b',
				'color_body_bg'         => '#f8fafc',
				'color_card_bg'         => '#ffffff',
				'color_box_bg'          => '#f1f5f9',
			),
		);
	}

	/**
	 * Get theme mod with default and preset support.
	 *
	 * @param string $key Color key.
	 * @return mixed
	 */
	public static function get_option( $key ) {
		$defaults = self::defaults();
		$preset   = get_theme_mod( self::PREFIX . 'color_preset', $defaults['color_preset'] );
		$presets  = self::presets();

		$default_value = isset( $defaults[ $key ] ) ? $defaults[ $key ] : '';

		if ( isset( $presets[ $preset ][ $key ] ) ) {
			$default_value = $presets[ $preset ][ $key ];
		}

		return get_theme_mod( self::PREFIX . $key, $default_value );
	}

	/**
	 * Sanitize normal hex, rgba, transparent, or CSS-safe color.
	 *
	 * @param string $value Color value.
	 * @return string
	 */
	public function sanitize_color_value( $value ) {
		$value = trim( (string) $value );

		if ( '' === $value ) {
			return '';
		}

		if ( 'transparent' === strtolower( $value ) ) {
			return 'transparent';
		}

		if ( false !== strpos( $value, 'rgba' ) || false !== strpos( $value, 'rgb' ) ) {
			return $this->sanitize_rgb_or_rgba( $value );
		}

		$hex = sanitize_hex_color( $value );

		if ( $hex ) {
			return $hex;
		}

		return '';
	}

	/**
	 * Sanitize RGB or RGBA color value.
	 *
	 * @param string $value RGB/RGBA value.
	 * @return string
	 */
	private function sanitize_rgb_or_rgba( $value ) {
		$value = preg_replace( '/\s+/', '', $value );

		if ( preg_match( '/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/', $value, $matches ) ) {
			$r = min( 255, max( 0, absint( $matches[1] ) ) );
			$g = min( 255, max( 0, absint( $matches[2] ) ) );
			$b = min( 255, max( 0, absint( $matches[3] ) ) );

			return "rgb({$r}, {$g}, {$b})";
		}

		if ( preg_match( '/^rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),([0-9.]+)\)$/', $value, $matches ) ) {
			$r = min( 255, max( 0, absint( $matches[1] ) ) );
			$g = min( 255, max( 0, absint( $matches[2] ) ) );
			$b = min( 255, max( 0, absint( $matches[3] ) ) );
			$a = min( 1, max( 0, (float) $matches[4] ) );

			return "rgba({$r}, {$g}, {$b}, {$a})";
		}

		return '';
	}

	/**
	 * Sanitize checkbox.
	 *
	 * @param mixed $checked Checked value.
	 * @return bool
	 */
	public function sanitize_checkbox( $checked ) {
		return (bool) $checked;
	}

	/**
	 * Sanitize color preset.
	 *
	 * @param string $value Preset.
	 * @return string
	 */
	public function sanitize_color_preset( $value ) {
		$choices = $this->color_preset_choices();

		return isset( $choices[ $value ] ) ? $value : 'default';
	}

	/**
	 * Convert option key to CSS variable name.
	 *
	 * @param string $key Option key.
	 * @return string
	 */
	private static function css_var_name( $key ) {
		return '--rx-' . str_replace( '_', '-', $key );
	}

	/**
	 * Build CSS variable declarations.
	 *
	 * @return string
	 */
	public static function build_css_variables() {
		$defaults = self::defaults();
		$css      = '';

		foreach ( $defaults as $key => $default ) {
			if ( 0 === strpos( $key, 'enable_' ) || 'color_preset' === $key ) {
				continue;
			}

			$value = self::get_option( $key );

			if ( '' === $value ) {
				continue;
			}

			$css .= sprintf(
				"%s:%s;\n",
				esc_html( self::css_var_name( $key ) ),
				esc_html( $value )
			);
		}

		$css .= "--rx-gradient-primary:linear-gradient(135deg,var(--rx-gradient-primary-start),var(--rx-gradient-primary-end));\n";
		$css .= "--rx-gradient-secondary:linear-gradient(135deg,var(--rx-gradient-secondary-start),var(--rx-gradient-secondary-end));\n";
		$css .= "--rx-gradient-accent:linear-gradient(135deg,var(--rx-gradient-accent-start),var(--rx-gradient-accent-end));\n";
		$css .= "--rx-gradient-hero:linear-gradient(135deg,var(--rx-gradient-hero-start),var(--rx-gradient-hero-end));\n";

		return $css;
	}

	/**
	 * Build front-end dynamic CSS.
	 *
	 * @return string
	 */
	public static function build_dynamic_css() {
		$enable_vars        = self::get_option( 'enable_color_css_variables' );
		$enable_dark        = self::get_option( 'enable_dark_mode' );
		$enable_system_dark = self::get_option( 'enable_system_dark_mode' );

		$css = '';

		if ( $enable_vars ) {
			$css .= ":root{\n";
			$css .= self::build_css_variables();
			$css .= "}\n";
		}

		$css .= "
html {
	color-scheme: light;
}

body {
	background: var(--rx-color-body-bg);
	color: var(--rx-color-body-text);
}

::selection {
	background: var(--rx-color-selection-bg);
	color: var(--rx-color-selection-text);
}

h1, h2, h3, h4, h5, h6,
.entry-title,
.page-title,
.site-title {
	color: var(--rx-color-heading);
}

p,
.entry-content,
.site-content {
	color: var(--rx-color-paragraph);
}

a {
	color: var(--rx-color-link);
	text-decoration-color: var(--rx-color-link-underline);
}

a:hover,
a:focus {
	color: var(--rx-color-link-hover);
}

a:visited {
	color: var(--rx-color-link-visited);
}

.site-header,
.rx-header {
	background: var(--rx-color-header-bg);
	color: var(--rx-color-header-text);
	border-bottom-color: var(--rx-color-header-border);
}

.site-header a,
.rx-header a {
	color: var(--rx-color-header-link);
}

.site-header a:hover,
.site-header a:focus,
.rx-header a:hover,
.rx-header a:focus {
	color: var(--rx-color-header-link-hover);
}

.rx-top-bar {
	background: var(--rx-color-header-top-bg);
	color: var(--rx-color-header-top-text);
}

.main-navigation,
.rx-navigation,
.rx-menu {
	background: var(--rx-color-nav-bg);
}

.main-navigation a,
.rx-navigation a,
.rx-menu a {
	color: var(--rx-color-nav-link);
}

.main-navigation a:hover,
.main-navigation a:focus,
.rx-navigation a:hover,
.rx-navigation a:focus,
.rx-menu a:hover,
.rx-menu a:focus,
.current-menu-item > a,
.current_page_item > a {
	color: var(--rx-color-nav-active);
}

.main-navigation ul ul,
.rx-navigation ul ul,
.rx-menu ul ul {
	background: var(--rx-color-nav-dropdown-bg);
	color: var(--rx-color-nav-dropdown-text);
}

.main-navigation ul ul a:hover,
.rx-navigation ul ul a:hover,
.rx-menu ul ul a:hover {
	background: var(--rx-color-nav-dropdown-hover);
}

.site-footer,
.rx-footer {
	background: var(--rx-color-footer-bg);
	color: var(--rx-color-footer-text);
	border-top-color: var(--rx-color-footer-border);
}

.site-footer h1,
.site-footer h2,
.site-footer h3,
.site-footer h4,
.rx-footer h1,
.rx-footer h2,
.rx-footer h3,
.rx-footer h4 {
	color: var(--rx-color-footer-heading);
}

.site-footer a,
.rx-footer a {
	color: var(--rx-color-footer-link);
}

.site-footer a:hover,
.site-footer a:focus,
.rx-footer a:hover,
.rx-footer a:focus {
	color: var(--rx-color-footer-link-hover);
}

.rx-footer-bottom {
	background: var(--rx-color-footer-bottom-bg);
	color: var(--rx-color-footer-bottom-text);
}

button,
input[type='button'],
input[type='submit'],
input[type='reset'],
.wp-block-button__link,
.rx-btn,
.button {
	background: var(--rx-color-button-bg);
	color: var(--rx-color-button-text);
	border-color: var(--rx-color-button-border);
}

button:hover,
button:focus,
input[type='button']:hover,
input[type='button']:focus,
input[type='submit']:hover,
input[type='submit']:focus,
input[type='reset']:hover,
input[type='reset']:focus,
.wp-block-button__link:hover,
.wp-block-button__link:focus,
.rx-btn:hover,
.rx-btn:focus,
.button:hover,
.button:focus {
	background: var(--rx-color-button-hover-bg);
	color: var(--rx-color-button-hover-text);
}

.rx-btn-secondary {
	background: var(--rx-color-button-secondary-bg);
	color: var(--rx-color-button-secondary-text);
}

.rx-btn-secondary:hover,
.rx-btn-secondary:focus {
	background: var(--rx-color-button-secondary-hover-bg);
	color: var(--rx-color-button-secondary-hover-text);
}

.rx-btn-outline {
	background: transparent;
	color: var(--rx-color-button-outline-text);
	border-color: var(--rx-color-button-outline-border);
}

.rx-btn-outline:hover,
.rx-btn-outline:focus {
	background: var(--rx-color-button-outline-hover-bg);
	color: var(--rx-color-button-outline-hover-text);
}

.card,
.rx-card,
.post-card,
.wp-block-group.is-style-card {
	background: var(--rx-color-card-bg);
	color: var(--rx-color-card-text);
	border-color: var(--rx-color-card-border);
	box-shadow: 0 10px 30px var(--rx-color-card-shadow);
}

.rx-box,
.rx-highlight-box,
.wp-block-group.is-style-rx-box {
	background: var(--rx-color-box-bg);
	border-color: var(--rx-color-box-border);
}

.sidebar,
.rx-sidebar {
	background: var(--rx-color-sidebar-bg);
	color: var(--rx-color-sidebar-text);
}

.sidebar h1,
.sidebar h2,
.sidebar h3,
.sidebar h4,
.sidebar .widget-title,
.rx-sidebar h1,
.rx-sidebar h2,
.rx-sidebar h3,
.rx-sidebar h4,
.rx-sidebar .widget-title {
	color: var(--rx-color-sidebar-heading);
}

.sidebar a,
.rx-sidebar a {
	color: var(--rx-color-sidebar-link);
}

.sidebar a:hover,
.rx-sidebar a:hover {
	color: var(--rx-color-sidebar-link-hover);
}

.widget,
.rx-widget {
	background: var(--rx-color-widget-bg);
	border-color: var(--rx-color-widget-border);
}

input,
textarea,
select {
	background: var(--rx-color-input-bg);
	color: var(--rx-color-input-text);
	border-color: var(--rx-color-input-border);
}

input::placeholder,
textarea::placeholder {
	color: var(--rx-color-input-placeholder);
}

input:focus,
textarea:focus,
select:focus {
	border-color: var(--rx-color-input-focus-border);
	box-shadow: 0 0 0 3px var(--rx-color-input-focus-shadow);
	outline: none;
}

label {
	color: var(--rx-color-label-text);
}

table,
.wp-block-table table {
	border-color: var(--rx-color-table-border);
}

thead,
.wp-block-table thead {
	background: var(--rx-color-table-header-bg);
	color: var(--rx-color-table-header-text);
}

td,
th {
	border-color: var(--rx-color-table-border);
}

tbody tr:nth-child(even) {
	background: var(--rx-color-table-stripe-bg);
}

tbody tr:hover {
	background: var(--rx-color-table-hover-bg);
}

.rx-alert-success {
	color: var(--rx-color-success);
	background: var(--rx-color-success-bg);
}

.rx-alert-warning {
	color: var(--rx-color-warning);
	background: var(--rx-color-warning-bg);
}

.rx-alert-danger {
	color: var(--rx-color-danger);
	background: var(--rx-color-danger-bg);
}

.rx-alert-info {
	color: var(--rx-color-info);
	background: var(--rx-color-info-bg);
}

.rx-medical-box {
	background: var(--rx-color-medical-soft-bg);
	border-left-color: var(--rx-color-medical-blue);
}

.rx-medical-blue {
	color: var(--rx-color-medical-blue);
}

.rx-medical-green {
	color: var(--rx-color-medical-green);
}

.rx-medical-red {
	color: var(--rx-color-medical-red);
}

.rx-medical-purple {
	color: var(--rx-color-medical-purple);
}

.breadcrumb,
.rx-breadcrumb {
	color: var(--rx-color-breadcrumb-text);
}

.breadcrumb a,
.rx-breadcrumb a {
	color: var(--rx-color-breadcrumb-link);
}

.pagination a,
.pagination span,
.nav-links a,
.nav-links span,
.page-numbers {
	background: var(--rx-color-pagination-bg);
	color: var(--rx-color-pagination-text);
	border-color: var(--rx-color-pagination-border);
}

.pagination .current,
.nav-links .current,
.page-numbers.current {
	background: var(--rx-color-pagination-active-bg);
	color: var(--rx-color-pagination-active-text);
}

code,
kbd,
tt,
var {
	background: var(--rx-color-code-bg);
	color: var(--rx-color-code-text);
}

pre {
	background: var(--rx-color-pre-bg);
	color: var(--rx-color-pre-text);
}

.rx-gradient-primary {
	background: var(--rx-gradient-primary);
}

.rx-gradient-secondary {
	background: var(--rx-gradient-secondary);
}

.rx-gradient-accent {
	background: var(--rx-gradient-accent);
}

.rx-hero,
.rx-gradient-hero {
	background: var(--rx-gradient-hero);
}

.has-rx-primary-color {
	color: var(--rx-color-primary) !important;
}

.has-rx-primary-background-color {
	background-color: var(--rx-color-primary) !important;
}

.has-rx-secondary-color {
	color: var(--rx-color-secondary) !important;
}

.has-rx-secondary-background-color {
	background-color: var(--rx-color-secondary) !important;
}

.has-rx-accent-color {
	color: var(--rx-color-accent) !important;
}

.has-rx-accent-background-color {
	background-color: var(--rx-color-accent) !important;
}
";

		if ( $enable_dark ) {
			$css .= "
html.rx-dark-mode,
body.rx-dark-mode {
	color-scheme: dark;
	--rx-color-body-bg: var(--rx-dark-color-body-bg);
	--rx-color-body-text: var(--rx-dark-color-body-text);
	--rx-color-heading: var(--rx-dark-color-heading);
	--rx-color-paragraph: var(--rx-dark-color-paragraph);
	--rx-color-card-bg: var(--rx-dark-color-card-bg);
	--rx-color-card-border: var(--rx-dark-color-card-border);
	--rx-color-header-bg: var(--rx-dark-color-header-bg);
	--rx-color-header-text: var(--rx-dark-color-header-text);
	--rx-color-footer-bg: var(--rx-dark-color-footer-bg);
	--rx-color-footer-text: var(--rx-dark-color-footer-text);
	--rx-color-input-bg: var(--rx-dark-color-input-bg);
	--rx-color-input-text: var(--rx-dark-color-input-text);
	--rx-color-input-border: var(--rx-dark-color-input-border);
}
";
		}

		if ( $enable_system_dark ) {
			$css .= "
@media (prefers-color-scheme: dark) {
	html:not(.rx-light-mode) {
		color-scheme: dark;
		--rx-color-body-bg: var(--rx-dark-color-body-bg);
		--rx-color-body-text: var(--rx-dark-color-body-text);
		--rx-color-heading: var(--rx-dark-color-heading);
		--rx-color-paragraph: var(--rx-dark-color-paragraph);
		--rx-color-card-bg: var(--rx-dark-color-card-bg);
		--rx-color-card-border: var(--rx-dark-color-card-border);
		--rx-color-header-bg: var(--rx-dark-color-header-bg);
		--rx-color-header-text: var(--rx-dark-color-header-text);
		--rx-color-footer-bg: var(--rx-dark-color-footer-bg);
		--rx-color-footer-text: var(--rx-dark-color-footer-text);
		--rx-color-input-bg: var(--rx-dark-color-input-bg);
		--rx-color-input-text: var(--rx-dark-color-input-text);
		--rx-color-input-border: var(--rx-dark-color-input-border);
	}
}
";
		}

		return trim( $css );
	}

	/**
	 * Enqueue dynamic CSS on frontend.
	 *
	 * @return void
	 */
	public function enqueue_dynamic_colors() {
		$handle = 'rx-theme-style';

		if ( ! wp_style_is( $handle, 'enqueued' ) ) {
			wp_register_style( 'rx-color-options', false, array(), wp_get_theme()->get( 'Version' ) );
			wp_enqueue_style( 'rx-color-options' );
			$handle = 'rx-color-options';
		}

		wp_add_inline_style( $handle, self::build_dynamic_css() );
	}

	/**
	 * Enqueue dynamic CSS inside block editor.
	 *
	 * @return void
	 */
	public function enqueue_editor_dynamic_colors() {
		wp_register_style( 'rx-editor-color-options', false, array(), wp_get_theme()->get( 'Version' ) );
		wp_enqueue_style( 'rx-editor-color-options' );

		$css = "
.editor-styles-wrapper {
	background: var(--rx-color-body-bg);
	color: var(--rx-color-body-text);
}
.editor-styles-wrapper h1,
.editor-styles-wrapper h2,
.editor-styles-wrapper h3,
.editor-styles-wrapper h4,
.editor-styles-wrapper h5,
.editor-styles-wrapper h6 {
	color: var(--rx-color-heading);
}
" . self::build_dynamic_css();

		wp_add_inline_style( 'rx-editor-color-options', $css );
	}

	/**
	 * Register Gutenberg editor color palette.
	 *
	 * @return void
	 */
	public function register_editor_color_palette() {
		if ( ! self::get_option( 'enable_editor_palette' ) ) {
			return;
		}

		add_theme_support(
			'editor-color-palette',
			array(
				array(
					'name'  => __( 'RX Primary', 'rx-theme' ),
					'slug'  => 'rx-primary',
					'color' => self::get_option( 'color_primary' ),
				),
				array(
					'name'  => __( 'RX Secondary', 'rx-theme' ),
					'slug'  => 'rx-secondary',
					'color' => self::get_option( 'color_secondary' ),
				),
				array(
					'name'  => __( 'RX Accent', 'rx-theme' ),
					'slug'  => 'rx-accent',
					'color' => self::get_option( 'color_accent' ),
				),
				array(
					'name'  => __( 'RX Heading', 'rx-theme' ),
					'slug'  => 'rx-heading',
					'color' => self::get_option( 'color_heading' ),
				),
				array(
					'name'  => __( 'RX Text', 'rx-theme' ),
					'slug'  => 'rx-text',
					'color' => self::get_option( 'color_body_text' ),
				),
				array(
					'name'  => __( 'RX Muted', 'rx-theme' ),
					'slug'  => 'rx-muted',
					'color' => self::get_option( 'color_body_text_muted' ),
				),
				array(
					'name'  => __( 'RX Medical Blue', 'rx-theme' ),
					'slug'  => 'rx-medical-blue',
					'color' => self::get_option( 'color_medical_blue' ),
				),
				array(
					'name'  => __( 'RX Medical Green', 'rx-theme' ),
					'slug'  => 'rx-medical-green',
					'color' => self::get_option( 'color_medical_green' ),
				),
				array(
					'name'  => __( 'RX Medical Red', 'rx-theme' ),
					'slug'  => 'rx-medical-red',
					'color' => self::get_option( 'color_medical_red' ),
				),
				array(
					'name'  => __( 'RX Light Background', 'rx-theme' ),
					'slug'  => 'rx-light-bg',
					'color' => self::get_option( 'color_box_bg' ),
				),
			)
		);

		add_theme_support(
			'editor-gradient-presets',
			array(
				array(
					'name'     => __( 'RX Primary Gradient', 'rx-theme' ),
					'gradient' => sprintf(
						'linear-gradient(135deg, %s, %s)',
						self::get_option( 'gradient_primary_start' ),
						self::get_option( 'gradient_primary_end' )
					),
					'slug'     => 'rx-primary-gradient',
				),
				array(
					'name'     => __( 'RX Secondary Gradient', 'rx-theme' ),
					'gradient' => sprintf(
						'linear-gradient(135deg, %s, %s)',
						self::get_option( 'gradient_secondary_start' ),
						self::get_option( 'gradient_secondary_end' )
					),
					'slug'     => 'rx-secondary-gradient',
				),
				array(
					'name'     => __( 'RX Accent Gradient', 'rx-theme' ),
					'gradient' => sprintf(
						'linear-gradient(135deg, %s, %s)',
						self::get_option( 'gradient_accent_start' ),
						self::get_option( 'gradient_accent_end' )
					),
					'slug'     => 'rx-accent-gradient',
				),
			)
		);
	}

	/**
	 * Customizer live preview JS.
	 *
	 * @return void
	 */
	public function customizer_live_preview() {
		wp_enqueue_script(
			'rx-color-customizer-preview',
			get_template_directory_uri() . '/assets/js/customizer-color-preview.js',
			array( 'customize-preview' ),
			wp_get_theme()->get( 'Version' ),
			true
		);
	}

	/**
	 * Print browser color-scheme meta.
	 *
	 * @return void
	 */
	public function print_color_scheme_meta() {
		$enable_system_dark = self::get_option( 'enable_system_dark_mode' );

		if ( $enable_system_dark ) {
			echo '<meta name="color-scheme" content="light dark">' . "\n";
		} else {
			echo '<meta name="color-scheme" content="light">' . "\n";
		}

		$theme_color = self::get_option( 'color_primary' );

		if ( $theme_color ) {
			printf(
				'<meta name="theme-color" content="%s">' . "\n",
				esc_attr( $theme_color )
			);
		}
	}
endif;

/**
 * Initialize RX color options.
 */
if ( class_exists( 'RX_Color_Options' ) ) {
	new RX_Color_Options();
}

/**
 * Helper function: get RX color option.
 *
 * Usage:
 * rx_get_color_option( 'color_primary' );
 *
 * @param string $key Color option key.
 * @return mixed
 */
if ( ! function_exists( 'rx_get_color_option' ) ) {
	function rx_get_color_option( $key ) {
		if ( class_exists( 'RX_Color_Options' ) ) {
			return RX_Color_Options::get_option( $key );
		}

		return '';
	}
}

/**
 * Helper function: output inline style color.
 *
 * Usage:
 * echo rx_color_style( 'color_primary', 'color' );
 *
 * @param string $key      Color key.
 * @param string $property CSS property.
 * @return string
 */
if ( ! function_exists( 'rx_color_style' ) ) {
	function rx_color_style( $key, $property = 'color' ) {
		$value = rx_get_color_option( $key );

		if ( ! $value ) {
			return '';
		}

		return sprintf(
			'%s:%s;',
			esc_attr( $property ),
			esc_attr( $value )
		);
	}
}

/**
 * Helper function: return CSS variable.
 *
 * Usage:
 * color: <?php echo esc_attr( rx_css_var( 'color_primary' ) ); ?>;
 *
 * @param string $key Color key.
 * @return string
 */
if ( ! function_exists( 'rx_css_var' ) ) {
	function rx_css_var( $key ) {
		return 'var(--rx-' . str_replace( '_', '-', sanitize_key( $key ) ) . ')';
	}
}

Now include it inside your theme functions.php:

/**
 * RX Theme Color Options
 */
require_once get_template_directory() . '/inc/options/color-options.php';

Optional live preview JS file:

Create:

mkdir -p assets/js
touch assets/js/customizer-color-preview.js

Paste this:

(function ($) {
	'use strict';

	const rxColorMap = {
		rx_color_primary: '--rx-color-primary',
		rx_color_primary_hover: '--rx-color-primary-hover',
		rx_color_primary_light: '--rx-color-primary-light',
		rx_color_primary_dark: '--rx-color-primary-dark',

		rx_color_secondary: '--rx-color-secondary',
		rx_color_secondary_hover: '--rx-color-secondary-hover',
		rx_color_secondary_light: '--rx-color-secondary-light',
		rx_color_secondary_dark: '--rx-color-secondary-dark',

		rx_color_accent: '--rx-color-accent',
		rx_color_accent_hover: '--rx-color-accent-hover',
		rx_color_accent_light: '--rx-color-accent-light',
		rx_color_accent_dark: '--rx-color-accent-dark',

		rx_color_body_bg: '--rx-color-body-bg',
		rx_color_body_text: '--rx-color-body-text',
		rx_color_body_text_muted: '--rx-color-body-text-muted',
		rx_color_heading: '--rx-color-heading',
		rx_color_paragraph: '--rx-color-paragraph',

		rx_color_link: '--rx-color-link',
		rx_color_link_hover: '--rx-color-link-hover',
		rx_color_link_visited: '--rx-color-link-visited',
		rx_color_link_underline: '--rx-color-link-underline',

		rx_color_header_bg: '--rx-color-header-bg',
		rx_color_header_text: '--rx-color-header-text',
		rx_color_header_link: '--rx-color-header-link',
		rx_color_header_link_hover: '--rx-color-header-link-hover',
		rx_color_header_border: '--rx-color-header-border',

		rx_color_footer_bg: '--rx-color-footer-bg',
		rx_color_footer_text: '--rx-color-footer-text',
		rx_color_footer_heading: '--rx-color-footer-heading',
		rx_color_footer_link: '--rx-color-footer-link',
		rx_color_footer_link_hover: '--rx-color-footer-link-hover',

		rx_color_button_bg: '--rx-color-button-bg',
		rx_color_button_text: '--rx-color-button-text',
		rx_color_button_hover_bg: '--rx-color-button-hover-bg',
		rx_color_button_hover_text: '--rx-color-button-hover-text',

		rx_color_card_bg: '--rx-color-card-bg',
		rx_color_card_text: '--rx-color-card-text',
		rx_color_card_border: '--rx-color-card-border',

		rx_color_input_bg: '--rx-color-input-bg',
		rx_color_input_text: '--rx-color-input-text',
		rx_color_input_border: '--rx-color-input-border',
		rx_color_input_focus_border: '--rx-color-input-focus-border',

		rx_gradient_primary_start: '--rx-gradient-primary-start',
		rx_gradient_primary_end: '--rx-gradient-primary-end',
		rx_gradient_secondary_start: '--rx-gradient-secondary-start',
		rx_gradient_secondary_end: '--rx-gradient-secondary-end',
		rx_gradient_accent_start: '--rx-gradient-accent-start',
		rx_gradient_accent_end: '--rx-gradient-accent-end',
		rx_gradient_hero_start: '--rx-gradient-hero-start',
		rx_gradient_hero_end: '--rx-gradient-hero-end'
	};

	Object.keys(rxColorMap).forEach(function (settingKey) {
		wp.customize(settingKey, function (value) {
			value.bind(function (newColor) {
				document.documentElement.style.setProperty(rxColorMap[settingKey], newColor);
			});
		});
	});

})(jQuery);

Use these CSS variables anywhere in your theme:

.example-box {
	background: var(--rx-color-card-bg);
	color: var(--rx-color-card-text);
	border: 1px solid var(--rx-color-card-border);
}

.example-button {
	background: var(--rx-color-primary);
	color: #fff;
}

.example-hero {
	background: var(--rx-gradient-hero);
}

This file gives your RX theme a strong, scalable color system.

Leave a Reply

Your email address will not be published. Required fields are marked *