/* ============================================================================
   PromptBuilder — A11Y FIXES          (Agent D — load position LAST of all)

   Registered last in $pb_stylesheets (promptbuilder.php) and additionally on the
   logged-out marketing view, because it has to win the cascade over every
   historical override pass above it.

   It contains exactly four things and nothing else:

     1. The screen-reader / hidden utility classes the semantic markup depends on.
        base.css currently ships a PROVISIONAL copy of these so the page was never
        broken while this file did not exist yet — Agent A can delete that block
        now (see the handoff in the Agent D report).
     2. Target-size corrections. Every control the health report measured under
        24x24 is brought up to WCAG 2.2 AA 2.5.8 "Target Size (Minimum)" without
        changing how anything looks at a glance.
     3. The replacement classes for the 85 inline style="" attributes that used to
        live in promptbuilder.php. Removing those is a hard precondition for ever
        serving a CSP without style-src 'unsafe-inline'.
     4. The accessible canvas outline — the keyboard/screen-reader representation
        of a canvas that is otherwise absolutely-positioned divs and SVG lines.

   It deliberately contains NO redesign. Where a token-based rule already exists
   in Agent A's stylesheets, the markup was changed to let that rule apply rather
   than a competing declaration being added here.

   Every value below uses a var(--token, fallback) pair. The fallback is not
   decoration: this file is also loaded on the logged-out marketing view, which
   ships promptbuilder.css and therefore has none of the workspace tokens.
   ========================================================================= */


/* ═══ 1. SCREEN-READER AND STATE UTILITIES ═══════════════════════════════════
   Canonical definitions. Note :not(:focus):not(:active) — an element that is
   visually hidden but focusable (the skip link, every control inside the canvas
   outline) has to become visible the moment it takes focus, or a sighted
   keyboard user loses their cursor entirely. */
.visually-hidden:not(:focus):not(:active),
.pb-visually-hidden:not(:focus):not(:active) {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Deliberately NOT !important. app.js and testpanel.js hide and show several of
   these elements by writing element.style.display directly; an inline style
   already outranks this rule, so both directions keep working. */
.is-hidden { display: none; }

.pb-skip-link {
    position: absolute;
    top: var(--space-2, 8px);
    left: var(--space-2, 8px);
    z-index: var(--z-modal-nested, 100000);
    padding: var(--space-2, 8px) var(--space-3, 12px);
    border-radius: var(--radius-md, 8px);
    background: var(--accent-solid, #6366F1);
    color: var(--text-on-accent, #FFFFFF);
    font-size: var(--fs-md, 13px);
    font-weight: var(--fw-semibold, 600);
    text-decoration: none;
    transform: translateY(-200%);
    transition: transform var(--dur-base, 0.18s) var(--ease-out, ease);
}
.pb-skip-link:focus,
.pb-skip-link:focus-visible {
    transform: translateY(0);
    color: var(--text-on-accent, #FFFFFF);
}


/* ═══ 2. TARGET SIZE — WCAG 2.2 AA 2.5.8 ═════════════════════════════════════
   The health report measured eight interactive controls under 24px. Each one
   below is the specific fix, with the reason it was under-size. */

/* The library search field is 16px tall inside a padded label, so the *label*
   was the real target and the input was not. Give the input its own height. */
#block-library-search {
    min-height: var(--hit-min, 24px);
}

/* Text-only "Clear" button: 27x13. Padding, not font size, closes the gap. */
.library-clear-search {
    min-height: var(--hit-min, 24px);
    padding-inline: var(--space-2, 8px);
}

/* Checkboxes and radios rendered at the UA default 13x13. Sizing the control
   itself (rather than relying on the wrapping label) is what makes the target
   real for pointer users, not just for hit-testing heuristics. */
.consent-option input[type="checkbox"],
.test-panel .prompt-type-label input[type="radio"],
.prompt-type-label input[type="radio"] {
    width: var(--hit-min, 24px);
    height: var(--hit-min, 24px);
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent-solid, #6366F1);
    cursor: pointer;
}
.consent-option input[type="checkbox"]:disabled,
.prompt-type-label input[type="radio"]:disabled { cursor: not-allowed; }

/* The temperature slider's track is 6px tall, so the whole input measured 6px.
   Height goes on the input; the visible track stays 6px via the pseudo-elements,
   so this is a hit-area change only — it does not alter the look. */
.range-slider {
    min-height: var(--hit-min, 24px);
    background: transparent;
    cursor: pointer;
}
.range-slider::-webkit-slider-runnable-track { height: 6px; }
.range-slider::-moz-range-track { height: 6px; }

/* The zoom readout became a real <button> (it has always been clickable — it
   resets zoom — but it was a <span>, so it was unreachable by keyboard and
   invisible to assistive tech). Strip the UA button chrome and restore contrast:
   rgba(255,255,255,0.4) on the top bar failed AA, which axe flagged. */
button.tb-zoom-display {
    appearance: none;
    background: transparent;
    border: 0;
    font: inherit;
    font-size: var(--fs-sm, 12px);
    font-weight: var(--fw-semibold, 600);
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary, rgba(255, 255, 255, 0.72));
    min-height: var(--hit-min, 24px);
    min-width: 44px;
}
button.tb-zoom-display:hover { color: var(--text-primary, #FFFFFF); }

/* Buttons that sit inside modals were measuring 19px tall. */
.app-modal .btn,
.trial-upgrade-btn,
.trial-banner-dismiss,
.canvas-empty-btn,
.canvas-hud-btn {
    min-height: var(--hit-min, 24px);
}

/* The block library items are the primary target in the whole app. */
.block-item { min-height: var(--hit-min, 24px); }


/* ═══ 3. REPLACEMENTS FOR THE REMOVED INLINE style="" ATTRIBUTES ═════════════ */

/* ── 3a. Block library list ──────────────────────────────────────────────────
   The 41 blocks are now a real <ul>/<li> per category. app.js hides individual
   blocks while filtering by writing .block-item's style.display, so the <li>
   must collapse to nothing when its only child is hidden — which it does, but
   only once the marker is gone. */
.block-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.block-list > li { display: block; }

/* .block-item is now role="button" + tabindex="0". Keep the drag affordance as
   the resting cursor: it is still primarily a drag source. */
.block-item[role="button"] { cursor: grab; }
.block-item[role="button"]:active { cursor: grabbing; }

/* The empty state's heading moved h4 -> h3 so the outline does not skip a level
   (h1 page > h2 "Block Library" > h3). HANDOFF: library.css still targets
   `.library-empty-state h4`; retarget it and this rule can go. */
.library-empty-state h3 {
    font-size: var(--fs-md, 13px);
    margin-bottom: var(--space-1, 4px);
    color: var(--text-primary, #FFFFFF);
}

/* ── 3b. Properties panel field hints (was style="font-size:11px;color:…") ── */
.pb-field-hint {
    display: block;
    margin-top: var(--space-2, 8px);
    font-size: var(--fs-2xs, 10px);
    line-height: var(--lh-normal, 1.5);
    color: var(--text-tertiary, rgba(255, 255, 255, 0.5));
}

/* Few-shot examples needs more room than the shared textarea default.
   (was style="min-height:120px") */
.pb-textarea-tall { min-height: 120px; }

/* ── 3c. Block context menu ──────────────────────────────────────────────────
   Was one 200-character inline style on the container plus one on each item.
   app.js positions it and toggles it with style.left/top/display, so only the
   resting appearance belongs here. The two items are <button role="menuitem">
   now instead of clickable <div>s, hence the UA-chrome reset. */
.pb-context-menu {
    position: fixed;
    display: none;
    z-index: var(--z-context-menu, 10003);
    min-width: 150px;
    padding: var(--space-1, 4px) 0;
    border-radius: var(--radius-md, 8px);
    background: var(--surface-2, #15122a);
    border: 1px solid var(--border-default, rgba(255, 255, 255, 0.09));
    box-shadow: var(--elev-3, 0 4px 12px rgba(0, 0, 0, 0.4));
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}
.pb-context-menu .context-menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    width: 100%;
    min-height: var(--hit-min, 24px);
    padding: var(--space-2, 8px) var(--space-4, 16px);
    appearance: none;
    background: transparent;
    border: 0;
    font: inherit;
    font-size: var(--fs-md, 13px);
    color: var(--text-primary, #FFFFFF);
    text-align: left;
    cursor: pointer;
    transition: background var(--dur-fast, 0.12s) var(--ease-out, ease);
}
.pb-context-menu .context-menu-item:hover,
.pb-context-menu .context-menu-item:focus-visible {
    background: var(--surface-3, rgba(255, 255, 255, 0.06));
}
.pb-context-menu .context-menu-item i {
    width: 16px;
    text-align: center;
    flex-shrink: 0;
}

/* ── 3d. Pro-feature modal (was four inline styles) ────────────────────────── */
.pb-text-center { text-align: center; }
.pb-upgrade-icon {
    font-size: 40px;
    color: var(--accent-fg, #A78BFA);
    margin-bottom: var(--space-4, 16px);
}
.pb-lead {
    margin-bottom: var(--space-3, 12px);
    font-size: var(--fs-lg, 15px);
    color: var(--text-primary, #FFFFFF);
}
.pb-lead-sub {
    margin-bottom: 0;
    color: var(--text-secondary, rgba(255, 255, 255, 0.72));
}

/* ── 3e. Trial-expired upgrade wall ──────────────────────────────────────────
   58 inline styles were removed from this view. Almost all of them were
   shadowing a better, token-based rule that already existed in trial-upgrade.css
   and could never fire. Only the properties with no existing rule are restated.

   HANDOFF to Agent A: the two retargets below exist because heading levels
   changed (h2 -> h1 for the page title, h3 -> h2 for the plan names) so this
   view finally has a document outline. Fold `h1` into `.upgrade-prompt1 h2` and
   `h2` into `.pricing-card h3` in trial-upgrade.css and delete this block. */
.upgrade-prompt1 h1 {
    margin-bottom: var(--space-3, 12px);
    font-size: var(--fs-3xl, 28px);
    color: var(--text-primary, #FFFFFF);
}
.pricing-card h2 {
    margin-bottom: var(--space-2, 8px);
    font-size: var(--fs-xl, 17px);
    text-align: center;
}

/* The two plan CTAs use the site-wide .button/.button-primary classes, which do
   not exist in the workspace stylesheets at all — the inline style was the only
   thing making them look like buttons. */
.pb-up-cta {
    display: block;
    width: 100%;
    min-height: 44px;
    padding: var(--space-3, 12px) var(--space-4, 16px);
    border: 1px solid transparent;
    border-radius: var(--radius-md, 8px);
    background: var(--accent-solid, #6366F1);
    color: var(--text-on-accent, #FFFFFF);
    font-size: var(--fs-md, 13px);
    font-weight: var(--fw-semibold, 600);
    text-align: center;
    text-decoration: none;
    transition: background var(--dur-base, 0.18s) var(--ease-out, ease);
}
.pb-up-cta:hover {
    background: var(--accent-solid-hover, #4F46E5);
    color: var(--text-on-accent, #FFFFFF);
}

/* The single highlighted feature row and its gold star. `.features i` paints
   every icon green, which would have silently turned the star into a tick. */
.pb-up-feature-highlight {
    margin: var(--space-1, 4px) calc(var(--space-4, 16px) * -1);
    padding: var(--space-2, 8px) var(--space-4, 16px);
    border-radius: var(--radius-md, 8px);
    background: var(--warning-bg, rgba(255, 215, 0, 0.1));
}
.pb-up-star.pb-up-star { color: var(--warning-fg, #FFD700); }

.pb-up-note {
    margin-top: var(--space-8, 32px);
    padding: var(--space-6, 24px);
    border-radius: var(--radius-xl, 16px);
    border: 1px solid var(--border-default, rgba(255, 255, 255, 0.12));
    background: var(--surface-3, rgba(255, 255, 255, 0.05));
    text-align: center;
}
.pb-up-note-lead {
    margin-bottom: var(--space-2, 8px);
    font-size: var(--fs-lg, 15px);
    font-weight: var(--fw-semibold, 600);
    color: var(--text-primary, #FFFFFF);
}
.pb-up-note-icon {
    margin-right: var(--space-2, 8px);
    color: var(--accent-fg, #A78BFA);
}
.pb-up-note-body {
    margin: 0;
    color: var(--text-secondary, rgba(255, 255, 255, 0.72));
}

/* ── 3f. Logged-out marketing view ───────────────────────────────────────────
   These rules run WITHOUT tokens.css, so they are written to stand on their own.
   The video used an inline 56.25% padding-bottom aspect box; `aspect-ratio` does
   the same job declaratively and survives the wrapper being reused elsewhere. */
.pb-ph-badge {
    display: inline-block;
    margin-top: 20px;
    margin-bottom: 10px;
}
.pb-ph-badge img {
    display: block;
    width: 250px;
    height: 54px;
}

.pb-video-section { margin: 3rem 0; }
.pb-video-heading {
    text-align: center;
    margin-bottom: 2rem;
}
.pb-video-frame {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: 1rem;
}
.pb-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-radius: 1rem;
    object-fit: cover;
}
/* The play button used to carry pointer-events:none, which made it decorative:
   the only way to start the video was clicking the overlay div, so the video was
   unreachable by keyboard. It is a real button now; its click still bubbles to
   the overlay listener in guest-video.js, so behaviour is unchanged for mice. */
.pb-video-fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    text-align: center;
    background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
    color: #fff;
}
.pb-video-fallback h3 { margin-bottom: 0.75rem; }
.pb-video-fallback p {
    margin: 0;
    color: rgba(255, 255, 255, 0.8);
}


/* ═══ 4. THE ACCESSIBLE CANVAS OUTLINE ═══════════════════════════════════════
   The canvas is absolutely-positioned <div>s joined by SVG <line>s: to a screen
   reader it is an empty box, and to a keyboard it is unreachable. #canvas-outline
   mirrors it as a real list — every block, its content, and what it feeds into —
   and carries the two controls (Select / Connect) that make the graph operable
   without a pointer.

   It is clipped to 1px until focus enters it, then it surfaces as a panel, so a
   sighted keyboard user can see where their focus has gone. */
.pb-canvas-outline {
    position: absolute;
    top: var(--space-3, 12px);
    left: var(--space-3, 12px);
    width: 1px;
    height: 1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}
.pb-canvas-outline:focus-within {
    /* Sits below the canvas HUD, which occupies the same top-left corner, and
       above it in the stack — otherwise the HUD badge covers this panel's
       heading, which is the first thing that tells you what the panel is. */
    top: calc(var(--space-3, 12px) * 2 + 40px);
    width: min(420px, calc(100% - var(--space-6, 24px)));
    height: auto;
    max-height: 60vh;
    overflow: auto;
    clip-path: none;
    white-space: normal;
    z-index: calc(var(--z-hud, 40) + 2);
    padding: var(--space-3, 12px);
    border-radius: var(--radius-lg, 12px);
    background: var(--surface-2, #15122a);
    border: 1px solid var(--border-default, rgba(255, 255, 255, 0.12));
    box-shadow: var(--elev-3, 0 16px 32px rgba(0, 0, 0, 0.34));
}

.pb-canvas-outline-heading {
    font-size: var(--fs-2xs, 10px);
    font-weight: var(--fw-bold, 700);
    letter-spacing: var(--ls-caps, 0.14em);
    text-transform: uppercase;
    color: var(--text-tertiary, rgba(255, 255, 255, 0.5));
    margin-bottom: var(--space-2, 8px);
}
.pb-canvas-outline-status {
    font-size: var(--fs-sm, 12px);
    color: var(--text-secondary, rgba(255, 255, 255, 0.72));
    margin-bottom: var(--space-2, 8px);
}
.pb-canvas-outline-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2, 8px);
}
.pb-canvas-outline-item {
    padding: var(--space-2, 8px);
    border-radius: var(--radius-md, 8px);
    background: var(--surface-3, rgba(255, 255, 255, 0.05));
    border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
}
.pb-canvas-outline-item[data-pb-connect-source="true"] {
    border-color: var(--accent-solid, #6366F1);
}
.pb-canvas-outline-summary {
    display: block;
    font-size: var(--fs-sm, 12px);
    line-height: var(--lh-normal, 1.5);
    color: var(--text-secondary, rgba(255, 255, 255, 0.72));
    margin-bottom: var(--space-2, 8px);
}
.pb-canvas-outline-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2, 8px);
}
.pb-canvas-outline-btn {
    min-height: var(--hit-min, 24px);
    padding: var(--space-1, 4px) var(--space-2, 8px);
    appearance: none;
    border-radius: var(--radius-sm, 6px);
    border: 1px solid var(--border-default, rgba(255, 255, 255, 0.12));
    background: var(--surface-1, rgba(255, 255, 255, 0.03));
    color: var(--text-primary, #FFFFFF);
    font: inherit;
    font-size: var(--fs-xs, 11px);
    cursor: pointer;
}
.pb-canvas-outline-btn:hover { background: var(--surface-3, rgba(255, 255, 255, 0.08)); }
.pb-canvas-outline-help {
    margin-top: var(--space-3, 12px);
    font-size: var(--fs-xs, 11px);
    line-height: var(--lh-normal, 1.5);
    color: var(--text-tertiary, rgba(255, 255, 255, 0.5));
}

/* While a keyboard connection is armed, every candidate target is outlined on
   the canvas itself, so the two views agree about what is happening. */
.prompt-block.pb-connect-source {
    outline: 2px dashed var(--accent-solid, #6366F1);
    outline-offset: 3px;
}

/* The skip link lives in a <nav> so that it is inside a landmark rather than
   being the one piece of content that landmark navigation cannot reach. The nav
   itself must take up no space — its only child is absolutely positioned — but
   its line-height:0 must not be inherited by the link, or the link collapses to
   a 16px-tall target the moment it becomes visible. */
.pb-skip-nav {
    height: 0;
    line-height: 0;
}
.pb-skip-nav .pb-skip-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--hit-min, 24px);
    line-height: var(--lh-normal, 1.5);
}
/* Two skip links: the second must not sit on top of the first when focused. */
.pb-skip-nav .pb-skip-link + .pb-skip-link { left: calc(var(--space-2, 8px) + 260px); }

/* Skip targets are given tabindex="-1" so the link actually moves focus. They
   must never draw a focus ring — the user did not focus them, the link did. */
#main-canvas:focus,
#guest-main:focus,
#canvas-outline:focus { outline: none; box-shadow: none; }

/* Standalone navigational links are real targets, not prose. "Back to Homepage"
   on the trial-expired wall was 150x19. */
.back-link a,
.pb-up-back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2, 8px);
    min-height: var(--hit-min, 24px);
}

/* ============================================================
   KEYBOARD CONNECT MODE
   Gives the mouse-only connection points a visible keyboard
   equivalent: the armed source is unmistakable, and candidate
   targets read as actionable while the mode is live.
   ============================================================ */
.prompt-block.is-connect-source {
    outline: 2px solid var(--accent-solid, #4F46E5);
    outline-offset: 3px;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent-solid, #4F46E5) 22%, transparent);
}

/* While arming, make the source's outputs legible rather than hairline dots. */
.pb-connect-mode .prompt-block.is-connect-source .connection-point.output {
    transform: scale(1.35);
    background: var(--accent-solid, #4F46E5);
}

/* The block the arrow keys have landed on is the pending target. */
.pb-connect-mode .prompt-block.selected:not(.is-connect-source) {
    outline: 2px dashed var(--accent-fg, #A5B4FC);
    outline-offset: 3px;
}

.pb-connect-mode .canvas-content { cursor: crosshair; }

@media (prefers-reduced-motion: reduce) {
    .pb-connect-mode .prompt-block.is-connect-source .connection-point.output {
        transform: none;
    }
}

/* ============================================================
   MODAL STACKING SAFETY NET
   Every .modal-overlay is fixed, full-viewport and shares one
   z-index. If two are ever open at once, the one later in the
   DOM swallows all pointer events and the other is visible but
   unclickable — which is exactly what happened when the welcome
   modal and the consent gate opened together.

   The consent gate is the blocking legal gate, so it is given
   an explicitly higher layer. It can never be the one trapped
   underneath.
   ============================================================ */
#promptbuilder-consent-modal.visible { z-index: 760; }

/* A dialog that is not marked visible must never intercept
   clicks, even if a stylesheet leaves it laid out. */
.modal-overlay:not(.visible) { pointer-events: none; }
.modal-overlay.visible { pointer-events: auto; }
