/* /Components/Layout/AppShell.razor.rz.scp.css */
/* Class names are prefixed because app.css is global and unscoped. It already owns .shell,
   .row and .glyph, and a scoped stylesheet does not stop a global rule reaching an element that
   happens to carry the same class — SheetLayout's header comment records how the easy schedule
   ended up painted black exactly this way. Scoping protects these rules from leaking out; it does
   nothing to keep app.css from leaking in.

   Phone first, because that is where the app is used and where the constraints are real. The
   wide layout is the exception, added back at the one breakpoint app.css already uses. */

.app-frame[b-xkydrq2arl] {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    background: var(--bg);
    color: var(--ink);
}

.app-body[b-xkydrq2arl] {
    flex: 1;
    min-width: 0;

    /* Room for the bar, plus whatever the phone reserves for its own home indicator. Without
       this the last row of every page sits underneath the navigation and cannot be tapped —
       which looks like the page ending early rather than like a layout fault. */
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
}

.app-rail[b-xkydrq2arl] {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 40;

    display: flex;
    justify-content: space-around;
    align-items: stretch;

    height: calc(56px + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);

    background: var(--panel);
    border-top: 1px solid var(--line);
}

.app-spot[b-xkydrq2arl] {
    flex: 1;

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;

    /* Never below 44px. Everything here is hit with a thumb, at arm's length, one-handed. */
    min-height: 44px;
    min-width: 44px;

    color: var(--ink-dim);
    text-decoration: none;
    font-size: 0.72rem;
    line-height: 1;

    /* A tab that flashes a grey box on tap looks broken on iOS. */
    -webkit-tap-highlight-color: transparent;
}

.app-spot.on[b-xkydrq2arl] {
    color: var(--accent);
}

.app-spot:hover[b-xkydrq2arl] {
    color: var(--ink);
}

.app-spot.on:hover[b-xkydrq2arl] {
    color: var(--accent);
}

/* A page that has taken the screen. The plan editor is painted by dragging a finger, and a bar
   across the bottom of the phone occupies the same pixels as the bottom of the drawing. */
.app-frame.immersive .app-rail[b-xkydrq2arl] {
    display: none;
}

.app-frame.immersive .app-body[b-xkydrq2arl] {
    padding-bottom: 0;
}

@media (min-width: 900px) {
    .app-frame[b-xkydrq2arl] {
        flex-direction: row;
    }

    .app-body[b-xkydrq2arl] {
        padding-bottom: 0;
    }

    .app-rail[b-xkydrq2arl] {
        position: sticky;
        inset: 0 auto 0 0;

        flex-direction: column;
        justify-content: flex-start;
        gap: 2px;

        width: 208px;
        height: 100dvh;
        padding: 12px 8px;

        border-top: 0;
        border-right: 1px solid var(--line);
    }

    .app-spot[b-xkydrq2arl] {
        flex: 0 0 auto;
        flex-direction: row;
        justify-content: flex-start;
        gap: 12px;

        padding: 10px 12px;
        border-radius: 8px;
        font-size: 0.95rem;
    }

    .app-spot.on[b-xkydrq2arl] {
        background: var(--panel-2);
    }
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
#blazor-error-ui[b-7vzbgokndo] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-7vzbgokndo] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-r651zc09zy],
.components-reconnect-repeated-attempt-visible[b-r651zc09zy],
.components-reconnect-failed-visible[b-r651zc09zy],
.components-pause-visible[b-r651zc09zy],
.components-resume-failed-visible[b-r651zc09zy],
.components-rejoining-animation[b-r651zc09zy] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-retrying[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-failed[b-r651zc09zy],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-r651zc09zy] {
    display: block;
}


#components-reconnect-modal[b-r651zc09zy] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-r651zc09zy 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-r651zc09zy 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-r651zc09zy 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-r651zc09zy]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-r651zc09zy 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-r651zc09zy {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-r651zc09zy {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-r651zc09zy {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-r651zc09zy] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-r651zc09zy] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-r651zc09zy] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-r651zc09zy] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-r651zc09zy] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-r651zc09zy] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-r651zc09zy] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-r651zc09zy 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-r651zc09zy] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-r651zc09zy {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Layout/SheetLayout.razor.rz.scp.css */
/* The door onto the drawing sheet.
 *
 * Same stock, same ink, same one signal colour as /easy. What changes is the scale: there is
 * exactly one thing to do on each of these screens, so the question is set large and everything
 * that is not the question gets out of its way. */

.gate[b-fw8fc9bcto] {
    --stock: var(--ground);
    --sheet: var(--ground-raised);
    --muted: var(--ink-quiet);
    --rule: var(--hair-violet);
    --signal: var(--hot);
    --lift: rgba(154, 167, 240, .10);
    --cast: 0, 0, 0;

    /* The drawing's own three. PlanView carries fallbacks for these, but a fallback cannot know
     * about dark mode — so a plan drawn on this sheet would come out light-roomed on a dark card.
     * A shell owns its whole palette. */
    --room: rgba(154, 167, 240, .08);
    --wall: rgba(154, 167, 240, .45);
    --wash: rgba(246, 160, 107, .12);

    --face: var(--face-body);

    min-height: 100vh;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 8vh 22px 64px;
    background:
        radial-gradient(120% 70% at 50% 0%, var(--lift) 0%, transparent 62%),
        var(--stock);
    color: var(--ink);
    font-family: var(--face);
    -webkit-font-smoothing: antialiased;
}

.gate .card[b-fw8fc9bcto] {
    width: 100%;
    max-width: 430px;
    padding: 34px 30px 30px;
    background: var(--sheet);
    border: 1px solid var(--rule);
    box-shadow:
        0 1px 1px rgba(var(--cast), 0.04),
        0 24px 48px -28px rgba(var(--cast), 0.4);
}

/* ---- everything below styles the page rendered inside ---- */

/* Sheet furniture, in one register, exactly as on /easy. */
.gate[b-fw8fc9bcto]  .mark,
.gate[b-fw8fc9bcto]  .step label,
.gate[b-fw8fc9bcto]  .tick,
.gate[b-fw8fc9bcto]  .foot {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.155em;
    text-transform: uppercase;
}

.gate[b-fw8fc9bcto]  .mark {
    margin: 0 0 30px;
    color: var(--muted);
    display: block;
}

/* The question. One per screen, and set like it is the only thing there. */
.gate[b-fw8fc9bcto]  h1 {
    margin: 0 0 24px;
    font-size: clamp(24px, 6.2vw, 30px);
    line-height: 1.2;
    font-weight: 600;
    letter-spacing: -0.021em;
    text-wrap: balance;
}

.gate[b-fw8fc9bcto]  .said {
    margin: -14px 0 24px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--muted);
}

.gate[b-fw8fc9bcto]  .step { display: flex; flex-direction: column; gap: 8px; }

.gate[b-fw8fc9bcto]  .step label { color: var(--muted); }

/* Only the current question is on screen, but every field stays in the DOM: this is one real
 * form posting to a real endpoint, because a cookie cannot be written from inside a Blazor
 * circuit. Hiding rather than unrendering is what lets the last step post all three answers. */
.gate[b-fw8fc9bcto]  .step[hidden] { display: none; }

.gate[b-fw8fc9bcto]  input,
.gate[b-fw8fc9bcto]  select {
    width: 100%;
    box-sizing: border-box;
    font-family: inherit;
    font-size: 17px;
    padding: 14px 13px;
    border: 1px solid var(--rule);
    background: var(--stock);
    color: var(--ink);
}

.gate[b-fw8fc9bcto]  input:focus,
.gate[b-fw8fc9bcto]  select:focus { outline: none; border-color: var(--signal); }

.gate[b-fw8fc9bcto]  .go {
    width: 100%;
    margin-top: 22px;
    min-height: 52px;
    padding: 0 18px;
    font-family: inherit;
    font-size: 16px;
    font-weight: 600;
    background: var(--ink);
    border: 1px solid var(--ink);
    color: var(--sheet);
    cursor: pointer;
}

.gate[b-fw8fc9bcto]  .go:disabled { opacity: 0.3; cursor: not-allowed; }

.gate[b-fw8fc9bcto]  .back {
    margin-top: 14px;
    padding: 8px 0;
    background: none;
    border: none;
    font-family: inherit;
    font-size: 13px;
    color: var(--muted);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.gate[b-fw8fc9bcto]  .back:hover { color: var(--ink); }

/* Three of them, and they are all visible at once — with a run this short, seeing the whole of it
 * is reassurance rather than an invitation to count what is left. */
.gate[b-fw8fc9bcto]  .ticks { display: flex; gap: 6px; margin-bottom: 26px; }

.gate[b-fw8fc9bcto]  .ticks i {
    height: 2px;
    flex: 1 1 0;
    background: var(--hair);
}

.gate[b-fw8fc9bcto]  .ticks i.done { background: var(--signal); }

.gate[b-fw8fc9bcto]  .wrong {
    margin: 18px 0 0;
    padding: 12px 14px;
    border-left: 2px solid var(--signal);
    background: rgba(117, 131, 141, 0.07);
    font-size: 14px;
    line-height: 1.5;
}

.gate[b-fw8fc9bcto]  .foot {
    margin: 28px 0 0;
    padding-top: 18px;
    border-top: 1px solid var(--rule);
    color: var(--muted);
}

.gate[b-fw8fc9bcto]  .foot a { color: var(--muted); }
.gate[b-fw8fc9bcto]  .foot a:hover { color: var(--signal); }

/* The invite code. Big, because it is read off this screen from across a room. */
.gate[b-fw8fc9bcto]  .code {
    margin: 4px 0 0;
    font-size: clamp(38px, 12vw, 54px);
    font-weight: 700;
    letter-spacing: 0.06em;
    font-variant-numeric: tabular-nums;
    color: var(--signal);
}

.gate[b-fw8fc9bcto]  .ago {
    font-size: 13px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.gate[b-fw8fc9bcto]  .people { margin: 24px 0 0; border-top: 1px solid var(--rule); }

.gate[b-fw8fc9bcto]  .who {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 0;
    border-bottom: 1px solid var(--hair);
}

.gate[b-fw8fc9bcto]  .who .name { flex: 1 1 auto; font-size: 16px; font-weight: 600; }
.gate[b-fw8fc9bcto]  .who .role { font-size: 11.5px; color: var(--muted); }

.gate[b-fw8fc9bcto]  .who button {
    background: none;
    border: 1px solid var(--rule);
    color: var(--muted);
    font-family: inherit;
    font-size: 12.5px;
    padding: 7px 11px;
    cursor: pointer;
}

.gate[b-fw8fc9bcto]  .who button:hover { border-color: var(--signal); color: var(--signal); }

.gate[b-fw8fc9bcto]  .quiet { color: var(--muted); font-size: 14px; line-height: 1.5; }

.gate[b-fw8fc9bcto]  :focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

@media (max-width: 430px) {
    .gate[b-fw8fc9bcto] { padding: 5vh 13px 40px; }
    .gate .card[b-fw8fc9bcto] { padding: 26px 20px 24px; }
}

/* The survey lists used to live here, columns and all. They have gone to Teach.razor.css, which
   is the only page that has ever used them — and, more to the point, they were laid out as fixed
   rem columns per row, which is a width that happens to work rather than a layout. See there. */

.gate[b-fw8fc9bcto]  pre.said {
    text-align: left;
    font-size: 12px;
    line-height: 1.5;
    overflow-x: auto;
    white-space: pre;
}
/* /Components/Pages/Draw.razor.rz.scp.css */
/*
 * The board.
 *
 * Flat while you draw, because a plan view is the right projection for putting things down and
 * the wrong one for finding them — which is the whole argument the stack was built on. The tilt
 * belongs on the screen that answers "where is it", not on the one that asks "where is this".
 */

.draw[b-vlntlub57j] {
    /* The width and the padding are .page's. What is left here is the one thing this screen needs
       that a reading page does not: a column as tall as the window, so the save bar has a floor. */

    /*
     * A column as tall as the window, so the save bar below has a floor to be pushed against.
     *
     * Sticky alone was not enough and the reason is easy to miss: position:sticky only holds an
     * element still while it would otherwise scroll away, so on a window tall enough to show the
     * whole page there is nothing to stick to and the button simply sits at the end of the
     * content - moving down every time the panel opens. Measuring it at a short viewport proved
     * only that short viewports work.
     */
    box-sizing: border-box;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;

    /* The heading and the line under it were left-aligned in a container wider than the board, so
       they sat off to one side of everything they introduce. */
    text-align: center;
}

/* The words wrap where they read well rather than at the edge of the page. */
.draw > .said[b-vlntlub57j] { max-width: 58ch; margin-left: auto; margin-right: auto; }

/*
 * One column, centred: the house above the board that makes it.
 *
 * Side by side put the drawing in a narrow strip while the board had a wide one, and the drawing
 * is the thing being made. Above it, both get the full width of the page and the eye travels the
 * way the work does - look at the house, reach for the board.
 */
/*
 * Deliberately not redefined here.
 *
 * It was, and the drawing collapsed to a third of its size. A scoped stylesheet is compiled with
 * an attribute selector, so a bare .split in this file outranks .page > .split in app.css
 * whatever the source order - the shell's max-width came through and its grid did not, leaving a
 * flex column whose align-items: center shrank every child to its own content.
 *
 * A page that wants something from the shell asks for it by name, at a specificity that does not
 * fight it.
 */

/*
 * The floors beside the drawing, not above the page.
 *
 * A flex row rather than anything positioned: the column takes the width it needs and the drawing
 * takes the rest. That matters more than it looks - the stack is a container-query container, so
 * it re-measures itself against whatever it is given and the drawing shrinks to fit on its own.
 * A phone has no clear margin to hang controls in, and this needs none.
 */
.seeing[b-vlntlub57j] {
    /* No cap of its own. The column the shell hands it is the size it should be - capping here
       was this page deciding its own width again, which is the habit being undone. */
    width: 100%;
    display: flex;
    align-items: center;

    gap: 10px;
    text-align: center;
}

/* Fills the column. It cannot shrink-wrap the drawing: the stack inside is a container-query
   container, so sizing it from its own contents is circular and it collapses to nothing. */
.looking[b-vlntlub57j] { flex: 1 1 auto; min-width: 0; }

/* A column, because a building is one. */
.storeys[b-vlntlub57j] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    width: 62px;
}

.storeys .step[b-vlntlub57j] {
    flex: 0 0 auto;
    width: 40px;
    padding: 8px 0;
    font-size: 13px;
}

/* The name between the arrows, small enough to sit in the column and still be a control. */
.storeys .storey-name[b-vlntlub57j] {
    flex: 0 0 auto;
    width: 100%;
    padding: 6px 4px;
    font: 600 11px/1.25 var(--face-body);
    overflow-wrap: anywhere;
}

.storeys .storey-name.empty[b-vlntlub57j] { opacity: .5; }

.storeys .floor-name[b-vlntlub57j] { width: 100%; padding: 6px 4px; font-size: 11px; text-align: center; }

/* Air between the arrows and the pair that changes the building rather than the view. */
.storeys .gap[b-vlntlub57j] { height: 12px; }

/* The cost of removing a floor cannot fit in a 62px column, so it stands out of it. */
/*
 * On a phone the rail goes under the drawing, not beside it.
 *
 * Sixty-two pixels of controls beside a three-hundred-and-ninety pixel screen left the drawing
 * 241 wide with squares about the size of the tip of a thumb, which is why nothing could be
 * placed or moved there. Under, the drawing gets the whole width; a row of four buttons costs
 * forty pixels of height and buys a third more drawing.
 */
@media (max-width: 640px) {
    .seeing[b-vlntlub57j] {
        flex-direction: column;
        gap: 6px;

        /* Stretch, not centre. As a column, centring sizes the drawing to its own content - and
           the stack inside is a container-query container, so that is circular and it collapses
           to nothing. Third time this has caught me: it must be given a width, never asked. */
        align-items: stretch;
    }

    .storeys[b-vlntlub57j] {
        flex-direction: row;
        width: auto;
        gap: 8px;
    }

    .storeys .storey-name[b-vlntlub57j] { width: auto; min-width: 90px; }
    .storeys .gap[b-vlntlub57j] { height: auto; width: 10px; }
    .storeys .cost[b-vlntlub57j] { position: static; transform: none; }
}

.storeys .cost[b-vlntlub57j] {
    position: absolute;
    transform: translateX(70px);
    white-space: nowrap;
    color: var(--hot);
    font-size: 10px;
}

/*
 * Past 1100 this is .page > .split from app.css: the drawing on the left, holding, and everything
 * that is a control on the right. It used to cap itself at 900 and sit as a column in the middle
 * of a two-thousand-pixel window - the exact ribbon-in-a-field the shell exists to stop.
 */

/* Everything on this page lines up on one centre. */
.chips[b-vlntlub57j], .steps[b-vlntlub57j] { justify-content: center; }

/*
 * The controls keep a reading measure; only the drawing takes the width.
 *
 * A tray stretched to eleven hundred pixels with four bricks in the middle of it is mostly empty
 * box, and three buttons the width of a wall are not easier to press for being enormous - they
 * just stop looking like buttons.
 */
.below[b-vlntlub57j] { max-width: 620px; margin: 0 auto; }

.steps .chip[b-vlntlub57j] { flex: 0 1 auto; }

/* The lens controls, under the drawing and out of the way of it. */
.lensing[b-vlntlub57j] {
    display: flex;
    gap: 8px;
    justify-content: center;
    margin-top: 6px;
}

.lensing .step[b-vlntlub57j] { flex: 0 0 auto; }
.lensing .step.wide[b-vlntlub57j] { padding-left: 14px; padding-right: 14px; }

/* --- the tray ---------------------------------------------------------------

   Where rooms come from, and where they go back to.

   The bricks are drawn as bricks rather than listed as words, because the thing you are about to
   put on the house should look like the thing that lands on it. */

.tray[b-vlntlub57j] {
    margin: 22px auto 0;
    padding: 14px 18px 18px;
    max-width: 620px;
    border: 1px dashed var(--hair-violet);
    border-radius: var(--r-panel);
    background: rgba(154, 167, 240, .03);
    transition: border-color .12s, background .12s;
}

/* While something is in the air this is also a bin, so it says so. */
.tray.open[b-vlntlub57j] {
    border-style: solid;
    border-color: var(--violet);
    background: rgba(154, 167, 240, .07);
}

.bricks[b-vlntlub57j] {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
    margin-bottom: 6px;
}

.cube[b-vlntlub57j] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 66px;
    padding: 14px 16px;
    font: 600 13px/1 var(--face-body);
    color: var(--ink-soft);
    background: rgba(154, 167, 240, .12);
    border: 1px solid rgba(154, 167, 240, .45);

    /* The side of the brick, so it sits on the shelf rather than being printed on it. */
    box-shadow: 3px 3px 0 rgba(154, 167, 240, .16);
    cursor: grab;
    user-select: none;

    /* No three-hundred-millisecond wait for a double-tap that is not coming. */
    touch-action: manipulation;
}

.cube:hover[b-vlntlub57j] { border-color: var(--violet); color: var(--ink); }

/*
 * Held, waiting to be put down.
 *
 * The tap path has no ghost - there is no pointer hovering a square to draw one under - so the
 * brick itself has to say it is in your hand, or a tap that armed something looks like a tap that
 * did nothing.
 */
.cube.armed[b-vlntlub57j] {
    border-color: var(--violet-bright);
    background: rgba(154, 167, 240, .34);
    color: var(--ink);
    box-shadow: 3px 3px 0 rgba(154, 167, 240, .16), 0 0 16px rgba(154, 167, 240, .5);
}

.cube.on[b-vlntlub57j] {
    border-color: var(--violet-bright);
    background: rgba(154, 167, 240, .22);
    color: var(--ink);
}

/* A room that exists already, waiting to be given a shape. Its name is the label. */
.cube.named[b-vlntlub57j] {
    min-width: 0;
    background: rgba(194, 202, 255, .08);
    border-style: dashed;
}

/* --- the room being worked on ------------------------------------------------

   Selecting a block opens this, and it holds everything about that room: its name, its sensors,
   and the only control on the screen that destroys anything.

   The name lives here rather than on the brick because the plane is tilted, and a text field on a
   skew is unpleasant to type into. What looked like a loss is a gain: a panel has room to say what
   a block cannot. */

.panel[b-vlntlub57j] {
    margin: 18px auto 0;
    padding: 16px 18px 18px;
    max-width: 620px;
    text-align: left;
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-panel);
    background: rgba(154, 167, 240, .05);
}

.panel .section[b-vlntlub57j] { margin-top: 14px; }

.panel .said[b-vlntlub57j] { margin: 12px 0; }

.panel.asking[b-vlntlub57j] { border-color: var(--violet); }

.drop.wide[b-vlntlub57j] {
    width: 100%;
    margin-top: 12px;
    padding: 11px 14px;
}

.drop.armed[b-vlntlub57j] {
    color: var(--hot);
    border-color: var(--hot);
    background: rgba(246, 160, 107, .08);
}

/* --- the chips ------------------------------------------------------------- */

.chips[b-vlntlub57j] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
}

.chip[b-vlntlub57j] {
    padding: 9px 15px;
    font: 600 13px/1 var(--face-body);
    color: var(--ink-body);
    background: var(--fill-ink);
    border: 1px solid var(--hair);
    cursor: pointer;
}

.chip:hover[b-vlntlub57j] { border-color: var(--hair-violet); }

.chip.on[b-vlntlub57j] {
    color: var(--ground);
    background: var(--violet);
    border-color: var(--violet);
}

/* Already on the board. Still tappable, because putting it somewhere else is a normal thing. */
.chip.down[b-vlntlub57j] {
    color: var(--ink-mono);
    background: transparent;
    border-style: dashed;
}

.chip.down.on[b-vlntlub57j] {
    color: var(--ground);
    background: var(--violet);
    border-style: solid;
}

/* --- saving ----------------------------------------------------------------

   Anchored to the bottom of the window rather than to the bottom of the page.

   It sat below whatever else was on screen, so opening the panel on a room pushed it down and
   closing it pulled it back up: the one control reached for by muscle memory was the one thing
   that moved every time anything was selected. The bar bleeds to the page edges and fades the
   content out under itself, so nothing looks cut off behind it. */

.commit[b-vlntlub57j] {
    /* Takes the slack, so the bar sits on the bottom of the window whether the page is long
       enough to scroll or not. */
    margin-top: auto;

    position: sticky;
    bottom: 0;
    z-index: 5;
    margin-left: -22px;
    margin-right: -22px;
    padding: 16px 22px calc(16px + env(safe-area-inset-bottom, 0px));
    background: linear-gradient(to top, var(--ground) 68%, rgba(11, 13, 22, 0));
}


.go[b-vlntlub57j] {
    margin-top: 8px;
    padding: 17px 22px;
    font: 700 17px/1 var(--face-body);
    color: var(--ground);
    background: var(--violet);
    border: 0;
    cursor: pointer;
}

.go.wide[b-vlntlub57j] { width: 100%; }

.go:disabled[b-vlntlub57j] {
    color: var(--ink-mono);
    background: var(--fill-violet);
    cursor: default;
}

/* --- stepping back --------------------------------------------------------- */

/*
 * Undo and redo, and a plain statement that nothing has been written.
 *
 * Without a way back, every action on this board was destructive and the only route to a previous
 * arrangement was to rebuild it by hand — which makes trying an arrangement expensive, and so
 * makes people not try.
 */
.steps[b-vlntlub57j] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 0 18px;
}

.steps .chip:disabled[b-vlntlub57j] {
    color: var(--ink-mono);
    border-style: dashed;
    cursor: default;
}

.pending[b-vlntlub57j] { color: var(--hot); }

/* --- the house being made -------------------------------------------------- */

.seeing[b-vlntlub57j] {
    padding: 6px 0 0;
}

/* --- making rooms where they live ------------------------------------------ */

/*
 * A room's name, typed on the room.
 *
 * There is no list of rooms on another screen any more, so this is the only place a room is
 * named — and it is the place where the consequence is visible.
 */
/*
 * What the room is called.
 *
 * It used to sit on the block itself, which was right while the board was flat and is not now: a
 * text field on a plane tilted forty degrees is a chore to type into. It reads as a loss and is
 * not one — up here it is the first line of a panel that can say more about the room than a
 * two-centimetre brick ever could.
 */
.who-edit[b-vlntlub57j] {
    display: block;
    width: 100%;
    padding: 11px 14px;
    font: 700 17px/1.2 var(--face-body);
    text-align: center;
    color: var(--ink);
    background: rgba(11, 13, 22, .6);
    border: 1px solid var(--violet);
    border-radius: var(--r-pill) !important;
}

.who-edit[b-vlntlub57j]::placeholder { color: var(--ink-faint); font-weight: 500; }

.floor-name[b-vlntlub57j] {
    padding: 9px 16px;
    font: 600 13px/1 var(--face-body);
    color: var(--ink);
    background: var(--fill-violet);
    border: 1px solid var(--violet);
}

/* Adding is a different act from choosing, so it does not look like a room. */
.add[b-vlntlub57j] {
    /* app.css gives every button flex: 1, which turned "+ Room" into a bar the width of the page
       for what is the smallest action on the screen. */
    flex: 0 0 auto;
    padding: 9px 15px;
    font: 600 13px/1 var(--face-body);
    color: var(--violet);
    background: transparent;
    border: 1px dashed var(--hair-violet);
    cursor: pointer;
}

.add:hover[b-vlntlub57j] { color: var(--violet-bright); border-color: var(--violet); }

/* A room and its removal travel together, so the x cannot be tapped for the wrong room. */
.chip-pair[b-vlntlub57j] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.drop[b-vlntlub57j] {
    padding: 9px 13px;
    font: 600 12px/1 var(--face-body);
    color: var(--ink-mono);
    background: transparent;
    border: 1px solid var(--hair);
    cursor: pointer;
}

.drop:hover[b-vlntlub57j] { color: var(--hot); border-color: var(--hot); }

.drop.small[b-vlntlub57j] { padding: 8px 10px; }

/* /Components/Pages/Easy.razor.rz.scp.css */
/* A drawing sheet.
 *
 * The page is a floorplan, so it borrows the vernacular of one: cool drafting stock, blue-black
 * ink, hairlines, a scale bar, a title block, and the things listed as a schedule. Two registers
 * of one grotesk carry it — a plain-spoken headline that answers the question, and tracked
 * micro-caps for everything the drawing itself says. One signal colour, spent only on what you
 * came here to find. */

.easy[b-8h25bu9ayd] {
    /* Only what app.css has no name for. The shell - padding, ground, ink, the light it sits in -
       comes from .page now, so this page and every other are the same object. */
    --room: rgba(154, 167, 240, .08);
    --wall: rgba(154, 167, 240, .45);
    --wash: rgba(246, 160, 107, .12);
    --cast: 0, 0, 0;
}

/* Night drafting. Not an inversion - the stock goes deep blue, the ink comes up, and the signal
 * warms slightly so it still separates from a dark ground.
 *
 * The width ladder and the two columns that used to be written out here are .page > .split in
 * app.css. They were right, and being right in one file is why no other screen had them. */

/* Sheet furniture: everything the drawing says about itself, in one register. */
.easy .home[b-8h25bu9ayd],
.easy .details[b-8h25bu9ayd],
.easy .storeys button[b-8h25bu9ayd],
.easy .block[b-8h25bu9ayd],
.easy .schedule .head[b-8h25bu9ayd],
.easy .adder label[b-8h25bu9ayd] {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.155em;
    text-transform: uppercase;
}

/* ---- header ---- */

.easy .top[b-8h25bu9ayd] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--hair-violet);
    margin-bottom: 26px;
}

.easy .home[b-8h25bu9ayd] { margin: 0; color: var(--ink); text-decoration: none; padding: 6px 0; }

.easy .home:hover[b-8h25bu9ayd] { color: var(--hot); }

.easy .details[b-8h25bu9ayd] {
    margin-left: auto;
    color: var(--ink-quiet);
    text-decoration: none;
    padding: 6px 0 6px 14px;
}

.easy .details:hover[b-8h25bu9ayd] { color: var(--hot); }

/* The one line that answers the question you opened this to ask — the only humane voice on the
 * page, and set to sound like one. */
.easy .headline em[b-8h25bu9ayd] { font-style: normal; color: var(--hot); }

/* ---- sheet index ---- */

.easy .storeys[b-8h25bu9ayd] { display: flex; gap: 2px; margin: 0 0 -1px; position: relative; z-index: 1; }

.easy .storeys button[b-8h25bu9ayd] {
    padding: 11px 17px;
    border: 1px solid var(--hair-violet);
    border-bottom-color: transparent;
    background: transparent;
    color: var(--ink-quiet);
    font-family: var(--face-body);
    cursor: pointer;
}

.easy .storeys button:hover[b-8h25bu9ayd] { color: var(--ink); }

.easy .storeys button.on[b-8h25bu9ayd] {
    background: var(--ground-raised);
    color: var(--ink);
    box-shadow: inset 0 2px 0 var(--hot);
}

/* ---- the drawing ---- */

.easy figure[b-8h25bu9ayd] {
    margin: 0 0 26px;
    padding: 26px 20px 0;
    background: var(--ground-raised);
    border: 1px solid var(--hair-violet);
    box-shadow:
        0 1px 1px rgba(var(--cast), 0.04),
        0 24px 48px -28px rgba(var(--cast), 0.4);
}

.easy svg.plan[b-8h25bu9ayd] { display: block; width: 100%; height: auto; max-height: 58vh; overflow: visible; }

.easy svg.plan .room[b-8h25bu9ayd] { fill: var(--room); }

/* The only fill on the sheet that carries meaning. */
.easy svg.plan .room.holds[b-8h25bu9ayd] { fill: var(--wash); }

/* Warmth pooling around the marker and spilling across the room it is in. This is the picture
 * the product is selling — everything else on the sheet exists to make it legible.
 *
 * Matched on the stop itself, not on an ancestor. These live inside <radialGradient id="glow">,
 * and "glow" there is an id — a descendant selector written against a class never matched it, so
 * both stops fell back to the SVG default of opaque black and the glow rendered as a solid black
 * disc a quarter the width of the flat. Invisible until the day something was actually placed. */
.easy svg.plan stop.hot[b-8h25bu9ayd] { stop-color: var(--hot); stop-opacity: 0.3; }
.easy svg.plan stop.cold[b-8h25bu9ayd] { stop-color: var(--hot); stop-opacity: 0; }

/* Thick, like the cut walls on a plan. At hairline weight it read as a wireframe. */
.easy svg.plan .wall[b-8h25bu9ayd] {
    stroke: var(--wall);
    stroke-width: 0.14;
    stroke-linecap: square;
    stroke-linejoin: miter;
}

.easy svg.plan .room-name[b-8h25bu9ayd],
.easy svg.plan .tag[b-8h25bu9ayd],
.easy svg.plan .scale text[b-8h25bu9ayd],
.easy svg.plan .key text[b-8h25bu9ayd] {
    font-family: var(--face-body);
    font-weight: 700;
    letter-spacing: 0.055px;
    text-transform: uppercase;
}

.easy svg.plan .room-name[b-8h25bu9ayd] {
    font-size: 0.23px;
    fill: var(--ink-quiet);
    text-anchor: middle;
}

.easy svg.plan .room-name.here[b-8h25bu9ayd] { fill: var(--hot); }

.easy svg.plan .scale line[b-8h25bu9ayd] { stroke: var(--ink-quiet); stroke-width: 0.035; }

.easy svg.plan .scale text[b-8h25bu9ayd],
.easy svg.plan .key text[b-8h25bu9ayd] { font-size: 0.19px; fill: var(--ink-quiet); }

/* ---- the equipment ---- */

/* Fixed devices, drawn as a plan draws them: the building's own ink, at a size that reads as
 * installed rather than as something to look at. The signal colour is spent on what you came here
 * to find, and a sensor is never that. */
.easy svg.plan .node rect[b-8h25bu9ayd],
.easy svg.plan .key rect[b-8h25bu9ayd] {
    fill: var(--ground-raised);
    stroke: var(--wall);
    stroke-width: 0.045;
}

.easy svg.plan .node .dot[b-8h25bu9ayd],
.easy svg.plan .key .dot[b-8h25bu9ayd] { fill: var(--wall); }

/* Nothing has been heard from it. Still drawn — a hole in the coverage is part of why an answer
 * might be wrong — but hollow and dashed, so the sheet shows the gap instead of hiding it. */
.easy svg.plan .node.off rect[b-8h25bu9ayd] { stroke: var(--ink-quiet); stroke-dasharray: 0.07 0.055; }
.easy svg.plan .node.off .dot[b-8h25bu9ayd] { fill: none; }

/* The marker is the thing you came here to find, so it always carries the signal. Being live
 * adds the ring, not the colour. */
.easy svg.plan .pin .halo[b-8h25bu9ayd] { fill: var(--ground-raised); stroke: var(--ground-raised); stroke-width: 0.09; }

.easy svg.plan .pin .disc[b-8h25bu9ayd] {
    fill: var(--hot);
    stroke: var(--ground-raised);
    stroke-width: 0.045;
}

.easy svg.plan .pin .mark[b-8h25bu9ayd] { font-size: 0.28px; text-anchor: middle; fill: var(--ground-raised); }

/* A plan annotates what it draws. */
.easy svg.plan .tag[b-8h25bu9ayd] {
    font-size: 0.2px;
    fill: var(--ink);
    paint-order: stroke;
    stroke: var(--ground-raised);
    stroke-width: 0.07;
}
.easy svg.plan .tag.before[b-8h25bu9ayd] { text-anchor: end; }

/* One ring per reading, going out once.
 *
 * Not a loop. The element is keyed on the observation time, so a new reading replaces it and the
 * animation runs again from the start — which makes the pulse mean "just heard" rather than
 * "heard at some point in the last two minutes". A tag that advertises every so often then looks
 * like exactly that, instead of like a steady heartbeat it does not have. */
.easy svg.plan .pin.live .ping[b-8h25bu9ayd] {
    fill: none;
    stroke: var(--hot);
    stroke-width: 0.05;
    transform-origin: center;
    transform-box: fill-box;
    animation: ping-b-8h25bu9ayd 1.6s cubic-bezier(0.2, 0.6, 0.3, 1) 1 both;
}

@keyframes ping-b-8h25bu9ayd {
    0% { transform: scale(1); opacity: 0.6; }
    100% { transform: scale(2.8); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .easy svg.plan .pin.live .ping[b-8h25bu9ayd] { animation: none; opacity: 0; }
}

/* Last known, not current. Hollow, so the drawing never claims something is somewhere it only
 * used to be — but still there, because where it was last is the most useful thing on the page
 * once a tag has gone quiet. */
.easy svg.plan .pin.stale .disc[b-8h25bu9ayd] { fill: var(--ground-raised); stroke: var(--hot); stroke-width: 0.07; }
.easy svg.plan .pin.stale .mark[b-8h25bu9ayd] { fill: var(--hot); }
.easy svg.plan .pin.stale .tag[b-8h25bu9ayd] { fill: var(--ink-quiet); }

/* ---- title block ---- */

.easy .block[b-8h25bu9ayd] {
    display: flex;
    flex-wrap: wrap;
    margin: 18px -20px 0;
    border-top: 1px solid var(--hair-violet);
    color: var(--ink);
}

.easy .block span[b-8h25bu9ayd] {
    flex: 1 1 0;
    min-width: 96px;
    padding: 11px 14px 12px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-variant-numeric: tabular-nums;
}

.easy .block span + span[b-8h25bu9ayd] { border-left: 1px solid var(--hair-violet); }
.easy .block b[b-8h25bu9ayd] { font-weight: 700; color: var(--ink-quiet); }

/* The same block with no drawing above it, for a home that has named its rooms and not drawn
 * them. It has to stand on its own rather than hang off the bottom of a figure that is not
 * there. */
.easy .block.standalone[b-8h25bu9ayd] {
    margin: 0 0 26px;
    background: var(--ground-raised);
    border: 1px solid var(--hair-violet);
    box-shadow:
        0 1px 1px rgba(var(--cast), 0.04),
        0 24px 48px -28px rgba(var(--cast), 0.4);
}

/* Something the house noticed. Volunteered rather than asked for, so it is drawn as a note in
 * the margin of the sheet rather than as another control competing for a tap. */
.easy .hint[b-8h25bu9ayd] {
    margin-top: 14px;
    padding: 18px 18px 16px;
    background: var(--ground-raised);
    border: 1px solid var(--hair-violet);
    border-left: 2px solid var(--ink-quiet);
}

.easy .hint .what[b-8h25bu9ayd] {
    margin: 0 0 4px;
    font-size: 16px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ink);
}

.easy .hint .where[b-8h25bu9ayd] { margin: 0 0 14px; font-size: 14px; color: var(--ink-quiet); }

.easy .hint button[b-8h25bu9ayd] {
    min-height: 42px;
    padding: 0 16px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.easy .hint button.go[b-8h25bu9ayd] { background: var(--ink); border: 1px solid var(--ink); color: var(--ground-raised); }

.easy .hint button.cancel[b-8h25bu9ayd] {
    background: none;
    border: none;
    color: var(--ink-quiet);
    font-weight: 400;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.easy .hint button.cancel:hover[b-8h25bu9ayd] { color: var(--ink); }

/* An offer, not a gate — so it is drawn as the quietest thing on the page. */
.easy a.unlock[b-8h25bu9ayd] {
    display: block;
    margin-top: 14px;
    padding: 15px;
    border: 1px dashed var(--hair-violet);
    color: var(--ink-quiet);
    font-size: 14px;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    transition: border-color 130ms ease, color 130ms ease;
}

.easy a.unlock:hover[b-8h25bu9ayd] { border-color: var(--hot); border-style: solid; color: var(--hot); }

/* ---- the schedule ---- */

/* "entry" and "line", not "thing" and "row", because app.css is not scoped and already owns
 * both of those names for the dark diagnostic page — `.thing` there carries a panel background,
 * a radius and a padding, and it was painting these rows black. Blazor's scoping only rewrites
 * the selectors in this file; it does not stop anyone else's from matching our markup. Out-
 * specifying a global stylesheet works until somebody adds one more declaration to it, so the
 * fix is a name it does not use. */

.easy .schedule[b-8h25bu9ayd] { background: var(--ground-raised); border: 1px solid var(--hair-violet); }

.easy .schedule .head[b-8h25bu9ayd] {
    display: flex;
    justify-content: space-between;
    padding: 10px 16px;
    border-bottom: 1px solid var(--hair-violet);
    color: var(--ink-quiet);
}

.easy .entry + .entry[b-8h25bu9ayd] { border-top: 1px solid var(--hair); }

/* The whole row is the control, so a thumb anywhere on it opens the history. */
.easy .entry button.line[b-8h25bu9ayd] {
    display: flex;
    align-items: center;
    gap: 13px;
    width: 100%;
    padding: 15px 16px;
    background: none;
    border: none;
    border-left: 2px solid transparent;
    text-align: left;
    font-family: inherit;
    color: inherit;
    cursor: pointer;
}

.easy .entry.here button.line[b-8h25bu9ayd] { border-left-color: var(--hot); }
.easy .entry button.line:hover[b-8h25bu9ayd] { background: rgba(117, 131, 141, 0.07); }

.easy .entry .glyph[b-8h25bu9ayd] { flex: 0 0 22px; font-size: 19px; line-height: 1; }

.easy .entry .name[b-8h25bu9ayd] {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 16.5px;
    font-weight: 600;
    letter-spacing: -0.008em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.easy .entry .answer[b-8h25bu9ayd] {
    flex: 0 0 auto;
    text-align: right;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.easy .entry .where[b-8h25bu9ayd] { font-size: 14.5px; font-weight: 600; }
.easy .entry.here .where[b-8h25bu9ayd] { color: var(--hot); }
.easy .entry .where.lost[b-8h25bu9ayd] { color: var(--ink-quiet); font-weight: 400; }

.easy .entry .when[b-8h25bu9ayd] {
    font-size: 11.5px;
    color: var(--ink-quiet);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}

/* ---- where it has been ---- */

.easy .been[b-8h25bu9ayd] { padding: 2px 16px 14px 34px; border-top: 1px dashed var(--hair-violet); }

.easy .stay[b-8h25bu9ayd] {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 0;
    font-size: 13px;
    color: var(--ink-quiet);
    font-variant-numeric: tabular-nums;
}

.easy .stay + .stay[b-8h25bu9ayd] { border-top: 1px solid var(--hair); }
.easy .stay .room[b-8h25bu9ayd] { flex: 1 1 auto; font-weight: 600; color: var(--ink); }
.easy .stay.now .room[b-8h25bu9ayd] { color: var(--hot); }
.easy .stay .span[b-8h25bu9ayd] { flex: 0 0 auto; }
.easy .stay .lasted[b-8h25bu9ayd] { flex: 0 0 62px; text-align: right; }
.easy .been .none[b-8h25bu9ayd] { padding: 11px 0 3px; font-size: 13px; }

/* Housekeeping, one tap down with the history. Quieter than everything above it, because
 * renaming a thing is not what anybody opened this page to do. */
.easy .edit[b-8h25bu9ayd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding-top: 12px;
    margin-top: 4px;
    border-top: 1px solid var(--hair);
}

.easy .edit .sure[b-8h25bu9ayd] { flex: 1 1 100%; font-size: 13.5px; color: var(--ink); font-weight: 600; }

.easy .edit input[b-8h25bu9ayd],
.easy .edit select[b-8h25bu9ayd] {
    font-family: inherit;
    font-size: 14px;
    padding: 9px 10px;
    border: 1px solid var(--hair-violet);
    background: var(--ground);
    color: var(--ink);
}

.easy .edit input[b-8h25bu9ayd] { flex: 1 1 130px; min-width: 0; }
.easy .edit input:focus[b-8h25bu9ayd], .easy .edit select:focus[b-8h25bu9ayd] { outline: none; border-color: var(--hot); }

.easy .edit button[b-8h25bu9ayd] {
    font-family: inherit;
    font-size: 13px;
    padding: 9px 12px;
    cursor: pointer;
}

.easy .edit button.save[b-8h25bu9ayd] {
    background: var(--ink);
    border: 1px solid var(--ink);
    color: var(--ground-raised);
    font-weight: 600;
}

.easy .edit button.save:disabled[b-8h25bu9ayd] { opacity: 0.3; cursor: not-allowed; }

.easy .edit button.plain[b-8h25bu9ayd] {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--ink-quiet);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Only the last one is pushed right, so "Rename  Remove" sit together rather than at opposite
 * ends of the row looking like unrelated controls. */
.easy .edit button.plain ~ button.plain[b-8h25bu9ayd] { margin-left: 0; }

.easy .edit button.plain:hover[b-8h25bu9ayd] { color: var(--hot); }

/* ---- adding something ---- */

.easy button.add[b-8h25bu9ayd] {
    width: 100%;
    margin-top: 14px;
    padding: 15px;
    border: 1px dashed var(--hair-violet);
    background: none;
    color: var(--ink-quiet);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 130ms ease, color 130ms ease;
}

.easy button.add:hover[b-8h25bu9ayd] { border-color: var(--hot); border-style: solid; color: var(--hot); }

.easy .adder[b-8h25bu9ayd] {
    margin-top: 14px;
    padding: 20px 18px;
    background: var(--ground-raised);
    border: 1px solid var(--hair-violet);
    display: flex;
    flex-direction: column;
    gap: 15px;
}

.easy .adder label[b-8h25bu9ayd] { display: flex; flex-direction: column; gap: 7px; color: var(--ink-quiet); }

.easy .adder .asking[b-8h25bu9ayd] {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.012em;
    color: var(--ink);
}

.easy .adder .none[b-8h25bu9ayd] { padding: 0; }

/* One of these is the thing in their hand. It is at the top because it is the loudest, and it
 * carries the signal colour because being within arm's reach is the whole evidence. */
.easy .adder button.offer[b-8h25bu9ayd] {
    display: flex;
    align-items: baseline;
    gap: 12px;
    width: 100%;
    padding: 14px 15px;
    background: var(--ground);
    border: 1px solid var(--hair-violet);
    text-align: left;
    font-family: inherit;
    color: var(--ink);
    cursor: pointer;
}

.easy .adder button.offer.close[b-8h25bu9ayd] { border-color: var(--hot); }

.easy .adder button.offer:hover[b-8h25bu9ayd] { border-color: var(--hot); }

.easy .adder button.offer .what[b-8h25bu9ayd] { flex: 1 1 auto; font-size: 16px; font-weight: 600; }

.easy .adder button.offer .where[b-8h25bu9ayd] {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--ink-quiet);
}

.easy .adder button.offer.close .where[b-8h25bu9ayd] { color: var(--hot); font-weight: 600; }

/* The escape hatch. Present, and clearly not the way in. */
.easy .adder button.typeit[b-8h25bu9ayd] {
    align-self: center;
    min-height: 0;
    padding: 4px 0;
    border: none;
    background: none;
    font-size: 13px;
    font-weight: 400;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.easy .adder input[b-8h25bu9ayd],
.easy .adder select[b-8h25bu9ayd] {
    font-family: inherit;
    font-size: 15px;
    padding: 11px 12px;
    border: 1px solid var(--hair-violet);
    background: var(--ground);
    color: var(--ink);
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
}

.easy .adder input:focus[b-8h25bu9ayd],
.easy .adder select:focus[b-8h25bu9ayd] { outline: none; border-color: var(--hot); }

.easy .adder .buttons[b-8h25bu9ayd] { display: flex; gap: 9px; margin-top: 3px; }

.easy .adder button[b-8h25bu9ayd] {
    flex: 1 1 0;
    min-height: 46px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.easy .adder button.go[b-8h25bu9ayd] { background: var(--ink); border: 1px solid var(--ink); color: var(--ground-raised); }
.easy .adder button.go:disabled[b-8h25bu9ayd] { opacity: 0.3; cursor: not-allowed; }
.easy .adder button.cancel[b-8h25bu9ayd] { background: none; border: 1px solid var(--hair-violet); color: var(--ink-quiet); }

.easy .quiet[b-8h25bu9ayd] { color: var(--ink-quiet); font-size: 14px; padding: 22px 2px; margin: 0; }

.easy :focus-visible[b-8h25bu9ayd] { outline: 2px solid var(--hot); outline-offset: 2px; }

@media (max-width: 430px) {
    .easy[b-8h25bu9ayd] { padding: 24px 13px 48px; }
    .easy figure[b-8h25bu9ayd] { padding: 18px 13px 0; }
    .easy .block[b-8h25bu9ayd] { margin: 15px -13px 0; }
    .easy .block span[b-8h25bu9ayd] { padding: 10px 12px 11px; min-width: 88px; }
    .easy .storeys button[b-8h25bu9ayd] { flex: 1 1 0; padding: 11px 6px; }
    .easy .entry button.line[b-8h25bu9ayd] { padding: 14px 13px; gap: 11px; }
    .easy .entry .name[b-8h25bu9ayd] { font-size: 15.5px; }
    .easy .been[b-8h25bu9ayd] { padding-left: 28px; }
}

/* ---- The home, room by room ---- */

.room-line[b-8h25bu9ayd] {
    display: grid;
    grid-template-columns: minmax(6.5rem, 30%) minmax(0, 1fr);
    gap: 12px;
    align-items: baseline;
    padding: 10px 2px;
    border-bottom: 1px solid var(--hair-violet);
}

.room-line .room-name[b-8h25bu9ayd] {
    font-size: 15px;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.room-line.empty .room-name[b-8h25bu9ayd] { font-weight: 500; opacity: 0.55; }

.room-line .room-holds[b-8h25bu9ayd] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    align-items: baseline;
}

.room-line .nothing[b-8h25bu9ayd] { font-size: 14px; opacity: 0.4; }

/* A thing in a room. A button because tapping it opens its history. */
.room-line .in-room[b-8h25bu9ayd] {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    min-height: 32px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.room-line .in-room .name[b-8h25bu9ayd] { font-size: 15px; }
.room-line .in-room .ago[b-8h25bu9ayd] { font-size: 12px; opacity: 0.55; }
.room-line .in-room:hover .name[b-8h25bu9ayd] { text-decoration: underline; }

/* Heard by nothing. Kept visible rather than dropped — a thing the house cannot find is the
 * one the person is most likely looking for. */
.room-line.lost-line .room-name[b-8h25bu9ayd] { color: var(--warn, #c68d14); }

/* ---- The doors ---- */

.top .doors[b-8h25bu9ayd] {
    display: inline-flex;
    gap: 14px;
    margin-left: auto;
}

.top .doors a[b-8h25bu9ayd] {
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    opacity: 0.7;
}

.top .doors a:hover[b-8h25bu9ayd] { opacity: 1; }

/* ---- At the door ---- */

.leaving[b-8h25bu9ayd] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 14px;
    margin: 0 0 14px;
    padding: 12px 14px;
    border-radius: 12px;
    border: 1px solid var(--hair-violet);
}

.leaving.short[b-8h25bu9ayd] {
    border-color: var(--warn, #c68d14);
    background: rgba(198, 141, 20, 0.08);
}

.leaving .lead[b-8h25bu9ayd] { font-size: 15px; font-weight: 600; }
.leaving.short .lead[b-8h25bu9ayd] { color: var(--warn, #c68d14); }

.leaving .kit[b-8h25bu9ayd] { display: flex; flex-wrap: wrap; gap: 6px 14px; }

.leaving .one[b-8h25bu9ayd] {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    min-height: 32px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.leaving .one .name[b-8h25bu9ayd] { font-size: 15px; }
.leaving .one.gone .name[b-8h25bu9ayd] { color: var(--warn, #c68d14); font-weight: 600; }
.leaving .one .state[b-8h25bu9ayd] { font-size: 12px; opacity: 0.7; }

.entry .edit .plain.on[b-8h25bu9ayd] { border-color: var(--signal, #ff4a17); color: var(--signal, #ff4a17); }

/* One of ours, straight out of its box. Louder than the "something has been living here"
 * suggestion below it, because this one is an event happening right now rather than a standing
 * observation — somebody is holding the thing while they read it. */
.hint.fresh[b-8h25bu9ayd] {
    border-color: var(--signal, #ff4a17);
}

.hint.fresh .what[b-8h25bu9ayd] {
    font-weight: 600;
    color: var(--signal, #ff4a17);
}
/* /Components/Pages/More.razor.rz.scp.css */
.more-list[b-hxnlivym65] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 16px 0 24px;
}

.more-row[b-hxnlivym65] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;

    /* Whole-row targets. A link the width of its text is a target the width of its text, and
       "Household" is nine characters of thumb. */
    min-height: 56px;
    padding: 12px 14px;

    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;

    color: var(--ink);
    text-decoration: none;
}

.more-row:hover[b-hxnlivym65] {
    border-color: var(--accent);
}

.more-mark[b-hxnlivym65] {
    display: flex;
    color: var(--ink-dim);
}

.more-what[b-hxnlivym65] {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.more-what small[b-hxnlivym65] {
    color: var(--ink-dim);
}

.more-arrow[b-hxnlivym65] {
    color: var(--ink-dim);
}

.more-out[b-hxnlivym65] {
    margin-top: 8px;
}
/* /Components/Pages/Network.razor.rz.scp.css */
/* The network, in Now's language: a kicker, a headline that says the one fact, a rule, then
   the instrument — a dark field of glowing sensors, violet structure, terracotta only where
   the live answer sits. */

.net[b-5terns2oyf] {
    padding: 30px clamp(16px, 4vw, 44px) 0;
    max-width: 1180px;
}

.net .kicker[b-5terns2oyf] {
    margin: 0 0 18px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.155em;
    text-transform: uppercase;
    color: var(--ink);
}

.net .head[b-5terns2oyf] {
    margin: 0 0 18px;
    font-size: clamp(25px, 6.4vw, 34px);
    line-height: 1.15;
    font-weight: 600;
    letter-spacing: -.021em;
    color: var(--ink);
    text-wrap: balance;
}

/* The warm word, the same trick Now uses: the number, or the fact that something is live. */
.net .head[b-5terns2oyf]  em { font-style: normal; color: var(--hot); }

.net .rule[b-5terns2oyf] {
    border: 0;
    border-top: 1px solid var(--hair-violet);
    margin: 0 0 22px;
}

/* ---- the field ---- */

.mesh[b-5terns2oyf] {
    position: relative;
    width: 100%;
    height: calc(100dvh - 12rem);
    min-height: 460px;
    overflow: hidden;
    border-radius: var(--r-panel);
    background: var(--ground);
    touch-action: none;
    isolation: isolate;
}

/* Depth: a broad glow from above and faint concentric rings, so the graph floats in a space
   rather than sitting on a flat black rectangle. The rings are the quiet holographic tell. */
.mesh .glow[b-5terns2oyf] {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(90% 70% at 50% 22%, var(--fill-violet), transparent 62%),
        radial-gradient(60% 50% at 50% 120%, var(--fill-hot), transparent 60%);
    opacity: .9;
}

.mesh .glow[b-5terns2oyf]::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 46%;
    width: 132%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background:
        repeating-radial-gradient(circle,
            transparent 0 58px,
            var(--hair-violet) 58px 59px,
            transparent 59px 118px);
    opacity: .32;
    mask: radial-gradient(circle, #000 0 44%, transparent 72%);
    -webkit-mask: radial-gradient(circle, #000 0 44%, transparent 72%);
}

.mesh-edges[b-5terns2oyf] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    overflow: visible;
}

/* Luminous filaments. A strong link glows brighter and wider; a travelling dash reads as the
   adverts actually passing between the two sensors. JS-drawn, so it needs ::deep to escape
   this component's scoped CSS or it renders with no stroke at all. */
.mesh[b-5terns2oyf]  .mesh-edge {
    stroke: var(--violet);
    stroke-width: calc(1px + var(--w, 0.3) * 2px);
    stroke-opacity: calc(0.28 + var(--w, 0.3) * 0.55);
    stroke-linecap: round;
    filter: drop-shadow(0 0 4px rgba(154, 167, 240, .55));
    stroke-dasharray: 2 12;
    animation: flow-b-5terns2oyf 1.4s linear infinite;
}

@keyframes flow-b-5terns2oyf { to { stroke-dashoffset: -14; } }

.mesh-nodes[b-5terns2oyf] {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* The node is a zero-size anchor at the sensor's point; mesh.js sets its translate3d, and the
   edge lines end at that same point — so the orb, centred on it, is what the lines touch. */
.mesh-node[b-5terns2oyf] {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    z-index: 1;
    opacity: 0;
    transform: translate3d(50%, 50%, 0);
}

.mesh-node.is-placed[b-5terns2oyf] { opacity: 1; transition: opacity .7s ease; }
.mesh-node:hover[b-5terns2oyf] { z-index: 6; }

/* The orb: a glowing core in a soft halo, pulsing gently — the sensor as a live thing, the way
   the active room glows on Now. Centred exactly on the node's point, so the edges reach it. */
.mesh-node .orb[b-5terns2oyf] {
    position: absolute;
    left: 0;
    top: 0;
    transform: translate(-50%, -50%);
    width: 46px;
    height: 46px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: radial-gradient(circle, var(--fill-violet) 0 40%, transparent 68%);
}

/* The name and the readout hang straight down from the orb, centred, out of the edges' way. */
.mesh-node .below[b-5terns2oyf] {
    position: absolute;
    left: 0;
    top: 22px;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.mesh-node .orb[b-5terns2oyf]::before {
    content: "";
    position: absolute;
    inset: 12px;
    border-radius: 50%;
    border: 1px solid var(--hair-violet);
    animation: breathe-b-5terns2oyf 3.6s ease-in-out infinite;
}

.mesh-node .core[b-5terns2oyf] {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: radial-gradient(circle at 40% 35%, var(--violet-bright), var(--violet) 70%);
    box-shadow: 0 0 14px 2px rgba(154, 167, 240, .7), 0 0 3px 1px rgba(194, 202, 255, .9);
}

@keyframes breathe-b-5terns2oyf {
    0%, 100% { transform: scale(1); opacity: .55; }
    50% { transform: scale(1.18); opacity: .95; }
}

/* Wellness, the Stack's idiom: dim when struggling, hollow and quiet when dark. */
.mesh-node.struggling .core[b-5terns2oyf] { opacity: .55; box-shadow: 0 0 8px 1px rgba(154, 167, 240, .4); }
.mesh-node.dark .core[b-5terns2oyf] {
    background: transparent;
    border: 1.5px solid var(--hair-violet);
    box-shadow: none;
}
.mesh-node.dark .orb[b-5terns2oyf]::before { animation: none; opacity: .3; }

/* The one warm exception: a sensor holding the live answer, blooming like the active room. */
.mesh-node.hot .orb[b-5terns2oyf] { background: radial-gradient(circle, var(--fill-hot) 0 42%, transparent 70%); }
.mesh-node.hot .orb[b-5terns2oyf]::before { border-color: rgba(246, 160, 107, .4); }
.mesh-node.hot .core[b-5terns2oyf] {
    background: radial-gradient(circle at 40% 35%, var(--hot-core), var(--hot) 70%);
    box-shadow: 0 0 20px 4px rgba(246, 160, 107, .75), 0 0 4px 1px rgba(255, 244, 230, .9);
}

.mesh-node .tag[b-5terns2oyf] {
    font-family: var(--face-display);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .005em;
    color: var(--ink-body);
    white-space: nowrap;
}

.mesh-node.hot .tag[b-5terns2oyf] { color: var(--hot-bright); }
.mesh-node.dark .tag[b-5terns2oyf] { color: var(--ink-quiet); }

/* The little readout of what this sensor hears — a glass panel, compact, four rows, the rest a
   count. Expands on hover. Not a tooltip: a considered instrument face. */
.mesh-node .window[b-5terns2oyf] {
    width: 156px;
    padding: 9px 11px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    background: linear-gradient(180deg, rgba(20, 23, 40, .82), rgba(15, 17, 32, .82));
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-row);
    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, .7);
    backdrop-filter: blur(6px);
    max-height: 118px;
    overflow: hidden;
    transition: max-height .28s ease, border-color .28s ease;
}

.mesh-node:hover .window[b-5terns2oyf] { max-height: 300px; border-color: var(--violet); }
.mesh-node.hot .window[b-5terns2oyf] { border-color: rgba(246, 160, 107, .35); }

.mesh-node .heard[b-5terns2oyf] {
    flex: none;
    display: grid;
    grid-template-columns: 1fr 30px;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    color: var(--ink-mono);
    animation: heard-in-b-5terns2oyf .4s ease;
}

.mesh-node .heard .what[b-5terns2oyf] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.mesh-node .heard.ours .what[b-5terns2oyf] { color: var(--violet-bright); }
.mesh-node .heard.tracked .what[b-5terns2oyf] { color: var(--hot-bright); font-weight: 600; }

.mesh-node .heard .bar[b-5terns2oyf] {
    height: 5px;
    border-radius: var(--r-pill);
    background: linear-gradient(
        to right,
        var(--violet) calc(var(--s, 0) * 100%),
        var(--fill-ink) calc(var(--s, 0) * 100%));
}

.mesh-node .heard.tracked .bar[b-5terns2oyf] {
    background: linear-gradient(
        to right,
        var(--hot) calc(var(--s, 0) * 100%),
        var(--fill-ink) calc(var(--s, 0) * 100%));
}

.mesh-node .more[b-5terns2oyf] {
    font-size: 9.5px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-quiet);
    padding-top: 1px;
}

@keyframes heard-in-b-5terns2oyf {
    from { opacity: 0; transform: translateY(-3px); }
    to { opacity: 1; transform: translateY(0); }
}

.mesh-empty[b-5terns2oyf] {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
    max-width: 22rem;
    margin: 0 auto;
    padding: 2rem;
    color: var(--ink-quiet);
    font-family: var(--face-body);
}

@media (prefers-reduced-motion: reduce) {
    .mesh-node[b-5terns2oyf], .mesh-node .core[b-5terns2oyf], .mesh-node .orb[b-5terns2oyf]::before, .mesh-node .heard[b-5terns2oyf],
    .mesh[b-5terns2oyf]  .mesh-edge { animation: none; transition: none; }
}

/* ---- controls: adding, and the tapped-sensor panel ---- */

/* The orbs are the one thing on the field you can touch. */
.mesh-node .orb[b-5terns2oyf] { pointer-events: auto; cursor: pointer; }

.controls[b-5terns2oyf] {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 8;
    max-width: 300px;
}

.controls .add[b-5terns2oyf] {
    font-family: var(--face-display);
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    background: var(--fill-violet);
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-pill);
    padding: 11px 18px;
    cursor: pointer;
    transition: border-color .2s ease, background .2s ease;
}

.controls .add:hover[b-5terns2oyf] { border-color: var(--violet); background: rgba(154, 167, 240, .16); }

.controls .pairing[b-5terns2oyf] {
    display: grid;
    gap: 8px;
    padding: 14px 16px;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--ink-body);
    background: linear-gradient(180deg, rgba(20, 23, 40, .92), rgba(15, 17, 32, .92));
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-panel);
    box-shadow: 0 16px 40px -14px rgba(0, 0, 0, .8);
    backdrop-filter: blur(8px);
}

.controls .pairing .sub[b-5terns2oyf] { color: var(--ink-quiet); font-size: 11.5px; }
.controls .pairing .code[b-5terns2oyf] { color: var(--hot); font-weight: 700; letter-spacing: .06em; }
.controls .ghost[b-5terns2oyf] {
    justify-self: start;
    color: var(--ink-quiet);
    background: none;
    border: 0;
    padding: 2px 0;
    cursor: pointer;
    font-size: 12px;
}
.controls .ghost:hover[b-5terns2oyf] { color: var(--hot); }

/* The edit panel: a glass sheet on the right, one tap deep, dismissed by its × or picking again. */
.panel[b-5terns2oyf] {
    position: absolute;
    top: 18px;
    right: 18px;
    z-index: 9;
    width: min(320px, calc(100% - 36px));
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 18px;
    background: linear-gradient(180deg, rgba(20, 23, 40, .94), rgba(13, 15, 26, .94));
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-panel);
    box-shadow: 0 24px 60px -18px rgba(0, 0, 0, .85);
    backdrop-filter: blur(10px);
    animation: panel-in-b-5terns2oyf .24s ease;
}

@keyframes panel-in-b-5terns2oyf { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

.panel-head[b-5terns2oyf] {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: baseline;
    gap: 10px;
}
.panel-head b[b-5terns2oyf] { font-family: var(--face-display); font-size: 15px; color: var(--ink); }
.panel-head .quiet[b-5terns2oyf] { font-size: 11px; color: var(--ink-quiet); }
.panel-head .x[b-5terns2oyf] {
    grid-column: 3;
    color: var(--ink-quiet);
    background: none; border: 0; cursor: pointer;
    font-size: 20px; line-height: 1; padding: 0 2px;
}
.panel-head .x:hover[b-5terns2oyf] { color: var(--hot); }

.panel .field[b-5terns2oyf] {
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-size: 11px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-quiet);
}

.panel .field .name[b-5terns2oyf],
.panel .field select[b-5terns2oyf] {
    font-family: var(--face-body);
    font-size: 14px;
    text-transform: none;
    letter-spacing: normal;
    color: var(--ink);
    background: var(--ground);
    border: 1px solid var(--hair-violet);
    border-radius: var(--r-row-tight);
    padding: 10px 12px;
}
.panel .field .name:focus[b-5terns2oyf],
.panel .field select:focus[b-5terns2oyf] { outline: 2px solid var(--violet); border-color: transparent; }

.panel-foot[b-5terns2oyf] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding-top: 2px;
}
.panel-foot .quiet[b-5terns2oyf] { font-size: 11px; color: var(--ink-quiet); }
.panel-foot .drop[b-5terns2oyf] {
    color: var(--hot);
    background: none;
    border: 1px solid rgba(246, 160, 107, .35);
    border-radius: var(--r-pill);
    padding: 7px 14px;
    cursor: pointer;
    font-size: 12.5px;
}
.panel-foot .drop:hover[b-5terns2oyf] { background: var(--fill-hot); }
/* /Components/Pages/Teach.razor.rz.scp.css */
/* Teaching the house, with the house on screen.
 *
 * Sits inside the sheet layout and borrows everything it can from it — the question, the small
 * print, the survey grid are all SheetLayout's. What is here is only what that layout has no
 * opinion about: the drawing, and the ring that says a recording is running.
 *
 * Names prefixed tc-. SheetLayout.razor.css warns in its own header that plain names are already
 * taken, and .room is claimed three times over across this project. */

/* The drawing already carries its own margin inside the viewBox, so this frame adds only enough
 * to keep the outer wall off the border line. Two lots of padding is what had the plan floating
 * in the middle of a grey box. */
.tc-plan[b-g9wuj7wmjv] {
    margin: 18px 0 16px;
    padding: 6px;
    background: var(--stock);
    border: 1px solid var(--rule);
}

/* The two lists: one grid each, with the rows as `display: contents`.
 *
 * This is the part worth reading. A list of rows where each row is its own grid can only line its
 * columns up if every column is a fixed width — which is a width that happens to work on the
 * screen it was checked on. That is what was here before, and it failed exactly as you would
 * expect: the template asked for more room than the row had, so every row shrank its own columns
 * to its own content and no two rows agreed where anything was.
 *
 * One grid for the whole list fixes it structurally. `display: contents` lifts each row's cells
 * into the parent grid, so all rows share one set of column tracks; `auto` lets those tracks size
 * to their widest content; `minmax(0, 1fr)` gives the leftover to the name and lets it give way
 * rather than push. Nothing here is a measurement, so there is nothing to re-tune at another
 * width, on another browser, or at another font size. */
.tc-things[b-g9wuj7wmjv],
.tc-rooms[b-g9wuj7wmjv] {
    display: grid;

    /* Stretch, not centre. The rule between rows is drawn by each cell's own top border, so if
       the cells are centred in the track they end up at different heights and the line comes out
       in steps. Stretching makes every cell the full height of its row, which puts all four
       borders on one line; the content is then centred inside the cell instead. */
    align-items: stretch;

    /* No column gap. The rule between rows is drawn by each cell's top border, and a gap between
       columns is a gap in that line — the separator comes out as four dashes rather than a rule.
       The breathing space is inside the cells instead, where it does not interrupt anything. */
    column-gap: 0;
    margin-top: 18px;
}

.tc-things[b-g9wuj7wmjv] { grid-template-columns: minmax(0, 1fr) auto auto; }

.tc-rooms[b-g9wuj7wmjv] { grid-template-columns: minmax(0, 1fr) auto auto auto; }

.tc-things .pickrow[b-g9wuj7wmjv],
.tc-rooms .survey-row[b-g9wuj7wmjv] { display: contents; }

/* The rule between rows has to be drawn by the cells, because the row itself no longer generates
   a box to hang it on. */
.tc-things .pickrow > *[b-g9wuj7wmjv],
.tc-rooms .survey-row > *[b-g9wuj7wmjv] {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    padding: 11px clamp(5px, 1.6vw, 8px);
    border-top: 1px solid var(--rule);
}

/* Flush with the edges of the list, so the rule spans it rather than floating inside it. */
.tc-things .pickrow > *:first-child[b-g9wuj7wmjv],
.tc-rooms .survey-row > *:first-child[b-g9wuj7wmjv] { padding-left: 0; }

.tc-things .pickrow > *:last-child[b-g9wuj7wmjv],
.tc-rooms .survey-row > *:last-child[b-g9wuj7wmjv] { padding-right: 0; }

.survey-what[b-g9wuj7wmjv] { min-width: 0; }

.survey-name[b-g9wuj7wmjv] {
    display: block;
    font-size: clamp(15px, 4.2vw, 17px);
    font-weight: 600;
    text-align: left;

    /* A room called something long shortens rather than reflowing the row it is in. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.survey-taught[b-g9wuj7wmjv] {
    display: block;
    font-size: clamp(12px, 3.4vw, 13px);
    color: var(--muted);
}

.survey-what .survey-taught[b-g9wuj7wmjv] { margin-top: 2px; }

.tc-things .survey-taught[b-g9wuj7wmjv] { text-align: right; }

.survey-dots[b-g9wuj7wmjv] {
    font-size: 11px;
    line-height: 1;
    letter-spacing: 2px;
    color: var(--muted);
    text-align: center;
    white-space: nowrap;
}

/* Spots hang below the room they belong to, across the whole width. */
.tc-rooms .spotrow[b-g9wuj7wmjv] {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 4px 0 4px 14px;
    font-size: 12px;
}

.tc-rooms .spotrow .survey-taught[b-g9wuj7wmjv] { text-align: left; }

/* Buttons keep a real touch target. 44 px is the one number here that is not a layout guess — it
   is the smallest thing a finger reliably hits, so it does not scale with the viewport. */
.tc-things .pick[b-g9wuj7wmjv],
.tc-rooms .pick[b-g9wuj7wmjv] {
    min-height: 44px;
    padding: 0 clamp(10px, 3vw, 14px);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    background: none;
    border: 1px solid var(--ink);
    border-radius: 6px;
    color: var(--ink);
    cursor: pointer;
}

.tc-rooms .drop[b-g9wuj7wmjv],
.tc-rooms .spotrow .drop[b-g9wuj7wmjv] {
    min-height: 44px;
    padding: 0 8px;
    font-family: inherit;
    font-size: 12px;
    white-space: nowrap;
    background: none;
    border: 1px solid transparent;
    border-radius: 6px;
    color: var(--muted);
    cursor: pointer;
}

.tc-rooms .drop:hover[b-g9wuj7wmjv] { border-color: var(--muted); }

/* The ring.
 *
 * Sixty seconds is long enough that a still screen reads as a stopped one, and somebody walking a
 * room is holding the phone at arm's length rather than reading it. An arc that visibly grows
 * answers "is this still going" without being read.
 *
 * Sized against the viewport with a ceiling, so it is generous on a phone and does not become a
 * dinner plate on a desktop. */
.tc-ring[b-g9wuj7wmjv] {
    display: block;
    width: clamp(104px, 34vw, 148px);
    height: auto;
    aspect-ratio: 1;
    margin: 6px auto 4px;
}

.tc-ring .tc-track[b-g9wuj7wmjv] {
    fill: none;
    stroke: var(--hair);
    stroke-width: 6;
}

.tc-ring .tc-run[b-g9wuj7wmjv] {
    fill: none;
    stroke: var(--signal);
    stroke-width: 6;
    stroke-linecap: round;

    /* Matches the once-a-second redraw, so the arc slides rather than stepping. */
    transition: stroke-dasharray 1s linear;
}

@media (prefers-reduced-motion: reduce) {
    .tc-ring .tc-run[b-g9wuj7wmjv] { transition: none; }
}

.tc-ring .tc-time[b-g9wuj7wmjv] {
    text-anchor: middle;
    font-family: inherit;
    font-size: 21px;
    font-weight: 600;
    fill: var(--ink);
    font-variant-numeric: tabular-nums;
}

/* The lines that belong to the ring rather than to the page, so they sit under it. */
.tc-mid[b-g9wuj7wmjv] { text-align: center; }

/* ------------------------------------------------------------------ the queue --
 *
 * The hologram idiom, learned by looking at the phone rather than at the tokens: one display
 * headline in the page's voice, each card a spoken question with names in structure violet,
 * a single micro-caps meta line, and compact pills that never wrap. Warmth appears exactly
 * once — the still-there dot, the one element that genuinely is the answer breathing.
 */

.tq-head[b-g9wuj7wmjv] {
    font-family: var(--face-display);
    font-weight: 400;
    font-size: clamp(26px, 7vw, 32px);
    letter-spacing: 0.01em;
    color: var(--ink);
    margin: 10px 0 16px;
    text-wrap: balance;
}

.tq-queue[b-g9wuj7wmjv] {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0 0 28px;
}

.tq-card[b-g9wuj7wmjv] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px 16px 12px;
    background: var(--ground-raised);
    border: 1px solid var(--hair);
    border-radius: var(--r-row);
    font-family: var(--face-body);
}

.tq-ask[b-g9wuj7wmjv] {
    margin: 0;
    font-size: clamp(17px, 4.6vw, 19px);
    line-height: 1.35;
    color: var(--ink-body);
    text-wrap: balance;
}

.tq-ask em[b-g9wuj7wmjv] { font-style: normal; font-weight: 600; color: var(--violet-bright); }

.tq-meta[b-g9wuj7wmjv] {
    margin: 0;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.155em;
    text-transform: uppercase;
    color: var(--ink-mono);
    font-variant-numeric: tabular-nums;
}

/* The one warm element: the answer, still breathing. */
.tq-live[b-g9wuj7wmjv] {
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-left: 7px;
    border-radius: var(--r-pill);
    background: var(--hot);
    vertical-align: 1px;
    animation: blink 2.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .tq-live[b-g9wuj7wmjv] { animation: none; }
}

.tq-actions[b-g9wuj7wmjv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 2px;
}

.tq-yes[b-g9wuj7wmjv],
.tq-no[b-g9wuj7wmjv],
.tq-room[b-g9wuj7wmjv] {
    min-height: 44px;
    padding: 0 20px;
    border-radius: var(--r-pill);
    font-family: var(--face-body);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.tq-yes[b-g9wuj7wmjv] {
    border: none;
    background: var(--violet);
    color: var(--ground);
}

.tq-yes:hover[b-g9wuj7wmjv] { background: var(--violet-bright); }

.tq-no[b-g9wuj7wmjv],
.tq-room[b-g9wuj7wmjv] {
    background: transparent;
    border: 1px solid var(--hair-violet);
    color: var(--violet-bright);
}

.tq-no:hover[b-g9wuj7wmjv],
.tq-room:hover[b-g9wuj7wmjv] { border-color: var(--violet); background: var(--fill-violet); }

.tq-plain[b-g9wuj7wmjv] {
    min-height: 44px;
    padding: 0 6px;
    margin-left: auto;
    border: none;
    background: none;
    color: var(--ink-quiet);
    font-family: var(--face-body);
    font-size: 13px;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.tq-plain:hover[b-g9wuj7wmjv] { color: var(--ink); }

.tq-rooms[b-g9wuj7wmjv] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.tq-rooms .tq-plain[b-g9wuj7wmjv] { margin-left: 0; }

.tq-sure[b-g9wuj7wmjv] { color: var(--hot-bright); font-size: 13px; }

.tq-relabel[b-g9wuj7wmjv] { margin: 4px 0 10px; }

.tq-yes:focus-visible[b-g9wuj7wmjv],
.tq-no:focus-visible[b-g9wuj7wmjv],
.tq-room:focus-visible[b-g9wuj7wmjv],
.tq-plain:focus-visible[b-g9wuj7wmjv] {
    outline: 2px solid var(--violet-bright);
    outline-offset: 2px;
}
/* /Components/Pages/Then.razor.rz.scp.css */
/*
 * One thing: the answer, then the qualifications, then the habit.
 *
 * The order is the argument. A room name large enough to read across a room, and everything that
 * might undermine it directly underneath rather than a scroll away — because the reason to doubt
 * an answer is worth exactly as much as the answer.
 */

/* 402px was this page's own guess at a phone. The shell decides now, like everywhere else. */
.then > *[b-p0ytnqhzar] { max-width: 620px; margin-left: auto; margin-right: auto; }

.back[b-p0ytnqhzar] {
    display: inline-block;
    margin-bottom: 18px;
    font-size: 13px;
    color: var(--violet);
    text-decoration: none;
}

.back:hover[b-p0ytnqhzar] { color: var(--violet-bright); }

.ident[b-p0ytnqhzar] {
    /* .mono in app.css already sets the face, tracking and case. */
    margin-bottom: 14px;
}

.kicker[b-p0ytnqhzar] {
    font-family: var(--face-mono);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--ink-mono);
}

/* Warm only when a single room is being named. Two rooms, or none, is not a triumph. */
.kicker.hot[b-p0ytnqhzar] { color: var(--hot); }

/*
 * The room name. The largest thing on any screen in this product, because it is the one word
 * most people opened the app for.
 */
.answer[b-p0ytnqhzar] {
    margin: 8px 0 10px;
    font-size: 48px;
    line-height: 1;
    letter-spacing: -0.01em;
    color: var(--ink);
}

/* "Not sure" is said in the same voice and the same size, quietened rather than hidden. */
.answer.faint[b-p0ytnqhzar] { color: var(--ink-quiet); }

.said[b-p0ytnqhzar] {
    margin: 0 0 20px;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--ink-quiet);
}

.said.quiet[b-p0ytnqhzar] { color: var(--ink-mono); }
.said.odd[b-p0ytnqhzar] { color: var(--hot); }

.section[b-p0ytnqhzar] {
    margin: 26px 0 10px;
}

/* --- the runners-up ------------------------------------------------------- */

.faint-returns[b-p0ytnqhzar] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.faint-returns li[b-p0ytnqhzar] {
    display: grid;
    grid-template-columns: 1fr 82px auto;
    align-items: center;
    gap: 12px;
}

.faint-returns .room[b-p0ytnqhzar] {
    font-size: 14px;
    color: var(--ink-body);
}

/* Two pixels tall. It is a comparison between three numbers, not a chart. */
.faint-returns .meter[b-p0ytnqhzar] {
    height: 2px;
    background: rgba(154, 167, 240, .18);
    border-radius: var(--r-pill);
    overflow: hidden;
}

.faint-returns .meter i[b-p0ytnqhzar] {
    display: block;
    height: 100%;
    background: var(--violet);
}

.faint-returns .pc[b-p0ytnqhzar] { color: var(--ink-mono); }

/* --- where it ends up ----------------------------------------------------- */

.strip[b-p0ytnqhzar] {
    display: flex;
    gap: 3px;
    margin: 4px 0 14px;
}

.day[b-p0ytnqhzar] {
    flex: 1;
    height: 26px;
    border-radius: 3px;
    background: var(--fill-ink);
}

/*
 * Ranked shades rather than a colour per room, so the commonest place is the same shade in every
 * home and the strip reads the same way whoever drew the plan.
 */
.day.one[b-p0ytnqhzar], .swatch.one[b-p0ytnqhzar] { background: var(--violet); }
.day.two[b-p0ytnqhzar], .swatch.two[b-p0ytnqhzar] { background: rgba(154, 167, 240, .62); }
.day.three[b-p0ytnqhzar], .swatch.three[b-p0ytnqhzar] { background: rgba(154, 167, 240, .38); }
.day.four[b-p0ytnqhzar], .swatch.four[b-p0ytnqhzar] { background: rgba(154, 167, 240, .22); }
.day.other[b-p0ytnqhzar], .swatch.other[b-p0ytnqhzar] { background: rgba(230, 233, 255, .1); }

.tally[b-p0ytnqhzar] {
    list-style: none;
    margin: 0 0 8px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.tally li[b-p0ytnqhzar] {
    display: grid;
    grid-template-columns: 12px 1fr auto;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--ink-body);
}

.swatch[b-p0ytnqhzar] {
    width: 12px;
    height: 12px;
    border-radius: 3px;
}

.tally .count[b-p0ytnqhzar] {
    font-family: var(--face-mono);
    font-size: 11px;
    letter-spacing: .1em;
    color: var(--ink-mono);
}

/* --- today ---------------------------------------------------------------- */

.stays[b-p0ytnqhzar] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.stays li[b-p0ytnqhzar] {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: baseline;
    gap: 12px;

    padding: 12px 16px;
    border: 1px solid var(--hair);
    border-radius: var(--r-row);
    background: var(--fill-ink);
}

.stays .room[b-p0ytnqhzar] {
    font-weight: 700;
    font-size: 15.5px;
    color: var(--ink);
}

.stays .when[b-p0ytnqhzar], .stays .how-long[b-p0ytnqhzar] {
    font-family: var(--face-mono);
    font-size: 10px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--ink-mono);
}
/* /Components/Pages/Things.razor.rz.scp.css */
/* Everything this home is looking for, and everything it could be.
 *
 * One column at every width. The content is a list of rows whose useful width is a sentence, and
 * a second column of anything would only push the two halves of one row apart on a phone. */

/* Its own palette, the same drafting one /easy uses.
 *
 * A page cannot borrow --rule and --signal from a neighbour's scoped stylesheet, and referring to
 * them with only a fallback gets you a light hairline on a dark sheet the moment somebody has
 * dark mode on. A shell owns its whole palette or it owns none of it. */
.things[b-6u1fixd0jl] {
    /* Only what app.css has no name for; the shell is .page. */
    --wash: rgba(246, 160, 107, .12);
    --cast: 0, 0, 0;
}

/* One column at every width: the useful width of a row is a sentence, and a second column of
   anything only pushes the two halves of one row apart on a phone. */

.things .top[b-6u1fixd0jl] { margin-bottom: 18px; }

/* Explicit colour rather than the page's link colour, which comes out very nearly invisible on
 * the dark sheet — and this is the only way off the page. */
.things .back[b-6u1fixd0jl] {
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    color: inherit;
    opacity: 0.65;
}

.things .back:hover[b-6u1fixd0jl] { opacity: 1; }

/* The heading is .page h1 now, at the size Now sets. */

.things h2[b-6u1fixd0jl] {
    margin: 34px 0 10px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-quiet);
}

.things .said[b-6u1fixd0jl] { margin: 0 0 6px; font-size: 15px; line-height: 1.55; }
.things h2[b-6u1fixd0jl] { color: var(--ink-quiet); opacity: 1; }
.things .quiet[b-6u1fixd0jl] { color: var(--ink-quiet); }

/* ---------------------------------------------------------------- what is tracked */

.things .kept[b-6u1fixd0jl] { list-style: none; margin: 0; padding: 0; }

.things .tracked[b-6u1fixd0jl] { border-bottom: 1px solid var(--hair-violet); }

/* The whole row is the control. A row with a tap target inside it is a row people miss. */
.things .line[b-6u1fixd0jl] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 12px;
    align-items: center;
    width: 100%;
    padding: 13px 2px;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.things .line .icon[b-6u1fixd0jl] { font-size: 20px; line-height: 1; }
.things .line .name[b-6u1fixd0jl] { font-size: 16px; min-width: 0; }

.things .badge[b-6u1fixd0jl] {
    display: inline-block;
    margin-left: 7px;
    padding: 1px 6px;
    border-radius: 999px;
    border: 1px solid var(--hair-violet);
    font-size: 11px;
    letter-spacing: 0.02em;
    opacity: 0.7;
    vertical-align: 1px;
}

.things .answer[b-6u1fixd0jl] {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    text-align: right;
}

.things .answer .spot[b-6u1fixd0jl] { font-size: 15px; }
.things .answer .spot.lost[b-6u1fixd0jl] { color: var(--ink-quiet); }
.things .answer .ago[b-6u1fixd0jl] { font-size: 12px; color: var(--ink-quiet); }

/* ---------------------------------------------------------------- the opened row */

.things .more[b-6u1fixd0jl] {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 4px 2px 18px;
}

.things .field[b-6u1fixd0jl] {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.6;
}

.things .field input[b-6u1fixd0jl] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--hair-violet);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 16px; /* Under 16px iOS zooms the whole page on focus. */
    letter-spacing: normal;
    text-transform: none;
}

/* Glyphs rather than a select: what sort of thing it is has nine answers, all of them a picture,
 * and a dropdown on a phone is a modal sheet for something that fits on one line. */
.things .kinds[b-6u1fixd0jl] { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 6px; }

.things .kind[b-6u1fixd0jl] {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border: 1px solid var(--hair-violet);
    border-radius: 10px;
    background: transparent;
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
    opacity: 0.5;
}

.things .kind.on[b-6u1fixd0jl] {
    opacity: 1;
    border-color: var(--violet);
    box-shadow: inset 0 0 0 1px var(--violet);
}

.things .acts[b-6u1fixd0jl] { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

.things button[b-6u1fixd0jl], .things .plain[b-6u1fixd0jl] {
    padding: 10px 14px;
    white-space: nowrap;
    border: 1px solid var(--hair-violet);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 14px;
    cursor: pointer;
    text-decoration: none;
    display: inline-block;
}

/* The one filled button on the page, violet like Save everywhere else. */
.things .save[b-6u1fixd0jl] {
    border-color: var(--violet);
    background: var(--violet);
    color: var(--ground);
}

.things button:disabled[b-6u1fixd0jl] { opacity: 0.35; cursor: default; }

.things .wide[b-6u1fixd0jl] { width: 100%; text-align: center; }
.things .plain.on[b-6u1fixd0jl] { border-color: var(--violet); }
.things .quiet-btn[b-6u1fixd0jl] { opacity: 0.55; }
.things .quiet-btn:hover[b-6u1fixd0jl] { opacity: 1; }

.things .drop[b-6u1fixd0jl] { border-color: var(--bad, #c0392b); color: var(--bad, #c0392b); }

.things .sure[b-6u1fixd0jl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--hair-violet);
    border-radius: 10px;
    font-size: 14px;
    line-height: 1.5;
}

.things .sure span[b-6u1fixd0jl] { flex: 1 1 14rem; }

/* ---------------------------------------------------------------- what could be tracked */

.things .offer[b-6u1fixd0jl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--hair-violet);
}

.things .offer .icon[b-6u1fixd0jl] { font-size: 20px; line-height: 1; }

/* Takes the slack, so the buttons sit at the right edge on a desktop and wrap under on a phone
 * instead of squeezing the name into two characters. */
.things .offer .what[b-6u1fixd0jl] {
    flex: 1 1 12rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 15px;
}

.things .offer .what .quiet[b-6u1fixd0jl] { font-size: 12px; }

/* Both offer buttons sit at their own width. Left to stretch, "Not mine" wrapped onto a line of
 * its own and became the widest control in the row — dismissing something read as the main
 * action and tracking it as the afterthought. */
.things .offer button[b-6u1fixd0jl] { flex: 0 0 auto; }

/* An ordinary control. Warm made "track this stranger's television" look like the answer to
   "where are my keys". */
.things .take[b-6u1fixd0jl] {
    border-color: var(--violet);
    color: var(--violet-bright);
}

/* Quieter than Track it, and only on the row it belongs to. */
.things .offer .plain[b-6u1fixd0jl] { border-color: transparent; color: var(--ink-quiet); }
.things .offer .plain:hover[b-6u1fixd0jl] { border-color: var(--hair-violet); color: var(--ink); }

.things .take:disabled[b-6u1fixd0jl] { border-color: var(--hair-violet); color: inherit; }

/*
 * A phone is a different kind of offer and says so before it is read: it exists only while
 * somebody is holding one against a sensor.
 *
 * Said with a raised surface rather than a warm outline. Warm means "the thing you are looking
 * for is in here", and it was on every adoption card and every button on this page - nine marks
 * on one screen. It was taken out of the drawing for the same reason: a screen with fifteen warm
 * marks has none.
 */
.things .offer.phone[b-6u1fixd0jl] {
    border: 1px solid var(--hair-violet);
    background: var(--ground-raised);
    box-shadow: 0 1px 1px rgba(0, 0, 0, .04), 0 24px 48px -28px rgba(0, 0, 0, .4);
    border-radius: 10px;
    padding: 12px;
    margin-bottom: 8px;
}

/* An instruction rather than an offer: same shape so it sits in the list, no border and no
 * button, so nothing about it looks tappable. */
.things .offer.teach[b-6u1fixd0jl] { border-bottom-style: dashed; }
.things .offer.teach .what[b-6u1fixd0jl] { font-size: 14px; }

.things .naming[b-6u1fixd0jl] {
    flex: 1 1 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.things .naming input[b-6u1fixd0jl] {
    flex: 1 1 10rem;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--hair-violet);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 16px;
}

/* ---------------------------------------------------------------- dismissed */

.things .disclose[b-6u1fixd0jl] {
    margin-top: 20px;
    border: 0;
    padding: 6px 0;
    font-size: 13px;
    opacity: 0.55;
}

.things .disclose:hover[b-6u1fixd0jl] { opacity: 1; }

.things .dismissed[b-6u1fixd0jl] { list-style: none; margin: 4px 0 0; padding: 0; }

.things .dismissed li[b-6u1fixd0jl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 9px 2px;
    border-bottom: 1px solid var(--hair-violet);
    font-size: 14px;
}

.things .dismissed .what[b-6u1fixd0jl] { flex: 1 1 10rem; opacity: 0.6; }
/* /Components/Plan/PlanCanvas.razor.rz.scp.css */
/* The viewport a plan is looked at through.
 *
 * Prefixed pc- throughout: .canvas and .plan are already spoken for by app.css and by two of the
 * pages, and the same collision is what PlanView's header warns about. */

.pc[b-j5s9ik8bu7] {
    position: relative;
    width: 100%;
    /* Without this the browser takes the pinch for itself and scrolls the page instead. */
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
}

.pc-svg[b-j5s9ik8bu7] {
    display: block;
    width: 100%;
    height: auto;
    max-height: 62vh;
    /* Zoomed in, the drawing is bigger than its box and has to be cut off at the edge rather
     * than painted over whatever is next to it. */
    overflow: hidden;
    font-family: var(--face, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif);
}

.pc-drawing[b-j5s9ik8bu7] {
    cursor: crosshair;
}

.pc:not(.pc-drawing)[b-j5s9ik8bu7] {
    cursor: grab;
}

.pc[data-pc-gesture='true'][b-j5s9ik8bu7],
.pc:not(.pc-drawing):active[b-j5s9ik8bu7] {
    cursor: grabbing;
}

/* ---- The buttons ---- */

.pc-tools[b-j5s9ik8bu7] {
    position: absolute;
    right: 0.4rem;
    bottom: 0.4rem;
    display: flex;
    gap: 0.25rem;
}

.pc-tool[b-j5s9ik8bu7] {
    min-width: 2.25rem;
    min-height: 2.25rem;
    padding: 0 0.5rem;
    border: 1px solid var(--rule, #c8d2d9);
    border-radius: 0.4rem;
    background: var(--sheet, #f9fbfc);
    color: inherit;
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0.85;
}

.pc-tool:hover[b-j5s9ik8bu7] {
    opacity: 1;
    border-color: var(--signal, #ff4a17);
}

.pc-fit[b-j5s9ik8bu7] {
    font-size: 0.8rem;
}

/* Only worth offering once there is something to come back from. */
.pc[data-pc-zoomed='false'] .pc-fit[b-j5s9ik8bu7] {
    opacity: 0.35;
}
/* /Components/Plan/PlanView.razor.rz.scp.css */
/* The drawing.
 *
 * Same vernacular as the sheet at /easy — cool stock, blue-black ink, hairlines, one signal
 * colour — but self-contained: every custom property carries a fallback, so this renders
 * correctly on a bare page and still inherits the page palette when it sits inside one. Nesting
 * it in .easy costs nothing and changes nothing.
 *
 * Every name is prefixed pv-. `.room`, `.wall` and `.node` are all already taken, by app.css,
 * Easy.razor.css and PlanEditor.razor.css between them. */

/* The svg itself is rendered by PlanCanvas now, so its box and its typeface live there —
 * a scoped rule here would carry this component's attribute and match nothing. */

/* The photograph underneath. Faint enough that the drawing reads as the drawing, strong enough
 * to trace a missed cupboard off. */
.pv .pv-backdrop[b-5q4u0bue09] {
    opacity: 0.28;
    pointer-events: none;
}

@media (prefers-color-scheme: dark) {
    /* A white page glares on a dark sheet, and inverting it keeps the ink legible as light lines. */
    .pv .pv-backdrop[b-5q4u0bue09] { opacity: 0.22; filter: invert(1); }
}

/* ---- Rooms ---- */

.pv .pv-room[b-5q4u0bue09] {
    fill: var(--room, #f1f5f7);
    transition: fill 140ms ease-out;
}

.pv .pv-tappable[b-5q4u0bue09] {
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* Nothing here yet. Drawn as an absence rather than a colour: the eye finds the hole, and a room
 * with nothing in it is the actionable one — SurveyCoverage orders its worklist the same way. */
.pv .pv-room.pv-waiting[b-5q4u0bue09] { fill: var(--sheet, #f9fbfc); }

/* Started, not finished. Deliberately not a colour of its own — half a signal reads as half
 * done, which is exactly what it is. */
.pv .pv-room.pv-thin[b-5q4u0bue09] { fill: var(--wash, rgba(255, 74, 23, 0.09)); }

.pv .pv-room.pv-done[b-5q4u0bue09] { fill: var(--done, rgba(46, 138, 96, 0.14)); }

.pv .pv-room.pv-selected[b-5q4u0bue09] { fill: var(--wash, rgba(255, 74, 23, 0.09)); }

.pv .pv-room.pv-warn[b-5q4u0bue09] { fill: var(--warn, rgba(198, 141, 20, 0.16)); }

/* Recording right now. The one animated thing on the drawing, because it is the one thing that
 * is actually happening. */
.pv .pv-room.pv-live[b-5q4u0bue09] {
    fill: var(--wash, rgba(255, 74, 23, 0.09));
    animation: pv-breathe-b-5q4u0bue09 2.4s ease-in-out infinite;
}

/* The edge round a highlighted room. Its own layer because a room is drawn in pieces and the
 * seams between them must not be stroked — see RoomOutline. */
.pv .pv-edge[b-5q4u0bue09] {
    fill: none;
    stroke-linecap: round;
}

.pv .pv-edge.pv-waiting[b-5q4u0bue09] {
    stroke: var(--rule, #c8d2d9);
    stroke-width: 0.03;
    stroke-dasharray: 0.18 0.14;
}

.pv .pv-edge.pv-selected[b-5q4u0bue09] {
    stroke: var(--signal, #ff4a17);
    stroke-width: 0.05;
}

.pv .pv-edge.pv-warn[b-5q4u0bue09] {
    stroke: var(--warnline, #c68d14);
    stroke-width: 0.04;
    stroke-dasharray: 0.2 0.12;
}

.pv .pv-edge.pv-live[b-5q4u0bue09] {
    stroke: var(--signal, #ff4a17);
    stroke-width: 0.06;
}

@keyframes pv-breathe-b-5q4u0bue09 {
    0%, 100% { fill-opacity: 1; }
    50% { fill-opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
    .pv .pv-room.pv-live[b-5q4u0bue09] { animation: none; }
}

/* A door, drawn across the gap the punch left. Without this the wall is simply absent and a
 * plan with a door in every partition reads as a plan with no partitions. */
.pv .pv-door[b-5q4u0bue09] {
    stroke: var(--door, #7f8c96);
    stroke-width: 0.05;
    stroke-linecap: round;
    stroke-dasharray: 0.12 0.1;
}

.pv .pv-hinge[b-5q4u0bue09] {
    fill: var(--door, #7f8c96);
}

/* ---- Walls ---- */

.pv .pv-wall[b-5q4u0bue09] {
    stroke: var(--wall, #17222a);
    stroke-width: 0.09;
    stroke-linecap: square;
    fill: none;
}

/* Heavier walls are drawn heavier. Concrete is 18 dB and foil insulation 30 dB against
 * plasterboard's 3 — the exceptions dominate wherever they exist, so they have to be visible at
 * a glance rather than hidden in a panel. */
/* No wall at all: two rooms open to each other.
 *
 * Drawn rather than omitted, and drawn as the absence it is — a hairline of dots where a wall
 * would be. It has to stay visible to stay tappable: a boundary that vanishes when you set it
 * cannot be set back, and this is a state somebody will want to undo. */
.pv .pv-wall.pv-open[b-5q4u0bue09] {
    stroke: var(--wall, #17222a);
    stroke-width: 0.04;
    stroke-dasharray: 0.06 0.14;
    stroke-linecap: round;
    opacity: 0.45;
}

.pv .pv-wall.pv-plasterboard[b-5q4u0bue09] { stroke-width: 0.07; }
.pv .pv-wall.pv-woodendoor[b-5q4u0bue09] { stroke-width: 0.06; stroke-dasharray: 0.16 0.08; }
.pv .pv-wall.pv-wood[b-5q4u0bue09] { stroke-width: 0.07; stroke-dasharray: 0.16 0.08; }
.pv .pv-wall.pv-brick[b-5q4u0bue09] { stroke-width: 0.11; }
.pv .pv-wall.pv-concrete[b-5q4u0bue09] { stroke-width: 0.15; }
.pv .pv-wall.pv-metal[b-5q4u0bue09] { stroke-width: 0.13; stroke-dasharray: 0.1 0.05; }

/* The one material worth shouting about: 30 dB is ten times the loss of a plasterboard wall and
 * will dominate every estimate made near it. */
.pv .pv-wall.pv-foilinsulation[b-5q4u0bue09] {
    stroke: var(--warnline, #c68d14);
    stroke-width: 0.16;
}

.pv .pv-wall-target[b-5q4u0bue09] {
    stroke: transparent;
    stroke-width: 0.42;
    stroke-linecap: round;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* ---- Sensors ---- */

.pv .pv-node rect[b-5q4u0bue09] {
    fill: var(--sheet, #f9fbfc);
    stroke: var(--wall, #17222a);
    stroke-width: 0.04;
}

.pv .pv-node .pv-dot[b-5q4u0bue09] { fill: var(--wall, #17222a); }

.pv .pv-node.pv-off rect[b-5q4u0bue09] {
    stroke: var(--muted, #75838d);
    stroke-dasharray: 0.07 0.055;
}

.pv .pv-node.pv-off .pv-dot[b-5q4u0bue09] { fill: none; }

/* Advice, not kit. Hollow and dashed so it can never be mistaken for a box already on a wall. */
.pv .pv-suggest circle[b-5q4u0bue09] {
    fill: var(--sheet, #f9fbfc);
    stroke: var(--signal, #ff4a17);
    stroke-width: 0.055;
    stroke-dasharray: 0.12 0.08;
}

.pv .pv-suggest text[b-5q4u0bue09] {
    text-anchor: middle;
    font-size: 0.24px;
    font-weight: 700;
    fill: var(--signal, #ff4a17);
    pointer-events: none;
}

/* ---- Lettering ---- */

.pv .pv-name[b-5q4u0bue09],
.pv .pv-note[b-5q4u0bue09],
.pv .pv-scale text[b-5q4u0bue09] {
    text-anchor: middle;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    fill: var(--muted, #75838d);
    pointer-events: none;
}

.pv .pv-name[b-5q4u0bue09] { font-size: 0.3px; }

.pv .pv-note[b-5q4u0bue09] {
    font-size: 0.21px;
    font-weight: 500;
    letter-spacing: 0.05em;
    text-transform: none;
}

.pv .pv-label.pv-selected .pv-name[b-5q4u0bue09],
.pv .pv-label.pv-live .pv-name[b-5q4u0bue09],
.pv .pv-label.pv-thin .pv-name[b-5q4u0bue09] { fill: var(--signal, #ff4a17); }

.pv .pv-label.pv-done .pv-name[b-5q4u0bue09] { fill: var(--doneink, #2e8a60); }

.pv .pv-label.pv-warn .pv-name[b-5q4u0bue09] { fill: var(--warnline, #c68d14); }

.pv .pv-scale line[b-5q4u0bue09] {
    stroke: var(--muted, #75838d);
    stroke-width: 0.035;
}

.pv .pv-scale text[b-5q4u0bue09] {
    font-size: 0.19px;
    text-anchor: start;
}

/* Night drafting. Only the two properties this component adds to the page palette need a dark
 * value; everything else comes from the sheet it sits on, or from the fallbacks above. */
@media (prefers-color-scheme: dark) {
    .pv[b-5q4u0bue09] {
        --done: rgba(74, 190, 138, 0.16);
        --doneink: #4abe8a;
        --warn: rgba(226, 172, 61, 0.16);
        --warnline: #e2ac3d;
    }
}
/* /Components/Setup/NextStep.razor.rz.scp.css */
/* The next thing to do, on the drawing sheet.
 *
 * Inherits every colour from the .easy page it sits inside — custom properties cascade, so there
 * is one palette and no second copy of it to drift. What it does not inherit is the quiet: this
 * is the one block on the page asking for something, so it is the one block with the signal
 * colour holding its edge. */

.next[b-vljdshfz5z] {
    margin: 0 0 26px;
    padding: 22px 20px 20px;
    background: var(--sheet);
    border: 1px solid var(--rule);
    border-left: 2px solid var(--signal);
    box-shadow:
        0 1px 1px rgba(var(--cast), 0.04),
        0 24px 48px -28px rgba(var(--cast), 0.4);
}

.next h2[b-vljdshfz5z] {
    margin: 0 0 8px;
    font-size: clamp(19px, 4.6vw, 22px);
    line-height: 1.25;
    font-weight: 600;
    letter-spacing: -0.015em;
    text-wrap: balance;
    color: var(--ink);
}

.next p[b-vljdshfz5z] {
    margin: 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--muted);
}

.next code[b-vljdshfz5z] {
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;
    font-size: 13px;
    color: var(--ink);
}

/* Waiting for a sensor to be unplugged. A slow pulse, because the page is doing something and
 * saying nothing would read as having stopped. */
.next.watching[b-vljdshfz5z] { border-left-color: var(--muted); }

.next.watching h2[b-vljdshfz5z]::after {
    content: "";
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-left: 9px;
    border-radius: 50%;
    background: var(--signal);
    vertical-align: middle;
    animation: waiting-b-vljdshfz5z 1.6s ease-in-out infinite;
}

@keyframes waiting-b-vljdshfz5z {
    0%, 100% { opacity: 0.25; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .next.watching h2[b-vljdshfz5z]::after { animation: none; opacity: 0.6; }
}

/* ---- picking a room ---- */

.rooms[b-vljdshfz5z] { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }

.rooms button[b-vljdshfz5z] {
    padding: 12px 15px;
    background: var(--stock);
    border: 1px solid var(--rule);
    color: var(--ink);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 130ms ease, color 130ms ease;
}

.rooms button:hover[b-vljdshfz5z] { border-color: var(--signal); color: var(--signal); }

.rooms button.other[b-vljdshfz5z] {
    background: none;
    border-style: dashed;
    color: var(--muted);
    font-weight: 400;
}

.rooms .own[b-vljdshfz5z] { display: flex; gap: 8px; width: 100%; }

.rooms .own input[b-vljdshfz5z] {
    flex: 1 1 auto;
    min-width: 0;
    font-family: inherit;
    font-size: 15px;
    padding: 12px;
    border: 1px solid var(--rule);
    background: var(--stock);
    color: var(--ink);
}

.rooms .own input:focus[b-vljdshfz5z] { outline: none; border-color: var(--signal); }

/* ---- the buttons that are not rooms ---- */

/* The three stages that hand off to another page use a link rather than a button, because they
 * navigate — and a link that looks like a button has to be one to the eye and a link to the
 * browser, so middle-click and long-press still do what they always do. */
.next a.go[b-vljdshfz5z] {
    display: inline-block;
    text-decoration: none;
    line-height: 46px;
}

.next a.go:hover[b-vljdshfz5z] {
    background: var(--signal, #ff4a17);
    border-color: var(--signal, #ff4a17);
}

.next button.go[b-vljdshfz5z],
.next a.go[b-vljdshfz5z] {
    margin-top: 16px;
    min-height: 46px;
    padding: 0 20px;
    background: var(--ink);
    border: 1px solid var(--ink);
    color: var(--sheet);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
}

.next button.go:disabled[b-vljdshfz5z] { opacity: 0.3; cursor: not-allowed; }

.rooms .own button.go[b-vljdshfz5z] { margin-top: 0; flex: 0 0 auto; }

.next button.quietly[b-vljdshfz5z] {
    margin-top: 14px;
    padding: 8px 0;
    background: none;
    border: none;
    font-family: inherit;
    font-size: 13px;
    color: var(--muted);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.next button.quietly:hover[b-vljdshfz5z] { color: var(--ink); }

.next :focus-visible[b-vljdshfz5z] { outline: 2px solid var(--signal); outline-offset: 2px; }
/* /Components/Stack/StackView.razor.rz.scp.css */
/*
 * The stack: the house as tilted planes, three layers to a floor.
 *
 * The tilt is one transform on a plain div and the grid is two repeating linear-gradients rather
 * than any drawn geometry, which is why this costs no script, no images and no layout work beyond
 * what the browser already does.
 */

/*
 * The stack sizes itself from the space it was given, not from the window.
 *
 * It did the opposite: a media query set a fixed pixel width past 1100px, which was right for the
 * one wide column it was written in and wrong the moment the same component was put in a 360px
 * one — where the plane came out 96px wider than its own container and ran under the board beside
 * it. A component that measures the viewport cannot be placed twice.
 */
.stack[b-vwveoo3e7u] {
    container-type: inline-size;

    /*
     * The one number every part of the drawing is sized from.
     *
     * The column decides, not the caller. Pinning this to a width passed in made the house on Now
     * shrink from 738px to 267 the moment the sizing moved off media queries - the page was asking
     * for a phone-sized drawing and getting exactly that on a 2100px monitor.
     *
     * 88 rather than 100 because the tilt spreads the plane past its own box, and the cap stops a
     * very wide column turning the house into wallpaper.
     */
    /*
     * How big the drawing is, and how big it would be at rest.
     *
     * Zoom resizes the plane rather than scaling it, and the difference is the whole reason this
     * is two variables. A CSS scale() on a plane that is already a composited 3D layer magnifies
     * the bitmap the browser last drew - so every line and every room name came back soft, like a
     * photograph enlarged. Changing the width instead makes the browser lay the drawing out again
     * at its new size, and one-pixel borders stay one pixel.
     *
     * The stage measures itself against the resting size, so the window stays put while the house
     * inside it grows.
     */
    /* The cap is a guard against a drawing sprawling across an ultrawide, not a size. 760 was
       low enough that in a wide column the drawing stopped growing and the slack around it pushed
       it off the controls beside it. */
    --plane-base: min(88cqw, 880px);
    --plane-fit: calc(var(--plane-base) * var(--zoom, 1));
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 26px 0 30px;

    /* The glow the planes sit in. Cool, because the house is structure; only the answer is warm. */
    background: radial-gradient(ellipse at 50% 26%, rgba(154, 167, 240, .2), transparent 58%);
}

.storey[b-vwveoo3e7u] {
    position: relative;
    width: var(--plane-fit);
    padding-bottom: 18px;
}

/* 26px between storeys, 14 when compact — the handoff's range. */
.storey + .storey[b-vwveoo3e7u] { margin-top: 26px; }
.stack.compact .storey + .storey[b-vwveoo3e7u] { margin-top: 14px; }

/*
 * How wide the drawing may be.
 *
 * The caller states a preferred width and this is the smaller of that and the room actually
 * available. 88 rather than 100 because the tilt spreads the plane past its own box: rotateZ(-42)
 * and rotateX(58) turn a 420px plane into a 456px bounding box, so a plane at a full 100% of its
 * container still overflows by about nine per cent.
 *
 * The height comes from the width by ratio, so one number describes the drawing and the proportion
 * cannot drift away from it.
 */
.plane[b-vwveoo3e7u] {
    width: var(--plane-fit);
    aspect-ratio: 246 / 126;
    position: relative;

    /* Never shrunk to fit the stage. As a flex item the default is to give way, so the plane was
       squeezed straight back to the width of the box it is supposed to be able to overflow - the
       zoom variable changed and the drawing did not move a pixel. */
    flex: none;

    /*
     * The whole illusion. 58 degrees back, 42 round — then whatever the lens is doing.
     *
     * Right to left: the house is drawn, then scaled, then moved, which is what "zoom and pan the
     * finished picture" means. The three variables default to doing nothing, so a screen that only
     * reads a home is transformed exactly as it always was.
     */
    transform:
        translate(var(--pan-x, 0px), var(--pan-y, 0px))
        rotateX(var(--lean, 58deg)) rotateZ(-42deg);

    /*
     * The layers stand apart in space rather than merely in paint order.
     *
     * Without this they are three coplanar things drawn on top of each other, which is a diagram.
     * With it the bricks sit above the floor and the things sit above the bricks, and the gaps are
     * visible from the angle the plane is already tilted at — which is what makes it a stack you
     * can see rather than a stack you have been told about.
     *
     * Nothing inside may carry a `filter`: it creates a containing block and flattens everything
     * below it back onto one plane. That is why the floor's thickness is a box-shadow.
     */
    transform-style: preserve-3d;

    /* How tall a room stands, as a share of the floor's width — so a wide floor is never a sheet
       of paper with lines on it. Held on the plane rather than on the brick because what goes
       inside a brick has to know how deep the inside is. */
    /* Tied to the plane rather than to the page, so a brick keeps its proportions as the
       drawing is resized. 6.25% is what 5.5cqw came to against the resting width. */
    --brick: calc(var(--plane-fit) * 0.0625);

    /*
     * How heavy a line is, as a share of the drawing rather than as a fixed pixel.
     *
     * Every stroke here used to be 1px whatever size the house was drawn at. On the reading
     * screens that is 1px in 465, which is a firm wireframe; in the editor the same house is drawn
     * at 969 and every edge came out half as heavy relative to what it describes - a wireframe
     * whose wires have thinned by half, which is exactly what "washed out" looks like. Zooming
     * made it worse, which is the wrong way round: leaning in should show more, not less.
     *
     * 0.0021 is the reading screens' own measured ratio, so this changes nothing there and gives
     * the editor the same presence at any size. The floor of 1px is what keeps that true - the
     * small drawings are already at it.
     */
    --line: max(1px, calc(var(--plane-fit) * 0.0021));

    border: var(--line) solid rgba(154, 167, 240, .45);

    background:
        linear-gradient(rgba(154, 167, 240, .08), rgba(154, 167, 240, .02)),
        linear-gradient(var(--grid-upper) 1px, transparent 1px),
        linear-gradient(90deg, var(--grid-upper) 1px, transparent 1px);
    background-size: auto, 32px 32px, 32px 32px;
}

/*
 * Warm is one room, not the floor it stands on.
 *
 * The whole storey used to go warm - plate, grid, slabs, and every room and face on it - so a
 * house with a set of keys in one room lit six rooms orange. Which floor it is on was still
 * readable, but which room was not, and the colour that means "this is the thing you are looking
 * for" was being spent on five rooms that are not.
 *
 * Only .room.holds is warm now. That is still perfectly legible as a floor answer, because the one
 * warm mark is on the floor that has it, and the floor's own name is warm beside it.
 */

/*
 * A drawn floor keeps its baseplate.
 *
 * Taking the rectangle away was the mistake. The undrawn ground floor read as a solid storey
 * precisely because it had one — an outer edge for the rooms to sit inside — and the floor
 * somebody had actually built lost it and read as tiles hanging in the dark. So the plate stays,
 * dashed, because it is the extent of the drawing rather than a wall anybody built.
 */
.plane.shaped[b-vwveoo3e7u] {
    border-style: dashed;
    border-color: rgba(154, 167, 240, .3);
    box-shadow: none;

    /*
     * The plate keeps its lines.
     *
     * They were dropped with the fill, which left the baseplate as an empty dashed rectangle and
     * took away the one thing that made it read as a surface. The grid is what says "this is a
     * floor" rather than "this is a boundary", and the bricks standing on it need something to
     * stand on.
     */
    background:
        linear-gradient(var(--grid-upper) 1px, transparent 1px),
        linear-gradient(90deg, var(--grid-upper) 1px, transparent 1px);
    background-size: 24px 24px, 24px 24px;
}

/* --- layer 1: the floor ----------------------------------------------------- */

/*
 * The shape of the home, as one quiet surface.
 *
 * One piece per block, no borders, one colour, so their union is the footprint and the joins
 * vanish without anything having to compute a polygon. Quiet on purpose: this layer says how big
 * the home is and what shape, and the bricks on top of it say everything else.
 */
.slabs[b-vwveoo3e7u] { position: absolute; inset: 0; pointer-events: none; }

/* --- layer 0: the squares, while a home is being built ---------------------- */

/*
 * A grid to build on, under everything.
 *
 * It leans less than the reading view does. At 58 degrees the depth axis is compressed to 53 per
 * cent, so a square is a half-height diamond — fine to look at and fiddly to aim at, and here you
 * are aiming. At 40 it is 77 per cent, which is still plainly a room standing in a house.
 */
/*
 * The stage the house stands on.
 *
 * A plane is laid out as a 246:126 box and then rotated, and layout knows nothing about the
 * rotation: the box reserves 0.51 of its own width in height while the drawn diamond is 0.80 of
 * it. That used to be patched with margins either side, which was honest arithmetic about one
 * fixed tilt and no answer at all once the drawing can be scaled to four times its size.
 *
 * So the plane is given a box to be looked at through instead. It clips, which is what makes a
 * zoomed house stay inside its own part of the page, and it is the thing gestures are measured
 * against.
 *
 * touch-action: none, because a finger dragging here moves the house rather than the page. The
 * page is scrolled from above or below the stage - a real cost, and the right way round for a
 * tool you are building something in.
 */
.lens[b-vwveoo3e7u] {
    position: relative;

    /* The resting size, not the drawing's size. As "width: 100%" it was sized by the plane inside
       it - a stage that grows to fit whatever stands on it clips nothing, which is how a house at
       nearly twice its size walked straight out over the page. */
    width: var(--plane-base);
    flex: none;

    /* Left, not centred. The stage is narrower than the column it sits in whenever the plane hits
       its cap, and centring that slack pushed the drawing away from the floor controls beside it -
       ninety-four pixels of nothing between a control and the only thing it controls. */
    margin-right: auto;
    /* Shorter than the diamond is tall, on purpose. The plate's far corners are empty grid and
       the house sits in the middle, so reserving the whole height buys nothing and costs the
       controls their place on the screen - they were pushed below the fold by empty ground. */
    height: calc(var(--plane-base) * 0.62);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    touch-action: none;
    cursor: grab;
}

.lens.moving[b-vwveoo3e7u] { cursor: grabbing; }

/*
 * No stage on a screen that only reads.
 *
 * display: contents removes the box entirely rather than neutralising it, so the plane sits where
 * it always sat. Left in as a real element it added its own height to every storey on Now and the
 * answer screen and pushed both floors down the page - identical drawings in the wrong places,
 * which is exactly the regression this component is measured against every time.
 */
.lens.off[b-vwveoo3e7u] { display: contents; }

/* The storey is sized by the stage, never by the drawing inside it. Without this the clipped plane
   still reported its full width upwards and dragged the whole column out of the page with it. */
.storey[b-vwveoo3e7u] { max-width: 100%; }

.plane.building[b-vwveoo3e7u] { --lean: 40deg; }

.cells[b-vwveoo3e7u] { position: absolute; inset: 0; }

/*
 * The ground the house stands on, and no louder than that.
 *
 * Dashed at .18 across a window three squares clear of the house on every side, this was the
 * loudest thing on the screen - fainter per line than the building's own edges, but there is
 * vastly more of it, so it won. The reading screens draw their plate as a quiet hairline at
 * --grid-upper and the ground here belongs in the same register.
 *
 * Still 1px while the building scales with --line. It is the ground, not the building, and the
 * whole complaint was that the two carried the same weight.
 */
.cell[b-vwveoo3e7u] {
    position: absolute;
    border: 1px solid var(--grid-upper);
    background: transparent;
    touch-action: manipulation;
}

.plane.building .room[b-vwveoo3e7u] { touch-action: manipulation; }

/*
 * Flatter on a phone.
 *
 * Forty degrees is comfortable to aim at with a mouse and tight with a thumb: the squares are
 * small to begin with on a narrow screen, and the tilt takes another quarter off their height.
 * Thirty-four leaves them squarer without the drawing stopping being a drawing.
 */
@media (max-width: 640px) {
    /* Flatter leans the diamond taller still, so the stage needs more room, not less. */
    .plane.building[b-vwveoo3e7u] { --lean: 34deg; }

    .lens[b-vwveoo3e7u] { height: calc(var(--plane-base) * 0.82); }

    /*
     * One name at a time on a narrow screen.
     *
     * Six labels over a house forty pixels wide overlap each other into a smear, and a name that
     * cannot be read is worse than no name - it is clutter over the thing you are aiming at. The
     * room you are working on says its name; the panel below says it again in full.
     */
    .plane.building .naming[b-vwveoo3e7u] { display: none; }
    .plane.building .room.picked .naming[b-vwveoo3e7u] { display: block; }
}

/* Where the block will land. Every square it would cover, lit before you let go. */
.cell.ghost[b-vwveoo3e7u] {
    border-style: solid;
    border-color: var(--violet);
    background: rgba(154, 167, 240, .3);
}

/*
 * Would not go there: over something already down, or off the board.
 *
 * Red, and deliberately not the warm colour. Everywhere else in this product warm means "this is
 * the thing you are looking for", and a refusal wearing it would make the one warm mark on a
 * screen mean two things.
 */
.cell.ghost.no[b-vwveoo3e7u] {
    border-color: rgb(226, 92, 92);
    background: rgba(226, 92, 92, .22);
}

/*
 * While something is being dragged, the blocks stop answering the pointer.
 *
 * They stand above the squares, so without this a block would swallow the drag events for every
 * square underneath it — including the squares under the block being dragged, which is most of
 * where a one-square nudge is going. The ghost would simply not appear where it matters most.
 */
.plane.dragging .room[b-vwveoo3e7u] { pointer-events: none; }

/*
 * A room's name, standing up out of the drawing.
 *
 * The plane is rotated forty degrees back and forty-two round; the label undoes both, in reverse
 * order, so the word faces the reader while its anchor stays in the room. Without this it is a
 * skewed smear that has to be decoded rather than read.
 */
.naming[b-vwveoo3e7u] {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translateZ(calc(var(--brick) * 1.4)) rotateZ(42deg) rotateX(-40deg)
        translate(-50%, -50%);
    font: 700 11px/1 var(--face-body);
    color: var(--ink);
    text-shadow: 0 1px 3px rgba(11, 13, 22, .9);
    white-space: nowrap;
    pointer-events: none;
}

/* Picked up: lifted off the plate and lit, so selection reads as holding it. */
.room.picked[b-vwveoo3e7u] {
    transform: translateZ(calc(var(--brick) * 1.9));
    border-color: var(--violet-bright);
    box-shadow: 0 0 18px rgba(154, 167, 240, .55);
}

.slab[b-vwveoo3e7u] {
    position: absolute;
    background: rgba(154, 167, 240, .07);
    outline: var(--line) solid rgba(154, 167, 240, .16);
}

/* --- layer 2: the bricks ---------------------------------------------------- */

/*
 * A room is a brick, and a brick has a top and a side.
 *
 * Flat outlines made twelve rooms into one chequered surface. A brick has a thickness under it, so
 * it sits on the floor rather than being painted onto it, and there is daylight between it and its
 * neighbours — which is the only thing that says where one room stops.
 *
 * The thickness is a box-shadow with no blur, which in a rotated plane reads as the brick's side.
 * No drop-shadow here: those chain, each filtering the last, and a run of them floods the shape
 * solid.
 */
/*
 * A room is a brick, and a brick is a box.
 *
 * Two real faces, not a shadow pretending to be one. The plane is already a 3D space — it has
 * transform-style: preserve-3d — so the top of the brick is the element itself lifted off the
 * plate, and two pseudo-elements hinge down from its near and right edges to make the sides that
 * this camera angle can see. The other two faces are behind the brick and would never be drawn, so
 * they are not built.
 *
 * Wireframe: the faces are barely filled and their edges carry the drawing. A floor of twelve
 * solid blocks is a mass, and the point of drawing the house at all is to see through it to the
 * one room that matters.
 */
.room[b-vwveoo3e7u] {
    position: absolute;
    transform-style: preserve-3d;
    transform: translateZ(var(--brick));

    border: var(--line) solid rgba(194, 202, 255, .6);

    /*
     * The lid, and you can see through it.
     *
     * It was nearly opaque, which closed the box and hid everything the box was drawn to show.
     * A room whose sensor and whose contents are behind its own ceiling is a room drawn for its
     * own sake — sheer enough that what is inside reads, solid enough that the box still has a
     * top.
     */
    background: rgba(35, 42, 74, .3);
}

/*
 * The sides of the brick.
 *
 * All four are built and the browser culls the two facing away — backface-visibility does the work
 * that guessing at the camera angle did badly, and got wrong: two hand-picked faces meant every
 * brick was missing the sides the view actually showed.
 *
 * A face is only emitted where that side is a wall. A seam inside a room has no face, which is
 * what lets two blocks of one hallway stand as a single brick instead of two flush ones with a
 * wall between them.
 */
.face[b-vwveoo3e7u] {
    position: absolute;
    background: rgba(154, 167, 240, .14);
    border: var(--line) solid rgba(194, 202, 255, .38);
}

.face.n[b-vwveoo3e7u], .face.s[b-vwveoo3e7u] { left: -1px; right: -1px; height: var(--brick); }
.face.w[b-vwveoo3e7u], .face.e[b-vwveoo3e7u] { top: -1px; bottom: -1px; width: var(--brick); }

/*
 * The walls hang down from the lid. All four of them folded the same way — upward — so every
 * brick came out an open tray with its sides rising and no top at all, and the element that was
 * meant to be the lid was acting as the floor.
 *
 * Signs matter here and are easy to get backwards: a face hinged at an edge and rotated one way
 * swings toward the viewer, the other way away from them. These four all swing away, down to the
 * plate the brick stands on.
 */
.face.n[b-vwveoo3e7u] { top: 0; transform-origin: top center; transform: rotateX(-90deg); }
.face.s[b-vwveoo3e7u] { bottom: 0; transform-origin: bottom center; transform: rotateX(90deg); }
.face.w[b-vwveoo3e7u] { left: 0; transform-origin: center left; transform: rotateY(90deg); }
.face.e[b-vwveoo3e7u] { right: 0; transform-origin: center right; transform: rotateY(-90deg); }

/* The room actually holding something. Filled, because this one is the answer. */
.room.holds[b-vwveoo3e7u] {
    border-color: var(--hot-core);
    background: rgba(246, 160, 107, .5);
    box-shadow: 0 0 22px rgba(255, 217, 184, .6);
}

.room.holds .face[b-vwveoo3e7u] {
    background: rgba(246, 160, 107, .38);
    border-color: rgba(255, 217, 184, .7);
}

/* --- layer 3: what is in the rooms ------------------------------------------ */

/*
 * Inside the rooms, not hovering over them.
 *
 * These floated above the lids, which put every sensor and every located thing in the air above
 * the house rather than in the room it is actually in — and on a tilted plane a dot above a room
 * sits visually over the room behind it, so the drawing pointed at the wrong one.
 *
 * Halfway up the brick, so it reads as being in the room's volume, seen through a sheer ceiling.
 */
.ear[b-vwveoo3e7u], .bloom[b-vwveoo3e7u], .ping[b-vwveoo3e7u], .core[b-vwveoo3e7u] {
    position: absolute;
    transform: translateZ(calc(var(--brick) / 2)) translate(-50%, -50%);
    border-radius: var(--r-pill);
    pointer-events: none;
}

/*
 * A sensor, where it actually is in the room.
 *
 * Small and cool: where the house can hear is a different kind of fact from where a thing is, and
 * a second warm mark would read as a second grade of answer.
 */
.ear[b-vwveoo3e7u] {
    width: 6px;
    height: 6px;
    background: rgba(194, 202, 255, .95);
    box-shadow: 0 0 10px rgba(154, 167, 240, .95);
}

/*
 * How the sensor says it is doing, as light rather than as a colour.
 *
 * Warm means "the thing you are looking for" everywhere else in this product, and a struggling
 * sensor drawn warm would sit beside the warm room holding your keys meaning something else
 * entirely — one screen, one warm mark, one meaning. So attention comes from the absence of light
 * instead: a well sensor glows, a struggling one is dim and ringed, a dark one is hollow.
 *
 * Three states and no more. A dot on a picture of a house cannot convey heap fragmentation, and
 * the numbers behind these belong on the sensors page where there is room to print them.
 */
.ear.poorly[b-vwveoo3e7u] {
    width: 8px;
    height: 8px;
    background: transparent;
    border: 1px dashed rgba(194, 202, 255, .75);
    box-shadow: none;
}

.ear.dark[b-vwveoo3e7u] {
    width: 8px;
    height: 8px;
    background: transparent;
    border: 1px solid rgba(230, 233, 255, .28);
    box-shadow: none;
}

/* The halo under the thing, which is what finds it at a glance. */
.bloom[b-vwveoo3e7u] {
    width: 44px;
    height: 44px;
    background: radial-gradient(circle, rgba(255, 217, 184, .4), rgba(246, 160, 107, 0) 70%);
}

/*
 * The ring going out from it. The only thing on the screen that moves.
 *
 * Slow — 2.4s — because this is the idle rate. It says "this is live" and nothing more urgent; a
 * fast pulse would read as an alarm about a set of keys sitting on a shelf.
 */
.ping[b-vwveoo3e7u] {
    width: 46px;
    height: 46px;
    border: 1px solid rgba(255, 217, 184, .55);
    animation: ping 2.4s ease-out infinite;
}

.core[b-vwveoo3e7u] {
    width: 11px;
    height: 11px;
    background: var(--hot-core);
    box-shadow: 0 0 18px rgba(255, 244, 230, 1);
}

/* --- the words, upright ----------------------------------------------------- */

.label[b-vwveoo3e7u] {
    position: absolute;
    left: 0;
    bottom: 0;

    font-family: var(--face-mono);
    font-weight: 600;
    font-size: 9.5px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--ink-mono);
}

.label.warm[b-vwveoo3e7u] { color: var(--hot); }

/* Which room, spelled out, because the lit piece is a few pixels across. */
.here[b-vwveoo3e7u] {
    position: absolute;
    right: 0;
    bottom: 0;
    padding-left: 14px;

    font-family: var(--face-body);
    font-weight: 700;
    font-size: 13px;
    color: var(--hot-bright);
}

/* Ties the word to the room: the same warm mark, on the label. */
.here[b-vwveoo3e7u]::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 7px;
    height: 7px;
    margin-top: -3.5px;
    border-radius: var(--r-pill);
    background: var(--hot-bright);
    box-shadow: 0 0 10px rgba(255, 217, 184, .9);
}

/*
 * The viewport queries that used to live here are gone.
 *
 * Three of them scaled the plane at 360, 1100, 1600 and 2000 pixels of window - which is the wrong
 * measurement. How big the house should be drawn is a fact about the column it is drawn in, and
 * the container query above answers that everywhere the component is placed, including the wide
 * column on Now where those queries were originally right by luck.
 */
