<?php
/**
 * Admin Bar Custom Elements (Pro)
 *
 * @package ASENHA
 */

namespace ASENHA\Classes;

/**
 * Pro module: custom admin bar nodes with a dedicated Settings screen.
 */
class Admin_Bar_Custom_Elements {

	const PAGE_SLUG = 'asenha-admin-bar';

	const AJAX_SAVE_ACTION = 'asenha_save_admin_bar_custom_elements';

	const MENU_PRIORITY = 9990;

	/**
	 * admin_bar_menu priority: custom nodes early (before core wp_menu at 10, typical plugins on top-secondary).
	 *
	 * @var int
	 */
	const ADMIN_BAR_PRIORITY_BEGIN = 5;

	/**
	 * admin_bar_menu priority: custom nodes late (after core left items; before my-account at 9991).
	 *
	 * @var int
	 */
	const ADMIN_BAR_PRIORITY_END = 9990;

	/**
	 * admin_bar_menu priority: after core wp_admin_bar_site_menu (priority 30 in WP_Admin_Bar::add_menus()).
	 *
	 * @var int
	 */
	const ADMIN_BAR_PRIORITY_AFTER_SITE_NAME = 31;

	/**
	 * Max length for SVG data URI icon values (bytes). Guards option size and abuse.
	 *
	 * @var int
	 */
	const MAX_SVG_DATA_URI_BYTES = 204800;

	/**
	 * Default role slug pre-selected for new ABCE rows created in JS.
	 *
	 * @var string
	 */
	const DEFAULT_NEW_ITEM_ROLE_SLUG = 'administrator';

	/**
	 * Triangle SVG for Options toggle (matches Admin Menu Organizer).
	 *
	 * @return string
	 */
	private function get_options_triangle_svg__premium_only() {
		return '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 16 16"><path fill="currentColor" d="M14.222 6.687a1.5 1.5 0 0 1 0 2.629l-10 5.499A1.5 1.5 0 0 1 2 13.5V2.502a1.5 1.5 0 0 1 2.223-1.314z"/></svg>';
	}

	/**
	 * Close icon SVG for remove control (matches Admin Menu Organizer).
	 *
	 * @return string
	 */
	private function get_remove_icon_svg__premium_only() {
		return '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path fill="#bbbbbb" d="M24 2.4L21.6 0L12 9.6L2.4 0L0 2.4L9.6 12L0 21.6L2.4 24l9.6-9.6l9.6 9.6l2.4-2.4l-9.6-9.6z"/></svg>';
	}

	/**
	 * Register Settings submenu (Pro).
	 */
	public function add_menu_item__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		add_submenu_page(
			'options-general.php',
			__( 'Admin Bar', 'admin-site-enhancements' ),
			__( 'Admin Bar', 'admin-site-enhancements' ),
			'manage_options',
			self::PAGE_SLUG,
			array( $this, 'render_settings_page__premium_only' )
		);
	}

	/**
	 * Output the dedicated admin UI.
	 */
	public function render_settings_page__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$config = $this->get_config__premium_only();
		?>
		<div class="wrap asenha-abce-wrap">
			<h1 class="wp-heading-inline"><?php echo esc_html__( 'Admin Bar Custom Elements', 'admin-site-enhancements' ); ?></h1>
			<p class="description">
				<?php echo esc_html__( 'Add custom elements for the left or right side of the admin bar. Drag to reorder parents and children. Drag a parent between the left and right columns to move it, or drag a child into another parent’s submenu to move it (including between columns), then save.', 'admin-site-enhancements' ); ?>
			</p>
			<div class="asenha-abce-columns">
				<div class="asenha-abce-column asenha-abce-column-left">
					<h2><?php echo esc_html__( 'Left side', 'admin-site-enhancements' ); ?></h2>
					<div class="asenha-abce-placement">
						<label for="asenha-abce-placement-left" class="asenha-abce-placement-label"><?php echo esc_html__( 'Placement', 'admin-site-enhancements' ); ?></label>
						<select id="asenha-abce-placement-left" class="asenha-abce-placement-select" name="asenha_abce_placement_left" autocomplete="off">
							<option value="begin" <?php selected( $config['placement_left'], 'begin' ); ?>><?php echo esc_html__( 'At the beginning of the left cluster', 'admin-site-enhancements' ); ?></option>
							<option value="after_site_name" <?php selected( $config['placement_left'], 'after_site_name' ); ?>><?php echo esc_html__( 'After the site name menu', 'admin-site-enhancements' ); ?></option>
							<option value="end" <?php selected( $config['placement_left'], 'end' ); ?>><?php echo esc_html__( 'At the end of the left cluster', 'admin-site-enhancements' ); ?></option>
						</select>
					</div>
					<ul id="asenha-abce-parents-left" class="asenha-abce-parent-sortable menu" data-placement="left">
						<?php
						foreach ( $config['parents_left'] as $item_id ) {
							if ( isset( $config['items'][ $item_id ] ) ) {
								$this->render_parent_item__premium_only( $item_id, $config['items'][ $item_id ], 'left', $config );
							}
						}
						?>
					</ul>
					<p>
						<button type="button" class="button asenha-abce-add-parent" data-placement="left"><?php echo esc_html__( 'Add parent element', 'admin-site-enhancements' ); ?></button>
					</p>
				</div>
				<div class="asenha-abce-column asenha-abce-column-right">
					<h2><?php echo esc_html__( 'Right side', 'admin-site-enhancements' ); ?></h2>
					<div class="asenha-abce-placement">
						<label for="asenha-abce-placement-right" class="asenha-abce-placement-label"><?php echo esc_html__( 'Placement', 'admin-site-enhancements' ); ?></label>
						<select id="asenha-abce-placement-right" class="asenha-abce-placement-select" name="asenha_abce_placement_right" autocomplete="off">
							<option value="begin" <?php selected( $config['placement_right'], 'begin' ); ?>><?php echo esc_html__( 'At the beginning of the right cluster', 'admin-site-enhancements' ); ?></option>
							<option value="before_account" <?php selected( $config['placement_right'], 'before_account' ); ?>><?php echo esc_html__( 'Before the user account menu', 'admin-site-enhancements' ); ?></option>
						</select>
					</div>
					<ul id="asenha-abce-parents-right" class="asenha-abce-parent-sortable menu" data-placement="right">
						<?php
						foreach ( $config['parents_right'] as $item_id ) {
							if ( isset( $config['items'][ $item_id ] ) ) {
								$this->render_parent_item__premium_only( $item_id, $config['items'][ $item_id ], 'right', $config );
							}
						}
						?>
					</ul>
					<p>
						<button type="button" class="button asenha-abce-add-parent" data-placement="right"><?php echo esc_html__( 'Add parent element', 'admin-site-enhancements' ); ?></button>
					</p>
				</div>
			</div>
			<p class="asenha-abce-save-row">
				<button type="button" id="asenha-abce-save" class="button button-primary button-large"><?php echo esc_html__( 'Save Changes', 'admin-site-enhancements' ); ?></button>
				<span class="asenha-abce-saving" style="display:none;" aria-hidden="true"><?php echo esc_html__( 'Saving…', 'admin-site-enhancements' ); ?></span>
				<span class="asenha-abce-saved" style="display:none;" role="status"><?php echo esc_html__( 'Saved.', 'admin-site-enhancements' ); ?></span>
			</p>
		</div>
		<?php
	}

	/**
	 * Get stored configuration with defaults.
	 *
	 * @return array<string,mixed>
	 */
	public function get_config__premium_only() {
		$options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
		$raw             = isset( $options_extra['admin_bar_custom_elements'] ) ? $options_extra['admin_bar_custom_elements'] : array();

		if ( ! is_array( $raw ) ) {
			$raw = array();
		}

		$config = array(
			'parents_left'     => isset( $raw['parents_left'] ) && is_array( $raw['parents_left'] ) ? $raw['parents_left'] : array(),
			'parents_right'    => isset( $raw['parents_right'] ) && is_array( $raw['parents_right'] ) ? $raw['parents_right'] : array(),
			'items'            => isset( $raw['items'] ) && is_array( $raw['items'] ) ? $raw['items'] : array(),
			'placement_left'   => 'end',
			'placement_right'  => 'before_account',
		);

		if ( isset( $raw['placement_left'] ) && is_string( $raw['placement_left'] ) ) {
			$pl = sanitize_key( $raw['placement_left'] );
			if ( in_array( $pl, array( 'begin', 'after_site_name', 'end' ), true ) ) {
				$config['placement_left'] = $pl;
			}
		}
		if ( isset( $raw['placement_right'] ) && is_string( $raw['placement_right'] ) ) {
			$pr = sanitize_key( $raw['placement_right'] );
			if ( in_array( $pr, array( 'begin', 'before_account' ), true ) ) {
				$config['placement_right'] = $pr;
			}
		}

		return $config;
	}

	/**
	 * Render one parent row and its children.
	 *
	 * @param string               $item_id Item id.
	 * @param array<string,mixed>  $data    Item data.
	 * @param string               $placement left|right.
	 * @param array<string,mixed>  $config  Full config.
	 */
	public function render_parent_item__premium_only( $item_id, $data, $placement, $config ) {
		$item_id = sanitize_key( $item_id );
		if ( '' === $item_id ) {
			return;
		}

		$children_order = isset( $data['children_order'] ) && is_array( $data['children_order'] ) ? $data['children_order'] : array();

		$triangle = $this->get_options_triangle_svg__premium_only();
		$remove_svg = $this->get_remove_icon_svg__premium_only();

		?>
		<li id="<?php echo esc_attr( $item_id ); ?>" class="menu-item parent-menu-item menu-item-depth-0 sortable-item asenha-abce-parent" data-item-id="<?php echo esc_attr( $item_id ); ?>" data-placement="<?php echo esc_attr( $placement ); ?>">
			<div class="asenha-abce-item-top">
				<div class="menu-item-bar">
					<div class="menu-item-handle">
						<span class="dashicons dashicons-menu"></span>
						<div class="item-title asenha-abce-item-title-row">
							<span class="asenha-abce-handle-title"><?php echo esc_html( isset( $data['title'] ) ? $data['title'] : $item_id ); ?></span>
						</div>
						<div class="submenu-toggle asenha-abce-submenu-toggle" role="button" tabindex="0" aria-expanded="false">
							<span class="arrow-right"><?php echo wp_kses( $triangle, get_kses_with_svg_ruleset() ); ?></span>
							<span class="submenu-text"><?php echo esc_html__( 'Submenu', 'admin-site-enhancements' ); ?></span>
						</div>
						<div class="options-toggle asenha-abce-options-toggle" role="button" tabindex="0" aria-expanded="false">
							<span class="arrow-right"><?php echo wp_kses( $triangle, get_kses_with_svg_ruleset() ); ?></span>
							<span class="options-text"><?php echo esc_html__( 'Options', 'admin-site-enhancements' ); ?></span>
						</div>
					</div>
				</div>
				<div class="remove-custom-menu-item-saved asenha-abce-remove" data-item-id="<?php echo esc_attr( $item_id ); ?>" role="button" tabindex="0" aria-label="<?php esc_attr_e( 'Remove', 'admin-site-enhancements' ); ?>">
					<?php echo wp_kses( $remove_svg, get_kses_with_svg_ruleset() ); ?>
				</div>
			</div>
			<div class="asenha-abce-options asenha-abce-options--collapsed" style="display:none;">
				<?php $this->render_item_fields__premium_only( $item_id, $data, 'parent', $placement ); ?>
			</div>
			<div class="submenu-wrapper asenha-abce-submenu-wrapper" style="display:none;">
				<ul id="abce-children-<?php echo esc_attr( $item_id ); ?>" class="submenu-sortable submenu asenha-abce-children" data-parent-id="<?php echo esc_attr( $item_id ); ?>">
					<?php
					foreach ( $children_order as $child_id ) {
						$child_id = sanitize_key( $child_id );
						if ( '' === $child_id || ! isset( $config['items'][ $child_id ] ) ) {
							continue;
						}
						$child_data = $config['items'][ $child_id ];
						if ( empty( $child_data['parent'] ) || $child_data['parent'] !== $item_id ) {
							continue;
						}
						$this->render_child_item__premium_only( $child_id, $child_data, $config );
					}
					?>
				</ul>
				<p class="asenha-abce-add-child-row">
					<button type="button" class="button asenha-abce-add-child" data-parent-id="<?php echo esc_attr( $item_id ); ?>"><?php echo esc_html__( 'Add child element', 'admin-site-enhancements' ); ?></button>
				</p>
			</div>
		</li>
		<?php
	}

	/**
	 * Render a child row.
	 *
	 * @param string              $item_id Item id.
	 * @param array<string,mixed> $data    Item data.
	 * @param array<string,mixed> $config  Full config.
	 */
	public function render_child_item__premium_only( $item_id, $data, $config ) {
		$item_id = sanitize_key( $item_id );
		if ( '' === $item_id ) {
			return;
		}

		$parent_id = isset( $data['parent'] ) ? sanitize_key( $data['parent'] ) : '';
		$triangle  = $this->get_options_triangle_svg__premium_only();
		$remove_svg = $this->get_remove_icon_svg__premium_only();
		?>
		<li id="<?php echo esc_attr( $item_id ); ?>" class="menu-item menu-item-depth-1 sortable-item asenha-abce-child" data-item-id="<?php echo esc_attr( $item_id ); ?>" data-parent-id="<?php echo esc_attr( $parent_id ); ?>">
			<div class="asenha-abce-item-top">
				<div class="menu-item-bar">
					<div class="menu-item-handle">
						<span class="dashicons dashicons-menu"></span>
						<div class="item-title asenha-abce-item-title-row">
							<span class="asenha-abce-handle-title"><?php echo esc_html( isset( $data['title'] ) ? $data['title'] : $item_id ); ?></span>
						</div>
						<div class="options-toggle asenha-abce-options-toggle" role="button" tabindex="0" aria-expanded="false">
							<span class="arrow-right"><?php echo wp_kses( $triangle, get_kses_with_svg_ruleset() ); ?></span>
							<span class="options-text"><?php echo esc_html__( 'Options', 'admin-site-enhancements' ); ?></span>
						</div>
					</div>
				</div>
				<div class="remove-custom-menu-item-saved asenha-abce-remove" data-item-id="<?php echo esc_attr( $item_id ); ?>" role="button" tabindex="0" aria-label="<?php esc_attr_e( 'Remove', 'admin-site-enhancements' ); ?>">
					<?php echo wp_kses( $remove_svg, get_kses_with_svg_ruleset() ); ?>
				</div>
			</div>
			<div class="asenha-abce-options asenha-abce-options--collapsed" style="display:none;">
				<?php $this->render_item_fields__premium_only( $item_id, $data, 'child', '' ); ?>
			</div>
		</li>
		<?php
	}

	/**
	 * Shared field table for parent or child.
	 *
	 * @param string              $item_id   Item id.
	 * @param array<string,mixed> $data      Item data.
	 * @param string              $role      parent|child.
	 * @param string              $placement left|right (parent only).
	 */
	public function render_item_fields__premium_only( $item_id, $data, $role, $placement ) {
		$defaults = array(
			'title'             => '',
			'href'              => '',
			'visibility'        => 'both',
			'parent'            => '',
			'icon'              => '',
			'role_filter_mode'  => 'all',
			'role_slugs'        => array(),
			'meta_html'         => '',
			'meta_class'        => '',
			'meta_target'       => '',
			'meta_title'        => '',
			'meta_menu_title'   => '',
		);

		$data = wp_parse_args( $data, $defaults );
		if ( ! is_array( $data['role_slugs'] ) ) {
			$data['role_slugs'] = array();
		}
		if ( 'child' === $role ) {
			$data = wp_parse_args( $data, array( 'role_filter_scope' => 'inherit' ) );
		}

		?>
		<input type="hidden" class="abce-field abce-id" data-field="id" value="<?php echo esc_attr( $item_id ); ?>" />
		<table class="form-table asenha-abce-field-table" role="presentation">
			<tbody>
				<tr>
					<th scope="row"><label for="abce-title-<?php echo esc_attr( $item_id ); ?>"><?php echo esc_html__( 'Title', 'admin-site-enhancements' ); ?></label></th>
					<td>
						<input type="text" class="large-text abce-field abce-title" id="abce-title-<?php echo esc_attr( $item_id ); ?>" data-field="title" value="<?php echo esc_attr( $data['title'] ); ?>" />
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="abce-href-<?php echo esc_attr( $item_id ); ?>"><?php echo esc_html__( 'Link', 'admin-site-enhancements' ); ?></label></th>
					<td>
						<input type="text" class="large-text abce-field abce-href" id="abce-href-<?php echo esc_attr( $item_id ); ?>" data-field="href" value="<?php echo esc_attr( $data['href'] ); ?>" placeholder="<?php echo esc_attr( admin_url() ); ?>" />
					</td>
				</tr>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Show on', 'admin-site-enhancements' ); ?></th>
					<td>
						<select class="abce-field abce-visibility" data-field="visibility">
							<option value="admin" <?php selected( $data['visibility'], 'admin' ); ?>><?php echo esc_html__( 'Backend', 'admin-site-enhancements' ); ?></option>
							<option value="frontend" <?php selected( $data['visibility'], 'frontend' ); ?>><?php echo esc_html__( 'Frontend', 'admin-site-enhancements' ); ?></option>
							<option value="both" <?php selected( $data['visibility'], 'both' ); ?>><?php echo esc_html__( 'Backend and frontend', 'admin-site-enhancements' ); ?></option>
						</select>
					</td>
				</tr>
				<?php $this->render_show_for_field_row__premium_only( $item_id, $data, $role ); ?>
				<?php if ( 'child' !== $role ) : ?>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Icon', 'admin-site-enhancements' ); ?></th>
					<td>
						<div class="custom-menu-field custom-menu-icon-field">
							<div class="icon-picker-wrapper">
								<div class="icon-picker">
									<span class="selected-menu-icon"></span>
									<input type="text" class="custom-menu-icon custom-menu-input-full abce-icon-input" data-menu-item-id="<?php echo esc_attr( $item_id ); ?>" value="<?php echo esc_attr( $data['icon'] ); ?>" placeholder="<?php esc_attr_e( 'Dashicon class or SVG data URI', 'admin-site-enhancements' ); ?>" />
								</div>
								<div class="icon-picker-controls">
									<button type="button" class="button icon-picker-button" data-menu-item-id="<?php echo esc_attr( $item_id ); ?>"><?php echo esc_html__( 'Choose Icon', 'admin-site-enhancements' ); ?></button>
									<img src="<?php echo esc_url( ASENHA_URL . 'assets/img/oval.svg' ); ?>" class="icon-picker-spinner" style="display: none;" alt="" />
									<input type="search" class="icon-picker-search" placeholder="<?php esc_attr_e( 'Search…', 'admin-site-enhancements' ); ?>" style="display:none;" data-menu-item-id="<?php echo esc_attr( $item_id ); ?>" />
								</div>
							</div>
							<div class="icon-library-container" data-menu-item-id="<?php echo esc_attr( $item_id ); ?>" style="display:none;"></div>
						</div>
					</td>
				</tr>
				<?php endif; ?>
			</tbody>
			<?php
			$show_advanced_meta = (
				'' !== trim( (string) $data['meta_html'] )
				|| '' !== trim( (string) $data['meta_class'] )
				|| '' !== trim( (string) $data['meta_target'] )
				|| '' !== trim( (string) $data['meta_title'] )
				|| '' !== trim( (string) $data['meta_menu_title'] )
			);
			$meta_section_id    = 'abce-meta-advanced-' . $item_id;
			$adv_triangle       = $this->get_options_triangle_svg__premium_only();
			?>
			<tbody>
				<tr class="asenha-abce-advanced-toggle-row">
					<td colspan="2" class="asenha-abce-advanced-toggle-cell">
						<button type="button" class="asenha-abce-advanced-toggle" aria-expanded="<?php echo $show_advanced_meta ? 'true' : 'false'; ?>" aria-controls="<?php echo esc_attr( $meta_section_id ); ?>">
							<span class="arrow-right<?php echo $show_advanced_meta ? ' rotate-down' : ''; ?>"><?php echo wp_kses( $adv_triangle, get_kses_with_svg_ruleset() ); ?></span>
							<span class="asenha-abce-advanced-toggle-text"><?php echo esc_html( $show_advanced_meta ? __( 'Hide advanced options', 'admin-site-enhancements' ) : __( 'Show advanced options', 'admin-site-enhancements' ) ); ?></span>
						</button>
					</td>
				</tr>
			</tbody>
			<tbody id="<?php echo esc_attr( $meta_section_id ); ?>" class="asenha-abce-meta-advanced"<?php echo $show_advanced_meta ? '' : ' style="display:none;"'; ?>>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Meta: HTML', 'admin-site-enhancements' ); ?></th>
					<td>
						<textarea class="large-text abce-field abce-meta-html" rows="2" data-field="meta_html"><?php echo esc_textarea( $data['meta_html'] ); ?></textarea>
					</td>
				</tr>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Meta: class', 'admin-site-enhancements' ); ?></th>
					<td>
						<input type="text" class="large-text abce-field abce-meta-class" data-field="meta_class" value="<?php echo esc_attr( $data['meta_class'] ); ?>" />
					</td>
				</tr>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Meta: target', 'admin-site-enhancements' ); ?></th>
					<td>
						<input type="text" class="regular-text abce-field abce-meta-target" data-field="meta_target" value="<?php echo esc_attr( $data['meta_target'] ); ?>" placeholder="_blank" />
					</td>
				</tr>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Meta: title (tooltip)', 'admin-site-enhancements' ); ?></th>
					<td>
						<input type="text" class="large-text abce-field abce-meta-title" data-field="meta_title" value="<?php echo esc_attr( $data['meta_title'] ); ?>" />
					</td>
				</tr>
				<tr>
					<th scope="row"><?php echo esc_html__( 'Meta: menu_title (ARIA)', 'admin-site-enhancements' ); ?></th>
					<td>
						<input type="text" class="large-text abce-field abce-meta-menu-title" data-field="meta_menu_title" value="<?php echo esc_attr( $data['meta_menu_title'] ); ?>" />
					</td>
				</tr>
			</tbody>
		</table>
		<?php
	}

	/**
	 * "Show For" role filter row (parent and child).
	 *
	 * @param string              $item_id Item id.
	 * @param array<string,mixed> $data    Parsed item data.
	 * @param string              $role    parent|child.
	 */
	private function render_show_for_field_row__premium_only( $item_id, $data, $role ) {
		$mode = isset( $data['role_filter_mode'] ) ? sanitize_key( (string) $data['role_filter_mode'] ) : 'all';
		if ( ! in_array( $mode, array( 'all', 'only', 'except' ), true ) ) {
			$mode = 'all';
		}
		$selected = isset( $data['role_slugs'] ) && is_array( $data['role_slugs'] ) ? $data['role_slugs'] : array();
		$selected = array_map( 'sanitize_key', $selected );
		$show_grid = ( 'only' === $mode || 'except' === $mode );
		$rf_name   = 'abce-role-filter-' . $item_id;
		$choices   = $this->get_abce_role_choices__premium_only();

		$scope = 'inherit';
		if ( 'child' === $role ) {
			$scope = isset( $data['role_filter_scope'] ) ? sanitize_key( (string) $data['role_filter_scope'] ) : 'inherit';
			if ( ! in_array( $scope, array( 'inherit', 'custom' ), true ) ) {
				$scope = 'inherit';
			}
		}
		$custom_block_hidden = ( 'child' === $role && 'inherit' === $scope );
		$scope_select_id     = 'abce-role-scope-' . $item_id;
		?>
				<tr class="asenha-abce-show-for-row">
					<th scope="row"><?php echo esc_html__( 'Show For', 'admin-site-enhancements' ); ?></th>
					<td>
						<fieldset class="asenha-abce-role-filter-fieldset">
							<legend class="screen-reader-text"><?php echo esc_html__( 'Show For', 'admin-site-enhancements' ); ?></legend>
							<?php if ( 'child' === $role ) : ?>
							<div class="asenha-abce-role-filter-scope-wrap">
								<label for="<?php echo esc_attr( $scope_select_id ); ?>" class="screen-reader-text"><?php echo esc_html__( 'Child role filter scope', 'admin-site-enhancements' ); ?></label>
								<select class="abce-field abce-role-filter-scope large-text" id="<?php echo esc_attr( $scope_select_id ); ?>" data-field="role_filter_scope" autocomplete="off">
									<option value="inherit" <?php selected( $scope, 'inherit' ); ?>><?php echo esc_html__( 'Inherit parent element settings', 'admin-site-enhancements' ); ?></option>
									<option value="custom" <?php selected( $scope, 'custom' ); ?>><?php echo esc_html__( 'Customize for this child element', 'admin-site-enhancements' ); ?></option>
								</select>
							</div>
							<?php endif; ?>
							<div class="asenha-abce-role-filter-custom-block"<?php echo $custom_block_hidden ? ' hidden="hidden" aria-hidden="true"' : ' aria-hidden="false"'; ?>>
							<div class="asenha-abce-role-filter-radios">
								<label class="asenha-abce-role-filter-label">
									<input type="radio" class="abce-role-filter-mode" name="<?php echo esc_attr( $rf_name ); ?>" value="all" <?php checked( $mode, 'all' ); ?> />
									<?php echo esc_html__( 'All user roles', 'admin-site-enhancements' ); ?>
								</label>
								<label class="asenha-abce-role-filter-label">
									<input type="radio" class="abce-role-filter-mode" name="<?php echo esc_attr( $rf_name ); ?>" value="only" <?php checked( $mode, 'only' ); ?> />
									<?php echo esc_html__( 'Only selected roles', 'admin-site-enhancements' ); ?>
								</label>
								<label class="asenha-abce-role-filter-label">
									<input type="radio" class="abce-role-filter-mode" name="<?php echo esc_attr( $rf_name ); ?>" value="except" <?php checked( $mode, 'except' ); ?> />
									<?php echo esc_html__( 'All roles except selected', 'admin-site-enhancements' ); ?>
								</label>
							</div>
							<div class="asenha-abce-role-grid-wrap<?php echo $show_grid ? ' is-visible' : ''; ?>"<?php echo $show_grid ? '' : ' hidden'; ?> aria-hidden="<?php echo $show_grid ? 'false' : 'true'; ?>">
								<div class="asenha-abce-role-grid" role="group" aria-label="<?php echo esc_attr__( 'Roles', 'admin-site-enhancements' ); ?>">
									<?php foreach ( $choices as $choice ) : ?>
										<?php
										$slug = isset( $choice['slug'] ) ? sanitize_key( (string) $choice['slug'] ) : '';
										if ( '' === $slug ) {
											continue;
										}
										$label = isset( $choice['label'] ) ? (string) $choice['label'] : $slug;
										$cb_id = 'abce-role-' . $item_id . '-' . $slug;
										?>
										<label class="asenha-abce-role-grid-item" for="<?php echo esc_attr( $cb_id ); ?>">
											<input type="checkbox" class="abce-role-slug" id="<?php echo esc_attr( $cb_id ); ?>" value="<?php echo esc_attr( $slug ); ?>" <?php checked( in_array( $slug, $selected, true ) ); ?> />
											<?php echo esc_html( $label ); ?>
										</label>
									<?php endforeach; ?>
								</div>
							</div>
							</div>
						</fieldset>
					</td>
				</tr>
		<?php
	}

	/**
	 * AJAX: save configuration.
	 */
	public function save_ajax__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			wp_die();
		}

		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'asenha-abce-save' ) ) {
			wp_send_json_error( array( 'message' => 'bad_nonce' ), 403 );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
		}

		$raw = isset( $_POST['payload'] ) ? wp_unslash( $_POST['payload'] ) : '';
		if ( ! is_string( $raw ) || '' === $raw ) {
			wp_send_json_error( array( 'message' => 'empty_payload' ), 400 );
		}

		$decoded = json_decode( $raw, true );
		if ( ! is_array( $decoded ) ) {
			wp_send_json_error( array( 'message' => 'invalid_json' ), 400 );
		}

		$sanitized = $this->sanitize_incoming_config__premium_only( $decoded );
		if ( is_wp_error( $sanitized ) ) {
			wp_send_json_error( array( 'message' => $sanitized->get_error_message() ), 400 );
		}

		$options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
		if ( ! is_array( $options_extra ) ) {
			$options_extra = array();
		}
		$options_extra['admin_bar_custom_elements'] = $sanitized;
		update_option( ASENHA_SLUG_U . '_extra', $options_extra, true );

		wp_send_json_success( array( 'status' => 'success' ) );
	}

	/**
	 * Validate and sanitize payload from JS.
	 *
	 * @param array<string,mixed> $data Raw.
	 * @return array<string,mixed>|\WP_Error
	 */
	public function sanitize_incoming_config__premium_only( $data ) {
		$out = array(
			'parents_left'     => array(),
			'parents_right'    => array(),
			'items'            => array(),
			'placement_left'   => 'end',
			'placement_right'  => 'before_account',
		);

		$pl = isset( $data['placement_left'] ) ? sanitize_key( $data['placement_left'] ) : 'end';
		if ( in_array( $pl, array( 'begin', 'after_site_name', 'end' ), true ) ) {
			$out['placement_left'] = $pl;
		}
		$pr = isset( $data['placement_right'] ) ? sanitize_key( $data['placement_right'] ) : 'before_account';
		if ( in_array( $pr, array( 'begin', 'before_account' ), true ) ) {
			$out['placement_right'] = $pr;
		}

		$parents_left = isset( $data['parents_left'] ) && is_array( $data['parents_left'] ) ? $data['parents_left'] : array();
		foreach ( $parents_left as $id ) {
			$id = sanitize_key( $id );
			if ( '' !== $id ) {
				$out['parents_left'][] = $id;
			}
		}
		$out['parents_left'] = array_values( array_unique( $out['parents_left'] ) );

		$parents_right = isset( $data['parents_right'] ) && is_array( $data['parents_right'] ) ? $data['parents_right'] : array();
		foreach ( $parents_right as $id ) {
			$id = sanitize_key( $id );
			if ( '' !== $id ) {
				$out['parents_right'][] = $id;
			}
		}
		$out['parents_right'] = array_values( array_unique( $out['parents_right'] ) );

		$items = isset( $data['items'] ) && is_array( $data['items'] ) ? $data['items'] : array();

		$all_parent_ids = array_merge( $out['parents_left'], $out['parents_right'] );

		foreach ( $items as $raw_id => $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}

			$id = sanitize_key( is_string( $raw_id ) ? $raw_id : ( isset( $item['id'] ) ? $item['id'] : '' ) );
			if ( '' === $id ) {
				continue;
			}

			if ( isset( $out['items'][ $id ] ) ) {
				return new \WP_Error( 'dup_id', __( 'Duplicate item IDs are not allowed.', 'admin-site-enhancements' ) );
			}

			// Reserved / collision with core: prefix if looks risky.
			if ( $this->is_reserved_bar_id( $id ) ) {
				return new \WP_Error( 'bad_id', __( 'That ID is reserved. Choose another.', 'admin-site-enhancements' ) );
			}

			$title = isset( $item['title'] ) ? sanitize_text_field( $item['title'] ) : '';
			$href  = isset( $item['href'] ) ? $this->sanitize_href__premium_only( $item['href'] ) : '';

			$vis = isset( $item['visibility'] ) ? sanitize_key( $item['visibility'] ) : 'both';
			if ( ! in_array( $vis, array( 'admin', 'frontend', 'both' ), true ) ) {
				$vis = 'both';
			}

			$parent = isset( $item['parent'] ) ? sanitize_key( $item['parent'] ) : '';
			if ( in_array( $id, $all_parent_ids, true ) ) {
				if ( '' !== $parent ) {
					return new \WP_Error( 'invalid', __( 'A parent element cannot have a parent.', 'admin-site-enhancements' ) );
				}
			}
			if ( '' !== $parent && ! in_array( $parent, $all_parent_ids, true ) ) {
				return new \WP_Error( 'bad_parent', __( 'A child element references an unknown parent.', 'admin-site-enhancements' ) );
			}

			// Child elements are text-only in the admin bar; icons are not supported.
			$icon = '';
			if ( '' === $parent ) {
				$icon = isset( $item['icon'] ) ? $this->sanitize_icon_value__premium_only( $item['icon'] ) : '';
			}

			$children_order = isset( $item['children_order'] ) && is_array( $item['children_order'] ) ? $item['children_order'] : array();
			$clean_children = array();
			foreach ( $children_order as $cid ) {
				$cid = sanitize_key( $cid );
				if ( '' !== $cid ) {
					$clean_children[] = $cid;
				}
			}
			$clean_children = array_values( array_unique( $clean_children ) );

			$meta_html = isset( $item['meta_html'] ) ? wp_kses_post( $item['meta_html'] ) : '';
			$meta_class = isset( $item['meta_class'] ) ? sanitize_text_field( $item['meta_class'] ) : '';
			if ( '' !== $meta_class && ! preg_match( '/^[\w\s\-]+$/', $meta_class ) ) {
				$meta_class = '';
			}
			$meta_target = isset( $item['meta_target'] ) ? sanitize_key( $item['meta_target'] ) : '';
			$meta_title = isset( $item['meta_title'] ) ? sanitize_text_field( $item['meta_title'] ) : '';
			$meta_menu_title = isset( $item['meta_menu_title'] ) ? sanitize_text_field( $item['meta_menu_title'] ) : '';

			$rf_mode = isset( $item['role_filter_mode'] ) ? sanitize_key( $item['role_filter_mode'] ) : 'all';
			if ( ! in_array( $rf_mode, array( 'all', 'only', 'except' ), true ) ) {
				$rf_mode = 'all';
			}
			$role_slugs_raw = isset( $item['role_slugs'] ) && is_array( $item['role_slugs'] ) ? $item['role_slugs'] : array();
			$role_slugs     = $this->sanitize_role_slugs_against_registered__premium_only( $role_slugs_raw );

			$row_item = array(
				'title'             => $title,
				'href'              => $href,
				'visibility'        => $vis,
				'parent'            => $parent,
				'icon'              => $icon,
				'role_filter_mode'  => $rf_mode,
				'role_slugs'        => $role_slugs,
				'children_order'    => $clean_children,
				'meta_html'         => $meta_html,
				'meta_class'        => $meta_class,
				'meta_target'       => $meta_target,
				'meta_title'        => $meta_title,
				'meta_menu_title'   => $meta_menu_title,
			);

			if ( '' !== $parent ) {
				$rfs = isset( $item['role_filter_scope'] ) ? sanitize_key( $item['role_filter_scope'] ) : 'inherit';
				if ( ! in_array( $rfs, array( 'inherit', 'custom' ), true ) ) {
					$rfs = 'inherit';
				}
				$row_item['role_filter_scope'] = $rfs;
			}

			$out['items'][ $id ] = $row_item;
		}

		// Ensure every parent id exists in items with empty parent.
		foreach ( $all_parent_ids as $pid ) {
			if ( ! isset( $out['items'][ $pid ] ) ) {
				return new \WP_Error( 'missing_parent', __( 'Parent configuration is incomplete.', 'admin-site-enhancements' ) );
			}
			$out['items'][ $pid ]['parent'] = '';
			unset( $out['items'][ $pid ]['role_filter_scope'] );
		}

		// Children must reference valid parent and appear in children_order.
		foreach ( $out['items'] as $cid => $cdata ) {
			if ( empty( $cdata['parent'] ) ) {
				continue;
			}
			$p = $cdata['parent'];
			if ( ! isset( $out['items'][ $p ] ) ) {
				return new \WP_Error( 'orphan', __( 'A child element references a missing parent.', 'admin-site-enhancements' ) );
			}
			if ( ! in_array( $cid, $out['items'][ $p ]['children_order'], true ) ) {
				$out['items'][ $p ]['children_order'][] = $cid;
			}
		}

		return $out;
	}

	/**
	 * Whether id collides with common core ids.
	 *
	 * @param string $id Sanitized id.
	 */
	private function is_reserved_bar_id( $id ) {
		$reserved = array(
			'wp-logo',
			'site-name',
			'updates',
			'comments',
			'new-content',
			'my-account',
			'top-secondary',
			'menu-toggle',
			'customize',
			'edit',
		);
		return in_array( $id, $reserved, true );
	}

	/**
	 * @param mixed $href Raw href.
	 */
	private function sanitize_href__premium_only( $href ) {
		$href = is_string( $href ) ? trim( $href ) : '';
		if ( '' === $href || '#' === $href ) {
			return '';
		}
		if ( preg_match( '#^https?://#i', $href ) ) {
			return esc_url_raw( $href );
		}
		// Relative site root.
		if ( 0 === strpos( $href, '/' ) ) {
			return esc_url_raw( site_url( $href ) );
		}
		// Admin-relative e.g. admin.php?page=x
		if ( is_string( $href ) && false !== strpos( $href, '.php' ) ) {
			return esc_url_raw( admin_url( $href ) );
		}
		return esc_url_raw( $href );
	}

	/**
	 * Protocol list for esc_url / esc_url_raw when storing or outputting SVG data URIs.
	 *
	 * WordPress default protocols omit `data`, which would strip icon picker values.
	 *
	 * @return string[]
	 */
	private function get_icon_data_uri_protocols__premium_only() {
		return array_merge( wp_allowed_protocols(), array( 'data' ) );
	}

	/**
	 * @param mixed $icon Raw.
	 */
	private function sanitize_icon_value__premium_only( $icon ) {
		if ( ! is_string( $icon ) ) {
			return '';
		}
		$icon = trim( $icon );
		if ( '' === $icon ) {
			return '';
		}
		if ( 0 === strpos( $icon, 'data:image/svg+xml' ) ) {
			if ( strlen( $icon ) > self::MAX_SVG_DATA_URI_BYTES ) {
				return '';
			}
			$clean = esc_url_raw( $icon, $this->get_icon_data_uri_protocols__premium_only() );
			return is_string( $clean ) ? $clean : '';
		}
		// dashicons-foo or multiple classes.
		$icon = sanitize_text_field( $icon );
		return $icon;
	}

	/**
	 * Register admin_bar_menu callbacks for left and right columns (priorities depend on placement settings).
	 */
	public function register_admin_bar_menu_hooks__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		$config = $this->get_config__premium_only();
		$priorities = $this->get_admin_bar_priorities_for_placements__premium_only(
			isset( $config['placement_left'] ) ? (string) $config['placement_left'] : 'end',
			isset( $config['placement_right'] ) ? (string) $config['placement_right'] : 'before_account'
		);

		add_action( 'admin_bar_menu', array( $this, 'register_left_nodes__premium_only' ), $priorities['left'] );
		add_action( 'admin_bar_menu', array( $this, 'register_right_nodes__premium_only' ), $priorities['right'] );
	}

	/**
	 * Map placement settings to admin_bar_menu priorities.
	 *
	 * @param string $placement_left  begin|after_site_name|end.
	 * @param string $placement_right begin|before_account.
	 * @return array{left:int,right:int}
	 */
	private function get_admin_bar_priorities_for_placements__premium_only( $placement_left, $placement_right ) {
		if ( 'begin' === $placement_left ) {
			$left = self::ADMIN_BAR_PRIORITY_BEGIN;
		} elseif ( 'after_site_name' === $placement_left ) {
			$left = self::ADMIN_BAR_PRIORITY_AFTER_SITE_NAME;
		} else {
			$left = self::ADMIN_BAR_PRIORITY_END;
		}
		$right = ( 'begin' === $placement_right ) ? self::ADMIN_BAR_PRIORITY_BEGIN : self::ADMIN_BAR_PRIORITY_END;
		return array(
			'left'  => $left,
			'right' => $right,
		);
	}

	/**
	 * Register left-column nodes on the admin bar.
	 *
	 * @param \WP_Admin_Bar $wp_admin_bar Bar.
	 */
	public function register_left_nodes__premium_only( $wp_admin_bar ) {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		if ( ! $wp_admin_bar instanceof \WP_Admin_Bar ) {
			return;
		}

		$options = get_option( ASENHA_SLUG_U, array() );
		if ( empty( $options['admin_bar_custom_elements'] ) ) {
			return;
		}

		$config = $this->get_config__premium_only();
		if ( empty( $config['items'] ) ) {
			return;
		}

		foreach ( $config['parents_left'] as $parent_id ) {
			if ( ! isset( $config['items'][ $parent_id ] ) ) {
				continue;
			}
			$this->maybe_add_item_tree__premium_only( $wp_admin_bar, $config, $parent_id, false );
		}
	}

	/**
	 * Register right-column nodes on the admin bar.
	 *
	 * @param \WP_Admin_Bar $wp_admin_bar Bar.
	 */
	public function register_right_nodes__premium_only( $wp_admin_bar ) {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		if ( ! $wp_admin_bar instanceof \WP_Admin_Bar ) {
			return;
		}

		$options = get_option( ASENHA_SLUG_U, array() );
		if ( empty( $options['admin_bar_custom_elements'] ) ) {
			return;
		}

		$config = $this->get_config__premium_only();
		if ( empty( $config['items'] ) ) {
			return;
		}

		foreach ( $config['parents_right'] as $parent_id ) {
			if ( ! isset( $config['items'][ $parent_id ] ) ) {
				continue;
			}
			$this->maybe_add_item_tree__premium_only( $wp_admin_bar, $config, $parent_id, 'top-secondary' );
		}
	}

	/**
	 * Add parent and ordered children.
	 *
	 * @param \WP_Admin_Bar        $wp_admin_bar Bar.
	 * @param array<string,mixed>  $config       Config.
	 * @param string               $item_id      Parent id.
	 * @param string|false         $bar_parent   false or top-secondary.
	 */
	private function maybe_add_item_tree__premium_only( $wp_admin_bar, $config, $item_id, $bar_parent ) {
		$item = $config['items'][ $item_id ];
		if ( ! $this->should_show_for_context__premium_only( $item['visibility'] ) ) {
			return;
		}
		if ( ! $this->should_show_for_user_roles__premium_only( $item ) ) {
			return;
		}

		$this->add_one_node__premium_only( $wp_admin_bar, $item_id, $item, $bar_parent );

		$order = isset( $item['children_order'] ) ? $item['children_order'] : array();
		foreach ( $order as $child_id ) {
			if ( ! isset( $config['items'][ $child_id ] ) ) {
				continue;
			}
			$child = $config['items'][ $child_id ];
			if ( empty( $child['parent'] ) || $child['parent'] !== $item_id ) {
				continue;
			}
			if ( ! $this->should_show_for_context__premium_only( $child['visibility'] ) ) {
				continue;
			}
			if ( ! $this->should_show_child_for_user_roles__premium_only( $child, $item ) ) {
				continue;
			}
			$this->add_one_node__premium_only( $wp_admin_bar, $child_id, $child, $item_id );
		}
	}

	/**
	 * @param string $visibility admin|frontend|both.
	 */
	private function should_show_for_context__premium_only( $visibility ) {
		if ( 'both' === $visibility ) {
			return true;
		}
		if ( 'admin' === $visibility ) {
			return is_admin();
		}
		if ( 'frontend' === $visibility ) {
			return ! is_admin();
		}
		return true;
	}

	/**
	 * Whether the current user passes the item's role filter (Show For).
	 *
	 * @param array<string,mixed> $item Item config.
	 */
	private function should_show_for_user_roles__premium_only( $item ) {
		$mode = isset( $item['role_filter_mode'] ) ? sanitize_key( (string) $item['role_filter_mode'] ) : 'all';
		if ( ! in_array( $mode, array( 'all', 'only', 'except' ), true ) ) {
			$mode = 'all';
		}
		if ( 'all' === $mode ) {
			return true;
		}
		if ( ! is_user_logged_in() ) {
			return false;
		}
		$slugs = isset( $item['role_slugs'] ) && is_array( $item['role_slugs'] ) ? $item['role_slugs'] : array();
		$user_roles = array_map( 'sanitize_key', (array) wp_get_current_user()->roles );
		$slugs      = array_map( 'sanitize_key', $slugs );
		$intersect  = array_intersect( $user_roles, $slugs );
		if ( 'only' === $mode ) {
			return ! empty( $intersect );
		}
		if ( 'except' === $mode ) {
			return empty( $intersect );
		}
		return true;
	}

	/**
	 * Child Show For: inherit parent's role filter or use child's own settings.
	 *
	 * @param array<string,mixed> $child       Child item.
	 * @param array<string,mixed> $parent_item Parent item (already passed context + parent role checks).
	 */
	private function should_show_child_for_user_roles__premium_only( $child, $parent_item ) {
		$scope = isset( $child['role_filter_scope'] ) ? sanitize_key( (string) $child['role_filter_scope'] ) : 'inherit';
		if ( ! in_array( $scope, array( 'inherit', 'custom' ), true ) ) {
			$scope = 'inherit';
		}
		if ( 'inherit' === $scope ) {
			return $this->should_show_for_user_roles__premium_only( $parent_item );
		}
		return $this->should_show_for_user_roles__premium_only( $child );
	}

	/**
	 * Registered roles as slug + translated label (for settings UI and localize).
	 *
	 * @return array<int,array{slug:string,label:string}>
	 */
	private function get_abce_role_choices__premium_only() {
		$choices  = array();
		$wp_roles = wp_roles();
		if ( ! $wp_roles || empty( $wp_roles->roles ) || ! is_array( $wp_roles->roles ) ) {
			return $choices;
		}
		foreach ( $wp_roles->roles as $slug => $role_data ) {
			if ( ! is_string( $slug ) || '' === $slug || ! is_array( $role_data ) ) {
				continue;
			}
			$name = isset( $role_data['name'] ) ? (string) $role_data['name'] : $slug;
			$choices[] = array(
				'slug'  => $slug,
				'label' => translate_user_role( $name ),
			);
		}
		return $choices;
	}

	/**
	 * Keep only slugs that exist in wp_roles().
	 *
	 * @param mixed $slugs Raw list.
	 * @return string[]
	 */
	private function sanitize_role_slugs_against_registered__premium_only( $slugs ) {
		if ( ! is_array( $slugs ) ) {
			return array();
		}
		$wp_roles = wp_roles();
		if ( ! $wp_roles || empty( $wp_roles->roles ) || ! is_array( $wp_roles->roles ) ) {
			return array();
		}
		$valid = array_keys( $wp_roles->roles );
		$out   = array();
		foreach ( $slugs as $s ) {
			$s = sanitize_key( is_string( $s ) ? $s : '' );
			if ( '' !== $s && in_array( $s, $valid, true ) ) {
				$out[] = $s;
			}
		}
		return array_values( array_unique( $out ) );
	}

	/**
	 * Add a single node.
	 *
	 * @param \WP_Admin_Bar       $wp_admin_bar Bar.
	 * @param string              $id           Node id.
	 * @param array<string,mixed> $item         Item data.
	 * @param string|false        $parent       Parent node id for add_node.
	 */
	private function add_one_node__premium_only( $wp_admin_bar, $id, $item, $parent ) {
		$title = isset( $item['title'] ) ? $item['title'] : '';
		$icon  = isset( $item['icon'] ) ? $item['icon'] : '';
		if ( ! empty( $item['parent'] ) ) {
			$icon = '';
		}
		$title = $this->build_title_html__premium_only( $title, $icon, $id );

		$href = isset( $item['href'] ) ? $item['href'] : '';
		if ( '' === $href ) {
			$href = false;
		}

		$meta = array();
		if ( ! empty( $item['meta_html'] ) ) {
			$meta['html'] = $item['meta_html'];
		}
		if ( ! empty( $item['meta_class'] ) ) {
			$meta['class'] = $item['meta_class'];
		}
		if ( ! empty( $item['meta_target'] ) ) {
			$meta['target'] = $item['meta_target'];
		}
		if ( ! empty( $item['meta_title'] ) ) {
			$meta['title'] = $item['meta_title'];
		}
		if ( ! empty( $item['meta_menu_title'] ) ) {
			$meta['menu_title'] = $item['meta_menu_title'];
		}

		$wp_admin_bar->add_node(
			array(
				'id'     => $id,
				'title'  => $title,
				'parent' => $parent,
				'href'   => $href,
				'meta'   => $meta,
			)
		);
	}

	/**
	 * Build title HTML with optional icon.
	 *
	 * @param string $text  Plain title.
	 * @param string $icon  Icon value.
	 * @param string $node_id Node id for SVG CSS.
	 */
	public function build_title_html__premium_only( $text, $icon, $node_id ) {
		$text = is_string( $text ) ? $text : '';
		$prefix = '';

		if ( is_string( $icon ) && '' !== trim( $icon ) ) {
			$icon = trim( $icon );
			if ( 0 === strpos( $icon, 'data:image/svg+xml' ) ) {
				if ( strlen( $icon ) > self::MAX_SVG_DATA_URI_BYTES ) {
					$icon = '';
				} else {
					$safe = esc_url( $icon, $this->get_icon_data_uri_protocols__premium_only() );
					if ( is_string( $safe ) && '' !== $safe ) {
						$url_in_css = esc_attr( $safe );
						$prefix       = '<span class="ab-icon asenha-abce-icon-svg" style="-webkit-mask-image:url(' . $url_in_css . ');mask-image:url(' . $url_in_css . ');"></span>';
					}
				}
			} else {
				$classes = sanitize_text_field( $icon );
				if ( preg_match( '/\bdashicons\b/', $classes ) ) {
					$prefix = '<span class="ab-icon ' . esc_attr( $classes ) . '"></span>';
				} else {
					$prefix = '<span class="ab-icon dashicons ' . esc_attr( $classes ) . '"></span>';
				}
			}
		}

		// Title may contain limited formatting.
		$text_html = wp_kses_post( $text );

		return $prefix . $text_html;
	}

	/**
	 * Inline CSS for the admin bar when custom elements are configured: Dashicon alignment in menupops,
	 * and when applicable mask/SVG icon sizing (currentColor) plus vertical nudge for SVG icons.
	 */
	public function print_svg_icon_css__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return;
		}

		$options = get_option( ASENHA_SLUG_U, array() );
		if ( empty( $options['admin_bar_custom_elements'] ) ) {
			return;
		}

		$config = $this->get_config__premium_only();
		if ( empty( $config['items'] ) || ! is_array( $config['items'] ) ) {
			return;
		}

		$has_svg_data_icon = false;
		foreach ( $config['items'] as $item ) {
			if ( empty( $item['icon'] ) || ! is_string( $item['icon'] ) ) {
				continue;
			}
			if ( 0 === strpos( $item['icon'], 'data:image/svg+xml' ) ) {
				$has_svg_data_icon = true;
				break;
			}
		}

		$css = '';

		// Nudge Dashicons in submenu parents (menupop) for better vertical alignment.
		$css .= '#wpadminbar .menupop > .ab-item > .ab-icon:before{top:2px;}';

		if ( $has_svg_data_icon ) {
			$css .= '#wpadminbar .ab-item .asenha-abce-icon-svg{width:20px;height:20px;display:inline-block;vertical-align:middle;position:relative;top:2px;color:inherit!important;background-color:currentColor;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;}';
		}

		echo '<style id="asenha-abce-admin-bar-icons">' . "\n" . $css . "\n" . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static CSS rule.
	}

	/**
	 * Localized data for the dedicated Settings screen script.
	 *
	 * @return array<string,mixed>
	 */
	public function get_localize_vars__premium_only() {
		if ( ! bwasenha_fs()->can_use_premium_code__premium_only() ) {
			return array();
		}

		return array(
			'saveNonce'              => wp_create_nonce( 'asenha-abce-save' ),
			'loadIconLibraryNonce'   => wp_create_nonce( 'load-icon-library-nonce' ),
			'asenhUrl'               => ASENHA_URL,
			'defaultNewItemRoleSlug' => self::DEFAULT_NEW_ITEM_ROLE_SLUG,
			'roleChoices'            => $this->get_abce_role_choices__premium_only(),
			'strings'                => array(
				'changeIcon'             => __( 'Choose Icon', 'admin-site-enhancements' ),
				'placeholderIcon'        => __( 'Dashicon class or SVG data URI', 'admin-site-enhancements' ),
				'searchIcon'             => __( 'Search…', 'admin-site-enhancements' ),
				'titleLabel'             => __( 'Title', 'admin-site-enhancements' ),
				'linkLabel'              => __( 'Link', 'admin-site-enhancements' ),
				'showOnLabel'            => __( 'Show on', 'admin-site-enhancements' ),
				'showForLabel'           => __( 'Show For', 'admin-site-enhancements' ),
				'roleFilterAll'          => __( 'All user roles', 'admin-site-enhancements' ),
				'roleFilterOnly'         => __( 'Only selected roles', 'admin-site-enhancements' ),
				'roleFilterExcept'       => __( 'All roles except selected', 'admin-site-enhancements' ),
				'rolesGroupAriaLabel'    => __( 'Roles', 'admin-site-enhancements' ),
				'roleFilterScopeInherit' => __( 'Inherit parent element settings', 'admin-site-enhancements' ),
				'roleFilterScopeCustom'  => __( 'Customize for this child element', 'admin-site-enhancements' ),
				'roleFilterScopeLabel'   => __( 'Child role filter scope', 'admin-site-enhancements' ),
				'visAdmin'               => __( 'Backend', 'admin-site-enhancements' ),
				'visFe'                  => __( 'Frontend', 'admin-site-enhancements' ),
				'visBoth'                => __( 'Backend and frontend', 'admin-site-enhancements' ),
				'iconLabel'              => __( 'Icon', 'admin-site-enhancements' ),
				'metaHtml'               => __( 'Meta: HTML', 'admin-site-enhancements' ),
				'metaClass'              => __( 'Meta: class', 'admin-site-enhancements' ),
				'metaTarget'             => __( 'Meta: target', 'admin-site-enhancements' ),
				'metaTitle'              => __( 'Meta: title (tooltip)', 'admin-site-enhancements' ),
				'metaMenuTitle'          => __( 'Meta: menu_title (ARIA)', 'admin-site-enhancements' ),
				'addChild'               => __( 'Add child element', 'admin-site-enhancements' ),
				'optionsLabel'           => __( 'Options', 'admin-site-enhancements' ),
				'submenuLabel'           => __( 'Submenu', 'admin-site-enhancements' ),
				'remove'                 => __( 'Remove', 'admin-site-enhancements' ),
				'confirmRemove'          => __( 'Remove this item?', 'admin-site-enhancements' ),
				'showAdvancedOptions'    => __( 'Show advanced options', 'admin-site-enhancements' ),
				'hideAdvancedOptions'    => __( 'Hide advanced options', 'admin-site-enhancements' ),
			),
		);
	}
}
