/* ==========================================================================
 * middots - page styles
 * --------------------------------------------------------------------------
 * Order: tokens (custom properties) -> page frame -> reading layout -> controls
 * -> draft bench -> type shelf -> formatting. Theme colors, sizes and fonts all
 * flow from the :root variables, which the controls rewrite at runtime:
 *   --bg --ink --dim --hairline   colors (inverted swaps them)
 *   --fs --fs-mono --lh           text size, index size, line height
 *   --font-body --font-mono       the two type-shelf slots
 *   --seam-h                      height of the top fade
 * Font files are declared in fonts.css, not here.
 * ========================================================================== */

:root {
    --fs: 19pt;
    --fs-mono: 10pt;
    --bg: #000000;
    --ink: #f4efec;
    --dim: #8a8a8a;
    --hairline: #3a3a3a;
    --lh: 1.42;
    --measure: 29em; /* the text measure: dragged at the text's right edge or typed in the sizes family; in ems, so it follows the face and the size */
    --seam-over: 64px; /* how far the top fade reaches past the first line of text */
    --head: 0px; /* a piece's head above its first line (phone only; beside the text on a wide screen) */
    --seam-h: calc(var(--pin) - var(--vt) + var(--head) + var(--seam-over));
    --font-body: 'EB Garamond', Georgia, serif;
    --font-mono: 'Fragment Mono', monospace;
    /* a variable upload's knob values (App.tsx, axes.ts); set beside every font-family so each slot keeps its own */
    --fvs-body: normal;
    --fvs-mono: normal;
    --vt: 0px; /* top inset reserved for a host header; 0 in the mirror */
    --hz: 0px; /* the horizon's shift, set by the horizon control */
    --pin: calc(190px + var(--hz) + var(--vt));
    /* the horizon line: the first line's baseline (top of the page + a phone's piece head + the body's ascent in its line box) */
    --hline: calc(var(--pin) + var(--head) + (0.817 + (var(--lh) - 1) / 2) * var(--fs));
    --ctl: calc(
        var(--hline) + 17px + 10px
    ); /* the stack starts one gap under the horizon handle and moves with it */
}
:root.inverted {
    --bg: #d2d2d2;
    --ink: #000000;
    --dim: #5a5a5a;
    --hairline: #b0b0b0;
}

/* inner-scroller foundation: the page is screen-sized and scrolls inside .scroller */
html,
body {
    margin: 0;
    height: 100% !important;
    overflow: hidden !important;
}
html {
    background: var(--bg);
    overscroll-behavior: none;
    transition: background 0.25s ease;
}
.scroller,
.controls,
.io-panel textarea {
    overscroll-behavior: contain;
}
#root,
.scroller {
    height: 100% !important;
}
.scroller {
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
}
.scroller::-webkit-scrollbar {
    display: none;
}

/* OpenType: kerning plus the standard and contextual ligatures every face on the shelf carries.
   Discretionary ligatures stay off: in these faces they are historical forms (ct, st) that pull
   the eye in running text. The font files keep all their features, so any of them can be turned on. */
html {
    font-kerning: normal;
    font-variant-ligatures: common-ligatures contextual;
    text-rendering: optimizeLegibility;
}
body {
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: var(--fs);
    line-height: var(--lh);
    -webkit-font-smoothing: antialiased;
    transition:
        background 0.25s ease,
        color 0.25s ease;
}

/* left-aligned page: titles column left, text right where the titles end */
.page {
    margin: 0;
    padding: var(--pin) 56px 120px 48px; /* top = sticky pin line: open titles never clamp-displace at scroll 0 */
    box-sizing: border-box;
}

/* story: side title + body as one row; the side title is the only title */
.story {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr); /* room for long titles beside the text */
    column-gap: 40px;
    margin: 0 0 34px;
}
.story-head {
    align-self: start;
    display: block;
    text-align: left;
    line-height: 1.42; /* fixed: the head's calibration constant assumes it, whatever the draft line height does */
    background: none;
    border: 0;
    padding: calc((0.817 + (var(--lh) - 1) / 2) * var(--fs) - 1.05 * var(--fs-mono)) 0 0 0; /* constant in both states (no jump on fold/unfold); tracks font size AND line height so the open title's baseline meets the first line's baseline at every setting (body offset = half leading + 0.817*fs, mono title offset 14px fixed) */
}
.story-head {
    position: relative;
}
.story-head-main {
    display: block;
    text-align: left;
    background: none;
    border: 0;
    padding: 0;
    line-height: inherit; /* a button resets line-height to normal; the head's 1.42 must reach the title and date, as it does in draft */
    cursor: pointer;
}
.story.open .story-head {
    position: sticky;
    top: var(--pin);
}
.fold-dot {
    position: absolute;
    left: -21px;
    top: calc((0.817 + (var(--lh) - 1) / 2) * var(--fs) - 1.05 * var(--fs-mono));
    height: calc(1.42 * var(--fs-mono));
    display: flex;
    align-items: center;
    background: none;
    border: 0;
    padding: 0 8px 0 0;
    margin: 0;
    cursor: pointer;
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: 14px;
    line-height: 1;
    color: var(--ink);
    animation: middot-blink 2.6s ease-in-out infinite;
    transition: color 0.35s ease;
}
.fold-dot:hover,
.fold-dot:focus-visible {
    color: var(--ink);
    animation-duration: 0.85s;
    outline: none;
}

/* the index's own new-piece plus moved out to the horizon (27 Sep 19:29) - this spacer
   only keeps the two lines above the first piece's title */
.list-plus {
    height: 0; /* the two-line gap is revoked (his ruling, 27 Sep 19:54): the first baselines of the
                  title and the text sit on the horizon axis itself; the plus is fixed and does not move */
}
.story-title {
    display: block;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--dim);
    transition: color 0.2s ease;
}
.story-head:hover .story-title,
.story-head:focus-visible .story-title {
    color: var(--ink);
    outline: none;
}
.story.open .story-title {
    color: var(--ink);
}
.story-when {
    display: block;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--dim);
    margin-top: 4px;
}
.story-fold {
    position: relative;
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition:
        grid-template-rows 0.55s ease,
        opacity 0.55s ease;
}
.story.open .story-fold {
    grid-template-rows: 1fr;
    opacity: 1;
}
.story-body {
    max-width: var(--measure, 29em);
    min-width: 0;
    overflow: hidden;
    min-height: 0;
} /* measure scales with the story font: 29em = 734px at 19pt */

/* audio rows and their notes share one indent */
.story-audio {
    margin: 1.42em 0 4px 2em;
} /* one empty line between the main text and the voice rows */
.audio-part {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 7px 0;
    min-height: 34px;
}
.audio-button {
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 1px solid var(--ink);
    background: transparent;
    color: var(--ink);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
.audio-button:hover,
.audio-button:focus-visible {
    background: var(--ink);
    color: var(--bg);
    outline: none;
}
.audio-track {
    flex: 1 1 auto;
    min-width: 40px;
    height: 18px;
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
    position: relative;
}
.audio-track::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 1px;
    background: var(--hairline);
}
.audio-fill {
    position: absolute;
    left: 0;
    top: 50%;
    height: 1px;
    background: var(--ink);
}
.audio-time {
    flex: none;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    color: var(--dim);
    white-space: nowrap;
}
.audio-label {
    flex: none;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    color: var(--dim);
}
.story-note {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--dim);
    margin: 0 0 14px calc(2 * var(--fs));
}

/* closing middots: every piece ends with them, after the voice excerpts; they blink */
@keyframes middot-blink {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.28;
    }
}
.endmark {
    margin: 14px 0 0;
    padding-left: 0;
    word-spacing: 0.25em;
    animation: middot-blink 2.6s ease-in-out infinite;
} /* flush with the first paragraph; one extra space between the glyphs */

/* archive end: blinking middots aligned with the main text column; they unfold a summary for the peekers */
.archive-end {
    margin: 48px 0 0 0;
    width: 280px;
} /* end of the TITLE column */
.archive-middots {
    display: block;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: var(--fs);
    word-spacing: 0.25em;
    color: var(--ink);
    animation: middot-blink 2.6s ease-in-out infinite;
}
.archive-middots:hover,
.archive-middots:focus-visible {
    animation-duration: 0.85s;
} /* fast blink on hover */
.archive-fold {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition:
        grid-template-rows 0.55s ease,
        opacity 0.55s ease;
}
.archive-end.open .archive-fold {
    grid-template-rows: 1fr;
    opacity: 1;
}
.archive-fold-inner {
    overflow: hidden;
    min-height: 0;
}
.archive-endmark {
    padding-left: 0;
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: var(--fs);
    word-spacing: 0.25em;
}
.archive-summary {
    margin-top: 1.42em;
    padding-left: 1.08em; /* one middots-width (14.4px of 19pt Garamond) in summary ems */
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    line-height: 1.42;
    color: var(
        --dim
    ); /* one empty line below the middots; indented one middots-width; slightly faded; set like a title */
}
.archive-summary p {
    margin: 0;
}

/* body text: first paragraph flush, the rest indented as blocks; no gaps */
.story-text p,
.story-text > div {
    margin: 0;
    padding-left: 2em;
}
.story-text > :first-child {
    padding-left: 0;
}

/* controls: ghost chrome, visible only while awake */
.controls {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.45s ease;
    position: fixed;
    right: 14px;
    top: var(--ctl);
    /* one column, never wrapped: the families fold (ControlGroup), and the horizon stops where the folded
       stack still ends above the bottom edge (HorizonControl hzMax), so no button ever leaves the page */
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: 10;
    overflow: visible; /* era menu and hover labels live left of the box */
}
/* the horizon handle sits on the horizon itself - the first line's baseline - on every page, above the stack */
.controls .horizon-control {
    position: fixed;
    right: 14px;
    top: calc(var(--hline) - 17px);
}
/* the horizon control is dragged: no scrolling or text selection under the finger */
.controls .horizon-control {
    touch-action: none;
    cursor: ns-resize;
    user-select: none;
    -webkit-user-select: none;
}
.controls .horizon-control {
    border: 0;
    border-radius: 0;
    background: none;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* the folder jump: a stack of title-wide buttons left of the home button, the rings' radius */
.home-jump {
    position: relative;
    display: flex;
}
.folder-jump {
    position: absolute;
    /* flush against the home button, the 10px air moved inside as padding: the hand can
       travel from the button onto the stack without the reveal dropping under it */
    right: 100%;
    padding-right: 10px;
    top: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    /* the jumps rest hidden: hovering the home button reveals them */
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}
.home-jump:hover .folder-jump,
.folder-jump:focus-within {
    opacity: 1;
    pointer-events: auto;
}
.controls .folder-jump-button {
    width: auto;
    height: 34px;
    padding: 0 13px;
    border-radius: 17px; /* the rings' radius, stretched to the folder's title */
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 9.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
    white-space: nowrap;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
}
.controls .folder-jump-button:hover,
.controls .folder-jump-button.on {
    color: var(--ink);
}
.horizon-line {
    display: block;
    width: 34px;
    height: 1px;
    background: var(--hairline);
    transition: background 0.2s ease;
} /* the rings' width and stroke */
.controls .horizon-control:hover .horizon-line,
.controls .horizon-control:focus-visible .horizon-line {
    background: var(--ink);
} /* as a ring turns ink on hover */
.controls .horizon-control.on .horizon-line {
    background: var(--ink);
}
:root.ui-awake .controls,
:root.horizon-drag .controls {
    opacity: 1;
    pointer-events: auto;
}

/* the plumb: the horizon's vertical companion - the pair is one set. Its line hangs from
   the top edge of the page down 34px, at the main text's right edge, where the width
   grip has always lived. Awake with the controls, hidden again at rest; the plumb is
   itself the width grip, and it shines ink on hover and while the drag holds */
.plumb {
    position: fixed;
    top: 0; /* tight to the page's top edge: the plumb hangs from it, like a plumb line does */
    /* and it hangs at the main text's right edge, where the width grip has always lived -
       the em in left must be the text's em, so the size is pinned on the element */
    left: calc(48px + 300px + 40px + min(var(--measure, 29em), 100vw - 48px - 300px - 40px - 56px) - 3px);
    width: 1px;
    height: 34px;
    background: var(--hairline);
    background-clip: content-box; /* the hairline stays 1px; the padding is the grip */
    padding: 0 8px 0 3px; /* 3px over the text's edge, 8px in the gap right of it */
    font-size: var(--fs); /* --measure's em resolves in the text's em, like the old handle */
    opacity: 0;
    transition: opacity 0.45s ease;
    cursor: col-resize;
    touch-action: none;
    z-index: 11;
}
:root.ui-awake .plumb {
    opacity: 1;
}
.plumb:hover,
:root.measure-drag .plumb,
:root:has(.horizon-control:hover) .plumb,
:root.horizon-drag .plumb {
    background-color: var(--ink); /* longhand: the shorthand would reset the content-box clip */
}
/* and the companion answers: hovering or dragging the plumb lights the horizon's line */
:root:has(.plumb:hover) .horizon-line,
:root.measure-drag .horizon-line {
    background: var(--ink);
}
/* the width drag is not a text selection: nothing highlights while the tick is held */
.plumb,
:root.measure-drag {
    -webkit-user-select: none;
    user-select: none;
}


:root.measure-drag .page {
    user-select: none;
}
.controls button {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--hairline);
    background: transparent;
    color: var(--dim);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}
.controls button {
    transition:
        color 0.35s ease,
        border-color 0.35s ease,
        opacity 0.35s ease;
}
.controls button:hover,
.controls button:focus-visible {
    color: var(--ink);
    border-color: var(--ink);
    outline: none;
}
.controls button {
    position: relative;
}
.controls button[data-tip]:hover:not(:disabled)::after {
    content: attr(data-tip);
    position: absolute;
    right: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 9.5pt; /* button labels: +1pt from 8.5 */
    letter-spacing: 0.04em;
    color: var(--dim);
    pointer-events: none;
}
.controls button:disabled {
    opacity: 0.3;
    cursor: default;
}
.controls button:disabled:hover {
    color: var(--dim);
    border-color: var(--hairline);
}

@media (max-width: 700px) {
    :root {
        --pin: calc(120px + var(--hz) + var(--vt));
        --head: calc(2 * 1.42 * var(--fs-mono) + 8px + 16px);
    }
    .page {
        padding: var(--pin) 20px 96px 18px;
    }
    .logo {
        left: calc(18px + 6 * (1ch + 0.04em));
    }
    .plumb {
        left: calc(18px + min(var(--measure, 29em), 100vw - 38px) - 3px);
    }
    .story {
        grid-template-columns: 1fr;
        margin: 0 0 26px;
    }
    .story-head {
        padding: 2px 0;
    }
    .story.open .story-head {
        margin: 0 0 16px;
        background: var(--bg);
        top: var(--pin);
    }
    .archive-end {
        margin: 40px 0 0 0;
        width: 280px;
    }
    .fold-dot {
        left: -15px;
        padding-right: 4px;
    }
    .audio-part {
        flex-wrap: wrap;
    }
    .audio-label {
        flex-basis: 100%;
        padding-left: 42px;
        margin-top: -6px;
    }
    .controls,
    .controls .horizon-control {
        right: 8px;
    }
}

/* top seam: the fade band at the top of the page (see .seam.standalone at the end) */
.seam {
    position: fixed;
    top: var(--vt);
    left: 0;
    right: 0;
    height: var(--seam-h);
    background: linear-gradient(
        to bottom,
        rgba(244, 239, 236, 1) 0%,
        rgba(244, 239, 236, 0.987) 8.1%,
        rgba(244, 239, 236, 0.951) 15.5%,
        rgba(244, 239, 236, 0.896) 22.5%,
        rgba(244, 239, 236, 0.825) 29%,
        rgba(244, 239, 236, 0.741) 35.3%,
        rgba(244, 239, 236, 0.648) 41.2%,
        rgba(244, 239, 236, 0.55) 47.1%,
        rgba(244, 239, 236, 0.45) 52.9%,
        rgba(244, 239, 236, 0.352) 58.8%,
        rgba(244, 239, 236, 0.259) 64.7%,
        rgba(244, 239, 236, 0.175) 71%,
        rgba(244, 239, 236, 0.104) 77.5%,
        rgba(244, 239, 236, 0.049) 84.5%,
        rgba(244, 239, 236, 0.013) 91.9%,
        rgba(244, 239, 236, 0) 100%
    );
    pointer-events: none;
    z-index: 5;
}

/* ---------- draft mode: the archive as a writing bench ---------- */

/* red caret and red-tinted selection, draft mode only */
.editable {
    caret-color: #dc143c;
    cursor: text;
}
.editable:focus {
    outline: none;
}
:root ::selection {
    background: #dc143c;
    color: #000000;
} /* full crimson, it bleeds */

/* editable title: ghost placeholder when empty */
span.story-title.editable:empty::before {
    content: attr(data-ph);
    color: var(--hairline);
}

/* editable body: an empty paragraph keeps its line only while the caret is inside it;
   every other empty line stays collapsed, so clicking into the text never opens
   gaps between the paragraphs */
.story-text.editable {
    min-height: calc(var(--lh) * 1em);
}
.story-text.editable > :is(p, div):empty[data-focus] {
    min-height: calc(var(--lh) * 1em);
}

/* draft heads don't fold; the stack under the title is the piece's version history */
.draft-story .story-head {
    cursor: default;
}
.draft-story .story-head:hover .story-title {
    color: var(--dim);
}
.draft-story .story-title:hover,
.draft-story .story-title:focus {
    color: var(--ink);
}
.version-stack {
    display: block;
    margin-top: 4px;
}
.story-when.version {
    display: block;
    background: none;
    border: 0;
    padding: 0;
    margin: 0; /* the stack already sits 4px under the title, exactly where the reading date sits */
    cursor: pointer;
    text-align: left;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    line-height: inherit; /* buttons don't inherit it on their own; the head's 1.42 is what reading uses */
    letter-spacing: 0.04em;
    color: var(--dim);
}
.story-when.version:hover {
    color: var(--ink);
}
.story-when.version.current {
    color: var(--dim);
} /* same grey as the reading date */
.draft-story.open .story-when.version:not(.current) {
    color: var(--hairline);
}
.draft-story.open .story-when.version:not(.current):hover {
    color: var(--ink);
}
/* the variation plus rides the middot's axis: one slot in, one slot wide, centered - the
   same seat the fold middot takes over the number's second digit (his ruling, 27 Sep 19:29) */
.version-add {
    display: flex;
    justify-content: center;
    width: 1ch;
    margin-left: calc(1ch + 0.04em);
    line-height: inherit;
    margin-top: 4px;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--hairline);
}
.version-add:hover,
.version-add:focus-visible {
    color: var(--ink);
    outline: none;
}
.draft-remove {
    position: absolute;
    top: calc((0.817 + (var(--lh) - 1) / 2) * var(--fs) - 1.2 * var(--fs-mono));
    right: 0;
    background: none;
    border: 0;
    padding: 2px 0 2px 8px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    color: var(--hairline);
}
.draft-remove:hover,
.draft-remove:focus-visible {
    color: var(--ink);
    outline: none;
}

/* draft-only controls: a divider and a color swatch among the icon ghosts */
.controls-gap {
    width: 34px;
    height: 34px;
    flex: none;
}
/* a family: its button in the stack, its members in a column to the left, level with it (slid up by
   ControlGroup where the window ends first); the column's right padding bridges the gap for a mouse */
.ctl-group {
    position: relative;
    width: 34px;
    height: 34px;
    flex: none;
}
.ctl-members {
    position: absolute;
    right: 34px;
    padding-right: 10px;
    display: flex;
    flex-direction: column;
    align-items: flex-end; /* the members hug the stack's side - a wide row (the pdf pick) must not push the rest left */
    gap: 10px;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateX(6px);
    transition:
        opacity 0.25s ease,
        transform 0.25s ease,
        visibility 0s linear 0.25s;
}
.ctl-group.open .ctl-members {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    transition:
        opacity 0.25s ease,
        transform 0.25s ease;
}
.ctl-glyph {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 12px;
    letter-spacing: 0.02em;
    line-height: 1;
}

/* the draft button leads the stack and turns over on hover: ink fill, background-colored icon */
.controls button.draft-toggle:hover,
.controls button.draft-toggle:focus-visible {
    background: var(--ink);
    color: var(--bg);
    border-color: var(--ink);
}
.controls button.draft-toggle {
    transition:
        color 0.35s ease,
        border-color 0.35s ease,
        background-color 0.35s ease,
        opacity 0.35s ease;
}

/* era control: one icon; hover unfolds the choices leftward, random leftmost */
.era-widget {
    position: relative;
    width: 34px;
}
.era-menu {
    position: absolute;
    right: 34px; /* flush against the icon: the right padding is a hover bridge, no dead gap to fall through */
    top: 50%;
    transform: translateY(-50%) translateX(8px);
    display: flex;
    align-items: center;
    gap: 11px;
    opacity: 0;
    visibility: hidden;
    /* leaving waits a beat, so a hand drifting between the years doesn't lose the fan */
    transition:
        opacity 0.35s ease 0.45s,
        transform 0.35s ease 0.45s,
        visibility 0s linear 0.8s;
    background: var(--bg);
    border-radius: 17px;
    padding: 3px 19px 3px 10px;
}
.era-widget:hover .era-menu,
.era-widget:focus-within .era-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%);
    transition:
        opacity 0.35s ease,
        transform 0.35s ease,
        visibility 0s;
}
.controls .era-choice {
    position: relative;
    width: auto;
    height: auto;
    border: 0;
    border-radius: 0;
    background: none;
    display: inline-block;
    padding: 4px 1px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 8.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
}
.controls .era-choice {
    transition: color 0.35s ease;
}
.controls .era-choice:hover,
.controls .era-choice:focus-visible {
    color: var(--ink);
    outline: none;
}
.controls .era-choice.current {
    color: var(--ink);
    border-bottom: 1px solid var(--ink);
}
.controls .era-menu button.era-choice[data-tip]:hover:not(:disabled)::after {
    content: attr(data-tip);
    position: absolute;
    top: calc(100% + 7px); /* under the year's underline, never on its line */
    right: auto;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 9pt;
    letter-spacing: 0.04em;
    color: var(--dim);
    pointer-events: none;
}
.controls button.swatch {
    position: relative;
}
.controls .swatch-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--dim);
    display: block;
    pointer-events: none;
}
.controls .swatch input[type='color'] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

/* export/import overlay */
.io-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.72);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 40;
}
.io-panel {
    width: min(620px, 86vw);
    background: var(--bg);
    border: 1px solid var(--hairline);
    padding: 18px;
    box-sizing: border-box;
}
.io-title {
    margin: 0 0 4px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--ink);
}
.io-note {
    margin: 0 0 12px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 8.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
}
.io-panel textarea {
    width: 100%;
    height: 280px;
    box-sizing: border-box;
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--hairline);
    padding: 10px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 8.5pt;
    line-height: 1.5;
    resize: vertical;
    caret-color: #dc143c;
}
.io-panel textarea:focus {
    outline: none;
    border-color: var(--dim);
}
.io-error {
    margin: 8px 0 0;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 8.5pt;
    color: #e5484d;
}
.io-row {
    display: flex;
    gap: 10px;
    margin-top: 12px;
    justify-content: flex-end;
}
.io-row button {
    background: transparent;
    border: 1px solid var(--hairline);
    border-radius: 15px;
    padding: 6px 14px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 8.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
}
.io-row button:hover,
.io-row button:focus-visible {
    color: var(--ink);
    border-color: var(--ink);
    outline: none;
}

/* toggled modes glow like a pressed key */
.controls button.on {
    color: var(--ink);
    border-color: var(--ink);
}
/* draft text keeps every space and line exactly as typed */
.story-text.editable,
.story-text.editable p,
.story-text.editable > div {
    white-space: pre-wrap;
}
/* a typed Tab is a real tab character; four spaces wide reads as an indent, not a gap */
.story-text {
    tab-size: 4;
}
/* commitment mode: what was deleted stays, struck and leaning */
s.ov {
    font-style: italic;
    text-decoration: line-through;
    text-decoration-thickness: 1px;
    text-decoration-color: currentColor;
    color: var(--dim);
}
/* focus dim: while writing, every paragraph but the caret's own fades to a whisper, and so do
   titles and the other pieces; the page comes back the moment the caret leaves the text */
:root.focusdim .story-text.editable > *,
:root.focusdim .story-head,
:root.focusdim .story-audio {
    transition: opacity 0.35s ease;
}
:root.focusdim.focus-in .story-text.editable > *:not([data-focus]),
:root.focusdim.focus-in .story-head,
:root.focusdim.focus-in .story-audio {
    opacity: 0.18;
}

/* platen mode: the typing line holds on the horizon (App.tsx platenFollow), the page rolls under it;
   the deep bottom padding lets the last line reach the horizon */
:root.platen .page {
    padding-bottom: 70vh;
}
/* folding a draft folds its version dates with the rest; the current date stays, like the reading index */
.vrow {
    position: relative; /* the shelf number hangs off the current row's date line */
    display: grid;
    grid-template-rows: 1fr;
    opacity: 1;
    /* the row's strut is the date font's, not the body's: a body-size strut was the empty line */
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    transition:
        grid-template-rows 0.55s ease,
        opacity 0.55s ease,
        margin-top 0.55s ease;
}
/* the version dates keep the head's own rhythm: the pitch between rows equals the pitch
   between the title line and the first date line */
.version-stack .vrow + .vrow {
    margin-top: 4px;
}
.vrow-inner {
    overflow: hidden;
    min-height: 0;
}
/* the shelf row's fixed gutter: six mono slots (three digits, three spaces) measured in the
   date font, so a proportional title font can never move the text column. The fold middot
   rides the second slot on the title line; the piece number leads the current date line. */
.gutter {
    position: relative;
    display: inline-block;
    width: calc(6 * (1ch + 0.04em));
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--dim);
}
/* the middot sits over the number's second digit: one slot in, one slot wide, centered */
.story-head .fold-dot {
    left: calc(1ch + 0.04em);
    top: 0;
    width: 1ch;
    height: 100%;
    padding: 0;
    justify-content: center;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
}
/* the draft title leads its head-main block, the same first line reading sets */
.draft-story .story-title {
    display: block;
}
/* the date line leads with its own number gutter: pull it back to the row's left edge, so the
   number sits under the fold middot's slot and the date keeps the shared text column. Direct
   child only: the draft's version rows hang inside the version stack, which pulls itself. */
.story-head-main > .story-when {
    margin-left: calc(-6 * (1ch + 0.04em));
}
/* the draft's version stack leads with the same number gutter: pull it back the same six slots.
   The mono metrics come along so the ch in the pull is the date font's, not the title's. */
.story-head-main .version-stack {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    margin-left: calc(-6 * (1ch + 0.04em));
}
/* a span head-main keeps the reading geometry but not the button's pointer */
.draft-story .story-head-main {
    cursor: default;
}
/* reading: the head's main button rides beside its gutter, tops level so the baselines meet */
.story-head .gutter,
.story-head-main {
    vertical-align: top;
}
.story-head-main {
    display: inline-block;
}
/* inside a version row the number shares the date's baseline, the same flow reading sets
   (the head-wide top alignment is for the title line's gutter, not the date rows) */
.vrow-inner .gutter {
    vertical-align: baseline;
}
/* a version date shares its line with its gutter */
.vrow-inner .story-when.version {
    display: inline-block;
}
.draft-story:not(.open) .vrow:not(.current) {
    grid-template-rows: 0fr;
    opacity: 0;
    margin-top: 0;
}
.draft-story:not(.open) .vrow:not(.current) button {
    pointer-events: none;
}
.version-stack {
    margin-top: 4px;
}
.vrow.add .version-add {
    margin-top: 4px;
}

/* type shelf */
.face-widget {
    position: relative;
    width: 34px;
}
.face-list {
    position: fixed;
    max-height: min(calc(100vh - 24px), 520px);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    padding: 12px 14px;
    background: var(--bg);
    border: 1px solid var(--hairline);
    border-radius: 14px;
    z-index: 12;
}
.face-list::-webkit-scrollbar {
    display: none;
}
.controls .face-choice {
    width: auto;
    height: auto;
    border: 0;
    border-radius: 0;
    background: none;
    display: block;
    flex: none;
    padding: 3px 0;
    white-space: nowrap;
    max-width: 18ch; /* long face names can't widen the panel */
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: calc(13px + 1pt); /* face names: +1pt */
    letter-spacing: 0;
    color: var(--dim);
    cursor: pointer;
    transition: color 0.35s ease;
}
.controls .face-choice.wing {
    margin-top: 12px;
}
.controls .face-choice:hover,
.controls .face-choice:focus-visible {
    color: var(--ink);
    outline: none;
}
.controls .face-choice.current {
    color: var(--ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 4px;
}

/* typed sizes */
.size-field {
    position: relative;
    width: 34px;
    height: 34px;
    display: block;
}
.size-field input {
    display: block; /* an inline input sinks below the label's baseline - the ring sat 5px low of its mates */
    width: 34px;
    height: 34px;
    box-sizing: border-box; /* the border rides inside the 34, the same ring as the hyphen's */
    border-radius: 50%;
    border: 1px solid var(--hairline);
    background: transparent;
    color: var(--dim);
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 10px;
    letter-spacing: 0;
    text-align: center;
    padding: 0;
    outline: none;
    caret-color: #dc143c;
    transition:
        color 0.35s ease,
        border-color 0.35s ease;
}
.size-field input:hover,
.size-field input:focus {
    color: var(--ink);
    border-color: var(--ink);
}
.size-field input::selection {
    background: #dc143c;
    color: #000;
}
/* the picked-numbers picker: two number rings with the hyphen in a ring of its own */
.pdf-pick {
    display: flex;
    align-items: center;
    gap: 6px;
}
.pdf-pick-dash {
    width: 34px;
    height: 34px;
    box-sizing: border-box; /* the border rides inside the 34, level with the number rings */
    border-radius: 50%;
    border: 1px solid var(--hairline);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--dim);
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 10px;
    user-select: none;
    -webkit-user-select: none;
}
.size-field[data-tip]:hover::after {
    content: attr(data-tip);
    position: absolute;
    right: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 9.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
    pointer-events: none;
}
.size-field:focus-within::after {
    display: none;
}

/* hand formatting */
.story-text strong {
    font-weight: 700;
}
.story-text u {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}
.story-text del {
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}
.fx-palette {
    position: fixed;
    z-index: 30;
    display: flex;
    gap: 2px;
    padding: 3px;
    background: var(--bg);
    border: 1px solid var(--hairline);
    border-radius: 17px;
    animation: fx-rise 0.22s ease;
}
@keyframes fx-rise {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}
.fx-palette button {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: var(--dim);
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: 16px;
    line-height: 1;
    padding: 0 0 2px;
    cursor: pointer;
    transition: color 0.2s ease;
}
.fx-palette button:hover {
    color: var(--ink);
}
.fx-palette button.on {
    color: #dc143c;
}
.fx-palette .fx-sep {
    width: 1px;
    align-self: stretch;
    margin: 6px 3px;
    background: var(--hairline);
}
.fx-palette .fx-indent,
.fx-palette .fx-outdent {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 18px;
}

/* dialogue pieces (two hands): every part starts flush, its hand mark (○ / ●) hanging in the margin */
.story.dialogue .story-text > p,
.story.dialogue .story-text > div {
    padding-left: 1.25em;
    text-indent: -1.25em;
}

/* ---- the owner's fonts: the upload button, then his fonts as the first shelf of the face list ----
   Every entry keeps the list's size and right edge; the × sits to the left of a name */
.controls .face-choice.face-upload {
    border: 1px solid var(--hairline);
    border-radius: 999px;
    padding: 2px 12px;
    margin-bottom: 6px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono); /* the interface face, like the other labels */
    color: var(--dim);
}
.controls .face-choice.face-upload:hover,
.controls .face-choice.face-upload:focus-visible {
    color: var(--ink);
    border-color: var(--dim);
}
.face-upload-note {
    margin: 0 0 4px;
    font-size: 11px;
    line-height: 1.3;
    opacity: 0.6;
    text-align: right;
    max-width: 180px;
}
.face-own {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 6px;
}
.controls .face-remove {
    width: auto;
    height: auto;
    flex: none;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--dim);
    font: inherit;
    font-size: 11px;
    opacity: 0.6;
    cursor: pointer;
    padding: 0;
}
.controls .face-remove:hover {
    opacity: 1;
    color: var(--ink);
    background: none;
}

/* ---- main page (Cover): one column, centered across, on the horizon - the folders, then + for a new one ---- */
.cover {
    /* on the horizon: the first folder's baseline is the baseline of a folder's first line of text.
       The page starts at the pin line; a piece's first line sits there on a wide screen, so no offset.
       On a phone the piece's head (title + date, then 16px) comes first - see the media rule below. */
    margin-top: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}
/* the logo, every page: pinned in the top rail, scroll never moves it. Its left edge is the titles'
   edge (past the number gutter), its line one line below the plumb's lower end. Mono, spaced, dim -
   the side-title style it has always worn. */
.logo {
    position: fixed;
    /* the titles' edge: the page's left padding plus the six-slot number gutter - the mark
       clears the numbers and starts where titles start; the mono metrics make the ch the gutter's */
    left: calc(48px + 6 * (1ch + 0.04em));
    top: calc(34px + var(--lh) * var(--fs)); /* one line below the plumb's lower end (his ruling, 27 Sep 16:00) */
    transform: translateY(-100%);
    z-index: 10;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    line-height: var(--lh);
    pointer-events: none;
    white-space: pre;
}
.logo-word {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    line-height: 1;
    letter-spacing: 0.04em;
    color: var(--dim);
}
.logo-caret {
    display: inline-block;
    width: 1px;
    height: 1.05em;
    margin-left: 1px;
    vertical-align: -0.18em;
    background: var(--dim);
}
.logo-sel {
    background: var(--hairline);
    color: var(--ink);
}
.logo-caret.rest {
    animation: pin-caret 1.06s steps(1) infinite;
}
@media (prefers-reduced-motion: reduce) {
    .logo-caret {
        display: none;
    }
}
/* the logo mounts as an empty slot in the flow: the mark itself is pinned to the top rail
   (see .logo), so the slot takes no space and the title area keeps the horizon */
.cover-folders {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}
.cover-folder {
    background: none;
    border: 0;
    padding: 0;
    line-height: var(--lh); /* same line box as the text, so the baselines meet */
    color: var(--dim);
    font: inherit;
    font-size: var(--fs);
    cursor: pointer;
    transition: color 0.35s ease;
}
.cover-folder:hover,
.cover-folder:focus-visible {
    color: var(--ink);
    outline: none;
}
/* the count hangs off the title's right edge (out of the flow), so the title alone is centered;
   raised like a superscript, set in oldstyle figures */
.cover-folder-count {
    position: absolute;
    left: 100%;
    top: calc(
        (var(--lh) - 1) / 2 * var(--fs) + 0.06 * var(--fs)
    ); /* half-leading, then just under the cap line */
    margin-left: 0.3em;
    font-size: 0.55em;
    line-height: 1;
    opacity: 0.6;
    color: var(--dim);
    white-space: nowrap;
    font-variant-numeric: oldstyle-nums;
    font-feature-settings: 'onum' 1;
}
/* the add plus, drawn his way (27 Sep 18:59): a custom plus from the same strokes as
   the horizon line and its vertical companion - 34px by 1px each way, the hairline's own -
   pinned on the horizon at the left-most side of the screen, the horizontal stroke exactly
   on the line, running right; it never scrolls, and it rides the horizon's drag. One seat
   on the cover for a new folder, one inside a folder for a new piece (27 Sep 19:29) */
.hair-plus {
    position: fixed;
    left: 0;
    top: calc(var(--hline) - 17px);
    width: 34px;
    height: 34px;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    z-index: 11;
}
.hair-plus::before,
.hair-plus::after {
    content: '';
    position: absolute;
    background: var(--hairline);
    transition: background 0.2s ease;
}
.hair-plus::before {
    left: 0;
    top: 17px; /* the stroke lies on the horizon line itself */
    width: 34px;
    height: 1px;
}
.hair-plus::after {
    left: 17px;
    top: 0;
    width: 1px;
    height: 34px;
}
/* one line shines per hover, never both: chance picks which (his ruling, 27 Sep 19:00) */
.hair-plus.shine-h::before {
    background: var(--ink);
}
.hair-plus.shine-v::after {
    background: var(--ink);
}
.hair-plus:focus-visible {
    outline: none;
}
.cover-new {
    margin-top: 22px;
    min-height: 1.4em;
}
/* a folder row: the title alone sets the centering; the count (or "delete") hangs off its right edge */
.cover-row {
    position: relative;
    display: inline-block;
    line-height: var(--lh);
    font-size: var(--fs);
}
.cover-delete {
    background: none;
    border: 0;
    padding: 0;
    color: #dc143c;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    letter-spacing: 0.04em;
    cursor: pointer;
    opacity: 0.85;
    animation: fx-rise 0.25s ease-out;
}
.cover-delete:hover,
.cover-delete:focus-visible {
    opacity: 1;
    outline: none;
}
/* a hit area wider than the word, reaching back over the gap to the title, so the way there never leaves it */
.cover-delete::after {
    content: '';
    position: absolute;
    inset: -0.6em -0.6em -0.6em -1.2em;
}
.cover-delete {
    position: absolute;
}
/* naming a folder: no line, no placeholder - the text and a blinking crimson caret, nothing else */
.cover-name {
    min-width: 1ch;
    max-width: 70vw;
    background: transparent;
    border: 0;
    color: var(--ink);
    font: inherit;
    font-size: var(--fs);
    text-align: center;
    padding: 2px 0;
    outline: none;
    caret-color: #dc143c;
}
.cover-folder {
    -webkit-touch-callout: none;
    user-select: none;
}
@media (max-width: 700px) {
    /* phone: a piece's text starts under its head (two mono lines + 8px of padding, then 16px), so the folders do too */
    .cover {
        margin-top: calc(2 * 1.42 * var(--fs-mono) + 8px + 16px);
    }
}

/* ---- sync: code field and join button, in the same panel style as the face list ---- */
.sync-panel form {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
}
.sync-panel form .pin + .box-submit {
    margin-top: -5px;
} /* one grid: the word's row sits one grid gap under the code */
.sync-actions {
    display: flex;
    gap: 14px;
    align-items: baseline;
}

/* the code field: small boxes, one per character; a typed character flashes, then settles into a middot */
.pin {
    position: relative;
}
.pin-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    border: 0;
    padding: 0;
    margin: 0;
    font-size: 16px;
    color: transparent;
    background: transparent;
    caret-color: transparent;
    cursor: text;
    z-index: 1;
}
/* the code and the action share one grid, four boxes wide: the code fills rows from the top, the word sits in the row(s) under it */
.pin-boxes,
.box-word {
    display: grid;
    grid-template-columns: repeat(4, 20px);
    gap: 5px;
    justify-content: end;
}
.pin-box {
    position: relative;
    width: 20px;
    height: 26px;
    box-sizing: border-box;
    border: 1px solid var(--hairline);
    border-radius: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 13px;
    line-height: 1;
    color: var(--ink);
    transition: border-color 0.15s ease;
}
.pin-box.filled {
    border-color: var(--dim);
}
.pin-box.active {
    border-color: var(--ink);
}
.pin-box.active::after {
    content: '';
    width: 1px;
    height: 13px;
    background: #dc143c;
    animation: pin-caret 1.06s steps(1) infinite;
}
.pin-char {
    animation: pin-in 0.12s ease-out;
}
.pin-dot {
    font-size: 22px;
    font-weight: 700;
    transform: translateY(-1px);
    animation: pin-seal 0.22s cubic-bezier(0.3, 1.6, 0.5, 1);
}
@keyframes pin-caret {
    50% {
        opacity: 0;
    }
}
@keyframes pin-in {
    from {
        transform: translateY(3px);
        opacity: 0;
    }
}
@keyframes pin-seal {
    from {
        transform: translateY(-1px) scale(0.2);
        opacity: 0.2;
    }
}
.pin-shake .pin-boxes {
    animation: pin-shake 0.36s ease;
}
@keyframes pin-shake {
    20%,
    60% {
        transform: translateX(-4px);
    }
    40%,
    80% {
        transform: translateX(4px);
    }
}
@media (prefers-reduced-motion: reduce) {
    .pin-char,
    .pin-dot,
    .pin-shake .pin-boxes {
        animation: none;
    }
}
.sync-note {
    margin: 0;
    max-width: 170px;
    font-size: 11px;
    line-height: 1.35;
    color: var(--dim);
    text-align: right;
}
/* under the code, a note keeps to the code's own width (the four boxes: 4 x 20px + 3 x 5px), so a message
   never widens the panel or pushes its grid apart; a longer one wraps inside that column */
.sync-form .sync-note {
    width: calc(4 * 20px + 3 * 5px);
    max-width: none;
    overflow-wrap: anywhere;
}

/* ---- past selves: a piece's snapshots, folded under its text in draft mode ---- */
.past {
    margin-top: 28px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    line-height: 1.42;
    color: var(--dim);
}
.past button {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    transition:
        color 0.25s ease,
        opacity 0.25s ease;
}
.past-toggle {
    opacity: 0.6;
}
.past-toggle:hover,
.past-toggle:focus-visible,
.past.open .past-toggle {
    opacity: 1;
    color: var(--ink);
    outline: none;
}
.past-count {
    margin-left: 0.5em;
    font-size: 0.85em;
    opacity: 0.6;
}
.past-list {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    margin-top: 10px;
    padding-left: 12px;
    border-left: 1px solid var(--hairline);
    animation: fx-rise 0.22s ease;
}
.past-date:hover,
.past-date:focus-visible {
    color: var(--ink);
    outline: none;
}
.past-date.on {
    color: #dc143c;
}
.past-actions {
    display: flex;
    gap: 18px;
    margin-top: 12px;
}
.past-act:hover,
.past-act:focus-visible {
    color: var(--ink);
    outline: none;
}
.past-act.strong {
    color: var(--ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 4px;
}
/* peeking: the past self stands where the text was, a shade quieter, the live editor hidden but kept */
.snap-hidden {
    display: none;
}
.snap-peek {
    opacity: 0.72;
    animation: fx-rise 0.22s ease;
}
.snap-peek-title {
    margin: 0 0 12px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    color: #dc143c;
}
.snap-peek .story-text p {
    white-space: pre-wrap;
}

/* ---- search: a field and its results, in the same panel style as the type shelf ---- */
.search-panel {
    align-items: stretch;
    width: min(340px, calc(100vw - 90px));
    max-height: min(70vh, 520px);
}
.search-field {
    background: transparent;
    color: var(--ink);
    border: 0;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 16px;
    padding: 2px 0 4px;
    outline: none;
    caret-color: #dc143c;
}
.search-field::placeholder {
    color: var(--dim);
    opacity: 0.6;
}
/* the searched word's line: the field takes the width, the tally hangs far right */
.search-field-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
}
.search-field-row .search-field {
    flex: 1;
    min-width: 0;
}
.search-count {
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--hairline);
}
.search-results {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 8px;
}
/* a folder's answers sit under its name; two lines of air before the name */
.search-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: calc(2 * 1.42 * var(--fs-mono));
}
.search-group:first-child {
    margin-top: 0;
}
.search-group-title {
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    color: var(--hairline);
}
.controls .search-hit {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    width: 100%;
    height: auto;
    padding: 2px 0;
    border: 0;
    border-radius: 0;
    background: none;
    text-align: left;
    cursor: pointer;
    color: var(--dim);
    font: inherit;
}
/* a hit is the head and the body in miniature: number and title on the head's mono line,
   the snippet in the body face at the same text column - indentation, not rules */
.search-hit-head {
    display: block;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    letter-spacing: 0.04em;
    line-height: 1.42;
}
.search-hit-head .gutter {
    color: var(--hairline);
}
.search-hit-title {
    opacity: 0.8;
}
.search-hit-line {
    display: block;
    line-height: 1.42;
}
.search-hit-text {
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 14px;
    line-height: 1.42; /* the title area's line height: the panel now shares its font */
    color: var(--dim);
}
.search-hit mark {
    font-family: var(--font-body);
    font-variation-settings: var(--fvs-body);
    background: none;
    color: var(--ink);
    text-decoration: underline;
    text-decoration-color: #dc143c;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}
.controls .search-hit.on .search-hit-text,
.controls .search-hit:hover .search-hit-text {
    color: var(--ink);
}
.controls .search-hit.on .search-hit-head,
.controls .search-hit:hover .search-hit-head {
    color: var(--ink);
}
::highlight(search-hit) {
    background-color: rgba(220, 20, 60, 0.28);
    color: inherit;
}
.search-flash {
    background: rgba(220, 20, 60, 0.18);
    transition: background 0.6s ease;
}

/* submit as a word in boxes (join, next, change, make it mine) */
.controls .face-choice.box-submit {
    padding: 0;
    border: 0;
    background: none;
    color: var(--dim);
    cursor: pointer;
}
.box-word .box-gap {
    width: 20px;
    height: 26px;
}
.box-submit .pin-box {
    font-size: 12px;
    color: var(--dim);
    border-color: var(--hairline);
    transition:
        color 0.2s ease,
        border-color 0.2s ease;
}
.controls .face-choice.box-submit:not(:disabled):hover .pin-box,
.controls .face-choice.box-submit:not(:disabled):focus-visible .pin-box {
    color: var(--ink);
    border-color: var(--ink);
}
.controls .face-choice.box-submit:not(:disabled) .pin-box {
    color: var(--ink);
    border-color: var(--dim);
}
.controls .face-choice.box-submit:disabled {
    opacity: 0.4;
    cursor: default;
}

/* a file dragged over the page: a quiet frame says it can land (App: font drop) */
html.font-dropping body {
    box-shadow: inset 0 0 0 1px currentColor;
}

/* a state word in the sync panel: the code's boxes, dimmed, no border colour of its own */
.sync-note.sync-word {
    width: auto;
}
.sync-word .pin-box {
    color: var(--dim);
    border-style: dashed;
}
/* one grid: a state word sits one box gap under the row above it, like the submit word under the code */
.sync-panel form > .sync-word {
    margin-top: -5px;
}



/* ---- knobs of a variable face (AxisKnobs): under its name in the face list, right-aligned like the list ----
   name, a thin line with a small dot, the value in oldstyle figures; the line is the whole hit area */
.face-list .face-choice {
    font-variation-settings: normal;
} /* names are set in their own faces, not the slot's knobs */
.face-axes {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    margin: 2px 0 8px;
    font-family: var(--font-mono);
    font-variation-settings: normal;
    font-size: 11px;
    color: var(--dim);
}
.face-axis {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    cursor: default;
}
.face-axis-name {
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}
.face-axis-value {
    width: 3.2em;
    text-align: left;
    font-variant-numeric: oldstyle-nums tabular-nums;
    color: var(--ink);
    opacity: 0.8;
}
.face-axis input[type='range'] {
    -webkit-appearance: none;
    appearance: none;
    width: 96px;
    height: 22px;
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
    touch-action: none;
}
.face-axis input[type='range']::-webkit-slider-runnable-track {
    height: 1px;
    background: var(--hairline);
}
.face-axis input[type='range']::-moz-range-track {
    height: 1px;
    background: var(--hairline);
}
.face-axis input[type='range']::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 9px;
    height: 9px;
    margin-top: -4px;
    border-radius: 50%;
    background: var(--dim);
    border: 0;
    transition: background 0.2s ease;
}
.face-axis input[type='range']::-moz-range-thumb {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--dim);
    border: 0;
}
.face-axis:hover input[type='range']::-webkit-slider-thumb,
.face-axis input[type='range']:focus-visible::-webkit-slider-thumb {
    background: var(--ink);
}
.face-axis:hover input[type='range']::-moz-range-thumb,
.face-axis input[type='range']:focus-visible::-moz-range-thumb {
    background: var(--ink);
}
.face-axis input[type='range']:focus {
    outline: none;
}
.face-axis:hover .face-axis-name {
    color: var(--ink);
}
@media (max-width: 600px) {
    .face-axis input[type='range'] {
        width: 84px;
        height: 28px;
    }
}

/* standalone mirror: with no host header above the page, the top fade is the
   page's own background thinning out (mask), so it follows --bg and inversion */
.seam.standalone {
    top: 0;
    background: var(--bg);
    -webkit-mask-image: linear-gradient(
        to bottom,
        #000 0%,
        rgba(0, 0, 0, 0.75) 35%,
        rgba(0, 0, 0, 0.35) 70%,
        transparent 100%
    );
    mask-image: linear-gradient(
        to bottom,
        #000 0%,
        rgba(0, 0, 0, 0.75) 35%,
        rgba(0, 0, 0, 0.35) 70%,
        transparent 100%
    );
}

.archive-middots {
    font-size: 14px;
    line-height: 1;
    word-spacing: 0;
    padding-right: 8px;
}
.face-own .face-remove {
    width: 18px;
    color: var(--dim);
    font-size: 15px;
    opacity: 0;
    pointer-events: none;
}
.face-own:hover .face-remove,
.face-own:focus-within .face-remove {
    opacity: 1;
    pointer-events: auto;
}
.face-own .face-remove:hover,
.face-own .face-remove:focus-visible {
    color: var(--ink);
}
.face-widget.body,
.face-widget.title {
    display: flex;
    align-items: center;
    width: auto;
    gap: 4px;
}
/* Keep the font button at the column edge even when no axes button is present. */
.face-widget.body > button:last-child,
.face-widget.title > button:last-child {
    margin-left: auto;
}
.controls .face-widget .face-axes-toggle {
    width: 26px;
    height: 26px;
    flex: none;
    font-family: var(--font-mono);
    font-size: 14px;
}
.face-axes-back {
    align-self: flex-end;
    margin-bottom: 10px;
    font-family: var(--font-mono);
}
.sync-panel .box-submit .box-word + .box-word {
    margin-top: 5px;
}
.sync-panel form > .box-submit {
    margin-top: -5px;
}

/* Reveal each delete mark on its piece title hover or keyboard focus. */
.story-head .draft-remove {
    color: var(--hairline);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
}
.story-head:hover .draft-remove,
.story-head:focus-within .draft-remove {
    color: var(--ink);
    opacity: 1;
    pointer-events: auto;
}
.story-head .draft-remove:hover,
.story-head .draft-remove:focus-visible { color: var(--ink); }
/* ---- admin page: the public face set's authoring surface (app.js: AdminPage) ---- */
.admin-page { max-width: 34em; margin: 0; padding: 0; font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--ink); } /* inside .page: the pin line and the titles' edge, like everything else */
.admin-invite, .admin-note, .admin-warn { color: var(--dim); }
.admin-warn { color: var(--pin); }
.admin-gate { display: flex; gap: .6em; align-items: center; }
.admin-code { font: inherit; letter-spacing: .5em; width: 6.5em; padding: .35em .6em .35em 1.1em; background: none; color: var(--ink); border: none; border-bottom: 1px solid var(--hairline); outline: none; }
.admin-go, .admin-add { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; padding: .35em 0; }
.admin-go:not(:disabled):hover, .admin-add:not(:disabled):hover { color: var(--ink); }
.admin-go:disabled { color: var(--hairline); cursor: default; }
.admin-row { display: flex; align-items: baseline; gap: 1em; padding: .45em 0; border-bottom: 1px solid var(--hairline); }
.admin-row-head { border-bottom: none; margin-top: .5em; }
.admin-col-title { flex: 1; }
.admin-counts { color: var(--dim); }
.admin-face-name { flex: 1; }
.admin-face-file { color: var(--dim); }
.admin-row-new .admin-face-name::after { content: ' · staged'; color: var(--dim); }
.admin-row-out { opacity: .45; }
.admin-row-out .admin-face-name { text-decoration: line-through; }
.admin-face-del { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; }
.admin-face-del:hover { color: var(--ink); }
.admin-move { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; padding: 0 .25em; }
.admin-move:not(:disabled):hover { color: var(--ink); }
.admin-move:disabled { opacity: .3; cursor: default; }
.admin-row-add, .admin-row-publish { border-bottom: none; margin-top: 1.2em; }
.admin-row-publish { gap: 1.4em; align-items: center; }
.admin-rollback { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; }
.admin-rollback:hover { color: var(--ink); }

/* ---- the code editor and the changes folder -------------------------------
 * the admin idiom stretched wide: the code's titles where titles live, the
 * text in the main area; verizon folds the titles over the text */
.editor-page, .changes-page, .shelf-page, .account-page { max-width: none; }
.admin-nav { border-bottom: none; gap: 1.4em; margin-top: .4em; }
.admin-nav-link { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; padding: .3em 0; }
.admin-nav-link.on, .admin-nav-link:not(.on):hover { color: var(--ink); }
/* the editor in the story idiom: the code's titles in the titles column (they fold under
   their dot), the file itself in the text column, as wide as the measure says */
.editor-story { margin-top: .8em; }
.editor-head { position: relative; }
.editor-list-fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.55s ease; }
.editor-list-fold.open { grid-template-rows: 1fr; }
.editor-list-fold > .editor-titles { overflow: hidden; min-height: 0; }
.editor-titles { display: flex; flex-direction: column; gap: .1em; align-items: flex-start; margin-top: 6px; max-height: 62vh; overflow-y: auto; } /* a long shelf scrolls inside the titles column; the head stays put */
.editor-title { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; text-align: left; padding: .3em 0; white-space: nowrap; }
.editor-title.on { color: var(--ink); }
.editor-title.out { opacity: .45; text-decoration: line-through; }
.changes-open > .admin-face-del { display: block; margin-bottom: .8em; }
.editor-title:not(.on):hover { color: var(--ink); }
.editor-body { max-width: var(--measure, 29em); margin-top: 0; font-size: var(--fs); } /* the measure's em is the text's, as on every page - the width grip sits at this column's right edge */
.editor-body > * { font-size: var(--fs-mono); }
.editor-loading { min-height: 20vh; }

/* the code surface: a transparent textarea over the colored lines; the caret is his,
   the colors and the numbers are the page's. One font metric for both layers. */
.code-surface {
    /* line 1's baseline sits on the story head's calibration constant, so the code's first
       baseline meets the title's baseline exactly as the text's does on every story */
    --code-pad: calc((0.817 + (var(--lh) - 1) / 2) * var(--fs) - 1.05 * var(--fs-mono));
    position: relative;
    height: 62vh;
    min-height: 300px;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: var(--fs-mono);
    line-height: 1.5;
}
.code-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    margin: 0;
    padding: var(--code-pad) 0 0 44px;
    font: inherit;
    line-height: inherit;
    letter-spacing: 0;
    background: transparent;
    color: transparent;
    caret-color: #dc143c;
    border: 0;
    outline: none;
    resize: none;
    white-space: pre-wrap; /* the code reflows to the measure - the width grip re-lays lines, never covers them */
    word-break: break-all;
    tab-size: 8;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none; /* the site's own scroller hides it too - and a gutter here would skew the wrap math */
}
.code-input::-webkit-scrollbar { display: none; }
.code-input::selection { background: #dc143c; color: transparent; }
.code-view,
.code-gutter {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}
.code-shift { position: absolute; top: var(--code-pad); left: 0; width: 100%; will-change: transform; } /* full width: the view's wrap column is the textarea's, to the pixel */
.code-line { position: absolute; left: 44px; width: calc(100% - 44px); white-space: pre-wrap; word-break: break-all; tab-size: 8; color: var(--ink); }
.code-measure { position: absolute; top: var(--code-pad); left: 44px; width: calc(100% - 44px); height: 0; overflow: hidden; visibility: hidden; pointer-events: none; white-space: pre-wrap; word-break: break-all; tab-size: 8; } /* the wrap yardstick: the textarea's own text box, offstage */
.code-measure > div { min-height: 1.5em; }
.code-gutter { width: 44px; right: auto; }
.code-num { position: absolute; left: 0; width: 32px; height: 1.5em; text-align: right; color: var(--dim); user-select: none; }
.tok-com, .tok-pun { color: var(--dim); }
.tok-str { color: #dc143c; }

/* the admin rings' slot in the rail's stack: one flex child holding the page's rings in the
   same column rhythm, so the whole stack - page buttons and admin rings alike - travels with
   the horizon and nothing overlaps (his ruling, 27 Sep 21:00) */
.admin-slot { display: flex; flex-direction: column; gap: 10px; }
/* the ring atom outside the rail: the same 34px hairline circle, the word in the tip */
.ring-btn {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--hairline);
    background: transparent;
    color: var(--dim);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    position: relative;
    text-decoration: none;
    transition: color 0.35s ease, border-color 0.35s ease;
}
.ring-btn:hover:not(:disabled), .ring-btn:focus-visible:not(:disabled) { color: var(--ink); border-color: var(--ink); }
.ring-btn:disabled { color: var(--hairline); cursor: default; }
.ring-btn[data-tip]:hover:not(:disabled)::after {
    content: attr(data-tip);
    position: absolute;
    right: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    white-space: nowrap;
    font-family: var(--font-mono);
    font-variation-settings: var(--fvs-mono);
    font-size: 9.5pt;
    letter-spacing: 0.04em;
    color: var(--dim);
    pointer-events: none;
}
.admin-apply { font: inherit; background: none; border: none; color: var(--dim); cursor: pointer; padding: .55em 0; letter-spacing: .06em; }
.admin-apply:not(:disabled):hover { color: var(--ink); }
.admin-apply:disabled { color: var(--hairline); cursor: default; }
.changes-title { flex: 1; font: inherit; background: none; border: none; color: var(--ink); cursor: pointer; text-align: left; padding: 0; }
.diff-block { padding: .4em 0 .9em 1.2em; line-height: 1.5; }
.diff-block div { white-space: pre-wrap; word-break: break-all; }
.diff-out { color: var(--dim); text-decoration: line-through; }
.diff-in { color: var(--ink); }
.diff-ctx { color: var(--hairline); }
@media (max-aspect-ratio: 1/1) {
    .code-surface { height: 50vh; }
}

/* the account: the admin's own settings - one label, one field, one button, his order 27 Sep 17:50 */
.account-note {
    font-size: 12px;
    opacity: 0.75;
    max-width: 34em;
}
