body { padding: 0; margin: 0 }
#unity-container { position: fixed; width: 100%; height: 100%; top: 0; left: 0; transform: none }
#unity-canvas { width: 100%; height: 100%; background: #FFFFFF; touch-action: none }
#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
#unity-logo { width: 154px; height: 130px; background: url('halocline-logo-light.png') no-repeat center }
#unity-progress-bar-empty { margin-left: auto; margin-right: auto; width: 141px; height: 18px; margin-top: 10px; background: url('progress-bar-empty-light.png') no-repeat center }
#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-light.png') no-repeat center }
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }

/* Vuplex creates every webview iframe with an inline `background-color: white` and
   `display: block`; Unity only clears both after the webview finishes initializing
   (UIWindowBase.InitializeAsync -> SetDefaultBackgroundEnabled(false) / Visible=false),
   which during startup lands seconds later — the full-viewport home and onboarding
   iframes flashed solid white over the loading screen the whole time (AB#4579 QA).
   A stylesheet !important beats inline styles, so this holds from element creation.
   Every surface here is designed transparent; pages that want a background paint
   their own (NgHome does). */
iframe[id^="WebView-"] { background-color: transparent !important }

/* ===========================================
   RESPONSIVE BREAKPOINT SYSTEM

   Breakpoints:
   - Mobile Portrait (< 576px): Full width
   - Tablet (576px - 767px): maxWidth = 360px
   - Desktop (>= 768px): maxWidth = 480px

   All spacing: 12px (0.75rem)
   =========================================== */

:root {
    /* Breakpoint variables */
    /* 416px min: the settings editing tab's 5-option "move step increment"
       segmented button (metric 0.5cm…10cm) needs ~320px, which didn't fit the
       ~264px content box left at the old 360px min (after the settings padding)
       and forced a horizontal scrollbar before the panel reached its minimum.
       Widening the min widens the docked home window AND the toolbar (both use
       --panel-width) — AB#4427 QA. */
    --panel-min: 26rem;        /* 416px - minimum width */
    --panel-max: 30rem;        /* 480px - maximum for >= 768px */

    /* Computed panel width (defined once, reused everywhere) */
    --panel-width: clamp(var(--panel-min), 25vw, var(--panel-max));

    /* Spacing — the ONE edge margin, referenced by every surface (toolbar,
       docked home window, view controls, context menu, more panel) for both
       its screen-edge inset and the inter-surface gaps, so the spacing around
       every iframe is identical. Scaled by --ui-scale (like the pills
       themselves) so it stays proportional at every resolution rather than
       reading tighter as the UI grows on large/hi-DPI screens (15px at
       scale 1; AB#4427 QA). */
    --spacing-edge: calc(0.9375rem * var(--ui-scale, 1));   /* 15px @ scale 1 */

    /* ── Aliases onto the shared webview control tokens ────────────────────
       index.html links shared/design-tokens.css, scaling.css and controls.css
       into THIS document, so the shared vocabulary resolves here directly —
       these are var() aliases, NOT copies to keep in sync. Only --spacing-edge,
       --panel-* and --surface-shadow-slack are host-only: the webviews never
       position themselves on screen, Unity/this template does, so those have no
       shared counterpart. Radii are intentionally NOT scaled by --ui-scale (MD3). */
    --surface-pill-h: var(--ctl-height);      /* 48 */
    --surface-radius: var(--ctl-radius);      /* 12 */
    --window-shadow: var(--ctl-elevation);

    /* The toolbar is a content-height pill (--surface-pill-h). The iframe adds a
       few px of slack beyond the pill so the pill's drop shadow (finding 8) is not
       clipped by the iframe edge; the toolbar page top-aligns the pill, so the
       visible TOP gap stays == --spacing-edge. The docked home window offset is
       computed from --surface-pill-h (the real pill), NOT this padded iframe
       height, so the toolbar→home gap is unaffected by the slack. AB#4427 QA. */
    --surface-shadow-slack: calc(6px * var(--ui-scale, 1));  /* room for the pill's shadow */
    --header-height: calc(var(--surface-pill-h) + var(--surface-shadow-slack));

    /* ── Per-surface iframe box, declared ONCE ─────────────────────────────
       These win on screen: Vuplex's WebGL backend gives each iframe an inline size
       derived from its Unity RectTransform, and the `!important` rules below override
       it. So each value MUST match its reference constant in
       Assets/Next/Composition/Scripts/Installer/UIWindowBaseFactory.cs
       (Toolbar/ViewControls/ContextMenu reference px, MorePanelWindow.ComputePanelHeight)
       — a mismatch is invisible until a real WebGL build clips the surface. Check a
       change against the page's intrinsic content with
       `node ci-toolbox/ui-preview/preview.mjs --page <surface> --scale 1`.
       All scale with --ui-scale, so fixed px would clip above scale 1. */
    --surface-context-w: calc(256px * var(--ui-scale, 1));  /* transform row + 4 icon buttons */
    /* The context menu measures its own card and reports it (shared/surface-autosize.js); Unity
       writes the result here as an inline property on :root, which outranks this declaration. So
       this value governs only the frames before the page's first report. */
    --surface-context-h: calc(116px * var(--ui-scale, 1));  /* hugs the compact content */
    --surface-modehint-w: var(--surface-viewcontrols-w);    /* mode-hint banner matches the view-controls pill (AB#4957) */
    --surface-modehint-h: calc(56px * var(--ui-scale, 1));  /* two text rows, content-hugging (AB#4957) */
    --surface-notifications-w: calc(360px * var(--ui-scale, 1));  /* toast panel width (AB#6055) */
    /* The toast panel measures its stack and reports it (shared/surface-autosize.js); Unity writes
       the result here as an inline property on :root, which outranks this declaration. So this
       value — one single-line toast plus the panel's padding — governs only the frames before
       the page's first report. */
    --surface-notifications-h: calc(60px * var(--ui-scale, 1));
    --surface-viewcontrols-w: calc(347px * var(--ui-scale, 1)); /* the row's intrinsic width */
}

/* Tablet: cap the panel at the (new) minimum so it can't inflate toward the
   desktop 480px on a narrow tablet, while staying >= --panel-min (416px) so the
   clamp range isn't inverted (AB#4427 QA). */
@media (max-width: 767px) {
    :root {
        --panel-max: 26rem;  /* 416px */
    }
}

/* Mobile Portrait: full width */
@media (max-width: 575px) {
    :root {
        --panel-min: calc(100vw - 1.5rem);  /* Full width minus 2x edge margin */
        --panel-max: calc(100vw - 1.5rem);
    }
}

/* ===== Visibility toggle ===== */
.is-hidden    { display: none !important; }
.is-block     { display: block !important; }
.is-inline    { display: inline !important; }
.is-invisible { visibility: hidden !important; }
.is-visible   { visibility: visible !important; }

/* ===== Home Window Fullscreen (no space loaded) ===== */
.homewindow-fullscreen {
    position: fixed !important;
    inset: 0 !important;
    width: 100vw !important;
    height: 100dvh !important;
    border: none !important;
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147483000;
}

/* ===== Home Window Docked (space loaded) ===== */
/* top = spacing + header + spacing */
/* height = 100vh - top - spacing */
.homeWindowDocked {
    position: fixed !important;
    /* top = edge (toolbar's own top margin) + the 48px pill + a HALF edge gap to
       the toolbar (a full edge read too wide; AB#4427 QA). Uses --surface-pill-h,
       not --header-height, so the toolbar iframe's shadow slack doesn't widen
       this gap. */
    top: calc(var(--spacing-edge) + var(--surface-pill-h) + var(--spacing-edge) / 2) !important;
    left: var(--spacing-edge) !important;
    width: var(--panel-width) !important;
    height: calc(100dvh - var(--spacing-edge) - var(--surface-pill-h) - var(--spacing-edge) / 2 - var(--spacing-edge)) !important;
    border: none !important;
    border-radius: var(--surface-radius) !important; /* uniform 12px, matches every pill (finding 3) */
    overflow: hidden !important; /* Clip content at corners */
    box-shadow: var(--window-shadow) !important; /* the docked window had no shadow (finding 3) */
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147483000 !important;
}

/* ===== Space Editing Toolbar (Header) ===== */
.spaceEditing {
    position: fixed !important;
    top: var(--spacing-edge) !important;
    left: var(--spacing-edge) !important;
    width: var(--panel-width) !important;
    height: var(--header-height) !important;
    border: none !important;
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147483001;
    box-sizing: border-box;
    overflow: hidden;
}

/* ===== Context Menu ===== */
.context {
    position: fixed !important;
    top: auto !important;
    left: auto !important;
    right: var(--spacing-edge) !important;
    bottom: var(--spacing-edge) !important;
    /* Rounded + clipped so the iframe's own drop shadow reads as the rounded card's
       shadow (finding 3). AB#4427 QA. */
    width: var(--surface-context-w) !important;
    height: var(--surface-context-h) !important;
    max-width: calc(100vw - 2 * var(--spacing-edge)) !important;
    border: none !important;
    border-radius: var(--surface-radius) !important;
    overflow: hidden !important;
    box-shadow: var(--window-shadow) !important;
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147482999 !important;
}

/* ===== View Controls ===== */
/* Width is the pill's natural width (--surface-viewcontrols-w) so the buttons never
   shrink below square (finding 6) — and no wider, since transparent iframe area still
   swallows clicks meant for the Unity canvas. Height carries a little slack beyond the
   pill so its drop shadow (finding 8) isn't clipped; the page top-aligns the pill so
   the top gap stays == --spacing-edge. */
.viewControls {
    position: fixed !important;
    top: var(--spacing-edge) !important;
    right: var(--spacing-edge) !important;
    left: auto !important;
    width: var(--surface-viewcontrols-w) !important;
    height: calc(var(--surface-pill-h) + var(--surface-shadow-slack)) !important;
    border: none !important;
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147482997 !important;
}

/* ===== Mode-hint banner (AB#4957) ===== */
/* Pill naming the active canvas mode (exit button + hint). Sized flush to the pill so no
   transparent iframe area swallows canvas pointer events; the nominal width matches the
   view-controls pill and MUST match ModeHintReferenceWidthPx in UIWindowBaseFactory.cs.
   Default: centered in the free top-row span between the toolbar (--panel-width, left) and
   the view controls (right) — the span-based left/max-width track the panel tokens, so the
   pill first shrinks (hint ellipsizes) as the viewport narrows, and can never overlap a
   neighbor even when the breakpoints below go stale. */
.modeHint {
    position: fixed !important;
    top: var(--spacing-edge) !important;
    left: calc((100vw + var(--panel-width) - var(--surface-viewcontrols-w)) / 2) !important;
    right: auto !important;
    transform: translateX(-50%) !important;
    width: var(--surface-modehint-w) !important;
    max-width: calc(100vw - var(--panel-width) - var(--surface-viewcontrols-w) - 3 * var(--spacing-edge)) !important;
    height: calc(var(--surface-modehint-h) + var(--surface-shadow-slack)) !important;
    border: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147482997 !important;
}

/* Top-row span too small for a useful pill: derivation panel-max(480) + vc(347) + 3*edge(45)
   = 872 used; below ~1200 the remaining span drops under ~330px. Move the banner to the
   right side under the view controls, centered over the canvas span right of the sidebar.
   Recompute this threshold when --panel-max or the view-controls width changes. */
@media (max-width: 1200px) {
    .modeHint {
        top: calc(var(--spacing-edge) + var(--surface-pill-h) + var(--spacing-edge) / 2) !important;
        left: auto !important;
        right: var(--spacing-edge) !important;
        transform: none !important;
        max-width: calc(100vw - var(--panel-width) - 2.5 * var(--spacing-edge)) !important;
    }
}

/* ===== Notification toast panel (AB#6055) ===== */
/* Bottom-center toast stack (bottom-right belongs to the context menu / more panel). The
   transparent iframe area DOES intercept canvas pointer input — cross-document hit-testing lands
   on the iframe root, not through it to the canvas — so the height follows the page's own
   measurement of its toasts (--surface-notifications-h, written by Unity) and the box never has
   more slack than the panel's own padding. Width MUST match NotificationsReferenceWidthPx in
   UIWindowBaseFactory.cs. */
.notifications {
    position: fixed !important;
    left: 50% !important;
    right: auto !important;
    bottom: var(--spacing-edge) !important;
    top: auto !important;
    transform: translateX(-50%) !important;
    width: var(--surface-notifications-w) !important;
    height: var(--surface-notifications-h) !important;
    border: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147482996 !important;
}
@media (max-width: 575px) {
    .notifications {
        left: var(--spacing-edge) !important;
        transform: none !important;
        width: calc(100vw - 2 * var(--spacing-edge)) !important;
    }
}

/* ===== Onboarding modal (AB#4579) ===== */
/* Full-viewport overlay above the fullscreen home window (2147483000) and the
   space toolbar (2147483001); the page inside renders backdrop + centered card. */
.onboardingModal {
    position: fixed !important;
    inset: 0 !important;
    width: 100vw !important;
    height: 100vh !important;
    border: 0 !important;
    transform: none !important;
    background: transparent;
    pointer-events: auto;
    z-index: 2147483002 !important;
}

/* Narrow windows — not enough room for the top-left toolbar (~416px) and the
   top-right view controls (~347px) side by side (they collide below ~793px).
   Stack them vertically (finding 14, option a): the view controls drop to a
   full-width row just below the toolbar, and the docked home window drops below
   that row. Breakpoint sits above the collision point (AB#4427 QA). */
@media (max-width: 850px) {
    /* Right-side stack over the canvas: view controls on top, mode-hint banner below —
       the sidebar keeps its full height (no left-column rows besides the toolbar). Both
       clamp to the canvas span right of the sidebar, shrinking before they end up behind
       it on the ≤575px break (AB#4957 responsive pass). */
    .viewControls {
        top: var(--spacing-edge) !important;
        right: var(--spacing-edge) !important;
        left: auto !important;
        width: var(--surface-viewcontrols-w) !important;
        max-width: calc(100vw - var(--panel-width) - 2.5 * var(--spacing-edge)) !important;
    }
    .modeHint {
        top: calc(var(--spacing-edge) + var(--surface-pill-h) + var(--spacing-edge) / 2) !important;
        max-width: calc(100vw - var(--panel-width) - 2.5 * var(--spacing-edge)) !important;
    }
}

/* Mobile Portrait: ContextMenu + More panel full width (view controls already
   stacked below the toolbar by the ≤850px rule above). */
@media (max-width: 575px) {
    /* Only the WIDTH goes full-bleed; the heights stay the shared per-surface tokens so
       there is one height per surface (these rules previously carried their own stale
       7.5rem/13.75rem copies, unscaled and still on the pre-compaction 120px). */
    .context {
        left: var(--spacing-edge) !important;
        width: calc(100vw - 2 * var(--spacing-edge)) !important;
    }
    /* View controls + mode-hint banner go full-bleed like the context menu, as second and
       third rows below the toolbar. The full-width sidebar sits ABOVE them in z-order, so
       while it is open they are behind it — deliberate, the canvas surfaces are only useful
       with the canvas visible anyway. AB#4957. */
    .viewControls {
        right: auto !important;
        left: var(--spacing-edge) !important;
        width: calc(100vw - 2 * var(--spacing-edge)) !important;
        max-width: none !important;
        top: calc(var(--spacing-edge) + var(--surface-pill-h) + var(--spacing-edge) / 2) !important;
    }
    .modeHint {
        top: calc(var(--spacing-edge) + 2 * (var(--surface-pill-h) + var(--spacing-edge) / 2)) !important;
        right: auto !important;
        left: var(--spacing-edge) !important;
        width: calc(100vw - 2 * var(--spacing-edge)) !important;
        max-width: none !important;
    }
}
