/*
Theme Name:  Photo Image Editor
Theme URI:   https://photo-image-editor.com
Description: A fully local, privacy-first browser-based image editor. No server uploads. Plugin-extensible tool panels.
Version:     7.53
Author:      Custom
Author URI:  https://photo-image-editor.com
License:     GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: photo-image-editor
Tags:        custom-menu, editor, image, responsive-layout, accessibility-ready
*/

/* Google Fonts is loaded once, via functions.php's pie-google-fonts
   handle (which already covers Syne + DM Mono, plus the extra Noto
   Sans families needed for other languages). An @import here used to
   duplicate that same request — @import is also always render-blocking
   and can't be deferred, so it's been removed rather than fixed. */

/* ──────────────────────────────────────────────────────────
   CSS CUSTOM PROPERTIES
────────────────────────────────────────────────────────── */
:root {
    --nav-bg:        #0f1117;
    --nav-surface:   #161b27;
    --nav-border:    #1e2535;
    --panel-bg:      #1a1614;
    --panel-surface: #221e1b;
    --panel-border:  #2e2820;
    --ws-bg:         #111010;
    --header-bg:     #0a0c12;
    --text:          #e6e4f0;
    --text-dim:      #9d9db8;
    --text-dimmer:   #55557a;
    --nav-idle:      #ffffff;
    --accent:        #6c63ff;
    --accent-glow:   rgba(108,99,255,.22);
    --warn:          #fbbf24;
    --danger:        #f87171;
    --r:  12px;
    --rs:  8px;
    --tr: .2s cubic-bezier(.4,0,.2,1);
    --canvas-max-w: clamp(205px, 35.2vw, 896px);
    --canvas-max-h: clamp(253px, 57.5vh, 920px);
    --sidebar-w:    220px;
    --header-h:     106px; /* approx: top-row + toolbar */
}

body.light {
    --nav-bg:        #eef2ff;
    --nav-surface:   #ffffff;
    --nav-border:    #cbd5e1;
    --panel-bg:      #f8fafc;
    --panel-surface: #ffffff;
    --panel-border:  #e2e8f0;
    --ws-bg:         #f1f5f9;
    --header-bg:     #ffffff;
    --text:          #0f172a;
    --text-dim:      #475569;
    --text-dimmer:   #94a3b8;
    --nav-idle:      #000000;
    --accent:        #6366f1;
}

/* ──────────────────────────────────────────────────────────
   RESET & BASE
────────────────────────────────────────────────────────── */
*,*::before,*::after { margin:0; padding:0; box-sizing:border-box; }
@media (prefers-reduced-motion:reduce){
    *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ──────────────────────────────────────────────────────────
   SKIP LINK & HELPERS
────────────────────────────────────────────────────────── */
.skip-link{
    position:absolute;left:-9999px;top:4px;z-index:9999;
    background:var(--accent);color:#fff;padding:8px 16px;
    border-radius:4px;font-family:'Syne',sans-serif;font-weight:700;
    font-size:.9rem;text-decoration:none;
}
.skip-link:focus{left:8px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ──────────────────────────────────────────────────────────
   BODY & SHELL
────────────────────────────────────────────────────────── */
body{
    font-family:'Syne',sans-serif;
    background:var(--ws-bg);
    color:var(--text);
    min-height:100vh;
    overflow-x:hidden;
    transition:background .25s,color .2s;
}
.main-container{
    max-width:1600px;
    width:100%;
    margin:0 auto;
    display:flex;
    flex-direction:column;
    min-height:100vh;
}
:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
::selection{background:var(--accent);color:#fff}

/* ──────────────────────────────────────────────────────────
   SVG RESETS
────────────────────────────────────────────────────────── */
button svg:not(.nav-cat-sparkles):not(.nav-cat-wrench):not(.pie-icon-letter-a):not(.pie-textedit-add-btn-icon):not(.pie-textedit-tab-btn-icon),.toolbar-btn svg,.download-btn svg{
    fill:none!important;fill-opacity:0!important;background:transparent!important
}
/* The Effects category icon (three colored sparkle bursts) is drawn
   entirely with per-path `fill`, not `stroke` — the blanket
   `button svg{fill:none}` reset above was silently making it fully
   invisible (a filled shape with fill:none has no visible pixels).
   The Image Text Editor's "A" glyph icons are the same case: an SVG
   <text> filled with currentColor, not an outline path. */
.nav-cat-sparkles path{fill-opacity:1!important}
.toolbar-btn svg{width:16px;height:16px;stroke:currentColor;stroke-width:3;overflow:visible;flex-shrink:0}
.zoom-strip  svg{width:16px;height:16px;stroke:var(--accent);stroke-width:2.5}

/* ──────────────────────────────────────────────────────────
   HEADER
────────────────────────────────────────────────────────── */
header{
    background:var(--header-bg);
    border-bottom:3px solid var(--accent);
    position:sticky;
    top:0;
    z-index:200;
    display:flex;
    flex-direction:column;
}

/* Top row */
.header-top{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:14px;
    padding:10px 20px 5px;
    flex-wrap:wrap;
    /* No max-height/overflow clip here: at high zoom this row can wrap
       onto a second line, and clipping it used to hide/crush those
       buttons right at the seam with .header-bottom below. The header's
       real rendered height is kept in sync via JS (initHeaderHeight in
       app-theme.js), so letting this row grow as needed is safe. */
}
.header-left{display:flex;align-items:center;gap:12px;flex-shrink:0}

/* ─── LOGO — always visible regardless of gradient support ─── */
.site-logo{
    display:inline-flex;
    align-items:center;
    gap:10px;
    text-decoration:none;
    line-height:1.5;
    overflow:visible;
}
.logo-mark{
    display:flex;align-items:center;justify-content:center;
    width:34px;height:34px;
    background:linear-gradient(135deg,#6c63ff,#c084fc);
    border-radius:8px;
    flex-shrink:0;
}
.logo-mark svg{width:18px;height:18px;stroke:#fff!important;fill:none!important;stroke-width:2!important}
.logo-text{
    /* System font stack, not the 'Syne' webfont: renders instantly with
       no network request/FOUT swap, and sidesteps a glyph-rendering bug
       in Syne's bold weight that was clipping the bottom of some letters
       (e.g. "G"). Each OS's own UI font is well-hinted and reliable. */
    font-family:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
    font-size:1.8rem;
    line-height:1.3;
    display:inline-block;
    padding:.05em 0 .15em;
    overflow:visible;
    font-weight:800;
    letter-spacing:normal;
    color:var(--accent);
}
/* Force solid in forced-colors / high-contrast mode */
@media (forced-colors:active){
    .logo-text{-webkit-text-fill-color:LinkText;color:LinkText;background:none}
}

/* Theme toggle */
.theme-toggle{
    background:var(--nav-surface);
    border:2px solid var(--accent);
    border-radius:30px;
    width:36px;height:36px;
    display:flex;align-items:center;justify-content:center;
    cursor:pointer;transition:var(--tr);flex-shrink:0;
}
.theme-toggle svg{width:18px;height:18px;fill:none}

/* ── Round icon-only buttons — same shape/size as the theme toggle.
   Home/Search/Language stay borderless-fill (background matches the
   surrounding header, only the outline shows) — Reset/Undo/Redo/
   Delete each get their own solid fill color instead. */
.icon-btn{
    background:transparent;
    border:2px solid var(--accent);
    border-radius:30px;
    width:36px;height:36px;
    display:flex;align-items:center;justify-content:center;
    cursor:pointer;transition:var(--tr);flex-shrink:0;
    color:var(--text);text-decoration:none;
    padding:0;font-family:inherit;
}
.icon-btn.blog-btn{
    width:auto;padding:0 16px;
    font-family:'Syne',sans-serif;font-size:.85rem;font-weight:700;
    white-space:nowrap;
}
.icon-btn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;overflow:visible}
/* Hover on any enabled button — unchanged: brighter, site-accent color. */
.icon-btn:hover:not(:disabled){background:#7c75ff;border-color:#7c75ff;color:#fff}
.icon-btn:disabled{opacity:.5;cursor:not-allowed;background:transparent;color:var(--text-dim);border-color:var(--nav-border)}

/* Reset/Undo/Redo/Delete — solid fill identifies each at rest;
   :active (pressed) brightens that same color instead of switching
   to the shared hover color above. */
.icon-btn.reset{background:#3a3f4b;border-color:#3a3f4b;color:#fff}
.icon-btn.reset:active{background:#565c6b;border-color:#565c6b}
.icon-btn.undo{background:#a855f7;border-color:#a855f7;color:#fff}
.icon-btn.undo:active{background:#c084fc;border-color:#c084fc}
.icon-btn.redo{background:#f59e0b;border-color:#f59e0b;color:#fff}
.icon-btn.redo:active{background:#fbbf24;border-color:#fbbf24}
.icon-btn.trash{background:#ef4444;border-color:#ef4444;color:#fff}
.icon-btn.trash:active{background:#f87171;border-color:#f87171}

/* Language trigger — flag doubles as the icon; hide the name + chevron
   that used to sit next to it in the old pill-shaped button. */
.icon-btn.lang-trigger{
    gap:0;padding:0;min-height:36px;
}
.icon-btn.lang-trigger .lang-native,
.icon-btn.lang-trigger .lang-chevron{display:none}
.icon-btn.lang-trigger .lang-flag{font-size:1.15rem}
.icon-btn.lang-trigger:hover,
.icon-btn.lang-trigger[aria-expanded="true"]{background:#7c75ff;color:#fff;border-color:#7c75ff}
/* Sun = shown in dark mode */
.theme-toggle .sun-icon{stroke:#fbbf24;display:block}
.theme-toggle .moon-icon{stroke:#000;fill:#1a1a2e;display:none} /* moon always BLACK */
body.light .theme-toggle .sun-icon{display:none}
body.light .theme-toggle .moon-icon{display:block}

/* Header right */
.header-buttons{display:flex;gap:10px;align-items:center;flex-wrap:wrap;flex:1;min-width:0}
/* Home + Search stay put; everything after them (Reset/Undo/Redo/
   Delete/Download/Language) centers within the remaining row space. */
.header-buttons-center{
    flex:1;display:flex;gap:10px;align-items:center;justify-content:center;flex-wrap:wrap;
}

/* Search */
.search-field{
    display:flex;align-items:center;gap:8px;
    background:var(--nav-surface);
    border:2px solid var(--accent);
    border-radius:40px;
    padding:4px 8px 4px 16px;
}
.search-field input{
    background:transparent;border:none;color:var(--text);
    font-size:.9rem;padding:7px 0;outline:none;width:200px;
    font-family:'Syne',sans-serif;
}
.search-field input::placeholder{color:var(--text-dimmer)}
.search-field button{
    background:var(--accent);border:none;border-radius:30px;
    padding:6px 16px;color:#fff;font-weight:600;cursor:pointer;
    transition:var(--tr);font-family:'Syne',sans-serif;font-size:.8rem;
}
.search-field button:hover{background:#7c75ff}

/* Download */
.download-btn{
    background:var(--accent);color:#fff;
    border:2px solid var(--accent);
    padding:9px 22px;border-radius:36px;
    font-family:'Syne',sans-serif;font-size:.92rem;font-weight:700;
    cursor:pointer;transition:background .2s;
    display:inline-flex;align-items:center;gap:8px;
    white-space:nowrap;flex-shrink:0;
}
.download-btn svg{width:18px;height:18px;stroke:#fff;stroke-width:2.5}
.download-btn:hover{background:#7c75ff}
.download-btn:disabled{opacity:.65;cursor:not-allowed;pointer-events:none}

/* Home/Search buttons — now round icon-only (.icon-btn handles the
   shape/size/colors); nothing further needed here. */

/* Toolbar row */
.header-bottom{
    display:flex;align-items:center;justify-content:center;
    gap:6px;padding:4px 12px;flex-wrap:wrap;
    border-top:1px solid var(--nav-border);
    /* No max-height/overflow clip — same reasoning as .header-top: at
       high zoom this row can wrap, and clipping hid/crushed buttons
       instead of showing them. The real header height stays in sync
       via JS (initHeaderHeight). */
    max-width:100%;box-sizing:border-box;
}
.toolbar-btn{
    display:inline-flex;align-items:center;gap:5px;
    padding:4px 10px !important;
    border-radius:30px;
    font-family:'Syne',sans-serif;font-size:.75rem;font-weight:700;
    cursor:pointer;transition:var(--tr);
    white-space:nowrap;height:28px;line-height:1;
    margin:5px 0;
    border:3px solid transparent;
    background:transparent;
    flex-shrink:1;max-width:100%;box-sizing:border-box;
}
.toolbar-btn:hover{transform:translateY(-1px)}
.toolbar-btn.reset{color:var(--warn);   border-color:var(--warn)}
.toolbar-btn.reset:hover{background:var(--warn);color:#fff}
.toolbar-btn.undo {color:#a855f7;border-color:#a855f7}
.toolbar-btn.undo:hover{background:#a855f7;color:#fff}
.toolbar-btn.redo {color:#f59e0b;border-color:#f59e0b}
.toolbar-btn.redo:hover{background:#f59e0b;color:#fff}
.toolbar-btn.trash{color:#ef4444;border-color:#ef4444}
.toolbar-btn.trash:hover{background:#ef4444;color:#fff}

/* Zoom — sits centered right under the canvas */
.zoom-strip-row{display:flex;justify-content:center;align-items:center;gap:10px;padding:10px 0}

/* Share button + dropdown menu, to the right of the zoom control */
.share-wrap{position:relative}
.share-menu{
    position:absolute;top:calc(100% + 8px);right:0;z-index:120;
    min-width:160px;list-style:none;margin:0;padding:6px;
    background:var(--panel-surface);border:1px solid var(--panel-border);
    border-radius:var(--rs);box-shadow:0 10px 30px rgba(0,0,0,.35);
}
.share-menu[hidden]{display:none}
.share-menu-item{
    display:block;width:100%;text-align:left;
    padding:9px 12px;border-radius:6px;border:none;background:transparent;
    color:var(--text);font-family:'Syne',sans-serif;font-size:.85rem;font-weight:600;
    cursor:pointer;text-decoration:none;transition:var(--tr);
}
.share-menu-item:hover{background:var(--nav-surface);color:var(--accent)}

/* Like/Dislike — unrestricted (any number of clicks bump the real,
   site-wide total kept on the server). Buttons are sized at half the
   standard .icon-btn (36px -> 18px), and the count sits centered
   below the button rather than beside it. */
.like-wrap{display:flex;flex-direction:column;align-items:center;gap:2px}
.like-wrap .like-btn{width:22px;height:22px;border-width:1px}
.like-wrap .like-btn svg{width:11px;height:11px}
.like-count{
    font-family:'DM Mono',monospace;font-size:.7rem;font-weight:600;
    color:var(--text-dim);min-width:1em;text-align:center;
}
.like-btn svg{transition:var(--tr)}
.like-btn.like-pop{animation:pie-like-pop .35s ease}
@keyframes pie-like-pop{
    0%{transform:scale(1)}
    40%{transform:scale(1.25)}
    100%{transform:scale(1)}
}

/* Quick download — same pill style as the upload button, sized down
   to sit comfortably in the zoom row. */
.zoom-download-btn{
    display:inline-flex;align-items:center;gap:8px;
    padding:8px 18px;font-size:.82rem;
}

/* Red "X" delete, next to Like/Dislike/Download in the zoom row */
.icon-btn.trash-x{background:#ef4444;border-color:#ef4444;color:#fff}
.icon-btn.trash-x:active{background:#f87171;border-color:#f87171}
.zoom-strip{
    display:flex;align-items:center;gap:6px;
    background:var(--nav-surface);padding:4px 12px;
    border-radius:30px;border:2px solid var(--accent);
}
.zoom-strip .zoom-label{
    font-size:.72rem;font-family:'Syne',sans-serif;
    font-weight:600;color:var(--text-dim);
}
.zoom-strip .zoom-val{
    font-size:.75rem;font-family:'DM Mono',monospace;
    font-weight:600;color:var(--accent);min-width:38px;text-align:right;
}
.zoom-step-btn{
    display:flex;align-items:center;justify-content:center;
    width:20px;height:20px;flex-shrink:0;padding:0;
    border:1px solid var(--panel-border);border-radius:50%;
    background:var(--panel-surface);color:var(--text-dim);
    font-size:.85rem;line-height:1;font-weight:700;
    cursor:pointer;transition:var(--tr);
}
.zoom-step-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--nav-surface)}
#zoomSlider{
    width:130px;height:7px;-webkit-appearance:none;appearance:none;
    background:#4a4a6a;border-radius:4px;cursor:pointer;
}
body.light #zoomSlider{background:#cbd5e1}
#zoomSlider::-webkit-slider-thumb{
    -webkit-appearance:none;width:14px;height:14px;
    background:var(--accent);border-radius:50%;cursor:pointer;
}
#zoomSlider::-moz-range-thumb{
    width:14px;height:14px;background:var(--accent);
    border-radius:50%;border:none;cursor:pointer;
}

/* Every slider in every tool panel matches the canvas zoom slider's look
   (same track color and accent-filled thumb) instead of each browser's
   unstyled native slider appearance. */
input[type="range"]:not(#zoomSlider){
    width:100%;height:7px;-webkit-appearance:none;appearance:none;
    background:#4a4a6a;border-radius:4px;cursor:pointer;
}
body.light input[type="range"]:not(#zoomSlider){background:#cbd5e1}
input[type="range"]:not(#zoomSlider)::-webkit-slider-thumb{
    -webkit-appearance:none;width:14px;height:14px;
    background:var(--accent);border-radius:50%;cursor:pointer;
}
input[type="range"]:not(#zoomSlider)::-moz-range-thumb{
    width:14px;height:14px;background:var(--accent);
    border-radius:50%;border:none;cursor:pointer;
}

/* ──────────────────────────────────────────────────────────
   APP LAYOUT — 3-column sticky grid
────────────────────────────────────────────────────────── */
.app{
    display:grid;
    grid-template-columns:var(--sidebar-w) 1fr 340px;
    align-items:start;
    flex:1;
}

/* ──────────────────────────────────────────────────────────
   LEFT SIDEBAR
   Sticky, full-height, thin scrollbar, NO height cap clipping
────────────────────────────────────────────────────────── */
.icon-nav{
    background:var(--nav-bg);
    border-right:1px solid var(--nav-border);
    position:sticky;
    top:var(--header-h);
    height:calc(100vh - var(--header-h));
    overflow-y:auto;
    overflow-x:hidden;
    padding:10px 10px 16px;
    display:flex;
    flex-direction:column;
    gap:1px;
    scrollbar-width:thin;
    scrollbar-color:var(--accent) transparent;
}
.icon-nav::-webkit-scrollbar{width:3px}
.icon-nav::-webkit-scrollbar-thumb{background:var(--accent);border-radius:3px}

/* WP nav menu reset */
.icon-nav ul.menu{
    list-style:none;margin:0;padding:0;
    display:flex;flex-direction:column;gap:1px;width:100%;
}
.icon-nav ul.menu li{width:100%}

/* Section heading */
.nav-section-label{
    font-size:.55rem;font-weight:700;letter-spacing:.1em;
    text-transform:uppercase;color:var(--text-dimmer);
    padding:12px 12px 4px;pointer-events:none;user-select:none;
}

/* Divider */
.nav-divider{height:1px;background:var(--nav-border);margin:6px 8px}
.icon-nav ul.menu li.nav-separator{pointer-events:none}

/* Tools / Effects / Color category switcher — three equal square buttons */
.nav-category-buttons{
    display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;
    padding:0 2px 10px;
}
.nav-category-btn{
    aspect-ratio:1;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:4px;padding:6px 4px;border-radius:10px;
    background:var(--panel-surface);border:1px solid var(--panel-border);
    cursor:pointer;transition:var(--tr);
    min-width:0;overflow:hidden;
}
.nav-category-btn:hover{border-color:var(--accent)}
.nav-category-btn.is-active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.nav-category-btn svg{width:22px;height:22px;flex-shrink:0}
.nav-category-btn span:last-child{
    font-size:.58rem;font-weight:700;color:var(--text-dim);
    text-transform:uppercase;letter-spacing:.04em;
}
.nav-category-btn.is-active span:last-child{color:var(--text)}
.nav-cat-sparkles{overflow:visible}

/* Styles sub-section — two half-height buttons ("Effects" / "Filters")
   shown directly under the Styles pill, splitting that category's tool
   list without needing a full square category button each. */
.nav-subcategory-buttons{
    display:grid;grid-template-columns:1fr 1fr;gap:6px;
    padding:0 2px 10px;
}
.nav-subcategory-buttons.hidden{display:none}
.nav-subcategory-btn{
    height:24px;display:flex;align-items:center;justify-content:center;
    border-radius:6px;background:var(--panel-surface);border:1px solid var(--panel-border);
    cursor:pointer;transition:var(--tr);
    font-size:.62rem;font-weight:700;color:var(--text-dim);
    text-transform:uppercase;letter-spacing:.04em;
}
.nav-subcategory-btn:hover{border-color:var(--accent)}
.nav-subcategory-btn.is-active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent);color:var(--text)}
.nav-cat-colorwheel{
    width:22px;height:22px;border-radius:50%;flex-shrink:0;
    background:conic-gradient(from 0deg,#ef4444,#f59e0b,#eab308,#22c55e,#06b6d4,#3b82f6,#a855f7,#ec4899,#ef4444);
    border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.15);
}
/* "Tools" category button — button stays the same transparent square
   as the others; only its wrench icon is colored like the header's
   download button (accent color), via currentColor on the icon. */
.nav-category-btn[data-category="tools"]{
    background:transparent;color:var(--accent);
}
.nav-category-btn[data-category="tools"] span:last-child{color:var(--text-dim)}
.nav-category-btn[data-category="tools"].is-active span:last-child{color:var(--text)}

/* Effects sparkle icon — 70% larger than the other two category icons
   (22px -> ~37px) so the star bursts read clearly at this size. */
.nav-cat-sparkles{width:41px!important;height:41px!important}

.nav-group{display:flex;flex-direction:column;gap:1px;width:100%}
.nav-group[hidden]{display:none}
/* Individual buttons also get [hidden] toggled for the Effects/Filters
   subcategory split — .nav-btn{display:flex} below is unconditional, so
   without this override the hidden attribute would have no visible
   effect and both subsections would show every item. */
.nav-btn[hidden]{display:none}

/* Nav button */
.nav-btn{
    position:relative;
    display:flex;align-items:center;gap:7px;
    padding:0 10px;border-radius:8px;
    cursor:pointer;border:none;background:transparent;
    transition:var(--tr);width:100%;
    font-family:'Syne',sans-serif;font-size:.875rem;font-weight:500;line-height:1;
    text-decoration:none;color:var(--nav-idle);min-height:35px;padding-top:4px;padding-bottom:4px;
}
.nav-btn .nav-icon{
    display:flex;align-items:center;justify-content:center;
    flex-shrink:0;width:15px;height:15px;
    color:var(--tc,var(--nav-idle));
}
.nav-btn .nav-icon svg{
    width:15px;height:15px;fill:none;
    stroke:currentColor;stroke-width:3;
    stroke-linecap:round;stroke-linejoin:round;
}
.nav-btn .nav-thumb{
    width:26px;height:26px;border-radius:5px;
    object-fit:cover;flex-shrink:0;
    border:1px solid var(--nav-border);
}

/* Effects sidebar items: an uploaded 30x50 thumbnail (see the "Sidebar
   Icon Thumbnail" meta box on each tool's Page) replaces the default
   15x15 SVG icon — the icon container resizes to fit it, and the row
   itself grows taller to accommodate it. */
.nav-btn .nav-label{flex:1;text-align:left;color:var(--nav-idle);line-height:1.2}

/* Effects items with an uploaded thumbnail show it as a hover preview
   that follows the cursor (see initNavThumbPreview() in app-theme.js).
   It's appended to <body> — not nested inside the sidebar button — since
   .icon-nav clips overflow for its own scrollbar and would otherwise cut
   the preview off invisibly instead of just letting it float over the
   canvas. */
.nav-thumb-preview-float{
    position:fixed;
    display:none;
    z-index:1000;
    border:2px solid var(--accent);
    border-radius:8px;
    overflow:hidden;
    background:var(--nav-surface);
    box-shadow:0 6px 20px rgba(0,0,0,.45);
    pointer-events:none;
}
.nav-thumb-preview-float.is-visible{display:block}
.nav-thumb-preview-float img{display:block;width:130px;height:130px;object-fit:cover}
/* Hover — brighter fill, same treatment as the download button */
.nav-btn:hover{background:var(--accent);color:#fff}
.nav-btn:hover .nav-label{color:#fff}
.nav-btn.active,
.icon-nav .current-menu-item>.nav-btn,
.icon-nav .current_page_item>.nav-btn{
    background:var(--nav-surface);
    box-shadow:inset 0 0 0 1px var(--accent);
    color:var(--accent);
}
.nav-btn.active .nav-label,
.icon-nav .current-menu-item>.nav-btn .nav-label,
.icon-nav .current_page_item>.nav-btn .nav-label{color:var(--accent)}

/* Per-tool accent colours */
.icon-nav .tool-crop>.nav-btn{--tc:#f472b6}
.icon-nav .tool-rotate>.nav-btn{--tc:#a3e635}
.icon-nav .tool-bgremove>.nav-btn{--tc:#2dd4bf}
.icon-nav .tool-quality>.nav-btn{--tc:#fde047}
/* also support direct data-panel attribute */
.nav-btn[data-panel="crop"]{--tc:#f472b6}
.nav-btn[data-panel="rotate"]{--tc:#a3e635}
.nav-btn[data-panel="bgremove"]{--tc:#2dd4bf}
.nav-btn[data-panel="quality"]{--tc:#fde047}
.icon-nav [class*="tool-"]>.nav-btn .nav-icon{color:var(--tc,var(--accent))}

/* Selected/current tool keeps its own tool colour consistently — it must
   not flip to the generic accent colour just because it became active,
   and must stay the same colour every time you navigate to it. */
.icon-nav [class*="tool-"]>.nav-btn.active,
.icon-nav [class*="tool-"].current-menu-item>.nav-btn,
.icon-nav [class*="tool-"].current_page_item>.nav-btn{
    box-shadow:inset 0 0 0 1px var(--tc,var(--accent));
    color:var(--tc,var(--accent));
}
.icon-nav [class*="tool-"]>.nav-btn.active .nav-label,
.icon-nav [class*="tool-"].current-menu-item>.nav-btn .nav-label,
.icon-nav [class*="tool-"].current_page_item>.nav-btn .nav-label{color:var(--tc,var(--accent))}

/* ──────────────────────────────────────────────────────────
   WORKSPACE (centre column)
   No overflow hidden — content flows naturally; page scrolls
────────────────────────────────────────────────────────── */
.workspace{
    display:flex;
    flex-direction:column;
    background:var(--ws-bg);
    min-height:100%;
    /* A grid/flex item's default min-width/min-height is "auto", which
       refuses to shrink below its content's intrinsic size — so an
       oversized zoomed canvas inside could force this whole column
       (and everything after it: the right panel, etc.) to widen and
       shift. Overriding to 0 lets overflow:auto below actually contain
       it instead. */
    min-width:0;
}

/* Status bar — sticky under header */
.ws-toolbar{
    display:flex;align-items:center;justify-content:space-between;
    gap:14px;flex-wrap:wrap;
    padding:8px 18px;background:var(--ws-bg);
    border-bottom:1px solid var(--panel-border);
    font-size:.75rem;position:sticky;
    top:var(--header-h);z-index:10;
}
#statusText{flex-shrink:0}
.ws-image-info{flex:1;justify-content:center;min-width:0;overflow:hidden}
#zoomInfo{flex-shrink:0}

/* Canvas wrapper — hard cap, NO scrollbar */
.canvas-wrapper{
    display:flex;
    /* Not center-aligned: once the canvas overflows, centering pushes
       part of it into "negative" scroll territory — a scroll container
       can never scroll there, so that portion (including the top/left
       margin) becomes permanently unreachable/clipped. Starting at the
       top-left means scroll position (0,0) IS the true top-left, so
       that margin always shows, and zoomed growth just extends further
       in the (reachable) forward-scroll direction. */
    align-items:flex-start;justify-content:flex-start;
    position:relative;
    /* Small checkerboard grid (the standard "transparent area" indicator)
       layered under the existing dark backdrop gradient, so a transparent
       PNG's see-through parts are always visible against it. */
    background-color:#0e0d0d;
    background-image:
        linear-gradient(45deg,rgba(255,255,255,.05) 25%,transparent 25%),
        linear-gradient(-45deg,rgba(255,255,255,.05) 25%,transparent 25%),
        linear-gradient(45deg,transparent 75%,rgba(255,255,255,.05) 75%),
        linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.05) 75%),
        radial-gradient(ellipse at 40% 50%,#161210 0%,#0e0d0d 100%);
    background-size:16px 16px,16px 16px,16px 16px,16px 16px,100% 100%;
    background-position:0 0,0 8px,8px -8px,-8px 0,0 0;
    width:100%;
    height:var(--canvas-max-h);
    max-height:var(--canvas-max-h);
    /* Fixed box: zoom must never change this element's own size —
       only its (scrollable) content grows/shrinks. min-width:0 keeps
       an oversized child from forcing it wider than 100% regardless. */
    min-width:0;
    box-sizing:border-box;
    overflow:auto; /* scrolls once the zoomed canvas exceeds this box */
    scrollbar-width:thin;
    scrollbar-color:var(--accent) var(--panel-surface);
}
.canvas-wrapper::-webkit-scrollbar{width:10px;height:10px}
.canvas-wrapper::-webkit-scrollbar-track{background:var(--panel-surface)}
.canvas-wrapper::-webkit-scrollbar-thumb{background:var(--accent);border-radius:6px}
.canvas-wrapper::-webkit-scrollbar-thumb:hover{background:#7c75ff}
body.light .canvas-wrapper{
    background-color:#d0d4e8;
    background-image:
        linear-gradient(45deg,rgba(0,0,0,.06) 25%,transparent 25%),
        linear-gradient(-45deg,rgba(0,0,0,.06) 25%,transparent 25%),
        linear-gradient(45deg,transparent 75%,rgba(0,0,0,.06) 75%),
        linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.06) 75%),
        radial-gradient(ellipse at 40% 50%,#e8eaf6 0%,#d0d4e8 100%);
    background-size:16px 16px,16px 16px,16px 16px,16px 16px,100% 100%;
    background-position:0 0,0 8px,8px -8px,-8px 0,0 0;
}
.canvas-container{
    position:relative;
    box-shadow:0 8px 40px rgba(0,0,0,.6),0 0 0 1px #2a2a2a;
    border-radius:8px;display:inline-block;
    /* No max-width/max-height here: this box has no padding and wraps
       #mainCanvas tightly, so it already matches the canvas's own
       (already-capped) size at rest. Capping it independently meant
       that once zoom grew the canvas past this same limit, the frame
       couldn't follow — the canvas visually overflowed past its own
       border on the far side. The canvas element enforces the 100%-
       zoom size limit on its own; this container just needs to hug it. */
    /* Margin instead of wrapper padding: when the zoomed canvas
       overflows and .canvas-wrapper starts scrolling, browsers drop
       a scroll container's own padding on the end side (right/bottom)
       but always respect margin on the scrolled content itself — so
       this is what keeps the gray gap visible on every side. */
    margin:20px;
}
#mainCanvas{
    display:block;cursor:crosshair;
    max-width:var(--canvas-max-w);
    max-height:var(--canvas-max-h);
    width:auto;height:auto;
    /* Zoom sets an explicit inline width/height (see app-theme.js
       setZoom) — real box resizing, not a transform, so normal CSS
       (flex centering, this container's margin, scrolling to any part
       of an oversized canvas) all keep working correctly whether
       zooming in or out. */
    transition:width .2s ease,height .2s ease;
}

/* Drop zone — fits inside canvas-wrapper, no scrollbar */
.drop-zone{
    position:absolute;inset:20px;
    display:flex;flex-direction:column;
    align-items:center;justify-content:center;
    gap:12px;
    background:rgba(10,10,14,.93);
    backdrop-filter:blur(12px);
    z-index:20;border-radius:16px;
    border:2px dashed var(--accent);
    text-align:center;padding:20px;
    overflow:hidden; /* never scrolls */
}
body.light .drop-zone{background:rgba(248,250,255,.96)}
.drop-zone.hidden{display:none}
.drop-zone h3{font-size:.98rem;font-weight:700}
.drop-zone p{font-size:.78rem;color:var(--text-dim)}
.drop-zone-buttons{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}

/* Upload button */
.upload-btn{
    padding:11px 26px;background:var(--accent);color:#fff;
    border-radius:50px;font-weight:700;border:none;cursor:pointer;
    font-size:.92rem;transition:transform .2s ease,background .2s ease;
    font-family:'Syne',sans-serif;
}
.upload-btn:hover{transform:translateY(-2px);background:#7c75ff}
.upload-btn.secondary{
    background:var(--panel-surface);color:var(--text);
    border:1px solid var(--nav-border);
}
.upload-btn.secondary:hover{background:var(--nav-surface)}

/* URL row inside drop zone */
.url-input-row{display:flex;gap:8px;width:100%;max-width:400px}
.url-input-row input{
    flex:1;padding:9px 14px;background:var(--panel-bg);
    border:1px solid var(--panel-border);border-radius:50px;
    color:var(--text);font-size:.82rem;outline:none;
    font-family:'Syne',sans-serif;
}
.url-input-row input:focus{border-color:var(--accent)}

/* ──────────────────────────────────────────────────────────
   ARTICLE / ABOUT AREA
   No overflow, no max-height, no scrollbar — flows with page
────────────────────────────────────────────────────────── */
.article-area{
    background:var(--panel-bg);
    border-top:1px solid var(--panel-border);
    padding:28px 28px 36px;
    /* NO overflow:hidden, NO max-height */
}
.article-area h3{font-size:.9rem;color:var(--accent);margin-bottom:12px;font-weight:700}
.article-content p{margin-bottom:8px;line-height:1.55;color:var(--text-dim);font-size:.82rem}

/* ── Tool cards grid (shown on home page) ── */
.tool-cards-grid{
    display:grid;
    grid-template-columns:repeat(3,1fr);
    gap:14px;
    margin-top:20px;
}
.tool-card{
    background:var(--panel-surface);
    border:1px solid var(--panel-border);
    border-radius:var(--r);
    padding:18px 16px 16px;
    display:flex;flex-direction:column;gap:8px;
    transition:var(--tr);
    text-decoration:none;color:inherit;
    cursor:pointer;
}
.tool-card:hover{border-color:var(--tc,var(--accent));transform:translateY(-2px)}

/* Image Text Editor — "A" glyph icon with drop shadow, plus a visible
   idle-state border on its own nav/card buttons (most tool buttons rely
   on hover/active state alone for a border, but this one needs to read
   clearly at rest too). */
.pie-icon-letter-a{filter:drop-shadow(1px 2px 1.5px rgba(0,0,0,.9))}
.tool-card.tool-textedit{border-color:var(--tc,#60a5fa)}
.icon-nav .tool-textedit>.nav-btn,
.nav-btn[data-panel="textedit"]{box-shadow:inset 0 0 0 1px var(--tc,#60a5fa)}
.tool-card-icon{
    width:38px;height:38px;border-radius:8px;
    display:flex;align-items:center;justify-content:center;
    background:rgba(108,99,255,.12);
    color:var(--tc,var(--accent));
    flex-shrink:0;
}
.tool-card-icon svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.tool-card-icon img{width:22px;height:22px;object-fit:cover;border-radius:4px}
.tool-card-title{font-size:.85rem;font-weight:700;color:var(--text)}
.tool-card-desc{font-size:.75rem;color:var(--text-dim);line-height:1.4}
/* accent colours for cards */
.tool-card.tool-crop{--tc:#f472b6}
.tool-card.tool-rotate{--tc:#a3e635}
.tool-card.tool-bgremove{--tc:#2dd4bf}
.tool-card.tool-quality{--tc:#fde047}

/* WordPress page content */
.workspace-content{
    padding:24px 28px 32px;
    font-size:.88rem;color:var(--text-dim);line-height:1.65;
    border-top:1px solid var(--panel-border);
}
.workspace-content h1,.workspace-content h2,.workspace-content h3{
    color:var(--text);margin-bottom:10px;margin-top:22px;
}
.workspace-content p{margin-bottom:12px}

/* ──────────────────────────────────────────────────────────
   RIGHT PANEL — sticky sidebar, scrollable, NO clip
────────────────────────────────────────────────────────── */
.right-panel{
    background:var(--panel-bg);
    border-left:1px solid var(--panel-border);
    border-bottom:1px solid var(--panel-border);
    display:flex;flex-direction:column;
    position:sticky;top:var(--header-h);
    max-height:350px;
    overflow-y:auto;
    scrollbar-width:thin;
    scrollbar-color:var(--panel-border) transparent;
}

/* ── Shared "?" help tooltip — used by all tool panels to keep the
   visible label short while still surfacing the explanation on hover
   or keyboard focus, without JS. ──────────────────────────────── */
.pie-help{
    display:inline-flex;align-items:center;justify-content:center;
    width:14px;height:14px;border-radius:50%;flex-shrink:0;
    background:var(--panel-border);color:var(--text-dim);
    font-size:.62rem;font-weight:700;line-height:1;
    cursor:help;position:relative;
}
.pie-help:hover,.pie-help:focus-visible{background:var(--accent);color:#fff;outline:none}
.pie-help:hover::after,.pie-help:focus-visible::after{
    content:attr(data-tip);
    position:absolute;left:50%;bottom:130%;transform:translateX(-50%);
    width:190px;max-width:60vw;
    background:var(--panel-surface);color:var(--text);
    border:1px solid var(--panel-border);border-radius:6px;
    padding:7px 9px;font-size:.68rem;font-weight:400;line-height:1.35;
    box-shadow:0 6px 18px rgba(0,0,0,.35);
    z-index:100;text-align:left;white-space:normal;
}
.right-panel::-webkit-scrollbar{width:3px}
.right-panel::-webkit-scrollbar-thumb{background:var(--panel-border);border-radius:3px}

/* Image info — now lives inline in the ws-toolbar, above the canvas */
.ws-image-info{display:none;align-items:center;gap:14px}
.ws-image-info.visible{display:flex}
.ws-info-item{
    display:flex;align-items:baseline;gap:5px;
    white-space:nowrap;
}
.info-lbl{font-size:.6rem;color:var(--text-dimmer);text-transform:uppercase}
.info-val{font-size:.75rem;font-weight:600;font-family:'DM Mono',monospace;color:var(--text)}

.panel-content{flex:1;padding:8px}
.tool-panel{display:none}
.tool-panel.active{display:block}
.empty-state{
    display:flex;flex-direction:column;align-items:center;
    gap:8px;padding:16px 12px;text-align:center;color:var(--text-dimmer);
}
.empty-state svg{opacity:.35}
.empty-state h4{font-size:.9rem;color:var(--text-dim)}
.empty-state p{font-size:.75rem;line-height:1.4}
.panel-heading{
    display:flex;align-items:center;gap:10px;
    margin-bottom:4px;padding-bottom:4px;
    border-bottom:1px solid var(--panel-border);
}
/* The tool's name is already shown by the page/nav — repeating it as an
   h3 at the top of every panel was redundant text eating into the
   350px height budget below, so it's dropped everywhere at once. */
.panel-heading h3{display:none}
.panel-heading p{font-size:.7rem;color:var(--text-dim)}
.panel-heading .pie-help{margin-left:auto}

/* ════════════════════════════════════════════════════════════
   GLOBAL TOOL-PANEL HEIGHT BUDGET — applies to every plugin panel
   by CSS class naming convention (pie-{tool}-panel/-section/-label/
   etc.), not per-plugin, so it also covers any plugin added later
   without needing its own CSS touched. .right-panel is hard-capped
   at 350px above; these rules keep each panel's own content compact
   enough to actually fit that budget without needing to scroll.
   ════════════════════════════════════════════════════════════ */
[class*="pie-"][class*="-panel"]{ gap:4px !important; padding:4px !important; }
[class*="pie-"][class*="-section"]{ padding-bottom:3px !important; margin-bottom:0 !important; }
[class*="pie-"][class*="-label"]{ margin-bottom:3px !important; font-size:.58rem !important; }
[class*="pie-"][class*="-slider-row"]{ margin-bottom:0 !important; gap:6px !important; }
[class*="pie-"][class*="-val"]{ font-size:.68rem !important; }
[class*="pie-"][class*="-status"]{ padding:3px !important; min-height:1.1em !important; font-size:1rem !important; }
[class*="pie-"][class*="-toggle-row"]{ margin-bottom:4px !important; gap:5px !important; }
[class*="pie-"][class*="-toggle-btn"]{ padding:5px 6px !important; font-size:.65rem !important; }
[class*="pie-"][class*="-toggle"]:not([class*="-toggle-btn"]):not([class*="-toggle-row"]){ margin-bottom:4px !important; }
[class*="pie-"][class*="-btn"]:not([class*="-btn-row"]):not([class*="toggle-btn"]):not([class*="secondary"]){ min-height:30px !important; padding:6px 14px !important; }

/* ──────────────────────────────────────────────────────────
   UTILITY BUTTONS
────────────────────────────────────────────────────────── */
.btn{
    display:inline-flex;align-items:center;gap:8px;
    padding:8px 16px;border-radius:var(--rs);
    font-size:.78rem;font-weight:600;cursor:pointer;
    transition:var(--tr);border:none;
    font-family:'Syne',sans-serif;min-height:38px;
}
.btn-primary{background:var(--accent);color:#fff}
.btn-primary:hover{background:#7c75ff}
.btn-ghost{background:var(--panel-surface);color:var(--text-dim);border:1px solid var(--panel-border)}
.btn-ghost:hover{border-color:var(--accent);color:var(--text)}
.btn-danger{background:rgba(248,113,113,.15);color:var(--danger);border:1px solid rgba(248,113,113,.3)}
.btn-danger:hover{background:rgba(248,113,113,.25)}

/* ──────────────────────────────────────────────────────────
   MODALS
────────────────────────────────────────────────────────── */
.modal-bg{
    position:fixed;inset:0;background:rgba(0,0,0,.85);
    z-index:1000;display:none;align-items:center;justify-content:center;
}
.modal{
    background:var(--panel-bg);border-radius:var(--r);
    padding:28px 24px;max-width:420px;width:90%;
    text-align:center;border:1px solid var(--accent);color:var(--text);
}
.modal h3{font-size:1rem;margin-bottom:6px}
.modal p{font-size:.85rem;color:var(--text-dim)}
.format-buttons{display:flex;gap:10px;justify-content:center;margin:16px 0;flex-wrap:wrap}
.format-btn{
    padding:8px 22px;background:var(--panel-surface);
    border:1px solid var(--panel-border);border-radius:30px;
    cursor:pointer;font-size:.88rem;font-weight:600;transition:var(--tr);
    font-family:'Syne',sans-serif;color:var(--text);min-height:40px;
}
.format-btn:hover{border-color:var(--accent);color:var(--accent)}
.modal-actions{display:flex;gap:10px;justify-content:center;margin-top:18px}

/* Search overlay */
.search-overlay{
    position:fixed;inset:0;background:rgba(0,0,0,.85);
    z-index:2000;display:none;align-items:flex-start;justify-content:center;
    padding-top:80px;
}
.search-overlay.open{display:flex}
.search-box{
    background:var(--panel-bg);border:1px solid var(--accent);
    border-radius:var(--r);width:90%;max-width:560px;
    box-shadow:0 20px 60px rgba(0,0,0,.5);overflow:hidden;
}
.search-box-input{
    display:flex;align-items:center;gap:10px;padding:14px 18px;
    border-bottom:1px solid var(--panel-border);
}
.search-box-input input{
    flex:1;background:transparent;border:none;outline:none;
    color:var(--text);font-family:'Syne',sans-serif;font-size:1rem;
}
.search-box-input input::placeholder{color:var(--text-dimmer)}
.search-box-input svg{width:18px;height:18px;stroke:var(--accent);fill:none;stroke-width:2;flex-shrink:0}
.search-results{max-height:360px;overflow-y:auto}
.search-result-item{
    display:flex;align-items:center;gap:12px;
    padding:12px 18px;cursor:pointer;transition:background .15s;
    text-decoration:none;color:var(--text);
    border-bottom:1px solid var(--panel-border);
}
.search-result-item:last-child{border-bottom:none}
.search-result-item:hover{background:var(--nav-surface)}
.search-result-icon{
    width:32px;height:32px;border-radius:7px;
    display:flex;align-items:center;justify-content:center;
    background:rgba(108,99,255,.12);flex-shrink:0;
}
.search-result-icon svg{width:16px;height:16px;fill:none;stroke:var(--accent);stroke-width:2}
.search-result-icon img{width:20px;height:20px;border-radius:3px;object-fit:cover}
.search-result-title{font-size:.88rem;font-weight:600}
.search-result-desc{font-size:.72rem;color:var(--text-dim);margin-top:2px}
.search-no-results{padding:24px;text-align:center;color:var(--text-dim);font-size:.85rem}
.search-hint{padding:10px 18px;font-size:.7rem;color:var(--text-dimmer);border-top:1px solid var(--panel-border)}

/* ──────────────────────────────────────────────────────────
   TOAST
────────────────────────────────────────────────────────── */
.toast{
    position:fixed;bottom:24px;left:50%;transform:translateX(-50%);
    background:#1e293b;backdrop-filter:blur(8px);
    border:1px solid var(--accent);border-radius:40px;
    padding:8px 22px;font-size:.82rem;color:#fff;
    opacity:0;transition:opacity .2s,transform .2s;
    z-index:1100;pointer-events:none;white-space:nowrap;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(-8px)}

/* ──────────────────────────────────────────────────────────
   MOBILE NAV
────────────────────────────────────────────────────────── */
.mobile-nav{display:none}

/* ──────────────────────────────────────────────────────────
   RESPONSIVE
────────────────────────────────────────────────────────── */
@media (max-width:1200px){
    :root{--sidebar-w:200px}
    .app{grid-template-columns:var(--sidebar-w) 1fr 240px}
}
@media (max-width:1000px){
    :root{--sidebar-w:180px}
    .app{grid-template-columns:var(--sidebar-w) 1fr 210px}
    .search-field input{width:140px}
    .tool-cards-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:780px){
    .right-panel{display:none}
    .app{grid-template-columns:var(--sidebar-w) 1fr}
    .tool-cards-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:600px){
    :root{--sidebar-w:150px}
    .nav-btn{font-size:.8rem;padding:9px 10px}
    .nav-btn .nav-icon{width:24px;height:24px}
    .nav-btn .nav-icon svg{width:17px;height:17px}
    .tool-cards-grid{grid-template-columns:1fr}
}

/* Mobile: ≤ 480px — one vertical stack, reordered independently of the
   desktop DOM nesting (header → editing area → function settings →
   function menu, all on the "first screen"; the article text is
   pushed after all of that, onto the second screen).

   .app and .workspace are pure layout wrappers on desktop (a grid and
   a flex column respectively) with no content of their own — turning
   them into `display:contents` here removes their own box but keeps
   every child on screen, promoting them to be direct flex items of
   .main-container (which is already `display:flex;flex-direction:
   column` at every screen size). That lets header, the toolbar,
   canvas, right panel, mobile nav and article — despite living at
   three different nesting depths in the markup — all be reordered
   relative to ONE ANOTHER with a single flat set of `order` values,
   without moving anything in PHP. */
@media (max-width:480px){
    :root{--header-h:auto}
    /* overflow-x on body/html only, not .main-container — that element
       is `position:sticky`'s scroll ancestor for the header; giving
       it its own overflow value would risk turning it into a second,
       nested scroll container and breaking the sticky header. */
    html, body{overflow-x:hidden;max-width:100%}
    .main-container{background:var(--ws-bg)} /* .workspace's own background, preserved now that its box is gone */

    .app{display:contents}
    .workspace{display:contents}

    /* 1. Header — capped well under 20% of a typical phone viewport.
       `header` already has `position:sticky;top:0` at every screen
       size (see the base `header{}` rule above), so it already stays
       fixed in place while the rest of the page scrolls beneath it —
       nothing extra needed here for that. What WAS broken here is the
       buttons underneath it: Home/Search/Download/Language and the
       Reset/Undo/Redo/Delete "step" buttons were all wrapping into an
       uneven, unpredictable number of lines together. Forcing the
       step-button group onto its own full-width line (via order +
       flex-basis) guarantees exactly two clean rows every time,
       regardless of label/translation length. */
    header{order:1;max-height:20vh;overflow:hidden}
    .header-top{flex-wrap:wrap;align-items:center;gap:6px;padding:6px 12px}
    .header-buttons{width:auto;flex-wrap:wrap;flex:initial;gap:6px}
    .icon-btn{width:32px;height:32px}
    .header-buttons-center{order:2;flex:1 0 100%;gap:8px}
    .search-field{flex:1 1 100%;min-width:0;order:5}
    .search-field input{width:100%;min-width:0}
    .download-btn{padding:6px 10px;font-size:.75rem}
    .home-btn span{display:none}
    .header-bottom{gap:5px;padding:6px 10px 8px}
    .toolbar-btn{padding:5px 9px;font-size:.7rem}
    .toolbar-btn svg{width:15px;height:15px}
    .zoom-strip .zoom-label{display:none}
    #zoomSlider{width:50px}

    /* 2. Editing area — reduced a further 20% (40vh → 32vh). */
    .ws-toolbar{order:2}
    .canvas-wrapper{order:3;height:32vh;max-height:32vh}
    .canvas-container{margin:12px}
    .drop-zone{inset:8px;padding:12px 8px;gap:6px}
    .drop-zone h3{font-size:.82rem}
    .drop-zone p{font-size:.66rem}
    .upload-btn{padding:9px 16px;font-size:.8rem}
    .url-input-row{flex-direction:column}
    .url-input-row input{width:100%}
    .zoom-strip-row{order:4}

    /* 3. Function settings — the right panel, now shown inline as
       part of the page flow instead of a sticky sidebar, and its own
       height budget reduced a further 20% (350px → 280px) by scaling
       every element inside it down another notch on top of the
       site-wide compaction rules (see the GLOBAL TOOL-PANEL HEIGHT
       BUDGET block above). */
    .icon-nav{display:none}
    .right-panel{
        order:5;display:block;width:100%;
        position:static;max-height:280px;
        border-left:none;border-top:1px solid var(--panel-border);
    }
    [class*="pie-"][class*="-panel"]{padding:3px!important;gap:3px!important}
    [class*="pie-"][class*="-section"]{padding-bottom:2px!important}
    [class*="pie-"][class*="-label"]{font-size:.54rem!important;margin-bottom:2px!important}
    [class*="pie-"][class*="-slider-row"]{gap:5px!important}
    [class*="pie-"][class*="-val"]{font-size:.62rem!important}
    [class*="pie-"][class*="-status"]{font-size:1rem!important;padding:2px!important;min-height:1em!important}
    [class*="pie-"][class*="-toggle-btn"]{padding:4px 5px!important;font-size:.6rem!important}
    [class*="pie-"][class*="-btn"]:not([class*="-btn-row"]):not([class*="toggle-btn"]):not([class*="secondary"]){min-height:26px!important;padding:5px 12px!important}
    .panel-heading{margin-bottom:2px!important;padding-bottom:2px!important;gap:6px!important}

    /* 4. Function selection menu — last item on the first screen. */
    .mobile-nav{
        order:6;display:flex;overflow-x:auto;gap:6px;
        padding:10px 12px;background:var(--nav-bg);
        border-top:1px solid var(--nav-border);
        -webkit-overflow-scrolling:touch;scrollbar-width:none;
    }
    .mobile-nav::-webkit-scrollbar{display:none}
    .mobile-nav-btn{
        display:flex;flex-direction:column;align-items:center;gap:4px;
        padding:8px 12px;border-radius:10px;
        border:1.5px solid var(--nav-border);background:var(--nav-surface);
        cursor:pointer;font-family:'Syne',sans-serif;font-size:.6rem;font-weight:600;
        white-space:nowrap;flex-shrink:0;color:var(--text-dim);
        transition:var(--tr);min-width:54px;min-height:54px;text-decoration:none;
    }
    .mobile-nav-btn svg{width:20px;height:20px;fill:none;stroke-width:2;stroke:currentColor}
    .mobile-nav-btn img{width:20px;height:20px;border-radius:4px;object-fit:cover}
    .mobile-nav-btn:hover,.mobile-nav-btn.active{border-color:var(--accent);color:var(--accent)}

    /* 5. Article text — after everything above, on the second screen.
       (Previously hidden outright on tool pages; now that tool pages
       can carry a real translated article, it's shown but ordered
       last instead.) */
    .article-area{order:7;padding:18px 16px 24px}
    .tool-cards-grid{grid-template-columns:1fr}
}
@media (max-width:360px){
    .logo-text{font-size:1rem}
    .toolbar-btn{padding:4px 7px;font-size:.65rem}
}
@media (forced-colors:active){
    .nav-btn.active{outline:2px solid ButtonText}
    .toolbar-btn{border:2px solid ButtonText}
    .drop-zone{border:2px solid ButtonText}
    .logo-text{-webkit-text-fill-color:LinkText;color:LinkText;background:none}
}

/* ═══════════════════════════════════════════════════════════
   LANGUAGE SWITCHER
   ═══════════════════════════════════════════════════════════ */
.lang-switcher {
    position: relative;
    flex-shrink: 0;
}

/* Trigger button */
.lang-trigger {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px;
    border-radius: 30px;
    background: var(--nav-surface);
    border: 2px solid var(--nav-border);
    color: var(--text);
    font-family: 'Syne', sans-serif;
    font-size: .82rem;
    font-weight: 600;
    cursor: pointer;
    transition: var(--tr);
    white-space: nowrap;
    min-height: 36px;
}
.lang-trigger:hover,
.lang-trigger[aria-expanded="true"] {
    border-color: var(--accent);
    color: var(--accent);
}
.lang-flag {
    font-size: 1.1rem;
    line-height: 1;
}
.lang-native {
    font-size: .82rem;
}
.lang-chevron {
    width: 14px;
    height: 14px;
    transition: transform .2s ease;
    flex-shrink: 0;
}
.lang-trigger[aria-expanded="true"] .lang-chevron {
    transform: rotate(180deg);
}

/* Dropdown list */
.lang-dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 500;
    background: var(--panel-bg);
    border: 1px solid var(--accent);
    border-radius: var(--r);
    padding: 6px 0;
    min-width: 200px;
    box-shadow: 0 16px 48px rgba(0,0,0,.45);
    list-style: none;
    animation: langDropIn .15s ease;
}
@keyframes langDropIn {
    from { opacity:0; transform:translateY(-6px); }
    to   { opacity:1; transform:translateY(0); }
}
/* RTL: open to the left */
.pie-rtl .lang-dropdown,
[dir="rtl"] .lang-dropdown {
    right: auto;
    left: 0;
}

/* Individual option */
.lang-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 16px;
    cursor: pointer;
    transition: background .12s;
    font-family: 'Syne', sans-serif;
    font-size: .85rem;
    color: var(--text);
    position: relative;
}
.lang-option:hover {
    background: var(--nav-surface);
}
.lang-option.active {
    background: var(--nav-surface);
    color: var(--accent);
}
.lang-option .lang-flag {
    font-size: 1.15rem;
    flex-shrink: 0;
}
.lang-option .lang-native {
    font-weight: 600;
    flex: 1;
}
.lang-option .lang-english {
    font-size: .72rem;
    color: var(--text-dimmer);
    margin-left: auto;
    padding-left: 8px;
}
.lang-check {
    width: 15px;
    height: 15px;
    stroke: var(--accent);
    flex-shrink: 0;
}

/* ═══════════════════════════════════════════════════════════
   FONT FAMILIES PER LANGUAGE
   Noto Sans variants loaded via functions.php Google Fonts URL
   ═══════════════════════════════════════════════════════════ */
.pie-lang-zh body,
.pie-lang-zh .nav-btn,
.pie-lang-zh .toolbar-btn,
.pie-lang-zh .download-btn,
.pie-lang-zh .upload-btn,
.pie-lang-zh .lang-trigger,
.pie-lang-zh .lang-option {
    font-family: 'Noto Sans SC', 'Syne', sans-serif;
}
.pie-lang-hi body,
.pie-lang-hi .nav-btn,
.pie-lang-hi .toolbar-btn,
.pie-lang-hi .download-btn,
.pie-lang-hi .upload-btn,
.pie-lang-hi .lang-trigger,
.pie-lang-hi .lang-option {
    font-family: 'Noto Sans Devanagari', 'Syne', sans-serif;
}
.pie-lang-ar body,
.pie-lang-ar .nav-btn,
.pie-lang-ar .toolbar-btn,
.pie-lang-ar .download-btn,
.pie-lang-ar .upload-btn,
.pie-lang-ar .lang-trigger,
.pie-lang-ar .lang-option {
    font-family: 'Noto Sans Arabic', 'Syne', sans-serif;
}
.pie-lang-bn body,
.pie-lang-bn .nav-btn,
.pie-lang-bn .toolbar-btn,
.pie-lang-bn .download-btn,
.pie-lang-bn .upload-btn,
.pie-lang-bn .lang-trigger,
.pie-lang-bn .lang-option {
    font-family: 'Noto Sans Bengali', 'Syne', sans-serif;
}

/* ═══════════════════════════════════════════════════════════
   RTL LAYOUT (Arabic)
   ═══════════════════════════════════════════════════════════ */
.pie-rtl,
html[dir="rtl"] {
    direction: rtl;
}
/* Flip the 3-column grid for RTL */
.pie-rtl .app,
html[dir="rtl"] .app {
    direction: rtl;
}
/* Left sidebar becomes right sidebar in RTL */
.pie-rtl .icon-nav,
html[dir="rtl"] .icon-nav {
    border-right: none;
    border-left: 1px solid var(--nav-border);
}
.pie-rtl .right-panel,
html[dir="rtl"] .right-panel {
    border-left: none;
    border-right: 1px solid var(--nav-border);
}
/* Nav button text aligns right in RTL */
.pie-rtl .nav-btn .nav-label,
html[dir="rtl"] .nav-btn .nav-label {
    text-align: right;
}
/* Header buttons order */
.pie-rtl .header-buttons,
html[dir="rtl"] .header-buttons {
    flex-direction: row-reverse;
}
/* Toolbar */
.pie-rtl .header-bottom,
html[dir="rtl"] .header-bottom {
    flex-direction: row-reverse;
}
/* Logo */
.pie-rtl .site-logo,
html[dir="rtl"] .site-logo {
    flex-direction: row-reverse;
}
/* Tool cards */
.pie-rtl .tool-card,
html[dir="rtl"] .tool-card {
    text-align: right;
}
/* Info grid */
.pie-rtl .info-lbl,
.pie-rtl .info-val,
html[dir="rtl"] .info-lbl,
html[dir="rtl"] .info-val {
    text-align: right;
}
/* Mobile nav RTL */
.pie-rtl .mobile-nav,
html[dir="rtl"] .mobile-nav {
    flex-direction: row-reverse;
}

/* ═══════════════════════════════════════════════════════════
   MOBILE — language switcher compact mode
   ═══════════════════════════════════════════════════════════ */
@media (max-width: 480px) {
    .lang-native { display: none; } /* show flag only on mobile */
    .lang-chevron { display: none; }
    .lang-trigger { padding: 7px 10px; }
    .lang-dropdown { right: 0; left: auto; min-width: 180px; }
    /* RTL mobile */
    .pie-rtl .lang-dropdown,
    html[dir="rtl"] .lang-dropdown { right: auto; left: 0; }
}

/* ═══════════════════════════════════════════════════════════
   ACCESSIBILITY — WCAG 2.1 AA / Section 508 COMPLIANCE
   ═══════════════════════════════════════════════════════════

   Covers:
    1.  Colour contrast — all interactive & text elements ≥ 4.5:1
    2.  Focus indicators — visible on every keyboard-focusable element
    3.  Touch target sizing — minimum 44×44px on all controls
    4.  Reduced motion — respects prefers-reduced-motion
    5.  Forced-colors / Windows High-Contrast mode
    6.  ARIA live regions — status, toast, canvas state
    7.  Error states — form validation with colour + icon + text
    8.  Keyboard traps — modals trap focus, Escape closes
    9.  Text resizing — layout survives 200% zoom
   10.  No information conveyed by colour alone
   11.  Pointer / coarse input — extra hit areas on mobile
   12.  Screen-reader-only helpers
   13.  Dyslexia / cognitive — line-height, spacing, readable sizes
   14.  Canvas fallback — visible text alternative when canvas unavailable

   ═══════════════════════════════════════════════════════════ */

/* ── 1. COLOUR CONTRAST — augmented custom properties ───── */
:root {
    /* Ensure minimum 4.5:1 contrast on dark backgrounds */
    --text-accessible:    #e8e6f4;   /* replaces #e6e4f0 — passes on #111010 */
    --text-dim-accessible:#9e9eb8;   /* replaces #7a7a94 — 4.57:1 on #1a1614 */
    --accent-accessible:  #8b85ff;   /* replaces #6c63ff — 4.52:1 on #0a0c12 */
    /* Error / warning / success with accessible contrast */
    --error-text:         #fca5a5;   /* #f87171 boosted — 5.1:1 on dark */
    --warn-text:          #fcd34d;   /* #fbbf24 boosted — 4.7:1 on dark */
    --success-text:       #6ee7b7;   /* #34d399 boosted — 4.8:1 on dark */
    /* Focus ring — always visible */
    --focus-ring:         3px solid #8b85ff;
    --focus-offset:       3px;
    /* Minimum touch target */
    --min-touch:          44px;
}
body.light {
    --text-accessible:    #1e1b4b;
    --text-dim-accessible:#374151;
    --accent-accessible:  #4338ca;
    --error-text:         #b91c1c;
    --warn-text:          #92400e;
    --success-text:       #065f46;
}

/* ── 2. FOCUS INDICATORS — replace :focus-visible globally ─ */
/* Remove outline:none from all inputs — accessibility violation */
.search-field input,
.url-input-row input,
.search-box-input input,
#zoomSlider {
    outline: none; /* handled below */
}

/* Universal visible focus ring for keyboard navigation */
:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: var(--focus-offset) !important;
    border-radius: 4px;
}

/* High-specificity overrides for elements that need special shapes */
.nav-btn:focus-visible,
.mobile-nav-btn:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: 2px !important;
    border-radius: 10px;
}
.toolbar-btn:focus-visible {
    outline: var(--focus-ring) !important;
    border-radius: 30px;
}
.upload-btn:focus-visible,
.download-btn:focus-visible {
    outline: var(--focus-ring) !important;
    border-radius: 50px;
}
.theme-toggle:focus-visible,
.lang-trigger:focus-visible,
.home-btn:focus-visible {
    outline: var(--focus-ring) !important;
    border-radius: 30px;
}
.lang-option:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: -2px !important;
    background: var(--nav-surface);
}
#mainCanvas:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: 4px !important;
}
.format-btn:focus-visible {
    outline: var(--focus-ring) !important;
    border-radius: 30px;
}
.tool-card:focus-visible {
    outline: var(--focus-ring) !important;
    border-radius: var(--r);
}
/* Inline URL / search inputs */
.url-input-row input:focus-visible,
.search-field input:focus-visible,
.search-box-input input:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: 0 !important;
    border-radius: 50px;
}
/* Zoom slider custom focus */
#zoomSlider:focus-visible {
    outline: var(--focus-ring) !important;
    outline-offset: 6px !important;
    border-radius: 4px;
}

/* ── 3. TOUCH TARGETS — WCAG 2.5.5 (minimum 44×44px) ───── */
/* .nav-btn intentionally excluded — the sidebar links are deliberately
   sized shorter than the 44px touch-target minimum per design request. */
.toolbar-btn,
.upload-btn,
.download-btn,
.home-btn,
.btn,
.format-btn,
.mobile-nav-btn,
.lang-trigger,
.lang-option,
.theme-toggle,
.search-field button,
.url-input-row button,
#loadUrlBtn,
#browseBtn,
#blankCanvasBtn,
#searchBtn {
    min-height: var(--min-touch);
    min-width:  var(--min-touch);
}
/* Extend clickable area with padding when needed */
.toolbar-btn {
    padding-top: max(6px, calc((var(--min-touch) - 1em) / 2));
    padding-bottom: max(6px, calc((var(--min-touch) - 1em) / 2));
}

/* ── 4. REDUCED MOTION — extended ─────────────────────────  */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration:       0.01ms !important;
        animation-iteration-count:1      !important;
        transition-duration:      0.01ms !important;
        scroll-behavior:          auto   !important;
    }
    /* Don't animate the lang dropdown */
    .lang-dropdown { animation: none !important; }
    /* Don't animate canvas zoom scale transform */
    .canvas-container { transition: none !important; }
    /* Don't animate toast slide */
    .toast { transition: opacity 0.01ms !important; }
}

/* ── 5. FORCED-COLORS / HIGH-CONTRAST MODE ────────────────  */
@media (forced-colors: active) {
    /* Use system colours — browser will adjust automatically */
    :root {
        --accent:       Highlight;
        --text:         ButtonText;
        --panel-bg:     Canvas;
        --nav-bg:       Canvas;
        --header-bg:    Canvas;
    }

    /* Ensure all borders are visible */
    .toolbar-btn,
    .upload-btn,
    .download-btn,
    .home-btn,
    .btn,
    .nav-btn,
    .lang-trigger,
    .theme-toggle {
        border: 2px solid ButtonText !important;
        forced-color-adjust: none;
    }

    /* Focus ring must use system Highlight */
    :focus-visible {
        outline: 3px solid Highlight !important;
    }

    /* Logo gradient text falls back to solid */
    .logo-text {
        -webkit-text-fill-color: LinkText !important;
        color: LinkText !important;
        background: none !important;
    }

    /* Modals */
    .modal { border: 2px solid ButtonText !important; }

    /* Drop zone dashed border */
    .drop-zone { border: 2px dashed ButtonText !important; }

    /* Canvas */
    .canvas-container { box-shadow: 0 0 0 2px ButtonText !important; }

    /* Toast */
    .toast { border: 2px solid Highlight !important; background: Canvas !important; color: ButtonText !important; }

    /* Tool cards */
    .tool-card { border: 2px solid ButtonText !important; }
    .tool-card:hover { border-color: Highlight !important; }

    /* Search overlay */
    .search-box { border: 2px solid ButtonText !important; }

    /* Lang dropdown */
    .lang-dropdown { border: 2px solid ButtonText !important; }

    /* SVG icons — ensure visibility */
    .nav-btn .nav-icon svg,
    .mobile-nav-btn svg,
    .toolbar-btn svg,
    .tool-card-icon svg {
        stroke: ButtonText !important;
        fill: none !important;
    }
}

/* ── 6. ARIA LIVE REGION — toast ──────────────────────────  */
/* Already has role="status" aria-live="polite" — CSS only ensures it
   is not visually hidden when active (no clip trick here) */
.toast[aria-hidden="true"] { display: none; }

/* ── 7. FORM VALIDATION — error / success states ─────────  */
/* URL input error state (set by JS via .has-error class) */
.url-input-row input.has-error {
    border-color: var(--error-text) !important;
    outline: 2px solid var(--error-text) !important;
}
.url-input-row input.has-error + .field-error {
    display: flex;
}
/* Inline error message (hidden by default, shown by JS) */
.field-error {
    display: none;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
    color: var(--error-text);
    margin-top: 4px;
    padding: 0 4px;
}
.field-error::before {
    content: '⚠';
    font-size: .85rem;
    flex-shrink: 0;
}
/* Search input live feedback */
.search-box-input.has-error {
    border-bottom-color: var(--error-text);
}
/* File size error */
.file-size-error {
    font-size: .72rem;
    color: var(--error-text);
    text-align: center;
    padding: 6px 12px;
    display: none;
}
.file-size-error.visible { display: block; }

/* ── 8. MODAL FOCUS TRAP ──────────────────────────────────  */
/* Modals already get JS focus management; CSS ensures the
   background is non-interactive when a modal is open */
.modal-bg[style*="flex"] ~ .app,
.modal-bg[style*="flex"] ~ nav {
    /* Not possible in CSS alone — handled in JS */
}
/* Modal close button always visible */
.modal .btn-ghost {
    min-width: 80px;
}

/* ── 9. TEXT RESIZING — 200% zoom ─────────────────────────  */
/* Use rem/em, not px for font sizes where possible.
   The breakpoints below handle layout at large text sizes. */
@media (min-resolution: 1dppx) {
    /* Ensure the header doesn't collapse content at 200% browser zoom */
    .header-top {
        flex-wrap: wrap;
        gap: 10px;
    }
    .header-bottom {
        flex-wrap: wrap;
    }
}

/* ── 10. COLOUR-ALONE INFORMATION — icon + text labels ─────  */
/* All toolbar buttons already have text labels (not icon-only).
   Error/success states use border + icon + text, not colour alone.
   Active nav items use box-shadow + colour (not colour alone). */

/* Ensure disabled state uses more than colour */
.download-btn:disabled,
button:disabled {
    opacity: .65;
    cursor: not-allowed;
    /* Add a visual pattern so it's not just colour */
    text-decoration-line: none;
    position: relative;
}
.download-btn:disabled::after,
button[aria-disabled="true"]::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: repeating-linear-gradient(
        -45deg,
        transparent,
        transparent 4px,
        rgba(0,0,0,.08) 4px,
        rgba(0,0,0,.08) 5px
    );
    pointer-events: none;
}

/* ── 11. COARSE POINTER (mobile/touch) ────────────────────  */
@media (pointer: coarse) {
    /* Expand all interactive elements to 44px on touch devices */
    .toolbar-btn { min-height: 44px; padding: 10px 14px; }
    .nav-btn     { min-height: 48px; }
    .format-btn  { min-height: 48px; min-width: 72px; }
    .home-btn    { min-height: 44px; padding: 10px 16px; }
    .lang-trigger{ min-height: 44px; }
    .lang-option { padding: 12px 18px; } /* larger tap area */
    #zoomSlider  { height: 20px; } /* easier to grab */
    #zoomSlider::-webkit-slider-thumb { width: 24px; height: 24px; }
    #zoomSlider::-moz-range-thumb     { width: 24px; height: 24px; }

    /* Increase font legibility on small screens */
    .nav-btn .nav-label { font-size: .9rem; }
    .toolbar-btn        { font-size: .82rem; }
}

/* ── 12. SCREEN-READER HELPERS ────────────────────────────  */
/* Already defined: .sr-only.
   Adding a visible-when-focused variant for skip links. */
.sr-only-focusable {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0);
    white-space: nowrap; border: 0;
}
.sr-only-focusable:focus,
.sr-only-focusable:active {
    position: static;
    width: auto; height: auto;
    overflow: visible; clip: auto;
    white-space: normal;
    margin: 0;
}

/* Skip link — already exists but make it more prominent */
.skip-link {
    background: var(--accent-accessible);
    color: #fff;
    font-size: 1rem;
    padding: 12px 24px;
    border: 2px solid #fff;
    box-shadow: 0 4px 12px rgba(0,0,0,.4);
    z-index: 10000;
}
.skip-link:focus { left: 12px; top: 12px; }

/* Multiple skip links */
.skip-links {
    position: absolute;
    top: 0; left: 0;
    z-index: 10000;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* ── 13. COGNITIVE / DYSLEXIA ACCESSIBILITY ───────────────  */
/* Adequate line-height, letter-spacing, paragraph spacing */
body {
    line-height: 1.6; /* was implicit — now explicit */
}
p, .article-content p, .workspace-content p {
    line-height: 1.65;
    max-width: 72ch; /* optimal reading line length */
}
/* Avoid all-caps for reading text (labels only, not body text) */
.info-lbl {
    font-size: .6rem; /* slightly larger — was .55rem — easier to read */
}
/* Tool card descriptions — adequate size */
.tool-card-desc {
    font-size: .78rem; /* was .75rem */
    line-height: 1.5;
}
/* Empty state text */
.empty-state p {
    font-size: .8rem; /* was .75rem */
    line-height: 1.5;
}

/* ── 14. CANVAS FALLBACK ─────────────────────────────────  */
/* When canvas is not supported / JS fails, show a text alternative */
.canvas-fallback {
    display: none;
    padding: 24px;
    text-align: center;
    color: var(--text-dim);
    font-size: .88rem;
    line-height: 1.6;
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    background: var(--panel-bg);
}
.no-canvas .canvas-fallback { display: block; }
.no-canvas #mainCanvas      { display: none; }

/* ── 15. VISIBLE BUTTON STATES (not just colour) ──────────  */
.toolbar-btn:active,
.upload-btn:active,
.download-btn:active,
.nav-btn:active,
.format-btn:active,
.home-btn:active {
    transform: scale(0.97);
    box-shadow: inset 0 2px 4px rgba(0,0,0,.3);
}

/* ── 16. LOADING / BUSY STATE ────────────────────────────  */
[aria-busy="true"] {
    cursor: progress;
    opacity: .7;
}
[aria-busy="true"]::after {
    content: '';
    display: inline-block;
    width: 12px; height: 12px;
    border: 2px solid var(--accent);
    border-top-color: transparent;
    border-radius: 50%;
    animation: pie-spin .6s linear infinite;
    margin-left: 8px;
    vertical-align: middle;
}
@media (prefers-reduced-motion: reduce) {
    [aria-busy="true"]::after { animation: none; content: '…'; border: none; }
}
@keyframes pie-spin {
    to { transform: rotate(360deg); }
}

/* ── 17. CONTRAST RATIO OVERRIDES (dark mode) ────────────  */
/* --text-dimmer (#3a3a52) fails on #1a1614 — replaced in labels */
.info-lbl     { color: var(--text-dim-accessible); }
.empty-state  { color: var(--text-dim-accessible); }
.panel-heading p { color: var(--text-dim-accessible); }
.nav-section-label { color: var(--text-dim-accessible); }
.article-content p { color: var(--text-dim-accessible); }
.tool-card-desc    { color: var(--text-dim-accessible); }
.workspace-content { color: var(--text-dim-accessible); }
.search-result-desc { color: var(--text-dim-accessible); }
/* Don't apply in light mode where original values pass */
body.light .info-lbl,
body.light .empty-state,
body.light .article-content p,
body.light .tool-card-desc,
body.light .workspace-content,
body.light .search-result-desc {
    color: var(--text-dim);
}

/* ── 18. ICON-ONLY BUTTONS — always require aria-label ───  */
/* Theme toggle has no text — ensure size and ring */
.theme-toggle {
    min-width:  44px;
    min-height: 44px;
}

/* ── 19. DROPDOWN / POPUP ACCESSIBLE POSITIONING ─────────  */
/* Ensure language dropdown stays within viewport */
.lang-dropdown {
    max-height: 80vh;
    overflow-y: auto;
}

/* ── 20. PRINT STYLES ────────────────────────────────────  */
@media print {
    header, .icon-nav, .right-panel, .mobile-nav,
    .lang-switcher, .search-overlay, .modal-bg,
    .toolbar-btn, .download-btn, .home-btn,
    .theme-toggle, .zoom-strip, .site-footer { display: none !important; }

    .app { display: block !important; }
    .workspace { width: 100% !important; }
    .canvas-wrapper { max-height: none !important; }
    body { background: #fff !important; color: #000 !important; }
    .article-area { border: 1px solid #ccc; }
}

/* ── 21. SITE FOOTER — sitemap ──────────────────────────── */
.site-footer {
    background: var(--nav-surface);
    border-top: 1px solid var(--panel-border);
    padding: 32px 24px 0;
    margin-top: 24px;
    font-size: 0.85rem;
    color: var(--text-dim);
}
.site-footer-inner {
    max-width: 1100px;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 32px 48px;
    justify-content: space-between;
    padding-bottom: 28px;
}
.site-footer-brand {
    flex: 1 1 220px;
    max-width: 320px;
}
.site-footer-name {
    display: block;
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text);
    margin-bottom: 6px;
}
.site-footer-tagline {
    margin: 0;
    line-height: 1.5;
}
.site-footer-sitemap {
    flex: 2 1 320px;
    display: flex;
    flex-wrap: wrap;
    gap: 32px 48px;
}
.site-footer-col ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.site-footer-heading {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
    color: var(--text);
    margin: 0 0 12px;
}
.site-footer-col a {
    color: var(--text-dim);
    text-decoration: none;
    transition: var(--tr);
}
.site-footer-col a:hover,
.site-footer-col a:focus-visible {
    color: var(--accent);
    text-decoration: underline;
}
.site-footer-bottom {
    max-width: 1100px;
    margin: 0 auto;
    padding: 16px 0;
    border-top: 1px solid var(--panel-border);
    font-size: 0.75rem;
    text-align: center;
}

@media (max-width: 640px) {
    .site-footer-inner { flex-direction: column; gap: 24px; }
    .site-footer-sitemap { gap: 24px 32px; }
}
