# Changelog

All notable changes to CloudScale Code Block are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [1.10.107] - 2026-06-15

### Fixed
- WordPress.org review: rename text domain from `cyber-devtools` to `cloudscale-cyber-devtools` across all 1,132 i18n call sites and plugin header (`Text Domain:`)
- WordPress.org review: gate "Powered by CloudScale" credit link on new opt-in setting `csdt_show_powered_by` (off by default); added checkbox to Code Block Settings panel and wired AJAX save handler
- WordPress.org review: sanitize `$_SERVER['REQUEST_URI']`, `$_SERVER['REQUEST_METHOD']`, and `$_SERVER['argv']` before concatenation in `class-monitor.php` fatal-error context and alert context
- WordPress.org review: sanitize `$_SERVER['REQUEST_URI']` in REST diagnostic capture and legacy-URL redirect handler (`cs-code-block.php`)
- WordPress.org review: sanitize + `rawurlencode` `$_GET` values passed to `add_query_arg()` in `redirect_legacy_slug()`
- WordPress.org review: add `esc_attr()` to `$pct` (bar chart height style attribute) in brute-force panel
- WordPress.org review: wrap `$icon` with `wp_kses()` in licence card output (`class-cloudscale-licence.php`)
- WordPress.org review: wrap translation format string with `wp_kses()` in `printf()` call for "Scan Posts" migration hint
- WordPress.org review: add `phpcs:ignore` with explanation to `implode($user_parts)` output (items are individually `esc_html()`-escaped in the loop above)
- WordPress.org review: constrain SMTP port `register_setting` sanitize callback to valid range `1–65535` (was `> 0` only)
- WordPress.org review: replace `WP_CONTENT_DIR . '/mu-plugins'` with `WPMU_PLUGIN_DIR` constant in 3 locations
- WordPress.org review: scope `SAVEQUERIES` define to admin, REST, and WP-CLI contexts only (was set on every request)
- WordPress.org review: add explicit `add_action('shutdown', 'ob_end_flush', 0)` after both `ob_start()` calls that use output-buffer callbacks (CSP nonce injector, AdSense dedup)
- WordPress.org review: add `phpcs:ignore NonPrefixedHooknameFound` to `wp_schedule_event()` calls scheduling WordPress core hooks `wp_scheduled_delete` and `delete_expired_transients`

### Added
- readme.txt: External services section now documents PayPal, Patchstack vulnerability database, Cloudflare API, Telegram Bot API, and GitHub/GitLab — with endpoints, data-sent descriptions, and links to each service's privacy policy and terms
- build.sh: PHPCS WordPress-standard check step (gracefully skips if `phpcs` not installed, with install instructions)
- Code Block Settings: "Show Powered by CloudScale credit link" opt-in checkbox (off by default)

## [1.10.95] - 2026-06-15

### Fixed
- WordPress.org PCP (round 3): replace `parse_url()` with `wp_parse_url()` in 10 call sites across `class-cs-passkey.php`, `class-sec-headers.php`, `class-perf-monitor.php`, `class-cloudscale-telegram.php`, and `class-csp.php` — PCP error `WordPress.WP.AlternativeFunctions.parse_url_parse_url`
- WordPress.org PCP (round 3): add `phpcs:ignore NonEnqueuedScript` to `output_ads_dedup_script()` in `cs-code-block.php` (hooked to `wp_head` priority 0; `wp_add_inline_script()` does not support priority-0 injection)
- WordPress.org PCP (round 3): add `phpcs:ignore NonEnqueuedScript` to Telegram admin panel inline script in `class-cloudscale-telegram.php`
- readme.txt: remove duplicate "AI Cyber Audit" and "AI Deep Dive Cyber Audit" bullet entries from Description section

### Added
- Managed AI: PayPal checkout and subscription flow as an alternative billing provider; `handle_paypal_checkout` and `handle_paypal_subscription` handlers in `CloudScale_Licence`; PayPal SDK button initialised client-side from `cloudscale-licence.js` when `paypalPlanId` is configured

## [1.10.94] - 2026-06-15

### Fixed
- WordPress.org automated scan: hardcode `'cloudscale-devtools'` text domain literal in all i18n calls in `class-cloudscale-licence.php` and `class-cloudscale-telegram.php` — `NonSingularStringLiteralDomain` error (variable `$td`/`$text_domain` not permitted)
- WordPress.org automated scan: exclude `phpcs.xml.dist` from distribution zip — `application_detected` error
- WordPress.org automated scan: add `PluginCheck.Security.DirectDB.UnescapedDBParameter` to existing `phpcs:ignore` on SQL Query Tool's free-form `get_results()` call

## [1.10.92] - 2026-06-15

### Fixed
- WordPress.org submission: replace echoed `<script>` tag in `class-cloudscale-licence.php` with `wp_add_inline_script()` (PCP hard block)
- WordPress.org submission: remove `cloudflare.com` URL patterns from PHP comments to avoid automated "Calling files remotely" false positive
- WordPress.org submission (G10): gate 404 page "Powered by CloudScale Devtools" link behind `csdt_404_show_credit` option (default off)
- WordPress.org submission (G4): add `== Credits ==` section to readme.txt documenting bundled minified JS sources (highlight.js, QRCode.js, Leaflet, MaxMind DB Reader)
- WordPress.org submission: fix `Contributors:` field from brand slug `cloudscale` to WP.org login `andrewjbaker`
- WordPress.org submission: add `phpcs.xml.dist` to exclude `lib/` from Plugin Check PHPCS scans
- WordPress.org submission: add `phpcs:ignore` comments with justifications for `fopen`/`fread`/`fclose`/`file_get_contents` on local log files across all monitor/audit classes
- WordPress.org submission: add architecture justification comment on `object-cache.php` `copy()` in `class-code-migrator.php`
- Build: exclude `archive/` directory from distribution zip
- Admin notice: fix `esc_html()` double-encoding `&nbsp;` HTML entity in thumbnails notice separator

## [1.10.58] - 2026-06-08

### Fixed
- Code Block editor: pasting into the code textarea no longer replaces the entire block. The `onPaste` handler now inserts clipboard text at the cursor (replacing only the selected range, like a normal textarea) and restores the caret position. Fresh-paste markdown fence stripping and language auto-detection are preserved when the textarea is empty or fully selected; the toolbar Paste button still does a full replace

## [1.10.9] - 2026-05-31

### Security
- Managed AI: `wp_unslash()` the `enabled` POST value in `ajax_set_enabled()` before casting, clearing the WordPress.org Plugin Check `ValidatedSanitizedInput.MissingUnslash` flag (the only remaining input read without unslash in the managed-AI handlers)

## [1.10.8] - 2026-05-31

### Security
- Managed AI: every admin-ajax handler now calls `check_ajax_referer()` directly at the top of the handler instead of delegating to the `guard()` helper, so PHPCS / WordPress.org Plugin Check can trace the nonce verification in-scope (`NonceVerification.Missing`); `guard()` now performs only the `manage_options` capability check

## [1.10.6] - 2026-05-30

### Added
- Managed AI: the Paystack subscription code is now captured (on recover / refresh / poll), stored in the `proxy_subscription_code` option, and displayed on the management panel

### Fixed
- Managed AI: "Cancel subscription" no longer dead-ends with "No subscription code on file" — when the code was never captured at checkout it is now backfilled from Paystack by customer email on license recovery (and as a self-heal during cancel); cancel/refund requests now send the subscription code and email to the proxy

## [1.9.514] - 2026-04-25

### Fixed
- CS Monitor: "Script error." hint match widened to a case-insensitive regex (`/^script error\.?$/i`) to handle browser variations in capitalisation and trailing punctuation

## [1.9.513] - 2026-04-25

### Fixed
- CS Monitor: `panelLocked` flag blocks `togglePanel()` and tab-click `openPanel()` for 600ms after every page load and bfcache restore — prevents iOS Safari ghost taps (phantom touches fired at the last navigation coordinates) from re-opening the panel immediately after it is force-collapsed

## [1.9.512] - 2026-04-25

### Fixed
- CS Monitor: panel now always starts collapsed on every page load — `restoreState()` calls `closePanel()` (removes `cs-perf-open` class) instead of only adjusting padding; `pageshow` listener added for iOS Safari bfcache restores where `DOMContentLoaded` does not re-fire; stale `localStorage.setItem(LS_OPEN)` write removed from resize drag handler

## [1.9.511] - 2026-04-25

### Added
- CS Monitor: JS error handler now replaces bare `Script error.` with an explanatory hint pointing to DevTools console and the `crossorigin="anonymous"` fix — makes cross-origin errors self-diagnosable without leaving the admin panel

## [1.9.510] - 2026-04-25

### Fixed
- Code Block: `crossorigin="anonymous"` added to the highlight.js CDN `<script>` tag so `window.onerror` receives full error details (filename, line, column) from cross-origin scripts instead of a masked `Script error.`

## [1.9.509] - 2026-04-25

### Fixed
- CSP: removed nonce from `style-src` — CSP Level 3 ignores `'unsafe-inline'` when a nonce is present in `style-src`, which was silently blocking all `style=""` attributes site-wide (broke the AI SEO summary box and any other inline-styled elements); `https://cdnjs.cloudflare.com` added to `style-src` directly to allow the hljs CDN CSS

## [1.9.508] - 2026-04-25

### Removed
- CS Monitor: `?` help panel removed entirely — was triggering automatically on iOS Safari due to bfcache page restore combined with a JS scope bug that prevented the display:none guard from applying

## [1.9.507] - 2026-04-25

### Fixed
- CS Monitor: help panel (`?` button) no longer auto-opens on iOS Safari — panel is explicitly force-hidden on every page load; a 600ms guard on the click handler blocks ghost taps that fire at page-load coordinates before the user has intentionally interacted

## [1.9.506] - 2026-04-25

### Fixed
- CS Monitor: panel always opens at default height (340px) — height and open-state are no longer persisted to `localStorage`, so dragging to full-screen no longer causes it to reopen full-screen on the next visit; `LS_OPEN` and `LS_HEIGHT` keys are cleared on every page load

## [1.9.505] - 2026-04-25

### Fixed
- CS Monitor: panel no longer auto-reopens on every page load — `restoreState()` now always starts collapsed; height and active tab are still persisted via `localStorage`

## [1.9.504] - 2026-04-25

### Fixed
- CSP: `style-src` now includes the per-request nonce when nonces are enabled — WordPress 6.x adds the nonce attribute to enqueued `<link>` stylesheet tags, so the nonce must also appear in `style-src` for non-self CDN stylesheets (e.g. highlight.js themes from cdnjs) to load; previously only `script-src` had the nonce, causing CDN CSS to be blocked and syntax highlighting colours to disappear

## [1.9.501] - 2026-04-25

### Added
- Thumbnails: hero image auto-sizing on single post pages — `post_thumbnail_html` filter (priority 11) swaps the featured image `src` to the plugin's already-generated 1200×630 Facebook social format when available; strips `srcset`/`sizes` so the browser loads the correct crop; CSS `aspect-ratio: 1200/630; object-fit: cover` injected via `wp_enqueue_scripts` as a no-src registered style so the layout holds for posts that have not yet been processed

## [1.9.498] - 2026-04-25

### Added
- Thumbnails: "Refresh Stale" button — scans all published posts in batches of 10, identifies posts where the featured image was replaced (attachment ID changed or `post_modified_gmt` newer than `_csdt_social_formats_gen_time`), regenerates social formats for each, and shows a live log with found/fixed counts and clickable post links

## [1.9.496] - 2026-04-25

### Fixed
- Thumbnails: `on_post_saved` now regenerates social formats when the featured image file is replaced in the Media Library — previously only triggered when the attachment ID changed, missing file-replacement updates; stores `_csdt_social_formats_gen_time` and compares against attachment `post_modified_gmt`
- Passkey login: back-to-picker recomputes available/setup methods from DB so stale transients with missing keys still show the full method list
- Passkey login: TOTP fallback link shown on passkey challenge screen when TOTP is also configured; `render_login_challenge` takes `$available` array instead of `$has_picker` bool; stores `wp_user_login` in credential on registration
- CSP scan: warnings and raw headers panels replaced `<table>` layout with `<div>` stacks so long header values wrap correctly on mobile
- Site Audit: CTA block description now stacks above button on narrow screens
- Admin banner header: flexbox alignment for icon + text

## [1.9.495] - 2026-04-24

### Added
- Test Account Manager: Block Basic Auth toggle — site-wide switch to disable REST API application passwords and HTTP Basic Auth for all users; prevents tools like curl and Postman from authenticating with username/password, without affecting session-based logins or test account flows
- Inline `<script>` handler for the save button — isolated from external JS so it works even when `cs-test-accounts.js` fails to load (e.g. Cloudflare tunnel hiccup)
- `ajax_toggle_block_basic_auth` AJAX handler in `CSDT_Test_Accounts` — persists `csdt_block_basic_auth` option; nonce-verified and admin-only
- `tests/block-basic-auth.spec.js` — Playwright test covering save, reload persistence (unchecked and checked), and safe-default restore

### Changed
- Removed duplicate Block Basic Auth click handler from `cs-test-accounts.js`; inline script is now the sole handler

## [1.9.379] - 2026-04-23

### Changed
- All inline `<script>` blocks extracted to enqueued JS files (`cs-csp.js`, `cs-optimizer-panel.js`, `cs-prefix-rollback.js`) — eliminates PCP `NonEnqueuedScript` violations
- All inline `<style>` blocks extracted to `wp_add_inline_style()` calls — eliminates PCP `NonEnqueuedStylesheet` violations
- All `onclick=` inline event handlers replaced with `data-cs-modal-open/close/backdrop` and `data-cs-copy-from` data attributes; event delegation added to `cs-admin-settings.js`
- `uninstall.php` updated to delete all current `csdt_devtools_*` options on plugin removal
- `build.sh` now excludes dev-only files from distribution zip

### Fixed
- Removed 5 `error_log()` debug statements left in cron scan handlers
- Removed stale `wp_ajax_nopriv_csdt_fpm_report` AJAX hook pointing to non-existent method
- Added `phpcs:ignore` annotations to all intentional `curl_multi`, `set_time_limit`, and `file_put_contents`/`file_get_contents` calls

## [1.9.376] - 2026-04-22

### Fixed
- Fatal error: `CSDT_SMTP::maybe_migrate_prefix()` and related migration methods changed from `private static` to `public static` — they are called cross-class from `CloudScale_DevTools::init()`
- All `private static` methods called cross-class in 9 include files promoted to `public static`
- Added missing `CloudScale_DevTools::get_client_ip()` referenced by `class-login.php`

## [1.8.120] - 2026-04-11

### Fixed
- Code Block editor: raw paste transform now detects markdown fenced blocks pasted as `<p>` elements (plain-text clipboard format from terminals and text editors) and converts them to a CloudScale code block with the correct language set — previously the fence markers became stray paragraphs

## [1.8.119] - 2026-04-11

### Added
- Thumbnails: Diagnose button on each flagged post row — checks meta state (both old `_cs_social_formats` and new `_csdt_social_formats` keys), file existence on disk for each platform, URL reachability per crawler UA, and og:image seen by each crawler
- Thumbnails: URL checker results — Copy Results to Clipboard button
- Thumbnails: Crawler Access Test merged into URL checker results; removed from separate Cloudflare Setup panel

### Fixed
- Thumbnails: `output_crawler_og_image()` now falls back to legacy `_cs_social_formats` meta key so posts published before the cs_ → csdt_ rename still serve the correct og:image
- Thumbnails: optimum image size targets reduced from 900 KB → 400 KB for Facebook, Twitter, LinkedIn, and Instagram
- Admin CSS: section header layout — title and hint text no longer run together; hint is right-aligned via `flex: 1; margin-left: auto`

### Changed
- Code Block editor: Paste button (and Ctrl+V into the textarea) now detects markdown fenced code blocks — extracts language from the fence header (handles aliases: `sh`/`shell`/`zsh` → bash, `py` → python, `js` → javascript, etc.) and strips fence markers so only the code content is stored

## [1.8.114] - 2026-04-10

### Fixed
- Explain modals: description content now renders formatted HTML — inline `<code>` tokens styled with dark background and amber text, `<strong>` / `<em>` emphasis, and `<ul>/<li>` bullet lists
- Explain modals: all plain-text `desc` items converted to `html` format with `<code>` markup for commands, file paths, query types, and technical values
- Expand `$explain_kses` allowlist: added `ul`, `ol`, `li`, `p`, `h4` so structured content can be used in item descriptions

## [1.8.111] - 2026-04-11

### Added
- Thumbnails: "Fix All Posts on Site" batch button — processes every published post in groups of 10 with live progress counter
- Thumbnails: Crawler UA detection — wp_head priority-1 og:image output so each platform receives its correctly-sized image

### Fixed
- Thumbnails: PNG and WebP featured images now converted to JPEG during social format generation so lossy compression can meet platform size targets
- Thumbnails: WebP source images were silently skipped by Fix/Fix All — webp now in supported formats list
- CS Monitor: performance data was injected after footer scripts ran (priority 9999), so the panel always showed empty data; data now injected at priority 15 via wp_add_inline_script() before scripts print at priority 20
- PCP: email-verified modal countdown script moved from inline PHP `<script>` to wp_add_inline_script()
- PCP: Thumbnails tab inline `<style>` block moved to wp_add_inline_style() on the cs-admin-tabs handle
- PCP: wp_delete_file() replaces unlink() for image backup temp-file cleanup
- PCP: REST hi-score endpoints use explicit anonymous permission callbacks instead of `__return_true` string
- PCP: Missing wp_unslash() before sanitize_text_field() on $wp->query_vars values in perf monitor

### Security
- SSRF protection on admin URL-check endpoints — private/reserved IP ranges rejected before outbound HTTP
- Cloudflare cache-purge endpoint validates supplied URL belongs to the current site
- DOM XSS fixed in email 2FA enable flow — innerHTML concatenation replaced with safe DOM + textContent
- TOTP secret cleared from DOM immediately after successful activation

## [1.8.107] - 2026-04-10

### Fixed
- Session cookie: hook moved from login_form_login (display-only, never fires on POST) to login_init so persistent-cookie flag is set before WordPress processes credentials

## [1.8.89] - 2026-04-10

### Added
- Login: brute-force protection — configurable per-account lockout after N failed attempts (default 5 attempts, 5-minute lock) with admin UI
- Thumbnails tab: Social Preview Diagnostics — URL checker (9-point OG/image diagnostic), recent posts auto-scan, Cloudflare WAF setup guide, crawler UA tester, cache purge, Media Library auditor with one-click recompress

### Fixed
- Login: session persistence — auth cookie is now persistent (not a session cookie) when a custom session duration is set

## [1.7.48] - 2026-04-05

### Added
- Code Block Settings: checkbox to show/hide the CS Monitor performance panel (saved via AJAX alongside theme settings; hides the panel for all users when unchecked)

## [1.7.36] - 2026-04-05

### Added
- CS Monitor: **Assets tab** — all enqueued JS and CSS files, attributed to plugin/theme/wp-core, with type filter and search
- CS Monitor: **Hooks tab** — top 50 WordPress hooks by cumulative execution time; sortable by count, total, or max time; search filter
- CS Monitor: **Object cache stats** card in Summary — hit rate, hit/miss counts, persistent cache detection (Redis/Memcache)
- CS Monitor: **Slowest Hooks** section in Summary — top 8 hooks by total time with bar chart
- CS Monitor: **Assets** summary card showing JS + CSS counts

## [1.7.25] - 2026-03-23

### Fixed
- `editor.js`: `onPasteCode` now handles both the toolbar Paste button and the browser's native paste event (Ctrl+V) — previously Ctrl+V completely bypassed `decodeClipboardText()`, meaning escape-sequence decoding never ran on keyboard pastes; textarea now has `onPaste` handler that calls `event.preventDefault()` and reads from `event.clipboardData` synchronously

## [1.7.24] - 2026-03-23

### Fixed
- `editor.js`: `decodeClipboardText()` replaced broken `JSON.parse` approach with direct regex-based decoding — `JSON.parse` was silently failing when `\u0022` decoded to `"` inside the JSON string, causing `\n` to be stored as literal `n` and `\u0022` to be stored as literal `u0022` in the database; now handles `\n`, `\t`, `\r`, `\\`, `\uXXXX`, and bare `uXXXX` correctly
- `editor.js`: Added `(attributes.content || '')` null guard on `.split('\n')` row calculation to prevent TypeError on null content
- `cs-code-block.php`: Removed `opacity:.5;pointer-events:none` inline styles from the Migrate All button — inline styles were never cleared when the button was re-enabled via JS, leaving it visually disabled
- `assets/cs-code-migrate.css`: Added `.cs-btn-orange:disabled` and `.cs-btn-primary:disabled` CSS rules to handle disabled state declaratively
- `cs-code-block.php`: Fixed `printf()` in `render_migrate_panel()` — outer format string was wrapped in `esc_html__()` while `%s` was replaced with raw HTML; outer string now uses `__()` with a `phpcs:ignore` annotation
- `blocks/code/block.json`: Synced `version` field from `1.7.18` to `1.7.23`

## [1.7.21] - 2026-03-22

### Fixed
- `readme.txt`: Reduced tags from 8 to 5 (WordPress.org enforces a maximum of 5)
- `readme.txt`: Shortened short description to 141 characters (WordPress.org maximum is 150)
- `readme.txt`: Updated `Requires at least` from 5.8 to 6.0 to match plugin header
- `cs-code-block.php`: Added `phpcs:ignore InputNotSanitized` on `$_POST['sql']` — validated via `is_safe_query()`, not a standard `sanitize_*()` call
- `cs-code-block.php`: Added `phpcs:ignore InputNotSanitized` on `$_POST['post_id']` reads in `ajax_preview()` and `ajax_migrate_single()` — sanitised via `(int)` cast
- `cs-convert.js`: Removed `onclick` attribute from JS-generated toast button; replaced with `addEventListener`
- `cs-code-block.js`: Added `.catch()` to `copyToClipboard()` promise chain — logs clipboard API rejection via `console.error()`
- `cs-admin-settings.js`: Added `console.error()` to settings save `.catch()` block

## [1.7.18] - 2026-03-13

### Security
- Hardened `is_safe_query()`: SQL queries containing semicolons are now rejected, preventing statement stacking
- Removed `$_REQUEST` fallback in SQL AJAX handler — only `$_POST` accepted
- Added `phpcs:ignore` annotations with rationale for all intentional `$wpdb` direct-query patterns

### Fixed
- Removed echoed `<style>` block from admin tools page — all styles now served via enqueued `cs-admin-tabs.css`
- Extracted inline `<script>` blocks from settings and SQL panels into enqueued JS files (`cs-admin-settings.js`, `cs-sql-editor.js`)
- Replaced dynamic `document.head.appendChild(style)` injection in block editor with `wp_add_inline_style()`
- Removed `console.warn()` and `console.log()` debug calls from `cs-convert.js`

### Added
- `uninstall.php` — removes `cs_code_default_theme` and `cs_code_theme_pair` options on plugin deletion
- `load_plugin_textdomain()` called on `init`; 48 user-facing strings wrapped with i18n functions across frontend and admin
- Full DocBlocks (`@since`, `@param`, `@return`) on all class methods and class definition
- `@package` and `@since` tags in plugin file header

### Changed
- `wp_ajax_cs_save_theme_setting` hook consolidated into `init()` alongside all other AJAX hooks
- `date()` replaced with `wp_date()` in migration scan to respect site timezone
- `block.json` version synced to plugin version

## [1.7.17]

### Added
- Copy button now shows a "Copy" label alongside the clipboard icon

### Changed
- CSS refactored for copy button styling

## [1.7.16]

### Fixed
- `build_migrate_block()` JSON encoding corrected: removed `JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES` flags that caused `<`, `>`, and quote characters to be stored as literal bytes, corrupting block attributes on subsequent Gutenberg saves

### Changed
- All enqueued assets now use `filemtime()` for cache busting
- Block editor toolbar improvements

## [1.7.15]

### Fixed
- Split `decode_migrated_content()` into two independent passes so the bare-`\n` newline fix always runs regardless of whether unicode escapes were already decoded in the database

## [1.7.14]

### Fixed
- `decode_migrated_content()` in `render_block()` decodes unicode escapes and bare newline separators left by the v1 migration bug, fixing display of affected code blocks without requiring database changes

## [1.7.13]

### Fixed
- Code Block Migrator now uses safe JSON encoding so special characters like `<`, `>`, and quotes are stored as proper unicode escapes in block comment attributes, preventing content corruption on subsequent Gutenberg saves

## [1.7.8]

### Added
- Copy, Paste, and Clear buttons to the block editor toolbar

## [1.7.6]

### Fixed
- White toolbar text for improved contrast
- UNDEFINED language badge no longer displayed
- Powered by CloudScale link added to block toolbar

## [1.7.3]

### Changed
- Admin CSS embedded inline for reliable rendering across all WordPress configurations
- Admin UI restyled to match the CloudScale plugin family: navy gradient banner, dark tab bar with orange active indicator, white card panels with coloured gradient section headers

## [1.7.0]

### Added
- 14 popular syntax colour themes: Atom One, GitHub, Monokai, Nord, Dracula, Tokyo Night, VS 2015/VS Code, Stack Overflow, Night Owl, Gruvbox, Solarized, Panda, Tomorrow Night, Shades of Purple
- Colour Theme selector in the settings panel
- HCL/Terraform and TOML to the language selector
- 14 new SQL quick queries organised into four groups: Health and Diagnostics, Content Summary, Bloat and Cleanup Checks, URL and Migration Helpers

### Changed
- Each theme loads its dark and light variant from the highlight.js CDN
- Toggle button switches between the dark and light variant of the chosen theme
- Frontend CSS refactored to use CSS custom properties for theme-agnostic styling
- Theme backgrounds and toolbar colours adapt automatically to the selected theme
- Enter key now runs the SQL query; Shift+Enter inserts a newline

## [1.6.0]

### Added
- Merged CloudScale SQL Command plugin into CloudScale Code Block
- Combined Tools page at Tools > CloudScale Code and SQL with tabbed interface
- AJAX save for theme settings (no page reload required)

### Removed
- Separate Settings > CloudScale Code Block page
- Separate Tools > CloudScale SQL page

## [1.5.0]

### Added
- Code Block Migrator tool to batch-convert legacy WordPress code blocks
- Auto-convert toast in the block editor for `core/code` and `core/preformatted` blocks
- Transform support from `core/code` and `core/preformatted`

## [1.1.0]

### Fixed
- Block now spans full content width in both editor and frontend
- Dark mode is now the proper default with Atom One Dark syntax colours
- Code no longer wraps; horizontal scroll on overflow
- Editor style properly registered via `block.json` `editorStyle`

### Added
- Alignment support (wide, full) in block toolbar

## [1.0.0]

### Added
- Initial release: Gutenberg block and `[cs_code]` shortcode for syntax-highlighted code
- Auto language detection for 30+ languages via highlight.js
- One-click clipboard copy button
- Dark/light mode toggle per block with site-wide default
- Language badge auto-detection
- Optional line numbers toggle
- Custom title/filename label per block
