<?php
/**
 * Mersal Notifications — admin UI.
 *
 * Single-page admin app (sidebar / topbar / pages) on the shared Mersal design
 * system. Rules are created/edited through a normal form posting to admin-post;
 * sender settings save through the shared AJAX autosave bar.
 *
 * @package Mersal_Notif
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Mersal_Notif_Admin {

	/** @var Mersal_Notif_Core */
	private $core;

	/** @var Mersal_Notif_Connect */
	private $connect;

	/** @var string */
	private $save_bar_html = '';

	/** @var bool Whether we are rendering a page embedded inside the Mersal Suite shell. */
	private $embed = false;

	/** @var bool Whether the embedded CSS/JS assets were already printed this request. */
	private static $suite_assets_printed = false;

	/**
	 * @param Mersal_Notif_Core    $core    Engine.
	 * @param Mersal_Notif_Connect $connect Account / gateway.
	 */
	public function __construct( Mersal_Notif_Core $core, Mersal_Notif_Connect $connect ) {
		$this->core    = $core;
		$this->connect = $connect;
	}

	/**
	 * Hooks.
	 */
	public function init() {
		add_action( 'admin_menu', array( $this, 'register_menu' ) );
		add_action( 'admin_init', array( $this, 'redirect_legacy_menu' ), 1 );
		// When the Suite owns the menu, page=mersal-notifications is unregistered
		// and wp-admin dies 403 BEFORE admin_init — this hook fires just before
		// that wp_die, so legacy links 302 to the suite instead of a dead end.
		add_action( 'admin_page_access_denied', array( $this, 'redirect_legacy_menu' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
		add_action( 'admin_body_class', array( $this, 'body_class' ) );
		add_action( 'admin_init', array( $this, 'handle_prefs' ) );
		add_action( 'admin_post_mnotif_save_settings', array( $this, 'save_settings' ) );
		add_action( 'wp_ajax_mnotif_save_settings', array( $this, 'ajax_save_settings' ) );
		add_action( 'admin_post_mnotif_save_rule', array( $this, 'handle_save_rule' ) );
		add_action( 'wp_ajax_mnotif_admin_pref', array( $this, 'ajax_admin_pref' ) );
		add_action( 'wp_ajax_mnotif_notif_seen', array( $this, 'ajax_notif_seen' ) );
	}

	/* ------------------------------------------------------------------ */
	/* Plumbing                                                           */
	/* ------------------------------------------------------------------ */

	public function register_menu() {
		// Folded into the unified Mersal Suite menu when the Suite SDK is present.
		if ( class_exists( 'Mersal_Suite' ) ) {
			return;
		}
		$icon      = plugins_url( 'assets/img/icon.svg', MNOTIF_FILE );
		$icon_path = MNOTIF_DIR . 'assets/img/mersal.svg';
		if ( file_exists( $icon_path ) ) {
			$icon = 'data:image/svg+xml;base64,' . base64_encode( (string) file_get_contents( $icon_path ) ); // phpcs:ignore
		}
		add_menu_page(
			__( 'Mersal Notifications', 'mersal-notifications' ),
			__( 'Mersal Notifications', 'mersal-notifications' ),
			'manage_options',
			MNOTIF_MENU_SLUG,
			array( $this, 'render' ),
			$icon,
			58.2
		);
	}

	/**
	 * Map a legacy standalone sub-page id to its Mersal Suite route leaf.
	 *
	 * @param string $page Legacy `mnotif_page` value.
	 * @return string Suite leaf (without the `nt.` prefix).
	 */
	public static function suite_leaf( $page ) {
		$map = array(
			'dashboard' => 'dash',
			'rules'     => 'rules',
			'edit'      => 'edit',
			'events'    => 'events',
			'sending'   => 'sending',
			'cart'      => 'cart',
			'widget'    => 'widget',
			'emails'    => 'emails',
			'mersal'    => 'connect',
			'logs'      => 'logs',
			'updates'   => 'updates',
		);
		return isset( $map[ $page ] ) ? $map[ $page ] : 'dash';
	}

	/**
	 * Redirect legacy `page=mersal-notifications` URLs to the unified Suite route.
	 */
	public function redirect_legacy_menu() {
		if ( ! class_exists( 'Mersal_Suite' ) ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_GET['page'] ) || MNOTIF_MENU_SLUG !== $_GET['page'] ) {
			return;
		}
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page = isset( $_GET['mnotif_page'] ) ? sanitize_key( wp_unslash( $_GET['mnotif_page'] ) ) : 'dashboard';
		if ( 'mersal' === $page && class_exists( 'Mersal_Suite_Account' ) ) {
			$url = Mersal_Suite_Account::connect_url( 'nt' );
		} else {
			$url = Mersal_Suite::instance()->url( 'nt.' . self::suite_leaf( $page ) );
		}
		$passthrough = array( 'motp_tab', 'motp_sync_gateways', 'mnotif_sync_gateways', 'synced', '_wpnonce' );
		foreach ( $passthrough as $key ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( isset( $_GET[ $key ] ) ) {
				$val = 'motp_tab' === $key ? sanitize_key( wp_unslash( $_GET[ $key ] ) ) : sanitize_text_field( wp_unslash( $_GET[ $key ] ) );
				$url = add_query_arg( $key, $val, $url );
			}
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['id'] ) ) {
			$url = add_query_arg( 'id', (int) $_GET['id'], $url );
		}
		wp_safe_redirect( $url );
		exit;
	}

	private function is_our_screen() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return is_admin() && isset( $_GET['page'] ) && MNOTIF_MENU_SLUG === $_GET['page'];
	}

	public function enqueue( $hook ) {
		if ( ! $this->is_our_screen() && ! $this->is_suite_screen() ) {
			return;
		}
		wp_enqueue_media();
		wp_enqueue_style( 'mnotif-fonts', 'https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700;800&family=Cairo:wght@400;600;700;800&display=swap', array(), null );
	}

	/**
	 * Whether the current request is the unified Mersal Suite screen.
	 *
	 * @return bool
	 */
	private function is_suite_screen() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return is_admin() && isset( $_GET['page'] ) && 'mersal-suite' === $_GET['page'];
	}

	private function asset( $rel ) {
		$path = MNOTIF_DIR . ltrim( $rel, '/' );
		return file_exists( $path ) ? (string) file_get_contents( $path ) : ''; // phpcs:ignore
	}

	/**
	 * Extra component CSS (tiles, placeholder toolbar, preview). Scoped to .mnotif-app.
	 *
	 * @return string
	 */
	private function extra_styles() {
		return <<<CSS
.mnotif-app .flbl{display:block;font-size:12px;color:var(--fg-3);margin-bottom:6px;font-weight:600}
.mnotif-app .mnotif-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.mnotif-app .mnotif-tile{position:relative;display:flex;align-items:center;gap:10px;padding:12px;border:2px solid var(--border);border-radius:12px;cursor:pointer;background:var(--surface);transition:.15s}
.mnotif-app .mnotif-tile input{position:absolute;opacity:0;pointer-events:none}
.mnotif-app .mnotif-tile .ti{width:38px;height:38px;border-radius:10px;display:grid;place-items:center;background:var(--surface-3);color:var(--fg-1)}
.mnotif-app .mnotif-tile .tl b{font-size:14px}
.mnotif-app .mnotif-tile .tc{position:absolute;top:9px;inset-inline-end:9px;color:var(--accent);opacity:0;transition:.15s}
.mnotif-app .mnotif-tile.sel{border-color:var(--accent);background:var(--accent-soft)}
.mnotif-app .mnotif-tile.sel .ti{background:var(--accent);color:#fff}
.mnotif-app .mnotif-tile.sel .tc{opacity:1}
.mnotif-app .mnotif-ph{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:8px}
.mnotif-app .mnotif-ph .phl{font-size:12px;color:var(--fg-3)}
.mnotif-app .mnotif-ph .phb{border:1px solid var(--border);background:var(--surface);border-radius:999px;padding:3px 10px;font-size:12px;cursor:pointer;color:var(--fg-2)}
.mnotif-app .mnotif-ph .phb:hover{border-color:var(--accent);color:var(--accent-2)}
.mnotif-app .mnotif-preview{margin-top:12px;border:1px dashed var(--border);border-radius:12px;overflow:hidden}
.mnotif-app .mnotif-preview .pvh{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--surface-2);font-size:12px;color:var(--fg-2)}
.mnotif-app .mnotif-preview .pvb{padding:14px;white-space:pre-wrap;min-height:54px;font-size:14px;line-height:1.6}
.mnotif-app .mnotif-switch-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:6px 0 12px}
.mnotif-app .mnotif-admbox{border-top:1px solid var(--border);padding-top:12px;margin-top:4px}
.mnotif-app .mnotif-quality{margin-top:10px;padding:12px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
.mnotif-app .mnotif-quality .qbar{height:8px;border-radius:999px;background:var(--surface-3);overflow:hidden}
.mnotif-app .mnotif-quality .qfill{display:block;height:100%;width:0;transition:width .25s,background .25s}
.mnotif-app .mnotif-quality .qmeta{display:flex;justify-content:space-between;margin-top:8px;font-size:12px;color:var(--fg-2)}
.mnotif-app .mnotif-quality .qtips{margin:8px 0 0;padding-inline-start:18px;font-size:12px;color:var(--fg-2)}
.mnotif-app .mnotif-quality .qtips li{margin:2px 0}
.mnotif-app .mnotif-code{background:var(--surface-2);border:1px solid var(--border);border-radius:10px;padding:12px;font-size:12px;overflow:auto;white-space:pre}
.mnotif-app .mnotif-wiz{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:18px}
.mnotif-app .mnotif-wiz .wstep{display:flex;align-items:center;gap:8px;padding:8px 14px;border:1px solid var(--border);border-radius:999px;background:var(--surface);cursor:pointer;font-size:13px;color:var(--fg-2);transition:.15s}
.mnotif-app .mnotif-wiz .wstep .wn{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;background:var(--surface-3);color:var(--fg-2);font-weight:700;font-size:12px}
.mnotif-app .mnotif-wiz .wstep.active{border-color:var(--accent);color:var(--accent-2);background:var(--accent-soft)}
.mnotif-app .mnotif-wiz .wstep.active .wn{background:var(--accent);color:#fff}
.mnotif-app .mnotif-wiz .wstep.done .wn{background:var(--success,#16a34a);color:#fff}
.mnotif-app .mnotif-wnav{display:flex;align-items:center;gap:10px;margin-top:18px}
.mnotif-app .mnotif-wnav .sp{flex:1}
.mnotif-app .mnotif-review .rrow{display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-bottom:1px solid var(--border)}
.mnotif-app .mnotif-review .rrow span{color:var(--fg-3);font-size:13px}
.mnotif-app .mnotif-review .rrow b{text-align:end;max-width:65%}
/* Message step: editor + live preview side by side */
.mnotif-app .mnotif-msg-grid{display:grid;grid-template-columns:1fr minmax(260px,320px);gap:16px;align-items:start}
@media (max-width:900px){.mnotif-app .mnotif-msg-grid{grid-template-columns:1fr}}
.mnotif-app .mnotif-msg-main{min-width:0}
.mnotif-app .mnotif-preview.wa{margin-top:0}
.mnotif-app .mnotif-preview .pvh .pv-tag{margin-inline-start:auto;font-size:10px;font-weight:700;color:var(--accent-2);background:var(--accent-soft);border-radius:999px;padding:2px 8px}
.mnotif-app .mnotif-preview .pvh{display:flex;align-items:center;gap:6px}
.mnotif-app .wa-surface{background:#0b141a;background-image:radial-gradient(rgba(255,255,255,.04) 1px,transparent 0);background-size:18px 18px;padding:16px 12px;min-height:120px;display:flex}
.mnotif-app .wa-bubble{position:relative;max-width:90%;margin-inline-start:auto;align-self:flex-start;background:#005c4b;color:#e9edef;border-radius:10px;border-top-inline-end-radius:2px;padding:7px 10px 5px;font-size:13.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word;box-shadow:0 1px 1px rgba(0,0,0,.25)}
.mnotif-app .wa-bubble .wa-time{display:block;text-align:end;font-size:10px;color:#8fb9ad;margin-top:3px;direction:ltr}
/* Message acceptance analyzer */
/* Alternative wordings (anti-ban message rotation) */
.mnotif-app .mnotif-var-modes{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-bottom:14px}
@media (max-width:900px){.mnotif-app .mnotif-var-modes{grid-template-columns:1fr}}
.mnotif-app .mnotif-var-mode{border:1.5px solid var(--border);border-radius:12px;padding:12px 13px;cursor:pointer;background:var(--surface);transition:border-color .14s,background .14s;display:block}
.mnotif-app .mnotif-var-mode input{position:absolute;opacity:0;width:0;height:0}
.mnotif-app .mnotif-var-mode .mi{font-size:20px;color:var(--fg-3);display:block;margin-bottom:5px}
.mnotif-app .mnotif-var-mode b{display:block;font-size:13px;color:var(--fg-1)}
.mnotif-app .mnotif-var-mode .d{display:block;font-size:11.5px;color:var(--fg-3);margin-top:2px;line-height:1.5}
.mnotif-app .mnotif-var-mode.is-on{border-color:var(--accent);background:var(--accent-soft)}
.mnotif-app .mnotif-var-mode.is-on .mi{color:var(--accent)}
.mnotif-app .mnotif-var{border:1px solid var(--border);border-radius:12px;padding:12px;margin-bottom:10px;background:var(--surface-2)}
.mnotif-app .mnotif-var.is-main{background:var(--surface);border-style:dashed}
.mnotif-app .mnotif-var-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:8px}
.mnotif-app .mnotif-var-top b{font-size:12.5px;color:var(--fg-1)}
.mnotif-app .mnotif-var-top .btn{margin-inline-start:auto}
.mnotif-app .mnotif-var-pin{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--fg-2);cursor:pointer}
.mnotif-app .mnotif-var-note{font-size:11.5px;color:var(--fg-3)}
.mnotif-app .mnotif-az{margin-top:14px;border:1px solid var(--border);border-radius:14px;background:var(--surface);overflow:hidden}
.mnotif-app .mnotif-az-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:13px 16px;border-bottom:1px solid var(--border)}
.mnotif-app .mnotif-az-gauge{display:flex;align-items:center;gap:10px}
.mnotif-app .mnotif-az-gauge .g{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;font-weight:800;font-size:13px;color:#fff;background:conic-gradient(var(--accent) 0,var(--surface-3) 0)}
.mnotif-app .mnotif-az-gauge .gl b{display:block;font-size:13px;color:var(--fg-1)}
.mnotif-app .mnotif-az-gauge .gl span{font-size:11px;color:var(--fg-3)}
.mnotif-app .mnotif-az-counts{display:flex;gap:14px;font-size:12px;font-weight:700}
.mnotif-app .mnotif-az-counts i{font-style:normal}
.mnotif-app .mnotif-az-counts .pass{color:#16a34a}
.mnotif-app .mnotif-az-counts .fail{color:#dc2626}
.mnotif-app .mnotif-az-ms{margin-inline-start:auto;font-size:10.5px;font-weight:700;letter-spacing:.05em;color:var(--fg-3);text-transform:uppercase}
.mnotif-app .mnotif-az-bar{flex-basis:100%;height:6px;border-radius:999px;background:var(--surface-3);overflow:hidden}
.mnotif-app .mnotif-az-bar span{display:block;height:100%;width:0;background:var(--accent);transition:width .3s,background .3s}
.mnotif-app .mnotif-az-cat{border-bottom:1px solid var(--border)}
.mnotif-app .mnotif-az-cat:last-child{border-bottom:0}
.mnotif-app .mnotif-az-cat-h{display:flex;align-items:center;gap:8px;padding:12px 16px;cursor:pointer;user-select:none;font-weight:800;font-size:13px;color:var(--fg-1)}
.mnotif-app .mnotif-az-cat-h .chev{transition:transform .2s;color:var(--fg-3);font-size:18px}
.mnotif-app .mnotif-az-cat.collapsed .chev{transform:rotate(-90deg)}
.mnotif-app .mnotif-az-cat.collapsed .mnotif-az-checks{display:none}
.mnotif-app .mnotif-az-cat-h .cbadge{margin-inline-start:auto;font-size:9.5px;font-weight:800;letter-spacing:.04em;padding:2px 8px;border-radius:6px;text-transform:uppercase}
.mnotif-app .mnotif-az-cat-h .cbadge.ok{color:#16a34a;background:rgba(22,163,74,.12)}
.mnotif-app .mnotif-az-cat-h .cbadge.iss{color:#dc2626;background:rgba(220,38,38,.12)}
.mnotif-app .mnotif-az-checks{padding:2px 16px 12px}
.mnotif-app .mnotif-az-chk{padding:7px 0;border-top:1px solid var(--surface-3)}
.mnotif-app .mnotif-az-chk:first-child{border-top:0}
.mnotif-app .mnotif-az-chk .row{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--fg-2)}
.mnotif-app .mnotif-az-chk .ci{flex:0 0 18px;width:18px;height:18px;border-radius:50%;display:grid;place-items:center;font-size:13px}
.mnotif-app .mnotif-az-chk.pass .ci{color:#16a34a}
.mnotif-app .mnotif-az-chk.warn .ci{color:#d97706}
.mnotif-app .mnotif-az-chk.fail .ci{color:#dc2626}
.mnotif-app .mnotif-az-fix{margin:6px 0 0;margin-inline-start:27px;display:flex;gap:7px;align-items:flex-start;font-size:12px;line-height:1.5;padding:8px 10px;border-radius:9px}
.mnotif-app .mnotif-az-fix .fi{flex:0 0 auto;font-size:15px;margin-top:1px}
.mnotif-app .mnotif-az-chk.warn .mnotif-az-fix{background:rgba(217,119,6,.08);color:#92600a}
.mnotif-app .mnotif-az-chk.fail .mnotif-az-fix{background:rgba(220,38,38,.08);color:#a51f1f}
.mnotif-app[data-dark="true"] .mnotif-az-chk.warn .mnotif-az-fix{color:#f0b04a}
.mnotif-app[data-dark="true"] .mnotif-az-chk.fail .mnotif-az-fix{color:#f08a82}
/* ---- Section rhythm: breathing room between stacked cards ---- */
.mnotif-app .page > .card + .card,
.mnotif-app .page > form > .card + .card,
.mnotif-app form.mnotif-settings-form > .card + .card,
.mnotif-app .mnotif-step > .card + .card{margin-top:18px}
/* ---- Wizard header: stronger, clearer ---- */
.mnotif-app .mnotif-wiz{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:20px;padding:10px;background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:var(--shadow-sm)}
.mnotif-app .mnotif-wiz .wstep{flex:1;min-width:130px;justify-content:center;display:flex;align-items:center;gap:9px;padding:11px 12px;border:1.5px solid transparent;border-radius:12px;background:transparent;cursor:pointer;font-size:13px;font-weight:700;color:var(--fg-3);transition:.15s}
.mnotif-app .mnotif-wiz .wstep:hover{background:var(--surface-3);color:var(--fg-1)}
.mnotif-app .mnotif-wiz .wstep .wn{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;background:var(--surface-3);color:var(--fg-2);font-weight:800;font-size:12px;flex:0 0 24px}
.mnotif-app .mnotif-wiz .wstep.active{border-color:var(--accent);color:var(--accent-2);background:var(--accent-soft)}
.mnotif-app .mnotif-wiz .wstep.active .wn{background:var(--accent);color:#fff}
.mnotif-app .mnotif-wiz .wstep.done{color:#16a34a}
.mnotif-app .mnotif-wiz .wstep.done .wn{background:#16a34a;color:#fff;font-size:0}
.mnotif-app .mnotif-wiz .wstep.done .wn::before{content:'✓';font-size:12px}
/* ---- Event picker (wizard step 1) ---- */
.mnotif-app .ntp-top{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
.mnotif-app .ntp-cats{display:flex;gap:7px;flex-wrap:wrap;flex:1;min-width:220px}
.mnotif-app .ntp-chip{display:inline-flex;align-items:center;gap:7px;padding:8px 13px;border:1.5px solid var(--border);border-radius:999px;background:var(--surface);cursor:pointer;font-size:12.5px;font-weight:700;color:var(--fg-2);transition:.15s;user-select:none}
.mnotif-app .ntp-chip .mi{width:16px;height:16px}
.mnotif-app .ntp-chip .cnt{font-size:10.5px;font-weight:800;background:var(--surface-3);color:var(--fg-3);border-radius:999px;padding:1px 7px}
.mnotif-app .ntp-chip:hover{border-color:var(--accent);color:var(--accent-2)}
.mnotif-app .ntp-chip.sel{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-2)}
.mnotif-app .ntp-chip.sel .cnt{background:var(--accent);color:#fff}
.mnotif-app .ntp-search{position:relative;flex:0 1 240px;min-width:180px}
.mnotif-app .ntp-search .mi{position:absolute;inset-inline-start:11px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--fg-3);pointer-events:none}
.mnotif-app .ntp-search input{width:100%;padding:9px 12px;padding-inline-start:34px;border:1.5px solid var(--border);border-radius:11px;background:var(--surface);color:var(--fg-1);font-size:13px}
.mnotif-app .ntp-search input:focus{outline:none;border-color:var(--accent)}
.mnotif-app .ntp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:10px}
.mnotif-app .ntp-card{position:relative;display:flex;gap:11px;align-items:flex-start;padding:13px;border:1.5px solid var(--border);border-radius:13px;background:var(--surface);cursor:pointer;transition:border-color .15s,box-shadow .15s,transform .1s;user-select:none}
.mnotif-app .ntp-card:hover{border-color:var(--accent);box-shadow:var(--shadow-sm);transform:translateY(-1px)}
.mnotif-app .ntp-card .ei{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;background:var(--surface-3);color:var(--fg-2);flex:0 0 36px;transition:.15s}
.mnotif-app .ntp-card b{display:block;font-size:13px;color:var(--fg-1);line-height:1.35}
.mnotif-app .ntp-card .ed{display:block;font-size:11.5px;color:var(--fg-3);margin-top:3px;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.mnotif-app .ntp-card .ck{position:absolute;top:9px;inset-inline-end:9px;width:20px;height:20px;border-radius:50%;border:1.5px solid var(--border);display:grid;place-items:center;font-size:0;color:#fff;background:transparent;transition:.15s}
.mnotif-app .ntp-card.sel{border-color:var(--accent);background:var(--accent-soft);box-shadow:0 2px 10px color-mix(in srgb,var(--accent) 20%,transparent)}
.mnotif-app .ntp-card.sel .ei{background:var(--accent);color:#fff}
.mnotif-app .ntp-card.sel .ck{background:var(--accent);border-color:var(--accent);font-size:12px}
.mnotif-app .ntp-card.sel .ck::before{content:'✓'}
.mnotif-app .ntp-card .evdel{position:absolute;bottom:8px;inset-inline-end:9px;width:22px;height:22px;border:none;border-radius:7px;background:transparent;color:var(--fg-3);cursor:pointer;display:grid;place-items:center;padding:0}
.mnotif-app .ntp-card .evdel:hover{background:rgba(220,38,38,.1);color:#dc2626}
.mnotif-app .ntp-card .evdel .mi{width:14px;height:14px}
.mnotif-app .ntp-empty{grid-column:1/-1;text-align:center;padding:26px;color:var(--fg-3);font-size:13px}
.mnotif-app .ntp-addrow{display:flex;gap:8px;align-items:center;margin-top:14px;padding:12px;border:1.5px dashed var(--border);border-radius:13px;background:var(--surface-2)}
.mnotif-app .ntp-addrow input{flex:1;min-width:0;padding:9px 12px;border:1.5px solid var(--border);border-radius:10px;background:var(--surface);color:var(--fg-1);font-size:13px}
.mnotif-app .ntp-dev{margin-top:10px}
.mnotif-app .ntp-dev summary{cursor:pointer;font-size:12.5px;font-weight:700;color:var(--fg-2);padding:6px 2px;user-select:none}
/* ---- Choice cards (radio choices as cards, used across settings pages) ---- */
.mnotif-app .mnotif-choice{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:9px;margin:2px 0 4px}
.mnotif-app .mnotif-choice .chc{position:relative;display:flex;gap:10px;align-items:center;padding:12px;border:1.5px solid var(--border);border-radius:12px;background:var(--surface);cursor:pointer;transition:.15s;user-select:none}
.mnotif-app .mnotif-choice .chc:hover{border-color:var(--accent)}
.mnotif-app .mnotif-choice .chc input{position:absolute;opacity:0;pointer-events:none}
.mnotif-app .mnotif-choice .chc .ci2{width:32px;height:32px;border-radius:9px;display:grid;place-items:center;background:var(--surface-3);color:var(--fg-2);flex:0 0 32px;transition:.15s}
.mnotif-app .mnotif-choice .chc b{display:block;font-size:12.5px;color:var(--fg-1);line-height:1.3}
.mnotif-app .mnotif-choice .chc small{display:block;font-size:11px;color:var(--fg-3);margin-top:2px}
.mnotif-app .mnotif-choice .chc .ck{margin-inline-start:auto;width:18px;height:18px;border-radius:50%;border:1.5px solid var(--border);display:grid;place-items:center;font-size:0;color:#fff;flex:0 0 18px;transition:.15s}
.mnotif-app .mnotif-choice .chc.sel{border-color:var(--accent);background:var(--accent-soft)}
.mnotif-app .mnotif-choice .chc.sel .ci2{background:var(--accent);color:#fff}
.mnotif-app .mnotif-choice .chc.sel .ck{background:var(--accent);border-color:var(--accent);font-size:11px}
.mnotif-app .mnotif-choice .chc.sel .ck::before{content:'✓'}
/* ---- Collapsible embedded email builder (wizard message step) ---- */
.mnotif-app .mnotif-eb-fold > summary::-webkit-details-marker{display:none}
.mnotif-app .mnotif-eb-fold > summary{border-bottom:none}
.mnotif-app .mnotif-eb-fold[open] > summary{border-bottom:1px solid var(--border)}
.mnotif-app .mnotif-eb-fold .fold-chev{transition:transform .2s}
.mnotif-app .mnotif-eb-fold[open] .fold-chev{transform:rotate(180deg)}
CSS;
	}

	public function body_class( $classes ) {
		if ( $this->is_our_screen() ) {
			$classes .= ' mnotif-screen';
		}
		return $classes;
	}

	private function current_page() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$p = isset( $_GET['mnotif_page'] ) ? sanitize_key( wp_unslash( $_GET['mnotif_page'] ) ) : 'dashboard';
		return $p ? $p : 'dashboard';
	}

	private function page_url( $page ) {
		if ( $this->embed && class_exists( 'Mersal_Suite' ) ) {
			return Mersal_Suite::instance()->url( 'nt.' . self::suite_leaf( $page ) );
		}
		return admin_url( 'admin.php?page=' . MNOTIF_MENU_SLUG . '&mnotif_page=' . $page );
	}

	/* ------------------------------------------------------------------ */
	/* Preferences                                                        */
	/* ------------------------------------------------------------------ */

	public function handle_prefs() {
		if ( ! $this->is_our_screen() || ! current_user_can( 'manage_options' ) ) {
			return;
		}
		if ( '1' !== get_option( 'mnotif_light_default_applied' ) ) {
			Mersal_Notif_Settings::update( array( 'theme' => 'light' ) );
			update_option( 'mnotif_light_default_applied', '1' );
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_GET['mnotif_pref'] ) ) {
			return;
		}
		check_admin_referer( 'mnotif_pref' );
		wp_safe_redirect( remove_query_arg( array( 'mnotif_pref', 'mnotif_val', '_wpnonce' ) ) );
		exit;
	}

	public function ajax_admin_pref() {
		check_ajax_referer( 'mnotif_pref', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
		}
		$pref = isset( $_POST['pref'] ) ? sanitize_key( wp_unslash( $_POST['pref'] ) ) : '';
		$val  = isset( $_POST['val'] ) ? sanitize_text_field( wp_unslash( $_POST['val'] ) ) : '';
		if ( 'lang' === $pref && in_array( $val, array( 'ar', 'en' ), true ) ) {
			Mersal_Notif_Settings::update( array( 'lang' => $val ) );
		} elseif ( 'dark' === $pref ) {
			Mersal_Notif_Settings::update( array( 'dark' => ( '1' === $val ) ? 1 : 0 ) );
		} else {
			wp_send_json_error( array( 'message' => 'invalid' ), 400 );
		}
		$s = Mersal_Notif_Settings::all();
		wp_send_json_success( array( 'lang' => $s['lang'], 'dark' => ! empty( $s['dark'] ) ) );
	}

	public function ajax_notif_seen() {
		check_ajax_referer( 'mnotif_notif', 'nonce' );
		if ( current_user_can( 'manage_options' ) ) {
			update_user_meta( get_current_user_id(), 'mnotif_notif_seen', time() );
		}
		wp_send_json_success();
	}

	/* ------------------------------------------------------------------ */
	/* Save                                                               */
	/* ------------------------------------------------------------------ */

	public function save_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You are not allowed to do this.', 'mersal-notifications' ) );
		}
		check_admin_referer( 'mnotif_save_settings', 'mnotif_nonce' );
		$page = $this->persist_settings();
		wp_safe_redirect( add_query_arg( 'updated', '1', $this->page_url( $page ) ) );
		exit;
	}

	public function ajax_save_settings() {
		check_ajax_referer( 'mnotif_save_settings', 'mnotif_nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
		}
		$page = $this->persist_settings();
		wp_send_json_success( array( 'page' => $page, 'message' => __( 'Settings saved.', 'mersal-notifications' ) ) );
	}

	private function persist_settings() {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- caller verifies nonce.
		$raw = isset( $_POST['mnotif'] ) && is_array( $_POST['mnotif'] ) ? wp_unslash( $_POST['mnotif'] ) : array();
		Mersal_Notif_Settings::update( $raw );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$page = isset( $_POST['mnotif_page'] ) ? sanitize_key( wp_unslash( $_POST['mnotif_page'] ) ) : 'sending';
		return $page ? $page : 'sending';
	}

	public function handle_save_rule() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You are not allowed to do this.', 'mersal-notifications' ) );
		}
		check_admin_referer( 'mnotif_save_rule', 'mnotif_nonce' );
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- verified above.
		$res = $this->core->save_rule( wp_unslash( $_POST ) );
		if ( ! empty( $res['ok'] ) ) {
			wp_safe_redirect( add_query_arg( 'saved', '1', $this->page_url( 'rules' ) ) );
		} else {
			wp_safe_redirect( add_query_arg( 'error', rawurlencode( $res['message'] ?? '1' ), $this->page_url( 'edit' ) ) );
		}
		exit;
	}

	/* ------------------------------------------------------------------ */
	/* Shell                                                              */
	/* ------------------------------------------------------------------ */

	public function render() {
		$s     = Mersal_Notif_Settings::all();
		$theme = $s['theme'];
		$lang  = $s['lang'];
		$dir   = 'ar' === $lang ? 'rtl' : 'ltr';
		$page  = $this->current_page();
		$dark  = ! empty( $s['dark'] ) ? 'true' : 'false';
		$font  = in_array( $s['ui_font'] ?? 'tajawal', array( 'tajawal', 'cairo', 'system' ), true ) ? $s['ui_font'] : 'tajawal';
		$en    = ( 'en' === $lang );

		echo "\n<style id=\"mnotif-admin-css\">\n" . $this->asset( 'assets/css/admin.css' ) . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo "\n<style id=\"mnotif-extra-css\">\n" . $this->extra_styles() . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

		$cfg = array(
			'ajax'       => admin_url( 'admin-ajax.php' ),
			'nonce'      => wp_create_nonce( 'mnotif_pref' ),
			'saveNonce'  => wp_create_nonce( 'mnotif_save_settings' ),
			'notifNonce' => wp_create_nonce( 'mnotif_notif' ),
			'shell'      => $this->page_url( $page ),
			'lang'       => $lang,
			'dark'       => ! empty( $s['dark'] ),
			'i18n'       => array(
				'discard' => $en ? 'Discard' : 'تجاهل',
				'save'    => $en ? 'Save changes' : 'حفظ التغييرات',
				'saving'  => $en ? 'Saving…' : 'جاري الحفظ…',
				'saved'   => $en ? 'All changes saved' : 'كل التغييرات محفوظة',
				'unsaved' => $en ? 'You have unsaved changes' : 'لديك تغييرات غير محفوظة',
			),
		);
		echo '<script>window.MNOTIF_ADMIN=' . wp_json_encode( $cfg ) . ';</script>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

		echo '<div class="mnotif-app" data-theme="' . esc_attr( $theme ) . '" data-dark="' . esc_attr( $dark ) . '" data-font="' . esc_attr( $font ) . '" dir="' . esc_attr( $dir ) . '" data-collapsed="false">';
		$this->sidebar( $page, $lang );

		echo '<div class="main">';
		$this->topbar( $page, $lang );
		echo '<div class="page scroll">';
		$this->render_page_body( $page, $s, $lang );
		echo '</div></div></div>';

		echo "\n<script id=\"mnotif-icons-js\">\n" . Mersal_Notif_Icons::inline_script() . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo "\n<script id=\"mnotif-admin-js\">\n" . $this->asset( 'assets/js/admin.js' ) . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Render a single sub-page body (cards/forms only — no shell chrome).
	 *
	 * @param string $page Sub-page id.
	 * @param array  $s    Settings.
	 * @param string $lang Language.
	 */
	private function render_page_body( $page, $s, $lang ) {
		switch ( $page ) {
			case 'rules':
				$this->page_rules( $lang );
				break;
			case 'edit':
				$this->page_edit( $s, $lang );
				break;
			case 'sending':
				$this->page_sending( $s, $lang );
				break;
			case 'cart':
				$this->page_cart( $s, $lang );
				break;
			case 'widget':
				$this->page_widget( $s, $lang );
				break;
			case 'emails':
				$this->page_emails( $s, $lang );
				break;
			case 'mersal':
				$this->page_mersal( $s, $lang );
				break;
			case 'events':
				$this->page_events( $lang );
				break;
			case 'logs':
				$this->page_logs( $lang );
				break;
			case 'updates':
				Mersal_Notif_Updater::instance()->render_admin_page( $lang );
				break;
			case 'dashboard':
			default:
				$this->page_dashboard( $s, $lang );
		}
	}

	/**
	 * Render a legacy sub-page embedded inside the Mersal Suite shell.
	 *
	 * @param string            $page Standalone sub-page id.
	 * @param Mersal_Suite|null $ctx  Suite context.
	 */
	public function render_suite_page( $page, $ctx = null ) {
		$s    = Mersal_Notif_Settings::all();
		$lang = ( $ctx && method_exists( $ctx, 'lang' ) ) ? $ctx->lang() : $s['lang'];
		$en   = ( 'en' === $lang );
		$dir  = 'ar' === $lang ? 'rtl' : 'ltr';
		$font = in_array( $s['ui_font'] ?? 'tajawal', array( 'tajawal', 'cairo', 'system' ), true ) ? $s['ui_font'] : 'tajawal';
		$dark = ! empty( $s['dark'] ) ? 'true' : 'false';

		$this->embed = true;

		if ( ! self::$suite_assets_printed ) {
			self::$suite_assets_printed = true;

			echo "\n<style id=\"mnotif-admin-css\">\n" . $this->asset( 'assets/css/admin.css' ) . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo "\n<style id=\"mnotif-extra-css\">\n" . $this->extra_styles() . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo '<style id="mnotif-embed-css">'
				. '.mersal-suite-app .mnotif-embed{display:block;min-height:0;height:auto;overflow:visible;background:transparent;width:100%;}'
				. '.mersal-suite-app .mnotif-embed .main{display:block;min-height:0;height:auto;overflow:visible;}'
				. '.mersal-suite-app .mnotif-embed .page,.mersal-suite-app .mnotif-embed .page.scroll{display:block;overflow:visible;min-height:0;padding:0;}'
				. '.mersal-suite-app .mnotif-embed .savebar{margin:18px 0 0;border:1px solid var(--border);border-radius:14px;bottom:16px;}'
				. '</style>';

			$cfg = array(
				'ajax'       => admin_url( 'admin-ajax.php' ),
				'nonce'      => wp_create_nonce( 'mnotif_pref' ),
				'saveNonce'  => wp_create_nonce( 'mnotif_save_settings' ),
				'notifNonce' => wp_create_nonce( 'mnotif_notif' ),
				'shell'      => $ctx ? $ctx->url( 'nt.' . self::suite_leaf( $page ) ) : '',
				'lang'       => $lang,
				'dark'       => ! empty( $s['dark'] ),
				'embedded'   => true,
				'i18n'       => array(
					'discard' => $en ? 'Discard' : 'تجاهل',
					'save'    => $en ? 'Save changes' : 'حفظ التغييرات',
					'saving'  => $en ? 'Saving…' : 'جاري الحفظ…',
					'saved'   => $en ? 'All changes saved' : 'كل التغييرات محفوظة',
					'unsaved' => $en ? 'You have unsaved changes' : 'لديك تغييرات غير محفوظة',
				),
			);
			echo '<script>window.MNOTIF_ADMIN=' . wp_json_encode( $cfg ) . ';</script>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo "\n<script id=\"mnotif-icons-js\">\n" . Mersal_Notif_Icons::inline_script() . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo "\n<script id=\"mnotif-admin-js\">\n" . $this->asset( 'assets/js/admin.js' ) . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}

		echo '<div class="mnotif-app mnotif-embed" data-theme="light" data-dark="' . esc_attr( $dark ) . '" data-font="' . esc_attr( $font ) . '" dir="' . esc_attr( $dir ) . '">';
		echo '<div class="page scroll">';
		$this->render_page_body( $page, $s, $lang );
		echo '</div></div>';

		$this->embed = false;
	}

	private function sidebar( $active, $lang ) {
		$en  = ( 'en' === $lang );
		$nav = array(
			array(
				'group' => $en ? 'Overview' : 'نظرة عامة',
				'items' => array(
					array( 'id' => 'dashboard', 'icon' => 'dashboard', 'label' => $en ? 'Dashboard' : 'الرئيسية' ),
				),
			),
			array(
				'group' => $en ? 'Notifications' : 'الإشعارات',
				'items' => array(
					array( 'id' => 'rules', 'icon' => 'notifications', 'label' => $en ? 'Notification rules' : 'قواعد الإشعارات' ),
					array( 'id' => 'edit', 'icon' => 'add_circle', 'label' => $en ? 'New rule' : 'قاعدة جديدة' ),
				),
			),
			array(
				'group' => $en ? 'Growth tools' : 'أدوات النمو',
				'items' => array(
					array( 'id' => 'cart', 'icon' => 'shopping_cart', 'label' => $en ? 'Abandoned carts' : 'السلات المتروكة' ),
					array( 'id' => 'widget', 'icon' => 'chat', 'label' => $en ? 'Chat widget' : 'ودجت الواتساب' ),
				),
			),
			array(
				'group' => $en ? 'Sending channels' : 'قنوات الإرسال',
				'items' => array(
					array( 'id' => 'mersal', 'icon' => 'hub', 'label' => $en ? 'Connect Mersal' : 'ربط حساب مرسال' ),
					array( 'id' => 'sending', 'icon' => 'tune', 'label' => $en ? 'Sender settings' : 'إعدادات الإرسال' ),
				),
			),
			array(
				'group' => $en ? 'Data' : 'البيانات',
				'items' => array(
					array( 'id' => 'logs', 'icon' => 'list_alt', 'label' => $en ? 'Activity log' : 'سجل النشاط' ),
					array( 'id' => 'updates', 'icon' => 'system_update_alt', 'label' => $en ? 'Updates' : 'التحديثات' ),
				),
			),
		);

		echo '<aside class="sidebar">';
		echo '<div class="side-brand"><div class="logo">م</div><div class="name"><b>' . ( $en ? 'Mersal Notifications' : 'مرسال للإشعارات' ) . '</b><span>' . ( $en ? 'Automated alerts' : 'تنبيهات تلقائية' ) . '</span></div><div class="ver">v' . esc_html( MNOTIF_VERSION ) . '</div></div>';
		echo '<nav class="side-nav scroll">';
		foreach ( $nav as $g ) {
			echo '<div><div class="side-group">' . esc_html( $g['group'] ) . '</div>';
			foreach ( $g['items'] as $it ) {
				$cls = 'side-link' . ( $active === $it['id'] ? ' active' : '' );
				echo '<a class="' . esc_attr( $cls ) . '" href="' . esc_url( $this->page_url( $it['id'] ) ) . '"><span class="mi">' . esc_html( $it['icon'] ) . '</span><span>' . esc_html( $it['label'] ) . '</span></a>';
			}
			echo '</div>';
		}
		echo '</nav>';

		$connected = $this->connect->is_connected();
		echo '<div class="side-foot"><a class="side-account" href="' . esc_url( $this->page_url( 'mersal' ) ) . '">';
		if ( $connected ) {
			echo '<div class="av">' . esc_html( $this->connect->account_initials() ) . '</div>';
			$host = wp_parse_url( $this->connect->site_url(), PHP_URL_HOST );
			echo '<div class="info"><b>' . esc_html( $this->connect->account_name() ? $this->connect->account_name() : ( $en ? 'Mersal account' : 'حساب مرسال' ) ) . '</b><span>' . esc_html( $host ? $host : 'mersal.it' ) . ' · ' . ( $en ? 'Connected' : 'متصل' ) . '</span></div>';
		} else {
			echo '<div class="av">م</div><div class="info"><b>' . ( $en ? 'Connect Mersal' : 'ربط حساب مرسال' ) . '</b><span>' . ( $en ? 'Open account settings' : 'افتح صفحة الربط' ) . '</span></div>';
		}
		echo '<div class="dot" style="background:' . ( $connected ? 'var(--success)' : 'var(--fg-3)' ) . ';"></div></a></div>';
		echo '</aside>';
	}

	private function topbar( $page, $lang ) {
		$en      = ( 'en' === $lang );
		$titles  = $this->page_titles( $lang );
		$meta    = $titles[ $page ] ?? array( $en ? 'Overview' : 'نظرة عامة', $en ? 'Dashboard' : 'الرئيسية' );
		$is_dark = (bool) Mersal_Notif_Settings::get( 'dark' );
		$brand   = $en ? 'Mersal Notifications' : 'مرسال للإشعارات';

		echo '<div class="topbar">';
		echo '<button class="icon-btn" data-collapse title="Toggle"><span class="mi">menu_open</span></button>';
		echo '<div class="crumbs"><span>' . esc_html( $brand ) . '</span><span class="mi sep sm">chevron_right</span><span>' . esc_html( $meta[0] ) . '</span><span class="mi sep sm">chevron_right</span><b>' . esc_html( $meta[1] ) . '</b></div>';
		echo '<div class="top-actions">';
		echo '<div class="lang-pill"><span class="mi sm">language</span><button type="button" class="seg ' . ( $en ? 'on' : '' ) . '" data-mnotif-pref-lang="en">EN</button><button type="button" class="seg ' . ( $en ? '' : 'on' ) . '" data-mnotif-pref-lang="ar">عربي</button></div>';
		echo '<button type="button" class="icon-btn" data-mnotif-pref-dark aria-pressed="' . ( $is_dark ? 'true' : 'false' ) . '"><span class="mi">' . ( $is_dark ? 'light_mode' : 'dark_mode' ) . '</span></button>';
		echo '<a class="btn primary" href="' . esc_url( $this->page_url( 'edit' ) ) . '"><span class="mi sm">add</span>' . ( $en ? 'New rule' : 'قاعدة جديدة' ) . '</a>';
		echo '</div></div>';
	}

	private function page_titles( $lang ) {
		$en = ( 'en' === $lang );
		return array(
			'dashboard' => array( $en ? 'Overview' : 'نظرة عامة', $en ? 'Dashboard' : 'الرئيسية' ),
			'rules'     => array( $en ? 'Notifications' : 'الإشعارات', $en ? 'Notification rules' : 'قواعد الإشعارات' ),
			'edit'      => array( $en ? 'Notifications' : 'الإشعارات', $en ? 'New rule' : 'قاعدة جديدة' ),
			'events'    => array( $en ? 'Notifications' : 'الإشعارات', $en ? 'Custom events' : 'أحداث مخصّصة' ),
			'cart'      => array( $en ? 'Growth tools' : 'أدوات النمو', $en ? 'Abandoned carts' : 'السلات المتروكة' ),
			'widget'    => array( $en ? 'Growth tools' : 'أدوات النمو', $en ? 'Chat widget' : 'ودجت الواتساب' ),
			'emails'    => array( $en ? 'Sending channels' : 'قنوات الإرسال', $en ? 'Email builder' : 'بيلدر الإيميل' ),
			'mersal'    => array( $en ? 'Sending channels' : 'قنوات الإرسال', $en ? 'Connect Mersal' : 'ربط حساب مرسال' ),
			'sending'   => array( $en ? 'Sending channels' : 'قنوات الإرسال', $en ? 'Sender settings' : 'إعدادات الإرسال' ),
			'logs'      => array( $en ? 'Data' : 'البيانات', $en ? 'Activity log' : 'سجل النشاط' ),
			'updates'   => array( $en ? 'Data' : 'البيانات', $en ? 'Updates' : 'التحديثات' ),
		);
	}

	/* ------------------------------------------------------------------ */
	/* Page: Dashboard                                                    */
	/* ------------------------------------------------------------------ */

	private function page_dashboard( $s, $lang ) {
		$en  = ( 'en' === $lang );
		$ov  = $this->core->get_overview();
		$log = $this->core->get_log( 6 );

		$this->page_head(
			$en ? 'Dashboard' : 'الرئيسية',
			$en ? 'A live overview of your automated notifications.' : 'نظرة حيّة على إشعاراتك التلقائية.',
			'<a class="btn" href="' . esc_url( $this->page_url( 'rules' ) ) . '"><span class="mi sm">notifications</span>' . ( $en ? 'Rules' : 'القواعد' ) . '</a><a class="btn primary" href="' . esc_url( $this->page_url( 'edit' ) ) . '"><span class="mi sm">add</span>' . ( $en ? 'New rule' : 'قاعدة جديدة' ) . '</a>'
		);

		$connected = $this->connect->is_connected();
		$sub       = $connected ? esc_html( $this->connect->account_email() ) . ' · ' . esc_html( $this->connect->plan_label() ) : ( $en ? 'Connect your Mersal account to send WhatsApp & SMS.' : 'اربط حساب مرسال لإرسال الواتساب والرسائل.' );
		echo '<div class="hero"><div class="inner"><div class="logo">م</div>';
		echo '<div style="flex:1;min-width:200px;"><div style="font-size:16px;font-weight:700;margin-bottom:4px;">' . ( $connected ? ( $en ? 'Connected to Mersal' : 'متّصل بمرسال' ) : ( $en ? 'Mersal Notifications is active' : 'مرسال للإشعارات مفعّل' ) ) . '</div><div style="font-size:13px;opacity:.9;">' . $sub . '</div></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo '<a class="btn" style="background:rgba(255,255,255,.16);color:#fff;border:1px solid rgba(255,255,255,.24);" href="' . esc_url( $this->page_url( 'mersal' ) ) . '">' . ( $connected ? ( $en ? 'Account' : 'الحساب' ) : ( $en ? 'Connect' : 'ربط' ) ) . '<span class="mi sm">arrow_forward</span></a>';
		echo '</div></div>';

		echo '<div class="grid-4" style="margin-bottom:20px;">';
		$this->stat( 'notifications', 'cyan', $en ? 'Rules' : 'القواعد', number_format_i18n( $ov['rules'] ) );
		$this->stat( 'bolt', 'green', $en ? 'Enabled' : 'المفعّلة', number_format_i18n( $ov['enabled'] ) );
		$this->stat( 'outgoing_mail', 'violet', $en ? 'Sent total' : 'إجمالي الإرسال', number_format_i18n( $ov['sent'] ) );
		$this->stat( 'today', 'amber', $en ? 'Sent today' : 'أُرسلت اليوم', number_format_i18n( $ov['today'] ) );
		echo '</div>';

		echo '<div class="card"><div class="card-head"><div class="ico"><span class="mi">history</span></div><div class="t"><b>' . ( $en ? 'Recent activity' : 'آخر النشاط' ) . '</b><span>' . ( $en ? 'Latest notifications sent' : 'آخر الإشعارات المُرسلة' ) . '</span></div><div class="right"><a class="btn ghost sm" href="' . esc_url( $this->page_url( 'logs' ) ) . '">' . ( $en ? 'View all' : 'الكل' ) . '</a></div></div>';
		$this->log_table( $log, $en );
		echo '</div>';
	}

	/* ------------------------------------------------------------------ */
	/* Page: Rules list                                                   */
	/* ------------------------------------------------------------------ */

	private function page_rules( $lang ) {
		$en       = ( 'en' === $lang );
		$rules    = $this->core->get_rules();
		$triggers = $this->core->get_triggers();

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['saved'] ) ) {
			echo '<div class="banner" style="margin-bottom:18px;"><span class="mi">check_circle</span><div>' . ( $en ? 'Rule saved.' : 'تم حفظ القاعدة.' ) . '</div></div>';
		}

		$this->page_head(
			$en ? 'Notification rules' : 'قواعد الإشعارات',
			$en ? 'Send a message automatically when an event happens.' : 'أرسل رسالة تلقائيًا عند وقوع حدث.',
			'<a class="btn primary" href="' . esc_url( $this->page_url( 'edit' ) ) . '"><span class="mi sm">add</span>' . ( $en ? 'New rule' : 'قاعدة جديدة' ) . '</a>'
		);

		echo '<div data-mnotif-rules data-nonce="' . esc_attr( wp_create_nonce( 'mnotif_rule' ) ) . '">';
		if ( empty( $rules ) ) {
			echo '<div class="card"><div class="card-body">';
			$this->empty_state( 'notifications', $en ? 'No rules yet' : 'لا توجد قواعد بعد', $en ? 'Create your first notification rule.' : 'أنشئ أول قاعدة إشعار.' );
			echo '</div></div>';
		} else {
			$sent_counts = $this->core->get_rule_sent_counts();
			// Group rules by event category (Wawp-style: easier management).
			$cats    = self::trigger_categories( $en );
			$grouped = array();
			foreach ( $rules as $r ) {
				$grouped[ self::trigger_category( $r['trigger_key'] ?? '' ) ][] = $r;
			}
			foreach ( $cats as $ck => $cm ) {
				if ( empty( $grouped[ $ck ] ) ) {
					continue;
				}
				$bucket = $grouped[ $ck ];
				$on_n   = count( array_filter( $bucket, function ( $x ) { return ! empty( $x['enabled'] ); } ) );
				echo '<div class="card" style="margin-bottom:16px;"><div class="card-head"><div class="ico"><span class="mi">' . esc_html( $cm[0] ) . '</span></div><div class="t"><b>' . esc_html( $cm[1] ) . '</b><span>' . esc_html( $cm[2] ) . '</span></div><div class="right"><span class="chip">' . esc_html( number_format_i18n( $on_n ) . ' / ' . number_format_i18n( count( $bucket ) ) ) . ' ' . ( $en ? 'active' : 'نشطة' ) . '</span></div></div><div class="card-body">';
				$this->rules_table( $bucket, $triggers, $sent_counts, $en );
				echo '</div></div>';
			}
		}
		echo '</div>';

		$this->rules_list_js();
	}

	/**
	 * One rules table (used per category group).
	 *
	 * @param array $rules       Rules in this group.
	 * @param array $triggers    Trigger labels.
	 * @param array $sent_counts Sent counters.
	 * @param bool  $en          English.
	 */
	private function rules_table( $rules, $triggers, $sent_counts, $en ) {
		{
			echo '<table class="table"><thead><tr><th>' . ( $en ? 'Name' : 'الاسم' ) . '</th><th>' . ( $en ? 'Trigger' : 'الحدث' ) . '</th><th>' . ( $en ? 'Channel' : 'القناة' ) . '</th><th>' . ( $en ? 'To' : 'إلى' ) . '</th><th>' . ( $en ? 'Sent' : 'أُرسلت' ) . '</th><th>' . ( $en ? 'Status' : 'الحالة' ) . '</th><th style="text-align:end;">' . ( $en ? 'Actions' : 'إجراءات' ) . '</th></tr></thead><tbody>';
			foreach ( $rules as $r ) {
				$trig = $triggers[ $r['trigger_key'] ] ?? $r['trigger_key'];
				echo '<tr>';
				echo '<td><b>' . esc_html( $r['name'] ) . '</b></td>';
				echo '<td>' . esc_html( $trig ) . '</td>';
				$chans = ( ! empty( $r['channels'] ) && is_array( $r['channels'] ) ) ? $r['channels'] : array( $r['channel'] ?? 'whatsapp' );
				echo '<td>';
				foreach ( $chans as $ch ) {
					echo $this->channel_chip( $ch ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				}
				echo '</td>';
				$rcps = ( ! empty( $r['recipients'] ) && is_array( $r['recipients'] ) ) ? $r['recipients'] : array( $r['send_to'] ?? 'customer' );
				$rmap = array( 'customer' => ( $en ? 'Customer' : 'العميل' ), 'admin' => ( $en ? 'Admin' : 'الأدمن' ) );
				$rlbl = array_map(
					function ( $x ) use ( $rmap ) {
						return $rmap[ $x ] ?? $x;
					},
					$rcps
				);
				echo '<td>' . esc_html( implode( ' + ', $rlbl ) ) . '</td>';
				echo '<td><b>' . esc_html( number_format_i18n( (int) ( $sent_counts[ $r['id'] ] ?? 0 ) ) ) . '</b></td>';
				echo '<td>' . ( ! empty( $r['enabled'] ) ? '<span class="chip success"><span class="dot success"></span>' . ( $en ? 'On' : 'مفعّلة' ) . '</span>' : '<span class="chip muted"><span class="dot"></span>' . ( $en ? 'Off' : 'متوقفة' ) . '</span>' ) . '</td>';
				echo '<td style="text-align:end;white-space:nowrap;">';
				echo '<a class="btn ghost sm" href="' . esc_url( add_query_arg( 'id', $r['id'], $this->page_url( 'edit' ) ) ) . '"><span class="mi sm">edit</span></a> ';
				echo '<button class="btn ghost sm" type="button" data-mnotif-test data-id="' . esc_attr( $r['id'] ) . '"><span class="mi sm">send</span></button> ';
			echo '<button class="btn ghost sm" type="button" data-mnotif-duplicate data-id="' . esc_attr( $r['id'] ) . '" title="' . esc_attr( $en ? 'Duplicate' : 'نسخ' ) . '"><span class="mi sm">content_copy</span></button> ';
				echo '<button class="btn ghost sm" type="button" data-mnotif-toggle="' . ( ! empty( $r['enabled'] ) ? '0' : '1' ) . '" data-id="' . esc_attr( $r['id'] ) . '"><span class="mi sm">' . ( ! empty( $r['enabled'] ) ? 'pause' : 'play_arrow' ) . '</span></button> ';
				echo '<button class="btn ghost sm" type="button" data-mnotif-delete data-id="' . esc_attr( $r['id'] ) . '"><span class="mi sm">delete</span></button>';
				echo '</td></tr>';
			}
			echo '</tbody></table>';
		}
	}

	private function rules_list_js() {
		$ajax = admin_url( 'admin-ajax.php' );
		?>
		<script>
		(function(){
			var box = document.querySelector('[data-mnotif-rules]');
			if (!box) return;
			var nonce = box.getAttribute('data-nonce');
			var ajax = <?php echo wp_json_encode( $ajax ); ?>;
			function post(action, id, extra, reload){
				var fd = new FormData();
				fd.append('action', action);
				fd.append('nonce', nonce);
				fd.append('id', id);
				if (extra) Object.keys(extra).forEach(function(k){ fd.append(k, extra[k]); });
				return fetch(ajax, { method:'POST', body:fd, credentials:'same-origin' })
					.then(function(r){ return r.json(); })
					.then(function(res){ if (reload !== false) window.location.reload(); return res; });
			}
			box.addEventListener('click', function(e){
				var del = e.target.closest('[data-mnotif-delete]');
				if (del){ if (confirm('Delete this rule?')) post('mnotif_delete_rule', del.getAttribute('data-id')); return; }
				var dup = e.target.closest('[data-mnotif-duplicate]');
				if (dup){ post('mnotif_duplicate_rule', dup.getAttribute('data-id')); return; }
				var tog = e.target.closest('[data-mnotif-toggle]');
				if (tog){ post('mnotif_toggle_rule', tog.getAttribute('data-id'), { enabled: tog.getAttribute('data-mnotif-toggle') }); return; }
				var test = e.target.closest('[data-mnotif-test]');
				if (test){
					test.disabled = true;
					post('mnotif_test_rule', test.getAttribute('data-id'), null, false).then(function(res){
						test.disabled = false;
						alert(res && res.data ? res.data.message : (res && res.success ? 'Test sent.' : 'Could not send test.'));
					});
					return;
				}
			});
		})();
		</script>
		<?php
	}

	/* ------------------------------------------------------------------ */
	/* Page: Rule edit / create                                           */
	/* ------------------------------------------------------------------ */

	private function page_edit( $s, $lang ) {
		$en = ( 'en' === $lang );
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$id   = isset( $_GET['id'] ) ? sanitize_text_field( wp_unslash( $_GET['id'] ) ) : '';
		$rule = $id ? $this->core->get_rule( $id ) : null;
		$get  = function ( $k, $d = '' ) use ( $rule ) {
			return $rule && isset( $rule[ $k ] ) ? $rule[ $k ] : $d;
		};

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['error'] ) ) {
			echo '<div class="banner danger" style="margin-bottom:18px;"><span class="mi">error</span><div>' . esc_html( sanitize_text_field( wp_unslash( $_GET['error'] ) ) ) . '</div></div>';
		}

		$this->page_head(
			$rule ? ( $en ? 'Edit rule' : 'تعديل القاعدة' ) : ( $en ? 'New rule' : 'قاعدة جديدة' ),
			$en ? 'Choose a trigger, a channel and a message.' : 'اختر الحدث والقناة والرسالة.'
		);

		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">';
		wp_nonce_field( 'mnotif_save_rule', 'mnotif_nonce' );
		echo '<input type="hidden" name="action" value="mnotif_save_rule">';
		echo '<input type="hidden" name="id" value="' . esc_attr( $id ) . '">';

		$sel_ch = ( $rule && ! empty( $rule['channels'] ) && is_array( $rule['channels'] ) ) ? $rule['channels'] : array( $get( 'channel', 'whatsapp' ) );
		$sel_rc = ( $rule && ! empty( $rule['recipients'] ) && is_array( $rule['recipients'] ) ) ? $rule['recipients'] : array( $get( 'send_to', 'customer' ) );
		$wc     = class_exists( 'WooCommerce' ) && function_exists( 'WC' );

		// Wizard header.
		$steps = array(
			$en ? 'Event' : 'الحدث',
			$en ? 'Channels' : 'القنوات',
			$en ? 'Message' : 'الرسالة',
			$en ? 'Advanced' : 'متقدّم',
			$en ? 'Test' : 'اختبار',
			$en ? 'Review' : 'مراجعة',
		);
		echo '<div class="mnotif-wiz" data-mnotif-wiz>';
		foreach ( $steps as $i => $label ) {
			echo '<div class="wstep' . ( 0 === $i ? ' active' : '' ) . '" data-go="' . esc_attr( $i + 1 ) . '"><span class="wn">' . esc_html( $i + 1 ) . '</span><span class="wt">' . esc_html( $label ) . '</span></div>';
		}
		echo '</div>';

		// ---- Step 1: Event ----
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only prefill.
		$preset_trigger = isset( $_GET['trigger'] ) ? sanitize_key( wp_unslash( $_GET['trigger'] ) ) : '';
		echo '<div class="mnotif-step" data-step="1">';
		$this->card_open( 'bolt', $en ? 'Pick an event' : 'اختر الحدث', $en ? 'When should this notification fire?' : 'إمتى يتبعت الإشعار ده؟' );
		$this->trigger_select( $get( 'trigger_key', $preset_trigger ), $en );
		echo '<div style="margin-top:14px;">';
		$this->text_field_raw( 'name', $get( 'name', '' ), $en ? 'Rule name (optional)' : 'اسم القاعدة (اختياري)', $en ? 'E.g. Order shipped alert' : 'مثال: تنبيه شحن الطلب' );
		echo '</div>';
		$this->switch_row_raw( 'enabled', (bool) $get( 'enabled', 1 ), $en ? 'Enabled' : 'مفعّلة', $en ? 'Turn this notification on.' : 'تشغيل هذا الإشعار.' );
		$this->card_close();
		echo '</div>';

		// ---- Step 2: Channels & recipients ----
		echo '<div class="mnotif-step" data-step="2" hidden>';
		$this->card_open( 'send', $en ? 'Channels & recipients' : 'القنوات والمستلمون', $en ? 'Send over one or more channels, to the customer and/or your admins.' : 'أرسل عبر قناة أو أكثر، للعميل و/أو الأدمن.' );
		echo '<label class="flbl">' . esc_html( $en ? 'Channels' : 'القنوات' ) . '</label>';
		$this->check_tiles( 'channels', $sel_ch, array(
			'whatsapp' => array( 'chat', 'WhatsApp' ),
			'sms'      => array( 'sms', 'SMS' ),
			'email'    => array( 'mail', 'Email' ),
		) );
		echo '<label class="flbl" style="margin-top:14px;">' . esc_html( $en ? 'Recipients' : 'المستلمون' ) . '</label>';
		$this->check_tiles( 'recipients', $sel_rc, array(
			'customer' => array( 'person', $en ? 'Customer / user' : 'العميل / المستخدم' ),
			'admin'    => array( 'shield_person', $en ? 'Admin(s)' : 'الأدمن' ),
		) );
		$delay_value = (int) $get( 'delay_value', $get( 'delay_minutes', 0 ) );
		$delay_unit  = (string) $get( 'delay_unit', 'minutes' );
		echo '<div class="grid-4" style="margin-top:14px;">';
		$this->text_field_raw( 'admin_users', $get( 'admin_users', '' ), $en ? 'Admin IDs (empty = all)' : 'أرقام الأدمن (فارغ = الكل)' );
		$this->number_field_raw( 'delay_value', $delay_value, $en ? 'Delay (0 = instant)' : 'تأخير (0 = فوري)' );
		echo '<div class="field"><label>' . esc_html( $en ? 'Delay unit' : 'وحدة التأخير' ) . '</label><select class="select" name="delay_unit">';
		foreach ( array(
			'minutes' => $en ? 'Minutes' : 'دقائق',
			'hours'   => $en ? 'Hours' : 'ساعات',
			'days'    => $en ? 'Days' : 'أيام',
		) as $du => $dl ) {
			echo '<option value="' . esc_attr( $du ) . '" ' . selected( $delay_unit, $du, false ) . '>' . esc_html( $dl ) . '</option>';
		}
		echo '</select></div>';
		$this->number_field_raw( 'cooldown_hours', $get( 'cooldown_hours', 0 ), $en ? 'Cooldown (hours, 0=off)' : 'فترة تهدئة (ساعات، 0=بلا)' );
		echo '</div>';
		echo '<p class="hint">' . esc_html( $en ? 'Hours/days delays let you build sequences: several rules on the same trigger with growing delays.' : 'التأخير بالساعات/الأيام يتيح بناء سلاسل: عدة قواعد على نفس الحدث بتأخيرات متصاعدة.' ) . '</p>';
		echo '<p class="hint">' . esc_html( $en ? 'Cooldown prevents re-notifying the same customer within the chosen number of hours.' : 'فترة التهدئة تمنع تكرار الإشعار لنفس العميل خلال عدد الساعات المحدد.' ) . '</p>';
		$this->card_close();
		echo '</div>';

		// ---- Step 3: Message ----
		echo '<div class="mnotif-step" data-step="3" hidden>';
		$this->card_open( 'edit_note', $en ? 'Message' : 'الرسالة', $en ? 'Personalize with placeholders and preview live.' : 'خصّص بالمتغيرات وشاهد المعاينة الحيّة.' );
		echo '<div class="grid-2 email-only">';
		echo '<div class="field"><label>' . esc_html( $en ? 'Email subject (email channel)' : 'عنوان الإيميل (لقناة الإيميل)' ) . '</label><input class="input" type="text" name="email_subject" value="' . esc_attr( $get( 'email_subject', '' ) ) . '"></div>';
		$email_tpls = class_exists( 'Mersal_Notif_Email_Templates' ) ? Mersal_Notif_Email_Templates::get_all() : array();
		echo '<div class="field"><label>' . esc_html( $en ? 'Email design template' : 'قالب تصميم الإيميل' ) . '</label><select class="select" name="email_template">';
		echo '<option value="0">' . esc_html( $en ? 'Plain (no template)' : 'عادي (بدون قالب)' ) . '</option>';
		$cur_tpl = (int) $get( 'email_template', 0 );
		foreach ( $email_tpls as $tid => $tpl ) {
			echo '<option value="' . esc_attr( $tid ) . '" ' . selected( $cur_tpl, (int) $tid, false ) . '>' . esc_html( $tpl['name'] ) . '</option>';
		}
		echo '</select><div class="hint"><a href="#" data-eb-fold-open>' . esc_html( $en ? 'Design templates in the Email builder below ↓' : 'صمّم القوالب من بيلدر الإيميل بالأسفل ↓' ) . '</a></div></div>';
		echo '</div>';
		$this->placeholder_toolbar( 'message', $this->core->get_placeholders() );
		echo '<div class="mnotif-msg-grid">';
		echo '<div class="mnotif-msg-main">';
		echo '<div class="field"><label>' . esc_html( $en ? 'Message body' : 'نص الرسالة' ) . '</label><textarea class="textarea" name="message" data-mnotif-msg rows="9">' . esc_textarea( $get( 'message', '' ) ) . '</textarea></div>';
		$media_mode = (string) $get( 'media_mode', '' );
		if ( '' === $media_mode ) {
			// Legacy rules: derive the mode from the old fields.
			if ( (int) $get( 'send_product_image', 0 ) ) {
				$media_mode = 'product';
			} elseif ( '' !== (string) $get( 'media_url', '' ) ) {
				$media_mode = 'custom';
			} else {
				$media_mode = 'none';
			}
		}
		echo '<div class="grid-2">';
		echo '<div class="field"><label>' . esc_html( $en ? 'Header media' : 'وسائط الرسالة' ) . '</label><select class="select" name="media_mode" data-mnotif-media-mode>';
		foreach ( array(
			'none'     => $en ? 'No media (text only)' : 'بدون وسائط (نص فقط)',
			'custom'   => $en ? 'Custom image / file URL' : 'رابط صورة/ملف مخصص',
			'featured' => $en ? 'Featured image (from context)' : 'الصورة البارزة (من السياق)',
			'product'  => $en ? 'Dynamic product image' : 'صورة المنتج الديناميكية',
		) as $mv => $ml ) {
			echo '<option value="' . esc_attr( $mv ) . '" ' . selected( $media_mode, $mv, false ) . '>' . esc_html( $ml ) . '</option>';
		}
		echo '</select></div>';
		echo '<div class="mnotif-media field" data-mnotif-media-box><label>' . esc_html( $en ? 'Media URL' : 'رابط الوسائط' ) . '</label><div class="row" style="gap:8px;"><input class="input" type="text" name="media_url" data-mnotif-media value="' . esc_attr( $get( 'media_url', '' ) ) . '" placeholder="https://...">';
		echo '<button type="button" class="btn" data-mnotif-media-pick><span class="mi sm">image</span>' . ( $en ? 'Select' : 'اختيار' ) . '</button></div><div class="hint">' . esc_html( $en ? 'Used for "Custom" mode, and as fallback for the dynamic modes.' : 'يُستخدم في وضع «مخصص»، وكاحتياطي للأوضاع الديناميكية.' ) . '</div></div>';
		echo '</div>';
		echo '</div>'; // .mnotif-msg-main
		// Live WhatsApp-style preview.
		echo '<div class="mnotif-msg-side">';
		echo '<div class="mnotif-preview wa"><div class="pvh"><span class="mi sm">visibility</span>' . ( $en ? 'Message preview' : 'معاينة الرسالة' ) . '<span class="pv-tag">' . ( $en ? 'Live Demo' : 'معاينة حيّة' ) . '</span></div>';
		echo '<div class="pvb wa-surface"><div class="wa-bubble"><span class="wa-txt" data-mnotif-preview></span><span class="wa-time">' . esc_html( date_i18n( 'H:i' ) ) . ' ✓✓</span></div></div></div>';
		echo '</div>'; // .mnotif-msg-side
		echo '</div>'; // .mnotif-msg-grid
		// Message acceptance analyzer (anti-ban / structure / engagement).
		echo '<div class="mnotif-az" data-mnotif-analyzer hidden></div>';
		$this->card_close();

		// Alternative wordings of the same notification.
		$this->variants_card( $rule, $get( 'trigger_key', $preset_trigger ), $en );

		// Embedded email template builder (merged from the old standalone screen).
		echo '<details class="card mnotif-eb-fold" data-eb-fold style="margin-top:18px;overflow:visible;">';
		echo '<summary class="card-head" style="cursor:pointer;list-style:none;">';
		echo '<div class="ico"><span class="mi">mark_email_read</span></div>';
		echo '<div class="t"><b>' . esc_html( $en ? 'Email template builder' : 'بيلدر قوالب الإيميل' ) . '</b><span>' . esc_html( $en ? 'Design an HTML template here, then pick it in "Email design template" above.' : 'صمّم قالب HTML هنا ثم اختره من «قالب تصميم الإيميل» بالأعلى.' ) . '</span></div>';
		echo '<span class="mi fold-chev" style="margin-inline-start:auto;color:var(--fg-3);">expand_more</span>';
		echo '</summary><div class="card-body">';
		$this->email_builder_ui( $en );
		echo '</div></details>';
		echo '<script>(function(){var f=document.querySelector("[data-eb-fold]");document.addEventListener("click",function(e){var o=e.target.closest("[data-eb-fold-open]");if(o&&f){e.preventDefault();f.open=true;try{f.scrollIntoView({behavior:"smooth",block:"start"});}catch(err){}}});})();</script>';

		// Per-language variants: the recipient's locale picks the matching copy,
		// with the main message as fallback.
		$translations = ( $rule && ! empty( $rule['translations'] ) && is_array( $rule['translations'] ) ) ? $rule['translations'] : array();
		$tr_langs     = array( 'ar' => 'العربية', 'en' => 'English', 'fr' => 'Français', 'tr' => 'Türkçe', 'de' => 'Deutsch', 'es' => 'Español', 'it' => 'Italiano', 'ru' => 'Русский', 'ur' => 'اردو', 'id' => 'Indonesia' );
		$this->card_open( 'translate', $en ? 'Language versions (optional)' : 'نسخ بلغات أخرى (اختياري)', $en ? 'Each recipient gets the version matching their language; others get the main message above.' : 'كل مستلم يستقبل النسخة المطابقة للغته؛ غير ذلك يستقبل الرسالة الرئيسية أعلاه.' );
		echo '<div data-mnotif-trs>';
		$ti = 0;
		foreach ( $translations as $tl => $tr ) {
			echo '<div class="card" data-tr-row style="margin-bottom:10px;"><div class="card-body">';
			echo '<div class="grid-2"><div class="field"><label>' . esc_html( $en ? 'Language' : 'اللغة' ) . '</label><select class="select" name="translations[' . esc_attr( $ti ) . '][lang]" data-tr-lang>';
			foreach ( $tr_langs as $lv => $ll ) {
				echo '<option value="' . esc_attr( $lv ) . '" ' . selected( $tl, $lv, false ) . '>' . esc_html( $ll ) . '</option>';
			}
			echo '</select></div>';
			echo '<div class="field email-only"><label>' . esc_html( $en ? 'Email subject' : 'عنوان الإيميل' ) . '</label><input class="input" type="text" name="translations[' . esc_attr( $ti ) . '][email_subject]" data-tr-subject value="' . esc_attr( $tr['email_subject'] ?? '' ) . '"></div></div>';
			echo '<div class="field"><label>' . esc_html( $en ? 'Message body' : 'نص الرسالة' ) . '</label><textarea class="textarea" name="translations[' . esc_attr( $ti ) . '][message]" data-tr-message rows="4">' . esc_textarea( $tr['message'] ?? '' ) . '</textarea></div>';
			echo '<button type="button" class="btn ghost sm" data-tr-remove><span class="mi sm">delete</span>' . ( $en ? 'Remove' : 'حذف' ) . '</button>';
			echo '</div></div>';
			++$ti;
		}
		echo '</div>';
		echo '<button type="button" class="btn" data-mnotif-add-tr><span class="mi sm">add</span>' . ( $en ? 'Add language version' : 'إضافة نسخة بلغة أخرى' ) . '</button>';
		?>
		<script>
		(function(){
			var box = document.querySelector('[data-mnotif-trs]');
			var add = document.querySelector('[data-mnotif-add-tr]');
			if (!box || !add) return;
			var langs = <?php echo wp_json_encode( $tr_langs ); ?>;
			function reindex(){
				box.querySelectorAll('[data-tr-row]').forEach(function(row, i){
					var l = row.querySelector('[data-tr-lang]'); if (l) l.name = 'translations['+i+'][lang]';
					var s = row.querySelector('[data-tr-subject]'); if (s) s.name = 'translations['+i+'][email_subject]';
					var m = row.querySelector('[data-tr-message]'); if (m) m.name = 'translations['+i+'][message]';
				});
			}
			add.addEventListener('click', function(){
				var i = box.querySelectorAll('[data-tr-row]').length;
				var opts = Object.keys(langs).map(function(k){ return '<option value="'+k+'">'+langs[k]+'</option>'; }).join('');
				var row = document.createElement('div');
				row.className = 'card'; row.setAttribute('data-tr-row',''); row.style.marginBottom = '10px';
				row.innerHTML = '<div class="card-body">'
					+ '<div class="grid-2"><div class="field"><label><?php echo esc_js( $en ? 'Language' : 'اللغة' ); ?></label><select class="select" data-tr-lang name="translations['+i+'][lang]">'+opts+'</select></div>'
					+ '<div class="field email-only"><label><?php echo esc_js( $en ? 'Email subject' : 'عنوان الإيميل' ); ?></label><input class="input" type="text" data-tr-subject name="translations['+i+'][email_subject]"></div></div>'
					+ '<div class="field"><label><?php echo esc_js( $en ? 'Message body' : 'نص الرسالة' ); ?></label><textarea class="textarea" data-tr-message name="translations['+i+'][message]" rows="4"></textarea></div>'
					+ '<button type="button" class="btn ghost sm" data-tr-remove><span class="mi sm">delete</span><?php echo esc_js( $en ? 'Remove' : 'حذف' ); ?></button>'
					+ '</div>';
				box.appendChild(row);
			});
			box.addEventListener('click', function(e){
				var rm = e.target.closest('[data-tr-remove]');
				if (rm){ rm.closest('[data-tr-row]').remove(); reindex(); }
			});
		})();
		</script>
		<?php
		$this->card_close();
		echo '</div>';

		// ---- Step 4: Advanced (filters + admin message) ----
		echo '<div class="mnotif-step" data-step="4" hidden>';
		$this->card_open( 'filter_alt', $en ? 'Filters (WooCommerce orders)' : 'الفلاتر (طلبات ووكومرس)', $en ? 'Only fire when the order matches. Ignored for non-order events.' : 'لا يُرسل إلا لو الطلب مطابق. تُتجاهل لغير أحداث الطلبات.' );
		$this->switch_row_raw( 'filter_country', (bool) $get( 'filter_country', 0 ), $en ? 'Filter by billing country' : 'فلترة حسب دولة الفوترة', '' );
		$countries = $wc ? WC()->countries->get_countries() : array();
		echo '<div class="grid-2">';
		$this->multiselect_field_raw( 'countries_whitelist', $get( 'countries_whitelist', '' ), $en ? 'Only these countries' : 'هذه الدول فقط', $countries );
		$this->multiselect_field_raw( 'countries_blocklist', $get( 'countries_blocklist', '' ), $en ? 'Exclude these countries' : 'استثناء هذه الدول', $countries );
		echo '</div>';
		$this->switch_row_raw( 'filter_product', (bool) $get( 'filter_product', 0 ), $en ? 'Filter by purchased product' : 'فلترة حسب منتج مشترى', '' );
		$this->text_field_raw( 'product_ids', $get( 'product_ids', '' ), $en ? 'Product IDs (comma separated)' : 'أرقام المنتجات (مفصولة بفواصل)' );
		$this->switch_row_raw( 'filter_category', (bool) $get( 'filter_category', 0 ), $en ? 'Filter by product category' : 'فلترة حسب تصنيف المنتج', '' );
		$this->text_field_raw( 'category_ids', $get( 'category_ids', '' ), $en ? 'Category IDs (comma separated)' : 'أرقام التصنيفات (مفصولة بفواصل)' );
		$this->switch_row_raw( 'filter_payment', (bool) $get( 'filter_payment', 0 ), $en ? 'Filter by payment method' : 'فلترة حسب طريقة الدفع', '' );
		$gateways = array();
		if ( $wc && WC()->payment_gateways() ) {
			foreach ( WC()->payment_gateways()->payment_gateways() as $gw ) {
				$gateways[ $gw->id ] = $gw->get_title() ? $gw->get_title() : $gw->id;
			}
		}
		$this->multiselect_field_raw( 'payment_gateways', $get( 'payment_gateways', '' ), $en ? 'Allowed payment methods' : 'طرق الدفع المسموحة', $gateways );
		$this->card_close();

		$adm_on = ( $rule && ( '' !== trim( wp_strip_all_tags( (string) $get( 'admin_message', '' ) ) ) || '' !== (string) $get( 'admin_subject', '' ) ) );
		$this->card_open( 'shield_person', $en ? 'Admin message (optional)' : 'رسالة الأدمن (اختياري)', $en ? 'Send admins a different text. Leave off to reuse the customer message.' : 'أرسل للأدمن نصًا مختلفًا. اتركه مغلقًا لاستخدام رسالة العميل.' );
		echo '<label class="mnotif-switch-row"><span>' . esc_html( $en ? 'Use a separate admin message' : 'استخدام رسالة أدمن منفصلة' ) . '</span><label class="mnotif-switch"><input type="checkbox" data-mnotif-adm ' . checked( $adm_on, true, false ) . '><span></span></label></label>';
		echo '<div class="mnotif-admbox" ' . ( $adm_on ? '' : 'hidden' ) . '>';
		echo '<div class="field email-only"><label>' . esc_html( $en ? 'Admin email subject' : 'عنوان إيميل الأدمن' ) . '</label><input class="input" type="text" name="admin_subject" value="' . esc_attr( $get( 'admin_subject', '' ) ) . '"></div>';
		$this->placeholder_toolbar( 'admin_message', $this->core->get_placeholders() );
		echo '<div class="field"><label>' . esc_html( $en ? 'Admin message body' : 'نص رسالة الأدمن' ) . '</label><textarea class="textarea" name="admin_message" rows="5">' . esc_textarea( $get( 'admin_message', '' ) ) . '</textarea></div>';
		echo '</div>';
		$this->card_close();
		echo '</div>';

		// ---- Step 5: Live test (simulator) ----
		echo '<div class="mnotif-step" data-step="5" hidden>';
		$this->card_open( 'science', $en ? 'Rule simulator' : 'محاكي القاعدة', $en ? 'Fire this rule with real site data before saving — every copy is delivered to YOU.' : 'اختبر القاعدة ببيانات حقيقية قبل الحفظ — كل النسخ هتتبعت ليك أنت.' );
		echo '<div class="grid-2">';
		echo '<div class="field"><label>' . esc_html( $en ? 'Context' : 'السياق' ) . '</label><select class="select" name="sim_order">';
		echo '<option value="">' . esc_html( $en ? 'Sample data (no order)' : 'بيانات تجريبية (بدون طلب)' ) . '</option>';
		if ( $wc && function_exists( 'wc_get_orders' ) ) {
			$sim_orders = wc_get_orders( array( 'limit' => 10, 'orderby' => 'date', 'order' => 'DESC' ) );
			foreach ( (array) $sim_orders as $so ) {
				$label = '#' . $so->get_id() . ' — ' . $so->get_formatted_billing_full_name() . ' — ' . html_entity_decode( wp_strip_all_tags( $so->get_formatted_order_total() ) );
				echo '<option value="' . esc_attr( $so->get_id() ) . '">' . esc_html( $label ) . '</option>';
			}
		}
		echo '</select><div class="hint">' . esc_html( $en ? 'Pick a real order to fill order placeholders with live values.' : 'اختر طلبًا حقيقيًا لتعبئة متغيرات الطلب بقيم فعلية.' ) . '</div></div>';
		echo '<div class="field"><label>' . esc_html( $en ? 'Delivery' : 'التسليم' ) . '</label><div class="hint" style="margin-top:10px;">' . esc_html( $en ? 'Messages go to the phone/email on your admin account. Delays are skipped.' : 'الرسائل هتوصل على الهاتف/الإيميل المسجلين في حسابك. يتم تجاهل التأخير.' ) . '</div></div>';
		echo '</div>';
		echo '<div style="display:flex;gap:10px;align-items:center;margin-top:8px;">';
		echo '<button type="button" class="btn primary" data-mnotif-fire-test data-nonce="' . esc_attr( wp_create_nonce( 'mnotif_rule' ) ) . '"><span class="mi sm">rocket_launch</span>' . ( $en ? 'Fire test notification' : 'إطلاق إشعار تجريبي' ) . '</button>';
		echo '<span data-mnotif-test-result style="font-size:13px;color:var(--fg-2);"></span>';
		echo '</div>';
		$this->card_close();
		echo '</div>';

		// ---- Step 6: Review ----
		echo '<div class="mnotif-step" data-step="6" hidden>';
		$this->card_open( 'fact_check', $en ? 'Review & save' : 'مراجعة وحفظ' );
		echo '<div class="mcamp-review mnotif-review" data-mnotif-review></div>';
		echo '<p class="hint" style="margin-top:10px;">' . esc_html( $en ? 'You already tested it — save to go live.' : 'جرّبتها خلاص — احفظ عشان تشتغل فعليًا.' ) . '</p>';
		$this->card_close();
		echo '</div>';

		// ---- Wizard nav ----
		echo '<div class="mnotif-wnav">';
		echo '<a class="btn" href="' . esc_url( $this->page_url( 'rules' ) ) . '">' . ( $en ? 'Cancel' : 'إلغاء' ) . '</a>';
		echo '<button type="button" class="btn" data-wiz-back hidden><span class="mi sm">arrow_back</span>' . ( $en ? 'Back' : 'السابق' ) . '</button>';
		echo '<div class="sp"></div>';
		echo '<button type="button" class="btn primary" data-wiz-next>' . ( $en ? 'Next' : 'التالي' ) . '<span class="mi sm">arrow_forward</span></button>';
		echo '<button type="submit" class="btn primary" data-wiz-save hidden><span class="mi sm">save</span>' . ( $en ? 'Save rule' : 'حفظ القاعدة' ) . '</button>';
		echo '</div>';
		echo '</form>';

		$this->builder_js( $lang );
	}

	/**
	 * Grouped, searchable trigger picker (optgroups by source) — quick to scan.
	 *
	 * @param string $current Selected trigger key.
	 * @param bool   $en      English UI.
	 */
	/**
	 * Category a trigger key belongs to (Wawp-style event categories).
	 *
	 * @param string $key Trigger key.
	 * @return string wp|woo|subs|cart|custom
	 */
	public static function trigger_category( $key ) {
		if ( 0 === strpos( $key, 'wc_sub_' ) ) {
			return 'subs';
		}
		if ( 0 === strpos( $key, 'ac_' ) ) {
			return 'cart';
		}
		if ( 0 === strpos( $key, 'custom_' ) ) {
			return 'custom';
		}
		if ( 0 === strpos( $key, 'wc_' ) ) {
			return 'woo';
		}
		return 'wp';
	}

	/**
	 * Event-category meta: icon, label, description (Wawp-style tiles).
	 *
	 * @param bool $en English.
	 * @return array<string,array{0:string,1:string,2:string}>
	 */
	public static function trigger_categories( $en ) {
		return array(
			'wp'     => array( 'person', 'WordPress', $en ? 'Core system events' : 'أحداث النظام الأساسية' ),
			'woo'    => array( 'shopping_bag', 'WooCommerce', $en ? 'Store & orders' : 'المتجر والطلبات' ),
			'subs'   => array( 'autorenew', $en ? 'Subscriptions' : 'الاشتراكات', $en ? 'Recurring payments' : 'المدفوعات المتكررة' ),
			'cart'   => array( 'shopping_cart', $en ? 'Cart journey' : 'رحلة السلة', $en ? 'Capture & win carts back' : 'التقاط واسترجاع السلات' ),
			'custom' => array( 'webhook', $en ? 'Custom' : 'مخصص', $en ? 'Your own events' : 'أحداثك الخاصة' ),
		);
	}

	/**
	 * Human description for a trigger key (shown under the event picker).
	 *
	 * @param string $key   Trigger key.
	 * @param string $label Trigger label.
	 * @param bool   $en    English.
	 * @return string
	 */
	/**
	 * Alternative wordings of the same notification.
	 *
	 * WhatsApp bans senders that push one identical text to many numbers, so a
	 * rule can hold several wordings and Mersal picks a different one per send.
	 * The main message above is always wording #1 — this card holds the rest,
	 * and offers the five ready-made professional versions for this event.
	 *
	 * @param array|null $rule    Rule being edited.
	 * @param string     $trigger Trigger key.
	 * @param bool       $en      English UI?
	 */
	private function variants_card( $rule, $trigger, $en ) {
		$variants = ( $rule && ! empty( $rule['variants'] ) && is_array( $rule['variants'] ) )
			? array_values( $rule['variants'] )
			: array();
		// Wording #1 is the main message field, not a row here.
		array_shift( $variants );

		$mode = $rule['variant_mode'] ?? 'rotate';
		$pick = (int) ( $rule['variant_pick'] ?? 0 );
		$lang = Mersal_Notif_Settings::get( 'lang', 'ar' );
		$ready = class_exists( 'Mersal_Notif_Library' ) ? Mersal_Notif_Library::variants( $trigger, $lang ) : array();

		$this->card_open(
			'shuffle',
			$en ? 'Alternative wordings' : 'صيغ بديلة للرسالة',
			$en
				? 'Keep several versions of this notification and Mersal sends a different one each time — the single most effective way to keep a WhatsApp number healthy.'
				: 'خزّن أكتر من صيغة لنفس الإشعار ومرسال هتبعت صيغة مختلفة كل مرة — دي أقوى حاجة بتحافظ على رقم الواتساب من الحظر.'
		);

		echo '<div class="mnotif-var-modes">';
		foreach ( array(
			'rotate' => array( 'repeat', $en ? 'Rotate in order' : 'تبديل بالترتيب', $en ? 'Every wording is used before any repeats' : 'كل الصيغ بتتستخدم قبل ما أي واحدة تتكرر' ),
			'random' => array( 'shuffle', $en ? 'Random' : 'عشوائي', $en ? 'Picked at random, never twice in a row' : 'اختيار عشوائي من غير تكرار مرتين ورا بعض' ),
			'fixed'  => array( 'push_pin', $en ? 'Pin one' : 'صيغة ثابتة', $en ? 'Always send the wording you choose' : 'ابعت دايمًا الصيغة اللي تختارها' ),
		) as $mv => $ml ) {
			echo '<label class="mnotif-var-mode' . ( $mode === $mv ? ' is-on' : '' ) . '">';
			echo '<input type="radio" name="variant_mode" value="' . esc_attr( $mv ) . '" ' . checked( $mode, $mv, false ) . ' data-mnotif-var-mode>';
			echo '<span class="mi">' . esc_html( $ml[0] ) . '</span>';
			echo '<b>' . esc_html( $ml[1] ) . '</b><span class="d">' . esc_html( $ml[2] ) . '</span>';
			echo '</label>';
		}
		echo '</div>';

		// Wording 1 is the main message field above; it still needs a pin control
		// so "Pin one" can choose it, which is the common case.
		echo '<div class="mnotif-var is-main">';
		echo '<div class="mnotif-var-top">';
		echo '<b>' . esc_html( $en ? 'Wording 1' : 'الصيغة 1' ) . '</b>';
		echo '<label class="mnotif-var-pin"><input type="radio" name="variant_pick" value="0" ' . checked( $pick, 0, false ) . '> ' . esc_html( $en ? 'Send this one' : 'ابعت دي' ) . '</label>';
		echo '<span class="mnotif-var-note">' . esc_html( $en ? 'This is the message body above.' : 'دي نص الرسالة اللي فوق.' ) . '</span>';
		echo '</div></div>';

		if ( $ready ) {
			echo '<div class="row" style="gap:8px;flex-wrap:wrap;margin-bottom:14px;">';
			echo '<button type="button" class="btn" data-mnotif-fill-var><span class="mi sm">auto_awesome</span>'
				. esc_html( $en ? 'Use the 5 ready-made wordings' : 'استخدم الـ5 صيغ الجاهزة' ) . '</button>';
			echo '<span class="hint" style="align-self:center;">' . esc_html(
				$en
					? 'Written for this exact event, using your placeholders. Replaces the message above and the list below.'
					: 'متكتوبة مخصوص للحدث ده وبتستخدم المتغيرات بتاعتك. بتستبدل الرسالة اللي فوق والقائمة اللي تحت.'
			) . '</span>';
			echo '</div>';
		}

		if ( class_exists( 'Mersal_Suite_Fields' ) ) {
			Mersal_Suite_Fields::message_list(
				array(
					'name'         => 'variants',
					'items'        => $variants,
					'defaults'     => array_slice( $ready, 1 ),
					'title'        => $en ? 'The other wordings' : 'باقي الصيغ',
					'desc'         => $en
						? 'Mersal sends a different one each time, so no two customers get the same text.'
						: 'مرسال بتبعت واحدة مختلفة كل مرة، فمفيش عميلين بياخدوا نفس النص.',
					'icon'         => 'shuffle',
					'lang'         => $en ? 'en' : 'ar',
					'rows'         => 4,
					'pin_name'     => 'variant_pick',
					'pin_value'    => $pick,
					'pin_offset'   => 1,
					'pin_label'    => $en ? 'Send this one' : 'ابعت دي',
					'pin_hidden'   => ( 'fixed' !== $mode ),
					'add_label'    => $en ? 'Add a wording' : 'إضافة صيغة',
					'placeholders' => array_slice( $this->core->get_placeholders(), 0, 8, true ),
					'hint'         => $en
						? 'Wording 1 is the message body above. Leave this list empty to send only that.'
						: 'الصيغة 1 هي نص الرسالة اللي فوق. سيب القائمة دي فاضية عشان تبعت هي بس.',
				)
			);
		} else {
			// An older sibling plugin's Suite SDK is loaded and has no list editor;
			// fall back to the plain rows rather than lose the field entirely.
			echo '<div data-mnotif-vars>';
			foreach ( $variants as $i => $v ) {
				$this->variant_row( $i, $v, $pick, $en );
			}
			echo '</div>';
			echo '<button type="button" class="btn" data-mnotif-add-var><span class="mi sm">add</span>' . esc_html( $en ? 'Add a wording' : 'إضافة صيغة' ) . '</button>';
		}

		$this->card_close();
		?>
		<script>
		(function(){
			var fill = document.querySelector('[data-mnotif-fill-var]');
			var main = document.querySelector('[data-mnotif-msg]');
			var ready = <?php echo wp_json_encode( array_values( $ready ) ); ?>;
			var confirmMsg = <?php echo wp_json_encode(
				$en
					? 'Replace the message and all wordings with the five ready-made ones?'
					: 'تستبدل الرسالة وكل الصيغ بالخمس صيغ الجاهزة؟'
			); ?>;

			if (fill && ready.length) {
				fill.addEventListener('click', function () {
					if (!window.confirm(confirmMsg)) return;
					if (main) {
						main.value = ready[0];
						main.dispatchEvent(new Event('input', { bubbles: true }));
					}
					// Wording 1 is the main body, so the list takes 2..n. The shared
					// editor owns its own rows — click its restore button rather than
					// reach into its markup from here.
					var restore = document.querySelector('[data-ms-list] [data-ms-restore]');
					if (restore) {
						var was = window.confirm;
						window.confirm = function () { return true; }; // already asked
						restore.click();
						window.confirm = was;
					}
				});
			}

			// "Pin one" only makes sense in fixed mode; the shared editor starts
			// those controls hidden and this reveals them when the mode changes.
			function syncMode(){
				var m = document.querySelector('[data-mnotif-var-mode]:checked');
				var fixed = m && m.value === 'fixed';
				document.querySelectorAll('[data-ms-pin-wrap], .mnotif-var-pin').forEach(function(el){
					el.style.display = fixed ? '' : 'none';
				});
				document.querySelectorAll('.mnotif-var-mode').forEach(function(el){
					el.classList.toggle('is-on', el.querySelector('input').checked);
				});
			}
			document.querySelectorAll('[data-mnotif-var-mode]').forEach(function(el){
				el.addEventListener('change', syncMode);
			});
			syncMode();
		})();
		</script>
		<?php
	}

	/**
	 * One alternative-wording row.
	 *
	 * @param int    $i    Zero-based index within the extra wordings.
	 * @param string $v    The wording.
	 * @param int    $pick Pinned index (1-based across the whole list).
	 * @param bool   $en   English UI?
	 */
	private function variant_row( $i, $v, $pick, $en ) {
		$n = $i + 1;
		echo '<div class="mnotif-var" data-var-row>';
		echo '<div class="mnotif-var-top">';
		echo '<b data-var-n>' . esc_html( ( $en ? 'Wording ' : 'الصيغة ' ) . ( $n + 1 ) ) . '</b>';
		echo '<label class="mnotif-var-pin"><input type="radio" name="variant_pick" value="' . esc_attr( $n ) . '" ' . checked( $pick, $n, false ) . '> ' . esc_html( $en ? 'Send this one' : 'ابعت دي' ) . '</label>';
		echo '<button type="button" class="btn ghost sm" data-var-del><span class="mi sm">delete</span>' . esc_html( $en ? 'Remove' : 'حذف' ) . '</button>';
		echo '</div>';
		echo '<textarea class="textarea" rows="4" name="variants[' . esc_attr( $n ) . ']">' . esc_textarea( $v ) . '</textarea>';
		echo '</div>';
	}

	private function trigger_description( $key, $label, $en ) {
		$fixed = array(
			'user_register'       => $en ? 'Sent automatically when a new user registers on your site.' : 'يُرسل تلقائيًا عند تسجيل مستخدم جديد في موقعك.',
			'wp_login'            => $en ? 'Sent automatically when a user logs into your site.' : 'يُرسل تلقائيًا عند تسجيل دخول مستخدم لموقعك.',
			'user_password_reset' => $en ? 'Sent after a user successfully resets their password.' : 'يُرسل بعد إعادة تعيين المستخدم لكلمة المرور بنجاح.',
			'wc_new_order'        => $en ? 'Sent the moment a new order is placed at checkout.' : 'يُرسل لحظة إنشاء طلب جديد من صفحة الدفع.',
			'wc_payment_complete' => $en ? 'Sent when the payment for an order is confirmed.' : 'يُرسل عند تأكيد استلام دفع الطلب.',
			'wc_order_note_added' => $en ? 'Sent when a new customer note is added to an order.' : 'يُرسل عند إضافة ملاحظة جديدة للعميل على الطلب.',
			'wc_sub_renewal_payment_complete' => $en ? 'Sent when a subscription renewal payment is successfully processed.' : 'يُرسل عند نجاح دفع تجديد الاشتراك.',
			'ac_shopping'         => $en ? 'Fires while a reachable customer has an active cart — great for gentle nudges.' : 'ينطلق عندما يكون لدى عميل (يمكن الوصول له) سلة نشطة — مناسب لتنبيه لطيف.',
			'ac_potential'        => $en ? 'Fires when a visitor leaves their contact but has no cart yet.' : 'ينطلق عندما يترك الزائر بيانات تواصله دون سلة بعد.',
			'ac_abandoned'        => $en ? 'Fires when a cart with contact details goes inactive past the threshold.' : 'ينطلق عندما تتحول سلة ببيانات تواصل إلى متروكة بعد مدة الخمول.',
		);
		if ( isset( $fixed[ $key ] ) ) {
			return $fixed[ $key ];
		}
		if ( 0 === strpos( $key, 'wc_status_' ) ) {
			/* translators: %s: order status label */
			return sprintf( $en ? 'Sent when an order status is updated to “%s”.' : 'يُرسل عند تحول حالة الطلب إلى «%s».', wp_strip_all_tags( $label ) );
		}
		if ( 0 === strpos( $key, 'wc_sub_' ) ) {
			/* translators: %s: subscription status label */
			return sprintf( $en ? 'Sent when a subscription is marked as “%s”.' : 'يُرسل عند تحول حالة الاشتراك إلى «%s».', wp_strip_all_tags( $label ) );
		}
		if ( 0 === strpos( $key, 'custom_' ) ) {
			return $en ? "Fire it from code: do_action( 'mnotif_trigger', '" . str_replace( 'custom_', '', $key ) . "', array( 'phone' => '…' ) );" : "أطلقه من الكود: do_action( 'mnotif_trigger', '" . str_replace( 'custom_', '', $key ) . "', array( 'phone' => '…' ) );";
		}
		/* translators: %s: event label */
		return sprintf( $en ? 'This notification triggers on the “%s” event.' : 'يُرسل هذا الإشعار عند حدث «%s».', wp_strip_all_tags( $label ) );
	}

	/**
	 * Visual event picker: category chips + live search + selectable event
	 * cards. Custom events are managed inline (add/delete) — the old separate
	 * "Custom events" screen is merged right here.
	 *
	 * @param string $current Selected trigger key.
	 * @param bool   $en      English.
	 */
	private function trigger_select( $current, $en ) {
		$triggers = $this->core->get_triggers();
		$cats     = self::trigger_categories( $en );

		$present = array();
		foreach ( $triggers as $key => $label ) {
			$cat = self::trigger_category( $key );
			$present[ $cat ] = isset( $present[ $cat ] ) ? $present[ $cat ] + 1 : 1;
		}
		$cur_cat = $current ? self::trigger_category( $current ) : '';

		echo '<div data-mnotif-evpick data-nonce="' . esc_attr( wp_create_nonce( 'mnotif_rule' ) ) . '">';

		// Real form field (hidden — the cards drive it).
		echo '<select name="trigger_key" data-mnotif-trig hidden style="display:none;"><option value=""></option>';
		foreach ( $triggers as $key => $label ) {
			echo '<option value="' . esc_attr( $key ) . '" ' . selected( $current, $key, false ) . '>' . esc_html( $label ) . '</option>';
		}
		echo '</select>';

		// Top bar: category chips + search.
		echo '<div class="ntp-top">';
		echo '<div class="ntp-cats" data-ntp-cats>';
		echo '<span class="ntp-chip sel" data-ntp-cat=""><span class="mi">apps</span>' . esc_html( $en ? 'All' : 'الكل' ) . '<span class="cnt">' . esc_html( number_format_i18n( count( $triggers ) ) ) . '</span></span>';
		foreach ( $cats as $ck => $cm ) {
			// "Custom" is always offered so the add-event box is reachable.
			if ( empty( $present[ $ck ] ) && 'custom' !== $ck ) {
				continue;
			}
			echo '<span class="ntp-chip" data-ntp-cat="' . esc_attr( $ck ) . '"><span class="mi">' . esc_html( $cm[0] ) . '</span>' . esc_html( $cm[1] ) . '<span class="cnt">' . esc_html( number_format_i18n( $present[ $ck ] ?? 0 ) ) . '</span></span>';
		}
		echo '</div>';
		echo '<div class="ntp-search"><span class="mi">search</span><input type="text" data-ntp-search placeholder="' . esc_attr( $en ? 'Search events…' : 'ابحث عن حدث…' ) . '"></div>';
		echo '</div>';

		// Event cards.
		echo '<div class="ntp-grid" data-ntp-grid>';
		foreach ( $triggers as $key => $label ) {
			$cat   = self::trigger_category( $key );
			$icon  = isset( $cats[ $cat ] ) ? $cats[ $cat ][0] : 'bolt';
			$desc  = $this->trigger_description( $key, $label, $en );
			$sel   = ( $current === $key ) ? ' sel' : '';
			$label = preg_replace( '/^[^:]+:\s*/u', '', (string) $label ); // category prefix lives on the chip already.
			echo '<div class="ntp-card' . esc_attr( $sel ) . '" data-ev="' . esc_attr( $key ) . '" data-cat="' . esc_attr( $cat ) . '" data-txt="' . esc_attr( mb_strtolower( $label . ' ' . $key ) ) . '">';
			echo '<span class="ei"><span class="mi">' . esc_html( $icon ) . '</span></span>';
			echo '<span style="min-width:0;flex:1;"><b>' . esc_html( $label ) . '</b><span class="ed">' . esc_html( $desc ) . '</span></span>';
			echo '<span class="ck"></span>';
			if ( 0 === strpos( $key, 'custom_' ) ) {
				echo '<button type="button" class="evdel" data-ntp-evdel="' . esc_attr( substr( $key, 7 ) ) . '" title="' . esc_attr( $en ? 'Delete this custom event' : 'حذف هذا الحدث المخصص' ) . '"><span class="mi">delete</span></button>';
			}
			echo '</div>';
		}
		echo '<div class="ntp-empty" data-ntp-empty hidden>' . esc_html( $en ? 'No events match your search.' : 'لا توجد أحداث مطابقة لبحثك.' ) . '</div>';
		echo '</div>';

		// Inline custom-event creator (merged from the old Custom events screen).
		echo '<div class="ntp-addrow">';
		echo '<span class="mi" style="width:18px;height:18px;color:var(--accent);">webhook</span>';
		echo '<input type="text" data-ntp-evname placeholder="' . esc_attr( $en ? 'Create a custom event… e.g. Loyalty reward' : 'أنشئ حدثًا مخصصًا… مثال: مكافأة الولاء' ) . '">';
		echo '<button type="button" class="btn primary sm" data-ntp-evadd><span class="mi sm">add</span>' . ( $en ? 'Add event' : 'إضافة حدث' ) . '</button>';
		echo '</div>';
		echo '<details class="ntp-dev"><summary>' . esc_html( $en ? 'How do I fire a custom event from code?' : 'إزاي أطلق الحدث المخصص من الكود؟' ) . '</summary>';
		echo '<pre class="mnotif-code">' . esc_html(
			"do_action( 'mnotif_trigger', 'your_slug', array(\n" .
			"    'user_id'      => 123,            // or pass phone/email directly\n" .
			"    'phone'        => '201000000000',\n" .
			"    'email'        => 'a@b.com',\n" .
			"    'name'         => 'Ahmed',\n" .
			"    'replacements' => array( 'reward' => '50 EGP', 'code' => 'VIP50' ),\n" .
			") );"
		) . '</pre>';
		echo '<p class="hint">' . esc_html( $en ? 'Your custom {{reward}} / {{code}} placeholders become available in the rule message.' : 'متغيراتك المخصّصة {{reward}} / {{code}} تصبح متاحة في رسالة القاعدة.' ) . '</p>';
		echo '</details>';

		echo '</div>'; // data-mnotif-evpick
		?>
		<script>
		(function(){
			var box  = document.querySelector('[data-mnotif-evpick]');
			if (!box) return;
			var sel   = box.querySelector('[data-mnotif-trig]');
			var grid  = box.querySelector('[data-ntp-grid]');
			var cats  = box.querySelector('[data-ntp-cats]');
			var search= box.querySelector('[data-ntp-search]');
			var empty = box.querySelector('[data-ntp-empty]');
			var cards = Array.prototype.slice.call(grid.querySelectorAll('.ntp-card'));
			var curCat = '', q = '';

			function applyFilter(){
				var shown = 0;
				cards.forEach(function(c){
					var okCat = !curCat || c.getAttribute('data-cat') === curCat;
					var okQ   = !q || (c.getAttribute('data-txt')||'').indexOf(q) !== -1;
					var show  = okCat && okQ;
					c.style.display = show ? '' : 'none';
					if (show) shown++;
				});
				if (empty) empty.hidden = shown > 0;
			}
			function pick(card){
				cards.forEach(function(c){ c.classList.remove('sel'); });
				card.classList.add('sel');
				sel.value = card.getAttribute('data-ev');
				sel.dispatchEvent(new Event('change', {bubbles:true}));
			}
			grid.addEventListener('click', function(e){
				var del = e.target.closest('[data-ntp-evdel]');
				if (del){
					e.stopPropagation();
					if (!confirm(<?php echo wp_json_encode( $en ? 'Delete this custom event?' : 'حذف هذا الحدث المخصص؟' ); ?>)) return;
					post('mnotif_del_event', { slug: del.getAttribute('data-ntp-evdel') }).then(function(){ location.reload(); });
					return;
				}
				var card = e.target.closest('.ntp-card');
				if (card) pick(card);
			});
			cats.addEventListener('click', function(e){
				var chip = e.target.closest('[data-ntp-cat]');
				if (!chip) return;
				cats.querySelectorAll('.ntp-chip').forEach(function(c){ c.classList.remove('sel'); });
				chip.classList.add('sel');
				curCat = chip.getAttribute('data-ntp-cat');
				applyFilter();
			});
			if (search) search.addEventListener('input', function(){ q = (search.value||'').trim().toLowerCase(); applyFilter(); });

			/* Inline custom-event creator */
			function post(action, data){
				var fd = new FormData(); fd.append('action', action); fd.append('nonce', box.getAttribute('data-nonce'));
				Object.keys(data||{}).forEach(function(k){ fd.append(k, data[k]); });
				return fetch(<?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();});
			}
			var addBtn = box.querySelector('[data-ntp-evadd]'), addName = box.querySelector('[data-ntp-evname]');
			if (addBtn) addBtn.addEventListener('click', function(){
				var v = (addName.value||'').trim(); if(!v){ addName.focus(); return; }
				addBtn.disabled = true;
				post('mnotif_add_event', { label: v }).then(function(){ location.reload(); });
			});

			/* Editing an existing rule: focus its category + scroll to the card. */
			var pre = grid.querySelector('.ntp-card.sel');
			if (pre){
				var pc = cats.querySelector('[data-ntp-cat="'+pre.getAttribute('data-cat')+'"]');
				if (pc) pc.click();
				setTimeout(function(){ try{ pre.scrollIntoView({block:'center'}); }catch(e){} }, 60);
			}
		})();
		</script>
		<?php
	}

	/**
	 * Multi-select tiles (checkboxes) for channels / recipients.
	 *
	 * @param string $name     Field name (posts as name[]).
	 * @param array  $selected Selected values.
	 * @param array  $options  value => [icon, label].
	 */
	private function check_tiles( $name, $selected, $options ) {
		$selected = array_map( 'strval', (array) $selected );
		echo '<div class="mnotif-tiles" data-mnotif-tiles>';
		foreach ( $options as $key => $o ) {
			$on = in_array( (string) $key, $selected, true );
			echo '<label class="mnotif-tile' . ( $on ? ' sel' : '' ) . '">';
			echo '<input type="checkbox" name="' . esc_attr( $name ) . '[]" value="' . esc_attr( $key ) . '" ' . checked( $on, true, false ) . '>';
			echo '<span class="ti"><span class="mi">' . esc_html( $o[0] ) . '</span></span>';
			echo '<span class="tl"><b>' . esc_html( $o[1] ) . '</b></span>';
			echo '<span class="tc mi">check_circle</span>';
			echo '</label>';
		}
		echo '</div>';
	}

	/**
	 * Placeholder insert toolbar.
	 *
	 * @param string $target Field name target.
	 * @param array  $phs    placeholder => label.
	 */
	private function placeholder_toolbar( $target, $phs ) {
		echo '<div class="mnotif-ph" data-ph-for="' . esc_attr( $target ) . '">';
		echo '<span class="phl">' . esc_html__( 'Insert:', 'mersal-notifications' ) . '</span>';
		foreach ( $phs as $code => $label ) {
			echo '<button type="button" class="phb" data-ph="' . esc_attr( $code ) . '" title="' . esc_attr( $label ) . '">' . esc_html( trim( $code, '{}' ) ) . '</button>';
		}
		echo '</div>';
	}

	/**
	 * Inline JS for the rule builder (tiles, placeholders, preview, media, email-only).
	 */
	private function builder_js( $lang = 'ar' ) {
		$en    = ( 'en' === $lang );
		$ajax  = admin_url( 'admin-ajax.php' );
		$nonce = wp_create_nonce( 'mnotif_rule' );
		$brand = trim( wp_strip_all_tags( (string) get_bloginfo( 'name' ) ) );

		// Spam-trigger / banned terminology checked client-side (en + ar).
		$banned = array(
			'free', 'click here', 'buy now', 'order now', 'act now', 'limited time', 'urgent',
			'winner', 'congratulations', 'guarantee', 'risk-free', '100%', 'cash', 'prize', 'cheap', 'discount code',
			'مجانا', 'مجاني', 'مجانًا', 'اضغط هنا', 'اشتري الان', 'اطلب الان', 'عاجل', 'اربح', 'مبروك', 'فرصة لا تعوض', 'خصم حصري',
		);

		// All analyzer labels + fix suggestions, pre-localized for the JS.
		$az = array(
			'cat'  => array(
				'compliance' => $en ? 'Anti-Ban & Compliance' : 'مكافحة الحظر والامتثال',
				'structure'  => $en ? 'Structure & Humanity' : 'البنية والطابع البشري',
				'engage'     => $en ? 'Engagement & Technical' : 'التفاعل والتقنية',
			),
			'lbl'  => array(
				'banned'   => $en ? 'Banned terminology' : 'مصطلحات محظورة',
				'optout'   => $en ? 'Opt-out (interaction)' : 'إلغاء الاشتراك (تفاعل)',
				'link'     => $en ? 'Link placement' : 'موضع الروابط',
				'clickbait'=> $en ? 'Clickbait detection' : 'كشف التصيّد (Clickbait)',
				'length'   => $en ? 'Optimal length' : 'الطول الأمثل',
				'read'     => $en ? 'Readability complexity' : 'سهولة القراءة',
				'white'    => $en ? 'Visual structure (white space)' : 'البنية البصرية (مسافات)',
				'rich'     => $en ? 'Rich content (emojis & formatting)' : 'محتوى غني (إيموجي وتنسيق)',
				'perso'    => $en ? 'Personalization intensity' : 'كثافة التخصيص',
				'cta'      => $en ? 'Interaction hook (CTA)' : 'محفّز التفاعل (CTA)',
				'spintax'  => $en ? 'Content diversity (SpinTax)' : 'تنويع المحتوى (SpinTax)',
				'brand'    => $en ? 'Brand signature' : 'توقيع العلامة التجارية',
				'ratio'    => $en ? 'Link vs length ratio' : 'نسبة الروابط للطول',
				'subject'  => $en ? 'Email subject' : 'عنوان الإيميل',
			),
			'fix'  => array(
				'banned'    => $en ? 'Avoid spam-trigger words (%s) — rephrase to sound natural.' : 'تجنّب كلمات تثير فلاتر السبام (%s) — أعد الصياغة بشكل طبيعي.',
				'optout'    => $en ? 'Add "Reply STOP to unsubscribe" to build sender reputation.' : 'أضف «أرسل STOP لإلغاء الاشتراك» لتحسين سمعة المُرسِل.',
				'link_start'=> $en ? 'Don\'t start with a link — add context first.' : 'لا تبدأ الرسالة برابط — أضف سياقًا أولًا.',
				'link_many' => $en ? 'Too many links — keep to one to avoid spam filters.' : 'روابط كثيرة — اكتفِ برابط واحد لتفادي فلاتر السبام.',
				'clickbait' => $en ? 'Reduce ALL-CAPS / excessive "!" — it looks like spam.' : 'قلّل الأحرف الكبيرة و«!» الزائدة — تبدو كسبام.',
				'short'     => $en ? 'A bit short — add more useful context.' : 'قصيرة شوية — أضف سياقًا مفيدًا.',
				'long'      => $en ? 'Too long — trim it for better delivery.' : 'طويلة جدًا — اختصرها لتسليم أفضل.',
				'read'      => $en ? 'Long sentences — break them into shorter ones.' : 'جمل طويلة — قسّمها لجمل أقصر.',
				'white'     => $en ? 'Solid text block detected. Add double line breaks between paragraphs.' : 'نص متلاصق — أضف فواصل أسطر مزدوجة بين الفقرات.',
				'rich'      => $en ? 'Add 1–2 emojis to look more human (don\'t overdo it).' : 'أضف ١–٢ إيموجي ليبدو النص بشريًا (بدون مبالغة).',
				'perso'     => $en ? 'Add a placeholder like {{name}} to personalize.' : 'أضف متغيرًا مثل {{name}} للتخصيص.',
				'cta'       => $en ? 'Add a clear call-to-action or a question.' : 'أضف دعوة واضحة لاتخاذ إجراء أو سؤالًا.',
				'spintax'   => $en ? 'Optional: use {Hi|Hello} to vary delivery and avoid duplicates.' : 'اختياري: استخدم {مرحبا|أهلاً} لتنويع الإرسال وتفادي التكرار.',
				'brand'     => $en ? 'Add your store name / signature at the message end.' : 'أضف اسم متجرك / التوقيع في نهاية الرسالة.',
				'ratio'     => $en ? 'Message is mostly links — add real content.' : 'الرسالة أغلبها روابط — أضف محتوى حقيقيًا.',
				'subject'   => $en ? 'Email channel is on but the subject is empty.' : 'قناة الإيميل مفعّلة بدون عنوان.',
			),
			'ui'   => array(
				'passed' => $en ? 'Passed' : 'ناجحة',
				'issues' => $en ? 'Issues' : 'مشاكل',
				'ms'     => $en ? 'MS ANALYSIS' : 'مللي/تحليل',
				'iss'    => $en ? 'Issues found' : 'توجد مشاكل',
				'ok'     => $en ? 'Success' : 'ممتاز',
				'accept' => $en ? 'Acceptance' : 'القبول',
				'qual'   => $en ? 'message quality' : 'جودة الرسالة',
				'empty'  => $en ? 'Start typing your message to analyze it…' : 'ابدأ كتابة رسالتك ليتم تحليلها…',
				'words'  => $en ? 'words/sentence' : 'كلمة/جملة',
				'lines'  => $en ? 'lines' : 'سطر',
			),
		);
		?>
		<script>
		(function(){
			var form = document.querySelector('.mnotif-app form[action*="admin-post"]');
			if (!form || !form.querySelector('[data-mnotif-msg]')) return;
			var ajax = <?php echo wp_json_encode( $ajax ); ?>, nonce = <?php echo wp_json_encode( $nonce ); ?>;

			/* ---- Wizard navigation ---- */
			var wsteps = Array.prototype.slice.call(form.querySelectorAll('.mnotif-wiz .wstep'));
			var panels = Array.prototype.slice.call(form.querySelectorAll('.mnotif-step'));
			var back = form.querySelector('[data-wiz-back]'), next = form.querySelector('[data-wiz-next]'), save = form.querySelector('[data-wiz-save]');
			var cur = 1, total = panels.length;
			function trigVal(){ var t=form.querySelector('[name="trigger_key"]'); return t? t.value : ''; }
			function showStep(n){
				cur = Math.max(1, Math.min(total, n));
				panels.forEach(function(p){ p.hidden = (+p.getAttribute('data-step') !== cur); });
				wsteps.forEach(function(w,i){ w.classList.toggle('active',(i+1)===cur); w.classList.toggle('done',(i+1)<cur); });
				if (back) back.hidden = cur===1;
				var last = cur===total;
				if (next) next.hidden = last;
				if (save) save.hidden = !last;
				if (last) buildReview();
				window.scrollTo({top:0,behavior:'smooth'});
			}
			if (next) next.addEventListener('click', function(){
				if (cur===1 && !trigVal()){ alert(<?php echo wp_json_encode( $en ? 'Please choose an event first.' : 'اختر الحدث أولًا.' ); ?>); return; }
				showStep(cur+1);
			});
			if (back) back.addEventListener('click', function(){ showStep(cur-1); });
			wsteps.forEach(function(w){ w.addEventListener('click', function(){ showStep(+w.getAttribute('data-go')); }); });

			function buildReview(){
				var box = form.querySelector('[data-mnotif-review]'); if(!box) return;
				function v(n){ var el=form.querySelector('[name="'+n+'"]'); return el? el.value : ''; }
				var ch = channelsOn().join(', ') || '—';
				var rc = Array.prototype.slice.call(form.querySelectorAll('input[name="recipients[]"]:checked')).map(function(i){return i.value;}).join(' + ') || '—';
				var trigTxt = ''; var ts=form.querySelector('[name="trigger_key"]'); if(ts&&ts.selectedIndex>=0) trigTxt=ts.options[ts.selectedIndex].text;
				var rows = [
					['<?php echo esc_js( 'Event' ); ?>', trigTxt||'—'],
					['<?php echo esc_js( 'Name' ); ?>', v('name')||'—'],
					['<?php echo esc_js( 'Channels' ); ?>', ch],
					['<?php echo esc_js( 'Recipients' ); ?>', rc],
					['<?php echo esc_js( 'Delay' ); ?>', (v('delay_value')||'0')+' '+(v('delay_unit')||'minutes')],
					['<?php echo esc_js( 'Cooldown' ); ?>', (v('cooldown_hours')||'0')+' h']
				];
				box.innerHTML = rows.map(function(){return '<div class="rrow"><span></span><b></b></div>';}).join('');
				box.querySelectorAll('.rrow').forEach(function(d,i){ d.querySelector('span').textContent=rows[i][0]; d.querySelector('b').textContent=rows[i][1]; });
			}

			/* Tiles toggle */
			form.querySelectorAll('[data-mnotif-tiles]').forEach(function(box){
				box.addEventListener('change', function(){
					box.querySelectorAll('.mnotif-tile').forEach(function(t){ t.classList.toggle('sel', t.querySelector('input').checked); });
					syncEmailOnly();
				});
			});
			function channelsOn(){ return Array.prototype.slice.call(form.querySelectorAll('input[name="channels[]"]:checked')).map(function(i){return i.value;}); }
			function syncEmailOnly(){ var on = channelsOn().indexOf('email')>=0; form.querySelectorAll('.email-only').forEach(function(e){ e.style.display = on?'':'none'; }); }
			syncEmailOnly();

			/* Placeholder insert */
			form.querySelectorAll('.mnotif-ph').forEach(function(bar){
				var target = form.querySelector('[name="'+bar.getAttribute('data-ph-for')+'"]');
				bar.querySelectorAll('.phb').forEach(function(b){
					b.addEventListener('click', function(){
						if(!target) return;
						var s=target.selectionStart||target.value.length, e=target.selectionEnd||target.value.length;
						target.value = target.value.slice(0,s)+b.getAttribute('data-ph')+target.value.slice(e);
						target.focus(); preview();
					});
				});
			});

			/* Live preview */
			var msg = form.querySelector('[data-mnotif-msg]'), pv = form.querySelector('[data-mnotif-preview]'), t;
			function preview(){
				if(!msg||!pv) return;
				clearTimeout(t); t=setTimeout(function(){
					var fd=new FormData(); fd.set('action','mnotif_preview'); fd.set('nonce',nonce); fd.set('message',msg.value);
					fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){
						pv.textContent=(res&&res.data)?res.data.preview:msg.value;
					}).catch(function(){ pv.textContent=msg.value; });
				},300);
			}
			if(msg){ msg.addEventListener('input', preview); preview(); }

			/* Media picker */
			var pick=form.querySelector('[data-mnotif-media-pick]'), media=form.querySelector('[data-mnotif-media]');
			if(pick&&media) pick.addEventListener('click', function(){
				if(!window.wp||!wp.media){ media.focus(); return; }
				var fr=wp.media({multiple:false});
				fr.on('select', function(){ var a=fr.state().get('selection').first().toJSON(); media.value=a.url; });
				fr.open();
			});

			/* Media mode: hide the URL box when "none" is selected */
			var mmode=form.querySelector('[data-mnotif-media-mode]'), mbox=form.querySelector('[data-mnotif-media-box]');
			function syncMedia(){ if(mmode&&mbox) mbox.style.display=(mmode.value==='none')?'none':''; }
			if(mmode){ mmode.addEventListener('change', syncMedia); syncMedia(); }

			/* Live test (simulator step): fire the unsaved rule to the current admin */
			var fireBtn=form.querySelector('[data-mnotif-fire-test]');
			if(fireBtn) fireBtn.addEventListener('click', function(){
				var out=form.querySelector('[data-mnotif-test-result]');
				fireBtn.disabled=true; if(out) out.textContent='…';
				var fd=new FormData(form);
				fd.set('action','mnotif_test_draft');
				fd.set('nonce', fireBtn.getAttribute('data-nonce'));
				fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){
					fireBtn.disabled=false;
					if(out) out.textContent=(res&&res.data&&res.data.message)?res.data.message:(res&&res.success?'OK':'—');
				}).catch(function(){ fireBtn.disabled=false; if(out) out.textContent='!'; });
			});

			/* Admin message toggle */
			var admCb=form.querySelector('[data-mnotif-adm]'), admBox=form.querySelector('.mnotif-admbox');
			if(admCb&&admBox) admCb.addEventListener('change', function(){
				admBox.hidden = !admCb.checked;
				if(!admCb.checked){ var m=admBox.querySelector('[name="admin_message"]'); if(m) m.value=''; var s=admBox.querySelector('[name="admin_subject"]'); if(s) s.value=''; }
			});

			/* Trigger quick-search (filters the dropdown options) */
			var trig=form.querySelector('[data-mnotif-trig]'), trigS=form.querySelector('[data-mnotif-trig-search]');
			if(trig&&trigS) trigS.addEventListener('input', function(){
				var q=(trigS.value||'').toLowerCase();
				Array.prototype.forEach.call(trig.querySelectorAll('option'), function(o){
					if(!o.value){ return; }
					var hit = o.textContent.toLowerCase().indexOf(q)>=0;
					o.hidden = !hit; o.disabled = !hit;
				});
			});

			/* ---- Message acceptance analyzer (anti-ban / structure / engagement) ---- */
			var azBox=form.querySelector('[data-mnotif-analyzer]');
			var AZ=<?php echo wp_json_encode( $az ); ?>;
			var BRAND=<?php echo wp_json_encode( $brand ); ?>;
			var BANNED=<?php echo wp_json_encode( $banned ); ?>;
			function emailOn(){ return channelsOn().indexOf('email')>=0; }
			function smsOn(){ return channelsOn().indexOf('sms')>=0; }
			function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];}); }
			function emojiCount(s){ try{ var m=s.match(/[\u{1F000}-\u{1FAFF}\u{2600}-\u{27BF}\u2190-\u21FF\u2B00-\u2BFF\u2700-\u27BF\uFE0F]/gu); return m?m.length:0; }catch(e){ var m2=s.match(/[\u2600-\u27BF\u2190-\u21FF\u2B00-\u2BFF]/g); return m2?m2.length:0; } }

			function buildChecks(){
				var raw=msg.value||'', text=raw.trim(), L=text.length;
				var urls=text.match(/https?:\/\/\S+/gi)||[];
				var phs=text.match(/\{\{[^}]+\}\}/g)||[];
				var spin=/\{[^{}|]+\|[^{}]+\}/.test(raw);
				var emo=emojiCount(raw);
				var hasBreak=/\n[ \t]*\n/.test(raw);
				var lines=raw.split(/\n/).filter(function(l){return l.trim();});
				var excl=(text.match(/[!！]/g)||[]).length;
				var letters=(text.match(/[A-Za-z]/g)||[]).length;
				var caps=(text.match(/[A-Z]/g)||[]).length;
				var capRatio=letters>10?caps/letters:0;
				var low=text.toLowerCase();
				var hit=BANNED.filter(function(w){ return w && low.indexOf(String(w).toLowerCase())>=0; });
				var sentences=text.split(/[.!؟?\n]+/).filter(function(s){return s.trim().length;});
				var longSent=sentences.filter(function(s){return s.trim().split(/\s+/).length>22;}).length;
				var startsLink=/^\s*https?:\/\//i.test(raw);
				var optout=/(unsubscribe|reply stop|\bstop\b|إلغاء|الغاء|توقف|ايقاف|إيقاف)/i.test(low);
				var cta=/(\?|؟|order|buy|shop|click|register|book|claim|download|visit|call|reply|اطلب|اشتري|تسوق|سجل|احجز|حمّل|حمل|تواصل|راسلنا|اتصل|رد)/i.test(low);
				var brandSig = (BRAND && low.indexOf(BRAND.toLowerCase())>=0) || /\{\{\s*(site_name|site|shop_name|store|store_name|company)\s*\}\}/i.test(text);
				var subEl=form.querySelector('[name="email_subject"]');
				var noSub=emailOn() && subEl && !subEl.value.trim();
				var nonLink=text.replace(/https?:\/\/\S+/gi,'').replace(/\{\{[^}]+\}\}/g,'').trim().length;

				function fmt(s,a){ return String(s).replace('%s', a); }
				// status: 'pass' | 'warn' | 'fail'
				var compliance=[
					{ k:'banned', s: hit.length?'fail':'pass', fix: hit.length?fmt(AZ.fix.banned, hit.slice(0,4).join(', ')):'' },
					{ k:'optout', s: optout?'pass':'warn', fix: optout?'':AZ.fix.optout },
					{ k:'link',   s: startsLink?'warn':(urls.length>2?'fail':'pass'), fix: startsLink?AZ.fix.link_start:(urls.length>2?AZ.fix.link_many:'') },
					{ k:'clickbait', s: (capRatio>0.6||excl>=4)?'fail':((capRatio>0.4||excl>=2)?'warn':'pass'), fix: (capRatio>0.4||excl>=2)?AZ.fix.clickbait:'' }
				];
				var avgWords=sentences.length?Math.round(sentences.reduce(function(a,s){return a+s.trim().split(/\s+/).length;},0)/sentences.length):0;
				var structure=[
					{ k:'length', s: L<25?'fail':(L<40||L>900?'warn':'pass'), fix: (L<40)?AZ.fix.short:(L>900?AZ.fix.long:''), note:(L+' / 40–700') },
					{ k:'read',   s: longSent>=2?'warn':'pass', fix: longSent>=2?AZ.fix.read:'', note:(avgWords?('~'+avgWords+' '+AZ.ui.words):'') },
					{ k:'white',  s: (L>200&&!hasBreak)?'warn':'pass', fix:(L>200&&!hasBreak)?AZ.fix.white:'', note:(lines.length+' '+AZ.ui.lines) },
					{ k:'rich',   s: emo>=1?'pass':'warn', fix: emo>=1?'':AZ.fix.rich, note:(emo+' emoji') }
				];
				var engage=[
					{ k:'perso', s: phs.length>=1?'pass':'fail', fix: phs.length>=1?'':AZ.fix.perso, note:(phs.length+' {{…}}') },
					{ k:'cta',   s: cta?'pass':'warn', fix: cta?'':AZ.fix.cta },
					{ k:'spintax', s: spin?'pass':'warn', fix: spin?'':AZ.fix.spintax },
					{ k:'brand', s: brandSig?'pass':'warn', fix: brandSig?'':AZ.fix.brand },
					{ k:'ratio', s: (urls.length>0 && nonLink<20)?'fail':'pass', fix:(urls.length>0&&nonLink<20)?AZ.fix.ratio:'', note:(urls.length+' URL') }
				];
				if(noSub){ compliance.push({ k:'subject', s:'fail', fix:AZ.fix.subject }); }
				return [
					{ key:'compliance', name:AZ.cat.compliance, items:compliance },
					{ key:'structure',  name:AZ.cat.structure,  items:structure },
					{ key:'engage',     name:AZ.cat.engage,     items:engage }
				];
			}

			function render(){
				if(!azBox||!msg) return;
				var t0=(window.performance&&performance.now)?performance.now():Date.now();
				var raw=(msg.value||'').trim();
				azBox.hidden=false;
				if(!raw){ azBox.innerHTML='<div class="mnotif-az-head"><span style="font-size:13px;color:var(--fg-3)">'+esc(AZ.ui.empty)+'</span></div>'; return; }
				var cats=buildChecks();
				var pass=0, fail=0;
				cats.forEach(function(c){ c.items.forEach(function(it){ if(it.s==='pass') pass++; else fail++; }); });
				var total=pass+fail, score=total?Math.round(pass/total*100):0;
				var color=score>=80?'#16a34a':(score>=55?'#d97706':'#dc2626');
				var t1=(window.performance&&performance.now)?performance.now():Date.now();
				var ms=Math.max(1, Math.round(t1-t0));
				var glyph={pass:'✓',warn:'!',fail:'✕'};

				var head=''+
					'<div class="mnotif-az-head">'+
						'<div class="mnotif-az-gauge"><div class="g" style="background:'+color+'">'+score+'</div>'+
						'<div class="gl"><b>'+esc(AZ.ui.accept)+'</b><span>'+esc(AZ.ui.qual)+'</span></div></div>'+
						'<div class="mnotif-az-counts"><i class="pass">✓ '+pass+' '+esc(AZ.ui.passed)+'</i><i class="fail">✕ '+fail+' '+esc(AZ.ui.issues)+'</i></div>'+
						'<div class="mnotif-az-ms">'+ms+' '+esc(AZ.ui.ms)+'</div>'+
						'<div class="mnotif-az-bar"><span style="width:'+score+'%;background:'+color+'"></span></div>'+
					'</div>';

				var body=cats.map(function(c){
					var bad=c.items.some(function(it){return it.s!=='pass';});
					var rows=c.items.map(function(it){
						var lbl=AZ.lbl[it.k]||it.k;
						if(it.note) lbl=lbl+' ('+it.note+')';
						var fix=it.fix?('<div class="mnotif-az-fix"><span class="fi">'+(it.s==='fail'?'✕':'💡')+'</span><span>'+esc(it.fix)+'</span></div>'):'';
						return '<div class="mnotif-az-chk '+it.s+'"><div class="row"><span class="ci">'+glyph[it.s]+'</span><span>'+esc(lbl)+'</span></div>'+fix+'</div>';
					}).join('');
					return '<div class="mnotif-az-cat'+(bad?'':' collapsed')+'" data-az-cat>'+
						'<div class="mnotif-az-cat-h" data-az-toggle><span class="chev">▾</span>'+esc(c.name)+
						'<span class="cbadge '+(bad?'iss':'ok')+'">'+esc(bad?AZ.ui.iss:AZ.ui.ok)+'</span></div>'+
						'<div class="mnotif-az-checks">'+rows+'</div></div>';
				}).join('');

				azBox.innerHTML=head+body;
			}

			azBox && azBox.addEventListener('click', function(e){
				var h=e.target.closest('[data-az-toggle]'); if(!h) return;
				h.parentNode.classList.toggle('collapsed');
			});

			var azT;
			function analyze(){ clearTimeout(azT); azT=setTimeout(render, 220); }
			if(msg){ msg.addEventListener('input', analyze); }
			var subEl2=form.querySelector('[name="email_subject"]'); if(subEl2) subEl2.addEventListener('input', analyze);
			form.querySelectorAll('[data-mnotif-tiles]').forEach(function(b){ b.addEventListener('change', analyze); });
			render();

			showStep(1);
		})();
		</script>
		<?php
	}

	/* ------------------------------------------------------------------ */
	/* Page: Custom events                                                */
	/* ------------------------------------------------------------------ */

	/**
	 * Manage custom events that any code/integration can fire.
	 *
	 * @param string $lang Language.
	 */
	private function page_events( $lang ) {
		$en     = ( 'en' === $lang );
		$events = $this->core->get_custom_events();

		$this->page_head(
			$en ? 'Custom events' : 'الأحداث المخصّصة',
			$en ? 'Define your own events, then create notification rules for them and fire them from anywhere.' : 'عرّف أحداثك الخاصة، ثم أنشئ قواعد إشعارات لها وأطلقها من أي مكان.'
		);

		echo '<div class="card" data-mnotif-events data-nonce="' . esc_attr( wp_create_nonce( 'mnotif_rule' ) ) . '"><div class="card-body">';
		echo '<div class="row" style="gap:8px;align-items:flex-end;margin-bottom:14px;">';
		echo '<div class="field" style="flex:1;margin:0;"><label>' . esc_html( $en ? 'New event name' : 'اسم الحدث الجديد' ) . '</label><input class="input" type="text" data-mnotif-ev-name placeholder="' . esc_attr( $en ? 'E.g. Loyalty reward' : 'مثال: مكافأة الولاء' ) . '"></div>';
		echo '<button type="button" class="btn primary" data-mnotif-ev-add><span class="mi sm">add</span>' . ( $en ? 'Add event' : 'إضافة' ) . '</button>';
		echo '</div>';

		echo '<div data-mnotif-ev-list>';
		if ( empty( $events ) ) {
			$this->empty_state( 'bolt', $en ? 'No custom events yet' : 'لا توجد أحداث مخصّصة', $en ? 'Add one above to get started.' : 'أضف واحدًا بالأعلى للبدء.' );
		} else {
			echo '<table class="table"><thead><tr><th>' . ( $en ? 'Event' : 'الحدث' ) . '</th><th>' . ( $en ? 'Slug' : 'المعرّف' ) . '</th><th style="text-align:end;">' . ( $en ? 'Actions' : 'إجراءات' ) . '</th></tr></thead><tbody>';
			foreach ( $events as $slug => $label ) {
				echo '<tr><td><b>' . esc_html( $label ) . '</b></td><td><code>custom_' . esc_html( $slug ) . '</code></td>';
				echo '<td style="text-align:end;"><button class="btn ghost sm" type="button" data-mnotif-ev-del data-slug="' . esc_attr( $slug ) . '"><span class="mi sm">delete</span></button></td></tr>';
			}
			echo '</tbody></table>';
		}
		echo '</div>';
		echo '</div></div>';

		// Developer usage.
		$this->card_open( 'code', $en ? 'How to fire an event' : 'كيفية إطلاق الحدث' );
		echo '<p style="color:var(--fg-2);margin:0 0 10px;">' . esc_html( $en ? 'Call this from a theme, snippet or another plugin:' : 'استدعِ هذا من القالب أو سنيبت أو إضافة أخرى:' ) . '</p>';
		echo '<pre class="mnotif-code">' . esc_html(
			"do_action( 'mnotif_trigger', 'your_slug', array(\n" .
			"    'user_id'      => 123,            // or pass phone/email directly\n" .
			"    'phone'        => '201000000000',\n" .
			"    'email'        => 'a@b.com',\n" .
			"    'name'         => 'Ahmed',\n" .
			"    'replacements' => array( 'reward' => '50 EGP', 'code' => 'VIP50' ),\n" .
			") );"
		) . '</pre>';
		echo '<p class="hint">' . esc_html( $en ? 'Your custom {{reward}} / {{code}} placeholders become available in the rule message.' : 'متغيراتك المخصّصة {{reward}} / {{code}} تصبح متاحة في رسالة القاعدة.' ) . '</p>';
		$this->card_close();

		$this->events_js();
	}

	/**
	 * Inline JS for the custom-events manager.
	 */
	private function events_js() {
		$ajax = admin_url( 'admin-ajax.php' );
		?>
		<script>
		(function(){
			var box = document.querySelector('[data-mnotif-events]');
			if (!box) return;
			var nonce = box.getAttribute('data-nonce'), ajax = <?php echo wp_json_encode( $ajax ); ?>;
			var add = box.querySelector('[data-mnotif-ev-add]'), name = box.querySelector('[data-mnotif-ev-name]');
			function post(action, data){
				var fd = new FormData(); fd.append('action', action); fd.append('nonce', nonce);
				Object.keys(data||{}).forEach(function(k){ fd.append(k, data[k]); });
				return fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();});
			}
			if (add) add.addEventListener('click', function(){
				var v = (name.value||'').trim(); if(!v){ name.focus(); return; }
				add.disabled = true;
				post('mnotif_add_event', { label: v }).then(function(){ window.location.reload(); });
			});
			box.addEventListener('click', function(e){
				var del = e.target.closest('[data-mnotif-ev-del]');
				if (del){ if(confirm('Delete this event?')) post('mnotif_del_event', { slug: del.getAttribute('data-slug') }).then(function(){ window.location.reload(); }); }
			});
		})();
		</script>
		<?php
	}

	/* ------------------------------------------------------------------ */
	/* Page: Sender settings                                              */
	/* ------------------------------------------------------------------ */

	private function page_sending( $s, $lang ) {
		$en = ( 'en' === $lang );
		$this->saved_notice( $en );
		$this->page_head(
			$en ? 'Sender settings' : 'إعدادات الإرسال',
			$en ? 'Choose which Mersal gateways deliver your notifications.' : 'اختر بوابات مرسال التي تُرسل إشعاراتك.'
		);

		$this->form_open( 'sending' );

		$this->card_open( 'hub', $en ? 'Gateways' : 'البوابات', $en ? 'Pick the gateway per channel (synced from your Mersal account).' : 'اختر البوابة لكل قناة (مزامنة من حسابك).' );
		$this->gateway_select( 'wa_gateway', $s['wa_gateway'] ?? '', 'whatsapp', $lang );
		$this->gateway_select( 'sms_gateway', $s['sms_gateway'] ?? '', 'sms', $lang );
		$this->card_close();

		$this->card_open( 'alternate_email', $en ? 'Email delivery' : 'إرسال البريد' );
		$this->choice_cards( 'email_provider', $s['email_provider'] ?? 'wordpress', $en ? 'Email provider' : 'مزوّد البريد', array(
			'wordpress' => array( 'dns', $en ? 'WordPress / SMTP' : 'وردبريس / SMTP', $en ? 'Send from this server' : 'الإرسال من السيرفر مباشرة' ),
			'mersal'    => array( 'hub', $en ? 'Mersal account' : 'حساب مرسال', $en ? 'Send via your Mersal gateway' : 'الإرسال عبر بوابة مرسال' ),
		) );
		$this->gateway_select( 'email_gateway', $s['email_gateway'] ?? '', 'email', $lang );
		echo '<div class="grid-2">';
		$this->text_field( 'email_from', $s['email_from'] ?? '', $en ? 'From email' : 'بريد المُرسِل', 'noreply@site.com', 'email' );
		$this->text_field( 'email_from_name', $s['email_from_name'] ?? '', $en ? 'From name' : 'اسم المُرسِل' );
		echo '</div>';
		$this->card_close();

		$this->card_open( 'dns', $en ? 'SMTP (optional)' : 'SMTP (اختياري)' );
		echo '<div class="grid-2">';
		$this->text_field( 'smtp_host', $s['smtp_host'] ?? '', 'SMTP Host' );
		$this->number_field( 'smtp_port', $s['smtp_port'] ?? 587, 'SMTP Port' );
		echo '</div>';
		$this->choice_cards( 'smtp_enc', $s['smtp_enc'] ?? 'tls', $en ? 'Encryption' : 'التشفير', array(
			'tls'  => array( 'lock', 'TLS', $en ? 'Recommended (port 587)' : 'مُوصى به (منفذ 587)' ),
			'ssl'  => array( 'verified_user', 'SSL', $en ? 'Port 465' : 'منفذ 465' ),
			'none' => array( 'lock_open', $en ? 'None' : 'بدون', $en ? 'Unencrypted' : 'بدون تشفير' ),
		) );
		echo '<div class="grid-2" style="margin-top:12px;">';
		$this->text_field( 'smtp_user', $s['smtp_user'] ?? '', $en ? 'Username' : 'اسم المستخدم' );
		$this->text_field( 'smtp_pass', $s['smtp_pass'] ?? '', $en ? 'Password' : 'كلمة المرور', '', 'password' );
		echo '</div>';
		$this->card_close();

		// Blacklist: recipients that must never be contacted.
		$this->card_open( 'block', $en ? 'Blacklist' : 'قائمة الحظر', $en ? 'Blocked numbers/emails never receive any notification (logged as "blocked").' : 'الأرقام/الإيميلات المحظورة لا يصلها أي إشعار نهائيًا (تُسجّل كـ«محظور»).' );
		echo '<div class="grid-2">';
		echo '<div class="field"><label>' . esc_html( $en ? 'Blocked numbers (one per line)' : 'أرقام محظورة (رقم في كل سطر)' ) . '</label><textarea class="textarea" name="mnotif[notif_blocked_numbers]" rows="5" style="direction:ltr;text-align:start;" placeholder="20100000000">' . esc_textarea( $s['notif_blocked_numbers'] ?? '' ) . '</textarea></div>';
		echo '<div class="field"><label>' . esc_html( $en ? 'Blocked emails (or @domain.com)' : 'إيميلات محظورة (أو @domain.com)' ) . '</label><textarea class="textarea" name="mnotif[notif_blocked_emails]" rows="5" style="direction:ltr;text-align:start;" placeholder="spam@example.com&#10;@baddomain.com">' . esc_textarea( $s['notif_blocked_emails'] ?? '' ) . '</textarea></div>';
		echo '</div>';
		$this->card_close();

		$this->form_close();
	}

	/* ------------------------------------------------------------------ */
	/* Page: Connect Mersal                                               */
	/* ------------------------------------------------------------------ */

	private function page_mersal( $s, $lang ) {
		$en        = ( 'en' === $lang );
		$connected = $this->connect->is_connected();
		$this->page_head(
			$en ? 'Connect Mersal' : 'ربط حساب مرسال',
			$en ? 'Link your mersal.it account to send through your gateways.' : 'اربط حساب mersal.it للإرسال عبر بواباتك.'
		);

		// A refusal for want of a subscription is not a retryable error — the
		// customer needs to buy the add-on, so say that and link them to it.
		if ( ! $connected && $this->connect->needs_subscription() ) {
			$this->not_subscribed_banner( $en );
		}

		$this->card_open( 'hub', $en ? 'Account' : 'الحساب' );
		if ( $connected ) {
			echo '<div class="row" style="gap:12px;align-items:center;margin-bottom:14px;"><div class="av" style="width:44px;height:44px;border-radius:12px;background:var(--accent);color:#fff;display:grid;place-items:center;font-weight:700;">' . esc_html( $this->connect->account_initials() ) . '</div>';
			echo '<div><b>' . esc_html( $this->connect->account_name() ) . '</b><div style="color:var(--fg-2);font-size:13px;">' . esc_html( $this->connect->account_email() ) . ' · ' . esc_html( $this->connect->plan_label() ) . '</div></div></div>';
			echo '<div style="display:flex;gap:10px;flex-wrap:wrap;">';
			echo '<a class="btn" href="' . esc_url( $this->connect->sync_gateways_url() ) . '"><span class="mi sm">sync</span>' . ( $en ? 'Sync gateways' : 'مزامنة البوابات' ) . '</a>';
			echo '<a class="btn danger" href="' . esc_url( $this->connect->disconnect_url() ) . '"><span class="mi sm">link_off</span>' . ( $en ? 'Disconnect' : 'فصل' ) . '</a>';
			echo '</div>';
		} else {
			echo '<p style="color:var(--fg-2);margin:0 0 14px;">' . ( $en ? 'You are not connected yet.' : 'لم يتم الربط بعد.' ) . '</p>';
			echo '<a class="btn primary" href="' . esc_url( $this->connect->launch_url() ) . '"><span class="mi sm">login</span>' . ( $en ? 'Connect with Mersal' : 'الربط عبر مرسال' ) . '</a>';
		}
		$this->card_close();

		if ( $connected ) {
			$gws = $this->connect->gateways();
			$this->card_open( 'lan', $en ? 'Your gateways' : 'بواباتك' );
			if ( empty( $gws ) ) {
				$this->empty_state( 'lan', $en ? 'No gateways found' : 'لا توجد بوابات', $en ? 'Add a gateway on mersal.it then click Sync.' : 'أضف بوابة على mersal.it ثم اضغط مزامنة.' );
			} else {
				echo '<table class="table"><thead><tr><th>' . ( $en ? 'Name' : 'الاسم' ) . '</th><th>' . ( $en ? 'Channel' : 'القناة' ) . '</th><th>' . ( $en ? 'Address' : 'العنوان' ) . '</th><th>' . ( $en ? 'Status' : 'الحالة' ) . '</th></tr></thead><tbody>';
				foreach ( $gws as $g ) {
					$g = (array) $g;
					echo '<tr><td>' . esc_html( $g['name'] ?? '' ) . '</td><td>' . esc_html( $g['channel'] ?? $g['type'] ?? '' ) . '</td><td>' . esc_html( $g['address'] ?? '' ) . '</td><td>' . esc_html( $g['status'] ?? '' ) . '</td></tr>';
				}
				echo '</tbody></table>';
			}
			$this->card_close();
		}
	}

	/* ------------------------------------------------------------------ */
	/* Page: Logs                                                         */
	/* ------------------------------------------------------------------ */

	private function page_logs( $lang ) {
		$en  = ( 'en' === $lang );
		$log = $this->core->get_log( 50 );
		$this->page_head( $en ? 'Activity log' : 'سجل النشاط', $en ? 'The last 50 notifications sent.' : 'آخر 50 إشعارًا أُرسل.' );
		echo '<div class="card"><div class="card-body">';
		$this->log_table( $log, $en );
		echo '</div></div>';
	}

	/**
	 * Shared log table renderer.
	 *
	 * @param array $log Log rows.
	 * @param bool  $en  English.
	 */
	private function log_table( $log, $en ) {
		if ( empty( $log ) ) {
			$this->empty_state( 'inbox', $en ? 'No activity yet' : 'لا يوجد نشاط بعد', $en ? 'Notifications you send will appear here.' : 'الإشعارات المُرسلة ستظهر هنا.' );
			return;
		}
		echo '<table class="table"><thead><tr><th>' . ( $en ? 'Recipient' : 'المستلم' ) . '</th><th>' . ( $en ? 'Channel' : 'القناة' ) . '</th><th>' . ( $en ? 'Rule' : 'القاعدة' ) . '</th><th>' . ( $en ? 'Status' : 'الحالة' ) . '</th><th style="text-align:end;">' . ( $en ? 'Time' : 'الوقت' ) . '</th></tr></thead><tbody>';
		foreach ( $log as $r ) {
			echo '<tr><td>' . esc_html( $r['to'] ) . '</td><td>' . $this->channel_chip( $r['channel'] ) . '</td><td>' . esc_html( $r['rule'] ?? '' ) . '</td><td>' . $this->status_chip( $r['status'], $en ) . '</td><td style="text-align:end;color:var(--fg-2);font-size:12px;">' . esc_html( $this->ago( $r['time'], $en ) ) . '</td></tr>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}
		echo '</tbody></table>';
	}

	/* ------------------------------------------------------------------ */
	/* Page: Abandoned carts                                              */
	/* ------------------------------------------------------------------ */

	private function page_cart( $s, $lang ) {
		$en = ( 'en' === $lang );
		$this->page_head(
			$en ? 'Abandoned carts' : 'السلات المتروكة',
			$en ? 'Track the cart journey, capture contacts early, and win carts back automatically.' : 'تتبّع رحلة السلة، التقط بيانات التواصل مبكرًا، واسترجع السلات تلقائيًا.',
			'<a class="btn primary" href="' . esc_url( add_query_arg( 'trigger', 'ac_abandoned', $this->page_url( 'edit' ) ) ) . '"><span class="mi sm">add</span>' . ( $en ? 'New recovery rule' : 'قاعدة استرجاع جديدة' ) . '</a>'
		);
		$this->saved_notice( $en );

		$stats = class_exists( 'Mersal_Notif_Abandoned_Cart' ) ? Mersal_Notif_Abandoned_Cart::get_admin_stats() : array();
		$cur   = function_exists( 'get_woocommerce_currency_symbol' ) ? html_entity_decode( get_woocommerce_currency_symbol() ) : '';
		echo '<div class="grid-4" style="margin-bottom:20px;">';
		$this->stat( 'shopping_cart', 'cyan', $en ? 'Tracked sessions' : 'جلسات متتبَّعة', number_format_i18n( (int) ( $stats['total'] ?? 0 ) ) );
		$this->stat( 'production_quantity_limits', 'amber', $en ? 'Abandoned' : 'متروكة', number_format_i18n( (int) ( $stats['abandoned'] ?? 0 ) + (int) ( $stats['notified'] ?? 0 ) ) );
		$this->stat( 'task_alt', 'green', $en ? 'Purchased' : 'اشترت', number_format_i18n( (int) ( $stats['purchased'] ?? 0 ) ) );
		$this->stat( 'payments', 'violet', $en ? 'Potential revenue' : 'إيراد محتمل', number_format_i18n( (float) ( $stats['potential_rev'] ?? 0 ) ) . ' ' . $cur );
		echo '</div>';

		$this->form_open( 'cart' );

		// --- Tracking & processing ---
		$this->card_open( 'radar', $en ? 'Tracking & processing' : 'التتبّع والمعالجة', $en ? 'When does a cart count as abandoned, and what do we capture along the way.' : 'إمتى تُعتبر السلة متروكة، وإيه اللي بنلتقطه في الطريق.' );
		$this->switch_row( 'abandoned_cart_enabled', ! empty( $s['abandoned_cart_enabled'] ), $en ? 'Enable abandoned cart tracking' : 'تفعيل تتبّع السلات المتروكة', $en ? 'Master switch for the whole module.' : 'المفتاح الرئيسي للوحدة كلها.' );
		echo '<div class="grid-3">';
		$this->number_field( 'ac_threshold_minutes', $s['ac_threshold_minutes'] ?? 60, $en ? 'Abandonment threshold (minutes)' : 'مدة اعتبار السلة متروكة (دقائق)' );
		echo '</div>';
		$this->switch_row( 'ac_capture_checkout', ! empty( $s['ac_capture_checkout'] ), $en ? 'Capture checkout fields while typing' : 'التقاط بيانات الدفع أثناء الكتابة', $en ? 'Saves phone/email the moment the customer types them — even if they never place the order.' : 'يحفظ الهاتف/الإيميل لحظة كتابتهم — حتى لو معملش الطلب.' );
		$this->switch_row( 'ac_prefill_checkout', ! empty( $s['ac_prefill_checkout'] ), $en ? 'Prefill checkout for returning visitors' : 'تعبئة حقول الدفع تلقائيًا للعائدين', '' );
		$this->switch_row( 'ac_track_pages', ! empty( $s['ac_track_pages'] ), $en ? 'Track visited pages' : 'تتبّع الصفحات المُزارة', $en ? 'Keeps the last 20 pages per visitor for context.' : 'يحتفظ بآخر 20 صفحة لكل زائر.' );
		echo '<div class="banner" style="margin-top:12px;"><span class="mi">bolt</span><div>' . ( $en
			? 'Reminder sequences are built in the rule builder using the cart triggers: <b>Customer shopping</b>, <b>Potential customer</b> and <b>Abandoned cart</b>. Create several rules with different delays to make a full sequence.'
			: 'سلاسل التذكير بتتبني من قواعد الإشعارات عبر محفّزات السلة: <b>عميل يتسوق</b>، <b>عميل محتمل</b>، و<b>سلة متروكة</b>. أنشئ أكثر من قاعدة بتأخيرات مختلفة لعمل سلسلة كاملة.' ) . '</div></div>';
		$this->card_close();

		// --- Legacy fallback message ---
		$this->card_open( 'chat', $en ? 'Fallback message' : 'رسالة الاسترجاع الاحتياطية', $en ? 'Sent only when no "Abandoned cart" rules exist. Placeholders: {{first_name}} {{cart_items}} {{cart_total}} {{coupon_code}} {{restore_url}}' : 'تُرسل فقط عند عدم وجود قواعد لمحفّز «سلة متروكة». المتغيرات: {{first_name}} {{cart_items}} {{cart_total}} {{coupon_code}} {{restore_url}}' );
		echo '<div class="field"><label>' . esc_html( $en ? 'Message template (empty = built-in default)' : 'قالب الرسالة (فارغ = القالب الافتراضي)' ) . '</label><textarea class="textarea" name="mnotif[ac_message_template]" rows="5">' . esc_textarea( $s['ac_message_template'] ?? '' ) . '</textarea></div>';
		$this->card_close();

		// --- Coupons ---
		$this->card_open( 'sell', $en ? 'Recovery coupons' : 'كوبونات الاسترجاع', $en ? 'A unique single-use coupon per cart, embedded via {{coupon_code}}.' : 'كوبون فريد يُستخدم مرة واحدة لكل سلة، يُدرج عبر {{coupon_code}}.' );
		$this->switch_row( 'ac_generate_coupon', ! empty( $s['ac_generate_coupon'] ), $en ? 'Auto-generate coupons' : 'توليد كوبونات تلقائيًا', '' );
		echo '<div class="grid-3">';
		$this->text_field( 'ac_coupon_prefix', $s['ac_coupon_prefix'] ?? 'REC', $en ? 'Code prefix' : 'بادئة الكود' );
		$this->select_field( 'ac_coupon_type', $s['ac_coupon_type'] ?? 'percent', $en ? 'Discount type' : 'نوع الخصم', array(
			'percent'    => $en ? 'Percentage %' : 'نسبة مئوية %',
			'fixed_cart' => $en ? 'Fixed amount' : 'مبلغ ثابت',
		) );
		$this->number_field( 'ac_coupon_discount', $s['ac_coupon_discount'] ?? 10, $en ? 'Discount value' : 'قيمة الخصم' );
		$this->number_field( 'ac_coupon_expiry_days', $s['ac_coupon_expiry_days'] ?? 7, $en ? 'Expires after (days)' : 'ينتهي بعد (أيام)' );
		$this->number_field( 'ac_coupon_min_spend', $s['ac_coupon_min_spend'] ?? 0, $en ? 'Minimum spend (0 = none)' : 'حد أدنى للطلب (0 = بدون)' );
		$this->number_field( 'ac_coupon_max_discount', $s['ac_coupon_max_discount'] ?? 0, $en ? 'Max discount cap (0 = none)' : 'سقف أقصى للخصم (0 = بدون)' );
		echo '</div>';
		$this->switch_row( 'ac_coupon_free_shipping', ! empty( $s['ac_coupon_free_shipping'] ), $en ? 'Grant free shipping' : 'شحن مجاني مع الكوبون', '' );
		$this->switch_row( 'ac_coupon_email_restrict', ! empty( $s['ac_coupon_email_restrict'] ), $en ? 'Lock coupon to the customer email' : 'قصر الكوبون على إيميل العميل', '' );
		echo '<div class="grid-2">';
		$this->text_field( 'ac_coupon_products', $s['ac_coupon_products'] ?? '', $en ? 'Allowed product IDs (CSV, empty = all)' : 'أرقام منتجات مسموحة (CSV، فارغ = الكل)' );
		$this->text_field( 'ac_coupon_cats', $s['ac_coupon_cats'] ?? '', $en ? 'Allowed category IDs (CSV)' : 'أرقام تصنيفات مسموحة (CSV)' );
		echo '</div>';
		$this->card_close();

		// --- Phone-capture popup ---
		$this->card_open( 'ad_units', $en ? 'Phone-capture popup' : 'بوب أب التقاط رقم الواتساب', $en ? 'Turn anonymous visitors into reachable contacts before they ever hit checkout.' : 'حوّل الزائر المجهول لعميل يمكن الوصول له قبل ما يوصل للدفع أصلًا.' );
		$this->switch_row( 'ac_popup_enabled', ! empty( $s['ac_popup_enabled'] ), $en ? 'Enable popup' : 'تفعيل البوب أب', '' );
		echo '<div class="grid-2">';
		$this->text_field( 'ac_popup_title', $s['ac_popup_title'] ?? '', $en ? 'Title' : 'العنوان', $en ? 'Add your WhatsApp number' : 'أضف رقم الواتساب الخاص بك' );
		$this->text_field( 'ac_popup_desc', $s['ac_popup_desc'] ?? '', $en ? 'Description' : 'الوصف', $en ? 'For a better experience and exclusive offers.' : 'لتحصل على تجربة أفضل وعروض حصرية.' );
		$this->text_field( 'ac_popup_btn', $s['ac_popup_btn'] ?? '', $en ? 'Button text' : 'نص الزر', $en ? 'Save' : 'حفظ' );
		$this->text_field( 'ac_popup_color', $s['ac_popup_color'] ?? '#0f8f6f', $en ? 'Accent color (hex)' : 'اللون الأساسي (hex)' );
		$this->text_field( 'ac_popup_success_title', $s['ac_popup_success_title'] ?? '', $en ? 'Success title' : 'عنوان النجاح', $en ? 'Excellent!' : 'ممتاز!' );
		$this->text_field( 'ac_popup_success_desc', $s['ac_popup_success_desc'] ?? '', $en ? 'Success description' : 'وصف النجاح', $en ? 'You can continue browsing.' : 'يمكنك الآن متابعة التصفح.' );
		$this->text_field( 'ac_popup_image', $s['ac_popup_image'] ?? '', $en ? 'Header image URL (optional)' : 'رابط صورة علوية (اختياري)' );
		$this->select_field( 'ac_popup_display', $s['ac_popup_display'] ?? 'all', $en ? 'Show on devices' : 'الأجهزة', array(
			'all'     => $en ? 'All devices' : 'كل الأجهزة',
			'desktop' => $en ? 'Desktop only' : 'كمبيوتر فقط',
			'mobile'  => $en ? 'Mobile only' : 'موبايل فقط',
		) );
		echo '</div>';
		$this->switch_row( 'ac_popup_trigger_cart', ! empty( $s['ac_popup_trigger_cart'] ), $en ? 'Trigger on add-to-cart' : 'الظهور عند الإضافة للسلة', '' );
		$this->switch_row( 'ac_popup_trigger_exit', ! empty( $s['ac_popup_trigger_exit'] ), $en ? 'Trigger on exit intent' : 'الظهور عند نية المغادرة', $en ? 'Desktop: fires when the mouse leaves toward the tab bar.' : 'على الكمبيوتر: يظهر لما الماوس يتحرك ناحية إغلاق التبويب.' );
		echo '<div class="grid-3">';
		$this->number_field( 'ac_popup_delay', $s['ac_popup_delay'] ?? 4, $en ? 'Timed trigger (seconds, 0 = off)' : 'ظهور مؤقّت (ثواني، 0 = إيقاف)' );
		$this->select_field( 'ac_popup_frequency', $s['ac_popup_frequency'] ?? 'days', $en ? 'Frequency' : 'تكرار الظهور', array(
			'once'   => $en ? 'Once ever' : 'مرة واحدة فقط',
			'days'   => $en ? 'Repeat after N days' : 'إعادة بعد عدد أيام',
			'always' => $en ? 'Every visit' : 'في كل زيارة',
		) );
		$this->number_field( 'ac_popup_frequency_days', $s['ac_popup_frequency_days'] ?? 7, $en ? 'Repeat after (days)' : 'إعادة الظهور بعد (أيام)' );
		$this->number_field( 'ac_popup_min_cart', $s['ac_popup_min_cart'] ?? 0, $en ? 'Min cart value (0 = any)' : 'حد أدنى لقيمة السلة (0 = أي قيمة)' );
		echo '</div>';
		$this->text_field( 'ac_popup_exclude', $s['ac_popup_exclude'] ?? '', $en ? 'Excluded page IDs (CSV)' : 'صفحات مستثناة (أرقام، CSV)' );
		$this->card_close();

		$this->form_close();

		// --- Recent carts table ---
		$carts = class_exists( 'Mersal_Notif_Abandoned_Cart' ) ? Mersal_Notif_Abandoned_Cart::get_recent_carts( 25 ) : array();
		$this->card_open( 'table_rows', $en ? 'Recent sessions' : 'أحدث الجلسات', $en ? 'The latest tracked visitors and carts.' : 'آخر الزوار والسلات المتتبَّعة.' );
		if ( empty( $carts ) ) {
			$this->empty_state( 'shopping_cart', $en ? 'Nothing tracked yet' : 'لا يوجد تتبّع بعد', $en ? 'Sessions appear once visitors browse with the module enabled.' : 'الجلسات هتظهر أول ما الزوار يتصفحوا والوحدة مفعّلة.' );
		} else {
			$smap = array(
				'active'    => array( $en ? 'Shopping' : 'يتسوق', 'success' ),
				'abandoned' => array( $en ? 'Abandoned' : 'متروكة', 'danger' ),
				'pending'   => array( $en ? 'Processing' : 'قيد المعالجة', '' ),
				'notified'  => array( $en ? 'Notified' : 'تم تذكيره', '' ),
				'purchased' => array( $en ? 'Purchased' : 'اشترى', 'success' ),
				'recovered' => array( $en ? 'Recovered' : 'رجع للسلة', 'success' ),
			);
			echo '<div style="overflow-x:auto;"><table class="table"><thead><tr><th>' . ( $en ? 'Contact' : 'العميل' ) . '</th><th>' . ( $en ? 'Cart' : 'السلة' ) . '</th><th>' . ( $en ? 'Total' : 'الإجمالي' ) . '</th><th>' . ( $en ? 'Device' : 'الجهاز' ) . '</th><th>' . ( $en ? 'Country' : 'الدولة' ) . '</th><th>' . ( $en ? 'Status' : 'الحالة' ) . '</th><th style="text-align:end;">' . ( $en ? 'Last activity' : 'آخر نشاط' ) . '</th></tr></thead><tbody>';
			foreach ( $carts as $c ) {
				$items = json_decode( (string) $c->cart_items, true );
				$count = is_array( $items ) ? count( $items ) : 0;
				$who   = $c->name ? $c->name : ( $c->phone ? $c->phone : ( $c->email ? $c->email : ( $en ? 'Guest' : 'زائر' ) ) );
				$st    = $smap[ $c->status ] ?? array( $c->status, '' );
				echo '<tr>';
				echo '<td><b>' . esc_html( $who ) . '</b>' . ( $c->phone ? '<div style="font-size:11px;color:var(--fg-2);direction:ltr;text-align:start;">' . esc_html( $c->phone ) . '</div>' : '' ) . '</td>';
				echo '<td>' . esc_html( number_format_i18n( $count ) ) . ' ' . ( $en ? 'items' : 'منتج' ) . '</td>';
				echo '<td>' . esc_html( number_format_i18n( (float) $c->cart_total, 2 ) ) . '</td>';
				echo '<td>' . esc_html( trim( ( $c->device ?? '' ) . ' · ' . ( $c->browser ?? '' ), ' ·' ) ) . '</td>';
				echo '<td>' . esc_html( $c->country ?? '' ) . '</td>';
				echo '<td><span class="chip ' . esc_attr( $st[1] ) . '">' . esc_html( $st[0] ) . '</span></td>';
				echo '<td style="text-align:end;color:var(--fg-2);font-size:12px;">' . esc_html( $this->ago( strtotime( $c->last_activity ), $en ) ) . '</td>';
				echo '</tr>';
			}
			echo '</tbody></table></div>';
		}
		$this->card_close();
	}

	/* ------------------------------------------------------------------ */
	/* Page: Chat widget                                                  */
	/* ------------------------------------------------------------------ */

	private function page_widget( $s, $lang ) {
		$en = ( 'en' === $lang );
		$w  = Mersal_Notif_Chat_Widget::get_settings();
		$st = Mersal_Notif_Chat_Widget::get_stats();
		$this->page_head(
			$en ? 'WhatsApp chat widget' : 'ودجت الواتساب',
			$en ? 'A floating chat button with agents, targeting and full analytics.' : 'زر شات عائم بوكلاء متعددين واستهداف وتحليلات كاملة.'
		);
		$this->saved_notice( $en );

		// --- Analytics ---
		$imp    = (int) ( $st['totals']['imp'] ?? $st['imp'] ?? 0 );
		$opens  = (int) ( $st['totals']['open'] ?? $st['open'] ?? 0 );
		$clicks = (int) ( $st['totals']['agent'] ?? $st['agent'] ?? 0 );
		$ctr    = $imp > 0 ? round( ( $clicks / $imp ) * 100, 1 ) : 0;
		echo '<div class="grid-4" style="margin-bottom:20px;">';
		$this->stat( 'visibility', 'cyan', $en ? 'Impressions' : 'مرات الظهور', number_format_i18n( $imp ) );
		$this->stat( 'open_in_full', 'violet', $en ? 'Opens' : 'مرات الفتح', number_format_i18n( $opens ) );
		$this->stat( 'chat', 'green', $en ? 'WhatsApp clicks' : 'نقرات واتساب', number_format_i18n( $clicks ) );
		$this->stat( 'percent', 'amber', $en ? 'Click rate' : 'معدل النقر', $ctr . '%' );
		echo '</div>';

		// Breakdown tables (top pages / agents / hours / devices).
		$pages  = is_array( $st['pages'] ?? null ) ? array_slice( $st['pages'], 0, 8, true ) : array();
		$agents = is_array( $st['agents'] ?? null ) ? array_slice( $st['agents'], 0, 8, true ) : array();
		$hours  = is_array( $st['hours'] ?? null ) ? $st['hours'] : array();
		$device = is_array( $st['device'] ?? null ) ? $st['device'] : array();
		if ( $pages || $agents || $hours || $device ) {
			echo '<div class="grid-2" style="margin-bottom:20px;align-items:start;">';
			if ( $pages ) {
				$this->card_open( 'travel_explore', $en ? 'Top pages' : 'أكثر الصفحات تفاعلًا' );
				$max = max( $pages );
				foreach ( $pages as $p => $n ) {
					echo '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;"><span style="flex:1;font-size:12px;direction:ltr;text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' . esc_html( $p ) . '</span><span style="width:120px;height:8px;border-radius:4px;background:var(--surface-3);overflow:hidden;"><span style="display:block;height:100%;width:' . esc_attr( $max ? round( $n / $max * 100 ) : 0 ) . '%;background:var(--accent);"></span></span><b style="font-size:12px;min-width:26px;text-align:end;">' . esc_html( number_format_i18n( $n ) ) . '</b></div>';
				}
				$this->card_close();
			}
			if ( $agents ) {
				$this->card_open( 'support_agent', $en ? 'Clicks per agent' : 'النقرات لكل وكيل' );
				$max = max( $agents );
				foreach ( $agents as $p => $n ) {
					echo '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;"><span style="flex:1;font-size:12px;direction:ltr;text-align:start;">' . esc_html( $p ) . '</span><span style="width:120px;height:8px;border-radius:4px;background:var(--surface-3);overflow:hidden;"><span style="display:block;height:100%;width:' . esc_attr( $max ? round( $n / $max * 100 ) : 0 ) . '%;background:var(--success,#16a34a);"></span></span><b style="font-size:12px;min-width:26px;text-align:end;">' . esc_html( number_format_i18n( $n ) ) . '</b></div>';
				}
				$this->card_close();
			}
			if ( $hours ) {
				$this->card_open( 'schedule', $en ? 'Engagement by hour' : 'التفاعل حسب الساعة' );
				$maxh = max( $hours );
				echo '<div style="display:flex;align-items:flex-end;gap:3px;height:70px;">';
				for ( $h = 0; $h < 24; $h++ ) {
					$n  = (int) ( $hours[ $h ] ?? 0 );
					$ht = $maxh ? max( 3, round( $n / $maxh * 100 ) ) : 3;
					echo '<span title="' . esc_attr( $h . ':00 — ' . $n ) . '" style="flex:1;height:' . esc_attr( $ht ) . '%;background:' . ( $n ? 'var(--accent)' : 'var(--surface-3)' ) . ';border-radius:2px;"></span>';
				}
				echo '</div><div style="display:flex;justify-content:space-between;font-size:10px;color:var(--fg-2);margin-top:4px;"><span>0</span><span>6</span><span>12</span><span>18</span><span>23</span></div>';
				$this->card_close();
			}
			if ( $device ) {
				$this->card_open( 'devices', $en ? 'Devices & platforms' : 'الأجهزة والأنظمة' );
				foreach ( $device as $d => $n ) {
					echo '<div style="display:flex;justify-content:space-between;font-size:13px;margin-bottom:6px;"><span>' . esc_html( $d ) . '</span><b>' . esc_html( number_format_i18n( $n ) ) . '</b></div>';
				}
				if ( ! empty( $st['os'] ) && is_array( $st['os'] ) ) {
					echo '<div style="border-top:1px solid var(--border);margin:8px 0;"></div>';
					foreach ( $st['os'] as $o => $n ) {
						echo '<div style="display:flex;justify-content:space-between;font-size:13px;margin-bottom:6px;color:var(--fg-2);"><span>' . esc_html( $o ) . '</span><b>' . esc_html( number_format_i18n( $n ) ) . '</b></div>';
					}
				}
				$this->card_close();
			}
			echo '</div>';
		}

		// --- Enable switch (main settings form) ---
		$this->form_open( 'widget' );
		$this->card_open( 'toggle_on', $en ? 'Status' : 'الحالة' );
		$this->switch_row( 'chat_widget_enabled', ! empty( $s['chat_widget_enabled'] ), $en ? 'Enable the chat widget' : 'تفعيل ودجت الواتساب', $en ? 'Shows the floating button on the front-end.' : 'يعرض الزر العائم في واجهة الموقع.' );
		$this->card_close();
		$this->form_close();

		// --- Widget settings (own AJAX form: agents repeater) ---
		$nonce = wp_create_nonce( 'mnotif_rule' );
		echo '<form data-mnotif-widget data-nonce="' . esc_attr( $nonce ) . '" onsubmit="return false;">';

		$this->card_open( 'palette', $en ? 'Appearance & behavior' : 'المظهر والسلوك' );
		echo '<div class="grid-3">';
		$this->text_field_raw( 'button_color', $w['button_color'], $en ? 'Button color' : 'لون الزر' );
		$this->text_field_raw( 'icon_color', $w['icon_color'], $en ? 'Icon color' : 'لون الأيقونة' );
		$this->select_field_raw( 'position', $w['position'], $en ? 'Position' : 'الموضع', array(
			'right' => $en ? 'Right' : 'يمين',
			'left'  => $en ? 'Left' : 'يسار',
		) );
		$this->number_field_raw( 'button_size', $w['button_size'], $en ? 'Button size (px)' : 'حجم الزر (px)' );
		$this->number_field_raw( 'bottom_offset', $w['bottom_offset'], $en ? 'Bottom offset (px)' : 'المسافة من الأسفل (px)' );
		$this->number_field_raw( 'corner_radius', $w['corner_radius'], $en ? 'Window corner radius (px)' : 'استدارة النافذة (px)' );
		echo '</div>';
		echo '<div class="grid-3">';
		$this->text_field_raw( 'header_title', $w['header_title'], $en ? 'Header title' : 'عنوان الهيدر' );
		$this->text_field_raw( 'reply_time', $w['reply_time'], $en ? 'Reply-time text' : 'نص وقت الرد' );
		$this->text_field_raw( 'welcome_msg', $w['welcome_msg'], $en ? 'Welcome message' : 'رسالة الترحيب' );
		echo '</div>';
		$this->switch_row_raw( 'show_desktop', ! empty( $w['show_desktop'] ), $en ? 'Show on desktop' : 'الظهور على الكمبيوتر', '' );
		$this->switch_row_raw( 'show_mobile', ! empty( $w['show_mobile'] ), $en ? 'Show on mobile' : 'الظهور على الموبايل', '' );
		$this->switch_row_raw( 'include_page_url', ! empty( $w['include_page_url'] ), $en ? 'Include page URL in the message' : 'إدراج رابط الصفحة في الرسالة', $en ? 'The agent instantly sees which page the visitor was on.' : 'الوكيل يعرف فورًا الزائر كان في أي صفحة.' );
		$this->switch_row_raw( 'powered_by', ! empty( $w['powered_by'] ), $en ? 'Show "Powered by Mersal"' : 'إظهار «Powered by Mersal»', '' );
		$this->text_field_raw( 'excluded_pages', $w['excluded_pages'], $en ? 'Excluded page IDs (CSV)' : 'صفحات مستثناة (أرقام، CSV)' );
		$this->card_close();

		$this->card_open( 'support_agent', $en ? 'Agents' : 'الوكلاء', $en ? 'Each agent appears as a separate WhatsApp contact in the widget.' : 'كل وكيل يظهر كجهة تواصل مستقلة داخل الودجت.' );
		echo '<div data-mnotif-agents>';
		$agents_rows = ! empty( $w['agents'] ) ? $w['agents'] : array( array() );
		foreach ( $agents_rows as $a ) {
			$this->widget_agent_row( $a, $en );
		}
		echo '</div>';
		echo '<button type="button" class="btn" data-mnotif-add-agent><span class="mi sm">add</span>' . ( $en ? 'Add agent' : 'إضافة وكيل' ) . '</button>';
		$this->card_close();

		$this->card_open( 'share', $en ? 'Social links' : 'روابط السوشيال', $en ? 'Optional links shown at the bottom of the chat window.' : 'روابط اختيارية أسفل نافذة الشات.' );
		echo '<div data-mnotif-socials>';
		$social_rows = ! empty( $w['social_links'] ) ? $w['social_links'] : array( array() );
		foreach ( $social_rows as $sl ) {
			$this->widget_social_row( $sl, $en );
		}
		echo '</div>';
		echo '<button type="button" class="btn" data-mnotif-add-social><span class="mi sm">add</span>' . ( $en ? 'Add link' : 'إضافة رابط' ) . '</button>';
		$this->card_close();

		echo '<div style="display:flex;justify-content:flex-end;margin-top:6px;"><button type="button" class="btn primary" data-mnotif-widget-save><span class="mi sm">save</span>' . ( $en ? 'Save widget settings' : 'حفظ إعدادات الودجت' ) . '</button></div>';
		echo '</form>';

		$this->widget_page_js( $en );
	}

	/* ------------------------------------------------------------------ */
	/* Page: Email builder                                                */
	/* ------------------------------------------------------------------ */

	private function page_emails( $s, $lang ) {
		$en = ( 'en' === $lang );
		$this->page_head(
			$en ? 'Email template builder' : 'بيلدر قوالب الإيميل',
			$en ? 'Compose branded HTML emails from blocks — assign a template to any rule from the message step.' : 'ركّب إيميلات HTML من بلوكات جاهزة — واربط القالب بأي قاعدة من خطوة الرسالة.'
		);
		$this->email_builder_ui( $en );
	}

	/**
	 * The block-based email template builder UI (styles + markup + JS).
	 * Rendered on the standalone Email builder screen AND embedded inside the
	 * rule wizard's message step (merged flow).
	 *
	 * @param bool $en English.
	 */
	private function email_builder_ui( $en ) {
		$templates = Mersal_Notif_Email_Templates::get_all();
		$nonce     = wp_create_nonce( 'mnotif_nonce' );

		echo '<style>
		.mnotif-eb{display:grid;grid-template-columns:260px minmax(0,1fr) 300px;gap:16px;align-items:start}
		.mnotif-eb > div{min-width:0}
		@media(max-width:1440px){.mnotif-eb{grid-template-columns:240px minmax(0,1fr) 280px}}
		@media(max-width:1200px){.mnotif-eb{grid-template-columns:1fr 1fr}.mnotif-eb > div:first-child{grid-column:1 / -1}}
		@media(max-width:900px){.mnotif-eb{grid-template-columns:1fr}.mnotif-eb > div:first-child{grid-column:auto}}
		.mnotif-eb-canvas{min-height:320px}
		.mnotif-eb-blk{border:1.5px solid var(--border);border-radius:10px;margin-bottom:8px;background:var(--surface);cursor:pointer;overflow:hidden}
		.mnotif-eb-blk.sel{border-color:var(--accent)}
		.mnotif-eb-blk .bh{display:flex;align-items:center;gap:8px;padding:8px 12px;font-size:12px;font-weight:700;color:var(--fg-2);background:var(--surface-3)}
		.mnotif-eb-blk .bh .sp{flex:1}
		.mnotif-eb-blk .bh button{border:none;background:transparent;cursor:pointer;color:var(--fg-3);padding:2px 4px;font-size:14px}
		.mnotif-eb-blk .bh button:hover{color:var(--fg-1)}
		.mnotif-eb-blk .bp{padding:10px 12px;font-size:12px;color:var(--fg-2);white-space:pre-wrap;overflow:hidden;max-height:56px}
		.mnotif-eb-add{display:grid;grid-template-columns:1fr 1fr;gap:8px}
		.mnotif-eb-add button{display:flex;align-items:center;gap:8px;padding:10px;border:1px solid var(--border);border-radius:10px;background:var(--surface);cursor:pointer;font-size:12.5px;font-weight:700;color:var(--fg-1)}
		.mnotif-eb-add button:hover{border-color:var(--accent)}
		.mnotif-eb-prev{background:#f4f4f4;border:1px solid var(--border);border-radius:12px;padding:24px 18px;overflow:auto;max-height:720px}
		.mnotif-eb-set .field{margin-bottom:10px}
		</style>';

		echo '<div class="mnotif-eb" data-mnotif-eb data-nonce="' . esc_attr( $nonce ) . '">';

		// --- Column 1: templates + blocks palette ---
		echo '<div>';
		$this->card_open( 'folder', $en ? 'Templates' : 'القوالب' );
		echo '<div class="field"><select class="select" data-eb-list><option value="0">' . esc_html( $en ? '+ New template' : '+ قالب جديد' ) . '</option>';
		foreach ( $templates as $tid => $tpl ) {
			echo '<option value="' . esc_attr( $tid ) . '">' . esc_html( $tpl['name'] ) . '</option>';
		}
		echo '</select></div>';
		echo '<div class="field"><label>' . esc_html( $en ? 'Template name' : 'اسم القالب' ) . '</label><input class="input" type="text" data-eb-name placeholder="' . esc_attr( $en ? 'Order confirmation' : 'تأكيد الطلب' ) . '"></div>';
		echo '<div style="display:flex;gap:8px;flex-wrap:wrap;">';
		echo '<button type="button" class="btn primary" data-eb-save><span class="mi sm">save</span>' . ( $en ? 'Save' : 'حفظ' ) . '</button>';
		echo '<button type="button" class="btn" data-eb-delete><span class="mi sm">delete</span>' . ( $en ? 'Delete' : 'حذف' ) . '</button>';
		echo '</div>';
		echo '<div style="border-top:1px solid var(--border);margin:12px 0;"></div>';
		echo '<div class="field"><label>' . esc_html( $en ? 'Send test to' : 'إرسال تجربة إلى' ) . '</label><div class="row" style="gap:8px;"><input class="input" type="email" data-eb-test-email value="' . esc_attr( wp_get_current_user()->user_email ) . '"><button type="button" class="btn" data-eb-test><span class="mi sm">send</span></button></div></div>';
		$this->card_close();

		$this->card_open( 'widgets', $en ? 'Add blocks' : 'إضافة بلوكات' );
		echo '<div class="mnotif-eb-add" data-eb-add>';
		$blocks = array(
			'header'  => array( 'vertical_align_top', $en ? 'Header' : 'هيدر' ),
			'text'    => array( 'notes', $en ? 'Text' : 'نص' ),
			'content' => array( 'article', $en ? 'Message body' : 'نص الإشعار' ),
			'button'  => array( 'smart_button', $en ? 'Button' : 'زر' ),
			'image'   => array( 'image', $en ? 'Image' : 'صورة' ),
			'items'   => array( 'receipt_long', $en ? 'Order items' : 'منتجات الطلب' ),
			'divider' => array( 'horizontal_rule', $en ? 'Divider' : 'فاصل' ),
			'spacer'  => array( 'height', $en ? 'Spacer' : 'مسافة' ),
			'footer'  => array( 'copyright', $en ? 'Footer' : 'فوتر' ),
		);
		foreach ( $blocks as $bk => $bm ) {
			echo '<button type="button" data-eb-addblk="' . esc_attr( $bk ) . '"><span class="mi sm">' . esc_html( $bm[0] ) . '</span>' . esc_html( $bm[1] ) . '</button>';
		}
		echo '</div>';
		$this->card_close();
		echo '</div>';

		// --- Column 2: layout canvas ---
		echo '<div>';
		$this->card_open( 'view_agenda', $en ? 'Layout' : 'التخطيط', $en ? 'Click a block to edit it. Use ▲▼ to reorder.' : 'اضغط على البلوك لتعديله. رتّب بـ ▲▼.' );
		echo '<div class="mnotif-eb-canvas" data-eb-canvas></div>';
		$this->card_close();
		echo '</div>';

		// --- Column 3: block settings ---
		echo '<div>';
		$this->card_open( 'tune', $en ? 'Block settings' : 'إعدادات البلوك' );
		echo '<div class="mnotif-eb-set" data-eb-settings><div class="hint">' . esc_html( $en ? 'Select a block to edit its settings.' : 'اختر بلوكًا لتعديل إعداداته.' ) . '</div></div>';
		$this->card_close();
		echo '</div>';

		// --- Full-width row: live preview (was squeezed into the middle column,
		// which left the 600px email canvas cramped and scrolling sideways) ---
		echo '<div class="mnotif-eb-full" style="grid-column:1 / -1;">';
		$this->card_open( 'visibility', $en ? 'Live preview' : 'معاينة حية' );
		echo '<div class="mnotif-eb-prev"><div data-eb-preview style="max-width:600px;margin:0 auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 6px 24px rgba(0,0,0,.08);"></div></div>';
		$this->card_close();
		echo '</div>';

		echo '</div>';

		$this->emails_page_js( $templates, $en );
	}

	/**
	 * Email builder JS: block state, renderer, settings panel, CRUD.
	 *
	 * @param array $templates Saved templates.
	 * @param bool  $en        English.
	 */
	private function emails_page_js( $templates, $en ) {
		$ajax = admin_url( 'admin-ajax.php' );
		$i18n = array(
			'header'  => $en ? 'Header' : 'هيدر',
			'text'    => $en ? 'Text' : 'نص',
			'content' => $en ? 'Message body' : 'نص الإشعار',
			'button'  => $en ? 'Button' : 'زر',
			'image'   => $en ? 'Image' : 'صورة',
			'items'   => $en ? 'Order items' : 'منتجات الطلب',
			'divider' => $en ? 'Divider' : 'فاصل',
			'spacer'  => $en ? 'Spacer' : 'مسافة',
			'footer'  => $en ? 'Footer' : 'فوتر',
			'fText'   => $en ? 'Text' : 'النص',
			'fTitle'  => $en ? 'Title' : 'العنوان',
			'fLogo'   => $en ? 'Logo URL (optional)' : 'رابط اللوجو (اختياري)',
			'fUrl'    => 'URL',
			'fBg'     => $en ? 'Background' : 'الخلفية',
			'fColor'  => $en ? 'Text color' : 'لون النص',
			'fSize'   => $en ? 'Font size' : 'حجم الخط',
			'fAlign'  => $en ? 'Alignment' : 'المحاذاة',
			'fWidth'  => $en ? 'Width %' : 'العرض %',
			'fH'      => $en ? 'Height (px)' : 'الارتفاع (px)',
			'fRadius' => $en ? 'Corner radius' : 'الاستدارة',
			'aStart'  => $en ? 'Start' : 'بداية',
			'aCenter' => $en ? 'Center' : 'وسط',
			'aEnd'    => $en ? 'End' : 'نهاية',
			'saved'   => $en ? 'Saved.' : 'تم الحفظ.',
			'needName'=> $en ? 'Enter a template name first.' : 'اكتب اسم القالب الأول.',
			'confirmDel' => $en ? 'Delete this template?' : 'حذف هذا القالب؟',
			'contentHint'=> $en ? 'The notification message text will be injected here.' : 'نص رسالة الإشعار هيتحقن هنا.',
			'itemsHint'  => $en ? 'Order items list ({{product}}) renders here.' : 'قائمة منتجات الطلب ({{product}}) هتظهر هنا.',
		);
		?>
		<script>
		(function(){
			var root = document.querySelector('[data-mnotif-eb]');
			if (!root) return;
			var ajax = <?php echo wp_json_encode( $ajax ); ?>;
			var nonce = root.getAttribute('data-nonce');
			var T = <?php echo wp_json_encode( $i18n ); ?>;
			var TPLS = <?php echo wp_json_encode( array_map( function ( $t ) { return array( 'id' => $t['id'], 'name' => $t['name'], 'json' => $t['content_json'] ); }, array_values( $templates ) ) ); ?>;
			var canvas = root.querySelector('[data-eb-canvas]');
			var settings = root.querySelector('[data-eb-settings]');
			var preview = root.querySelector('[data-eb-preview]');
			var nameEl = root.querySelector('[data-eb-name]');
			var listEl = root.querySelector('[data-eb-list]');
			var curId = 0, blocks = [], selIdx = -1;

			function defBlock(type){
				switch(type){
					case 'header':  return {type:type, logo:'', title:'{{shop_name}}', bg:'#0f172a', color:'#ffffff'};
					case 'text':    return {type:type, text:'', size:14, color:'#374151', align:'start'};
					case 'content': return {type:type};
					case 'button':  return {type:type, label:'<?php echo esc_js( $en ? 'Open' : 'فتح' ); ?>', url:'{{site_link}}', bg:'#0f8f6f', color:'#ffffff', radius:8, align:'center'};
					case 'image':   return {type:type, url:'', width:100, align:'center'};
					case 'items':   return {type:type};
					case 'divider': return {type:type, color:'#e5e7eb'};
					case 'spacer':  return {type:type, h:20};
					case 'footer':  return {type:type, text:'© {{shop_name}} — {{site_link}}', color:'#9ca3af'};
				}
				return {type:type};
			}
			function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];}); }

			/* --- HTML renderer: table-based, fully inline-styled --- */
			function renderBlock(b){
				var a = {start:'<?php echo is_rtl() ? 'right' : 'left'; ?>', center:'center', end:'<?php echo is_rtl() ? 'left' : 'right'; ?>'};
				switch(b.type){
					case 'header':
						return '<tr><td style="background:'+esc(b.bg)+';padding:26px 32px;text-align:center;">'
							+ (b.logo ? '<img src="'+esc(b.logo)+'" alt="" style="max-height:44px;margin-bottom:8px;">' : '')
							+ '<div style="color:'+esc(b.color)+';font-size:20px;font-weight:700;font-family:Arial,sans-serif;">'+esc(b.title)+'</div></td></tr>';
					case 'text':
						return '<tr><td style="padding:14px 32px;text-align:'+(a[b.align]||a.start)+';color:'+esc(b.color)+';font-size:'+(+b.size||14)+'px;line-height:1.7;font-family:Arial,sans-serif;">'+String(b.text||'').replace(/\n/g,'<br>')+'</td></tr>';
					case 'content':
						return '<tr><td style="padding:14px 32px;color:#374151;font-size:14px;line-height:1.7;font-family:Arial,sans-serif;">{{content}}</td></tr>';
					case 'button':
						return '<tr><td style="padding:18px 32px;text-align:'+(a[b.align]||'center')+';"><a href="'+esc(b.url)+'" style="display:inline-block;background:'+esc(b.bg)+';color:'+esc(b.color)+';padding:12px 28px;border-radius:'+(+b.radius||8)+'px;text-decoration:none;font-weight:700;font-size:14px;font-family:Arial,sans-serif;">'+esc(b.label)+'</a></td></tr>';
					case 'image':
						return '<tr><td style="padding:14px 32px;text-align:'+(a[b.align]||'center')+';">'+(b.url?'<img src="'+esc(b.url)+'" alt="" style="width:'+(+b.width||100)+'%;max-width:100%;border-radius:6px;">':'')+'</td></tr>';
					case 'items':
						return '<tr><td style="padding:14px 32px;"><div style="background:#f8fafc;border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px;color:#374151;font-size:13px;line-height:1.9;font-family:Arial,sans-serif;white-space:pre-line;">{{product}}</div></td></tr>';
					case 'divider':
						return '<tr><td style="padding:8px 32px;"><div style="border-top:1px solid '+esc(b.color)+';"></div></td></tr>';
					case 'spacer':
						return '<tr><td style="height:'+(+b.h||20)+'px;line-height:'+(+b.h||20)+'px;">&nbsp;</td></tr>';
					case 'footer':
						return '<tr><td style="padding:20px 32px;text-align:center;color:'+esc(b.color)+';font-size:12px;font-family:Arial,sans-serif;">'+esc(b.text)+'</td></tr>';
				}
				return '';
			}
			function renderHTML(){
				return '<table width="100%" cellpadding="0" cellspacing="0" role="presentation">'+blocks.map(renderBlock).join('')+'</table>';
			}
			function previewHTML(){
				// Preview substitutes sample values for placeholders.
				return renderHTML()
					.replace(/\{\{content\}\}/g, '<?php echo esc_js( $en ? 'Hi Ahmed 👋 your order #1024 is confirmed and being prepared.' : 'مرحباً أحمد 👋 تم تأكيد طلبك #1024 وجارٍ تجهيزه.' ); ?>')
					.replace(/\{\{product\}\}/g, '1. Product A × 2 = 300\n2. Product B × 1 = 150')
					.replace(/\{\{shop_name\}\}/g, <?php echo wp_json_encode( get_bloginfo( 'name' ) ); ?>)
					.replace(/\{\{site_link\}\}/g, <?php echo wp_json_encode( home_url() ); ?>);
			}

			/* --- Canvas + settings UI --- */
			function draw(){
				canvas.innerHTML = blocks.length ? '' : '<div class="hint" style="padding:20px;text-align:center;"><?php echo esc_js( $en ? 'Add blocks from the palette to start.' : 'أضف بلوكات من القائمة للبدء.' ); ?></div>';
				blocks.forEach(function(b, i){
					var d = document.createElement('div');
					d.className = 'mnotif-eb-blk' + (i===selIdx?' sel':'');
					var summary = b.title || b.text || b.label || (b.type==='content'?T.contentHint:(b.type==='items'?T.itemsHint:'')) || b.url || '';
					d.innerHTML = '<div class="bh"><span class="mi sm">drag_indicator</span>'+esc(T[b.type]||b.type)
						+ '<span class="sp"></span>'
						+ '<button type="button" data-mv="-1" title="up">▲</button><button type="button" data-mv="1" title="down">▼</button><button type="button" data-cp title="copy">⧉</button><button type="button" data-rm title="del">✕</button></div>'
						+ (summary ? '<div class="bp">'+esc(String(summary).slice(0,90))+'</div>' : '');
					d.addEventListener('click', function(e){
						var mv = e.target.closest('[data-mv]');
						if (mv){ e.stopPropagation(); var to=i+ +mv.getAttribute('data-mv'); if(to<0||to>=blocks.length) return; var t=blocks[i]; blocks[i]=blocks[to]; blocks[to]=t; selIdx=to; refresh(); return; }
						if (e.target.closest('[data-rm]')){ e.stopPropagation(); blocks.splice(i,1); selIdx=-1; refresh(); return; }
						if (e.target.closest('[data-cp]')){ e.stopPropagation(); blocks.splice(i+1,0,JSON.parse(JSON.stringify(b))); refresh(); return; }
						selIdx = i; refresh();
					});
					canvas.appendChild(d);
				});
				preview.innerHTML = previewHTML();
				drawSettings();
			}
			function fld(label, html){ return '<div class="field"><label>'+esc(label)+'</label>'+html+'</div>'; }
			function inp(prop, val, type){ return '<input class="input" type="'+(type||'text')+'" data-eb-prop="'+prop+'" value="'+esc(val)+'">'; }
			function ta(prop, val){ return '<textarea class="textarea" rows="4" data-eb-prop="'+prop+'">'+esc(val)+'</textarea>'; }
			function alignSel(prop, val){
				var o=['start','center','end'].map(function(k){ return '<option value="'+k+'"'+(val===k?' selected':'')+'>'+esc(k==='start'?T.aStart:(k==='center'?T.aCenter:T.aEnd))+'</option>'; }).join('');
				return '<select class="select" data-eb-prop="'+prop+'">'+o+'</select>';
			}
			function drawSettings(){
				if (selIdx<0 || !blocks[selIdx]){ settings.innerHTML='<div class="hint"><?php echo esc_js( $en ? 'Select a block to edit its settings.' : 'اختر بلوكًا لتعديل إعداداته.' ); ?></div>'; return; }
				var b = blocks[selIdx], h='';
				switch(b.type){
					case 'header': h=fld(T.fLogo,inp('logo',b.logo))+fld(T.fTitle,inp('title',b.title))+fld(T.fBg,inp('bg',b.bg,'color'))+fld(T.fColor,inp('color',b.color,'color')); break;
					case 'text': h=fld(T.fText,ta('text',b.text))+fld(T.fSize,inp('size',b.size,'number'))+fld(T.fColor,inp('color',b.color,'color'))+fld(T.fAlign,alignSel('align',b.align)); break;
					case 'button': h=fld(T.fText,inp('label',b.label))+fld(T.fUrl,inp('url',b.url))+fld(T.fBg,inp('bg',b.bg,'color'))+fld(T.fColor,inp('color',b.color,'color'))+fld(T.fRadius,inp('radius',b.radius,'number'))+fld(T.fAlign,alignSel('align',b.align)); break;
					case 'image': h=fld(T.fUrl,inp('url',b.url))+fld(T.fWidth,inp('width',b.width,'number'))+fld(T.fAlign,alignSel('align',b.align)); break;
					case 'divider': h=fld(T.fColor,inp('color',b.color,'color')); break;
					case 'spacer': h=fld(T.fH,inp('h',b.h,'number')); break;
					case 'footer': h=fld(T.fText,inp('text',b.text))+fld(T.fColor,inp('color',b.color,'color')); break;
					case 'content': h='<div class="hint">'+esc(T.contentHint)+'</div>'; break;
					case 'items': h='<div class="hint">'+esc(T.itemsHint)+'</div>'; break;
				}
				settings.innerHTML = h;
				settings.querySelectorAll('[data-eb-prop]').forEach(function(el){
					el.addEventListener('input', function(){
						var v = el.value;
						if (el.type==='number') v = +v;
						blocks[selIdx][el.getAttribute('data-eb-prop')] = v;
						preview.innerHTML = previewHTML();
						// Update summary line without full redraw (keeps focus).
						var blk = canvas.children[selIdx], bp = blk && blk.querySelector('.bp');
						if (bp) bp.textContent = String(blocks[selIdx].title||blocks[selIdx].text||blocks[selIdx].label||blocks[selIdx].url||'').slice(0,90);
					});
				});
			}
			function refresh(){ draw(); }

			/* --- Palette --- */
			root.querySelector('[data-eb-add]').addEventListener('click', function(e){
				var b = e.target.closest('[data-eb-addblk]');
				if (!b) return;
				blocks.push(defBlock(b.getAttribute('data-eb-addblk')));
				selIdx = blocks.length-1;
				refresh();
			});

			/* --- Template CRUD --- */
			function loadTemplate(id){
				curId = +id || 0;
				selIdx = -1;
				if (!curId){ blocks=[defBlock('header'),defBlock('content'),defBlock('button'),defBlock('footer')]; nameEl.value=''; refresh(); return; }
				var t = TPLS.find(function(x){ return +x.id === curId; });
				nameEl.value = t ? t.name : '';
				try{ blocks = t && t.json ? (JSON.parse(t.json)||[]) : []; }catch(e){ blocks=[]; }
				if (!blocks.length) blocks=[defBlock('content')];
				refresh();
			}
			listEl.addEventListener('change', function(){ loadTemplate(listEl.value); });

			root.querySelector('[data-eb-save]').addEventListener('click', function(){
				var btn=this;
				if (!nameEl.value.trim()){ alert(T.needName); return; }
				btn.disabled=true;
				var fd=new FormData();
				fd.append('action','mnotif_save_email_template');
				fd.append('nonce',nonce);
				fd.append('id',curId);
				fd.append('name',nameEl.value.trim());
				fd.append('content_json',JSON.stringify(blocks));
				fd.append('content_html',renderHTML());
				fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){
					btn.disabled=false;
					if(res&&res.success){
						var id=res.data.id;
						var t=TPLS.find(function(x){return +x.id===+id;});
						if(t){ t.name=nameEl.value.trim(); t.json=JSON.stringify(blocks); var op=listEl.querySelector('option[value="'+id+'"]'); if(op) op.textContent=t.name; }
						else { TPLS.push({id:id,name:nameEl.value.trim(),json:JSON.stringify(blocks)}); var o=document.createElement('option'); o.value=id; o.textContent=nameEl.value.trim(); listEl.appendChild(o); }
						curId=id; listEl.value=String(id);
						/* Embedded in the rule wizard: keep the rule's template select in sync. */
						var rsel=document.querySelector('select[name="email_template"]');
						if(rsel){ var ro=rsel.querySelector('option[value="'+id+'"]'); if(ro){ ro.textContent=nameEl.value.trim(); } else { var nro=document.createElement('option'); nro.value=id; nro.textContent=nameEl.value.trim(); rsel.appendChild(nro); rsel.value=String(id); } }
						alert(T.saved);
					} else { alert((res&&res.data&&res.data.message)||'!'); }
				}).catch(function(){ btn.disabled=false; });
			});

			root.querySelector('[data-eb-delete]').addEventListener('click', function(){
				if (!curId || !confirm(T.confirmDel)) return;
				var fd=new FormData();
				fd.append('action','mnotif_delete_email_template');
				fd.append('nonce',nonce);
				fd.append('id',curId);
				fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(){
					var op=listEl.querySelector('option[value="'+curId+'"]'); if(op) op.remove();
					var rsel=document.querySelector('select[name="email_template"]');
					if(rsel){ var ro=rsel.querySelector('option[value="'+curId+'"]'); if(ro){ ro.remove(); rsel.value='0'; } }
					TPLS=TPLS.filter(function(x){return +x.id!==curId;});
					listEl.value='0'; loadTemplate(0);
				});
			});

			root.querySelector('[data-eb-test]').addEventListener('click', function(){
				var btn=this, em=root.querySelector('[data-eb-test-email]').value.trim();
				if(!em) return;
				btn.disabled=true;
				// Save first if new, then test by id.
				function fire(id){
					var fd=new FormData();
					fd.append('action','mnotif_test_email_template');
					fd.append('nonce',nonce);
					fd.append('id',id);
					fd.append('email',em);
					fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){
						btn.disabled=false;
						alert((res&&res.data&&res.data.message)||(res&&res.success?'OK':'!'));
					}).catch(function(){ btn.disabled=false; });
				}
				if (curId){ fire(curId); } else { btn.disabled=false; alert(T.needName); }
			});

			loadTemplate(0);
		})();
		</script>
		<?php
	}

	/**
	 * One agent repeater row.
	 *
	 * @param array $a  Agent.
	 * @param bool  $en English.
	 */
	private function widget_agent_row( $a, $en ) {
		echo '<div class="card" data-agent-row style="margin-bottom:10px;"><div class="card-body">';
		echo '<div class="grid-3">';
		$this->text_field_raw( 'agent_name[]', $a['name'] ?? '', $en ? 'Name' : 'الاسم' );
		$this->text_field_raw( 'agent_phone[]', $a['phone'] ?? '', $en ? 'WhatsApp number (intl)' : 'رقم الواتساب (دولي)', '2010xxxxxxx' );
		$this->text_field_raw( 'agent_role[]', $a['role'] ?? '', $en ? 'Role (optional)' : 'الوظيفة (اختياري)' );
		echo '</div><div class="grid-2">';
		$this->text_field_raw( 'agent_message[]', $a['message'] ?? '', $en ? 'Prefilled message (optional)' : 'رسالة مسبقة (اختياري)' );
		$this->text_field_raw( 'agent_avatar[]', $a['avatar'] ?? '', $en ? 'Avatar image URL (optional)' : 'رابط صورة (اختياري)' );
		echo '</div>';
		echo '<button type="button" class="btn ghost sm" data-remove-row><span class="mi sm">delete</span>' . ( $en ? 'Remove' : 'حذف' ) . '</button>';
		echo '</div></div>';
	}

	/**
	 * One social-link repeater row.
	 *
	 * @param array $s2 Link.
	 * @param bool  $en English.
	 */
	private function widget_social_row( $s2, $en ) {
		echo '<div data-social-row style="display:flex;gap:10px;align-items:flex-end;margin-bottom:8px;">';
		echo '<div style="flex:1;">';
		$this->text_field_raw( 'social_label[]', $s2['label'] ?? '', $en ? 'Label' : 'الاسم', 'Facebook' );
		echo '</div><div style="flex:2;">';
		$this->text_field_raw( 'social_url[]', $s2['url'] ?? '', 'URL', 'https://' );
		echo '</div>';
		echo '<button type="button" class="btn ghost sm" data-remove-row style="margin-bottom:14px;"><span class="mi sm">close</span></button>';
		echo '</div>';
	}

	/**
	 * Widget page JS: repeaters + AJAX save.
	 *
	 * @param bool $en English.
	 */
	private function widget_page_js( $en ) {
		$ajax = admin_url( 'admin-ajax.php' );
		?>
		<script>
		(function(){
			var form = document.querySelector('[data-mnotif-widget]');
			if (!form) return;
			var ajax = <?php echo wp_json_encode( $ajax ); ?>;
			var nonce = form.getAttribute('data-nonce');
			form.addEventListener('click', function(e){
				var rm = e.target.closest('[data-remove-row]');
				if (rm){ var row = rm.closest('[data-agent-row],[data-social-row]'); if (row) row.remove(); return; }
			});
			var addA = form.querySelector('[data-mnotif-add-agent]');
			if (addA) addA.addEventListener('click', function(){
				var box = form.querySelector('[data-mnotif-agents]');
				var first = box.querySelector('[data-agent-row]');
				if (!first) return;
				var clone = first.cloneNode(true);
				clone.querySelectorAll('input').forEach(function(i){ i.value=''; });
				box.appendChild(clone);
			});
			var addS = form.querySelector('[data-mnotif-add-social]');
			if (addS) addS.addEventListener('click', function(){
				var box = form.querySelector('[data-mnotif-socials]');
				var first = box.querySelector('[data-social-row]');
				if (!first) return;
				var clone = first.cloneNode(true);
				clone.querySelectorAll('input').forEach(function(i){ i.value=''; });
				box.appendChild(clone);
			});
			var save = form.querySelector('[data-mnotif-widget-save]');
			if (save) save.addEventListener('click', function(){
				save.disabled = true;
				var fd = new FormData();
				fd.append('action','mnotif_save_widget');
				fd.append('nonce', nonce);
				['button_color','icon_color','position','button_size','bottom_offset','corner_radius','header_title','reply_time','welcome_msg','excluded_pages'].forEach(function(k){
					var el = form.querySelector('[name="'+k+'"]');
					if (el) fd.append(k, el.value);
				});
				['show_desktop','show_mobile','include_page_url','powered_by'].forEach(function(k){
					var el = form.querySelector('input[type="checkbox"][name="'+k+'"]');
					fd.append(k, el && el.checked ? '1' : '');
				});
				form.querySelectorAll('[data-agent-row]').forEach(function(row, i){
					['name','phone','role','message','avatar'].forEach(function(f){
						var el = row.querySelector('[name="agent_'+f+'[]"]');
						fd.append('agents['+i+']['+f+']', el ? el.value : '');
					});
				});
				form.querySelectorAll('[data-social-row]').forEach(function(row, i){
					['label','url'].forEach(function(f){
						var el = row.querySelector('[name="social_'+f+'[]"]');
						fd.append('social_links['+i+']['+f+']', el ? el.value : '');
					});
				});
				fetch(ajax,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){
					save.disabled = false;
					alert(res && res.data && res.data.message ? res.data.message : <?php echo wp_json_encode( $en ? 'Saved.' : 'تم الحفظ.' ); ?>);
				}).catch(function(){ save.disabled = false; });
			});
		})();
		</script>
		<?php
	}

	/* ------------------------------------------------------------------ */
	/* Helpers (UI)                                                       */
	/* ------------------------------------------------------------------ */

	private function page_head( $title, $sub, $actions = '' ) {
		echo '<div class="page-head"><div class="titles"><h1>' . esc_html( $title ) . '</h1><p>' . esc_html( $sub ) . '</p></div>';
		if ( $actions ) {
			echo '<div class="actions">' . $actions . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}
		echo '</div>';
	}

	private function card_open( $icon, $title, $subtitle = '' ) {
		echo '<div class="card"><div class="card-head"><div class="ico"><span class="mi">' . esc_html( $icon ) . '</span></div><div class="t"><b>' . esc_html( $title ) . '</b>';
		if ( $subtitle ) {
			echo '<span>' . esc_html( $subtitle ) . '</span>';
		}
		echo '</div></div><div class="card-body">';
	}

	private function card_close() {
		echo '</div></div>';
	}

	private function stat( $icon, $kind, $label, $value ) {
		echo '<div class="stat"><div class="top"><div class="ico ' . esc_attr( $kind ) . '"><span class="mi">' . esc_html( $icon ) . '</span></div><b>' . esc_html( $label ) . '</b></div><div class="val">' . esc_html( $value ) . '</div></div>';
	}

	private function empty_state( $icon, $title, $desc ) {
		echo '<div class="empty"><div class="ico"><span class="mi xl">' . esc_html( $icon ) . '</span></div><b>' . esc_html( $title ) . '</b><span>' . esc_html( $desc ) . '</span></div>';
	}

	private function form_open( $page ) {
		echo '<form class="mnotif-settings-form" method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">';
		echo '<input type="hidden" name="action" value="mnotif_save_settings">';
		echo '<input type="hidden" name="mnotif_page" value="' . esc_attr( $page ) . '">';
		wp_nonce_field( 'mnotif_save_settings', 'mnotif_nonce' );
	}

	private function form_close() {
		$this->flush_save_bar();
		echo '</form>';
	}

	private function save_bar( $en ) {
		ob_start();
		echo '<div class="savebar is-idle" data-savebar hidden aria-live="polite">';
		echo '<span class="help is-status" data-savebar-status hidden></span>';
		echo '<div class="save-actions"><button type="button" class="btn" data-savebar-discard>' . ( $en ? 'Discard' : 'تجاهل' ) . '</button>';
		echo '<button type="button" class="btn primary" data-savebar-save><span class="mi sm">save</span>' . ( $en ? 'Save changes' : 'حفظ التغييرات' ) . '</button></div></div>';
		$this->save_bar_html = ob_get_clean();
	}

	private function flush_save_bar() {
		if ( ! $this->save_bar_html ) {
			$this->save_bar( 'en' === Mersal_Notif_Settings::get( 'lang', 'ar' ) );
		}
		echo $this->save_bar_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		$this->save_bar_html = '';
	}

	/**
	 * The "your plan does not include this plugin" state.
	 *
	 * mersal.it refuses the link with plan_upgrade_required when the account has
	 * no subscription for this product. Repeating "linking failed, try again"
	 * would send the customer round the same loop forever, so name the reason
	 * and point at the add-ons store.
	 *
	 * @param bool $en English UI?
	 */
	private function not_subscribed_banner( $en ) {
		$url = 'https://mersal.it/user/addons/?plugin=notifications';
		echo '<div class="card" style="margin-bottom:18px;border-color:var(--warn);">';
		echo '<div class="card-body" style="text-align:center;padding:32px 24px;">';
		echo '<div style="width:56px;height:56px;border-radius:16px;background:var(--warn-soft);color:var(--warn);display:grid;place-items:center;margin:0 auto 14px;"><span class="mi" style="font-size:30px;">lock</span></div>';
		echo '<h3 style="margin:0 0 8px;font-size:17px;color:var(--fg-1);">'
			. esc_html( $en ? 'Your subscription does not include this plugin' : 'اشتراكك الحالي مايشملش الإضافة دي' )
			. '</h3>';
		echo '<p style="margin:0 auto 18px;max-width:520px;font-size:13.5px;color:var(--fg-2);line-height:1.8;">'
			. esc_html(
				$en
					? 'mersal.it refused the link because this add-on is not on your account. Subscribe to it, then come back and link the site — nothing you have configured here is lost.'
					: 'mersal.it رفض الربط لأن الإضافة دي مش على حسابك. اشترك فيها وبعدين ارجع اربط الموقع — كل اللي ظبطته هنا محفوظ زي ما هو.'
			)
			. '</p>';
		$err = $this->connect->last_connect_error();
		if ( $err ) {
			echo '<p style="margin:0 auto 18px;max-width:520px;font-size:12px;color:var(--fg-3);">' . esc_html( $err ) . '</p>';
		}
		echo '<div style="display:flex;gap:10px;justify-content:center;flex-wrap:wrap;">';
		echo '<a class="btn primary" href="' . esc_url( $url ) . '" target="_blank" rel="noopener"><span class="mi sm">shopping_cart</span>'
			. esc_html( $en ? 'Subscribe now' : 'اشترك الآن' ) . '</a>';
		echo '<a class="btn" href="' . esc_url( $this->connect->launch_url() ) . '"><span class="mi sm">refresh</span>'
			. esc_html( $en ? 'Already subscribed — try linking again' : 'اشتركت بالفعل — جرّب الربط تاني' ) . '</a>';
		echo '</div></div></div>';
	}

	private function saved_notice( $en ) {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['updated'] ) && '1' === $_GET['updated'] ) {
			echo '<div class="banner" style="margin-bottom:18px;"><span class="mi">check_circle</span><div>' . ( $en ? 'Settings saved.' : 'تم حفظ الإعدادات.' ) . '</div></div>';
		}
	}

	/* --- mnotif[...] settings fields (autosave bar) --- */

	private function number_field( $key, $val, $label, $hint = '' ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><input class="input" type="number" name="mnotif[' . esc_attr( $key ) . ']" value="' . esc_attr( $val ) . '">';
		if ( $hint ) {
			echo '<div class="hint">' . esc_html( $hint ) . '</div>';
		}
		echo '</div>';
	}

	private function text_field( $key, $val, $label, $placeholder = '', $type = 'text' ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><input class="input" type="' . esc_attr( $type ) . '" name="mnotif[' . esc_attr( $key ) . ']" value="' . esc_attr( $val ) . '" placeholder="' . esc_attr( $placeholder ) . '"></div>';
	}

	private function select_field( $key, $val, $label, $options ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><select class="select" name="mnotif[' . esc_attr( $key ) . ']">';
		foreach ( $options as $ov => $ol ) {
			echo '<option value="' . esc_attr( $ov ) . '" ' . selected( $val, $ov, false ) . '>' . esc_html( $ol ) . '</option>';
		}
		echo '</select></div>';
	}

	/**
	 * Radio choices rendered as selectable cards (settings pages).
	 *
	 * @param string $key     Settings key (posts as mnotif[key]).
	 * @param string $val     Current value.
	 * @param string $label   Field label.
	 * @param array  $options value => [icon, title, subtitle] (subtitle optional).
	 */
	private function choice_cards( $key, $val, $label, $options ) {
		if ( $label ) {
			echo '<label class="flbl">' . esc_html( $label ) . '</label>';
		}
		echo '<div class="mnotif-choice">';
		foreach ( $options as $ov => $o ) {
			$sel = ( (string) $val === (string) $ov ) ? ' sel' : '';
			echo '<label class="chc' . esc_attr( $sel ) . '">';
			echo '<input type="radio" name="mnotif[' . esc_attr( $key ) . ']" value="' . esc_attr( $ov ) . '" ' . checked( (string) $val, (string) $ov, false ) . '>';
			echo '<span class="ci2"><span class="mi">' . esc_html( $o[0] ) . '</span></span>';
			echo '<span style="min-width:0;"><b>' . esc_html( $o[1] ) . '</b>' . ( ! empty( $o[2] ) ? '<small>' . esc_html( $o[2] ) . '</small>' : '' ) . '</span>';
			echo '<span class="ck"></span>';
			echo '</label>';
		}
		echo '</div>';
	}

	private function switch_row( $key, $on, $title, $desc ) {
		echo '<div class="toggle-row"><div class="text"><b>' . esc_html( $title ) . '</b><span>' . esc_html( $desc ) . '</span></div>';
		echo '<label class="mnotif-switch"><input type="hidden" name="mnotif[' . esc_attr( $key ) . ']" value="0"><input type="checkbox" name="mnotif[' . esc_attr( $key ) . ']" value="1" ' . checked( $on, true, false ) . '><span></span></label></div>';
	}

	private function gateway_select( $key, $val, $type, $lang ) {
		$en   = ( 'en' === $lang );
		$lbl  = 'email' === $type ? ( $en ? 'Email gateway' : 'بوابة الإيميل' ) : ( 'whatsapp' === $type ? ( $en ? 'WhatsApp gateway' : 'بوابة الواتساب' ) : ( $en ? 'SMS gateway' : 'بوابة الرسائل' ) );
		$opts = array();
		foreach ( $this->connect->gateways() as $g ) {
			$g     = (array) $g;
			$gtype = strtolower( (string) ( $g['type'] ?? $g['channel'] ?? 'whatsapp' ) );
			if ( ! $this->connect->gateway_matches_type_public( $gtype, $type ) ) {
				continue;
			}
			$uid = $g['gateway_identifier'] ?? ( $g['uid'] ?? ( $g['identifier'] ?? ( $g['id'] ?? '' ) ) );
			if ( $uid ) {
				$label = $g['name'] ?? $uid;
				$addr  = trim( (string) ( $g['address'] ?? '' ) );
				if ( $addr ) {
					$label .= ' — ' . $addr;
				}
				$opts[ $uid ] = $label;
			}
		}
		if ( $opts && count( $opts ) <= 8 ) {
			// Few gateways → selectable cards (clearer than a dropdown).
			$icon  = 'email' === $type ? 'mail' : ( 'whatsapp' === $type ? 'chat' : 'sms' );
			$cards = array(
				'' => array( 'bolt', $en ? 'Auto' : 'تلقائي', $en ? 'First active gateway' : 'أول بوابة نشطة' ),
			);
			foreach ( $opts as $ov => $ol ) {
				$parts = explode( ' — ', (string) $ol, 2 );
				$cards[ $ov ] = array( $icon, $parts[0], $parts[1] ?? '' );
			}
			$this->choice_cards( $key, $val, $lbl, $cards );
		} elseif ( $opts ) {
			echo '<div class="field"><label>' . esc_html( $lbl ) . '</label><select class="select" name="mnotif[' . esc_attr( $key ) . ']">';
			echo '<option value="">' . esc_html( $en ? 'Auto (active gateway)' : 'تلقائي (أول بوابة نشطة)' ) . '</option>';
			foreach ( $opts as $ov => $ol ) {
				echo '<option value="' . esc_attr( $ov ) . '" ' . selected( $val, $ov, false ) . '>' . esc_html( $ol ) . '</option>';
			}
			echo '</select></div>';
		} else {
			echo '<div class="field"><label>' . esc_html( $lbl ) . '</label><input class="input" type="text" name="mnotif[' . esc_attr( $key ) . ']" value="' . esc_attr( $val ) . '" placeholder="gateway_identifier">';
			if ( ! $this->connect->is_connected() ) {
				echo '<div class="hint"><a href="' . esc_url( $this->page_url( 'mersal' ) ) . '">' . esc_html( $en ? 'Connect Mersal to load your gateways automatically.' : 'اربط مرسال لتحميل بواباتك تلقائيًا.' ) . '</a></div>';
			}
			echo '</div>';
		}
	}

	/* --- raw-name fields for the rule form --- */

	private function text_field_raw( $name, $val, $label, $placeholder = '', $type = 'text' ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><input class="input" type="' . esc_attr( $type ) . '" name="' . esc_attr( $name ) . '" value="' . esc_attr( $val ) . '" placeholder="' . esc_attr( $placeholder ) . '"></div>';
	}

	private function number_field_raw( $name, $val, $label ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><input class="input" type="number" name="' . esc_attr( $name ) . '" value="' . esc_attr( $val ) . '"></div>';
	}

	private function textarea_field_raw( $name, $val, $label, $rows = 3 ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><textarea class="textarea" name="' . esc_attr( $name ) . '" rows="' . esc_attr( $rows ) . '">' . esc_textarea( $val ) . '</textarea></div>';
	}

	private function select_field_raw( $name, $val, $label, $options ) {
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><select class="select" name="' . esc_attr( $name ) . '">';
		echo '<option value="">' . esc_html( '—' ) . '</option>';
		foreach ( $options as $ov => $ol ) {
			echo '<option value="' . esc_attr( $ov ) . '" ' . selected( $val, $ov, false ) . '>' . esc_html( $ol ) . '</option>';
		}
		echo '</select></div>';
	}

	/**
	 * Multi-select bound to a CSV value (name posts as an array).
	 *
	 * @param string $name    Field name (posts as name[]).
	 * @param string $csv     Current CSV value.
	 * @param string $label   Label.
	 * @param array  $options value => label.
	 */
	private function multiselect_field_raw( $name, $csv, $label, $options ) {
		$selected = array_filter( array_map( 'trim', explode( ',', (string) $csv ) ), 'strlen' );
		echo '<div class="field"><label>' . esc_html( $label ) . '</label><select class="select" name="' . esc_attr( $name ) . '[]" multiple size="5">';
		if ( empty( $options ) ) {
			echo '<option value="" disabled>' . esc_html__( 'WooCommerce not active', 'mersal-notifications' ) . '</option>';
		}
		foreach ( $options as $ov => $ol ) {
			echo '<option value="' . esc_attr( $ov ) . '" ' . ( in_array( (string) $ov, $selected, true ) ? 'selected' : '' ) . '>' . esc_html( $ol ) . '</option>';
		}
		echo '</select></div>';
	}

	private function switch_row_raw( $name, $on, $title, $desc ) {
		echo '<div class="toggle-row"><div class="text"><b>' . esc_html( $title ) . '</b><span>' . esc_html( $desc ) . '</span></div>';
		echo '<label class="mnotif-switch"><input type="hidden" name="' . esc_attr( $name ) . '" value="0"><input type="checkbox" name="' . esc_attr( $name ) . '" value="1" ' . checked( $on, true, false ) . '><span></span></label></div>';
	}

	private function channel_chip( $channel ) {
		$map = array(
			'email'    => array( '#6366f1', 'mail', 'Email' ),
			'whatsapp' => array( '#25D366', 'chat', 'WhatsApp' ),
			'sms'      => array( '#0ea5e9', 'sms', 'SMS' ),
		);
		$c = $map[ $channel ] ?? array( '#8a9389', 'help', ucfirst( (string) $channel ) );
		return '<span class="chip" style="background:' . esc_attr( $c[0] ) . '1f;color:' . esc_attr( $c[0] ) . ';"><span class="mi sm">' . esc_html( $c[1] ) . '</span>' . esc_html( $c[2] ) . '</span>';
	}

	private function status_chip( $status, $en ) {
		if ( 'failed' === $status ) {
			return '<span class="chip danger"><span class="dot danger"></span>' . ( $en ? 'Failed' : 'فشل' ) . '</span>';
		}
		if ( 'blocked' === $status ) {
			return '<span class="chip muted"><span class="dot"></span>' . ( $en ? 'Blocked' : 'محظور' ) . '</span>';
		}
		return '<span class="chip success"><span class="dot success"></span>' . ( $en ? 'Sent' : 'تم الإرسال' ) . '</span>';
	}

	private function ago( $ts, $en ) {
		$diff = max( 0, time() - (int) $ts );
		if ( $diff < 60 ) {
			return $en ? $diff . 's ago' : 'منذ ' . $diff . ' ث';
		}
		return human_time_diff( $ts, time() ) . ( $en ? ' ago' : '' );
	}
}
