<?php
/**
 * Tab-intro texts — short summary + expandable longer explanation.
 *
 * Audience is non-experts: school admins, content creators, freelancers
 * who installed the plugin and want to know "what is this tab and do I
 * need to touch it?" before reading the actual settings.
 *
 * Structure per intro:
 *   short — one or two sentences, always visible at the top of the tab
 *   long  — paragraphs that expand on click. Cover: what does it do,
 *           who needs it, what happens if I leave defaults, what breaks
 *           if I misconfigure, where else to look.
 *
 * @package Brainwerk Security Suite
 */

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

class Shieldforge_Admin_Intros {

    /**
     * Map of tab-slug => intro array. Returns null for tabs without intros
     * (caller skips render).
     *
     * Texts are wrapped in __() so they translate via the standard WP i18n
     * pipeline (German .mo can be added later for non-English audiences).
     */
    public static function all() {
        return array(
            'dashboard' => array(
                'icon'  => 'dashicons-dashboard',
                'short' => __( '<strong>The "is anything on fire?" overview.</strong> Live security status of your site at a glance — threat level, recent attacker activity, and what (if anything) needs your attention.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'What you see here', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'A threat-score from 0 to 100 (calm / elevated / high / critical), action items pulled from the last 24 hours, brute-force lockouts, anomalous logins, top attacker IPs and which usernames they are guessing. The same overview also appears as a widget on your main WordPress dashboard.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Should I do anything?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'On a calm day: nothing. The score stays low, no action items, and you can close the tab. On a busy day, the action items are clickable shortcuts that take you to the relevant tool — no detective work required.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'How the score is calculated', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Four signal groups, each capped at 25 points so no single noisy signal can push the score on its own: failed-login volume, distinct attacker IPs, probing density (bots scanning your site for known files), and escalation signals (lockouts + anomalies + file changes + malware hits). The breakdown is shown in the daily digest email.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'login' => array(
                'icon'  => 'dashicons-lock',
                'short' => __( '<strong>Stops password-guessing attacks.</strong> When someone (or a bot) tries to log in too often with the wrong password, Brainwerk Security Suite locks them out — by IP and by account.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Why two kinds of lockout?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'IP-based lockout works against a single attacker hammering your site from one IP. But modern botnets rotate through hundreds of IPs to avoid that — so we ALSO lock the targeted account itself. After a configurable number of failed attempts, that username is locked for a configurable window. Attackers can\'t bypass it just by changing IP.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Safe defaults', 'brainwerk-security-suite' ) ),
                    array( 'p', __( '5 wrong tries within 5 minutes locks the IP for 30 minutes. 8 wrong tries within 15 minutes locks the account for 15 minutes. These defaults catch automated attacks without locking out real users who fat-fingered their password.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'I\'m on a CDN — will it see real IPs?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'If your nginx/Apache forwards the original client IP via PROXY-protocol or X-Forwarded-For, yes. The "Healthcheck" banner at the top warns you if all visitors arrive as 127.0.0.1 — that means the chain is hiding the real IP and brute-force protection would be useless without fixing the proxy first.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'twofactor' => array(
                'icon'  => 'dashicons-smartphone',
                'short' => __( '<strong>Two-factor authentication (2FA) — the single biggest defense against stolen passwords.</strong> Even if someone gets your password, they still need a 6-digit code from your phone to log in.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'How does it work?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'You install a free authenticator app on your phone (Google Authenticator, Microsoft Authenticator, Authy, 2FAS — any of them). It generates a 6-digit code that changes every 30 seconds. When you log in, you enter your password as usual, then the current code from the app. Without the phone in hand, your password is useless to an attacker.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'What if I lose my phone?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'When you set up 2FA, you get 8 single-use recovery codes. Save them in your password manager or print them out. Each one can be used exactly once instead of an authenticator code. If you lose all 8 recovery codes too, an admin (with manage_network_options capability) can disable 2FA for any user from this tab.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Setting it up', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'This tab is the admin overview. The actual setup form is on each user\'s own profile page — only you have the device, only you can enroll it. If "Force 2FA for these roles" is enabled, users in those roles see a warning until they finish setup.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'hardening' => array(
                'icon'  => 'dashicons-shield',
                'short' => __( '<strong>Closes off WordPress\'s "default doors" that attackers always try first.</strong> Each toggle here disables a feature that 99% of sites don\'t use but that 100% of bots probe for.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'What gets turned off?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'XML-RPC (a legacy API used by very old mobile apps — modern apps use REST). The in-admin file editor (lets a logged-in admin edit theme/plugin files directly — usable as a one-click backdoor if your account is hijacked). Author enumeration (visiting /?author=1 reveals usernames). The WordPress version string in the page source (lets bots match against vulnerability databases). REST API access for anonymous visitors to sensitive endpoints (users, comments, search).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Will this break my site?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Almost never. None of these are used by normal visitors or modern themes/plugins. The few cases where it matters: if you use Jetpack with the WordPress mobile app or a third-party scheduler that POSTs via XML-RPC, you may need to leave XML-RPC on. Test after enabling each toggle if you have a complex setup.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'What about more advanced hardening?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'See the "Hardening+" tab for custom login URL, honeypot anti-bot, and Content-Security-Policy headers — those are riskier (lockout potential) so they live separately and ship default-OFF.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'hardening-plus' => array(
                'icon'  => 'dashicons-superhero',
                'short' => __( '<strong>Three layered defenses for sites that want more than the basics.</strong> Each can lock you out if misconfigured — read carefully before enabling.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Custom login URL', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Move /wp-login.php to a path of your choosing. Bots blindly hammer /wp-login.php — they\'ll get a 404 and move on. Crucial lockout-recovery: add a SHIELDFORGE_LOGIN_RESCUE constant to wp-config.php BEFORE enabling this. If you forget your slug, the rescue token brings you back.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Honeypot anti-bot', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'A hidden field is added to login / register / comment forms. Real users never see it. Bots fill every visible field — submissions with the hidden field non-empty are blocked. 100% local, no Google reCAPTCHA, no third-party data transfer. Stops the dumb mass-bot 90% with zero user friction.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Security HTTP headers (incl. CSP)', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Each header is set ONLY if your nginx/Apache doesn\'t already send it. CSP (Content-Security-Policy) is off by default because a wrong policy can blank out your site — turn it on in Report-Only mode first, watch the browser console for violations, then enforce.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'firewall' => array(
                'icon'  => 'dashicons-shield-alt',
                'short' => __( '<strong>Currently-blocked IPs and how long they stay blocked.</strong> This is the live consequence of the brute-force protection on the Login tab.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'How does an IP get on this list?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Either automatically (it tripped the brute-force threshold and got auto-blocked for the configured lockout duration) or manually (you clicked "Block this IP" on the Logs tab).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Can I unblock someone?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Yes — every row has an "Unblock" link. Useful when you locked yourself out by typing your own password wrong too many times.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Does this stop ALL traffic from the IP?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'No — only login attempts. The block prevents further password guessing but doesn\'t stop the IP from reading public pages. For full IP-blocking, use a Pro feature like Geo-blocking or Cloud Threat Intel, or block at the firewall/CDN layer.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Crawler rate-limiting (further down this page)', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Caps how many requests per minute a single IP may make — with separate, stricter budgets for crawlers. Genuine search engines (Google, Bing, Apple, Yandex, Baidu) are verified via reverse-DNS and never throttled; bots FAKING a Googlebot user-agent are blocked outright. Logged-in users and whitelisted IPs are always exempt. Off by default.', 'brainwerk-security-suite' ) ),
                ),
                'cols' => array(
                    array( __( 'IP', 'brainwerk-security-suite' ), __( 'The blocked source IP (or anonymized /24 if IP anonymization is on).', 'brainwerk-security-suite' ) ),
                    array( __( 'Reason', 'brainwerk-security-suite' ), __( 'Why the block was created — typically `bf_threshold` (brute-force) or `admin_quick_block` (you blocked manually).', 'brainwerk-security-suite' ) ),
                    array( __( 'Blocked until', 'brainwerk-security-suite' ), __( 'When the block expires automatically. After this time the IP can attempt logins again.', 'brainwerk-security-suite' ) ),
                    array( __( 'Action', 'brainwerk-security-suite' ), __( '"Unblock" removes the entry immediately — useful if you locked yourself out.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'scanner' => array(
                'icon'  => 'dashicons-search',
                'short' => __( '<strong>Knows what every PHP file on your site SHOULD look like, and tells you when one suddenly changes.</strong> The earliest warning that something compromised your site.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'How does it know what is "normal"?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'On the first run, it computes a SHA-256 hash of every PHP file under WordPress core, your plugins, your themes, and mu-plugins. That\'s your "baseline" — typically 5,000 to 15,000 files. After that, the daily scan re-hashes everything and tells you about anything that was added, modified, or deleted.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'But files change all the time when I update plugins!', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Right — every time WordPress installs an update, hundreds of files change. The scanner picks those up too, but they appear bunched up at the time of the update — you\'ll recognize them. The dangerous ones are the changes that happen WITHOUT an update — those are the ones to investigate.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'And the malware-pattern checks?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'For every new or changed file, Brainwerk Security Suite runs 16 regex rules looking for hostile patterns: eval(base64_decode(...)), known web shells (c99/r57/WSO), inline admin-user-creation, password-cookie hijacks. Findings show the exact line and code snippet. False-positive rate is very low.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Privacy', 'brainwerk-security-suite' ) ),
                    array( 'p', __( '100% local. No file contents leave your server. The scan results stay in your own database.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Repository integrity check (further down this page)', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Compares every wp.org-hosted plugin and theme file against the official checksums from wordpress.org. A modified, missing or extra file means someone may have tampered with the package — it is reported here so you can inspect it and reinstall the clean copy from wordpress.org the standard way. Plugins/themes NOT from wp.org are listed as "unverifiable" and never touched.', 'brainwerk-security-suite' ) ),
                ),
                'cols' => array(
                    array( __( 'When', 'brainwerk-security-suite' ), __( 'UTC timestamp of when the scanner found the change.', 'brainwerk-security-suite' ) ),
                    array( __( 'Type', 'brainwerk-security-suite' ), __( 'What changed: <code>file added</code> (new file appeared), <code>file changed</code> (existing file modified), <code>file missing</code> (file deleted), <code>malware suspect</code> (suspicious code pattern detected).', 'brainwerk-security-suite' ) ),
                    array( __( 'Path / Detail', 'brainwerk-security-suite' ), __( 'Path of the affected file relative to your WordPress root. For malware hits the rule ID and a code snippet are shown below the path.', 'brainwerk-security-suite' ) ),
                    array( __( 'Severity', 'brainwerk-security-suite' ), __( '<code>info</code> = informational, <code>warn</code> = worth checking, <code>high</code> = file in WP core or admin (very suspicious), <code>critical</code> = known web shell signature.', 'brainwerk-security-suite' ) ),
                    array( __( 'Actions', 'brainwerk-security-suite' ), __( '"Re-baseline" accepts the current state as the new normal (the change won\'t be reported again). "Whitelist" suppresses all future alerts for this exact path.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'vulnerabilities' => array(
                'icon'  => 'dashicons-warning',
                'short' => __( '<strong>Tells you which of your installed plugins/themes have known security holes — and which version fixes them.</strong> Most WordPress hacks happen via outdated plugins; this tab tells you which ones to update first.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Where does the data come from?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'A daily check against the wpvulnerability.net public database (free, EU-hosted, no API key). For every plugin and theme installed on your site, Brainwerk Security Suite sends ONLY the slug + version (e.g. "contact-form-7 / 5.3.1") — no site URL, no admin email, no IP. The response is a list of CVE-IDs that affect your version, with the version that fixes them.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Active vs inactive plugins', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Vulnerabilities on ACTIVE components are dangerous — fix immediately. Vulnerabilities on INACTIVE plugins are usually unreachable but still worth removing (less attack surface, fewer files to maintain). The dashboard widget only nags about active critical ones to avoid alert fatigue.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'CVSS scores explained', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'CVSS is a 0-10 severity score. 9.0+ = critical (often remote code execution), 7.0-8.9 = high, 4.0-6.9 = medium, below 4.0 = low. Anything 7.0+ on an active plugin should be patched this week, not "soon".', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Disable the scan', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'If you want fully air-gapped operation, untick "Enable scanner" below — no outbound calls at all. Brainwerk Security Suite stays useful but you lose the early-warning on plugin CVEs.', 'brainwerk-security-suite' ) ),
                ),
                'cols' => array(
                    array( __( 'Component', 'brainwerk-security-suite' ), __( 'Plugin / theme name with its slug below (the slug is what we send to the vulnerability API).', 'brainwerk-security-suite' ) ),
                    array( __( 'Version', 'brainwerk-security-suite' ), __( 'The version installed on your site right now. Compare to "Fixed in" below to see if you need to update.', 'brainwerk-security-suite' ) ),
                    array( __( 'Active', 'brainwerk-security-suite' ), __( '<code>active</code> (red dot) = currently in use — patch THIS WEEK. <code>inactive</code> = installed but not running — not exploitable but still worth removing.', 'brainwerk-security-suite' ) ),
                    array( __( 'Vulnerability', 'brainwerk-security-suite' ), __( 'Short name of the CVE. The badge next to it is the CVSS score (0–10): 9.0+ critical, 7.0–8.9 high, 4.0–6.9 medium. "No patch available" means the vendor has not released a fix yet.', 'brainwerk-security-suite' ) ),
                    array( __( 'Fixed in', 'brainwerk-security-suite' ), __( 'The plugin/theme version that fixes this CVE. Update to this version (or newer) to close the hole.', 'brainwerk-security-suite' ) ),
                    array( __( 'Sources', 'brainwerk-security-suite' ), __( 'Public CVE-IDs (clickable, opens the official advisory). EUVD = EU Vulnerability Database mirror.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'anomaly' => array(
                'icon'  => 'dashicons-chart-line',
                'short' => __( '<strong>Spots logins that look unusual for a given user — without sending data to any cloud.</strong> "You normally log in from Vienna at 9am — this 3am attempt from Russia looks weird."', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'How does it learn what\'s "normal"?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'After each successful login, Brainwerk Security Suite updates a small per-user statistical baseline: which hours of the day you usually log in, which IP family (residential / datacenter / mobile / unknown), and which type of browser (modern / legacy / bot-like). The baseline becomes meaningful after about 5 logins per user.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'How does scoring work?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Each new login is compared to the baseline using a Z-score (how far is this from your normal pattern). A score of 0-100 is computed; above the alert threshold the event is logged as severity HIGH and shown in the digest with an explanation ("logged in at 3am from a datacenter IP — your usual is daytime from a residential IP").', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'No cloud, no AI', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'This is pure local statistics. No machine learning, no model server, no data leaves the site. Explainable: every flagged event tells you which signal triggered it.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'audit' => array(
                'icon'  => 'dashicons-clipboard',
                'short' => __( '<strong>Who changed what, when.</strong> A complete trail of post edits, user changes, plugin/theme updates, and security-relevant setting changes. Useful for incident response and DSGVO Art. 32 compliance.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'What gets recorded?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Post edits (who edited which post, what fields changed — but NOT the post body, for privacy + log size). User changes (someone updated their email, role, password). Plugin/theme/core updates. Security-sensitive options (siteurl, admin_email, "anyone can register", default-role-for-new-users, network site_admins).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'What does NOT get recorded?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The actual content of post edits (avoid leaking drafts into logs). Password values (only "[changed]" markers). Hundreds of harmless WordPress option-write spam (transients, cache markers). Auto-drafts and revisions and nav-menu items (skipped by default — too noisy).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'When is this useful?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Three scenarios: (1) Something broke yesterday — the audit log shows what was changed. (2) Compliance — DSGVO Art. 32 requires "measures for security of processing" and a paper trail is one. (3) Incident response after a hack — see exactly what the attacker touched after they got in.', 'brainwerk-security-suite' ) ),
                ),
                'cols' => array(
                    array( __( 'When', 'brainwerk-security-suite' ), __( 'UTC timestamp of when the change happened.', 'brainwerk-security-suite' ) ),
                    array( __( 'Who', 'brainwerk-security-suite' ), __( 'The user who made the change (clickable — links to the user-edit screen). "system / cron" means it was an automated WP process, not a person.', 'brainwerk-security-suite' ) ),
                    array( __( 'Action', 'brainwerk-security-suite' ), __( 'Type of change: <code>post updated</code>, <code>user profile updated</code>, <code>option changed</code>, <code>plugin activated</code>, etc.', 'brainwerk-security-suite' ) ),
                    array( __( 'What', 'brainwerk-security-suite' ), __( 'The specific object changed: post title and ID, plugin file, option name with old→new values. For password and similar sensitive fields you only see "[changed]".', 'brainwerk-security-suite' ) ),
                    array( __( 'IP', 'brainwerk-security-suite' ), __( 'Source IP of the change (anonymized to /24 by default). Useful when investigating "who did this from where".', 'brainwerk-security-suite' ) ),
                ),
            ),

            'logs' => array(
                'icon'  => 'dashicons-list-view',
                'short' => __( '<strong>The raw event stream — every login, block, anomaly, file change, vulnerability finding.</strong> Where you go when you need to dig into "what happened at 03:47 last Tuesday".', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Filter and search', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'You can narrow the list by event type, severity, IP, username, or date range. Click "Block this IP" or "Unblock" inline — no need to switch tabs. The default view is the latest 50; pagination shows older entries.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'How long are logs kept?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Configurable retention, default 30 days. A daily cleanup cron drops anything older. If you want to keep them longer for compliance, increase the retention setting on the Privacy / GDPR tab.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Audit-only view?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'For who-changed-what queries (post edits, user changes, plugin updates), use the Audit tab — it shows the same data filtered to just the audit-trail events with prettier per-event-type rendering.', 'brainwerk-security-suite' ) ),
                ),
                'cols' => array(
                    array( __( 'When', 'brainwerk-security-suite' ), __( 'Server timestamp in UTC. Note: NOT in your local timezone — this avoids ambiguity when investigating across time zones / daylight savings.', 'brainwerk-security-suite' ) ),
                    array( __( 'Event', 'brainwerk-security-suite' ), __( 'What happened. Common ones: <code>login_success</code>, <code>login_failure</code>, <code>login_blocked</code> (BF lockout active), <code>bruteforce_lockout</code> (a new IP just got blocked), <code>probing_404</code> (bot tried a known sensitive URL), <code>anomaly_detected</code> (login that doesn\'t match the user\'s usual pattern), <code>hardening_block</code> (REST/honeypot/geo-block fired), <code>file_added/changed/missing</code>, <code>malware_suspect</code>, <code>vulnerability_found</code>, <code>2fa_required/passed/failed</code>.', 'brainwerk-security-suite' ) ),
                    array( __( 'Severity', 'brainwerk-security-suite' ), __( '<code>info</code> = normal activity, <code>warn</code> = worth a glance, <code>high</code> = important investigate, <code>critical</code> = fire-on-the-roof. Severity decides which events trigger real-time email and dashboard nags.', 'brainwerk-security-suite' ) ),
                    array( __( 'IP', 'brainwerk-security-suite' ), __( 'Source IP of the request. Anonymized to /24 (IPv4) or /64 (IPv6) by default — turn that off in Privacy / GDPR if you need full IPs for forensics.', 'brainwerk-security-suite' ) ),
                    array( __( 'User', 'brainwerk-security-suite' ), __( 'Username being attempted (for login events) or the user who triggered the event. May be hashed if pseudonymization is enabled.', 'brainwerk-security-suite' ) ),
                    array( __( 'Context', 'brainwerk-security-suite' ), __( 'JSON blob with event-specific extras: paths for file events, CVE IDs for vulnerability events, the rule that matched for malware, the score breakdown for anomalies. The "_v" field is the plugin version that wrote the event — useful when triaging post-update bugs.', 'brainwerk-security-suite' ) ),
                    array( __( 'Actions', 'brainwerk-security-suite' ), __( '"Block this IP" creates a manual firewall block on the IP for the configured lockout duration. "Unblock" removes an existing block. No "delete event" — events stay until the retention cutoff.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'notifications' => array(
                'icon'  => 'dashicons-email-alt',
                'short' => __( '<strong>Email alerts on critical events + a daily summary.</strong> The daily digest is the single most important email — pure ASCII, works with every mail provider, and tells you in 30 seconds if something needs attention.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Real-time alerts', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Sent immediately when critical events fire: brute-force lockouts, new admin users, anomalous logins, malware-pattern hits. Quiet hours can suppress non-critical alerts overnight, with critical ones overriding the silence.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Daily digest', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'One email per day with the threat score, 24h-vs-7d trend, top attacker IPs, top targeted usernames, top probing patterns, vulnerable active components, and an ASCII heatmap of the last 24 hours. Pure-ASCII so it survives every mail pipeline (php mail / classic SMTP / OAuth-SMTP / Microsoft Graph) without character corruption.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Where is this digest from?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Same data the dashboard widget shows, formatted for inbox consumption. The bottom of every email tells the recipient how to disable it — important so you don\'t train people to ignore them.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'multisite' => array(
                'icon'  => 'dashicons-admin-multisite',
                'short' => __( '<strong>Network-wide settings + per-site overrides for WordPress Multisite installations.</strong> Configure once at the network level, override only where needed.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'How configuration cascades', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'On Multisite, Brainwerk Security Suite stores defaults in network-options (sitemeta), and any setting saved at a single-site level overrides them just for that site. Most network admins set strict defaults and let nothing override; agencies that host clients on subsites can give each client their own thresholds.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Aggregate dashboard', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The cross-site stats appear in the network-admin dashboard widget — you see "12 lockouts across 7 sites in the last 24h" instead of 12 separate single-site widgets.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Single-site install?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'This tab is only meaningful on Multisite. On a single-site install you can ignore it — every setting saves to that one site\'s options.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'privacy' => array(
                'icon'  => 'dashicons-privacy',
                'short' => __( '<strong>What data Brainwerk Security Suite stores about your visitors, and your DSGVO/GDPR controls for it.</strong> This is the page you copy-paste from when updating your site\'s privacy policy.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Default-on privacy', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'IP anonymization is on by default — IPv4 addresses are stored as /24 (e.g. 1.2.3.0), IPv6 as /64. Username pseudonymization is off by default but can be turned on if you want only hashed usernames in the log. Log retention is 30 days; older entries are auto-deleted.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Privacy-policy snippet generator', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The generator produces ready-to-paste DE/EN text describing what Brainwerk Security Suite stores and for how long. Copy it into your "Datenschutzerklärung" / "Privacy Policy" page so you have an honest, accurate disclosure.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'External services', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The free plugin makes ONE outbound call: the daily vulnerability check sends slug+version of installed plugins/themes to wpvulnerability.net. Nothing else leaves your server. You can disable the scanner under "Vulnerabilities → Settings" if you prefer fully air-gapped operation.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'tools' => array(
                'icon'  => 'dashicons-admin-tools',
                'short' => __( '<strong>Manual one-shot actions.</strong> Send a test email, force a log cleanup, retroactively anonymize old log entries — things you do once or twice, not in daily operation.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Test the alert email', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Sends a sample notification to the address configured under Notifications. Use this to verify the email pipeline works (SMTP, Office 365 Graph, whatever you use) BEFORE a real attack — better to find out the email goes to spam now than during an incident.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Cleanup logs now', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Manually trigger the daily retention-cleanup. Useful right after you reduced the retention setting and want the older entries gone immediately.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Retroactive IP anonymization', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'If you turned anonymization ON after the plugin had already been collecting raw IPs, this rewrites the historical entries to the anonymized form. One-time operation — safe to run, irreversible.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'incident' => array(
                'icon'  => 'dashicons-sos',
                'short' => __( '<strong>The "we think we\'ve been hacked — now what?" module.</strong> Forensic triage, evidence preservation, staged lockdown and a written incident report. It detects, preserves and reports — it never auto-deletes anything.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'What is an "incident" here?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'A suspected compromise: a web shell finding, an unexplained admin user, files changing without an update. Instead of panicking, you start a structured response from this tab: collect the facts, secure the evidence, optionally restrict the site, and get a report you can hand to your host, your boss, or the data-protection officer.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Why no automatic cleanup?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Deliberate design decision: every destructive action is human-gated. Automated "cleaners" routinely delete the evidence you need to understand HOW the attacker got in — and if you don\'t know that, they\'ll be back through the same door. This module preserves first, and lets YOU decide what to remove.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Current status of the module', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The foundation is live: incident records, the opt-in toggle and the manual audit trigger. Automated triggers, the forensic engine and the staged lockdown ship in upcoming phases — each one opt-in. Until then the tab is safe to leave disabled.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'threat-network' => array(
                'icon'  => 'dashicons-networking',
                'short' => __( '<strong>Optional, privacy-preserving attack-data sharing between Brainwerk Security Suite sites.</strong> Your site reports anonymized attacker indicators; in return it receives a signed feed of threats seen across the network — including virtual-patch firewall rules.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'What exactly leaves my server?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Only verified facts about blocked attacks: an irreversibly hashed IP indicator (rotating weekly salt — no raw IPs, not even reversible by us), the attack category, the matched rule, HTTP method and status. No URLs with visitor data, no usernames, no e-mail addresses. The "What was sent" audit list on this tab shows every single event, so you can verify this claim yourself.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'What do I get back?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'A cryptographically signed (Ed25519) intel feed: attacker indicators observed on multiple sites, and curated firewall rules ("virtual patches") for actively exploited vulnerabilities. The plugin verifies the signature against a pinned public key before applying anything — a tampered or spoofed feed is rejected outright (fail-closed).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Is this on by default?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'No. Everything here is opt-in: sharing is off until you enable it, and IP-blocking based on the received feed is a second, separate opt-in. Applying the virtual-patch rules is on once you join, because that\'s the main benefit and carries no privacy cost.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'EU hosting', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The central endpoint is operated on EU infrastructure under GDPR. Retention on the server is time-limited; indicators age out automatically.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'modules' => array(
                'icon'  => 'dashicons-screenoptions',
                'short' => __( '<strong>Nine self-contained extra modules, each with its own toggle — all OFF by default.</strong> Pwned-password check, extra security headers, local CAPTCHA, live traffic view, core file compare, privacy dashboard, trusted devices, magic login links, and the Web Application Firewall.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Why a separate page?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'These optional modules add extra layers of protection — each is off by default. Each card on this page is one module — a toggle, its settings, and where applicable a small data view. Enable only what you need; every module you leave off costs zero performance.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Which ones are worth turning on first?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'For most sites: the WAF (blocks SQL-injection, XSS and traversal patterns before WordPress processes them — start with paranoia level 1), the Pwned-password check (rejects passwords that appeared in public breaches, checked via k-anonymity — the password itself never leaves your server), and the local CAPTCHA (pure-PHP arithmetic puzzle, no Google services, no consent banner needed).', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Anything with lockout potential?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'The WAF on a high paranoia level can block legitimate requests of unusual plugins — watch the Firewall tab after enabling and lower the level if you see false positives. Magic login links replace passwords with e-mailed one-time links; make sure your site can reliably send mail before relying on them.', 'brainwerk-security-suite' ) ),
                ),
            ),

            'license' => array(
                'icon'  => 'dashicons-id-alt',
                'short' => __( '<strong>Upgrade to Brainwerk Security Suite Pro.</strong> The free plugin works on its own — Pro adds WebAuthn / Passkeys, geo-blocking, EU-hosted cloud threat intel, AI-assisted incident analysis (BYOK Mistral or self-hosted Ollama), Slack/Discord/Telegram/Teams notifications, multisite aggregate dashboard, and white-label mode.', 'brainwerk-security-suite' ),
                'long'  => array(
                    array( 'h', __( 'Where do I get Pro?', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'From security-suite.brainwerk.at. Brainwerk Security Suite Pro is a separate plugin (.zip) that you install alongside this free one — license activation happens inside the Pro plugin, no key has to be entered here.', 'brainwerk-security-suite' ) ),
                    array( 'h', __( 'Pricing model', 'brainwerk-security-suite' ) ),
                    array( 'p', __( 'Per-installation tiers (1 site / 5 sites / unlimited). Annual subscription with continued updates and priority support. Sold through Freemius — EU-friendly checkout, full GDPR documentation.', 'brainwerk-security-suite' ) ),
                ),
            ),
        );
    }

    /**
     * Render the intro card for a given tab. No-op for unknown tabs.
     * Called from Shieldforge_Admin::render_page() before the tab view.
     */
    public static function render( $tab ) {
        $intros = self::all();
        if ( ! isset( $intros[ $tab ] ) ) {
            return;
        }
        $intro = $intros[ $tab ];
        $icon  = $intro['icon'] ?? 'dashicons-info';
        $short = $intro['short'] ?? '';
        $long  = is_array( $intro['long'] ?? null ) ? $intro['long'] : array();
        ?>
        <div class="sf-intro" data-tab="<?php echo esc_attr( $tab ); ?>">
            <div class="sf-intro-short">
                <span class="sf-intro-icon dashicons <?php echo esc_attr( $icon ); ?>"></span>
                <span class="sf-intro-text">
                    <?php
                    echo wp_kses(
                        $short,
                        array(
                            'strong' => array(),
                            'em'     => array(),
                            'code'   => array(),
                            'br'     => array(),
                        )
                    );
                    ?>
                </span>
            </div>
            <?php if ( ! empty( $long ) ) : ?>
                <details class="sf-intro-details">
                    <summary><?php esc_html_e( 'Read more about what this tool is for', 'brainwerk-security-suite' ); ?></summary>
                    <div class="sf-intro-long">
                        <?php foreach ( $long as $block ) :
                            list( $type, $text ) = $block;
                            if ( 'h' === $type ) {
                                echo '<h3>' . esc_html( $text ) . '</h3>';
                            } else {
                                echo '<p>' . wp_kses(
                                    $text,
                                    array(
                                        'strong' => array(),
                                        'em'     => array(),
                                        'code'   => array(),
                                        'br'     => array(),
                                        'a'      => array( 'href' => true, 'target' => true, 'rel' => true ),
                                    )
                                ) . '</p>';
                            }
                        endforeach;

                        // Optional column glossary — only on tabs with data tables.
                        $cols = isset( $intro['cols'] ) && is_array( $intro['cols'] ) ? $intro['cols'] : array();
                        if ( ! empty( $cols ) ) :
                            ?>
                            <h3><?php esc_html_e( 'Columns explained', 'brainwerk-security-suite' ); ?></h3>
                            <dl class="sf-intro-cols">
                                <?php foreach ( $cols as $col ) :
                                    list( $name, $desc ) = $col;
                                    ?>
                                    <dt><?php echo esc_html( $name ); ?></dt>
                                    <dd><?php
                                        echo wp_kses(
                                            $desc,
                                            array(
                                                'strong' => array(),
                                                'em'     => array(),
                                                'code'   => array(),
                                                'br'     => array(),
                                                'a'      => array( 'href' => true, 'target' => true, 'rel' => true ),
                                            )
                                        );
                                    ?></dd>
                                <?php endforeach; ?>
                            </dl>
                        <?php endif; ?>
                    </div>
                </details>
            <?php endif; ?>
        </div>
        <?php
    }
}
