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

   ══ THIS FILE DECLARES NO DESIGN ═════════════════════════════════════════
   No colours, no type scale, no spacing scale. Every value is var(--qm-*).
   Where a number is not a token it is a mechanical dimension and it is
   commented as one.

   ══ ONE NAME, ONE OWNER ══════════════════════════════════════════════════
   Every class here is defined in exactly one place. On the switching page two
   blocks styled .qsw-note 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.

   ══ REDUCED-MOTION RULES GO LAST IN THE FILE ═════════════════════════════
   A media query adds no specificity. On the SMS page the reduced-motion block
   sat above a later section and did nothing at all, because both selectors
   were (0,2,0) and source order decided it. New sections go ABOVE the final
   block, never below.

   ══ THE PAGE'S GESTURES, ONE PER SECTION, NO REPEATS ═════════════════════
     01  THE TAIL       the log runs, decelerates, and stops on one row
     02  THE DROP       that same row is pinned out, four leaders drawn from it
     03  THE NARROWING  nine rows from three clinics collapse to the four that are yours
     04  THE WITHDRAWAL one lane draws through; the other draws, then un-draws
     05  THE ERASURE     an edge crosses each row: the claim loses its ink, the truth is written in
   ############################################################################ */


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

/* a low, cold light — this is a page about a record, not a product demo */
.qal-tex--vault {
    background: radial-gradient( 42rem 28rem at 22% -6%, rgba(206, 222, 255, 0.04), transparent 62% ), radial-gradient( 50rem 26rem at 86% 106%, var(--qm-violet-tint), transparent 66% );
}


/* ============================================================================
   02 · ENTRANCE
   ----------------------------------------------------------------------------
   Both selector forms are listed on purpose. The observer puts .qal-in on the
   element it saw, which is sometimes the element being animated and sometimes
   an ancestor. A rule written only as `.qal-in .qal-rise` silently does
   nothing when the observed element IS the .qal-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 .qal-in, so
   nothing ever comes back. The inline script adds .qal-js as its first act
   for exactly this reason — it just was not being read by anything.

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

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


/* ============================================================================
   03 · SECTION 01 — THE TAIL   (full-bleed)
   ----------------------------------------------------------------------------
   WHY THIS IS NOT A SPLIT HERO WITH A PANEL. Four pages had already been built
   with that exact silhouette — grid, big gradient headline, lead, two buttons,
   panel on the right. Read one after another they stopped reading as design
   and started reading as a template. This page opens with the artefact
   instead: the log itself, edge to edge, tailing.

   GESTURE: THE TAIL AND THE STOP. The tape runs, decelerates, and halts on one
   row; the rest dim; the headline arrives afterwards as the human reading of
   the row that stopped.

   IT IS AN ANIMATION, NOT A TRANSITION, and that is not a style preference —
   the observer arms this element in the same tick the script adds its class,
   so a transition would have no rendered start state and would simply snap.
   That cost this page one full rebuild already; see block 04.

   THE HEADLINE IS DELIBERATELY NOT HERO-SIZED. qm-h2's scale, on the full
   measure, under the object. The row is the hero.
   ============================================================================ */
.qal-tail {
    position: relative;
    padding-block-end: clamp(3rem, 7vw, 5.5rem);
}

/* ── 3.1 · the feed ───────────────────────────────────────────────────────
   Full-bleed: no container, no border, no radius. A log is not a card.
   The height is a deliberate aspect; the tape inside is normal flow and only
   `transform` moves, so nothing here can fail to reflow.
   ---------------------------------------------------------------------- */
.qal-feed {
    position: relative;
    height: clamp(19rem, 46vh, 27rem);
    overflow: hidden;
    /* a mask, not a fade-to-background: the rows have to run past the edges,
       not stop at them. black/transparent are alpha geometry here, not
       colours — there is no token for "opaque". */
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, black 26%, black 68%, transparent 100%);
    mask-image: linear-gradient(180deg, transparent 0%, black 26%, black 68%, transparent 100%);
}

.qal-tape {
    position: absolute;
    inset-inline: 0;
    top: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    /* the tape starts high and runs down to rest — tail -f, decelerating */
    transform: translateY(-58%);
}

.qal-in .qal-tape,
.qal-feed.qal-in .qal-tape {
    animation: qal-tail 2100ms cubic-bezier(0.13, 0.85, 0.18, 1) 120ms both;
}

@keyframes qal-tail {
    from {
        transform: translateY(-58%);
    }

    to {
        transform: translateY(-31.5%);
    }
}

.qal-tape__row {
    display: grid;
    grid-template-columns: auto minmax(0, 1.5fr) minmax(0, 1.3fr) auto;
    align-items: baseline;
    gap: clamp(0.75rem, 2.5vw, 2.25rem);
    padding: clamp(0.5rem, 1.2vw, 0.7rem) var(--qm-gutter);
    font: 500 var(--qm-fs-xs) / 1.5 var(--qm-font-mono);
    letter-spacing: 0.02em;
    color: var(--qm-text-faint);
    border-block-start: 1px solid var(--qm-rule-faint);
    white-space: nowrap;
    overflow: hidden;
}

.qal-tape__a {
    color: var(--qm-text-muted);
}

.qal-tape__r {
    text-align: right;
}

/* A LOG ON A PHONE SHOWS TIME AND ACTION, and that is not a compromise —
   it is what every log viewer on earth does at this width. Left as four
   columns the rows clipped 24 elements at 320px: the actor and the role were
   present, unreadable, and pushing the action code out of the row. Dropping
   them puts the two columns that carry the meaning back in full.

   The rows keep white-space:nowrap and overflow:hidden on purpose. A log
   TRUNCATES, it does not wrap — a wrapped log row stops looking like a log. */
@media (max-width: 51.999rem) {
    .qal-tape__row {
        grid-template-columns: auto minmax(0, 1fr);
        gap: var(--qm-sp-4);
        padding-inline: var(--qm-sp-5);
    }

    .qal-tape__w,
    .qal-tape__r {
        display: none;
    }
}


/* ── 3.2 · the row it stops on ────────────────────────────────────────────
   Everything dims except this one. The dim is what makes it a stop rather
   than a pause — a tape that merely halts is still a list.
   ---------------------------------------------------------------------- */
.qal-in .qal-tape__row {
    animation: qal-dim var(--qm-t-slow) var(--qm-ease) 1700ms both;
}

@keyframes qal-dim {
    to {
        opacity: 0.22;
    }
}

.qal-tape__row[data-hero="1"] {
    border-block-start-color: var(--qm-rule-strong);
    border-block-end: 1px solid var(--qm-rule-strong);
    background: var(--qm-surface-1);
}

.qal-in .qal-tape__row[data-hero="1"] {
    animation: qal-hold var(--qm-t-slow) var(--qm-ease) 1700ms both;
}

@keyframes qal-hold {
    to {
        opacity: 1;
    }
}

.qal-tape__row[data-hero="1"] .qal-tape__a {
    color: var(--qm-warn);
}

.qal-tape__row[data-hero="1"] .qal-tape__t,
.qal-tape__row[data-hero="1"] .qal-tape__w,
.qal-tape__row[data-hero="1"] .qal-tape__r {
    color: var(--qm-text);
}

/* ── 3.3 · what the row means, said afterwards ────────────────────────── */
.qal-said {
    margin-top: clamp(2rem, 5vw, 3.25rem);
}

.qal-said > * + * {
    margin-top: var(--qm-sp-5);
}

/* NOT --qm-fs-hero and NOT --qm-fs-display. The object above is the hero and
   this is its caption; a headline that outweighs the artefact puts the page
   straight back into the template. */
.qal-h1 {
    max-width: 28ch;
    margin: 0;
    font: 600 var(--qm-fs-h2) / var(--qm-lh-head) var(--qm-font-display);
    letter-spacing: var(--qm-track-h2);
    color: var(--qm-text);
    text-wrap: balance;
}

.qal-said__p {
    max-width: var(--qm-w-prose);
    margin: 0;
    font-size: var(--qm-fs-body);
    line-height: var(--qm-lh-body);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

.qal-said__go {
    margin: 0;
}


/* ============================================================================
   04 · SECTION 02 — THE DISSECTION
   ----------------------------------------------------------------------------
   GESTURE: THE DROP. The row from section 01 is pinned out like a specimen and
   four leader lines draw down from it, each landing on what its segment
   actually is. An anatomy plate. Nothing else on this site is one, and it is
   the second section in a row that refuses to be a card.

   ══ ONE SET OF TRACKS, DECLARED ONCE ═════════════════════════════════════
   The row, the leaders and the notes all read --qal-cols from the wrapper.
   Declared three times they would drift the first time anybody edited one,
   and a leader line that does not land under its own segment is worse than
   no leader line at all.

   FRACTIONAL TRACKS, NOT auto. The tape in section 01 can use auto because
   every cell there holds one short string. Here the row holds values and the
   notes hold paragraphs, so `auto` would size the two grids differently and
   the alignment — which is the entire point — would be gone.
   ============================================================================ */
.qal-spec {
    --qal-cols: 0.9fr 1.5fr 1.4fr 0.7fr;
    padding-block: clamp(3.5rem, 8vw, 6rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

.qal-h2 {
    max-width: 30ch;
    margin: var(--qm-sp-4) 0 0;
    font: 600 var(--qm-fs-h2) / var(--qm-lh-head) var(--qm-font-display);
    letter-spacing: var(--qm-track-h2);
    color: var(--qm-text);
    text-wrap: balance;
}

.qal-plate {
    margin-top: clamp(2rem, 5vw, 3.25rem);
}

/* ── 4.1 · the specimen ───────────────────────────────────────────────── */
.qal-spec__row,
.qal-leads,
.qal-notes {
    display: grid;
    grid-template-columns: var(--qal-cols);
    gap: clamp(0.75rem, 2.5vw, 2.25rem);
    padding-inline: var(--qm-gutter);
    margin: 0;
    list-style: none;
}

.qal-spec__row {
    align-items: baseline;
    padding-block: clamp(0.6rem, 1.4vw, 0.9rem);
    border-block: 1px solid var(--qm-rule-strong);
    background: var(--qm-surface-1);
    font: 500 var(--qm-fs-xs) / 1.5 var(--qm-font-mono);
    letter-spacing: 0.02em;
    color: var(--qm-text);
    white-space: nowrap;
    overflow: hidden;
}

.qal-seg {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.qal-seg--a {
    color: var(--qm-warn);
}

/* ── 4.2 · the leaders ────────────────────────────────────────────────────
   A hairline per track, drawn from the row down to its note. It hangs at the
   LEFT edge of its own track because that is where the value starts — a
   leader centred in the track would point at the middle of nothing.
   ---------------------------------------------------------------------- */
.qal-leads {
    height: clamp(1.75rem, 4vw, 3rem);
}

.qal-lead {
    position: relative;
}

    .qal-lead::before {
        content: "";
        position: absolute;
        inset-block: 0;
        left: 0;
        width: 1px;
        background: var(--qm-rule-strong);
        transform: scaleY(0);
        transform-origin: top;
    }

    /* the foot — a short tick so the line lands on its label instead of just
       stopping in the air */
    .qal-lead::after {
        content: "";
        position: absolute;
        left: 0;
        bottom: 0;
        width: 9px;
        height: 1px;
        background: var(--qm-rule-strong);
        transform: scaleX(0);
        transform-origin: left;
    }

.qal-in .qal-lead::before {
    animation: qal-drop 320ms var(--qm-ease) calc(var(--i) * 220ms + 320ms) both;
}

.qal-in .qal-lead::after {
    animation: qal-tick 180ms var(--qm-ease) calc(var(--i) * 220ms + 620ms) both;
}

@keyframes qal-tick {
    from {
        transform: scaleX(0);
    }

    to {
        transform: scaleX(1);
    }
}

@keyframes qal-drop {
    from {
        transform: scaleY(0);
    }

    to {
        transform: scaleY(1);
    }
}

/* ── 4.3 · what each segment is ───────────────────────────────────────── */
.qal-notes {
    align-items: start;
}

/* NO TOP BORDER AT THE PLATE WIDTHS, and the reason is an optical accident
   worth recording: each leader hangs at the left edge of its own track, so
   the line to the RIGHT of any gap is the next leader. Add a horizontal rule
   across the note underneath and the three of them close into a rectangle —
   four open boxes instead of four leader lines. The label terminates the
   line; it does not need a rule as well. The border comes back below 60rem,
   where the leaders are gone and stacked notes do need separating. */
.qal-note {
    min-width: 0;
    padding-block-start: var(--qm-sp-3);
}

.qal-in .qal-note {
    animation: qal-note-in var(--qm-t-med) var(--qm-ease) calc(var(--i) * 220ms + 560ms) both;
}

@keyframes qal-note-in {
    from {
        opacity: 0;
        transform: translateY(6px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.qal-note__k {
    margin: 0 0 var(--qm-sp-2);
    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);
}

.qal-note__b {
    margin: 0;
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

    .qal-note__b strong {
        color: var(--qm-text);
        font-weight: 500;
    }

/* ── 4.4 · the two fields the tail never showed ───────────────────────── */
.qal-unseen {
    display: grid;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    margin: clamp(2.25rem, 5vw, 3.25rem) 0 0;
    padding: var(--qm-sp-5) var(--qm-gutter) 0;
    border-block-start: 1px solid var(--qm-rule);
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-muted);
    text-wrap: pretty;
}

@media (min-width: 60rem) {
    .qal-unseen {
        grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
        align-items: baseline;
    }
}

.qal-unseen__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-faint);
}

.qal-unseen strong {
    color: var(--qm-text-secondary);
    font-weight: 500;
}

/* ── 4.5 · the plate folds up ─────────────────────────────────────────────
   Four columns of prose do not exist on a phone. The specimen keeps the two
   columns that carry meaning — the same pair the tape keeps — the leaders go
   entirely (there is nothing to lead to once the notes are stacked), and each
   note carries its own label, which is what the leader was doing.
   ---------------------------------------------------------------------- */
@media (max-width: 59.999rem) {
    .qal-spec {
        --qal-cols: auto minmax(0, 1fr);
    }

    .qal-spec__row {
        gap: var(--qm-sp-4);
    }

    .qal-seg--w,
    .qal-seg--r {
        display: none;
    }

    .qal-leads {
        display: none;
    }

    .qal-notes {
        grid-template-columns: minmax(0, 1fr);
        gap: clamp(1.25rem, 4vw, 1.75rem);
        margin-top: clamp(1.5rem, 4vw, 2rem);
    }

    /* stacked, so they do need a rule between them */
    .qal-note {
        border-block-start: 1px solid var(--qm-rule-faint);
    }
}


/* ============================================================================
   05 · SECTION 03 — THE SCOPE
   ----------------------------------------------------------------------------
   A THIRD SILHOUETTE. Full-bleed, then a full-bleed plate, then this: a narrow
   centred column. Two edge-to-edge sections in a row is a rhythm; three would
   be a habit, and a habit is how a page becomes a template.

   GESTURE: THE NARROWING. Nine rows from three clinics. The WHERE clause
   lands, and every row that is not yours COLLAPSES — not fades. The list
   closes over them and what remains is shorter and complete.

   grid-template-rows: 1fr -> 0fr IS THE WHOLE TRICK. It is the one animatable
   way to take a row to nothing and let its neighbours have the space back.
   max-height guesses a number and then fights it; height:0 does not animate
   from auto; opacity leaves a hole where the row was, which is exactly the
   thing this gesture must not do — a hole says "hidden from you", and the
   truth is that the row was never in the result set.
   ============================================================================ */
.qal-scope {
    padding-block: clamp(3.5rem, 8vw, 6rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

.qal-col {
    max-width: 46rem;
    margin-inline: auto;
}

.qal-col > * + * {
    margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
}

/* ── 5.1 · the clause ─────────────────────────────────────────────────── */
/* margin-block-end only. A `margin: 0` shorthand here re-zeroes the top
   margin that `.qal-col > * + *` had just set — same specificity, later in
   the file, so the shorthand wins and the column loses its rhythm. Three
   children were doing it and the section read as one solid block. */
.qal-scope__q {
    margin-block-end: 0;
    padding: var(--qm-sp-4) var(--qm-sp-5);
    border: 1px solid var(--qm-rule);
    border-radius: var(--qm-r-sm);
    background: var(--qm-bg-1);
    font: 500 var(--qm-fs-sm) / 1.4 var(--qm-font-mono);
    letter-spacing: 0.02em;
    color: var(--qm-text);
}

.qal-scope__kw {
    color: var(--qm-violet);
}

/* ── 5.2 · nine rows becoming four ────────────────────────────────────── */
.qal-scope__list {
    margin-block-end: 0;
    padding: 0;
    list-style: none;
    border-block-start: 1px solid var(--qm-rule-faint);
}

/* THE ROW IS A ONE-TRACK GRID AND THE LINE IS ITS ONLY CHILD, which is not a
   stylistic choice: grid-template-rows:0fr only collapses the track it names,
   and three sibling spans would auto-place into three tracks with only the
   first one collapsing. One child, overflow hidden, and the padding lives on
   the child so the padding collapses with it. */
.qal-scope__row {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 420ms var(--qm-ease-io) calc(var(--i) * 60ms + 700ms), opacity 260ms var(--qm-ease) calc(var(--i) * 60ms + 700ms);
}

/* THE COLLAPSING CHILD CARRIES NOTHING OF ITS OWN. First attempt put the
   padding and the separator rule on this element and the rows bottomed out at
   19px instead of 0 — a 0fr track sizes the child's CONTENT box, and
   overflow:hidden clips content, not padding and not a border. Both moved to
   the grandchild, which the clip does reach. */
.qal-scope__line {
    overflow: hidden;
    min-height: 0;
}

.qal-scope__inner {
    display: grid;
    grid-template-columns: auto auto minmax(0, 1fr);
    align-items: baseline;
    gap: clamp(0.75rem, 3vw, 1.5rem);
    padding-block: 0.55rem;
    border-block-end: 1px solid var(--qm-rule-faint);
}

.qal-scope__c,
.qal-scope__t,
.qal-scope__a {
    font: 500 var(--qm-fs-xs) / 1.5 var(--qm-font-mono);
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.qal-scope__c {
    color: var(--qm-text-faint);
}

.qal-scope__t {
    color: var(--qm-text-muted);
}

.qal-scope__a {
    color: var(--qm-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
}

.qal-scope__row[data-mine="1"] .qal-scope__c {
    color: var(--qm-violet);
}

.qal-scope__row[data-mine="1"] .qal-scope__a {
    color: var(--qm-text);
}

/* the rows that were never in the result set close up */
.qal-in .qal-scope__row[data-mine="0"] {
    grid-template-rows: 0fr;
    opacity: 0;
}


/* ── 5.3 · the two rules and the failure mode ─────────────────────────── */
.qal-rules {
    margin-block-end: 0;
}

.qal-rule {
    display: grid;
    gap: var(--qm-sp-2) var(--qm-sp-5);
    padding-block: clamp(1rem, 2.5vw, 1.35rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

    .qal-rule dt {
        margin: 0;
        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);
    }

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

        .qal-rule dd strong {
            color: var(--qm-text);
            font-weight: 500;
        }

@media (min-width: 46rem) {
    .qal-rule {
        grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
        align-items: baseline;
    }
}

/* THE CLINIC ID IS THE POINT OF THIS SECTION, so unlike the tape in section 01
   nothing may be dropped here. At the narrowest widths the line becomes two
   rows instead — the id above, the event below — which keeps all three facts
   and still truncates rather than wrapping, the way a log does. */
@media (max-width: 26rem) {
    .qal-scope__inner {
        grid-template-columns: auto minmax(0, 1fr);
        gap: 0 var(--qm-sp-3);
    }

    .qal-scope__c {
        grid-column: 1 / -1;
        margin-block-end: 2px;
    }
}


/* ============================================================================
   06 · SECTION 04 — THE RAIL
   ----------------------------------------------------------------------------
   A FOURTH SILHOUETTE: a contained wide diagram, after a full-bleed tape, a
   full-bleed plate and a narrow centred column. The moment two sections of
   this page share a shape it starts becoming the template section 01 was
   written to escape.

   GESTURE: THE WITHDRAWAL. Two lanes run left to right. The top draws through
   and a card lands. The bottom draws as far as the rollback and then UN-DRAWS
   — the ink retreats to nothing and the outcome slot stays empty. Nothing
   else on this site withdraws.

   NO ABSOLUTELY POSITIONED TEXT. The nodes and their labels are a three-column
   grid sitting on top of the hairline; only the hairline and the ink are
   positioned, and neither of them contains a word. That is the rule this whole
   project has been following since a fixed-height 3D rig full of absolute
   children put a card on top of a paragraph at 390px.
   ============================================================================ */
.qal-rail {
    padding-block: clamp(3.5rem, 8vw, 6rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

.qal-lanes {
    margin: clamp(2rem, 5vw, 3.25rem) 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: clamp(1.75rem, 4vw, 2.75rem);
}

.qal-lane {
    display: grid;
    gap: var(--qm-sp-4);
    padding-block-start: var(--qm-sp-4);
    border-block-start: 1px solid var(--qm-rule-faint);
}

@media (min-width: 60rem) {
    .qal-lane {
        grid-template-columns: minmax(0, 10rem) minmax(0, 1fr) minmax(0, 13rem);
        align-items: center;
        gap: clamp(1.25rem, 3vw, 2.5rem);
    }
}

.qal-lane__k {
    margin: 0;
    font: 500 var(--qm-fs-label) / 1.4 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    color: var(--qm-text-muted);
}

/* ── 6.1 · the track ──────────────────────────────────────────────────── */
.qal-track {
    position: relative;
    /* a mechanical height: enough for the node marks plus one line of label */
    min-height: 3.25rem;
}

    /* the route, unlit */
    .qal-track::before {
        content: "";
        position: absolute;
        inset-inline: 0;
        top: 4px;
        height: 1px;
        background: var(--qm-rule-faint);
    }

.qal-track__ink {
    position: absolute;
    inset-inline: 0;
    top: 4px;
    height: 1px;
    background: var(--qm-rule-strong);
    transform: scaleX(0);
    transform-origin: left;
}

.qal-nodes {
    position: relative;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--qm-sp-3);
}

.qal-node {
    display: grid;
    gap: var(--qm-sp-2);
    font: 500 var(--qm-fs-label) / 1.3 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    color: var(--qm-text-faint);
    opacity: 0;
}

    .qal-node i {
        width: 7px;
        height: 7px;
        background: var(--qm-bg-0);
        border: 1px solid var(--qm-rule-strong);
        transform: rotate(45deg);
    }

.qal-in .qal-node {
    animation: qal-node-in var(--qm-t-med) var(--qm-ease) calc(var(--i) * 900ms + var(--n) * 420ms + 300ms) both;
}

@keyframes qal-node-in {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* ── 6.2 · the lane that completes ────────────────────────────────────── */
.qal-lane[data-kind="commit"] .qal-track__ink {
    background: var(--qm-signal);
}

.qal-in .qal-lane[data-kind="commit"] .qal-track__ink {
    animation: qal-draw 1350ms var(--qm-ease-io) 300ms both;
}

@keyframes qal-draw {
    from {
        transform: scaleX(0);
    }

    to {
        transform: scaleX(1);
    }
}

.qal-lane[data-kind="commit"] .qal-node:last-child i {
    border-color: var(--qm-signal);
    background: var(--qm-signal);
}

/* ── 6.3 · the lane that withdraws ────────────────────────────────────────
   0 -> 0.66 -> 0. The ink advances as far as the rollback node and then goes
   back the way it came, which is the only honest picture of a transaction
   that did not commit.
   ---------------------------------------------------------------------- */
.qal-lane[data-kind="rollback"] .qal-track__ink {
    background: var(--qm-alert);
}

.qal-in .qal-lane[data-kind="rollback"] .qal-track__ink {
    animation: qal-withdraw 2200ms var(--qm-ease-io) 1200ms both;
}

@keyframes qal-withdraw {
    0% {
        transform: scaleX(0);
    }

    38%, 52% {
        transform: scaleX(0.66);
    }

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

.qal-lane[data-kind="rollback"] .qal-node:last-child {
    color: var(--qm-alert);
}

.qal-lane[data-kind="rollback"] .qal-node:last-child i {
    border-color: var(--qm-alert);
}

/* ── 6.4 · what lands, and what does not ──────────────────────────────── */
.qal-out {
    display: grid;
    gap: var(--qm-sp-2);
    margin: 0;
    padding: var(--qm-sp-4);
    border: 1px solid var(--qm-rule-faint);
    border-radius: var(--qm-r-sm);
}

.qal-out__k {
    font: 500 var(--qm-fs-label) / 1.3 var(--qm-font-mono);
    letter-spacing: var(--qm-track-label);
    text-transform: uppercase;
    color: var(--qm-text-faint);
}

.qal-out__v {
    font-size: var(--qm-fs-xs);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

.qal-out--card {
    background: var(--qm-surface-1);
    border-color: var(--qm-rule);
    opacity: 0;
}

.qal-in .qal-out--card {
    animation: qal-land var(--qm-t-med) var(--qm-ease) 1700ms both;
}

@keyframes qal-land {
    from {
        opacity: 0;
        transform: translateY(6px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* THE EMPTY SLOT IS THE ARGUMENT. It never fills, it never animates, and it
   must not be "improved" by putting a message in it. */
.qal-out--void .qal-out__v {
    color: var(--qm-text-faint);
}


/* ============================================================================
   07 · SECTION 05 — THE UNCLAIMED   (the close)
   ----------------------------------------------------------------------------
   A FIFTH SILHOUETTE: full-measure rows separated by hairlines and nothing
   else. No card, no panel, no plate, no diagram. Four sections have each had
   their own shape and this one has the plainest of all, because the content is
   the page admitting what it cannot do and a decorated admission is not one.

   GESTURE: THE ERASURE. A hard edge crosses each row from left to right. On
   the left of the edge the claim loses its ink and settles to a ghost; on the
   right the truth is written in behind it. One edge, one direction, per row,
   staggered — the only thing moving on the screen.

   TWO MECHANISMS, ONE GRAMMAR — and the split is on purpose:
     · the CLAIM is a short display line, so it can afford `background-clip:
       text`: the glyphs themselves change colour under a travelling stop.
       That is the only way to erase a sentence's ASSERTION without erasing
       the sentence, which is what this section needs.
     · the TRUTH is a four-line paragraph, and `background-clip: text` on body
       copy costs the real text colour and gains nothing, so it is masked
       instead. The mask moves the same distance in the same direction, so the
       two read as one edge even though they are two properties.

   BOTH DEGRADE UPWARDS. The mask is additive — no mask support means visible
   text. The colour-clip is guarded behind @supports, so a browser without it
   never sees `color: transparent` and simply renders the claim in full.

   ANIMATIONS, NOT TRANSITIONS. Same reason as every other section here: the
   observer arms the element in the tick it adds the class, so a transition
   has no rendered start state and snaps. `both` fill holds the from-state
   through the delay.
   ============================================================================ */
.qal-close {
    padding-block: clamp(3.5rem, 8vw, 6rem) clamp(4rem, 9vw, 7rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

/* ── 7.1 · the four rows ──────────────────────────────────────────────────
   The counter is the page's own numbering of its own omissions. Mono, faint,
   in its own track, so the claim and the truth both start on a straight left
   edge and the travelling edge has something to start from.
   ---------------------------------------------------------------------- */
.qal-unsaid {
    counter-reset: qal-unsaid;
    margin: clamp(2rem, 5vw, 3.25rem) 0 0;
    padding: 0;
    list-style: none;
    border-block-end: 1px solid var(--qm-rule-faint);
}

.qal-unsaid__row {
    counter-increment: qal-unsaid;
    display: grid;
    grid-template-columns: minmax(0, 2.25rem) minmax(0, 1fr);
    align-items: baseline;
    padding-block: clamp(1.25rem, 3vw, 1.75rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

    .qal-unsaid__row::before {
        content: counter(qal-unsaid, decimal-leading-zero);
        font: 500 var(--qm-fs-xs) / 1.6 var(--qm-font-mono);
        letter-spacing: var(--qm-track-label);
        color: var(--qm-text-faint);
    }

/* Stacked on a phone, side by side from 60rem — the claim never gets so
   narrow that a three-word sentence breaks over three lines, which would
   turn the erasure into a staircase instead of an edge. */
.qal-swap {
    display: grid;
    gap: var(--qm-sp-3);
}

@media (min-width: 60rem) {
    .qal-swap {
        grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
        align-items: baseline;
        gap: clamp(1.5rem, 3.5vw, 2.75rem);
    }
}

/* ── 7.2 · the claim, and its erasure ─────────────────────────────────────
   The quotation marks are the whole reason a reader who arrives after the
   animation still understands the row: a quoted faint sentence is a thing
   somebody said, and the paragraph beside it is the answer. Without them the
   left column is just dim text and the contrast is carried entirely by a
   heading four inches up the page.

   The gradient is TWICE the element wide with one stop in the middle. At
   `background-position: 100% 0` the window sits over the bright half; at
   `0% 0` it sits over the faint half; in between, the stop travels the full
   width of the text. There is no second copy of the sentence anywhere.
   ---------------------------------------------------------------------- */
.qal-claim {
    display: block;
    font: 600 var(--qm-fs-h3) / var(--qm-lh-tight) var(--qm-font-display);
    letter-spacing: var(--qm-track-h3);
    color: var(--qm-text-faint);
    text-wrap: balance;
}

    .qal-claim::before {
        content: "\201C";
    }

    .qal-claim::after {
        content: "\201D";
    }

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .qal-claim {
        background-image: linear-gradient(90deg, var(--qm-text-faint) 46%, var(--qm-text) 54%);
        background-repeat: no-repeat;
        /* 200% wide, one stop at the middle — see the note above */
        background-size: 200% 100%;
        background-position: 100% 0;
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }

    .qal-in .qal-claim {
        animation: qal-unsay 640ms var(--qm-ease) calc(var(--i) * 260ms + 820ms) both;
    }
}

@keyframes qal-unsay {
    from {
        background-position: 100% 0;
    }

    to {
        background-position: 0 0;
    }
}

/* ── 7.3 · the truth, written in behind it ────────────────────────────────
   Mask geometry, since it is the kind of arithmetic that gets "tidied" into
   nonsense a year from now: the mask is 250% of the element wide, so the
   element's own width is a 40% window onto it. Solid across the first 40% of
   the mask, a ramp from 40% to 53%, clear after that. At `mask-position:
   100% 0` the window sits entirely inside the clear part; at `0% 0` it sits
   entirely inside the solid part; the ramp — about a third of a column wide
   — is what crosses the paragraph. A hard stop looks like a cut on prose; a
   ramp looks like writing.
   ---------------------------------------------------------------------- */
.qal-truth {
    display: block;
    max-width: var(--qm-w-prose);
    font-size: var(--qm-fs-sm);
    line-height: var(--qm-lh-body);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 40%, transparent 53%, transparent 100%);
    mask-image: linear-gradient(90deg, #000 0%, #000 40%, transparent 53%, transparent 100%);
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: 250% 100%;
    mask-size: 250% 100%;
    -webkit-mask-position: 0 0;
    mask-position: 0 0;
}

/* the starting state is scoped to scripting: with no observer to finish the
   sweep, an unscoped `mask-position: 100%` would hide all four paragraphs
   permanently and the section would be four faint fragments */
.qal-js .qal-truth {
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
}

.qal-in .qal-truth {
    animation: qal-say 780ms var(--qm-ease) calc(var(--i) * 260ms + 1120ms) both;
}

@keyframes qal-say {
    from {
        -webkit-mask-position: 100% 0;
        mask-position: 100% 0;
    }

    to {
        -webkit-mask-position: 0 0;
        mask-position: 0 0;
    }
}

/* ── 7.4 · four questions ─────────────────────────────────────────────────
   Deliberately NOT the dt/dd shape section 03 used for its two rules: that
   one is a label in a narrow left track with prose beside it. This is two
   columns of question-then-answer, because a question is a sentence and a
   sentence set as a label reads like a heading nobody wrote.
   ---------------------------------------------------------------------- */
.qal-asks-wrap {
    margin-top: clamp(2.75rem, 6vw, 4rem);
}

.qal-asks__k {
    margin: 0;
    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);
}

.qal-asks {
    display: grid;
    gap: 0 clamp(1.75rem, 4vw, 3rem);
    margin: var(--qm-sp-5) 0 0;
}

@media (min-width: 52rem) {
    .qal-asks {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.qal-ask {
    padding-block: clamp(1rem, 2.5vw, 1.35rem);
    border-block-start: 1px solid var(--qm-rule-faint);
}

    .qal-ask dt {
        margin: 0;
        font: 500 var(--qm-fs-body) / var(--qm-lh-head) var(--qm-font-display);
        color: var(--qm-text);
        text-wrap: pretty;
    }

    .qal-ask dd {
        margin: var(--qm-sp-2) 0 0;
        font-size: var(--qm-fs-sm);
        line-height: var(--qm-lh-body);
        color: var(--qm-text-secondary);
        text-wrap: pretty;
    }

/* ── 7.5 · the last paragraph ─────────────────────────────────────────── */
.qal-final {
    max-width: var(--qm-w-prose);
    margin: clamp(2.75rem, 6vw, 4rem) 0 0;
    font-size: var(--qm-fs-lead);
    line-height: var(--qm-lh-body);
    color: var(--qm-text-secondary);
    text-wrap: pretty;
}

    .qal-final strong {
        color: var(--qm-text);
        font-weight: 500;
    }

.qal-close__go {
    margin-top: clamp(2rem, 5vw, 2.75rem);
}



/* ============================================================================
   08 · REDUCED MOTION
   ----------------------------------------------------------------------------
   LAST IN THE FILE. New sections go above this block. See the header.
   The row is shown already captured and already sealed, because the row is
   information and information does not need to arrive.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
    /* .qal-js .qal-rise, NOT .qal-rise. The start state is (0,2,0) now that it
       is scoped to scripting, and a media query adds no specificity — written
       as a bare .qal-rise this rule is (0,1,0), loses outright, and the whole
       page stays invisible for anyone who has asked for less motion unless the
       armed rule happens to save it. It does today. That is not a design. */
    .qal-js .qal-rise {
        opacity: 1;
        transform: none;
        transition: none;
    }

    /* the tape is shown at rest, already stopped on its row, with nothing
       having travelled to get there */
    .qal-tape,
    .qal-in .qal-tape {
        animation: none;
        transform: translateY(-31.5%);
    }

    .qal-in .qal-tape__row {
        animation: none;
        opacity: 0.22;
    }

    .qal-in .qal-tape__row[data-hero="1"] {
        animation: none;
        opacity: 1;
    }

    /* the plate is shown drawn and annotated */
    .qal-in .qal-lead::before {
        animation: none;
        transform: scaleY(1);
    }

    .qal-in .qal-lead::after {
        animation: none;
        transform: scaleX(1);
    }

    .qal-in .qal-note {
        animation: none;
        opacity: 1;
        transform: none;
    }

    /* the result set is shown already narrowed — the foreign rows were never
       in it, so there is nothing to watch leave */
    .qal-scope__row,
    .qal-in .qal-scope__row[data-mine="0"] {
        transition: none;
    }

    /* the two lanes are shown at their outcomes: one drawn through with its
       card, one empty. The withdrawal is an argument, not a performance. */
    .qal-in .qal-node,
    .qal-in .qal-out--card {
        animation: none;
        opacity: 1;
        transform: none;
    }

    .qal-in .qal-lane[data-kind="commit"] .qal-track__ink {
        animation: none;
        transform: scaleX(1);
    }

    .qal-in .qal-lane[data-kind="rollback"] .qal-track__ink {
        animation: none;
        transform: scaleX(0);
    }

    /* the erasure is shown finished: the claim already a ghost, the truth
       already written. Both are INFORMATION — the section is unreadable if
       either is left at its start state, and `animation: none` alone would
       leave the truth masked out entirely. */
    .qal-in .qal-claim {
        animation: none;
        background-position: 0 0;
    }

    .qal-in .qal-truth,
    .qal-js .qal-truth {
        animation: none;
        -webkit-mask-position: 0 0;
        mask-position: 0 0;
    }
}
