/*
 * The web UI as an app, on a phone.
 *
 * Wyldcards on a narrow screen is a web page with a page's habits: eleven
 * full-width buttons stacked above the first song, every row wearing nine more,
 * a breadcrumb running under the floating account menu. The app the same writer
 * has on their phone opens on the songs themselves — a navigation bar with a
 * back chevron and a title, a plain list of rows, and everything a row can do
 * kept behind a "..." until it is asked for.
 *
 * This sheet is that shape, and it is deliberately only a shape: every rule
 * here hangs off `html.app-shell`, which app-shell.js sets on a narrow viewport
 * or in an installed window and clears otherwise. Nothing below moves a node,
 * rewrites a form or replaces a control — the same markup the desktop page is
 * built from is re-laid-out, so a row's Delete is the same Delete whichever
 * chrome is around it, and taking the class off puts the page back exactly as
 * it was. That is what keeps this from becoming a second UI to maintain.
 *
 * Loaded after wyldcards.css on every page that has one, so these rules win on
 * order rather than on specificity wars or `!important` (a handful survive
 * where wyldcards.css itself used `!important` first).
 */

html.app-shell {
    /* The two bars the page has to keep clear of, plus the notch and home
       indicator. Read by the padding rules below and by app-shell.js. */
    --app-bar-height: 3rem;
    --app-tab-height: 3.25rem;
    --app-safe-top: env(safe-area-inset-top, 0px);
    --app-safe-bottom: env(safe-area-inset-bottom, 0px);
    --app-safe-left: env(safe-area-inset-left, 0px);
    --app-safe-right: env(safe-area-inset-right, 0px);

    /* Chrome — bars, tabs, sheets, row separators — in the system's own voice.
       The words in a song are left in the site's typeface on purpose: it is the
       furniture that should look native, not the writing. */
    --app-ui-font: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    --app-hairline: color-mix(in srgb, var(--fg, #000) 14%, transparent);
    --app-bar-bg: color-mix(in srgb, var(--bg, #fff) 82%, transparent);
    --app-press: color-mix(in srgb, var(--fg, #000) 7%, transparent);
    --app-sheet-bg: var(--box-bg, var(--bg, #fff));
    --app-scrim: color-mix(in srgb, #000 40%, transparent);
    --app-tint: var(--accent, #2563eb);
    --app-danger: #d3382f;

    /* A tap should not paint a grey box over half a row, and a double tap on a
       list should not zoom the page. */
    -webkit-tap-highlight-color: transparent;
}

html.app-shell.-dark-theme,
html.app-shell[data-app-dark="1"] {
    --app-hairline: color-mix(in srgb, #fff 18%, transparent);
    --app-danger: #ff6961;
}

html.app-shell body {
    /* Room for the two fixed bars. A page with neither still gets the top one:
       app-shell.js only builds the tab bar where there are tabs to show, and
       clears --app-tab-height when it does not. */
    padding-top: calc(var(--app-bar-height) + var(--app-safe-top));
    padding-bottom: calc(var(--app-tab-height) + var(--app-safe-bottom));
    overscroll-behavior-y: none;
}

html.app-shell body.app-shell-no-tabs {
    --app-tab-height: 0rem;
}

html.app-shell button,
html.app-shell a,
html.app-shell input,
html.app-shell select,
html.app-shell label {
    touch-action: manipulation;
}

/* The landing page and the login screen are their own designs, already built
   for a phone, and neither is a place a back chevron or a tab bar belongs. */
html.app-shell body.landing-body,
html.app-shell body.login-body {
    padding-top: var(--app-safe-top);
    padding-bottom: var(--app-safe-bottom);
}

/* ---------------------------------------------------------------------------
   The navigation bar
   ------------------------------------------------------------------------ */

.app-bar {
    display: none;
}

/* app-shell.js hides the bar on the pages that are their own design. Without
   this the rule below would still paint it: an author `display` beats the
   `hidden` attribute's user-agent one. */
html.app-shell .app-bar[hidden] {
    display: none;
}

html.app-shell .app-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1600;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: calc(var(--app-bar-height) + var(--app-safe-top));
    padding: var(--app-safe-top) var(--app-safe-right) 0 var(--app-safe-left);
    box-sizing: border-box;
    font-family: var(--app-ui-font);
    background: var(--app-bar-bg);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-bottom: 1px solid var(--app-hairline);
}

.app-bar-back {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
    flex: 0 1 auto;
    min-width: 0;
    height: 100%;
    padding: 0 0.5rem 0 0.35rem;
    max-width: 100%;
    color: var(--app-tint);
    font-size: 1rem;
    text-decoration: none;
    background: none;
    border: 0;
}

.app-bar-back:active {
    opacity: 0.4;
}

.app-bar-back svg {
    flex: 0 0 auto;
}

.app-bar-back-label {
    max-width: 7rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Centred on the bar itself rather than in a middle column: the two ends are
   never the same width — a back chevron carrying a long wyldcards name on one
   side, two buttons on the other — and a title centred between them is a title
   that wanders as you move through the app. Taken out of the flow so it is
   centred on the screen and stays there, and kept clear of both ends by a
   margin wide enough for them. */
.app-bar-title {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    max-width: calc(100% - 13rem);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--fg);
    pointer-events: none;
}

.app-bar-trailing {
    flex: 0 0 auto;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    height: 100%;
    padding-right: 0.35rem;
}

/* The bar's own buttons: the page's primary action, and the "..." holding
   everything else its toolbar offers. Neither does anything itself — each
   forwards to a control the page already has. */
.app-bar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    height: 2.5rem;
    padding: 0 0.35rem;
    border: 0;
    background: none;
    box-shadow: none;
    color: var(--app-tint);
}

.app-bar-btn:active {
    opacity: 0.4;
}

.app-bar-btn[hidden] {
    display: none;
}

/* Account and help sit in `.header-actions`, which wyldcards.css
   floats over the top-right of every page — and which, at this width, lands on
   top of whatever that page put there. In this chrome the bar's right-hand side
   belongs to the page's own actions and the account belongs in the tab bar, so
   the two toggles go away while the group itself stays exactly where it is.
   Their menus are still opened, by app-shell.js clicking these same buttons
   from the More tab: a hidden button answers `.click()` like any other, which
   is why nothing here has to be moved, cloned or rebuilt. */
html.app-shell .header-actions {
    position: fixed;
    top: 0;
    left: 0;
    right: auto;
    width: 0;
    height: 0;
    overflow: visible;
    z-index: 1700;
}

html.app-shell .header-actions-group {
    height: 0;
    padding: 0;
    background: none;
    border: 0;
}

html.app-shell .header-actions .nav-dropdown-toggle {
    display: none;
}

/* The sync strip stays reachable in the app bar while the desktop header is
   collapsed to zero size. It is intentionally a dot on phones to preserve room
   for the page's primary action. */
html.app-shell .wyldcards-sync-status {
    position: fixed;
    top: calc(var(--app-safe-top) + 0.55rem);
    right: calc(var(--app-safe-right) + 3rem);
    z-index: 1701;
}

/* The brand, the breadcrumb and each page's own big heading all say what the
   bar now says. */
html.app-shell body > header.sidebar.menu > nav,
html.app-shell nav[aria-label="Breadcrumb"],
html.app-shell .app-bar-shadowed-heading {
    display: none !important;
}

/* Collapsed to nothing, so the bar above is the only chrome at the top of the
   page. `!important` throughout because that is what it is being argued with:
   wyldcards.css already pins this header per-page with important margins and
   padding of its own, and this has to win on every page rather than on the ones
   that happen not to. */
html.app-shell body > header.sidebar.menu {
    position: absolute !important;
    top: 0 !important;
    height: 0 !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    overflow: visible;
}

/* One crumb survives that rule: the editor's last one is not a word but the
   field a song is renamed in, and it is the only place a song can be renamed
   from once it is open. The bar carries the same title to be read; this is the
   one to type in, at the head of the song as it is in the app. */
html.app-shell .text-document-edit-page nav[aria-label="Breadcrumb"] {
    display: block !important;
}

html.app-shell .text-document-edit-page nav[aria-label="Breadcrumb"] ol {
    display: block;
    margin: 0;
    padding: 0;
}

html.app-shell .text-document-edit-page nav[aria-label="Breadcrumb"] li:not(.text-document-breadcrumb-title) {
    display: none;
}

/* With the crumbs before it gone, the separator that joined it to them is
   pointing at nothing. */
html.app-shell .text-document-edit-page .text-document-breadcrumb-title::before,
html.app-shell .text-document-edit-page .text-document-breadcrumb-title::marker {
    content: none;
}

html.app-shell .text-document-breadcrumb-title-input {
    width: 100%;
    font-size: 1.25rem;
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   The tab bar
   ------------------------------------------------------------------------ */

.app-tabs {
    display: none;
}

html.app-shell .app-tabs {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1600;
    display: flex;
    align-items: stretch;
    height: calc(var(--app-tab-height) + var(--app-safe-bottom));
    padding: 0 var(--app-safe-right) var(--app-safe-bottom) var(--app-safe-left);
    box-sizing: border-box;
    font-family: var(--app-ui-font);
    background: var(--app-bar-bg);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-top: 1px solid var(--app-hairline);
}

html.app-shell body.app-shell-no-tabs .app-tabs {
    display: none;
}

.app-tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.125rem;
    padding: 0.25rem 0.125rem;
    border: 0;
    background: none;
    box-shadow: none;
    color: var(--muted-fg, #64748b);
    font-size: 0.625rem;
    line-height: 1.1;
    letter-spacing: 0.01em;
    text-decoration: none;
}

.app-tab svg {
    width: 24px;
    height: 24px;
}

.app-tab:active {
    opacity: 0.45;
}

.app-tab[aria-current="page"] {
    color: var(--app-tint);
}

/* ---------------------------------------------------------------------------
   Lists: a row is a row
   ------------------------------------------------------------------------ */

/* Full bleed, the way a grouped list is: the separators run to both edges and
   the text is inset from them, rather than every row being a floating card with
   a gutter around it.

   The lists only. The editor shares `.text-documents-page` with them and is not
   a list at all — taking its gutters away puts the words of a song against the
   glass on both sides. */
html.app-shell main.text-documents-page:not(.text-document-edit-page),
html.app-shell main.wyldcards-list-page,
html.app-shell main.stack-list-page {
    padding-left: 0;
    padding-right: 0;
}

html.app-shell main.text-document-edit-page {
    padding-left: calc(0.75rem + var(--app-safe-left));
    padding-right: calc(0.75rem + var(--app-safe-right));
}

/* Its toolbar wraps rather than running off the side: four menus, two links and
   a timestamp do not fit across a phone on one line. */
html.app-shell .text-document-toolbar-row,
html.app-shell .text-document-top-bar-actions {
    flex-wrap: wrap;
    row-gap: 0.35rem;
}

html.app-shell .text-documents-list,
html.app-shell html.app-shell .wyldcards-list-cards {
    display: block;
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--box-bg, var(--bg, #fff));
    border-top: 1px solid var(--app-hairline);
    border-bottom: 1px solid var(--app-hairline);
}

html.app-shell .text-document-card,
html.app-shell .wyldcards-list-row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    /* Room on the right for the chevron and the "..." the row keeps there. */
    padding: 0.6rem calc(3.25rem + var(--app-safe-right)) 0.6rem calc(1rem + var(--app-safe-left));
    min-height: 3.25rem;
    box-sizing: border-box;
    margin: 0;
    border: 0;
    border-radius: 0;
    border-left: 0;
    box-shadow: none;
    background: none;
    /* The rise-in animation is a page's flourish; a list that redraws on every
       filter keystroke should not re-stage itself each time. */
    animation: none;
    transform: none;
    overflow: hidden;
}

html.app-shell .text-document-card + .text-document-card,
html.app-shell .wyldcards-list-row + .wyldcards-list-row {
    /* Inset separators, stopping short of the left edge under the text. */
    box-shadow: inset 0 1px 0 0 var(--app-hairline);
}

html.app-shell .text-document-card:hover,
html.app-shell .wyldcards-list-row:hover {
    transform: none;
    box-shadow: none;
    border-color: transparent;
}

html.app-shell .text-document-card.app-row-pressed,
html.app-shell .wyldcards-list-row.app-row-pressed {
    background: var(--app-press);
}

/* The card list's drag grip. Two things the phone shell would otherwise take
   from it: the blanket touch-action above turns every button back into a
   tap-and-scroll target, which is exactly the gesture a drag needs to keep for
   itself, and a 22px glyph is not a thumb-sized thing to take hold of. */
html.app-shell .wyldcards-card-list-grip {
    touch-action: none;
    min-width: 2.75rem;
    min-height: 2.75rem;
}

html.app-shell .text-document-card-main,
html.app-shell .wyldcards-title-container {
    flex: 1 1 auto;
    min-width: 0;
}

html.app-shell .text-document-card-title,
html.app-shell .wyldcards-list-title {
    display: block;
    margin: 0;
    font-size: 1rem;
    font-weight: 500;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* One subtitle line under the title, the way a row reads in the app: what it is
   and when it was last touched. The rest of the meta strip — the type badge, the
   folder chip, the lock — says things this list already says by being itself. */
html.app-shell .text-document-card-meta {
    margin: 0.1rem 0 0;
    gap: 0.4rem;
    font-size: 0.8125rem;
    color: var(--muted-fg, #64748b);
    white-space: nowrap;
    overflow: hidden;
}

html.app-shell .text-document-type-badge,
html.app-shell .text-document-folder-badge {
    display: none;
}

/* The lock is a state, not a label: it stays, as a padlock with the word off. */
html.app-shell .text-document-locked-badge {
    font-size: 0.8125rem;
}

html.app-shell .text-document-preview {
    margin: 0.1rem 0 0;
    font-size: 0.8125rem;
    color: var(--muted-fg, #64748b);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Reordering by dragging a handle is a mouse's gesture. The rows still move —
   the handle's own arrow keys still work, and the sort control is in the list's
   "..." — but the handle itself is not worth a thumb's width on every row. */
html.app-shell .text-document-drag-handle,
html.app-shell .wyldcards-list-card-drag-handle {
    display: none;
}

/* Checkboxes are for picking several rows out of a list, which on a phone is a
   mode you enter rather than one you are always in. Hidden until the list's
   "..." turns Select on. */
html.app-shell .text-document-card-lead,
html.app-shell .wyldcards-list-card-lead,
html.app-shell .text-documents-select-all,
html.app-shell .wyldcards-list-select-all {
    display: none;
}

html.app-shell body.app-selecting .text-document-card-lead,
html.app-shell body.app-selecting .wyldcards-list-card-lead,
html.app-shell body.app-selecting .text-documents-select-all,
html.app-shell body.app-selecting .wyldcards-list-select-all {
    display: inline-flex;
}

html.app-shell body.app-selecting .text-document-card-lead .text-document-select input,
html.app-shell body.app-selecting .wyldcards-list-card-lead input[type="checkbox"] {
    width: 1.375rem;
    height: 1.375rem;
}

/* The row's own "..." — the one control this sheet adds to a row. It is the
   whole trailing end of the row: with no swipe to reveal them, what a row can
   do needs something visible to press, and a chevron beside it would be two
   marks in the same corner saying different things. Pressing the row itself
   still opens what it names. */
.app-row-more {
    display: none;
}

html.app-shell .app-row-more {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: calc(3rem + var(--app-safe-right));
    padding: 0 var(--app-safe-right) 0 0;
    border: 0;
    background: none;
    box-shadow: none;
    color: var(--muted-fg, #94a3b8);
}

html.app-shell .app-row-more:active {
    background: var(--app-press);
}

/* ---------------------------------------------------------------------------
   Everything a row or a list can do, behind a sheet
   ------------------------------------------------------------------------ */

/* A row's controls and a list's toolbar are the same markup they always were;
   in this chrome they are off-screen until asked for, and then they are a
   sheet. Off-screen rather than `display: none` so a form inside one still
   posts, and so the sheet can animate in from where it sits. */
html.app-shell .text-document-card-actions,
html.app-shell .wyldcards-list-actions,
html.app-shell .app-sheet-source {
    /* A popover starts life `display: none` and is centred in the viewport by
       the user agent with a border and a margin of its own. All four of those
       are overridden here, so the same rules describe a sheet whether it is
       raised into the top layer or by the fallback class. */
    position: fixed;
    inset: auto 0 0 0;
    margin: 0;
    z-index: 1700;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: auto;
    max-height: 70vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0.5rem calc(0.75rem + var(--app-safe-right))
             calc(0.75rem + var(--app-safe-bottom)) calc(0.75rem + var(--app-safe-left));
    box-sizing: border-box;
    font-family: var(--app-ui-font);
    background: var(--app-sheet-bg);
    border: 0;
    border-top-left-radius: 0.875rem;
    border-top-right-radius: 0.875rem;
    box-shadow: 0 -8px 40px -12px color-mix(in srgb, #000 55%, transparent);
    transform: translateY(101%);
    visibility: hidden;
    transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1), visibility 0.28s;
}

html.app-shell .app-sheet-open,
html.app-shell .text-document-card-actions:popover-open,
html.app-shell .wyldcards-list-actions:popover-open,
html.app-shell .app-sheet-source:popover-open {
    transform: translateY(0);
    visibility: visible;
}

/* The dimming behind a sheet in the top layer. Written out rather than taken
   from `--app-scrim`: a backdrop does not inherit custom properties in every
   engine that supports it. */
html.app-shell [popover]::backdrop {
    background: rgba(0, 0, 0, 0.4);
}

/* The grabber, so the thing reads as something that came up and can go back
   down. Drawn on the sheet rather than marked up inside it, for the same reason
   the chevron is. */
html.app-shell .text-document-card-actions::before,
html.app-shell .wyldcards-list-actions::before,
html.app-shell .app-sheet-source::before {
    content: "";
    flex: 0 0 auto;
    align-self: center;
    width: 2.25rem;
    height: 0.3125rem;
    margin: 0.125rem 0 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--fg, #000) 22%, transparent);
}

/* Inside a sheet every control is one full-width row, whatever it was on the
   desktop page — a link, a submit button, a select. */
html.app-shell .text-document-card-actions > *,
html.app-shell .wyldcards-list-actions > *,
html.app-shell .app-sheet-source > * {
    flex: 0 0 auto;
    width: 100%;
    margin: 0;
}

html.app-shell .text-document-card-actions .wyldcards-list-action-btn,
html.app-shell .wyldcards-list-actions .wyldcards-list-action-btn,
html.app-shell .app-sheet-source .wyldcards-list-action-btn,
html.app-shell .text-document-card-actions button,
html.app-shell .wyldcards-list-actions button,
html.app-shell .app-sheet-source button,
html.app-shell .text-document-card-actions > a,
html.app-shell .wyldcards-list-actions > a,
html.app-shell .app-sheet-source > a {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.5rem;
    width: 100%;
    min-height: 2.875rem;
    margin: 0;
    padding: 0 0.5rem;
    box-sizing: border-box;
    text-align: left;
    font-size: 1.0625rem;
    font-weight: 400;
    color: var(--fg);
    background: none;
    border: 0;
    box-shadow: none;
    border-radius: 0.5rem;
}

html.app-shell .text-document-card-actions .wyldcards-list-action-btn:active,
html.app-shell .wyldcards-list-actions .wyldcards-list-action-btn:active,
html.app-shell .app-sheet-source .wyldcards-list-action-btn:active,
html.app-shell .text-document-card-actions button:active,
html.app-shell .app-sheet-source button:active {
    background: var(--app-press);
}

/* A primary button is white words on a solid fill. Inside a sheet the fill is
   gone — every row of a sheet is a row — so the words have to come back, and
   they were set `#fff !important` in wyldcards.css, which is the one place this
   sheet cannot outrank on order alone. */
html.app-shell .text-document-card-actions .wyldcards-list-action-btn--primary,
html.app-shell .wyldcards-list-actions .wyldcards-list-action-btn--primary,
html.app-shell .app-sheet-source .wyldcards-list-action-btn--primary {
    color: var(--app-tint) !important;
    font-weight: 500;
}

/* Delete stays the one red word in the list, as it is on the desktop page. */
html.app-shell .text-document-delete-btn,
html.app-shell .app-sheet-source .bad,
html.app-shell .text-document-card-actions .bad {
    color: var(--app-danger) !important;
}

html.app-shell .text-document-card-actions form,
html.app-shell .wyldcards-list-actions form,
html.app-shell .app-sheet-source form {
    display: block;
    width: 100%;
    margin: 0;
}

html.app-shell .text-document-card-actions select,
html.app-shell .app-sheet-source select {
    width: 100%;
    min-height: 2.875rem;
    font-size: 1.0625rem;
}

/* The scrim under whichever sheet is up, and the tap that puts it away. */
.app-scrim {
    display: none;
}

html.app-shell .app-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1650;
    background: var(--app-scrim);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.28s ease, visibility 0.28s;
}

html.app-shell .app-scrim.app-scrim-open {
    opacity: 1;
    visibility: visible;
}

/* ---------------------------------------------------------------------------
   Page toolbars
   ------------------------------------------------------------------------ */

/* The wall of buttons above a list — Import, Export, Email, To wyldcards, Archive,
   Delete, Trash, New — is the page's toolbar. The primary one stays out as a
   button; app-shell.js moves the rest behind the bar's "...". What is left is
   laid out as one row rather than a stack of full-width blocks. */
html.app-shell .text-documents-section-actions,
html.app-shell .text-documents-top-actions,
html.app-shell .wyldcards-list-actions,
html.app-shell .wyldcards-list-header-actions {
    display: flex;
    flex-wrap: nowrap;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0 calc(1rem + var(--app-safe-right)) 0 calc(1rem + var(--app-safe-left));
}

/* Stack actions stay on their row rather than opening the shell's ellipsis. */
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions {
    position: static;
    z-index: auto;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    width: auto;
    max-height: none;
    overflow: visible;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
    transform: none;
    visibility: visible;
    transition: none;
}
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions::before {
    display: none;
}
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions > * {
    width: auto;
}
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions .wyldcards-list-action-btn,
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions button,
html.app-shell [data-stack-actions-inline] .wyldcards-list-actions > a {
    width: auto;
    min-height: 0;
    padding: 0.4rem 0.6rem;
}

html.app-shell .text-documents-section-actions > .app-shell-hidden,
html.app-shell .text-documents-top-actions > .app-shell-hidden,
html.app-shell .wyldcards-list-actions > .app-shell-hidden,
html.app-shell .wyldcards-list-header-actions > .app-shell-hidden,
html.app-shell .app-shell-hidden {
    display: none !important;
}

html.app-shell .text-documents-section-header,
html.app-shell .wyldcards-list-header {
    display: block;
    padding: 0;
    margin: 0;
    border: 0;
}

html.app-shell .text-documents-section-intro,
html.app-shell .wyldcards-list-header-intro {
    padding: 0 calc(1rem + var(--app-safe-right)) 0.35rem calc(1rem + var(--app-safe-left));
}

/* The bar is the top of the page now, so the page does not need a second one
   made of margin. */
html.app-shell main.wyldcards-list-page,
html.app-shell main.text-documents-page,
html.app-shell main.stack-list-page {
    padding-top: 0.5rem;
}

/* The home screen uses a semantic table for its list layout. At phone widths it
   becomes the same edge-to-edge row list as the other collections, while the
   links and bulk-selection controls stay in their existing markup. */
html.app-shell .stack-list-page .user-list-header {
    margin: 0;
    padding: 0 calc(1rem + var(--app-safe-right)) 0.5rem calc(1rem + var(--app-safe-left));
}

/* A folder's path lines up with the header under it. */
html.app-shell .stack-folder-page .stack-folder-path {
    padding: 0.5rem calc(1rem + var(--app-safe-right)) 0 calc(1rem + var(--app-safe-left));
}

html.app-shell .stack-list-page .user-list-header-text > h1 {
    display: none;
}

html.app-shell .stack-list-page .user-list-panel {
    margin: 0;
    border-top: 1px solid var(--app-hairline);
    border-bottom: 1px solid var(--app-hairline);
    border-radius: 0;
    background: var(--box-bg, var(--bg, #fff));
}

html.app-shell .stack-list-page .user-list-table,
html.app-shell .stack-list-page .user-list-table tbody,
html.app-shell .stack-list-page .user-list-table .wyldcards-list-row,
html.app-shell .stack-list-page .user-list-table .user-list-main-cell {
    display: block;
    width: 100%;
}

html.app-shell .stack-list-page .user-list-table .wyldcards-list-row {
    padding: 0.6rem calc(3.25rem + var(--app-safe-right)) 0.6rem calc(1rem + var(--app-safe-left));
}

html.app-shell .stack-list-page .user-list-table .user-list-main-cell {
    padding: 0;
}

html.app-shell .stack-list-page .user-list-table .user-list-item {
    gap: 0.75rem;
}

html.app-shell .stack-list-page .user-list-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Each list page opens with its own name in a heading beside a large mark, and
   the bar above now says the same word. The line under it — "2 wyldcards", "5
   songs" — is the part that was telling a writer something, so that stays. */
html.app-shell .wyldcards-list-header-mark,
html.app-shell .text-documents-section-mark,
html.app-shell .wyldcards-list-header-text > h1,
html.app-shell .text-documents-heading-row > h2,
html.app-shell .wyldcards-list-import-hint,
html.app-shell .text-documents-header {
    display: none;
}

/* The songs and notes lists introduce themselves with a mark, a heading, and —
   on songs — a link to read the whole script, which goes where the back chevron
   already goes. With the heading in the bar the whole strip is saying nothing
   the screen does not, and an empty strip is still thirty pixels of it.

   The breadcrumb's own bar goes with it. Matched by what is inside it so this
   reaches the two list pages and not the editor, whose `.top-bar` carries the
   File, Edit and Tools menus and has to stay. */
html.app-shell .text-documents-section-intro,
html.app-shell .top-bar:has(> .text-documents-top-actions) {
    display: none;
}

/* Search and sort share one line, the way a list's own controls do, instead of
   being two full-width blocks between the writer and their songs. */
html.app-shell .wyldcards-list-toolbar,
html.app-shell .text-documents-toolbar {
    display: flex;
    /* The wyldcards toolbar stacks its two controls in a column at this width
       and the songs one wraps; either way the sort control ends up on a line of
       its own under a full-width search field, which is two rows of chrome for
       one row's worth of controls. */
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem calc(1rem + var(--app-safe-right)) 0.5rem calc(1rem + var(--app-safe-left));
}

/* Making a folder is a thing you do occasionally, not a full-width button
   standing between the toolbar and the first row. */
html.app-shell .wyldcards-list-folder-new,
html.app-shell .text-document-folder-new {
    justify-content: flex-start;
    padding: 0 calc(1rem + var(--app-safe-right)) 0.5rem calc(1rem + var(--app-safe-left));
}

html.app-shell .wyldcards-list-folder-new > *,
html.app-shell .text-document-folder-new > * {
    flex: 0 0 auto;
    width: auto;
}

html.app-shell .text-documents-search-wrap,
html.app-shell .wyldcards-list-search-wrap {
    flex: 1 1 auto;
    min-width: 0;
    max-width: none;
    padding: 0;
}

html.app-shell .wyldcards-list-toolbar-actions {
    flex: 0 0 auto;
    width: auto;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0;
}

html.app-shell .wyldcards-list-sort {
    max-width: 8rem;
}

/* "Edit all on one page" is the songs list's second way in, and a good one —
   but it is not what a thumb is reaching for above the list, so it waits in
   the "..." with the rest of the toolbar. */
html.app-shell .wyldcards-list-toolbar-actions > .wyldcards-list-action-btn {
    display: none;
}

/* Select all, and the bar of things to do with what is selected, belong to the
   mode rather than to the page. */
html.app-shell .wyldcards-list-bulkbar,
html.app-shell .text-documents-select-all,
html.app-shell .wyldcards-list-select-checkbox,
html.app-shell .text-document-select-checkbox {
    display: none;
}

html.app-shell body.app-selecting .wyldcards-list-bulkbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem calc(1rem + var(--app-safe-right)) 0.5rem calc(1rem + var(--app-safe-left));
}

html.app-shell body.app-selecting .text-documents-select-all {
    display: inline-flex;
}

html.app-shell body.app-selecting .wyldcards-list-select-checkbox,
html.app-shell body.app-selecting .text-document-select-checkbox {
    display: block;
    width: 1.375rem;
    height: 1.375rem;
    flex: 0 0 auto;
}

html.app-shell .text-documents-search-wrap input,
html.app-shell .wyldcards-list-search-wrap input,
html.app-shell input[type="search"] {
    width: 100%;
    min-height: 2.25rem;
    border-radius: 0.625rem;
    /* Under 16px iOS zooms the page in on focus and never zooms back out. */
    font-size: 1rem;
}

/* ---------------------------------------------------------------------------
   Dialogs and menus as sheets
   ------------------------------------------------------------------------ */

html.app-shell .confirm-modal[hidden] {
    display: none;
}

html.app-shell .confirm-modal {
    position: fixed;
    inset: 0;
    z-index: 1700;
    display: flex;
    align-items: flex-end;
    justify-content: stretch;
    padding: 0;
    background: var(--app-scrim);
}

html.app-shell .confirm-modal-panel {
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 1.25rem calc(1.25rem + var(--app-safe-right))
             calc(1.25rem + var(--app-safe-bottom)) calc(1.25rem + var(--app-safe-left));
    box-sizing: border-box;
    font-family: var(--app-ui-font);
    border-radius: 0.875rem 0.875rem 0 0;
    animation: app-sheet-rise 0.28s cubic-bezier(0.32, 0.72, 0, 1) both;
}

html.app-shell .confirm-modal-actions {
    display: flex;
    flex-direction: column-reverse;
    gap: 0.5rem;
}

html.app-shell .confirm-modal-actions button {
    width: 100%;
    min-height: 2.875rem;
    border-radius: 0.75rem;
    font-size: 1.0625rem;
}

/* The header menus — account, help, the export lists — keep their own
   open/closed handling in nav-dropdowns.js; only where they are drawn changes.
   They are not popovers, because that handling is not this file's to take over,
   so they sit above the tab bar on z-index instead of in the top layer. */
html.app-shell .header-actions .nav-dropdown-menu,
html.app-shell .nav-dropdown-menu {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1750;
    width: auto;
    min-width: 0;
    max-width: none;
    max-height: 70vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0.75rem calc(0.75rem + var(--app-safe-right))
             calc(0.75rem + var(--app-safe-bottom)) calc(0.75rem + var(--app-safe-left));
    box-sizing: border-box;
    font-family: var(--app-ui-font);
    border: 0;
    border-radius: 0.875rem 0.875rem 0 0;
    box-shadow: 0 -8px 40px -12px color-mix(in srgb, #000 55%, transparent);
    transform: none;
}

/* The editor's own menus — File, Edit, Version, Tools, Writing — are pinned
   under their buttons by a rule four classes deep, which outranks the one above
   and left them as narrow panels stuck to the left edge. Matched at the same
   depth so they are sheets like the rest. */
html.app-shell .wyldcards-tools-group .tools-dropdown .nav-dropdown-menu {
    left: 0;
    right: 0;
    width: auto;
    min-width: 0;
    transform: none;
}

/* A sheet comes up from the bottom of the screen, which is where the sprint's
   clock floats. The clock is a readout and the sheet is being read, so the
   clock stands down for as long as one is up — and the sprint's own controls
   are in that sheet anyway. */
html.app-shell body:has(.nav-dropdown.open) .writing-sprint-strip,
html.app-shell body:has([popover]:popover-open) .writing-sprint-strip,
html.app-shell body:has(.app-sheet-open) .writing-sprint-strip {
    display: none;
}

/* The dimming behind one, which the sheets above get from their backdrop. No
   script needed for it: a menu being open is a class on the page. */
html.app-shell body:has(.nav-dropdown.open)::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1740;
    background: rgba(0, 0, 0, 0.4);
}

html.app-shell .nav-dropdown.open .nav-dropdown-menu::before {
    content: "";
    display: block;
    width: 2.25rem;
    height: 0.3125rem;
    margin: 0 auto 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--fg, #000) 22%, transparent);
}

html.app-shell .nav-dropdown.open .nav-dropdown-menu {
    animation: app-sheet-rise 0.28s cubic-bezier(0.32, 0.72, 0, 1) both;
}

html.app-shell .nav-dropdown-item {
    min-height: 2.875rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0 0.5rem;
    border-radius: 0.5rem;
    font-size: 1.0625rem;
}

html.app-shell .nav-dropdown-item:active {
    background: var(--app-press);
}

/* Help feature finder rows on the sheet: two lines, left-aligned like the
   rest of the sheet, sized for touch. */
html.app-shell .help-feature-search-results .help-feature-result {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.15rem;
    padding: 0.45rem 0.5rem;
}

html.app-shell .help-feature-result-title {
    font-size: 1rem;
}

html.app-shell .help-feature-result-desc {
    font-size: 0.8125rem;
}

html.app-shell .help-feature-group-label {
    margin-left: 0.5rem;
    font-size: 0.72rem;
}

html.app-shell .help-feature-search-more {
    font-size: 0.9375rem;
}

/* A keyboard hint on a device with no keyboard. */
html.app-shell .nav-dropdown-shortcut {
    display: none;
}

@keyframes app-sheet-rise {
    from { transform: translateY(101%); }
    to   { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    html.app-shell .text-document-card-actions,
    html.app-shell .wyldcards-list-actions,
    html.app-shell .app-sheet-source,
    html.app-shell .app-scrim {
        transition-duration: 0.01ms;
    }

    html.app-shell .confirm-modal-panel,
    html.app-shell .nav-dropdown.open .nav-dropdown-menu {
        animation-duration: 0.01ms;
    }
}

/* ---------------------------------------------------------------------------
   The landing page
   ------------------------------------------------------------------------ */

/* The public page is often a person's first phone interaction with the app.
   Keep its path into the product one-handed: account creation leads, sign-in
   remains an equally large target, and help does not compete with either. */
html.app-shell body.landing-body .landing-hero {
    padding-right: calc(1rem + var(--app-safe-right));
    padding-left: calc(1rem + var(--app-safe-left));
}

html.app-shell body.landing-body .landing-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
}

html.app-shell body.landing-body .landing-cta-primary,
html.app-shell body.landing-body .landing-cta-secondary {
    width: 100%;
    min-height: 3.25rem;
    box-sizing: border-box;
}

/* ---------------------------------------------------------------------------
   The editor
   ------------------------------------------------------------------------ */

/* A song being written wants the whole screen. The tab bar goes — there is a
   back chevron for leaving — and the bar above stays, because that chevron is
   the way out and the editor's own menus hang off it. */
html.app-shell body.app-shell-editor {
    padding-bottom: var(--app-safe-bottom);
}

html.app-shell body.app-shell-editor .app-tabs {
    display: none;
}

/* Lyric lines are the content, so they keep the site's typeface and its text
   scaling; what changes is that a line is not wrapped in mouse furniture. */
html.app-shell .song-block-controls {
    opacity: 1;
}

html.app-shell .song-block-row textarea,
html.app-shell .text-document-editor textarea {
    font-size: max(1rem, calc(1rem * var(--wyldcards-text-scale, 1)));
}

/* The card workspace keeps its own compact navigation. Its desktop layout
   reserves space for the floating header controls, which the app bar replaces
   on a phone; remove that empty strip and make its dense actions scroll within
   the toolbar instead of widening the page. */
html.app-shell main.wyldcards-card-page .wyldcards-toolbar {
    gap: 0.35rem;
    min-height: 3.25rem;
    padding: 0.4rem calc(0.5rem + var(--app-safe-right)) 0.4rem calc(0.5rem + var(--app-safe-left));
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

html.app-shell main.wyldcards-card-page .wyldcards-toolbar::-webkit-scrollbar {
    display: none;
}

/* The toolbar scrolls sideways, which clips anything hung below it, so its
   menus open as a sheet pinned under the toolbar (nav-dropdowns.js sets the top). */
html.app-shell main.wyldcards-card-page .wyldcards-toolbar .nav-dropdown-menu {
    position: fixed;
    top: var(--card-toolbar-menu-top, 6rem);
    right: calc(0.5rem + var(--app-safe-right));
    left: calc(0.5rem + var(--app-safe-left));
    min-width: 0;
    max-width: none;
    max-height: calc(100dvh - var(--card-toolbar-menu-top, 6rem) - 6rem);
    overflow-y: auto;
}

html.app-shell main.wyldcards-card-page .wyldcards-toolbar .nav-dropdown-item {
    min-height: 2.75rem;
}

html.app-shell main.wyldcards-card-page .wyldcards-toolbar-group {
    flex: 0 0 auto;
    gap: 0.35rem;
}

/* The actions group was wider than a phone, so New card and Edit sat past the
   edge where only a sideways swipe found them. Let it wrap to a second row, and
   drop the last-edited line so the card arrows share the first row with Stacks. */
html.app-shell main.wyldcards-card-page .wyldcards-toolbar-right {
    flex: 1 1 auto;
    min-width: 0;
    flex-wrap: wrap;
}

html.app-shell main.wyldcards-card-page .wyldcards-last-edited-line {
    display: none;
}

html.app-shell main.wyldcards-card-page .wyldcards-toolbar-arrow,
html.app-shell main.wyldcards-card-page .wyldcards-toolbar-link,
html.app-shell main.wyldcards-card-page .wyldcards-toolbar-mode {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem;
}

html.app-shell main.wyldcards-card-page .wyldcards-jump-history-control[disabled] {
    display: none;
}

/* ---------------------------------------------------------------------------
   Data grid and card discussions
   ------------------------------------------------------------------------ */

/* A spreadsheet needs its own scroll surface on a phone. Using the dynamic
   viewport keeps the final rows above the home indicator after browser chrome
   expands or collapses. */
html.app-shell .data-workspace {
    padding-right: 0;
    padding-left: 0;
}

html.app-shell .data-workspace-header {
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem calc(1rem + var(--app-safe-right)) 0.6rem calc(1rem + var(--app-safe-left));
}

html.app-shell .data-workspace-header h1 {
    display: block;
    margin: 0.2rem 0 0;
    font-size: 1.125rem;
}

html.app-shell .data-workspace-add {
    flex: 0 0 auto;
    min-height: 2.75rem;
    white-space: nowrap;
}

html.app-shell .data-workspace-viewbar {
    gap: 0.5rem;
    padding: 0.6rem calc(1rem + var(--app-safe-right)) 0.6rem calc(1rem + var(--app-safe-left));
}

html.app-shell .data-workspace-view-picker {
    width: 100%;
}

html.app-shell .data-workspace-view-picker label {
    flex: 1 1 auto;
}

html.app-shell .data-workspace-view-picker select {
    min-height: 2.5rem;
    font-size: 1rem;
}

html.app-shell .data-workspace-options {
    flex: 1 1 auto;
}

html.app-shell .data-workspace-options summary {
    display: flex;
    align-items: center;
    min-height: 2.5rem;
    padding: 0 0.5rem;
    font-size: 0.9375rem;
}

html.app-shell .data-workspace-options form {
    left: calc(-0.5rem - var(--app-safe-left));
    right: calc(-0.5rem - var(--app-safe-right));
    width: auto;
    max-width: none;
}

html.app-shell .data-workspace-grid .table-scroll {
    max-height: calc(100dvh - var(--app-bar-height) - var(--app-tab-height) - var(--app-safe-top) - var(--app-safe-bottom) - 12rem);
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

html.app-shell .data-workspace-table {
    min-width: 38rem;
}

html.app-shell .data-workspace-table td {
    min-width: 8.5rem;
}

html.app-shell .data-workspace-primary {
    min-width: 12rem !important;
}

html.app-shell .wyldcards-card-comments {
    margin: 0.75rem calc(0.75rem + var(--app-safe-right)) 0.75rem calc(0.75rem + var(--app-safe-left));
}

html.app-shell .wyldcards-card-comments-details {
    padding: 0.625rem;
}

html.app-shell .wyldcards-card-comments-details[open] > .wyldcards-comments-close {
    top: 0.625rem;
    right: 0.625rem;
    min-height: 2rem;
}

html.app-shell .wyldcards-comment > header {
    flex-wrap: wrap;
    gap: 0.3rem 0.6rem;
}

html.app-shell .wyldcards-comment-delete {
    min-height: 2.5rem;
    padding: 0.35rem 0.2rem;
}

html.app-shell .wyldcards-comment-form textarea {
    min-height: 3.25rem;
    font-size: 1rem;
}

html.app-shell .wyldcards-comment-form button {
    width: 100%;
    min-height: 2.5rem;
}

@media (max-width: 25rem) {
    html.app-shell .data-workspace-header {
        flex-direction: column;
    }

    html.app-shell .data-workspace-header form,
    html.app-shell .data-workspace-add {
        width: 100%;
    }
}

/* ---------------------------------------------------------------------------
   Search results
   ------------------------------------------------------------------------ */

/* The list rows stack their parts in a column on a phone, which put a result's
   card number, its text and its chevron on three lines of their own — a
   screenful held four results. Keep them on one line, as the card list does. */
html.app-shell .stack-list-page .user-list-table .wyldcards-find-hit-link {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
}

html.app-shell .wyldcards-find-hit-link .user-list-info,
html.app-shell .wyldcards-find-hit-link .user-list-meta {
    flex: 1 1 auto;
    min-width: 0;
}

html.app-shell .wyldcards-find-hit-link .wyldcards-card-list-number {
    flex: none;
    width: auto;
    min-width: 1.25rem;
}

/* Two lines rather than one, so the highlighted words are not the part cut. */
html.app-shell .wyldcards-find-hit-snippet {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* The search box and its hint ran into both edges of the screen. */
html.app-shell .wyldcards-search-form,
html.app-shell .wyldcards-search-hint {
    box-sizing: border-box;
    padding-inline: calc(1rem + var(--app-safe-left)) calc(1rem + var(--app-safe-right));
}
