/*
 * The hologram palette, from the design handoff.
 *
 * Two colours carry the whole product: violet is structure - the house, the sensors, anything
 * that is simply there - and terracotta is the live answer, the thing you are looking for. That
 * split is the reason the screens read at a glance, so resist adding a third accent; a palette
 * where everything is highlighted highlights nothing.
 *
 * The older names below are kept as aliases rather than deleted. Sixteen scoped stylesheets
 * reference them, and renaming every one in the same change as introducing a new palette would
 * mean no single revert could undo either.
 */
:root {
    /* Ground */
    --ground: #0b0d16;
    --ground-raised: #0f1120;
    --chrome: #141728;

    /* Ink */
    --ink: #e6e9ff;
    --ink-body: rgba(230, 233, 255, .85);
    --ink-quiet: rgba(230, 233, 255, .7);

    /*
     * The floor for small type, and an accessibility rule rather than a style choice: the
     * handoff is explicit that 9.5-11px instrumentation never goes below .62 alpha. Anything
     * dimmer stops being quiet and starts being unreadable.
     */
    --ink-mono: rgba(230, 233, 255, .62);

    /* Structure */
    --violet: #9aa7f0;
    --violet-bright: #c2caff;

    /* The live match */
    --hot: #f6a06b;
    --hot-bright: #ffd9b8;
    --hot-core: #fff4e6;

    /* Hairlines and fills, all over the ground */
    --hair: rgba(230, 233, 255, .13);
    --hair-violet: rgba(154, 167, 240, .24);
    --fill-ink: rgba(230, 233, 255, .05);
    --fill-violet: rgba(154, 167, 240, .09);
    --fill-hot: rgba(246, 160, 107, .12);

    /* Grid lines on the stack's planes */
    --grid-upper: rgba(154, 167, 240, .12);
    --grid-lower: rgba(246, 160, 107, .15);

    /* Geometry. Every button, chip and input is a pill. */
    --r-pill: 999px;
    --r-panel: 22px;
    --r-row: 18px;
    --r-row-tight: 16px;

    /* Type */
    --face-display: "Space Grotesk", ui-sans-serif, system-ui, "Segoe UI", sans-serif;
    --face-body: Figtree, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
    --face-mono: ui-monospace, Menlo, "Cascadia Mono", Consolas, monospace;

    /* --- aliases, so the existing scoped stylesheets keep working --- */
    --bg: var(--ground);
    --panel: var(--ground-raised);
    --panel-2: var(--chrome);
    --ink-dim: var(--ink-quiet);
    --line: var(--hair);
    --accent: var(--violet);

    /* There is no green in this palette. "Fine" is structure, so it is violet like the rest of
       the things that are simply there; only the live answer and a genuine fault are warm. */
    --ok: var(--violet);
    --bad: var(--hot);

    /* The plan editor's drawing surface. Dark now, so it sits in the same room as everything
       else - a sheet of white paper in this palette reads as a hole in the screen. */
    --floor: #10131f;
    --floor-line: rgba(154, 167, 240, .22);
}

/*
 * Motion. Two keyframes, and the handoff is explicit that nothing else moves.
 */
@keyframes ping {
    0% { transform: scale(.2); opacity: .9; }
    70% { opacity: .15; }
    100% { transform: scale(1); opacity: 0; }
}

@keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: .25; }
}

/*
 * Required by the handoff, and the right default regardless: a pulsing ring around the thing
 * somebody is hunting for is exactly the kind of motion that makes some people ill.
 */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--face-body);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

/* The display face is for answers and titles only - a room name, a screen heading, a stat.
   It has one weight and no italic, so it is unusable for anything running longer than a line. */
/* 600, not 400: the old display face had one weight and got its presence from being fat by
   design. This one is a grotesque and has to be asked. */
h1, h2, h3, .display { font-family: var(--face-display); font-weight: 600; letter-spacing: -.02em; }

code { font-family: var(--face-mono); font-size: 0.9em; }

/*
 * Every button, chip and input is a pill.
 *
 * The handoff states this as an absolute rather than a preference, and it is the single rule that
 * does most to make a screen look like it belongs to this product - a 6px corner and a 999px one
 * read as two different pieces of software sitting next to each other.
 *
 * Forced, which wants explaining. Blazor's scoped stylesheets compile to attribute selectors, so
 * every component rule outranks a plain element rule here no matter how it is written; the choice
 * is this or editing the same declaration in sixteen files and re-editing it in each new one.
 * A design-system invariant is exactly the kind of rule that earns the override.
 *
 * Deliberately not applied inside the plan editor, which is a drafting tool rather than one of
 * these screens and whose small square controls are correct for what it is. It is the one page
 * that renders inside .shell, which is what excludes it here.
 */
button:not(.shell *),
input:not([type="checkbox"]):not([type="radio"]):not(.shell *),
select:not(.shell *) {
    border-radius: var(--r-pill) !important;
}

/*
 * Instrumentation: node ids, dBm, ages, hints. Upright, wide-tracked, upper case and small.
 *
 * It is a separate voice on purpose - these are readings rather than prose, and setting them
 * like prose invites somebody to read them as a sentence about the house.
 */
.mono {
    font-family: var(--face-mono);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--ink-mono);
}

.shell {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    padding: 24px;
    min-height: 100vh;
}

.canvas-pane { flex: 0 0 auto; }

h1 {
    margin: 0 0 4px;
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
}

h2 {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-dim);
}

.subtle { color: var(--ink-dim); font-weight: 400; font-size: 0.85em; }

a.elsewhere {
    float: right;
    font-size: 12.5px;
    font-weight: 400;
    color: var(--accent);
    text-decoration: none;
}

a.elsewhere:hover { text-decoration: underline; }

.waiting, .hint, .note {
    color: var(--ink-dim);
    font-size: 12.5px;
    margin: 10px 0 0;
    max-width: 46ch;
}

/* ---- floor plan ---- */

svg.floor {
    display: block;
    margin-top: 12px;
    border-radius: 10px;
    background: var(--floor);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.45);
    touch-action: none;
    user-select: none;
    cursor: crosshair;
}

svg.floor .bg { fill: var(--floor); }

svg.floor .room {
    fill: none;
    stroke: var(--floor-line);
    stroke-width: 1.5;
}

svg.floor .wall { stroke-width: 5; stroke-linecap: round; opacity: 0.75; }
svg.floor .wall.plasterboard { stroke: #b9b0a0; }
svg.floor .wall.woodendoor   { stroke: #c39a63; }
svg.floor .wall.brick        { stroke: #a1685a; }
svg.floor .wall.concrete     { stroke: #7d7d7d; }
svg.floor .wall.foilinsulation { stroke: #5a6a7a; }

svg.floor .obstacle {
    fill: rgba(90, 80, 65, 0.16);
    stroke: rgba(90, 80, 65, 0.4);
    stroke-width: 1;
}

svg.floor .surface {
    fill: none;
    stroke: rgba(60, 90, 120, 0.45);
    stroke-width: 1.2;
    stroke-dasharray: 5 4;
}

/* Room names. Drawn over the heatmap because the name is the answer, not the blob. */
svg.floor text.room-label {
    font-size: 12px;
    font-weight: 600;
    fill: #6b6357;
    text-anchor: middle;
    pointer-events: none;
    paint-order: stroke;
    stroke: rgba(244, 241, 234, 0.85);
    stroke-width: 3.5px;
    stroke-linejoin: round;
}

/* The room the estimate actually names, so it is legible without reading the blob. */
svg.floor .room-group.named .room { fill: rgba(86, 168, 255, 0.1); stroke: #56a8ff; }
svg.floor .room-group.named text.room-label { fill: #245c8c; }

svg.floor text.label {
    font-size: 10px;
    fill: #7a7266;
    text-anchor: middle;
    pointer-events: none;
}

svg.floor text.subtle-label { fill: #8d99a8; }

svg.floor .node circle {
    fill: #1c2029;
    stroke: var(--accent);
    stroke-width: 2.5;
    cursor: grab;
}

svg.floor .node.dragging circle { stroke: #fff; cursor: grabbing; }

svg.floor .node text {
    font-size: 11px;
    font-weight: 600;
    fill: #e8eaee;
    text-anchor: middle;
    pointer-events: none;
}

svg.floor .truth line {
    stroke: #111;
    stroke-width: 2.5;
    stroke-linecap: round;
}

svg.floor .estimate .halo {
    fill: none;
    stroke: rgba(255, 255, 255, 0.9);
    stroke-width: 5;
}

svg.floor .estimate .ring {
    fill: none;
    stroke: #14171c;
    stroke-width: 2.2;
    stroke-dasharray: 4 3;
}

/* The trail sits under the posterior and must not compete with it. */
svg.floor image.trail-layer { opacity: 0.55; mix-blend-mode: multiply; }

svg.floor .route {
    fill: none;
    stroke: #2b3a55;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
    opacity: 0.8;
    stroke-dasharray: 6 4;
}

/* The journey: where it has been, as stays rather than as a decaying trail. */
svg.floor .journey {
    fill: none;
    stroke: #7a5ea8;
    stroke-width: 2.2;
    stroke-linejoin: round;
    stroke-linecap: round;
    opacity: 0.7;
    stroke-dasharray: 7 5;
}

svg.floor .stop {
    fill: #7a5ea8;
    stroke: var(--floor);
    stroke-width: 1.6;
}

svg.floor .stop.here {
    fill: #4b3d6b;
    stroke-width: 2.4;
}

/* A stay that could only be placed to within a room. Hollow and wide, because the size is the
   uncertainty — drawing it as a dot would claim a spot on the floor nobody worked out. These
   used to be written as 0,0 and plotted in the corner of the flat. */
svg.floor .stop.roughly {
    fill: rgba(122, 94, 168, 0.13);
    stroke: #7a5ea8;
    stroke-width: 1.4;
    stroke-dasharray: 4 3;
}

/* The playback marker. Deliberately unlike the live estimate ring: a recording must never be
   mistaken for the present. */
svg.floor .playhead .pulse {
    fill: rgba(122, 94, 168, 0.22);
    stroke: none;
}

svg.floor .playhead .dot {
    fill: #4b3d6b;
    stroke: var(--floor);
    stroke-width: 2;
}

.panel section.replaying {
    background: rgba(122, 94, 168, 0.08);
    border-radius: 8px;
    padding-left: 10px;
    padding-right: 10px;
    margin-left: -10px;
    margin-right: -10px;
}

.note.recording { color: var(--bad); }

.journey-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 12.5px;
}

.journey-list li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 8px;
    border-radius: 6px;
    border-left: 3px solid transparent;
    background: rgba(122, 94, 168, 0.08);
}

.journey-list li.here {
    border-left-color: #9d80cf;
    background: rgba(122, 94, 168, 0.2);
}

.journey-list .room { flex: 1 1 auto; font-weight: 600; }
.journey-list .when { color: var(--ink-dim); font-variant-numeric: tabular-nums; }

.journey-list .how-long {
    flex: 0 0 auto;
    color: var(--ink-dim);
    font-variant-numeric: tabular-nums;
    min-width: 62px;
    text-align: right;
}

/* The gap between the estimate and the truth, drawn rather than only tabulated. */
svg.floor .miss {
    stroke: #14171c;
    stroke-width: 1.4;
    stroke-dasharray: 2 4;
    opacity: 0.55;
}

/* Everything is inert except the backdrop, so pointer coordinates are always relative to
   the full canvas and hit-testing can be done in world units on the server. */
svg.floor image { pointer-events: none; }
svg.floor polygon, svg.floor line, svg.floor text, svg.floor circle { pointer-events: none; }
svg.floor .bg { pointer-events: all; }

.legend {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    font-size: 11.5px;
    color: var(--ink-dim);
}

.legend .ramp {
    flex: 0 0 130px;
    height: 9px;
    border-radius: 5px;
    background: linear-gradient(90deg,
        rgba(70, 105, 180, 0.12) 0%,
        rgba(34, 150, 145, 0.55) 38%,
        rgba(240, 178, 62, 0.8) 68%,
        rgba(214, 58, 45, 0.95) 100%);
}

/* ---- panel ---- */

.panel {
    flex: 0 0 320px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 18px;
}

.panel section { padding: 14px 0; border-top: 1px solid var(--line); }
.panel section:first-of-type { border-top: none; padding-top: 4px; }

.status {
    font-size: 12px;
    padding: 6px 10px;
    border-radius: 6px;
    margin-bottom: 6px;
    display: inline-block;
}

.status.ok  { background: rgba(75, 191, 115, 0.15); color: var(--ok); }
.status.bad { background: rgba(217, 119, 87, 0.15); color: var(--bad); }

.row { display: flex; gap: 8px; }

/* A room per button, so a flat with six of them does not squeeze them to nothing. */
.row.wrap { flex-wrap: wrap; }
.row.wrap button { flex: 1 1 auto; min-width: 84px; }

/* The one question only the person standing there can answer, asked once. */
.truth {
    margin-top: 10px;
    padding: 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel-2);
}

.truth .note { margin-top: 0; }

button {
    flex: 1;
    padding: 7px 12px;
    background: var(--panel-2);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 7px;
    font-size: 13px;
    cursor: pointer;
}

button:hover:not(:disabled) { border-color: var(--accent); color: #fff; }
button:disabled { opacity: 0.4; cursor: not-allowed; }

/* Armed: one more click destroys something there is no undo for. */
button.armed {
    border-color: var(--bad);
    background: rgba(217, 119, 87, 0.16);
    color: var(--bad);
}

button.armed:hover:not(:disabled) { border-color: var(--bad); color: var(--bad); }

label.radio, label.check {
    display: block;
    padding: 4px 0;
    font-size: 13px;
    cursor: pointer;
}

/* A control with nothing behind it. Kept visible on purpose — knowing a layer exists and is
   unavailable is worth more during development than a tidy panel that hides it. */
label.radio.dead, label.check.dead { opacity: 0.42; cursor: not-allowed; }

label.field {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    padding: 5px 0;
    font-size: 13px;
    color: var(--ink-dim);
}

select, input[type="number"] {
    background: var(--panel-2);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 5px 8px;
    font-size: 13px;
    width: 140px;
}

dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 14px;
    margin: 0;
    font-size: 13px;
}

dt { color: var(--ink-dim); }
dd { margin: 0; font-variant-numeric: tabular-nums; }
dd.error { color: var(--accent); font-weight: 600; }

@media (max-width: 900px) {
    .shell { flex-direction: column; }
    .panel { flex: 1 1 auto; width: 100%; max-width: 640px; }
}

/* ---- sign in ---- */

.signin {
    max-width: 340px;
    margin: 12vh auto;
    padding: 26px 28px 30px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 14px;
}

.signin h1 { margin-bottom: 2px; }
.signin > .subtle { display: block; margin-bottom: 22px; font-size: 13px; }

.signin form { display: flex; flex-direction: column; gap: 14px; }

label.field-block {
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--ink-dim);
}

label.field-block input {
    width: 100%;
    background: var(--panel-2);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 7px;
    padding: 9px 11px;
    font-size: 14px;
    text-transform: none;
    letter-spacing: normal;
}

label.field-block input:focus {
    outline: none;
    border-color: var(--accent);
}

button.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #0d1116;
    font-weight: 600;
    padding: 9px 12px;
}

button.primary:hover:not(:disabled) { color: #0d1116; filter: brightness(1.08); }

.signin-error {
    margin: 14px 0 0;
    padding: 8px 11px;
    border-radius: 7px;
    background: rgba(217, 119, 87, 0.14);
    border-left: 3px solid var(--bad);
    color: var(--bad);
    font-size: 12.5px;
}

/* ---- who is signed in ---- */

.whoami {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 12px;
    color: var(--ink-dim);
    margin-bottom: 10px;
}

.whoami .home { font-weight: 600; color: var(--ink); }
.whoami form { margin-left: auto; }

.whoami button {
    background: none;
    border: none;
    color: var(--ink-dim);
    font-size: 12px;
    padding: 0;
    cursor: pointer;
    text-decoration: underline;
}

.whoami button:hover { color: var(--accent); }

/* ---- things on the map ---- */

svg.floor .pin .disc {
    fill: var(--floor);
    stroke: #5c6470;
    stroke-width: 2;
}

svg.floor .pin.selected .disc { stroke: var(--accent); stroke-width: 3; }

svg.floor .pin .glyph {
    font-size: 15px;
    text-anchor: middle;
    pointer-events: none;
}

svg.floor .pin .pin-label {
    font-size: 11px;
    font-weight: 600;
    fill: #4a4a52;
    text-anchor: middle;
    pointer-events: none;
    paint-order: stroke;
    stroke: rgba(244, 241, 234, 0.9);
    stroke-width: 3.5px;
    stroke-linejoin: round;
}

/* ---- things list ---- */

.things { display: flex; flex-direction: column; gap: 4px; }

.thing {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 5px 8px;
    border-radius: 7px;
    border-left: 3px solid transparent;
    background: var(--panel-2);
    cursor: pointer;
}

.thing:hover { border-left-color: var(--line); }
.thing.selected { border-left-color: var(--accent); background: rgba(86, 168, 255, 0.12); }

.thing .glyph { flex: 0 0 auto; font-size: 15px; }

.thing input.name {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    background: none;
    border: 1px solid transparent;
    border-radius: 5px;
    color: var(--ink);
    font-size: 13px;
    padding: 2px 4px;
}

.thing input.name:hover { border-color: var(--line); }
.thing input.name:focus { outline: none; border-color: var(--accent); background: var(--panel); }

.thing .where { flex: 0 0 auto; font-size: 12px; color: var(--ink-dim); text-align: right; }
.thing .where .ago { opacity: 0.75; }
.thing .where .lost { color: var(--bad); }

.thing button.drop {
    flex: 0 0 22px;
    padding: 2px 0;
    font-size: 11px;
    background: none;
    border: none;
    color: var(--ink-dim);
}

.add-thing { margin-top: 10px; display: flex; flex-direction: column; gap: 2px; }
.add-thing .pair { display: flex; gap: 6px; }
.add-thing .pair input { width: 67px; }

/* The sensor-to-sensor check. A list of links, not a table: three sensors make three links and
   six make fifteen, and a column layout would be unreadable long before that matters. */
.panel ul.links {
    list-style: none;
    margin: 0.35rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.panel ul.links li {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    font-size: 0.82rem;
}

.panel ul.links .pair {
    font-weight: 600;
}

/* Said once, in the one place it matters: the geometry everything else is derived from is
   wrong. Amber rather than red — it is a measurement to act on, not a failure. */
.panel .note.warn {
    color: #e0a458;
}

/* ============================================================================
 * The page shell
 *
 * One shell for every screen inside the app, lifted from what /easy already did and proved.
 *
 * Every page used to invent its own. Measured at 1500px there were five wrappers, four heading
 * sizes and four top paddings across six screens, and exactly one of them - Now - used the width
 * it was given. Worse, the lesson was already written down in Easy.razor.css and never left it:
 * "this screen was drawn at 402px and then centred in whatever it was opened on, so on a wide
 * monitor it was a narrow ribbon of content in a field of nothing".
 *
 * So the ribbon-in-a-field fix lives here now, once, and pages ask for it by name.
 * ========================================================================== */

.page {
    min-height: 100vh;
    box-sizing: border-box;
    padding: 40px 22px 72px;

    /* The light the planes sit in. Cool, because the house is structure and only the answer is
       warm - the same rule the drawing itself follows. */
    background:
        radial-gradient(120% 70% at 50% 0%, rgba(154, 167, 240, .10) 0%, transparent 62%),
        var(--ground);

    color: var(--ink);
    font-family: var(--face-body);
    -webkit-font-smoothing: antialiased;
}

/* One measure for a page that is a single column of reading. */
.page > .column { max-width: 620px; margin: 0 auto; }

/*
 * A single column for a page whose one thing is wide.
 *
 * Not everything belongs in two columns. The split is right when the second column is a list long
 * enough to stand beside a drawing; it is wrong when it holds four controls, because then the
 * things that belong underneath the drawing end up beside it with a void below them. Wider than
 * .column so the drawing has room, and still one column so under means under.
 */
.page > .broad { width: 100%; max-width: 620px; margin: 0 auto; }

@media (min-width: 1100px) {
    .page > .broad { max-width: 1180px; }
}

/*
 * A desk is not a tall phone.
 *
 * Past 1100 the page splits: the one thing worth looking at on the left, everything that is a
 * list on the right. Past 1600 the two stop being equal - the list keeps a readable measure and
 * every pixel beyond it goes to the drawing, which is the only thing here that is better bigger.
 *
 * Children say which side they are on rather than the grid naming them, so a second page can use
 * this without teaching it about headlines and houses.
 */
.page > .split {
    /* width: 100% because auto side margins cancel stretch on a flex child, and one of these
       pages is a flex column so its sticky footer has a floor. Without it the split sized itself
       to its own content there and came out half the width it was allowed. A shell should not
       depend on what kind of box its page happens to be. */
    width: 100%;
    max-width: 620px;
    margin: 0 auto;
}

@media (min-width: 1100px) {
    .page > .split {
        max-width: 1180px;
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: 40px;
        align-items: start;
    }

    /* Everything is a list on the right, unless it says otherwise. */
    .page > .split > * { grid-column: 2; }

    /* Across both, for anything about the whole screen. */
    .page > .split > .wide { grid-column: 1 / -1; }

    /*
     * The left column, and it holds.
     *
     * Spanning many rows rather than one: the right column is a list of unknown length, and
     * without the span this would be one row tall with the rest of the column empty beneath it.
     * Sticky, so it stays on screen while somebody reads down the other side.
     */
    .page > .split > .tall {
        grid-column: 1;
        grid-row: 3 / span 99;
        position: sticky;
        top: 24px;
    }
}

@media (min-width: 1600px) {
    .page > .split { max-width: 1560px; grid-template-columns: minmax(0, 1fr) 520px; }
}

@media (min-width: 2000px) {
    .page > .split { max-width: 1880px; grid-template-columns: minmax(0, 1fr) 560px; }
}

/*
 * A raised surface: the drawing, a sensor, a card of anything.
 *
 * One definition, so a card on Sensors and the drawing on Now are the same object seen twice
 * rather than two things that happen to resemble each other.
 */
.surface {
    background: var(--ground-raised);
    border: 1px solid var(--hair-violet);
    box-shadow:
        0 1px 1px rgba(0, 0, 0, .04),
        0 24px 48px -28px rgba(0, 0, 0, .4);
}

/*
 * One heading, one size, on every page inside the app.
 *
 * There were four - 33, 30, 28 and 20 - which is four different claims about how important the
 * top of a page is. This is Now's, because Now is the screen this product is judged by.
 *
 * Scoped to .page rather than set on h1 globally: the door screens set their question larger on
 * purpose, and the older panels in this file have their own idea of a heading that is not worth
 * disturbing to make a number match.
 */
.page h1 {
    margin: 0 0 26px;
    font-size: clamp(25px, 6.4vw, 33px);
    line-height: 1.2;
    font-weight: 600;
    letter-spacing: -.021em;
    text-wrap: balance;
}

/* Small caps furniture: the register every label on every screen is set in. */
.stamp {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .155em;
    text-transform: uppercase;
    color: var(--ink-quiet);
}
