﻿@charset "UTF-8";
/* ############################################################################
   QLYNIC  ·  sms-inbox.css
   PAGE EXTENSION SHEET   —   ~/public/css/sms-inbox.css
   ----------------------------------------------------------------------------
   PAGE ......... public/SmsInbox.aspx
   SYSTEM ....... Qlynic Marketing UI · MERIDIAN v1
   PREFIX ....... .qsm- (page-local only)

   ══ THIS FILE DECLARES NO DESIGN ═════════════════════════════════════════
   No colours, no type scale, no spacing scale. Every value is var(--qm-*).
   If a value here is not a token, it is a mechanical dimension — a track
   width, a pin travel — and it is commented as one.

   ══ ONE NAME, ONE OWNER ══════════════════════════════════════════════════
   Every class in this file is defined in exactly one place. On the switching
   page two blocks styled .qsw-note and .qsw-fork independently, and margin
   notes three sections apart silently inherited a 72px top margin from a
   paragraph they had nothing to do with. If a name is taken, take another.

   ══ THE PAGE'S GESTURES, ONE PER SECTION, NO REPEATS ═════════════════════
     01  THE ACQUIRE    one scan lights the panel; each bolt throws as it passes
     02  THE TEST       three disclosures go dark, one after another
     03  THE RESOLVE    six sends settle; one turns over long after the rest
     04  THE MONTH      thirty columns accumulate and cross a line
     05  THE NON-ANSWER a reply is thought about, and never composed
   ############################################################################ */


/* ============================================================================
   01 · SHELL
   ============================================================================ */
.qsm {
    position: relative;
    background: var(--qm-bg-0);
    color: var(--qm-text);
}

/* a late-evening wash — this is a page about the phone at 11:47pm, and the
   light should be coming from one lamp and one screen, not from the room */
.qsm-tex--night {
    background: radial-gradient( 44rem 30rem at 16% -8%, rgba(214, 228, 255, 0.045), transparent 62% ), radial-gradient( 52rem 28rem at 88% 108%, var(--qm-azure-tint), transparent 66% );
}



/* ── 1.1 · THE FLOOR ──────────────────────────────────────────────────────
   A grid laid flat in perspective and drifting toward the reader, so the
   panel above it has a world to float over rather than a colour to sit on.

   TWO THINGS THAT ARE NOT DESIGN VALUES, and are therefore allowed here:
     · the mask gradient uses black/transparent. A mask channel is alpha
       geometry, not a colour — there is no token for "opaque".
     · 64px is a grid pitch and 74deg is a horizon angle. Both are optical,
       and both are commented rather than tokenised because no token means
       "one grid square".

   IT DRIFTS BY TRANSFORM, NOT BY background-position, because a background
   animation on an element this size repaints the whole layer every frame and
   a transform does not.
   ---------------------------------------------------------------------- */
.qsm-floor {
    position: absolute;
    inset: auto 0 -6% 0;
    height: 62%;
    perspective: 420px;
    perspective-origin: 50% 0%;
    overflow: hidden;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, black 26%, black 80%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0%, black 26%, black 80%, transparent 100%);
}

.qsm-floor__grid {
    position: absolute;
    left: -60%;
    right: -60%;
    top: 0;
    height: 320%;
    transform-origin: 50% 0%;
    /* one grid square is 88px before projection. It was 64 and rule-faint,
       and at 74 degrees the near squares compressed into a smudge and the far
       ones vanished — a floor you cannot see is not a floor, it is noise. */
    background-image: repeating-linear-gradient(90deg, var(--qm-rule-strong) 0 1px, transparent 1px 88px), repeating-linear-gradient(0deg, var(--qm-rule-strong) 0 1px, transparent 1px 88px);
    animation: qsm-floor-drift 9s linear infinite;
}

@keyframes qsm-floor-drift {
    from {
        transform: rotateX(74deg) translateY(0);
    }

    to {
        transform: rotateX(74deg) translateY(88px);
    }
}

/* ============================================================================
   02 · ENTRANCE
   ----------------------------------------------------------------------------
   Both selector forms are listed on purpose. The observer puts .qsm-in on the
   element it saw, which is sometimes the element being animated and sometimes
   an ancestor of it. A rule written only as `.qsm-in .qsm-rise` silently does
   nothing when the observed element IS the .qsm-rise.
   ============================================================================ */
/* ══ THE START STATE IS SCOPED TO SCRIPTING ══════════════════════════════
   Unscoped, `opacity: 0` here renders the ENTIRE PAGE blank when JavaScript
   is off or has not run yet: nothing but the observer ever adds `.qsm-in`, so
   nothing ever comes back. The inline script adds `.qsm-js` to the wrapper as
   its first act for exactly this reason — it just was not being read here.

   SPECIFICITY, DELIBERATELY: this becomes (0,2,0), the same weight as the
   armed rules below it. They win on source order because they are below it.
   Anything inserted between them and this rule breaks the entrance. */
.qsm-js .qsm-rise {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--qm-t-slow) var(--qm-ease) var(--qsm-d, 0ms), transform var(--qm-t-slow) var(--qm-ease) var(--qsm-d, 0ms);
}

.qsm-in .qsm-rise,
.qsm-rise.qsm-in {
    opacity: 1;
    transform: none;
}


/* ============================================================================
   03 · THE COMPOSITION
   ----------------------------------------------------------------------------
   A split, so the headline is qm-h1 (32–48px) and NOT qm-hero-title (48–92px).
   The kit's hero size assumes the full measure; dropped into a 1fr column it
   runs to four lines and swallows the argument.
   ============================================================================ */
.qsm-split {
    display: grid;
    gap: clamp(2.5rem, 5vw, 4rem);
    align-items: center;
    margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

@media (min-width: 68rem) {
    .qsm-split {
        grid-template-columns: 1fr 1.02fr;
        gap: clamp(3rem, 5vw, 5rem);
    }
}

/* min-width:0 is not decoration. A grid item defaults to min-width:auto, so
   it refuses to shrink below its longest unbreakable child — at 320px the
   button labels alone held this column at 317px inside a 280px track, and
   .qm-hero's overflow-x:clip hid the evidence instead of producing a
   scrollbar. Clipped text is worse than a scrollbar because nobody reports
   it. */
.qsm-say {
    min-width: 0;
}

.qsm-say > * + * {
    margin-top: var(--qm-sp-6);
}

.qsm-say .qm-actions {
    margin-top: clamp(2rem, 4vw, 2.75rem);
}


/* ============================================================================
   04 · SECTION 01 — THE GOVERNOR
   ----------------------------------------------------------------------------
   GESTURE: THE BOLTS. Four pins thrown left to right in sequence, each one
   slamming into its receiver and settling back two pixels. The recoil is the
   whole point — a bolt that glides to a stop reads as a progress bar, and a
   progress bar is a promise. A bolt that slams reads as a limit.

   NOTHING HERE GLOWS. The only lit thing is the kit's own live status pill,
   which is cyan because a conversation in flight is genuinely a live thing —
   the one use the system reserves cyan for.

   THE NUMBERS ARE HARD-CODED IN THE MARKUP, NOT HERE, and they mirror
   Web.config. See the page header before changing either.
   ============================================================================ */
.qsm-rig {
    /* the panel is the visual weight of the hero, so it gets the wider
       column and none of the prose measure constraints */
    min-width: 0;
}

.qsm-gov {
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-lg);
    background: linear-gradient(180deg, var(--qm-surface-2), var(--qm-surface-1));
    box-shadow: inset 0 1px 0 var(--qm-edge-light), 0 40px 90px -40px rgba(2, 4, 10, 0.98);
}

.qsm-gov__head,
.qsm-gov__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    margin: 0;
    padding: var(--qm-sp-4) clamp(1.1rem, 2.5vw, 1.6rem);
    font: 500 var(--qm-fs-label) / 1.5 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

.qsm-gov__head {
    border-block-end: 1px solid var(--qm-rule);
    border-start-start-radius: var(--qm-r-lg);
    border-start-end-radius: var(--qm-r-lg);
    background: var(--qm-bg-1);
}

.qsm-gov__foot {
    border-block-start: 1px solid var(--qm-rule);
}


/* ── 4.1 · a bolt ─────────────────────────────────────────────────────── */
.qsm-bolts {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
}

.qsm-bolt {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: baseline;
    gap: var(--qm-sp-2) var(--qm-sp-4);
    padding: clamp(0.9rem, 2vw, 1.15rem) clamp(1.1rem, 2.5vw, 1.6rem);
}

    .qsm-bolt + .qsm-bolt {
        border-block-start: 1px solid var(--qm-rule-faint);
    }

.qsm-bolt__k {
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-muted);
}

.qsm-bolt__v {
    font: 500 var(--qm-fs-h3) / 1 var(--qm-font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    color: var(--qm-text);
}

.qsm-bolt__n {
    grid-column: 2 / -1;
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

/* the last stop is the one the clinic does not control, so it is the only
   one carrying an accent */
.qsm-bolt--hard .qsm-bolt__v {
    color: var(--qm-warn);
}


/* ── 4.2 · the throw ──────────────────────────────────────────────────────
   MECHANICAL DIMENSIONS, not design values. The first build made the track
   44x15 and at 1440 it was six per cent of the panel — the gesture of the
   whole section rendered as a smudge. A limit has to be legible or it is
   decoration.

   The travel is carried as a custom property so the keyframes stay one
   definition across both track sizes. It cannot be derived in CSS from the
   track width, because the pin is a fixed size and calc() has no access to a
   sibling's box.
   ---------------------------------------------------------------------- */
.qsm-bolt__track {
    --qsm-travel: 28px;
    position: relative;
    align-self: center;
    width: 56px;
    height: 22px;
    border: 1px solid var(--qm-rule);
    border-radius: 3px;
    background-color: var(--qm-bg-0);
    /* a rail, so the throw has something to travel along */
    background-image: repeating-linear-gradient(90deg, var(--qm-rule-faint) 0 1px, transparent 1px 7px);
    box-shadow: inset 0 1px 2px rgba(2, 4, 10, 0.7);
}

@media (min-width: 40rem) {
    .qsm-bolt__track {
        --qsm-travel: 58px;
        width: 88px;
    }
}

    /* the receiver the bolt seats against */
    .qsm-bolt__track::after {
        content: "";
        position: absolute;
        top: 3px;
        bottom: 3px;
        right: 2px;
        width: 2px;
        border-radius: 1px;
        background: var(--qm-rule-strong);
    }

.qsm-bolt__pin {
    position: absolute;
    top: 3px;
    left: 2px;
    width: 20px;
    height: 14px;
    border-radius: 2px;
    background: var(--qm-text-faint);
}

.qsm-in .qsm-bolt__pin {
    animation: qsm-throw 460ms var(--qm-ease-io) calc(860ms + var(--i) * 150ms) both;
}

/* it slams past the seat and settles back two pixels. A bolt that eases to a
   stop reads as a progress bar, and a progress bar is a promise. A bolt that
   slams reads as a limit. */
@keyframes qsm-throw {
    0% {
        transform: translateX(0);
        background: var(--qm-text-faint);
    }

    68% {
        transform: translateX(calc(var(--qsm-travel) + 3px));
    }

    82% {
        transform: translateX(calc(var(--qsm-travel) - 3px));
    }

    100% {
        transform: translateX(var(--qsm-travel));
        background: var(--qm-text-secondary);
    }
}

.qsm-in .qsm-bolt--hard .qsm-bolt__pin {
    animation-name: qsm-throw-hard;
}

@keyframes qsm-throw-hard {
    0% {
        transform: translateX(0);
        background: var(--qm-text-faint);
    }

    68% {
        transform: translateX(calc(var(--qsm-travel) + 3px));
    }

    82% {
        transform: translateX(calc(var(--qsm-travel) - 3px));
    }

    100% {
        transform: translateX(var(--qsm-travel));
        background: var(--qm-warn);
    }
}





/* ── 4.3 · THE ACQUIRE ───────────────────────────────────────────────────
   REPLACES A GLITCH THAT DESERVED TO GO. That build tore five opaque slices
   sideways with two-pixel azure and violet fringes. Caught mid-animation on
   a real screen it did not read as a designed effect at all — it read as a
   broken render: hard neon rules striping the panel and slabs sitting on top
   of the text. An effect that looks like a bug is a bug.

   THE PROBLEM UNDERNEATH IT was that the panel had three separate events
   fighting for the same second — a card swinging in, a glitch, and four
   bolts throwing on their own clock. Nothing caused anything else.

   NOW THERE IS ONE EVENT. A single scan line crosses the panel and
   everything it passes comes online behind it: the header, then each
   governor in turn, each bolt thrown as the light reaches its row. The scan
   is the cause and the bolts are the consequence, which is both better
   choreography and a truer picture — this is a live line being acquired.

   CYAN, and it is the only cyan on the page. The kit reserves it for live
   things; a conversation governor coming online is the one moment on this
   page that qualifies.

   IT ANIMATES `top`, NOT A TRANSFORM, which is normally the wrong choice.
   Here it is the only one available: a percentage translateY resolves
   against the ELEMENT's own height, and the element is two pixels tall. It
   is one small box for one second, once.
   ---------------------------------------------------------------------- */
/* DELIBERATELY NOT SCOPED TO .qsm-js. Every other start state on this page is,
   so that the page reads correctly with scripting off — but this one is a 2px
   glowing line that exists only to travel. Its correct resting state IS absent:
   revealed statically it is a bright bar welded across the top of the panel,
   which looks like a rendering fault rather than a design. Ornament that only
   means something in motion stays hidden; content never does. */
.qsm-scan {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 2px;
    opacity: 0;
    pointer-events: none;
}

    /* the line itself, brightest across the middle so the ends do not stab
       the card's rounded corners */
    .qsm-scan::before {
        content: "";
        position: absolute;
        inset: 0;
        background: linear-gradient(90deg, transparent, var(--qm-signal) 16%, var(--qm-signal) 84%, transparent);
        box-shadow: 0 0 20px 1px var(--qm-signal-tint);
    }

    /* the bloom it drags behind itself */
    .qsm-scan::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        bottom: 100%;
        height: 72px;
        background: linear-gradient(180deg, transparent, var(--qm-signal-tint));
    }

.qsm-rig.qsm-in .qsm-scan {
    animation: qsm-scan 1180ms var(--qm-ease-io) 560ms both;
}

@keyframes qsm-scan {
    0% {
        top: 0;
        opacity: 0;
    }

    7% {
        opacity: 1;
    }

    86% {
        opacity: 1;
    }

    100% {
        top: 100%;
        opacity: 0;
    }
}

/* Nothing on the panel exists until the light has reached it — but ONLY if
   something is running to bring the light. Scoped to .qsm-js, because with
   scripting off there is no scan and an unscoped opacity:0 would render the
   governor as an empty box. */
.qsm-js .qsm-gov__head,
.qsm-js .qsm-gov__foot,
.qsm-js .qsm-bolt {
    opacity: 0;
}

.qsm-rig.qsm-in .qsm-gov__head {
    animation: qsm-lite 400ms var(--qm-ease) 620ms both;
}

.qsm-rig.qsm-in .qsm-bolt {
    animation: qsm-lite 400ms var(--qm-ease) calc(760ms + var(--i) * 150ms) both;
}

.qsm-rig.qsm-in .qsm-gov__foot {
    animation: qsm-lite 400ms var(--qm-ease) 1420ms both;
}

@keyframes qsm-lite {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}


/* ============================================================================
   04.5 · THE CARD IS ACTUALLY IN SPACE
   ----------------------------------------------------------------------------
   A flat card with a drop shadow is a picture of a card. This one is a real
   object: the rig carries the perspective, an inner .qsm-tilt carries the
   pointer parallax, .qsm-gov carries the entrance, and the four bolt rows are
   each lifted a different distance off the card face so they parallax against
   it as it turns. Two nested transforms, because one element cannot hold two
   independent ones without them fighting.

   ══ WHY THIS IS SAFE AND THE REJECTED 3D BUILD WAS NOT ═══════════════════
   The switching page once had a 3D hero and it was rightly thrown out: it was
   a FIXED-HEIGHT rig full of ABSOLUTELY POSITIONED children, so at 390px the
   card sat on top of the paragraph underneath it. Nothing here is absolutely
   positioned and nothing here has a fixed height. Every box is in normal flow
   and sized by its own content; `transform` does not participate in layout,
   so the card can rotate all it likes and the column beneath it still
   measures the same. That is the whole difference.

   ══ AND IT IS OFF WHEN IT SHOULD BE ══════════════════════════════════════
   Below 68rem the card is flat — a rotated panel on a narrow screen is a
   panel with unreadable edges. Under prefers-reduced-motion the whole thing
   is flat and still, and the floor is removed.
   ============================================================================ */
@media (min-width: 68rem) {
    .qsm-rig {
        /* 1600px was too far back — at that distance the projection is
           nearly orthographic and a twelve-degree turn reads as a rectangle
           that is slightly off. 1050 is close enough for the keystone to be
           unmistakable and still far enough not to look like a fisheye. */
        perspective: 1050px;
        perspective-origin: 24% 44%;
    }

    .qsm-tilt {
        transform-style: preserve-3d;
        transform: rotateY(var(--qsm-ry, 0deg)) rotateX(var(--qsm-rx, 0deg));
        transition: transform 220ms var(--qm-ease);
        will-change: transform;
    }

    .qsm-gov {
        transform-style: preserve-3d;
        /* the resting attitude of the card */
        transform: rotateY(-15deg) rotateX(4deg);
        transition: transform 900ms var(--qm-ease) 120ms, opacity 700ms var(--qm-ease) 120ms;
    }

    /* it arrives edge-on from behind and swings square */
    .qsm-js .qsm-rig .qsm-gov {
        opacity: 0;
        transform: rotateY(-38deg) rotateX(10deg) translateZ(-220px);
    }

    .qsm-rig.qsm-in .qsm-gov {
        opacity: 1;
        transform: rotateY(-15deg) rotateX(4deg) translateZ(0);
    }

    /* the contents stand off the face of the card, each row a little further
       than the last, so turning the card slides them against each other */
    .qsm-bolts {
        transform-style: preserve-3d;
    }

    .qsm-bolt {
        transform: translateZ(calc(8px + var(--i) * 7px));
    }

    .qsm-gov__head {
        transform: translateZ(3px);
    }

    /* THE CARD HAS A BACK — AND IT MUST LIVE IN THE CARD'S OWN SPACE.
       Built first as .qsm-tilt::before it produced a spectacular failure: the
       plate was axis-aligned while the card was rotated twelve degrees, so
       inside preserve-3d the two surfaces INTERSECTED and the browser
       depth-sorted them per fragment. Half the card's own text was painted
       over by the plate that was supposed to be behind it — "TURN CAP" read
       as "N CAP".

       As a pseudo-element of .qsm-gov it inherits the card's rotation, stays
       exactly parallel to the face, and cannot intersect anything. Two
       surfaces at different Z in the same rotated frame are stacked; two
       surfaces in different frames are a knife fight. */
    .qsm-gov {
        position: relative;
    }

        .qsm-gov::before {
            content: "";
            position: absolute;
            inset: 0;
            border: 1px solid var(--qm-rule-faint);
            border-radius: var(--qm-r-lg);
            background: var(--qm-bg-1);
            pointer-events: none;
        }

        .qsm-js .qsm-gov::before {
            transform: translateZ(-42px);
            opacity: 0;
            transition: opacity 500ms var(--qm-ease) 640ms;
        }

    .qsm-rig.qsm-in .qsm-gov::before {
        opacity: 1;
    }

    /* NO CAST SHADOW. A dark ellipse floated at translateZ(-150px) is another
       surface in another frame, and it cut the card open the same way. The
       card's own box-shadow plus the grid receding behind it already read as
       height; a third surface bought nothing and broke everything. */
}

/* ============================================================================
   05 · REDUCED MOTION
   ----------------------------------------------------------------------------
   Everything is already where it belongs; nothing travels to get there. The
   bolts are shown thrown, because thrown is the true state.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
    /* .qsm-js .qsm-rise — the start state gained a class, so a bare
       .qsm-rise here is (0,1,0) and loses to it. A media query adds nothing. */
    .qsm-js .qsm-rise {
        opacity: 1;
        transform: none;
        transition: none;
    }

    /* flat, still, and no floor. The card is an object, not a performance,
       and everything on it is already on. */
    .qsm-floor,
    .qsm-scan {
        display: none;
    }

    .qsm-gov__head,
    .qsm-gov__foot,
    .qsm-bolt {
        opacity: 1;
        animation: none;
    }



    .qsm-tilt,
    .qsm-rig .qsm-gov,
    .qsm-rig.qsm-in .qsm-gov {
        transform: none;
        opacity: 1;
        transition: none;
    }

    .qsm-gov::before {
        display: none;
    }

    .qsm-bolt,
    .qsm-gov__head {
        transform: none;
    }

    .qsm-in .qsm-bolt__pin,
    .qsm-in .qsm-bolt--hard .qsm-bolt__pin {
        animation: none;
        transform: translateX(var(--qsm-travel));
        background: var(--qm-text-secondary);
    }

    .qsm-in .qsm-bolt--hard .qsm-bolt__pin {
        background: var(--qm-warn);
    }
}


/* ============================================================================
   06 · SECTION 02 — THE LOCK SCREEN
   ----------------------------------------------------------------------------
   GESTURE: THE LOCK-SCREEN TEST. Three phrases in a real reminder go dark one
   after another, each underlined in alert as it goes, until only what is
   operationally necessary is still readable.

   NOTHING IS REMOVED AND NOTHING CLAIMS TO BE. There is no redaction feature
   in the source, so the reader is watching WHICH WORDS ARE DISCLOSURES, not
   watching a product delete them. Extinguishing rather than striking is the
   whole reason this gesture is honest — a strike-through says "we took this
   out", and we did not.

   ALERT is used here and nowhere else on the page. Warn carries the STOP row
   in section 01, cyan carries the scan; this is the only thing on the page
   that is a hazard rather than a limit, and it gets its own colour once.

   IT IS OPACITY AND FILTER ONLY, so the message does not reflow while it is
   being read. Blurring a phrase must never move the phrase after it.
   ============================================================================ */
.qsm-phone {
    max-width: 30rem;
    margin: clamp(1.5rem, 3.5vw, 2.25rem) auto 0;
}

/* IT HAS TO LOOK LIKE A LOCK SCREEN OR THE ARGUMENT DOES NOT LAND. Built
   first as a mono date and time on one hairline row, it read as another
   panel header and the whole "face-up on a table" premise went with it. A
   large clock over a date is the one piece of furniture every phone on earth
   shares. */
.qsm-phone__hd {
    margin: 0 0 clamp(1.25rem, 3vw, 1.9rem);
    text-align: center;
}

.qsm-phone__t {
    margin: 0;
    font: 300 clamp(3.25rem, 2.2rem + 4vw, 5rem) / 1 var(--qm-font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.04em;
    color: var(--qm-text);
}

.qsm-phone__d {
    margin: var(--qm-sp-2) 0 0;
    font: 500 var(--qm-fs-label) / 1 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

/* ── 6.1 · the notification ───────────────────────────────────────── */
.qsm-note {
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-lg);
    background: linear-gradient(180deg, var(--qm-surface-2), var(--qm-surface-1));
    box-shadow: inset 0 1px 0 var(--qm-edge-light), 0 30px 70px -34px rgba(2, 4, 10, 0.98);
}

.qsm-note__hd {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--qm-sp-4);
    margin: 0;
    padding: var(--qm-sp-3) clamp(1rem, 2.5vw, 1.4rem);
    border-block-end: 1px solid var(--qm-rule-faint);
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-muted);
}

.qsm-msg {
    margin: 0;
    padding: clamp(1rem, 2.5vw, 1.4rem);
    font-size: var(--qm-fs-sm);
    line-height: 1.7;
    color: var(--qm-text);
    text-wrap: pretty;
}

/* ── 6.2 · the three disclosures ──────────────────────────────────── */
/* TWO ELEMENTS, NOT ONE, AND THE REASON IS INHERITANCE. The marker started
   as a pseudo-element of the phrase itself — and a pseudo-element is a child,
   so it inherited the opacity:0.14 and blur(3px) meant for the phrase and
   dimmed itself into nothing. The thing labelling the hazard cannot be
   subject to the hazard. The outer span holds the marker; only the inner
   span goes dark. */
.qsm-tell {
    position: relative;
}

.qsm-tell__t {
    display: inline-block;
    transition: opacity 620ms var(--qm-ease) calc(760ms + var(--i) * 420ms), filter 620ms var(--qm-ease) calc(760ms + var(--i) * 420ms);
}

    /* the line that marks it as the hazard, drawn just before it goes dark */
    .qsm-tell::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        bottom: -2px;
        height: 1px;
        background: var(--qm-alert);
    }

    .qsm-js .qsm-tell::after {
        transform: scaleX(0);
        transform-origin: left;
        transition: transform 320ms var(--qm-ease) calc(560ms + var(--i) * 420ms);
    }

.qsm-in .qsm-tell__t {
    opacity: 0.14;
    filter: blur(3px);
}

.qsm-in .qsm-tell::after {
    transform: none;
}

.qsm-phone__cap {
    margin: var(--qm-sp-4) 0 0;
    padding-inline: var(--qm-sp-2);
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-muted);
    text-wrap: pretty;
}

/* ── 6.3 · what each one gives away ───────────────────────────────── */
.qsm-tests {
    display: grid;
    gap: clamp(1.25rem, 3vw, 2rem);
    margin: clamp(2.25rem, 5vw, 3.25rem) 0 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 52rem) {
    .qsm-tests {
        grid-template-columns: repeat(3, 1fr);
        align-items: start;
    }
}

.qsm-test {
    padding-block-start: var(--qm-sp-4);
    border-block-start: 1px solid var(--qm-rule);
}

.qsm-test__k {
    margin: 0 0 var(--qm-sp-3);
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-alert);
}

.qsm-test__b {
    margin: 0;
    font-size: var(--qm-fs-sm);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

/* ── 6.4 · shared with section 01's closing furniture ─────────────── */
.qsm-carry {
    margin-top: clamp(2.25rem, 5vw, 3.25rem);
}

.qsm-src {
    margin-top: clamp(1.5rem, 3vw, 2rem);
    max-width: var(--qm-w-prose);
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-muted);
    text-wrap: pretty;
}

    .qsm-src a {
        color: var(--qm-text-secondary);
        text-decoration: underline;
        text-underline-offset: 2px;
        text-decoration-color: var(--qm-rule-strong);
    }


/* ============================================================================
   07 · SECTION 03 — THE LEDGER
   ----------------------------------------------------------------------------
   GESTURE: THE RESOLVE. Six sends advance QUEUED -> SENT -> DELIVERED in
   sequence and settle. One sits on SENT long after the others have finished
   and only then turns over to UNDELIVERED.

   THE DELAY IS THE CONTENT. A failure does not announce itself at the moment
   of sending; it announces itself after everyone has stopped looking. If the
   failed row resolved with the rest of them this section would be a table.

   THE THREE STATES ARE STACKED IN ONE GRID CELL and cross-faded, so the row
   never changes width as the word changes. A ledger whose columns twitch
   while it settles reads as broken, and the whole argument here is that the
   log is trustworthy.

   ALERT is shared with section 02 — it is this page's colour for a hazard, as
   distinct from warn, which is section 01's colour for a limit. One meaning
   per colour, across the page.
   ============================================================================ */
.qsm-led {
    margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-lg);
    background: var(--qm-bg-1);
    box-shadow: inset 0 1px 0 var(--qm-edge-light);
}

.qsm-led__hd {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    margin: 0;
    padding: var(--qm-sp-4) clamp(1.1rem, 2.5vw, 1.6rem);
    border-block-end: 1px solid var(--qm-rule);
    font: 500 var(--qm-fs-label) / 1.5 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

/* ── 7.1 · one send ───────────────────────────────────────────────── */
.qsm-sends {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
}

.qsm-send {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    padding: clamp(0.8rem, 1.8vw, 1.05rem) clamp(1.1rem, 2.5vw, 1.6rem);
}

    .qsm-send + .qsm-send {
        border-block-start: 1px solid var(--qm-rule-faint);
    }

.qsm-send__to {
    font: 500 var(--qm-fs-sm) / 1.4 var(--qm-font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    color: var(--qm-text-secondary);
}

.qsm-send__why {
    grid-column: 1 / -1;
    margin: var(--qm-sp-2) 0 0;
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

.qsm-js .qsm-send__why {
    opacity: 0;
    transition: opacity var(--qm-t-slow) var(--qm-ease) 2560ms;
}

.qsm-in .qsm-send__why {
    opacity: 1;
}

/* ── 7.2 · the state, stacked so the row cannot twitch ────────────── */
.qsm-state {
    display: grid;
    justify-items: end;
}

    .qsm-state__v {
        grid-area: 1 / 1;
        font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
        letter-spacing: var(--qm-track-label);
        text-transform: uppercase;
        color: var(--qm-text-faint);
    }

    .qsm-js .qsm-state__v {
        opacity: 0;
    }

/* WITHOUT SCRIPTING THE LEDGER IS SHOWN SETTLED. Three values share one grid
   cell — that is what stops the row twitching as they turn over — so simply
   revealing them all prints QUEUED, SENT and DELIVERED on top of each other.
   The two interim states are removed and the outcome is what shows: the same
   resolution the reduced-motion block reaches, for the same reason. The delay
   is the argument, and an argument does not need re-enacting. */
.qsm:not(.qsm-js) .qsm-state__v--q,
.qsm:not(.qsm-js) .qsm-state__v--s {
    display: none;
}

.qsm-state__v--d {
    color: var(--qm-text-muted);
}

.qsm-send[data-fail="1"] .qsm-state__v--d {
    color: var(--qm-alert);
}

.qsm-send[data-fail="1"] .qsm-send__to {
    color: var(--qm-text);
}

/* the run. Backwards fill is doing real work here: the first state has to be
   on screen before its own animation starts, and the other two must not be. */
.qsm-in .qsm-state__v--q {
    animation: qsm-st-first 420ms linear calc(var(--i) * 110ms) both;
}

.qsm-in .qsm-state__v--s {
    animation: qsm-st-mid 460ms linear calc(420ms + var(--i) * 110ms) both;
}

.qsm-in .qsm-state__v--d {
    animation: qsm-st-last 320ms var(--qm-ease) calc(880ms + var(--i) * 110ms) both;
}

/* the one that does not come back. It holds on SENT for another second and a
   half after every other row has finished — long enough that the reader has
   moved on, which is exactly when the real one turns over. */
.qsm-in .qsm-send[data-fail="1"] .qsm-state__v--s {
    animation-duration: 1620ms;
}

.qsm-in .qsm-send[data-fail="1"] .qsm-state__v--d {
    animation-delay: 2340ms;
}

@keyframes qsm-st-first {
    0%, 92% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

@keyframes qsm-st-mid {
    0% {
        opacity: 0;
    }

    4%, 92% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

@keyframes qsm-st-last {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* ── 7.3 · the three readings ─────────────────────────────────────── */
.qsm-beats {
    display: grid;
    gap: clamp(1.25rem, 3vw, 2rem);
    margin: clamp(2.25rem, 5vw, 3.25rem) 0 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 52rem) {
    .qsm-beats {
        grid-template-columns: repeat(3, 1fr);
        align-items: start;
    }
}

.qsm-beat {
    padding-block-start: var(--qm-sp-4);
    border-block-start: 1px solid var(--qm-rule);
}

.qsm-beat__k {
    margin: 0 0 var(--qm-sp-3);
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-muted);
}

.qsm-beat__b {
    margin: 0;
    font-size: var(--qm-fs-sm);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}


/* ============================================================================
   09 · SECTION 04 — THE ALLOWANCE
   ----------------------------------------------------------------------------
   GESTURE: THE MONTH. Thirty columns rise in sequence, left to right, as the
   month plays out. Nothing else on this page grows — section 01 lights, 02
   goes dark, 03 changes state, this one accumulates.

   THE COLUMNS ARE A RUNNING TOTAL, NOT DAILY VOLUME. A daily bar chart of the
   same month is a flat field with one spike in it, and a flat field does not
   cross anything. The cumulative staircase is what makes the allowance line
   an event rather than a label.

   THE PLOT HAS A FIXED HEIGHT AND THAT IS FINE HERE. The rejected 3D build on
   the switching page was a fixed-height rig full of absolutely positioned
   TEXT, which cannot reflow. This box contains one short label and thirty
   flex children that size themselves from the container; the height is a
   deliberate aspect, not a trap.
   ============================================================================ */
.qsm-month {
    margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
    padding: clamp(1.1rem, 2.5vw, 1.6rem);
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-lg);
    background: var(--qm-bg-1);
    box-shadow: inset 0 1px 0 var(--qm-edge-light);
}

.qsm-month__hd {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    margin: 0 0 clamp(1.25rem, 3vw, 1.9rem);
    font: 500 var(--qm-fs-label) / 1.5 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

/* ── 9.1 · the plot ───────────────────────────────────────────────── */
.qsm-plot {
    position: relative;
    height: clamp(9rem, 22vw, 14rem);
}

.qsm-days {
    display: flex;
    align-items: flex-end;
    gap: clamp(2px, 0.5vw, 5px);
    height: 100%;
    margin: 0;
    padding: 0;
    list-style: none;
}

.qsm-day {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    align-items: flex-end;
}

    .qsm-day > span {
        display: block;
        width: 100%;
        height: calc(var(--v) * 100%);
        border-radius: 2px 2px 0 0;
        background: var(--qm-rule-strong);
    }

    .qsm-js .qsm-day > span {
        transform: scaleY(0);
        transform-origin: bottom;
        transition: transform 380ms var(--qm-ease) calc(var(--i) * 34ms + 260ms);
    }

.qsm-in .qsm-day > span {
    transform: none;
}

/* PAST THE LINE THE MONTH IS BEING BILLED — AND THE ZONE SAYS SO, NOT THE
   BARS. Filling the six crossing columns solid warn put six bright slabs in
   a section built on restraint; they read as the loudest thing on the page
   and the staircase underneath them disappeared. The billed region is a
   tint, and a crossing column gets an amber lid. Same fact, a tenth of the
   volume. */
.qsm-over {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: var(--lim);
    background: var(--qm-warn-tint);
    border-radius: 2px 2px 0 0;
    pointer-events: none;
}

.qsm-js .qsm-over {
    opacity: 0;
    transition: opacity var(--qm-t-slow) var(--qm-ease) 200ms;
}

.qsm-in .qsm-over {
    opacity: 1;
}

.qsm-day[data-over="1"] > span {
    box-shadow: inset 0 2px 0 var(--qm-warn);
}

/* the allowance itself */
.qsm-limit {
    position: absolute;
    left: 0;
    right: 0;
    bottom: var(--lim);
    height: 1px;
    background: var(--qm-warn);
}

.qsm-js .qsm-limit {
    opacity: 0;
    transition: opacity var(--qm-t-med) var(--qm-ease) 180ms;
}

.qsm-in .qsm-limit {
    opacity: 1;
}

.qsm-limit__k {
    position: absolute;
    left: 0;
    bottom: 5px;
    font: 500 var(--qm-fs-label) / 1 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-warn);
}

.qsm-plot__x {
    display: flex;
    justify-content: space-between;
    margin: var(--qm-sp-3) 0 0;
    padding-block-start: var(--qm-sp-3);
    border-block-start: 1px solid var(--qm-rule-faint);
    font: 500 var(--qm-fs-label) / 1 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

.qsm-month__cap {
    margin: var(--qm-sp-4) 0 0;
    max-width: var(--qm-w-prose);
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-muted);
    text-wrap: pretty;
}


/* ============================================================================
   10 · SECTION 05 — THE NON-ANSWER  (the close)
   ----------------------------------------------------------------------------
   GESTURE: THE NON-ANSWER. A message arrives. A typing indicator appears,
   thinks for a second and a half, and stops. The space where a reply would
   have gone stays empty.

   EVERY OTHER GESTURE ON THIS PAGE IS SOMETHING HAPPENING — a scan lights the
   panel, phrases go dark, states turn over, columns accumulate. This one is
   the absence of something happening, which is why it closes the page: the
   argument of the whole thing is that the restraint is the product.

   THE REPLY AREA RESERVES ITS HEIGHT ON PURPOSE. Nothing shifts when the dots
   go, because the emptiness is the content and content does not collapse. If
   a later hand "tidies" this by removing the min-height, the gesture becomes
   a layout jump and the point is lost.

   THE DOTS ARE SQUARES, not circles, and they are hairline-scaled. A circular
   three-dot bubble is the visual signature of every chat widget ever shipped,
   and this page is not a chat widget — it is a governor.
   ============================================================================ */
.qsm-thread {
    max-width: 34rem;
    margin: clamp(1.5rem, 3.5vw, 2.25rem) auto 0;
    padding: clamp(1.1rem, 2.5vw, 1.6rem);
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-lg);
    background: var(--qm-bg-1);
    box-shadow: inset 0 1px 0 var(--qm-edge-light);
}

.qsm-thread__hd {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    margin: 0 0 clamp(1rem, 2.5vw, 1.4rem);
    padding-block-end: var(--qm-sp-3);
    border-block-end: 1px solid var(--qm-rule-faint);
    font: 500 var(--qm-fs-label) / 1.5 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

/* ── 10.1 · what arrived ──────────────────────────────────────────── */
.qsm-ask {
    max-width: 26rem;
    margin: 0;
    padding: var(--qm-sp-4) clamp(0.9rem, 2vw, 1.2rem);
    border: 1px solid var(--qm-rule-faint);
    border-radius: var(--qm-r-md);
    background: var(--qm-surface-2);
    font-size: var(--qm-fs-sm);
    line-height: 1.65;
    color: var(--qm-text);
    text-wrap: pretty;
}

.qsm-js .qsm-ask {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--qm-t-slow) var(--qm-ease) 260ms, transform var(--qm-t-slow) var(--qm-ease) 260ms;
}

.qsm-in .qsm-ask {
    opacity: 1;
    transform: none;
}

/* ── 10.2 · what did not ──────────────────────────────────────────── */
.qsm-ans {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    /* the reserved silence — see the block comment */
    min-height: 4.5rem;
    margin-top: var(--qm-sp-4);
}

.qsm-dots {
    display: inline-flex;
    gap: 5px;
}

/* DELIBERATELY NOT SCOPED TO .qsm-js, like .qsm-scan. The dots are the machine
   thinking, and thinking is a thing that happens over time — statically they
   are three grey pips printed on top of "No reply composed", which is both
   ugly and the opposite of what the section says. Ornament that only means
   something in motion stays hidden without scripting; content never does. */
.qsm-dots {
    opacity: 0;
    transition: opacity var(--qm-t-med) var(--qm-ease) 980ms;
}

.qsm-in .qsm-dots {
    opacity: 1;
    animation: qsm-dots-out var(--qm-t-med) var(--qm-ease) 2540ms forwards;
}

    .qsm-dots i {
        width: 6px;
        height: 6px;
        background: var(--qm-text-faint);
    }

.qsm-in .qsm-dots i {
    animation: qsm-think 1200ms var(--qm-ease-io) infinite;
}

.qsm-in .qsm-dots i:nth-child(2) {
    animation-delay: 140ms;
}

.qsm-in .qsm-dots i:nth-child(3) {
    animation-delay: 280ms;
}

@keyframes qsm-think {
    0%, 60%, 100% {
        transform: translateY(0);
        opacity: 0.5;
    }

    30% {
        transform: translateY(-5px);
        opacity: 1;
    }
}

@keyframes qsm-dots-out {
    to {
        opacity: 0;
    }
}

.qsm-none {
    margin: 0;
    font: 500 var(--qm-fs-label) / 1 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

.qsm-js .qsm-none {
    opacity: 0;
    transition: opacity var(--qm-t-slow) var(--qm-ease) 2900ms;
}

.qsm-in .qsm-none {
    opacity: 1;
}

/* the dots and the verdict share the same slot, so the verdict does not
   arrive somewhere the dots were not */
.qsm-dots,
.qsm-none {
    grid-area: 1 / 1;
}

.qsm-ans {
    display: grid;
    grid-template-columns: 1fr;
    justify-items: end;
    align-items: center;
}

.qsm-thread__cap {
    margin: clamp(1rem, 2.5vw, 1.4rem) 0 0;
    padding-block-start: var(--qm-sp-4);
    border-block-start: 1px solid var(--qm-rule-faint);
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-muted);
    text-wrap: pretty;
}

/* ── 10.3 · the four refusals ─────────────────────────────────────── */
.qsm-wont {
    display: grid;
    gap: clamp(1.25rem, 3vw, 2rem);
    margin: clamp(2.25rem, 5vw, 3.25rem) 0 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 60rem) {
    .qsm-wont {
        grid-template-columns: repeat(2, 1fr);
        align-items: start;
    }
}

.qsm-won {
    padding-block-start: var(--qm-sp-4);
    border-block-start: 1px solid var(--qm-rule);
}

.qsm-won__k {
    margin: 0 0 var(--qm-sp-3);
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text);
}

.qsm-won__b {
    margin: 0;
    font-size: var(--qm-fs-sm);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

    .qsm-won__b a {
        color: var(--qm-text);
        text-decoration: underline;
        text-underline-offset: 2px;
        text-decoration-color: var(--qm-rule-strong);
    }

/* ── 10.4 · the close ─────────────────────────────────────────────── */
.qsm-close {
    max-width: var(--qm-w-prose);
    margin: clamp(2.25rem, 5vw, 3.25rem) 0 0;
    padding-block-start: clamp(1.5rem, 3.5vw, 2.25rem);
    border-block-start: 1px solid var(--qm-rule);
    font-size: var(--qm-fs-lead);
    line-height: var(--qm-lh-body);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

#qsm-stop .qm-actions {
    margin-top: clamp(1.75rem, 4vw, 2.5rem);
}


/* ============================================================================
   11 · REDUCED MOTION — SECTIONS 02 TO 05
   ----------------------------------------------------------------------------
   THIS BLOCK IS LAST IN THE FILE AND HAS TO STAY LAST.

   These overrides were originally written into block 05, next to section 01's
   reduced-motion rules, and they silently did nothing. A media query adds no
   specificity — `@media (prefers-reduced-motion) .qsm-in .qsm-state__v--d` and
   the plain `.qsm-in .qsm-state__v--d` in block 07 are both (0,2,0), so the
   later one wins on source order alone. Block 07 was appended after block 05,
   so the ledger kept running its animation for a reader who had asked the
   operating system for stillness, and the failed row sat invisible until its
   2.3-second delay elapsed.

   Any new section's reduced-motion rules go BELOW this comment, not above.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {

    /* section 02 — the disclosures are shown already dark, because dark is
       the point and the point does not need to travel to get there */
    .qsm-tell__t,
    .qsm-tell::after,
    .qsm-send__why {
        transition: none;
    }

    /* section 03 — the ledger is shown settled. The delay is the argument,
       and an argument does not need re-enacting for someone who asked for
       stillness. */
    .qsm-state__v--q,
    .qsm-state__v--s {
        display: none;
    }

    .qsm-state__v--d,
    .qsm-in .qsm-state__v--d,
    .qsm-in .qsm-send[data-fail="1"] .qsm-state__v--d {
        opacity: 1;
        animation: none;
    }

    .qsm-send__why,
    .qsm-in .qsm-send__why {
        opacity: 1;
    }

    /* section 04 — the month is shown finished. The columns are information,
       not choreography, and the information does not need to arrive. */
    .qsm-day > span,
    .qsm-in .qsm-day > span {
        transform: none;
        transition: none;
    }

    .qsm-limit,
    .qsm-in .qsm-limit,
    .qsm-over,
    .qsm-in .qsm-over {
        opacity: 1;
        transition: none;
    }

    /* section 05 — the message is there and the reply never was. Nothing has
       to think in front of someone who asked for stillness; the silence is
       the same silence either way. */
    .qsm-ask,
    .qsm-in .qsm-ask {
        opacity: 1;
        transform: none;
        transition: none;
    }

    .qsm-dots,
    .qsm-in .qsm-dots {
        display: none;
    }

    .qsm-none,
    .qsm-in .qsm-none {
        opacity: 1;
        transition: none;
    }
}
