      /* Panel width is a TWO-var system:
         --klar-panel-open-width — the user's width (pre-paint restore + the
           resizer write this; never touched by hide/show)
         --klar-panel-width      — the EFFECTIVE width everything derives
           from: aside width, the no-iframe content column (html margin) and
           --klar-vw. 0 when the panel is hidden. Registered as a <length> so
           the hide/show TOGGLE can transition it — one animated var reflows
           the entire layout through the same calc pipeline as a resize drag.
           The transition is gated on html.klar-panel-anim (toggle-time only),
           so dragging stays instant. */
      @property --klar-panel-width {
        syntax: "<length>";
        inherits: true;
        initial-value: 260px;
      }
      :root {
        --klar-panel-width: var(--klar-panel-open-width, 260px);
      }
      html[data-klar-panel-closed] {
        --klar-panel-width: 0px;
      }
      html.klar-panel-anim {
        transition: --klar-panel-width 150ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      /* LEFT (Pages) panel — the same two-var + toggle-time transition
         system as the right panel, replicating Klar Core's sections panel
         collapse (width → 0, 150ms ease). */
      @property --klar-left-width {
        syntax: "<length>";
        inherits: true;
        initial-value: 0px;
      }
      :root {
        --klar-left-width: 0px;
      }
      html[data-klar-pages-open] {
        --klar-left-width: var(--klar-left-open-width, 224px);
      }
      html.klar-left-anim {
        transition: --klar-left-width 150ms cubic-bezier(0.4, 0, 0.2, 1), --klar-panel-width 150ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      /* Chrome uses Klar's own theme tokens (emitted into klar-editor-panel.css by
       Tailwind's @theme), so the demo matches the real editor's colors exactly. */
      #app,
      #app * {
        box-sizing: border-box;
      }
      /* Pin the whole app to the viewport — only inner regions (page, panel) scroll. */
      html:not([data-klar-no-iframe]),
      html:not([data-klar-no-iframe]) body {
        height: 100%;
      }
      html:not([data-klar-no-iframe]) body {
        margin: 0;
        color: var(--color-foreground);
        background: var(--color-surface);
        height: 100vh;
        overflow: hidden;
      }
      /* Flex column lives on a wrapper, not <body>, so the root stays a plain
         block (no flex overlay cluttering <body> in DevTools). */
      #app {
        height: 100%;
        display: flex;
        flex-direction: column;
        /* color baseline lives here (not on body): in no-iframe mode the
           <body> belongs to the page being edited */
        color: var(--color-foreground);
      }
      /* Font smoothing is inherited, so in no-iframe mode a site's
         `body { -webkit-font-smoothing: antialiased }` reaches the chrome —
         reset it on every chrome root (Klar doesn't use antialiased). The
         tooltip/confirm dialog live outside #app as body children, hence the
         second selector. */
      #app,
      [data-klar-host-chrome] {
        -webkit-font-smoothing: auto;
        -moz-osx-font-smoothing: auto;
      }
      /* Header skeleton — mirrors Klar's Toolbar: h-[60px] px-4 pl-3 bg-surface
         border-b border-edge, brand left / actions right (gap-2.5). */
      #app header {
        height: 60px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 16px 0 12px;
        background: var(--color-surface);
        border-bottom: 1px solid var(--color-edge);
        flex: 0 0 auto;
        position: relative;
      }
      /* Edit-count pill — centered in the header, exactly as Klar's toolbar. */
      #app .edit-badge {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        display: inline-flex;
        align-items: center;
        padding: 3px 10px;
        font-size: 11px;
        font-weight: 600;
        background: var(--color-surface-hover);
        color: var(--color-muted);
        border-radius: 9999px;
        pointer-events: none;
      }
      #app .brand,
      #app .actions {
        display: flex;
        align-items: center;
        gap: 10px;
      }
      #app .brand img {
        display: block;
      }
      /* The load-live-site icon and Apply edits use Klar's LITERAL toolbar classes
         (from klar-editor-panel.css) so they're pixel-identical — same text-sm rem
         sizing against Klar's 13px root and the same system font stack. Only the
         icon's active state needs a hook the class string can't express. */
      #app #toggleurl.active {
        background: var(--color-secondary);
        color: #fff;
      }
      /* Collapsible URL bar — toggled by the globe icon. */
      #app .urlbar {
        display: flex;
        gap: 8px;
        padding: 10px 14px;
        border-bottom: 1px solid var(--color-edge);
        background: var(--color-surface);
        flex: 0 0 auto;
      }
      #app .urlbar input {
        flex: 1 1 auto;
        min-width: 0;
        background: var(--color-base);
        color: var(--color-foreground);
        border: 1px solid var(--color-edge);
        border-radius: 8px;
        padding: 6px 10px;
        font: inherit;
        font-size: 12px;
        outline: none;
      }
      #app .urlbar input:focus {
        border-color: var(--color-primary);
      }
      #app .urlbar button {
        flex: 0 0 auto;
        font: inherit;
        font-size: 12px;
        padding: 6px 14px;
        border-radius: 8px;
        border: 1px solid var(--color-edge);
        background: var(--color-secondary);
        color: var(--color-foreground);
        cursor: pointer;
      }
      #app .urlbar button:hover {
        opacity: 0.85;
      }
      /* Saved-sites dropdown — same look as the gray buttons, with its own
         chevron (appearance:none kills the native one). Long urls ellipsize. */
      #app .urlbar select {
        flex: 0 0 auto;
        max-width: 220px;
        font: inherit;
        font-size: 12px;
        padding: 6px 26px 6px 14px;
        border-radius: 8px;
        border: 1px solid var(--color-edge);
        background-color: var(--color-secondary);
        color: var(--color-foreground);
        cursor: pointer;
        appearance: none;
        -webkit-appearance: none;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: right 10px center;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
      }
      #app .urlbar select:hover {
        opacity: 0.85;
      }
      /* Icon-only remove-site × — same gray button, square-ish */
      #app #removesite {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 6px 9px;
        color: var(--color-muted, #999);
      }
      #app #removesite:hover {
        color: var(--color-foreground);
      }
      #app #removesite[hidden] {
        display: none;
      }

      /* ── Pages panel (left) — Klar Core's SectionsPanel replica ───────
         Outer collapses via the width var (overflow clips); the inner column
         keeps its full width so content never rewraps mid-animation — the
         same model as the right panel's collapse. */
      #app #pagespanel {
        width: var(--klar-left-width, 0px);
        overflow: hidden;
        flex: 0 0 auto;
        height: 100%;
      }
      #app #pagespanelcol {
        width: var(--klar-left-open-width, 224px);
        height: 100%;
        display: flex;
        flex-direction: column;
        background: var(--color-surface);
        border-right: 1px solid var(--color-edge);
      }
      /* tab strip — Core's: 11px uppercase, active = primary underline */
      #app #ptabs {
        display: flex;
        border-bottom: 1px solid var(--color-edge);
        flex-shrink: 0;
      }
      #app #ptabs .ptab {
        /* Core: flex-1 py-2 text-[11px] font-medium uppercase tracking-[0.5px] */
        flex: 1;
        padding: 8px 0;
        font-family: inherit;
        font-size: 11px;
        font-weight: 500;
        line-height: 1.5;
        letter-spacing: 0.5px;
        text-transform: uppercase;
        cursor: pointer;
        /* Core renders NO underline: its border-none utility neutralizes the
           active border-b-2/border-b-primary (Tailwind --tw-border-style:
           none), so the active tab differs by text color only. */
        border: none;
        background: transparent;
        color: var(--color-subtle);
        transition: color 150ms;
      }
      #app #ptabs .ptab:hover {
        color: var(--color-muted);
      }
      #app #ptabs .ptab.active {
        color: var(--color-foreground);
      }
      #app #pageslist {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        padding: 8px;
      }
      /* file rows — Core's PageRow classes translated */
      #app .prow {
        /* Core row: gap-1.5 text-[12px] rounded-lg, outer pl-2/pr-1 + inner py-6px */
        display: flex;
        align-items: center;
        gap: 6px;
        width: 100%;
        padding: 6px 4px 6px 8px;
        border: none;
        border-radius: 8px;
        background: transparent;
        color: var(--color-muted);
        font-family: inherit;
        font-size: 12px;
        font-weight: 400;
        line-height: 1.5;
        cursor: pointer;
        text-align: left;
        transition: background-color 100ms, color 100ms;
        position: relative;
      }
      #app .prow:hover {
        color: var(--color-foreground);
        background: var(--color-surface-hover);
      }
      #app .prow.current {
        color: var(--color-foreground);
        background: var(--color-surface-hover);
      }
      #app .prow svg {
        flex: 0 0 auto;
        color: var(--color-subtle);
      }
      #app .prow .pname {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      #app .prow .pdel {
        flex: 0 0 auto;
        display: none;
        align-items: center;
        justify-content: center;
        width: 18px;
        height: 18px;
        border: none;
        border-radius: 6px;
        background: transparent;
        color: var(--color-subtle);
        cursor: pointer;
        padding: 0;
      }
      #app .prow:hover .pdel {
        display: flex;
      }
      #app .prow .pdel:hover {
        color: var(--color-danger, #e5484d);
      }
      /* SECTIONS tab — Core's section list: p-4 container, gap-2 column,
         h-12 rounded-2xl rows with a 30px secondary icon chip. */
      #app #pageslist.sections-mode {
        padding: 16px;
        display: flex;
        flex-direction: column;
        gap: 8px;
      }
      #app .srow {
        display: flex;
        flex-shrink: 0;
        align-items: center;
        gap: 8px;
        height: 48px;
        padding: 0 8px;
        border: none;
        font-family: inherit;
        font-size: 12px;
        font-weight: 600;
        line-height: 1.5;
        cursor: pointer;
        border-radius: 16px;
        transition: color 150ms, background 150ms;
        text-align: left;
        width: 100%;
        background: transparent;
        color: var(--color-muted);
      }
      #app .srow:hover {
        color: var(--color-foreground);
        background: var(--color-surface-hover);
      }
      #app .srow.active {
        background: var(--color-surface-input);
        color: var(--color-foreground);
      }
      #app .srow .sicon {
        flex-shrink: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 30px;
        height: 30px;
        border-radius: 8px;
        background: var(--color-secondary);
        color: #fff;
        box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, .1);
      }
      #app .srow .slabel {
        flex: 1;
      }
      #app .pempty {
        padding: 12px 8px;
        font-size: 12px;
        line-height: 1.5;
        color: var(--color-muted);
      }
      #app #togglepages.active {
        background: var(--color-secondary);
        color: #fff;
      }
      #app main {
        display: flex;
        flex: 1 1 auto;
        min-height: 0;
      }
      #app #stage {
        flex: 1 1 auto;
        min-width: 0;
        background: #252525;
      }
      #app #editor {
        width: 100%;
        height: 100%;
        border: 0;
        background: #252525;
        display: block;
      }
      /* Draggable divider — an absolute overlay straddling the panel's left edge,
         so it takes NO layout space (no gap band). Invisible by default (only the
         aside's 1px border-left shows); highlights on hover / while dragging. */
      #app #resizer {
        position: absolute;
        left: -3px;
        top: 0;
        bottom: 0;
        width: 6px;
        z-index: 10;
        cursor: col-resize;
        background: transparent;
        transition: background 0.12s;
      }
      #app #resizer:hover,
      #app #resizer.dragging {
        background: transparent;
      }

      #app aside {
        position: relative;
        width: var(--klar-panel-width, 260px);
        flex: 0 0 auto;
        border-left: 1px solid var(--color-edge);
        display: flex;
        flex-direction: column;
        min-width: 260px;
        background: var(--color-surface);
      }
      #app [hidden] {
        display: none !important;
      }
      /* Pinned (?site=) mode — stamped on <html> by the pre-paint head script
         so the toggle never flashes before the module bundle hides it. */
      html[data-pinned] #toggleurl {
        display: none !important;
      }
      /* The editor script's injected chrome (:list/:blocks toolbars, add
         menus, bubbles — z-index 99998..100000, designed for the iframe
         where the panel can't collide) must stack BELOW the floating panel:
         cap it under the chrome's 9999 ceiling. Host chrome (tooltip,
         confirm dialog) is excluded — those must stay above the panel. */
      html[data-klar-no-iframe] [data-klar-injected]:not([data-klar-host-chrome]) {
        z-index: 9998 !important;
      }
      /* Collapsed/minimized: the resizer must not offer itself — it overhangs
         the aside's left edge by 3px (outside the overflow clip), so the
         pill was showing a col-resize cursor and its "Drag to resize" title. */
      html[data-klar-panel-closed] #app aside #resizer {
        display: none;
      }
      /* Hide panel (header toggle) — the aside collapses to width 0, exactly
         like Klar's StructuredPanel (EditorLayout's panelOpen). Stamped on
         <html> pre-paint so a closed panel never flashes in. The transition
         class is applied by app.js ONLY while toggling (Klar adds/removes
         transition-all the same way), so drag-resize stays instant. */
      html[data-klar-panel-closed] #app aside {
        /* width follows the animated --klar-panel-width (→ 0) — no width
           override here or the aside would snap while the column animates */
        min-width: 0 !important;
        border-left-width: 0;
        overflow: hidden;
      }
      #app aside.panel-anim {
        /* the animated --klar-panel-width drives the width each frame — an
           element-level width transition here would ease-chase those values
           and lag. min-width 0 so the 260px floor doesn't snap mid-animation. */
        min-width: 0;
        overflow: hidden;
      }
      /* While collapsing (and when closed), the panel's content keeps its
         full width and gets CLIPPED by the shrinking aside — Klar's collapse
         behavior. Without this the flex children shrink along and the text
         visibly rewraps mid-animation. The resizer is positioned (its own
         width) and the Show HTML modal is viewport-fixed — both excluded. */
      html[data-klar-panel-closed] #app aside > :not(#resizer):not(#outwrap),
      #app aside.panel-anim > :not(#resizer):not(#outwrap) {
        width: var(--klar-panel-open-width, 260px);
        min-width: var(--klar-panel-open-width, 260px);
      }
      /* No-iframe mode (no-iframe.html) — stamped on <html> by that page's
         pre-paint head script. The edited page IS this page: content lives as
         direct <body> children, so the chrome turns into fixed overlays and
         the body scrolls like a normal page. Every rule is scoped to `#app >`
         so a loaded site's own <header>/<aside> is never restyled. The
         `html[…] body` compound outranks the content's own `body { … }` rule
         (0-1-1 vs 0-0-1), so the reserved header/panel space holds regardless
         of load order. */
      /* The editor script hides the page scrollbar (same look as the iframe),
         but its style is injected only when the module runs — hide it from
         the FIRST paint here instead, or it flashes in for ~200ms. The
         attribute is stamped by the pre-paint head script, before this sheet
         applies. Scrolling itself still works.
         The header offset is reserved on <html>, NOT as body padding — body
         padding would override the page's own (a page's `body { padding:
         56px 24px }` must survive intact). The panel column IS reserved
         (html margin-right), giving a static side-by-side layout like the
         iframe pages — viable because vw units in the content's CSS are
         REWRITTEN at inject time to calc(var(--klar-vw) * N): vw always
         measures the real viewport, so without the rewrite every 100vw
         layout would overflow by the panel's width. --klar-vw derives from
         the panel-width var, so dragging the resizer reflows the site
         correctly live. Known gap: @media breakpoints still evaluate against
         the real viewport (media queries can't use var()). */
      html[data-klar-no-iframe] {
        scrollbar-width: none;
        margin-right: var(--klar-panel-width, 260px);
        margin-left: var(--klar-left-width, 0px);
        --klar-vw: calc((100vw - var(--klar-panel-width, 260px) - var(--klar-left-width, 0px)) / 100);
        /* the header eats --klar-header-h of height the same way the panel
           eats width — the iframe pages get this by shrinking the iframe.
           The "Hide Klar header" setting zeroes the var (data-klar-no-header)
           and every derived offset — spacer, vh rewrite, fixed-nav bumps,
           chrome tops — follows it live. */
        --klar-header-h: 60px;
        --klar-vh: calc((100vh - var(--klar-header-h, 60px)) / 100);
        /* Klar's canvas tone on the root: with html carrying its own
           background, the body's background stops propagating to the canvas,
           so overscroll and the area outside the content column read as
           editor canvas (same #252525 as the iframe pages' #stage) instead
           of leaking the site's body color. */
        background-color: #252525;
      }
      html[data-klar-no-iframe]::-webkit-scrollbar {
        display: none;
      }
      /* "Hide Klar header" (settings): zero the band, drop the bar */
      html[data-klar-no-iframe][data-klar-no-header] {
        --klar-header-h: 0px;
      }
      html[data-klar-no-iframe][data-klar-no-header] #app > header {
        display: none;
      }
      html[data-klar-no-iframe]::before {
        /* flow spacer for the 60px fixed header: content starts below it and
           the page's own top spacing applies from there — same geometry the
           page gets inside the iframe (whose top edge sits below the header) */
        content: "";
        display: block;
        height: var(--klar-header-h, 60px);
      }
      html[data-klar-no-iframe] #app {
        display: contents; /* children position themselves */
      }
      html[data-klar-no-iframe] #app > header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 999;
      }
      html[data-klar-no-iframe] #app > .urlbar {
        position: fixed;
        top: var(--klar-header-h, 60px);
        left: 0;
        right: 0;
        z-index: 2147480000;
      }
      html[data-klar-no-iframe] #app > aside {
        position: fixed;
        top: var(--klar-header-h, 60px);
        right: 0;
        bottom: 0;
        z-index: 9999;
      }
      html[data-klar-no-iframe] #app > #pagespanel {
        position: fixed;
        top: var(--klar-header-h, 60px);
        left: 0;
        bottom: 0;
        z-index: 998;
        height: auto;
      }
      /* ── Floating-panel mode (KLAR_EDITOR_CONFIG.floatingPanel, or
         ?panel=floating|column override) — the panel is a draggable glass
         card OVER the page instead of a reserved column. The column
         machinery is untouched and fully switchable back: this mode just
         zeroes the reservation (--klar-vw returns to true 1vw — the unit
         rewrite still runs but becomes identity) and restyles the aside.
         app.js owns drag/dock/pill behavior; position persists in LS. */
      html[data-klar-no-iframe][data-klar-floating] {
        margin-right: 0;
        /* the LEFT (Pages) panel is a reserved column in every mode — only
           the right panel floats. Left width 0 → identity (true 1vw). */
        --klar-vw: calc((100vw - var(--klar-left-width, 0px)) / 100);
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside {
        /* 260px default in EVERY standalone mode (floating, static column,
           iframe) — a user-resized width still wins via --klar-panel-open-width */
        width: var(--klar-panel-open-width, 260px);
        /* position defaults come from vars so the pre-paint head script can
           restore a persisted spot BEFORE first paint (no dock-then-jump);
           app.js inline styles take over from there */
        top: var(--klar-panel-top, calc(var(--klar-header-h, 60px) + 16px));
        right: var(--klar-panel-r, 16px);
        bottom: auto;
        left: var(--klar-panel-left, auto);
        /* hug the current content — empty state stays compact, selecting an
           element grows the card to its widget, capped at the viewport (the
           pane scrolls beyond that). interpolate-size lets the height
           animate to/from auto (no-op where unsupported). */
        height: auto;
        /* exactly the settled empty-state height (tab strip + "Click an
           element…" pane), so the deferred panel mount changes NOTHING on
           load — the card paints once, at its final size */
        min-height: 188px;
        /* the cap follows the card's own top offset (app.js mirrors every
           top it sets into --klar-panel-top), so a card flown/dragged lower
           on the page never runs past the viewport bottom */
        max-height: calc(100vh - var(--klar-panel-top, calc(var(--klar-header-h, 60px) + 16px)) - 16px);
        interpolate-size: allow-keywords;
        min-width: 0;
        border: 1px solid var(--color-edge);
        border-radius: 14px;
        box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
        overflow: hidden;
        /* glass fill + blur live on ::before — backdrop-filter on the aside
           itself would trap the viewport-fixed dialogs (containing block) */
        background: transparent;
        /* keep the card permanently composited: when the tooltip (huge
           z-index, overlapping) appears, Chromium re-layerizes the card and
           GPU-paints its FIRST frame without the rounded clip — a one-frame
           square flash on every tooltip (screencast-verified, 3/77 frames →
           0 with this). will-change: opacity promotes the layer WITHOUT
           creating a containing block, so the fixed-position dialogs inside
           the shadow root stay full-viewport. */
        will-change: opacity;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside::before {
        content: "";
        position: absolute;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        border-radius: inherit;
        clip-path: inset(0 round 14px);
        background: color-mix(in srgb, var(--color-surface) 90%, transparent);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
      }
      /* Bookend window-chrome controls (follow / minimize) — floating card
         only. Styled as furniture, not buttons: no fills, subtle color,
         hover-revealed with the card so the resting strip stays pristine.
         The two fixed-width ends flank the flex-1 tabs symmetrically. */
      #app .tabs .winctl {
        display: none;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .tabs .winctl,
      html[data-klar-no-iframe] #app > aside .tabs #settingstoggle {
        display: flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        width: 30px;
        align-self: stretch;
        padding: 0;
        background: transparent;
        border: none;
        cursor: pointer;
        color: var(--color-subtle);
        opacity: 0.35;
        transition: opacity 150ms, color 150ms;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside:hover .tabs .winctl,
      html[data-klar-no-iframe] #app > aside:hover .tabs #settingstoggle {
        opacity: 1;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .tabs .winctl:hover,
      html[data-klar-no-iframe] #app > aside .tabs #settingstoggle:hover {
        color: var(--color-foreground);
      }
      /* follow is a TOGGLE — when active it reads exactly like hover (white,
         full strength) even at rest: the hover-reveal ghosting must not dim
         a selected state */
      html[data-klar-no-iframe][data-klar-floating] #app > aside .tabs #followtoggle.active,
      html[data-klar-no-iframe] #app > aside .tabs #settingstoggle.active {
        color: var(--color-foreground);
        opacity: 1;
      }
      /* Settings view (gear bookend) — borrows the pane in place */
      #app #settingsbody {
        padding: 16px 14px;
        /* pin the chrome font — a site's own `h3 { font-family }` rule
           matches these plain elements and leaks serif into the view */
        font-family: Inter, system-ui, -apple-system, sans-serif;
      }
      #app #settingsbody h3,
      #app #settingsbody p,
      #app #settingsbody label {
        font-family: inherit;
      }
      #app #settingsbody h3 {
        margin: 0 0 6px;
        font-size: 12px;
        font-weight: 600;
        color: var(--color-foreground);
      }
      #app #settingsbody h3 {
        margin-bottom: 14px;
      }
      #app .setting-row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
      }
      #app .setting-row label {
        font-size: 13px;
        font-weight: 500;
        color: rgba(255, 255, 255, 0.7);
        cursor: pointer;
      }
      #app .setting p {
        margin: 6px 0 0;
        font-size: 11px;
        line-height: 1.5;
        color: rgba(255, 255, 255, 0.4);
      }
      /* air between stacked settings — each block's heading needs room */
      #app .setting + .setting {
        margin-top: 18px;
      }
      /* Site controls in settings — the header's actions, panel-sized.
         Same look as the urlbar's controls (base input, secondary buttons). */
      #app .setting-load {
        display: flex;
        gap: 8px;
        margin-top: 8px;
      }
      /* the Saved sites sub-heading follows the load row — needs its own air */
      #app #s-siteslabel {
        margin-top: 14px;
      }
      #app .setting-load input,
      #app .setting-load select {
        flex: 1 1 auto;
        min-width: 0;
        background: var(--color-base);
        color: var(--color-foreground);
        border: 1px solid var(--color-edge);
        border-radius: 8px;
        padding: 6px 10px;
        font-size: 12px;
        outline: none;
      }
      #app .setting-load input:focus {
        border-color: var(--color-primary);
      }
      #app .setting-load select {
        background-color: var(--color-secondary);
        cursor: pointer;
        appearance: none;
        -webkit-appearance: none;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: right 10px center;
        padding-right: 26px;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
      }
      #app .setting-load button,
      #app .setting-actions button,
      #app .setting-actions a {
        display: flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        font-size: 12px;
        padding: 6px 12px;
        border-radius: 8px;
        border: 1px solid var(--color-edge);
        background: var(--color-secondary);
        color: var(--color-foreground);
        cursor: pointer;
        text-decoration: none;
      }
      #app .setting-load button:hover,
      #app .setting-actions button:hover,
      #app .setting-actions a:hover {
        opacity: 0.85;
      }
      #app .setting-actions {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        margin-top: 12px;
      }
      /* the iOS-style switch — Klar core's SetupForm toggle, verbatim:
         w-9 h-5 rounded-full, bg-primary when on, white 14px knob 3px→18px */
      #app .switch {
        position: relative;
        flex: 0 0 auto;
        width: 36px;
        height: 20px;
        padding: 0;
        border: none;
        border-radius: 9999px;
        background: rgba(255, 255, 255, 0.2);
        cursor: pointer;
        transition: background-color 150ms;
      }
      #app .switch[aria-checked="true"] {
        background: var(--color-primary);
      }
      #app .switch span {
        display: block;
        width: 14px;
        height: 14px;
        border-radius: 50%;
        background: #fff;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
        transform: translateX(3px);
        transition: transform 150ms;
      }
      #app .switch[aria-checked="true"] span {
        transform: translateX(18px);
      }
      /* the tab strip doubles as the drag handle (buttons stay clickable);
         it keeps the solid surface it sat on before the glass card */
      html[data-klar-no-iframe][data-klar-floating] #app > aside .tabs {
        cursor: grab;
        background: var(--color-surface);
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside.klar-dragging {
        transition: none !important;
        cursor: grabbing;
      }
      /* Corner resize handles — floating card only (the column keeps its
         single edge resizer). Invisible hotspots with window-style cursors,
         above the edge resizer (10) and the tab strip. */
      #app aside .klar-rz {
        display: none;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .klar-rz {
        display: block;
        position: absolute;
        width: 14px;
        height: 14px;
        /* above #panel: it carries data-klar-injected, so the chrome cap
           rule stamps it z-index 9998 (z applies to flex items even when
           static) — the bottom handles sat underneath at 11 */
        z-index: 9999;
        background: transparent;
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .klar-rz[data-c="nw"] { top: 0; left: 0; cursor: nwse-resize; }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .klar-rz[data-c="ne"] { top: 0; right: 0; cursor: nesw-resize; }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .klar-rz[data-c="sw"] { bottom: 0; left: 0; cursor: nesw-resize; }
      html[data-klar-no-iframe][data-klar-floating] #app > aside .klar-rz[data-c="se"] { bottom: 0; right: 0; cursor: nwse-resize; }
      /* minimized: no resize affordance (same as the edge resizer) — must
         out-specify the floating show rule above, which carries one more
         attribute selector */
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside .klar-rz {
        display: none;
      }
      /* manual corner resize is instant, like the strip drag */
      html[data-klar-no-iframe][data-klar-floating] #app > aside.klar-resizing {
        transition: none !important;
      }
      /* height animates only from the first element click on (klar-ready) —
         the panel's deferred first mount otherwise ANIMATES its initial
         settle, a visible flicker on load. The empty-state min-height floor
         lifts at the same moment: it only exists so the card is BORN at its
         settled size, and compact widgets (a lone Class field) are shorter
         than it — the floor would leave dead space under them. */
      html[data-klar-no-iframe][data-klar-floating] #app > aside.klar-ready {
        transition: height 150ms cubic-bezier(0.4, 0, 0.2, 1);
        min-height: 0;
      }
      /* auto-positioning flight to the clicked element (app.js adds the
         class for the move's duration; height stays animated) */
      html[data-klar-no-iframe][data-klar-floating] #app > aside.klar-flying {
        transition: left 200ms cubic-bezier(0.4, 0, 0.2, 1), top 200ms cubic-bezier(0.4, 0, 0.2, 1), height 150ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      html[data-klar-no-iframe][data-klar-floating] #app > aside.panel-anim {
        transition: width 150ms cubic-bezier(0.4, 0, 0.2, 1), height 150ms cubic-bezier(0.4, 0, 0.2, 1), border-radius 150ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      /* minimize: the card scales down UNIFORMLY toward the corner (a
         transform keeps every corner converging and the aspect intact —
         animating the box gave a lopsided tall sliver) with a slight fade.
         Transform is animation-time only, so the fixed dialogs' containing
         block is untouched when it matters. */
      html[data-klar-no-iframe][data-klar-floating] #app > aside.klar-minimizing {
        /* opacity values come inline from app.js — the class is used in BOTH
           directions (minimize fade-out, restore fade-in) */
        transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1), opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
        pointer-events: none;
      }
      /* collapsed → a floating pill at the card's position; click reopens */
      html[data-klar-no-iframe][data-klar-floating] #app > aside #cfg {
        min-height: 320px;
      }
      /* the Editable Elements pane keeps the solid surface it sat on before
         the glass card (the textarea's own --color-base is unchanged) */
      html[data-klar-no-iframe][data-klar-floating] #app > aside #cfgwrap,
      html[data-klar-no-iframe][data-klar-floating] #app > aside #settingswrap {
        background: var(--color-surface);
      }
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside {
        /* exactly the header's icon button: p-2 + 16px icon, rounded-lg,
           surface-input — plus a shadow for separation over page content */
        width: 32px !important;
        min-width: 32px !important;
        /* !important: an inline height from a corner resize must not
           stretch the pill */
        height: 32px !important;
        min-height: 32px !important; /* the card's empty-state floor must not stretch the pill */
        /* 12px, not the header's 8px: on 1x displays (most users) 8px on a
           32px box aliases into near-square — this reads clearly rounded */
        border-radius: 10px;
        border: none;
        background: var(--color-surface-input);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
        cursor: pointer;
      }
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside:hover {
        background: var(--color-secondary);
      }
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside::before {
        display: none; /* icon button is solid — no glass layer */
      }
      /* NO display:none on the children — the img/svg quick-pick dialogs
         portal into the panel's shadow root and must stay renderable while
         minimized (position:fixed escapes the pill's overflow clipping, the
         same way the column mode's width-0 collapse worked). The clipped
         content is covered by the pill face below. */
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside {
        overflow: hidden;
      }
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside::after {
        content: "";
        position: absolute;
        inset: 0;
        /* solid face: covers the clipped panel content under the icon;
           the aside's overflow:hidden + border-radius clips it round */
        background: var(--color-surface-input) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23bbb' stroke-width='1.5'%3E%3Crect x='1.5' y='1.5' width='13' height='13' rx='2'/%3E%3Cpath d='M10.5 1.5v13'/%3E%3C/svg%3E") center / 16px no-repeat;
      }
      html[data-klar-no-iframe][data-klar-floating][data-klar-panel-closed] #app > aside:hover::after {
        background-color: var(--color-secondary);
      }
      /* Minimize-to-header (data-klar-min-header): the header's own
         hide-panel button is the minimize target and the restore control,
         so there is no pill — the closed card parks off-screen. NOT
         display:none, and NO pointer-events:none: the img/svg quick-pick
         dialogs portal into the panel's shadow root, render position:fixed
         at viewport coords (will-change:opacity creates no containing
         block, so they escape the aside), and must stay clickable. */
      html[data-klar-no-iframe][data-klar-floating][data-klar-min-header][data-klar-panel-closed] #app > aside {
        left: -9999px !important;
        right: auto !important;
        box-shadow: none;
      }
      /* Content CSS is demoted into the klar-content layer, so chrome rules
         win wherever one exists. These pin the fundamentals nothing else
         declares — a site's `svg { fill:#000 }` / `img { opacity:0 }` must
         not blank the chrome's icons. The fill/stroke pin is limited to the
         authored stroke icons; panel icons mix fill- and stroke-based. */
      html[data-klar-no-iframe] #app svg,
      html[data-klar-no-iframe] #app img {
        visibility: visible;
        opacity: 1;
      }
      /* A site's element rules (`h2 { font-family: serif; letter-spacing }`)
         reach any chrome element the chrome declares nothing for — e.g. the
         Show HTML overlay's heading. Pin the inheritable text properties on
         ALL chrome text elements at ZERO specificity (:where): every real
         chrome rule still wins, content rules never apply. */
      html[data-klar-no-iframe] #app :where(h1, h2, h3, h4, h5, h6, p, a, span, label, strong, em, small, li, button, input, textarea, select, code, pre, div) {
        font-family: inherit;
        letter-spacing: normal;
        text-transform: none;
        text-shadow: none;
      }
      html[data-klar-no-iframe] #app > header svg,
      html[data-klar-no-iframe] #app > .urlbar svg,
      html[data-klar-no-iframe] #app #outwrap svg {
        fill: none;
        stroke: currentColor;
      }
      /* The editor's injected style forces `a { cursor: text !important }`
         (click-to-edit on content links) — content-only intent that reaches
         the chrome's anchor buttons here. Counter with equal !important;
         higher specificity wins. */
      html[data-klar-no-iframe] #app a,
      html[data-klar-no-iframe] [data-klar-host-chrome] a {
        cursor: pointer !important;
      }
      /* Tab header — mirrors Klar's StructuredPanel tabs exactly: `flex border-b
         border-edge` container; each tab `flex-1 py-2 text-[11px] font-medium
         uppercase tracking-[0.5px]`, active `text-foreground border-b-2
         border-b-primary`, inactive `text-subtle hover:text-muted`. */
      #app .tabs {
        display: flex;
        border-bottom: 1px solid var(--color-edge);
        flex: 0 0 auto;
      }
      #app .tabs .tab {
        flex: 1 1 0%;
        padding: 0.5rem 0;
        font-family: inherit;
        font-size: 11px;
        line-height: 1.5; /* match Klar's tab (py-2 + 11px/1.5) — body no longer sets it */
        font-weight: 500;
        text-transform: uppercase;
        letter-spacing: 0.5px;
        cursor: pointer;
        background: transparent;
        border: none;
        color: var(--color-subtle);
        transition: color 150ms;
      }
      #app .tabs .tab:hover {
        color: var(--color-muted);
      }
      #app .tabs .tab.active {
        color: var(--color-foreground);
      }
      #app .tabs .act {
        align-self: center;
        margin-left: auto;
        font: inherit;
        font-size: 11px;
        padding: 4px 11px;
        border-radius: 999px;
        border: 1px solid var(--color-edge);
        background: var(--color-secondary);
        color: var(--color-foreground);
        cursor: pointer;
      }
      #app .tabs .act.primary {
        background: var(--color-foreground);
        color: var(--color-base);
        border-color: var(--color-foreground);
      }
      #app .tabs .act:hover {
        opacity: 0.85;
      }
      #app #applycfg {
        display: none;
      }

      #app .pane {
        flex: 1 1 auto;
        overflow: auto;
        min-height: 0;
        /* NO scrollbar-width/scrollbar-color here: the standards properties
           DISABLE ::-webkit-scrollbar styling in Chrome, falling back to
           macOS overlay bars (invisible at rest). Klar core styles the
           webkit path only — same here. */
      }
      /* the pane is the panel's real scroll container — same scrollbar as
         Klar core's sidebar (its .scrollbar-panel styling, copied verbatim:
         6px, transparent track, faint thumb) */
      #app .pane::-webkit-scrollbar {
        width: 6px;
      }
      #app .pane::-webkit-scrollbar-track {
        background: transparent;
      }
      #app .pane::-webkit-scrollbar-thumb {
        background: #ffffff14;
        border-radius: 3px;
      }
      #app .pane::-webkit-scrollbar-thumb:hover {
        background: #ffffff24;
      }
      #app #cfgwrap {
        display: flex;
        flex-direction: column;
        padding: 12px 14px;
      }
      #app #cfg {
        flex: 1 1 auto;
        width: 100%;
        resize: none;
        background: var(--color-base);
        color: var(--color-foreground);
        border: 1px solid var(--color-edge);
        border-radius: 8px;
        font: 11px/1.5 var(--font-mono, ui-monospace, monospace);
        padding: 8px 10px;
        outline: none;
      }
      #app #cfg:focus {
        border-color: var(--color-primary);
      }
      /* "Show HTML" modal — an exact replica of Klar's Project Settings modal
         (src/components/SetupForm.tsx). Plain CSS mirrors the Tailwind values
         (backdrop-blur-2xl = blur(40px), rounded-3xl = 24px, etc.) since the
         standalone CSS build doesn't compile SetupForm's utility classes. */
      /* The Show HTML modal chrome (outwrap/outcard/outhead/closeout/outbody)
         is styled by Klar Core's LITERAL utility classes in the markup — the
         Project Settings modal's classes verbatim — so the two can't drift.
         Only the inner source view below is styled here. Small-window guard:
         the fixed 597px body may not fit, so cap the card and let the body
         shrink (Core runs in a viewport-sized app; this page can be tiny). */
      /* The modal moved OUT of the aside: the aside's will-change:opacity
         makes it a backdrop root, which killed the card's backdrop blur (it
         could only sample the aside's own transparent content, so the page
         showed through SHARP). As a sibling it needs to outrank the aside
         (9999) and the urlbar in the chrome z-ladder. */
      #app #outwrap {
        z-index: 2147480001;
      }
      #app #outcard {
        max-height: calc(100vh - 48px);
        /* flex column (Core's is block) purely so the 597px body can SHRINK
           under the cap — no visual difference at full size */
        display: flex;
        flex-direction: column;
      }
      #app #outbody {
        min-height: 0;
        flex-shrink: 1;
        /* Core's Project Settings body renders TALLER than its h-[597px]
           content: the sidebar (16 nav items + pt-4) stretches the flex row.
           Match the RENDERED height, not the class — 626 eyeballed exact
           against Core side-by-side (user-calibrated). */
        height: 626px;
      }
      #app #outhead h2 {
        margin: 0;
      }
      #app #outnav {
        width: 180px;
        flex-shrink: 0;
        /* the side nav is BACK: two entries now (HTML / Data) — Core's
           Project Settings sidebar look (w-[180px] px-3 pt-4 border-r) */
        display: flex;
        flex-direction: column;
        padding: 16px 12px 0;
        border-right: 1px solid rgba(255, 255, 255, 0.1);
      }
      #app #outnav .navitem {
        display: flex;
        align-items: center;
        gap: 10px;
        width: 100%;
        margin-bottom: 2px;
        padding: 8px 12px;
        border: none;
        border-radius: 8px;
        font: 500 13px/1.5 inherit;
        background: transparent;
        color: rgba(255, 255, 255, 0.5);
        cursor: pointer;
        transition: color 150ms, background-color 150ms;
      }
      #app #outnav .navitem:hover {
        color: rgba(255, 255, 255, 0.7);
        background: rgba(255, 255, 255, 0.05);
      }
      #app #outnav .navitem.active {
        background: rgba(255, 255, 255, 0.1);
        color: #fff;
      }
      /* Data view: the heading block (Core's section-heading pattern —
         TagsPanel's h2 + description) provides the top spacing instead of
         the hidden tab row */
      #app #datahead {
        margin: 20px 24px 16px;
      }
      #app #datahead h2,
      #app #datahead p {
        margin-top: 0;
        margin-bottom: 0;
      }
      #app #datahead h2 {
        margin-bottom: 4px;
      }
      #app #outcontent {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        overflow: hidden;
      }
      /* HTML / HEAD / BODY tabs — Klar's segmented control (SetupForm's
         "Project defaults / This page" toggle). */
      #app #outtabs {
        display: flex;
        align-items: center;
        gap: 8px;
        width: fit-content;
        margin: 16px 24px 16px;
        padding: 4px;
        background: rgba(255, 255, 255, 0.05);
        border-radius: 8px;
      }
      #app #outtabs button {
        padding: 6px 12px;
        font: 500 12px/1 inherit;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        background: transparent;
        color: rgba(255, 255, 255, 0.5);
        transition: color 150ms, background-color 150ms;
      }
      #app #outtabs button:hover {
        color: rgba(255, 255, 255, 0.7);
      }
      #app #outtabs button.active {
        background: rgba(255, 255, 255, 0.15);
        color: #fff;
      }
      /* Section title — Klar's field-label style (EditorTextField in SetupForm):
         no top margin, mb-2 (8px) below. */
      #app #outtitle {
        display: none;
        margin: 0 24px 8px;
        font-size: 13px;
        font-weight: 500;
        color: rgba(255, 255, 255, 0.7);
      }
      #app #out {
        flex: 1;
        min-width: 0;
        /* a Klar input field (SetupForm's textarea look) holding the
           HTML/Data output — selectable, copy-ready */
        margin: 0 24px 20px;
        padding: 14px 16px;
        overflow: auto;
        font: 11px/1.6 var(--font-mono, ui-monospace, monospace);
        white-space: pre-wrap;
        word-break: break-word;
        color: rgba(255, 255, 255, 0.8);
        background: rgba(255, 255, 255, 0.08);
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 12px;
        outline: none;
        resize: none;
      }
      #app #out::placeholder {
        color: var(--color-muted);
        font-family: Inter, system-ui, sans-serif;
      }
      #app .muted {
        color: var(--color-muted);
      }
