== Typography Stylist — Full Changelog ==

The complete version history of Typography Stylist. Recent releases are also
summarized in readme.txt; release notes with downloads live on GitHub:
https://github.com/mattcowan/typography-stylist-for-wordpress/releases


== Changelog ==

= 2.2.2 =
* **NEW: Fit-to-width sizing.** The Typography Stylist block gains a third font-sizing mode alongside Inherit and Responsive: each line of the block (split on line breaks) is sized so its text spans the full block width — the classic wedding-invitation/poster look where a short line renders huge and a long line renders smaller, all flush to the same width. The editor measures each line with its real fonts, weights, letter spacing, and OpenType features (swashes and ligatures change widths) and stores per-line ratios; the frontend renders with CSS container-query units and stays zero-JavaScript. Lines never wrap in this mode, inline font sizes on selections are ignored (the block controls sizing), an optional maximum-size cap stops short lines growing enormous on wide screens, and browsers without container-query support fall back to the responsive clamp() sizes. Automatic optical sizing is disabled on fit lines — fonts with an opsz axis (like Fraunces) change glyph widths with the rendered size, which would break the measured fit; setting the optical-size axis to a fixed value with the variable-font sliders still works. Editing is fully WYSIWYG in a single view: each line renders at its own fitted size while you type — the poster layout stays live as you edit — and Quick Feature Toggle changes (line height, fonts, features) preview and land on selections at their true rendered sizes. Under the hood the editor feeds RichText a per-line-wrapped copy of the content while the stored markup stays flat, so selections, the native formatting toolbar, undo, and paste all keep working unchanged. Existing blocks are untouched: non-fit save output is byte-identical, with a save deprecation as a safety net.
* Fixed: variable-font axis sliders in the Quick Feature Toggles now change only the selected text instead of restyling the whole block. The axis panels read their starting values from the selection but wrote changes to the block-level attribute — selecting one line and moving a slider restyled every line. QFT axis changes now land on the selection as a styled span (like the other QFT controls: with the caret in styled text they update that span in place; with no styled text they still fall back to the block attribute), while the sidebar Inspector sliders intentionally remain block-level. "Reset to defaults" removes the axis settings from the selection the same way.
* Fixed: an axis change (or any extension-applied block property) no longer applies to every Typography Stylist block on the page. The property-application event had no targeting, so every mounted block handled it; it is now handled only by the block whose Quick Feature Toggles modal is open (or, for sidebar events, the selected block).
* Fixed: the variable-font axis panels now initialize from the selection inside the iframed editor canvas (WordPress 6.3+). They walked the top document's selection, which cannot see block content in the iframe; the host editor now hands them the selection's axis values directly.
* Fixed: fonts registered in the WP Font Library (WordPress 6.5+) no longer lose their webfont on the frontend. The plugin skipped its own @font-face for every registered font on the assumption that WordPress prints those faces — but WordPress only prints faces for fonts activated in global styles, so registered-but-unactivated fonts (including every auto-registered upload) silently rendered with a local or system fallback while the editor looked correct. The plugin now checks what WordPress will actually print (merged theme.json families) and keeps emitting its own @font-face whenever the family isn't there; activating the font in the Site Editor still hands printing over to WordPress with no double output.
* Improved: the "Detect Axes from Font File" server fallback now reports the actual failure reason instead of a generic error.
* Developer: font-variation-settings values arriving through the typost-apply-block-properties extension event are validated on every apply path (invalid values are treated as empty, never partially applied into a style string).
* Changed: bumped the Variable Fonts module version constant (1.3.1) so browsers pick up the updated module scripts.
* Improved: the Glyphs panel can now be repositioned by dragging its title bar, matching the Quick Feature Toggles modal — useful when the panel covers the text you're inserting into.
* Fixed: choosing an alternate glyph is now reversible — clicking the base glyph in the Glyphs panel's alternates view restores the plain character. Previously the base glyph was inserted as plain text that inherited the very alternate being removed (an ampersand swapped for its "and" alternate could never be swapped back), and because the caret collapsed after each insertion, every retry appended another copy instead of replacing. Alternates-view clicks now keep the inserted glyph selected so consecutive picks swap in place, and base-glyph clicks explicitly clear the alternate while keeping the surrounding font, weight, and spacing. Extensions get the same powers via a new `swap` flag on the `typost-insert-content` event (see HOOKS.md).
* Changed: bumped the Glyphs Panel module version constant (1.2.2) so browsers pick up the updated module scripts.
* Fixed: fonts uploaded together in one ZIP no longer share each other's variable-font axes. Every font family extracted from a kit points at the same kit directory, and axis detection scanned that whole directory — so each family was assigned the axes of whichever font file happened to parse first. A ZIP containing EB Garamond (weight axis only) and Fraunces (optical size, SOFT, WONK, weight) gave Fraunces a lone weight slider and hid its custom axes, and gave non-variable fonts in the same ZIP a phantom weight slider in place of their real weight dropdown. Detection is now scoped to the font files each family's own @font-face rules reference, with the file path confined to the kit directory (kit CSS arrives inside an uploaded ZIP, so it is untrusted input). Fonts uploaded on their own were never affected.
* Improved: "Detect Axes from Font File" is now the way to repair fonts whose axes were mis-detected before this fix. It gained a server-side fallback that re-reads uploaded fonts with the corrected detection, so it still works when the in-browser font parser is unavailable. The browser is tried first because it can read real axis names out of the font ("Softness" rather than "SOFT") and can decompress WOFF2, which PHP cannot. Re-detection returns the axes for review; nothing is stored until Save Changes.
* Added: the detect button now says up front that it replaces every axis row and discards hand-set axis names, ranges, and defaults, and asks for confirmation before overwriting axes that are already defined. Detecting axes for the first time is still a single click.
* Changed: variable-font axis sliders now sit directly beneath the weight control in the inline editor and the Quick Feature Toggles, matching the block sidebar. Font Style previously came between them, separating the axis sliders from the weight they extend.

= 2.2.0 =
* Fixed: converting a styled heading or paragraph to a Typography Stylist block no longer destroys inline styling. The inline editor's convert button rebuilt the block from plain text whenever the selection crossed styled-span boundaries — exactly the selections that surface the convert option — wiping per-letter glyph alternates, swashes, fonts, and weights; it now applies the popover's settings over the existing markup with every surrounding span preserved (and on any failure converts with the content untouched rather than ever rebuilding from text). The block-menu transform's feature-extraction path is now guarded the same way: features are only lifted to block level when the spans carry nothing else that stripping them would silently delete. Converted spans also use the modern font-ID format so frontend font loading works.
* **NEW: Font Style (visual italic) controls.** All three editing surfaces gain a Font Style setting — block-level in the Typography Stylist block sidebar, per-selection in its Quick Feature Toggles, and per-selection in the inline editor for regular heading and paragraph blocks — selecting the font's italic (or upright) face. This is deliberately style-only: it never adds emphasis semantics, and the control says so — for semantic emphasis that screen readers announce, use the editor's own Italic button, which continues to work as before. Ideal for display typography where italic is a design choice, not emphasis.
* Fixed: feature previews now render with the italic face when the selection is italic — whether via the editor's Italic button (em), the new Font Style setting, or an italic styled span. Previously previews always showed the roman face, hiding italic-only glyphs like EB Garamond's swash italic capitals.
* Improved: the Glyphs Panel now browses the face variant actually rendering at your selection. Select italic text (via the Italic button or the Font Style setting) and open the panel: it loads the font’s italic file — with its own glyph set and features, like swash italic capitals — and renders every cell in that face. No toggle needed; the selection decides.
* Fixed: moving one variable-font axis slider no longer changes other axes. The axis panels emitted every axis on any change — including untouched axes pinned to the font file's built-in defaults, which differ from normal rendering (Fraunces' built-in weight default is 900, so nudging its WONK slider turned text bold). Only axes the author has actually adjusted (or that were already applied to the text) are written into font-variation-settings; "Reset to defaults" now returns axes to natural rendering instead of pinning them.
* Fixed: the variable-font Weight slider in the Quick Feature Toggles now works — it identified its context with a selector that matched nothing, dispatched to the wrong editor, and was silently dropped. The weight slider and the custom-axes panel also now share one axis session, so weight and custom-axis adjustments combine instead of overwriting each other.
* Changed: bumped the Variable Fonts module version constant (1.3.0) so browsers pick up the updated module scripts.
* Fixed: Quick Feature Toggle changes always land on the selected text. The per-setting apply paths read the live editor selection, which the popover itself can collapse by taking focus — toggles then silently applied block-wide (or not at all) despite an active selection. All appliers, clear/reset actions, and the settings-detection now share one selection resolver that falls back to the selection captured when the popover opened.
* Fixed: applying a font or feature over a whole span no longer wipes glyph alternates chosen from the Glyphs Panel — the rebuilt font-feature-settings honors raw indexed alternate values (e.g. a 2nd stylistic alternate) instead of flattening them, in both the apply and the feature-removal paths.
* Fixed: changing the font of styled text now clears variable-font axis values carried over from the previous font (axis settings are font-specific) — in whole-span merges and partial-selection splits alike.
* Fixed: splitting a styled span (partial-selection changes) corrupted spans whose attributes or styles contain double quotes — variable-font axis values and glyph alternates — because attribute values were not escaped when rebuilding the markup.
* Changed: the 3-level limit on nested styled spans is now enforced on every application path — previously one fallback path could exceed it. Applying to a fully-selected span merges in place regardless of depth, so existing deeply-nested content remains editable.
* Developer: span styling internals consolidated — one canonical style-string parser/builder (parseStyleString/buildStyleString), one shared whole-span merge (mergeTypostSpanStyling), and one QFT selection resolver, replacing seven copy-paste variants (see todo/refactor-style-string-helpers.md).
* Fixed: font (and other single-value) changes over multi-span selections in the Typography Stylist block's quick toggles now actually take effect. Applying a font to a selection containing styled spans wrapped them in a new span whose font-family every inner span overrode — the change looked like it did nothing, and repeated attempts deepened the nesting. The wrapped property is now removed from descendant spans so the new value renders throughout (their other settings are untouched), applied feature tags merge into descendants that declare their own feature settings, and descendant spans left with nothing are unwrapped.
* Fixed: changing one setting over a mixed selection in the inline editor no longer wipes the others. Selecting text that contained differently-styled spans (different features, sizes, or fonts on parts of the selection) and then changing any single setting — font family, weight, size, spacing, line height, or a feature toggle — replaced the entire selection with one uniform span built from the popover's controls, destroying every per-part setting. The editor now detects mixed selections and applies only the changed property to each styled run: a font change re-fonts everything while each part keeps its own features and sizes, and a feature toggle adds to (or removes from) each part's own feature set. Uniform selections and presets behave as before.
* Fixed: feature previews in the inline editor now render in the selection's actual font. Spans written since v1.1.6 carry only a numeric font ID (no legacy data-font family name), which the preview resolution didn't consult — previews silently fell back to the block's theme font. Affected any span created by the Typography Stylist block's quick toggles or built programmatically, including the wp.org Live Preview demo headline.
* Fixed: inserting a glyph from the Glyphs Panel no longer loses the surrounding span's styling. Swapping a selected letter for a feature glyph replaced its typost span outright, dropping font size (fixed and responsive), letter spacing, and line height — the inserted letter landed at the default size. Insertion now merges the replaced span's styling into the new glyph's span (the glyph's own feature, font, and weight still win), and glyphs swapped at the very start of a span no longer inherit formatting from the text before the span.
* Improved: the Glyphs Panel now opens straight to the selected text's alternates. A selected letter pre-fills the "Alternates for character" box; a short combination (up to 4 characters, e.g. "Th") shows its exact ligature alternates, falling back to the first letter's alternates when the font has no such ligature. Longer selections still open the full glyph grid, and the "All glyphs" button returns to it at any time.
* Changed: bumped the Glyphs Panel module version constant (1.2.1) so browsers pick up the updated module scripts.

= 2.1.2 =
* **NEW: automatic font-weight detection.** Newly uploaded font kits and newly added Adobe Fonts get their "Available Font Weights" checkboxes pre-set to only the weights the font actually ships, instead of all nine weights being enabled by default. Uploaded kits read the weights from their parsed (or generated) @font-face rules; Adobe Fonts read them from the kit stylesheet, fetched server-side when the project is added. WordPress Font Library fonts adopted from the editor picker carry their real weights too. Variable fonts covering the full 100–900 range keep all weights enabled (the weight slider replaces the dropdown anyway). Detection only ever narrows when it is confident — if the stylesheet can't be fetched or a kit can't be read, all weights stay enabled — and the checkboxes remain fully editable.
* New: one-click "Auto-detect weights for existing fonts" button on the Custom Fonts tab. Shown only for fonts added before weight detection existed that were never manually configured; it processes uploaded and Adobe fonts in one pass and disappears once every font is covered. Manual font definitions are skipped — there is no font file to read.
* Fixed: the Glyphs Panel reported "No readable font file is available" for variable fonts uploaded as font-only ZIPs — the generated @font-face CSS declares `format('truetype-variations')`, which the panel's file picker didn't recognize. Variable-font format hints now normalize to their base format, so variable fonts glyph-browse like any other uploaded font.

= 2.1.1 =
* Packaging: re-release of the 2.1.0 feature set under a fresh version number. The 2.1.0 tag's downloadable ZIP was cached against stale contents and never delivered the new files (Variable Fonts core integration, font metadata/sources modules, WordPress Font Library integration); 2.1.1 ships them correctly. See the 2.1.0 entry below for the full list of changes included in this release.

= 2.1.0 =
* Fixed: deleting an uploaded font now also removes its WordPress Font Library registration — previously the wp_font_family post survived the delete, kept printing @font-face rules for font files that no longer existed, and made the font appear to still be installed. Removal is ownership-guarded: only families the plugin itself registered are ever touched.
* Fixed: fonts registered in the WordPress Font Library no longer appear twice on the Custom Fonts tab (once as an uploaded font card and again in the read-only WP Library rows). The uploaded card with its "In WP Library" badge is now the single listing; genuine Library fonts — including orphaned registrations from older versions — remain visible.
* Removed: the required "Font Kit Name" field from the Upload Font Kit form. The name was stored but never displayed anywhere — font cards show the family names read from the kit. The REST endpoint still accepts an optional `name` and defaults to the ZIP filename, so API callers keep working.
* **NEW: font-only ZIPs (no CSS) are now accepted by Upload Font Kit.** Uploading a ZIP that contains just font files — e.g. a Google Fonts download — no longer fails with "No CSS file found in the font kit". The plugin reads each font's built-in metadata (name, OS/2, and fvar tables for TTF, OTF, and WOFF files) and generates the @font-face stylesheet automatically: correct family names, weights, italics, and for variable fonts a font-weight range with the matching format('…-variations'). Generated kits flow through the existing pipeline unchanged, including variable-font axis detection, the Variable card badge, and the editor weight slider. WOFF2 metadata cannot be read server-side, so WOFF2-only ZIPs fall back to filename-based detection and the upload shows a "review the generated font styles" warning. Kits whose CSS files contain no @font-face rules get the same fallback.
* **NEW: WordPress Font Library integration (WP 6.5+).** Uploaded webfont kits can now be registered in the WordPress Font Library (Appearance → Editor): newly uploaded fonts register automatically (toggle in Options), and existing fonts can be registered per font or in bulk from the Custom Fonts tab — registration is opt-in and fully reversible. Registered fonts keep their numeric IDs: the plugin's `--font-N` CSS variables alias to WordPress's `--wp--preset--font-family--{slug}` presets with a literal fallback, so all existing content, inline spans, and extension integrations keep rendering forever, even if a font is later removed from the Library. WordPress serves the font files for registered fonts (no double-loading). Adobe Fonts and custom font definitions remain plugin-managed by design (Adobe fonts load from Adobe's servers and may not be self-hosted).
* **NEW: WordPress Font Library fonts in the editor font pickers.** Both the inline editor and the Typography Stylist block now offer Library fonts (theme fonts and fonts installed via Appearance → Editor) in a dedicated picker group. Picking one adopts it seamlessly — it gets a numeric font ID like every other source, so the save format and all extensions work unchanged.
* **NEW: Variable font support.** Automatic axis detection on upload, per-axis admin configuration, and axis sliders in the editor — weight, width, slant, optical size, and any custom axes a font defines.
* **NEW: `typost_force_enqueue_font_ids` filter** — themes and extensions can force specific fonts to load on every page (for fonts referenced only from theme CSS, invisible to the content scan).
* Improved: extension data saves on the font edit form no longer race the page reload (`typost:font-saved` now provides a `waitUntil()` collector).
* Fixed: the per-page font CSS cache key now includes the used font IDs, so pages using different fonts can no longer share stale cached CSS.
* Fixed: font CSS variables now load inside the iframed block editor canvas (WP 6.3+) even when no uploaded webfont kits exist — Adobe Fonts, custom font definitions, and Font Library fonts previously fell back to the system font in the editor while rendering correctly on the frontend.
* Improved: the Glyphs Panel now distinguishes missing or failed parsing-library loads from genuinely unreadable fonts, shows honest error messages with technical detail, and offers a "Try again" button that retries without reloading the page.
* **NEW: "Detect Axes from Font File" button** — each font's Variable Font settings can now read the axis definitions (tag, name, min/max/default) straight from the font binary in your browser, instead of typing them by hand. Works for uploaded kits, Adobe Fonts, and custom font definitions, including WOFF2 files that upload-time detection can't parse. Detected axes fill the form for review; nothing is stored until you save.
* Improved: variable fonts without a weight (`wght`) axis no longer show the standard Font Weight dropdown in the editors — the variable axis sliders take its place (matching the per-font "Hide weight selection" admin setting, which previously only affected the admin form).
* Fixed: the "Variable Font Axes" section in the inline editor pop-up now has the same left/right padding as the other sections.
* Developer: the `typost_weight_control` JS filter recognizes a new `'hidden'` return value (suppress the weight control entirely), and the `typost_qft_after_font_controls` hook state now includes `inlineFontFamilyAtSelection` — see HOOKS.md.
* Fixed: extension panels rendered into font-dependent hook points (e.g. the Variable Font axis sliders) no longer go stale when the font is changed — the hook containers now remount with fresh state on font switch instead of keeping the previous font's controls.
* Improved: Variable Font quick-select buttons for custom axes now snap to round values (200, 400, 600 instead of 201, 401, 601) and are capped at 7 buttons so they fit on a single row; near-duplicate values next to the axis default are no longer generated.
* Added: variable font axes are now detected automatically when fonts are added — both webfont kit ZIP uploads and Adobe Fonts kits. Each family in a kit is checked individually, so kits mixing variable and static fonts work correctly; static families are simply left untouched.
* Fixed: axis detection (and glyph loading) for Adobe Fonts kits containing multiple families could resolve the wrong family's font file — per-family entries store a single family name, which the font loader now honors.
* Developer: new `typost:fonts-added` jQuery admin event fires after a kit upload or Adobe Fonts add, with the new entries and a `waitUntil()` collector so extensions can post-process fonts before the page reloads — see HOOKS.md.
* Fixed: a variable font with a weight (wght) axis but "Hide weight selection" unchecked showed the weight slider until the first edit, then inconsistently swapped to the weight dropdown. The unchecked setting now consistently keeps the standard weight dropdown (the wght slider is skipped); other variable axes still show in their own panel.
* Changed: "Hide weight selection" now defaults to checked for every variable font — when a weight (wght) axis exists the slider replaces the weight dropdown, and without one the weight is fixed by the font file, so the discrete weight UI is hidden either way. An explicit admin toggle still wins. Previously the auto rule only hid weights for variable fonts without a wght axis, leaving the redundant weight controls visible for exactly the fonts that least need them.
* Changed: bumped the Variable Fonts (1.2.1) and Glyphs Panel (1.1.2) module version constants so browsers pick up the updated module scripts (these files ship unminified and are cache-busted only by those constants).
* Accessibility: the Variable Fonts axis Tag and Name inputs on the settings page now have accessible labels (fixes 10 "missing form label" WAVE errors).
* Accessibility: color-contrast audit of all admin color schemes. Alice Blue's primary and muted-text colors were darkened to meet WCAG AA 4.5:1 on every panel background (feature code badges, size values, descriptions, visibility labels); the Dark scheme's badge text and danger color were corrected; High Contrast's danger red was darkened; and the Admin Colors scheme now automatically darkens colors derived from the WordPress admin palette until they meet 4.5:1.
* Accessibility: fixed heading hierarchy on the settings page — font card names are now h3 (previously h4 directly under the tab's h2).
* Changed: the read-only Variable Fonts admin tab was removed. Variable fonts are now marked with a "Variable" pill on their font cards (hover it to see the configured axis tags), alongside the existing source badges — the same information, in context. Axes are still managed in each font's edit form.
* Developer: new `typost_font_card_badges` PHP filter lets extensions append badges to font card headers on the Custom Fonts tab — see HOOKS.md.
* Improved: WP Font Library cards now render the font name in its own typeface (when font files are registered; @font-face CSS is printed via wp_print_font_faces on WP 6.4+), and the font-family code chip no longer touches the "Manage in Editor" button. The chip also follows the admin color scheme instead of hardcoded grays.
* Changed: the Quick Feature Toggles popover now shows the same two-line usage tips notice as the inline popover (drag-to-reposition + instant-apply/undo) and shares its dismissal — closing the notice in either popover hides it in both, remembered per browser.
* Changed: the "i" icon tooltips in the block sidebar and inline popover were replaced with plain help text (matching the line-height controls) or removed. The Font Family tip claiming "fonts only load on pages where they are used" was removed as inaccurate for WordPress Font Library fonts, which WordPress loads site-wide; the Font Size clamp() explanation now appears as help text when Responsive mode is selected; the OpenType overview is now a regular note at the top of the features panel.
* Removed: the required "Project Name" field from the Add Adobe Fonts Project form — since kits create one entry per family (named by the family), the project name was stored but never displayed anywhere.
* Fixed: the Glyphs button in the inline Typography Stylist popover now aligns with the section headings instead of sitting flush against the popover edge.
* Changed: the collapsible Tips list at the bottom of the inline popover was removed; its one non-obvious tip ("Changes apply instantly, press Ctrl+Z to undo") joined the drag-to-reposition tip in the notice at the top of the panel. The notice is now dismissible, and the dismissal is remembered per browser. The other tips duplicated information available elsewhere.
* Fixed: when a kit contains several variable fonts, the automatic axis detection could silently lose the first font's result — the per-font saves ran concurrently against a REST endpoint that does a read-modify-write on a shared option, so the earliest write was overwritten by the others. Axis saves are now serialized, so every detected font's axes persist.
* Developer: new block attribute `animationConfigId` + inline `data-animation-id` attribute as integration points for the upcoming Animations extension; font subsystem partially extracted into `includes/` modules (public extension API unchanged).

= 2.0.1 =
* Fixed: Mixed-content blocking of locally-hosted fonts in the Glyphs Panel — same-host `http://` font file URLs are now upgraded to `https://` before fetching, so fonts whose stored kit CSS contains absolute insecure URLs load correctly on HTTPS sites (cross-origin URLs are left untouched)

= 2.0.0 =
* **NEW: Glyphs Panel (built into core) — the flagship feature of 2.0.** An Illustrator-style full-font glyph browser. Explore every character and OpenType feature in a font; search by character, U+ codepoint, or glyph name; filter by Unicode block, stylistic set, or OpenType feature; and view all alternates for a single character. Click or press Enter to insert any glyph (including indexed feature alternates) directly into your content via a "Glyphs…" button in the inline rich-text toolbar (any heading or paragraph), in the Typography Stylist block's Quick Feature Toggles, or from a dedicated "Glyphs" admin tab (browse + copy to clipboard); closing the panel returns you to the editor popover you launched it from. Accessible by design: the glyph grid is a fully keyboard-navigable ARIA grid (arrow keys, Home/End, Page Up/Down, Enter to insert) with row/column semantics, and insertions and result counts are announced to screen readers — inserted glyphs use the real Unicode character plus CSS font-feature-settings, so assistive technology always reads the underlying text. Works with uploaded webfont kits, Adobe Fonts, custom font definitions, and WordPress Font Library fonts; font files are read in your browser, on demand, for metadata only — no glyph outlines are ever extracted or stored, and nothing font-derived is written to your server, making sure you respect font EULAs.
* **MAJOR CHANGE:** Inline text editor (richtext toolbar button) now uses live preview instead of Apply button paradigm - changes are auto-applied immediately with debouncing (matching the Typography Stylist block UX)
* **NEW: Extensibility hook system** - Comprehensive PHP and JavaScript hooks enabling third-party extensions via standalone WordPress plugins
* **NEW: Admin tab extensibility** - Data-driven admin settings tabs with filter-based registration for extensions to add their own configuration tabs
* **NEW: JavaScript hook system** (`window.typostHooks`) - Lightweight action/filter system for both the inline editor and Typography Stylist block, with container-based hook points for rendering extension UI
* **NEW: Per-font OpenType feature visibility** - Configure which of the 51 OpenType features appear in the editor on a per-font basis; defaults to all features visible for full backward compatibility
* **NEW: Unified font list** - All font sources (uploaded kits, Adobe Fonts, custom definitions, WP Font Library) now appear in a single organized list with color-coded type badges instead of three separate sections
* **NEW: Drag-to-reorder fonts** - Drag fonts up and down the list to control the order they appear in editor dropdowns; order is persisted via the REST API
* **NEW: WordPress Font Library integration** - Fonts registered through the WordPress Font Library (WP 6.5+) now appear in the Custom Fonts admin list as read-only entries with a link to manage them in the Appearance Editor; gracefully absent on older WordPress versions
* **NEW: Font name preview** - Font names in the Custom Fonts admin list now render in their actual typeface using CSS variables, making it easy to identify fonts at a glance
* **NEW: Card width slider** - Adjustable preview card width (280–800px) in the Font Features tab, persisted per-browser via localStorage
* **NEW: Contextual help panels** - Collapsible help panels added to each admin tab (Custom Fonts, Font Features, Options, Accessibility, Replacement Fonts) explaining what each section does and how to use it
* **NEW: Block editor Help & Tips panel** - A collapsible "Help & Tips" inspector panel in the Typography Stylist block explains when to use block vs. inline styling, accessibility features, and font selection guidance
* **NEW: Contextual tooltips** - Info tooltips on key block editor controls (font family, font weight, font size, letter spacing, line height, OpenType features) using WCAG-compliant `<Tooltip>` + `<Button>` pattern; keyboard focusable with screen reader support
* Added: `typost_editor_data` filter for extensions to add data to the block editor
* Added: `typost_editor_assets` action for extensions to enqueue editor scripts
* Added: `typost_admin_tabs` filter for registering custom admin settings tabs
* Added: `typost_admin_localize_data` filter for extensions to add admin page data
* Added: `typost_admin_assets` action for extensions to enqueue admin scripts/styles
* Added: `typost_register_rest_routes` action for extensions to register REST API endpoints
* Added: `typost_available_features` filter for modifying the available OpenType features list
* Added: `typost_presets` filter (replacing legacy `typost_default_presets`) for modifying the combined presets list
* Added: `typost_cache_clear` action for extensions to clear their caches when core clears
* Added: `typost_font_uploaded` and `typost_font_deleted` actions for font lifecycle events
* Added: `typost_admin_tab_content_{id}` and `typost_admin_tab_after_{id}` actions for admin tab content
* Added: 5 inline editor hook points, 4 Quick Feature Toggle hook points, 3 Inspector Controls hook points
* Added: State communication pattern via `typost_current_editor_state` filter and `typost-apply-block-properties` CustomEvent
* Added: HOOKS.md developer documentation with vanilla DOM and React extension examples
* Added: Blueprint specification for the Variable Font Axes extension
* Added: REST endpoints for font feature visibility (`GET/POST /typost/v1/font-feature-visibility/{font_id}`) and font order (`GET/POST /typost/v1/font-order`)
* Added: `filterFeaturesByVisibility()` utility function (exported from utils.js and exposed via `window.typostSharedUtils`) for filtering features based on per-font visibility settings
* Fixed: Editor nonce was incorrectly cached in transient (nonces are session-specific and must always be fresh)
* Fixed: Help tab section headers now use the primary text color instead of the accent color, fixing low contrast in the Alice Blue admin color scheme (WCAG-compliant across all schemes)
* Fixed: REST API namespace in bundled documentation corrected to the canonical `/wp-json/typost/v1/`
* Removed: Apply button from inline editor toolbar
* Removed: "Apply Anyway" and "Discard Changes" buttons from the word boundary accessibility warning workflow — these warning-specific actions are now obsolete because the warning is non-blocking and changes apply immediately via live preview
* Removed: Internal undo system (Undo button) - now relies on native WordPress undo (Ctrl+Z)
* Removed: Redundant preview panel with device toggles - live preview on actual selected text makes it unnecessary
* Removed: Separate Uploaded Fonts, Adobe Fonts, and Custom Font Definitions sections — replaced by unified font list
* Changed: Word boundary accessibility warning is now a persistent, non-blocking informational notice at top of modal instead of blocking application; it remains visible while editing but does not prevent changes and can effectively be dismissed by proceeding with edits or converting to a Typography Stylist block
* Changed: Users can still choose to convert to a Typography Stylist block for improved accessibility when needed, but this is now an optional follow-up action rather than a requirement to proceed
* Changed: Admin settings tabs are now data-driven with priority-based ordering (supports URL deep-linking via `?tab=` parameter)
* Changed: Add Font forms (upload kit, Adobe Fonts, custom definition) are now grouped in a collapsible accordion section beneath the font list
* Changed: Feature visibility is editor-UI-only — already-applied features in saved content continue to render correctly regardless of visibility settings
* Improved: Inline editor now matches Typography Stylist block UX with consistent debounce timings: Features (instant), Sliders (400ms), Dropdowns (300ms), Responsive Font-Size (600ms)
* Improved: User can still manage accessibility settings in Settings → Typography Stylist → Accessibility
* Improved: Font Features tab preview selector now includes WP Font Library fonts (when available) alongside uploaded, Adobe, and custom fonts
* Improved: Feature visibility changes auto-save on toggle with a brief "Saved" confirmation — no Save button needed
* Improved: Per-font feature visibility includes master "Enable All" / "Disable All" controls both on the Font Features tab and inside each font's edit form
* Improved: Glyphs Panel toolbar controls (Alternates, Search, OpenType feature, Unicode block) now show visible labels
* Improved: Glyphs Panel default "All glyphs" view also lists OpenType feature variants (e.g. stylistic alternates) previously reachable only by filtering or typing a character
* Note: Each debounced change creates its own undo step in WordPress undo history - use Ctrl+Z to undo individual changes (more granular than previous single Apply button undo)
* Note: WP Font Library fonts appear in the admin list as read-only; font order and feature visibility settings for WP Library fonts are not yet supported in this release

= 1.2.2 =
* Added: Re-introduced "Apply Anyway" button in the word boundary accessibility warning when applying features to partial words in core blocks, giving users the choice to proceed despite potential screen reader fragmentation
* Added: Smart conversion detection - the "Convert to Typography Stylist Block" button is automatically hidden when conversion is not possible (e.g., inside a locked pattern), with an adjusted warning message
* Added: Safety fallback - if block conversion fails despite the pre-check, features are applied directly with a snackbar notice informing the user
* Added: "Disable Word Boundary Warning" option in Settings → Typography Stylist → Accessibility to skip the partial word warning entirely
* Added: "Manage this setting" link in the warning message that deep-links to the admin accessibility settings page, auto-switching to the Accessibility tab and highlighting the relevant setting
* Fixed: Nonce mismatch in Accessibility and Options settings forms caused "The link you followed has expired" error when saving - the nonce names in wp_nonce_field() and check_admin_referer() did not match

= 1.2.1 =
* Added: Per-font weight restrictions - configure which font weights are available for each font in the admin panel (Settings → Typography Stylist → Custom Fonts). Fonts default to all weights for variable font compatibility
* Added: Single-weight auto-apply - when a font has only one available weight, the weight selector is hidden and the weight is automatically applied
* Added: Weight validation on font change - switching fonts automatically adjusts the weight to the closest available option
* Fixed: CSS variable trailing comma caused fonts without fallbacks to fail loading on both frontend and block editor (e.g. `--font-20: "EsmeraldaPro", ;` produced invalid CSS)
* Fixed: Line breaks (Shift+Enter) in Typography Stylist blocks caused words to run together in screen reader text (e.g. "MILANOCORTINA" instead of "MILANO CORTINA")
* Fixed: Inline editor modal lost font selection state on close/reopen - selecting a font, closing the modal without applying, then reopening and clicking Apply would silently fail because stale state caused the apply logic to enter the wrong code path
* Fixed: Missing data-lineheight attribute in format type registration - line-height values were silently dropped when reading back existing formatted content
* Improved: Apply notice in the inline editor now includes a "Convert to a Typography Stylist block" link, guiding users toward the block type that supports real-time preview
* Changed: "Cancel" button renamed to "Discard Changes" in accessibility warning for clearer intent
* Changed: "Edit Fallbacks" button renamed to "Edit Settings" in admin font management to reflect expanded functionality
* Improved: OpenType feature previews now show cumulative checked features - toggling a stylistic set updates ALL preview windows to include that feature, accurately showing how features combine (essential for fonts like Bookmania where stylistic sets interact to produce different glyphs)

= 1.2.0 =
* Fixed: Inline styles applied to wrong character when content contains line breaks (Shift+Enter) - styling the "M" on a second line would incorrectly style the "I" instead, off by one character per line break
* Fixed: TreeWalker document context bug - TreeWalkers are now created from the correct document object (DOMParser), preventing cross-context errors
* Fixed: Responsive font-size Reset button now removes all related attributes (data-fontsize-min, data-fontsize-preferred, data-fontsize-max) instead of leaving orphaned attributes
* Fixed: Memory leak in debounced auto-apply functions - cleanup handlers now properly cancel pending debounced calls on component unmount
* Fixed: Preview span removal now preserves nested elements instead of flattening to text, maintaining complex formatting structure
* Fixed: Stale closure bug in auto-apply functions - debounced wrappers now call latest version of apply functions via refs, resolving issue where controls wouldn't work when styles were already applied
* Improved: Quick Features Toggle auto-apply - letter spacing, line height, font family, font weight, and font size now apply automatically with debouncing (400ms for sliders, 300ms for dropdowns, 600ms for responsive font-size)
* Improved: Consistent UX across all Quick Features controls - all controls now auto-apply like OpenType features, no more confusion about which controls need Apply buttons
* Improved: Clear/Reset buttons now actually remove properties from content instead of just resetting state - clicking Reset removes the data attribute and CSS property from spans
* Improved: UI reorganization - Active Features section moved above feature panels for better visibility
* Added: Individual Reset buttons for font family, font weight, and font size with undo icons for clear visual feedback
* Added: `buildTextOffsetMap()` utility that accounts for `<br>` elements in character offset calculations, matching WordPress RichText's offset system
* Added: `getEffectiveTextLength()` utility for accurate text length measurement including line breaks
* Added: `debounce()` utility function with cancel method for performance optimization during rapid slider adjustments
* Added: `removePropertyFromSpan()` utility to remove specific properties and unwrap empty spans
* Added: `removePropertyFromSelection()` utility to find and remove properties from all spans in selection
* Added: Comprehensive test suite with 24 tests for property removal utilities, including edge cases for responsive font-size
* Improved: All 12 TreeWalker-based offset calculations across the inline editor, Typography Stylist block, and shared utilities now correctly handle multi-line content
* Technical: Extracted `classifyAtomicNode()` helper within `splitSpanAndApply` to reduce code duplication in segment classification logic
* Technical: Debounced functions use refs to avoid stale closures and maintain access to current state across renders

= 1.1.9 =
* Fixed: Archive page font loading - fonts now load correctly and more consistently on blog home, category pages, tag pages, and all archive types
* Fixed: WordPress hook timing issue - font detection now runs on `template_redirect` hook (after main query) instead of `wp_enqueue_scripts` (before query) for archive pages
* Added: Manual cache clear button in Settings → Typography Stylist → Options tab for troubleshooting font loading issues
* Added: Admin setting to control archive page full content checking (enabled by default)
* Improved: Singular pages (posts, pages) continue using optimized detection path without changes
* Improved: Cache clearing when options are changed to ensure settings take effect immediately
* Improved: Font detection caches now automatically clear when posts or pages are saved, so typography changes appear on the frontend immediately
* Updated: Filter `typost_check_full_content_on_archives` now defaults to true (was false)
* Technical: Font detection results cached in instance variables to avoid redundant queries
* Note: Existing sites will automatically benefit from improved archive page font loading

= 1.1.8 =
* Improved: Windows Narrator focus enhancement - screen reader accessible headings now display a visible focus outline that corresponds to the full styled headline area, making it easier to identify which heading is being read

= 1.1.7 =
* Improved: Screen reader elements maintain full-size dimensions while remaining invisible, using modern clip-path technique with backwards compatibility for legacy browsers
* Added: High contrast mode support for Windows users with enhanced outline visibility (4px outline with system Highlight color)
* Added: Dark mode support with adjusted outline colors for better visibility on dark backgrounds
* Added: pointer-events management to prevent invisible overlay from blocking interactions with styled text when not focused


= 1.1.6 =
* Improved: Standardized control order across all interfaces for better consistency. Reordered controls to: Font Family → Font Weight → Font Size → Line Height → Letter Spacing → OpenType Features.
* Fixed: Font size persistence bug where changes wouldn't persist after closing Quick Features Toggle popover
* Fixed: All inline controls (font weight, font family, font size, letter spacing, line height) now correctly apply only to selected text instead of entire block (sporadic errors before)
* Fixed: Sequential feature application bug where applying multiple inline features would incorrectly affect entire block
* Fixed: State management issue where inline control values wouldn't reset after successful apply
* Fixed: Inline fonts (applied via Quick Feature Toggles) now load correctly on frontend
* Fixed: Font detection now properly extracts inline fonts from Typography Stylist block content HTML
* Fixed: Quick Feature Toggle preview now displays in correct inline font instead of block-level font
* Fixed: OpenType features now apply only to selected text, not entire span when selecting partial text within existing styled spans
* Fixed: Font-feature-settings CSS now preserved when applying other inline styles (line-height, letter-spacing) to text with existing OpenType features
* Fixed: Nested span handling - applying features to partial selections within styled text now creates proper nested or split spans instead of merging incorrectly
* Fixed: Block-level fonts no longer incorrectly included in unrelated inline operations
* Fixed: Line-height and letter-spacing controls no longer pass incorrect empty data-features attributes that interfered with attribute preservation
* Improved: Inline fonts now use CSS variable system (var(--font-ID)) matching block-level architecture for consistent font loading and replacement
* Improved: Enhanced attribute preservation system to prevent style conflicts during sequential inline edits while properly handling font-family overrides
* Improved: Added comprehensive validation and fallback mechanisms for all inline text styling functions
* Improved: Inline state variables now reset after successful apply to prevent UI/content desync
* Improved: Font override logic - applying new inline font to text with existing font now properly replaces old font instead of preserving it
* Added: parseInlineFontFamilyAtCursor() utility for detecting inline fonts at cursor position
* Added: Memoized inline font detection for improved preview performance
* Developer: extract_fonts_from_blocks() enhanced to parse inline HTML content for data-font-id attributes

= 1.1.5 =
* Added: Line-height controls for block-level and inline text styling
* Added: Line-height control in Typography Stylist block inspector panel
* Added: Line-height control in Quick Features Toggle popover for inline selections
* Added: Line-height control in inline editor toolbar for standard heading/paragraph blocks
* Improved: Line-height can be adjusted from 0.5 to 3.0 with 0.1 step increments
* Improved: Responsive font size controls now operate independently without auto-adjusting other values
* Improved: Responsive font size labels now clearly indicate screen sizes (Mobile, Intermediate, Large)
* Improved: Visual warning displayed when responsive font sizes are out of logical order
* Improved: Default responsive font sizes for new blocks changed to 16/32/64 for more dramatic scaling
* Fixed: Confusing slider behavior where adjusting one size would move other sliders
* Developer: Breakpoint values (320px, 1920px) extracted to named constants (RESPONSIVE_FONT_MIN_VIEWPORT, RESPONSIVE_FONT_MAX_VIEWPORT) for future configurability across Typography Stylist block and inline editor

= 1.1.4 =
* Fixed: Mixed content warnings on HTTPS sites when loading custom fonts
* Improved: Font URLs now use relative paths for protocol-agnostic loading
* Improved: Legacy fonts with absolute URLs are automatically converted at render time

= 1.1.3 =
* Initial release approved for public distribution.
* Typography Stylist Block with ARIA markup and semantic HTML
* Smart selection validation warns when partial word selections could fragment text
* Conversion tool from inline formats to accessible block structure
* Configurable aria-label support for inline formatted text
* Screen reader class options (visually-hidden, sr-only, or custom classes)
* Accessibility documentation
* Upload custom font kits from MyFonts, Fontspring, and other webfont providers
* Adobe Fonts (Typekit) integration via embed code
* Define fonts loaded through themes, plugins, or CDN services
* Font fallback system
* Secure font file storage with .htaccess protection
* Font preview system with size controls
* OpenType feature support: ligatures (liga, dlig, calt)
* Stylistic sets (ss01-ss20)
* Swashes (swsh, cswh) and alternates (salt, titl, ornm)
* Quick-apply presets for common typography styles
* Custom preset creation and saving
* Inline text selection in the block editor
* Live preview before applying changes
* Popover interface with features organized by category
* Spanish (es_ES) and French (fr_FR) translations
* Native CSS font-feature-settings
* WordPress block editor (Gutenberg) API integration
* REST API for plugin features
* JSX/React architecture for the custom block
* WordPress @wordpress/scripts build toolchain
* Transient caching
* Rate-limited REST API endpoints (50 requests/minute per user)
