/* ==========================================================================
   60  Folio — the redesign's foundation: tokens and components
   --------------------------------------------------------------------------
   Built 2026-09-30 from the owner's style sheet (Style.dc.html §03–§14, Style3 §28–§30,
   Style5 §44 and §46), as a trial. NOT loaded by index.html yet; dev/folio-kit.html is the
   only page that reads it. Nothing here reaches the deck log: every rule is written under
   `.folio`, and the tokens are declared on `.folio` itself.

   WHY THE TOKENS ARE ON `.folio` AND NOT ON `:root`. The same reason the log's are on a
   selector list at the head of css/02-auth.css — scope — with one lesson taken from what
   that list has cost (references/world-traps.md): an overlay appended to <body> is inside
   no room, so it resolves nothing unless it is named. Here the rule is simpler and the JS
   enforces it: EVERY piece that 60-folio-ui.js puts on <body> (a sheet, a dialog, the undo
   bar) carries the `folio` class itself. Do not add a new overlay without it; a screenshot
   of one that resolved nothing would look like the outgoing world, not like an error.

   The world, as settled by the owner (do not reinterpret):
     paper #F7F6F3 · ink #1A1614 · graphite #66635F · pale #A8A7A1 · band #EFEEE9
     card #FDFCFA · rule #E3E3DE · dashed hairlines rgba(26,22,20,.18)
     red #C4111F is the ONLY accent: Save/commit, "now", faults, the irreversible warning,
     the required dot. Delete and Remove are ink (Undo covers them). Links are underlined ink.
     Newsreader 400 for titles; Geist for body; Geist Mono small caps for eyebrows.
     Square corners everywhere except the glass capsule, radios and a sheet's top corners.
   ========================================================================== */

.folio {
    --fo-paper: #F7F6F3;
    --fo-ink: #1A1614;
    --fo-graphite: #66635F;
    --fo-pale: #A8A7A1;
    --fo-band: #EFEEE9;
    --fo-card: #FDFCFA;
    --fo-rule: #E3E3DE;
    --fo-hair: rgba(26,22,20,0.18);
    --fo-hair-firm: rgba(26,22,20,0.28);   /* a card's or a menu's edge */
    --fo-hair-open: rgba(26,22,20,0.35);   /* the "not yet" tag, the offline note */
    --fo-red: #C4111F;
    --fo-scrim: rgba(26,22,20,0.42);
    --fo-bone: #E6E4DE;                    /* the two bone greys of §46 C/H */
    --fo-bone-light: #ECEAE5;
    --fo-edge: rgba(26,22,20,0.92);        /* the outlined button's border */

    --fo-serif: 'Newsreader', Georgia, serif;
    --fo-sans: 'Geist', system-ui, sans-serif;
    --fo-mono: 'Geist Mono', ui-monospace, Menlo, monospace;

    --fo-gutter: 24px;       /* every page board keeps 24px at the sides */
    --fo-tap: 44px;          /* nothing pressable is smaller */
    --fo-sheet-corner: 20px; /* a sheet, not a card */
    --fo-field-x: 12px;      /* §04 draws a field with 12px sides; a room set flush in its
                                gutter sets this to 0 (ActivityEdit, ExpenseEdit do) */

    font-family: var(--fo-sans);
    font-size: 15px;
    line-height: 1.4;
    color: var(--fo-ink);
    background: var(--fo-paper);
    -webkit-font-smoothing: antialiased;
}

/* A control does not inherit its face (see 01-tokens.css for the app-wide lesson);
   inside the folio every control takes the folio's. `:where` keeps this at the weight of a
   bare element rule — written as `.folio button` it outranked `.fo-btn`, and the first
   photograph of the kit showed every dark button with its word in ink on ink. */
:where(.folio) button, :where(.folio) input, :where(.folio) textarea, :where(.folio) select { font: inherit; color: inherit; }
.folio a { color: var(--fo-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.folio b { font-weight: 500; }
.folio svg { display: block; }

/* ---- type ------------------------------------------------------------------ */

.fo-eyebrow {
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-graphite);
}
.fo-eyebrow--ink { color: var(--fo-ink); }
.fo-eyebrow--small { font-size: 9px; color: var(--fo-pale); }
.fo-serif { font-family: var(--fo-serif); font-weight: 400; }
.fo-quiet { font-size: 12px; line-height: 1.5; color: var(--fo-graphite); }

/* A section's title on a form: mono ink over a dashed hairline (§04 Long text, ActivityEdit). */
.fo-section {
    padding-bottom: 8px;
    border-bottom: 1px dashed var(--fo-hair);
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-ink);
}

/* ---- the top bar (§10, §32) ------------------------------------------------- */
/* Three columns: the left action, the mono title, the right action. The right action is
   red and underlined ONLY when it commits (Save, Done, Make); a Contents or a Close is ink.
   `is-running` is §46 E: the hairline under the head carries a short ink stroke across
   while the page is brought up to date, and nothing else moves. */
.fo-bar {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 12px;
    height: 44px;
    padding: 0 var(--fo-gutter);
    border-bottom: 1px dashed var(--fo-hair);
}
.fo-bar__title {
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fo-bar__act {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    min-height: var(--fo-tap);
    min-width: var(--fo-tap);
    padding: 0;
    border: none;
    background: transparent;
    font-size: 14px;
    color: var(--fo-ink);
    text-decoration: none;
    cursor: pointer;
}
.fo-bar__act--right { justify-self: end; justify-content: flex-end; }
.fo-bar__act--commit { color: var(--fo-red); text-decoration: underline; text-underline-offset: 3px; }
.fo-bar.is-running { overflow: hidden; }
.fo-bar.is-running::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 70px;
    height: 1.5px;
    background: var(--fo-ink);
    animation: fo-run 1.4s cubic-bezier(.45,0,.55,1) infinite;
}

/* ---- buttons (§03, §32) ----------------------------------------------------- */
/* One dark button per screen; a second choice beside it is outlined; a third never.
   Delete is outlined ink, not red — the Undo bar is its safety. */
.fo-btn {
    height: 52px;
    padding: 0 24px;
    border: none;
    background: var(--fo-ink);
    color: var(--fo-card);
    font-size: 15px;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.fo-btn--full { width: 100%; }
.fo-btn--secondary {
    padding: 0 22px;
    border: 1px solid var(--fo-edge);
    background: transparent;
    color: var(--fo-ink);
}
.fo-btn--compact { height: 44px; padding: 0 18px; font-size: 14px; }
.fo-btn--square { width: 44px; height: 44px; padding: 0; flex-shrink: 0; }
.fo-btn__arrow { font-family: var(--fo-serif); font-style: italic; font-size: 17px; }
.fo-btn:disabled, .fo-btn.is-disabled {
    background: var(--fo-rule);
    color: var(--fo-pale);
    border-color: transparent;
    cursor: default;
}
/* Working (§03, §46 F): only sign-in and sign-up, which must hear back. The word becomes a
   mono line — SIGNING IN… — and nothing spins; there is no caret. */
.fo-btn.is-working, .fo-btn.is-working:disabled {
    background: var(--fo-ink);
    color: var(--fo-card);
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: default;
}
/* Text actions: a link is underlined ink; Back is a word without one; the mono word (Hide)
   is the instrument's own voice. All three stand 44 tall. */
.fo-text, .fo-back, .fo-word {
    display: inline-flex;
    align-items: center;
    min-height: var(--fo-tap);
    padding: 0;
    border: none;
    background: transparent;
    color: var(--fo-ink);
    cursor: pointer;
}
.fo-text { font-size: 15px; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.fo-back { font-size: 15px; text-decoration: none; }
.fo-word { font-family: var(--fo-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; text-decoration: none; }

/* ---- fields (§04) ----------------------------------------------------------- */
/* A mono label above a 17px value on a dashed baseline. Typing thickens the baseline to a
   2px ink line and lifts the ground to the card; it never glows. A fault turns the label,
   the line and the note red. A required label ends in a red dot. Only two lines are solid
   ink: under a title field (the page's own name, in serif) and under an amount typed in a
   row. */
.fo-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    min-width: 0;
    padding: 12px var(--fo-field-x) 10px;
    border: none;
    border-bottom: 1px dashed var(--fo-hair);
    background: transparent;
    text-align: left;
    cursor: text;
}
.fo-field__label {
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-graphite);
}
.fo-field__label.is-required { color: var(--fo-ink); }
.fo-field__label.is-required::after {
    content: '·';
    margin-left: 4px;
    color: var(--fo-red);
    font-size: 16px;
    line-height: 0;
    vertical-align: -2px;
}
.fo-field__input, .fo-field__value {
    display: flex;
    align-items: center;
    min-height: 22px;
    width: 100%;
    padding: 0;
    border: none;
    background: transparent;
    font-size: 17px;
    letter-spacing: -0.01em;
    color: var(--fo-ink);
    outline: none;
}
.fo-field__input::placeholder { color: var(--fo-pale); opacity: 1; }
.fo-field:focus-within {
    border-bottom-color: transparent;
    box-shadow: inset 0 -2px 0 0 var(--fo-ink);
    background: var(--fo-card);
}
.fo-field.is-fault {
    border-bottom-color: transparent;
    box-shadow: inset 0 -2px 0 0 var(--fo-red);
}
.fo-field.is-fault .fo-field__label { color: var(--fo-red); }
.fo-field__note { padding: 0 var(--fo-field-x); font-size: 12px; color: var(--fo-red); }
.fo-field.is-disabled { cursor: default; }
.fo-field.is-disabled .fo-field__label,
.fo-field.is-disabled .fo-field__input,
.fo-field.is-disabled .fo-field__value { color: var(--fo-pale); }
/* A hint under the value, in the instrument's voice ("Read from the booking"). */
.fo-field__hint { font-family: var(--fo-mono); font-size: 8px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fo-graphite); }

/* The title field: the page's own name, in serif, over a solid ink line. */
.fo-field--title { padding-bottom: 8px; border-bottom: 1.5px solid var(--fo-ink); }
.fo-field--title .fo-field__input, .fo-field--title .fo-field__value {
    font-family: var(--fo-serif);
    font-size: 30px;
    letter-spacing: -0.03em;
    line-height: 1.05;
    min-height: 32px;
}

/* A pick-one: the field shows what is chosen and ▾; a tap opens the choice sheet (§05,
   §29). It is a button, so the keyboard reaches it; the value never types. */
.fo-field--pick { cursor: pointer; }
.fo-field--pick .fo-field__value { justify-content: space-between; gap: 8px; }
.fo-field--pick .fo-field__value > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fo-field--pick .fo-field__value.is-empty > span { color: var(--fo-pale); }
.fo-chev { flex-shrink: 0; }
.fo-field--pick:focus-visible { outline: none; box-shadow: inset 0 -2px 0 0 var(--fo-ink); border-bottom-color: transparent; }

/* Two or three fields side by side, as the forms draw dates and money. */
.fo-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.fo-fields--three { grid-template-columns: 72px 1fr 1fr; }

/* An amount typed inside a row (§04): a name, then a mono figure over a solid 1.5px ink
   line, then its unit. */
.fo-amount-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 10px var(--fo-field-x);
    border-bottom: 1px dashed var(--fo-hair);
}
.fo-amount-row__name { font-size: 15px; }
.fo-amount { display: flex; align-items: baseline; gap: 5px; }
.fo-amount__input {
    width: 76px;
    padding: 2px 0 3px;
    border: none;
    border-bottom: 1.5px solid var(--fo-ink);
    background: transparent;
    text-align: right;
    font-family: var(--fo-mono);
    font-size: 14px;
    outline: none;
}
.fo-amount__input:focus { border-bottom-width: 2px; padding-bottom: 2.5px; }
.fo-amount__unit { font-family: var(--fo-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fo-graphite); }

/* The search box (§04): the one boxed field. 44 tall, a 1px rule, on the card. While typed
   in it takes an ink edge and a Clear. */
.fo-search {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 44px;
    padding: 0 12px;
    border: 1px solid var(--fo-rule);
    background: var(--fo-card);
    cursor: text;
}
.fo-search svg { flex-shrink: 0; }
.fo-search__input { flex: 1; min-width: 0; padding: 0; border: none; background: transparent; font-size: 15px; outline: none; }
.fo-search__input::placeholder { color: var(--fo-pale); opacity: 1; }
.fo-search__clear {
    display: none;
    margin-left: auto;
    min-height: var(--fo-tap);
    padding: 0;
    border: none;
    background: transparent;
    font-size: 12px;
    color: var(--fo-graphite);
    cursor: pointer;
}
.fo-search.is-typing { border-color: var(--fo-ink); }
.fo-search.is-typing .fo-search__clear { display: inline-flex; align-items: center; }
.fo-search--short { height: 40px; }
.fo-search--short .fo-search__input { font-size: 14px; }

/* Long text (§04): under a section title, in a pale box, in serif; only the empty box's
   hint leans. Typing takes the ink edge, as the search box does — §04 says nothing about
   the box while typed in, and this is the nearest rule (an interpretation, recorded). */
.fo-longtext { display: flex; flex-direction: column; }
.fo-longtext__box {
    margin-top: 2px;
    min-height: 64px;
    padding: 10px 12px;
    border: 1px solid var(--fo-rule);
    background: var(--fo-card);
    font-family: var(--fo-serif);
    font-size: 15px;
    line-height: 1.5;
    resize: vertical;
    outline: none;
}
.fo-longtext__box::placeholder { font-style: italic; color: var(--fo-pale); opacity: 1; }
.fo-longtext__box:focus { border-color: var(--fo-ink); }
.fo-longtext__count {
    align-self: flex-end;
    margin-top: 4px;
    font-family: var(--fo-mono);
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-pale);
}

/* ---- the sheet (§05, §29) --------------------------------------------------- */
/* Rises from the bottom over a 42% ink scrim; 20px top corners; a handle; a mono title
   that names the thing. A row is at least 58px: the name in 15px medium, one grey line
   under it; a dot marks the current setting, a chevron a way in. A tap chooses and closes.
   The search variant is the same sheet at most 60% of the screen: the box stays at its top
   and the list scrolls under it with no visible scrollbar. */
.fo-scrim {
    position: fixed;
    inset: 0;
    z-index: 9000;
    background: var(--fo-scrim);
    opacity: 0;
    transition: opacity .2s ease-out;
}
.fo-scrim.is-open { opacity: 1; }
.fo-scrim--centre { display: flex; align-items: center; justify-content: center; padding: var(--fo-gutter); }
.fo-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9001;
    box-sizing: border-box;
    max-height: 92vh;
    padding: 10px var(--fo-gutter) 34px;
    background: var(--fo-paper);
    border-radius: var(--fo-sheet-corner) var(--fo-sheet-corner) 0 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transform: translateY(100%);
    transition: transform .24s ease-out;
}
.fo-sheet.is-open { transform: none; }
.fo-sheet--search { height: 60vh; }
/* The handle's box is taller than its 4px line, so a thumb finds it; it and the title take
   the pull (foSheetPull), and touch-action: none keeps the page from scrolling with it. */
.fo-sheet__handle { align-self: center; flex-shrink: 0; box-sizing: content-box; width: 36px; height: 4px; padding: 10px 24px; margin: -10px 0 2px; border-radius: 9999px; background: var(--fo-rule); background-clip: content-box; touch-action: none; cursor: grab; }
.fo-sheet__title { touch-action: none; }
.fo-scrim { touch-action: none; }
.fo-sheet__title {
    flex-shrink: 0;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding-bottom: 8px;
    border-bottom: 1px dashed var(--fo-hair);
    font-family: var(--fo-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-ink);
}
.fo-sheet__search { flex-shrink: 0; margin-top: 12px; }
.fo-sheet__list { flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: none; display: flex; flex-direction: column; }
.fo-sheet__list::-webkit-scrollbar { display: none; }
.fo-sheet__group {
    flex-shrink: 0;
    padding: 14px 0 6px;
    border-bottom: 1px dashed var(--fo-hair);
    font-family: var(--fo-mono);
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-pale);
}
.fo-sheet__row {
    flex-shrink: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 58px;
    padding: 8px 0;
    border: none;
    border-bottom: 1px dashed var(--fo-hair);
    background: transparent;
    text-align: left;
    cursor: pointer;
}
.fo-sheet--search .fo-sheet__row { min-height: 48px; }
.fo-sheet__row-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.fo-sheet__row-name { font-size: 15px; font-weight: 500; }
.fo-sheet__row-sub { font-size: 12px; color: var(--fo-graphite); }
.fo-sheet__row-code { width: 44px; flex-shrink: 0; font-family: var(--fo-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; }
.fo-sheet__row-code + .fo-sheet__row-text { flex: 1; }
.fo-sheet__row-code + .fo-sheet__row-text .fo-sheet__row-name { font-weight: 400; }
.fo-dot { width: 10px; height: 10px; flex-shrink: 0; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--fo-pale); }
.fo-dot.is-current { background: var(--fo-ink); box-shadow: none; }
.fo-way { flex-shrink: 0; color: var(--fo-graphite); }
.fo-sheet__empty { padding: 14px 0; font-size: 12px; color: var(--fo-graphite); }
/* What a searched sheet says when the answer is words (PlaceSearch: "Nothing by that name
   on the map."), and the quiet line under its rows. */
.fo-sheet__said { flex-shrink: 0; margin: 18px 0 0; font-family: var(--fo-serif); font-style: italic; font-size: 17px; }
.fo-sheet__note { flex-shrink: 0; margin: 12px 0 0; font-size: 12px; line-height: 1.5; color: var(--fo-graphite); }
.fo-sheet__cancel {
    flex-shrink: 0;
    margin-top: 12px;
    min-height: var(--fo-tap);
    border: none;
    background: transparent;
    font-size: 14px;
    text-align: center;
    cursor: pointer;
}
/* The kit page shows a sheet standing on the page rather than rising over it. */
.fo-sheet--inline { position: static; transform: none; max-height: none; border: 1px solid var(--fo-rule); border-bottom: none; }
.fo-sheet--inline.fo-sheet--search { height: 420px; }

/* ---- the dialog (§11, §44) -------------------------------------------------- */
/* Only for what Undo cannot reach — deleting or leaving a trip, handing it on. A card with
   light-grey corner ticks; an eyebrow; a red warning triangle beside the serif title; what
   goes and what stays; "It can't be undone." in a red-ruled line; the safe choice first,
   outlined; the act in black. Delete is black even here. */
.fo-dialog {
    position: relative;
    width: 100%;
    max-width: 342px;
    padding: 22px 20px 18px;
    background: var(--fo-paper);
    border: 1px dashed var(--fo-hair-firm);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.fo-tick { position: absolute; width: 10px; height: 10px; pointer-events: none; }
.fo-tick--tl { top: -1px; left: -1px; border-top: 1.5px solid var(--fo-pale); border-left: 1.5px solid var(--fo-pale); }
.fo-tick--tr { top: -1px; right: -1px; border-top: 1.5px solid var(--fo-pale); border-right: 1.5px solid var(--fo-pale); }
.fo-tick--bl { bottom: -1px; left: -1px; border-bottom: 1.5px solid var(--fo-pale); border-left: 1.5px solid var(--fo-pale); }
.fo-tick--br { bottom: -1px; right: -1px; border-bottom: 1.5px solid var(--fo-pale); border-right: 1.5px solid var(--fo-pale); }
.fo-dialog__eyebrow { font-family: var(--fo-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fo-graphite); }
.fo-dialog__head { display: flex; align-items: center; gap: 10px; }
.fo-dialog__head svg { flex-shrink: 0; }
.fo-dialog__title { font-family: var(--fo-serif); font-size: 24px; letter-spacing: -0.02em; line-height: 1.15; }
.fo-dialog__line { font-size: 13px; line-height: 1.5; color: var(--fo-ink); }
.fo-dialog__never {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid var(--fo-red);
    font-size: 13px;
    line-height: 1.4;
    color: var(--fo-red);
}
.fo-dialog__acts { display: flex; gap: 8px; margin-top: 8px; }
.fo-dialog__acts > .fo-btn { flex: 1; padding: 0; }

/* A card and a menu of actions share the ticked dashed edge (§05, §06). */
.fo-card { position: relative; padding: 16px 18px; border: 1px dashed var(--fo-hair-firm); background: rgba(253,252,250,0.7); }
.fo-menu { position: relative; border: 1px dashed var(--fo-hair-firm); background: var(--fo-card); }
.fo-menu__row {
    display: flex;
    align-items: center;
    width: 100%;
    height: 44px;
    padding: 0 14px;
    border: none;
    border-top: 1px dashed var(--fo-hair);
    background: transparent;
    font-size: 15px;
    text-align: left;
    cursor: pointer;
}
.fo-menu__row:first-of-type { border-top: none; }

/* ---- the undo bar (§30) ----------------------------------------------------- */
/* The one feedback for an act that changed something. Across the foot, 16px from the
   sides; 28 from the bottom, or above the tab bar (96) where there is one. Five seconds,
   then it goes and the act is final. One at a time; a new one replaces the last. */
.fo-undo {
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: 28px;
    z-index: 9500;
    box-sizing: border-box;
    min-height: 52px;
    padding: 12px 8px 12px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    background: var(--fo-ink);
    color: var(--fo-card);
    font-size: 14px;
}
.fo-undo--above-tabs { bottom: 96px; }
.fo-undo__msg { min-width: 0; line-height: 1.45; }   /* wraps: a refusal names a booking and its dates (§37 #4) */
.fo-undo__act {
    flex-shrink: 0;
    min-height: var(--fo-tap);
    padding: 0 12px;
    border: none;
    background: transparent;
    color: var(--fo-card);
    font-weight: 500;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.fo-undo--inline { position: static; }

/* ---- tags (§06, §28) -------------------------------------------------------- */
/* 22px, square, mono 9px caps. Settled is a grey fill; chosen an ink outline; not-yet a
   dashed one; now a red outline — the present only, never a fault. A state tag is never
   pressable. */
.fo-tag {
    height: 22px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    font-family: var(--fo-mono);
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-ink);
    white-space: nowrap;
}
.fo-tag--settled { background: var(--fo-rule); }
.fo-tag--settled.fo-tag--quiet { color: var(--fo-graphite); }
.fo-tag--chosen { border: 1px solid var(--fo-ink); }
.fo-tag--open { border: 1px dashed var(--fo-hair-open); color: var(--fo-graphite); }
.fo-tag--now { border: 1px solid var(--fo-red); color: var(--fo-red); }
.fo-tag--filled { background: var(--fo-ink); color: var(--fo-card); }
.fo-tag--small { height: 22px; padding: 0 7px; font-size: 8px; flex-shrink: 0; }
/* A tag standing in a row's right column with a link under it (§25 Marked): the tag
   above, "Add the ticket" beneath, both to the right edge. */
.fo-tag-col { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
/* The "now" mark on its own: a red dot and the word. */
.fo-now { display: inline-flex; align-items: center; gap: 6px; font-family: var(--fo-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fo-red); }
.fo-now::before { content: ''; width: 6px; height: 6px; border-radius: 9999px; background: var(--fo-red); }

/* ---- the glass capsule (§10) ------------------------------------------------ */
/* The one round thing besides radios and a sheet's corners: the tab bar. */
.fo-tabs {
    height: 58px;
    padding: 6px;
    box-sizing: border-box;
    display: flex;
    gap: 4px;
    border-radius: 82px;
    background: rgba(215,215,208,0.5);
    box-shadow: inset 0 0 10px rgba(0,0,0,0.08);
    border: 1px solid rgba(253,252,250,0.6);
    font-size: 13px;
    font-weight: 500;
}
.fo-tabs__tab {
    flex-grow: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 11px;
    border: none;
    border-radius: 9999px;
    background: transparent;
    color: var(--fo-ink);
    cursor: pointer;
}
.fo-tabs__tab.is-on { padding: 0 16px; background: var(--fo-ink); color: var(--fo-card); }
.fo-tabs__tab--aside { flex-grow: 0; margin-left: auto; padding: 0 14px; background: var(--fo-card); }

/* ---- loading (§46) ---------------------------------------------------------- */
/* The rules: kept copy first, and a quiet mono line saying only what it knows; bones only
   when nothing is held; the rule under the head runs while refreshing (.fo-bar.is-running);
   photographs come as their colour, then blurred, then sharp; never a spinner, never a
   cover, never a guessed percent. The timing is the JS's (foLoading): nothing under 0.3s,
   the line at 0.3s, the running rule joins at 1s, words and Try again at 8s. */
.fo-check {
    display: none;
    justify-content: flex-end;
    align-items: baseline;
    gap: 8px;
    padding: 6px var(--fo-gutter) 0;
    font-family: var(--fo-mono);
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--fo-pale);
}
.fo-check.is-on { display: flex; }
.fo-check.is-failed, .fo-check.is-slow { color: var(--fo-red); }
.fo-check__retry { flex-shrink: 0; white-space: nowrap; min-height: 24px; padding: 0; border: none; background: transparent; color: var(--fo-ink); text-decoration: underline; text-underline-offset: 2px; font: inherit; cursor: pointer; }

.fo-bone { display: block; background: var(--fo-bone); animation: fo-breathe 1.6s ease-in-out infinite; }
.fo-bone--light { background: var(--fo-bone-light); }
/* A row of bones the shape of a list row: a 40px square and two lines (§46 C/H). */
.fo-bone-row { display: grid; grid-template-columns: 40px 1fr; gap: 10px; align-items: center; padding: 9px var(--fo-gutter); border-bottom: 1px dashed var(--fo-hair); }
.fo-bone-row__lines { display: flex; flex-direction: column; gap: 6px; }

/* A photograph's tile: its own colour (--c, kept with it when uploaded), then a tiny
   blurred copy, then the sharp one fades in. The tile never changes size. */
.fo-photo { display: block; position: relative; overflow: hidden; background: var(--c, var(--fo-rule)); }
.fo-photo img { display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .3s ease-out, filter .3s ease-out; }
.fo-photo.is-blurred img { opacity: 1; filter: blur(6px); transform: scale(1.06); }
.fo-photo.is-sharp img { opacity: 1; filter: none; transform: none; }

/* A bar only where the length is known (upload, pages made); otherwise the running stroke. */
.fo-progress { height: 2px; background: var(--fo-rule); position: relative; overflow: hidden; }
.fo-progress__fill { height: 2px; background: var(--fo-ink); }
.fo-progress--running .fo-progress__fill { position: absolute; top: 0; bottom: 0; width: 30%; animation: fo-run2 1.3s ease-in-out infinite; }
/* Words for a long wait, in the app's own voice (Boswell's would be Courier Prime). */
.fo-long { display: flex; flex-direction: column; gap: 14px; }
.fo-long__line { font-size: 14px; line-height: 1.5; }

@keyframes fo-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes fo-run { from { transform: translateX(-80px); } to { transform: translateX(100vw); } }
@keyframes fo-run2 { from { left: -30%; } to { left: 100%; } }

/* Reduced motion: bones stand still, the stroke stops, words stay; sheets and the scrim
   arrive without sliding. */
@media (prefers-reduced-motion: reduce) {
    .folio .fo-bone, .folio .fo-bar.is-running::after, .folio .fo-progress--running .fo-progress__fill { animation: none; }
    .folio .fo-bar.is-running::after { width: 100%; opacity: .3; }
    .folio .fo-sheet, .folio .fo-scrim, .folio .fo-photo img,
    .fo-sheet.folio, .fo-scrim.folio { transition: none; }
}
