/*
 * The demo's own layer, loaded after every /manage stylesheet so it wins on equal
 * specificity.
 *
 * Deliberately thin. The point of generating the snapshot from the real portal is that
 * the portal's CSS is the demo's CSS — anything restyled here is a place the demo has
 * started lying about the product. What is left is the two things a marketing embed
 * needs that a real session does not: the frame must not scroll, and controls that
 * cannot work must not invite a click.
 */

/* ---- No scrolling, bar one exception -------------------------------
 * body.is-logged-in already pins the page at 100dvh with overflow:hidden, so the page
 * itself never scrolled. These are the inner panes, which really do scroll in the
 * product. Content is sized in scripts/demo/data.js to fit 1664x1040; this is the fence
 * that makes a mistake there visible as clipping rather than hiding it behind a
 * scrollbar on the marketing page. The one deliberate exception is below.
 * ------------------------------------------------------------------ */
.portal-main,
.tab-content,
.portal-kanban,
.portal-contacts-list-wrap {
    overflow: hidden !important;
}

/* ---- The exceptions ------------------------------------------------
 * Two lists keep the vertical scrolling they have in the product, because both hold
 * more than a fixed frame can show and neither reads well truncated.
 *
 * Both are capped rather than merely set to `overflow: auto`. Nothing in either is
 * height-constrained — the board measured 1468px tall against a 1040px frame — so
 * `overflow-y` on its own does nothing at all and the surplus is silently clipped away
 * with no way to reach it. The cap is what creates a scrollport.
 *
 * `overscroll-behavior: contain` on both is the fence: without it a wheel gesture that
 * reaches the end carries on into the Framer page behind the iframe, so a visitor
 * flicking through leads would fling the marketing site instead.
 * ------------------------------------------------------------------ */

/* The stocklist. 17 residences over six levels; ~9 rows fit. */
.demo-ready .stock-table-wrap {
    max-height: calc(100dvh - 350px);
    overflow-y: auto !important;
    overscroll-behavior: contain;
}

/*
 * The dashboard grid, now that its sub-tabs are clickable.
 *
 * Overview is curated to six widgets and fits exactly, so it never scrolls. The other
 * three are not curated and could not be without guessing: Properties & Pricing alone
 * defines thirteen widgets. They scroll instead, which also means the Overview tuning
 * does not have to be redone three more times.
 *
 * 234px is measured, not rounded: it is the grid's exact distance from the top of the
 * frame, so the cap leaves precisely the room Overview's six widgets occupy (806px, to
 * the pixel). Rounding it to 250 cost 16px and gave Overview a scrollbar for the sake of
 * its own last row.
 */
.demo-ready .rw-grid {
    max-height: calc(100dvh - 234px);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* ---- Kanban columns ------------------------------------------------
 * Kanban columns keep the vertical scrolling they have in the product.
 *
 * A pipeline worth showing has more leads than fit a fixed frame, and the two ways to
 * hold the no-scroll line both cost more than they save: cap the Lead column at what
 * fits (four cards, which reads as a quiet pipeline) or let it clip (a card sliced in
 * half at the fold, which reads as a bug). Scrolling here is what the real board does.
 *
 * `overscroll-behavior: contain` is the fence. Without it, a wheel gesture that reaches
 * the end of a column carries on into the Framer page behind the iframe, so a visitor
 * flicking through leads would fling the marketing site instead.
 * ------------------------------------------------------------------ */
.demo-ready .portal-kanban-cards {
    /*
     * The height cap is what makes this scroll at all. Nothing in the board is
     * height-constrained — the column, the kanban root and the pane all grow to fit their
     * content (the board measured 1468px tall against a 1040px frame), so `overflow-y`
     * alone did exactly nothing and the extra leads were simply clipped away with no way
     * to reach them.
     *
     * 300px is the measured distance from the top of the frame to the first card (276px)
     * plus a little breathing room at the bottom. Capping the CARD LIST rather than the
     * column keeps the column headers and their counts pinned while the cards move,
     * which is how a kanban is supposed to behave.
     */
    max-height: calc(100dvh - 300px);
    overflow-y: auto !important;
    overscroll-behavior: contain;
}

/* The drawers are full-height by design and their bodies legitimately scroll. Keep them
   clipped too, but allow the pointer through so nothing feels frozen. */
.portal-contact-detail-panel,
.portal-residence-drawer,
#portalFilesDrawer {
    overflow: hidden !important;
}

/* Scrollbars would still paint a gutter in some engines even with nothing to scroll. */
.demo-ready ::-webkit-scrollbar { width: 0; height: 0; }
.demo-ready * { scrollbar-width: none; }

/* ---- Inert affordances --------------------------------------------
 * The demo answers no writes, so a control that looks pressable and does nothing is
 * worse than one that plainly is not. Pointer cursors are dropped from everything
 * except the things demo-nav.js actually handles.
 * ------------------------------------------------------------------ */
/*
 * `:where()` keeps this at ZERO specificity beyond `.demo-ready`, which is the whole
 * point: everything below it re-enables something, and a re-enable that cannot win is
 * just a comment.
 *
 * This was first written as `button:not(#portalFilesBtn):not(#portalProjectBtn)...`.
 * `:not()` takes the specificity of its argument, so three ID negations scored (3,1,1)
 * and beat every re-enable underneath — the drawer close buttons computed
 * `pointer-events: none` and no drawer could be closed by clicking. Do not reintroduce
 * ID negations here; add to the allow-lists below instead.
 */
.demo-ready :where(button, input, select, textarea, [contenteditable]) {
    cursor: default;
    pointer-events: none;
}

/* The three top-bar controls the demo actually handles. */
.demo-ready #portalFilesBtn,
.demo-ready #portalProjectBtn,
.demo-ready #portalNotificationsBtn {
    pointer-events: auto;
    cursor: pointer;
}

/*
 * The dashboard's own sub-tabs.
 *
 * `[data-rw-tab]` rather than `.rw-tabbtn`, which is the point: the portal renders the
 * Campaigns tab as `<button class="rw-tabbtn rw-soon" disabled>` with no data attribute
 * because it is not ready, and Generate Report carries `data-rw-action` instead. Keying
 * on the attribute leaves both of them inert without naming either.
 */
.demo-ready #rwTabbar [data-rw-tab] {
    pointer-events: auto;
    cursor: pointer;
}

/* …but a drawer still has to be closable.
 *
 * Scoped to `button` on purpose, and it must stay that way. These selectors out-specify
 * the portal's own rules, so anything they touch has its pointer events GRANTED BACK —
 * including things the portal deliberately made inert. `.pfd-backdrop` carries
 * `data-pfd-close`, is a full-viewport fixed div at z-index 1190, and is switched off
 * with `pointer-events: none` until the drawer opens. An unscoped `[data-pfd-close]`
 * here revived it over the whole page, and since it is `opacity: 0` the only symptom was
 * that nothing on the demo was clickable.
 *
 * Close controls are all buttons; backdrops are not.
 */
.demo-ready button[data-drawer-close],
.demo-ready button[data-pfd-close],
.demo-ready button.portal-contact-drawer-close,
.demo-ready button.project-detail-modal-close,
.demo-ready button[aria-label="Close"] {
    pointer-events: auto;
    cursor: pointer !important;
}

.demo-ready .tab[data-tab]:not(.tab--disabled),
.demo-ready .portal-kanban-card,
.demo-ready .portal-contacts-list-row,
.demo-ready tr.stock-data-row {
    cursor: pointer;
}

/* ---- Command ribbon dot field -------------------------------------
 * The real .mcr field is a <canvas> painted by a rAF loop in command-ribbon.js. With no
 * script it would serialise as a blank box, so the generator swaps in this span and the
 * same grid is drawn as a static background. GAP 9 / R0 0.9 mirrors the canvas.
 * ------------------------------------------------------------------ */
.demo-mcr-field {
    display: block;
    width: 100%;
    height: 100%;
    background-image: radial-gradient(
        circle at 1px 1px,
        color-mix(in srgb, var(--portal-text) 38%, transparent) 0.9px,
        transparent 0.9px
    );
    background-size: 9px 9px;
    opacity: 0.55;
}

/* ---- Text selection ------------------------------------------------
 * A visitor dragging across the embed should not end up with half the page highlighted.
 * ------------------------------------------------------------------ */
.demo-ready body {
    -webkit-user-select: none;
    user-select: none;
}
