/*
    Link Adder - the signed-in app.

    css/app.css and the surviving rules from css/style.css, in one file. The
    old style.css positioned floating action buttons that the rail replaced,
    and styled a .box tile that had no width - both are gone.
*/

/*
    Link Adder - the signed-in app.
    ---------------------------------------------------------------------------
    The organizing idea is a card catalog. Every list already carries a color in
    the database, so that color, not an invented brand accent, is the accent
    everywhere: it runs down the left edge of a card as a spine, the way a
    colored tab runs down a file folder. One list, one color, followed
    consistently from the lists grid into the list itself and on into the
    browser start page.

    Light mode only, on purpose. This is a tool people keep open next to their
    work, and it should read like paper rather than a dashboard.
*/

:root {
    --paper:      #fbfcfd;
    --card:       #ffffff;
    --ink:        #15202b;
    --ink-soft:   #5b6b7c;
    --ink-faint:  #93a1b0;
    --rule:       #e3e9ef;
    --rule-soft:  #eef2f6;

    --shadow:      0 1px 2px rgba(21, 32, 43, .05);
    --shadow-lift: 0 10px 28px rgba(21, 32, 43, .11), 0 2px 6px rgba(21, 32, 43, .06);

    --display: "Archivo", "Roboto Condensed", system-ui, sans-serif;
    --body:    "Source Sans 3", system-ui, -apple-system, "Segoe UI", sans-serif;
    --mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    /* falls back to a neutral when a list has no color of its own */
    --accent: #5b6b7c;

    --spine: 5px;
}

/* ------------------------------------------------------------------ shell */

body.la-app {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--body);
    font-size: 16px;
    line-height: 1.55;
}

.la-wrap {
    max-width: 1240px;
    margin: 0 auto;
    padding: 24px 28px 96px;
}

/* Section heading. The rule runs the full width and the label sits on it,
   like the tab on a divider card. */
.la-head {
    display: flex;
    /* center, not baseline: this row mixes an icon, a heading and a 36px
       input, and aligning those on a text baseline sits the input low and
       reads as crowded. */
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 16px;
    margin: 0 0 24px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--rule);
}

/* The title and its count belong together; everything else can wrap away. */
.la-head h1 + .la-count { margin-left: -8px; }

.la-head h1 {
    margin: 0;
    font-family: var(--display);
    font-size: 21px;
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--ink);
}

.la-head .la-count {
    font-family: var(--mono);
    font-size: 12px;
    color: var(--ink-faint);
    letter-spacing: .02em;
}

.la-head .la-spacer { flex: 1; }

/* --------------------------------------------------------------- controls */

.la-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 36px;
    padding: 0 15px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--body);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: border-color .12s, box-shadow .12s, transform .12s;
}

.la-btn:hover {
    color: var(--ink);
    border-color: var(--ink-faint);
    box-shadow: var(--shadow-lift);
    transform: translateY(-1px);
}

.la-btn:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}

.la-btn-primary {
    background: var(--ink);
    border-color: var(--ink);
    /*  Not #fff. --ink is the text color, so on a dark theme it is a light
        grey and white on top of it is unreadable. --paper is whatever the page
        is, so the pair inverts correctly either way round. */
    color: var(--paper);
}

.la-btn-primary:hover { color: var(--paper); }

.la-btn svg { width: 16px; height: 16px; }

.la-search {
    position: relative;
    flex: 1 1 220px;
    min-width: 180px;
    max-width: 340px;
}

.la-search input {
    width: 100%;
    height: 36px;
    padding: 0 13px 0 34px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--body);
    font-size: 14px;
    outline: none;
}

.la-search input:focus {
    border-color: var(--ink-faint);
    box-shadow: 0 0 0 3px rgba(91, 107, 124, .12);
}

.la-search svg {
    position: absolute;
    left: 10px;
    top: 10px;
    width: 16px;
    height: 16px;
    color: var(--ink-faint);
    pointer-events: none;
}

/* ------------------------------------------------------------ lists grid */

.la-lists {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
    gap: 16px;
}

/* The spine is the signature: a solid bar of the list's own color down the
   left edge, with the card body sitting flush against it. */
.la-list {
    position: relative;
    display: block;
    padding: 20px 20px 16px calc(20px + var(--spine));
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--card);
    box-shadow: var(--shadow);
    color: var(--ink);
    text-decoration: none;
    overflow: hidden;
    transition: box-shadow .14s, transform .14s, border-color .14s;
}

.la-list::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: var(--spine);
    background: var(--accent);
}

.la-list:hover {
    color: var(--ink);
    transform: translateY(-2px);
    border-color: var(--ink-faint);
    box-shadow: var(--shadow-lift);
}

.la-list:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.la-list-top {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 3px;
}

.la-list-top .la-type {
    display: inline-flex;
    color: var(--accent);
}

.la-list-top .la-type svg { width: 17px; height: 17px; }

.la-list h2 {
    flex: 1;
    margin: 0;
    font-family: var(--display);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.la-list .la-n {
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-faint);
    white-space: nowrap;
}

.la-list p {
    margin: 0 0 14px;
    font-size: 14px;
    color: var(--ink-soft);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.9em;
}

/* A peek at what is inside: the favicons of the most recent few links. */
.la-peek {
    display: flex;
    align-items: center;
    gap: 5px;
    padding-top: 12px;
    border-top: 1px solid var(--rule-soft);
}

.la-peek img {
    width: 18px;
    height: 18px;
    border-radius: 4px;
    object-fit: contain;
    background: var(--rule-soft);
}

.la-peek .la-more {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-faint);
    margin-left: 2px;
}

.la-peek .la-peek-empty {
    font-size: 13px;
    color: var(--ink-faint);
}

/* ------------------------------------------------------------- link tiles */

.la-links {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(214px, 1fr));
    gap: 16px;
}

.la-link {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--card);
    box-shadow: var(--shadow);
    color: var(--ink);
    text-decoration: none;
    overflow: hidden;
    transition: box-shadow .14s, transform .14s, border-color .14s;
}

.la-link:hover {
    color: var(--ink);
    transform: translateY(-2px);
    border-color: var(--ink-faint);
    box-shadow: var(--shadow-lift);
}

.la-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The preview. When a link has no image the tile shows its initial on a wash
   of the list color, which keeps a wall of tiles legible rather than blank. */
.la-shot {
    position: relative;
    aspect-ratio: 16 / 10;
    background: var(--rule-soft);
    overflow: hidden;
}

.la-shot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.la-shot .la-initial {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent);
    color: #fff;
    font-family: var(--display);
    font-size: 34px;
    font-weight: 700;
    opacity: .92;
}

/* The label strip, where the card's identity lives. */
.la-label {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 12px 12px;
    border-top: 1px solid var(--rule-soft);
}

.la-label img.la-fav {
    width: 16px;
    height: 16px;
    margin-top: 2px;
    border-radius: 4px;
    object-fit: contain;
    flex: none;
}

.la-label .la-text { min-width: 0; flex: 1; }

.la-label strong {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-family: var(--body);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
}

/* Scoped to the hostname, not to every span in the label. .la-text is itself
   a span, so the bare selector handed the wrapper white-space: nowrap and the
   title could never wrap to its second line - it just clipped. */
.la-label .la-hostname {
    display: block;
    margin-top: 2px;
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.la-label .la-text {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* --------------------------------------------------------------- feedback */

.la-empty {
    max-width: 460px;
    margin: 72px auto;
    text-align: center;
}

.la-empty h2 {
    margin: 0 0 8px;
    font-family: var(--display);
    font-size: 19px;
    font-weight: 700;
}

.la-empty p {
    margin: 0 0 18px;
    color: var(--ink-soft);
}

.la-badge {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--rule-soft);
    color: var(--ink-soft);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .02em;
}

.la-badge-warn { background: #fdf0e6; color: #9a5423; }

@media (max-width: 640px) {
    .la-wrap { padding: 8px 16px 80px; }
    .la-head { flex-wrap: wrap; }
    .la-links { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
    .la-list, .la-link, .la-btn { transition: none; }
    .la-list:hover, .la-link:hover, .la-btn:hover { transform: none; }
}

/* ------------------------------------------------- tile overlay + editing */

/* The whole card is the link. The pencil and the editor sit above that
   overlay so they stay clickable. */
.la-link { position: relative; }

.la-open {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: 10px;
}

.la-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.la-head .la-type { display: inline-flex; color: var(--accent); }
.la-head .la-type svg { width: 20px; height: 20px; }

.la-purpose {
    margin: -8px 0 20px;
    max-width: 62ch;
    color: var(--ink-soft);
}

.la-label .la-note {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-top: 5px;
    font-family: var(--body);
    font-size: 12.5px;
    font-style: normal;
    line-height: 1.4;
    color: var(--ink-soft);
}

/*  A todo row is a single line, so the dial's actions fan out past the bottom
    of it and the card's overflow clips them off. That clipping is there to keep
    a tile's picture inside its rounded corners, and a todo row has no picture,
    so it is the one case that can let them out.

    Raised while open so the actions sit above the rows underneath rather than
    behind them, since a later grid item paints over an earlier one. */
.la-links.is-todos .la-link { overflow: visible; }
.la-links.is-todos .la-link:has(.la-dial.is-open) { z-index: 5; }

/* ------------------------------------------------------------- speed dial */

/*  One button on the tile that opens the two things you can do to a link.
    Hidden until the tile is hovered, so a wall of tiles stays a wall of
    pictures rather than a wall of controls. */
.la-dial {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.la-dial-toggle,
.la-dial-item {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--rule);
    border-radius: 50%;
    background: rgba(255, 255, 255, .96);
    color: var(--ink-soft);
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: color .12s, background .12s, border-color .12s;
}

.la-dial-toggle svg { width: 15px; height: 15px; }
.la-dial-item svg { width: 14px; height: 14px; }

.la-dial-toggle { opacity: 0; transition: opacity .12s; }

.la-link:hover .la-dial-toggle,
.la-link:focus-within .la-dial-toggle,
.la-dial.is-open .la-dial-toggle { opacity: 1; }

.la-dial-toggle:hover { color: var(--ink); border-color: var(--ink-faint); }
.la-dial-toggle:focus-visible { opacity: 1; outline: 2px solid var(--ink); outline-offset: 2px; }

.la-dial.is-open .la-dial-toggle { color: var(--ink); border-color: var(--ink-faint); }

/*  The actions fan out below the toggle. They are laid out even when closed so
    the open transition has somewhere to travel from. */
.la-dial-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    opacity: 0;
    transform: translateY(-6px) scale(.9);
    pointer-events: none;
    transition: opacity .13s ease, transform .13s ease;
}

.la-dial.is-open .la-dial-actions {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

/*  Each action names itself on hover rather than carrying a permanent label,
    which is what keeps the dial small. */
.la-dial-item { position: relative; }

.la-dial-item::after {
    content: attr(data-label);
    position: absolute;
    right: calc(100% + 8px);
    top: 50%;
    transform: translateY(-50%);
    padding: 3px 8px;
    border-radius: 6px;
    background: var(--ink);
    color: var(--paper);
    font-family: var(--body);
    font-size: 11.5px;
    font-weight: 600;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity .12s;
}

.la-dial-item:hover::after,
.la-dial-item:focus-visible::after { opacity: 1; }

.la-dial-item:hover { color: var(--ink); border-color: var(--ink-faint); }
.la-dial-item:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-trash:hover { color: #fff; background: #c0392b; border-color: #c0392b; }
.la-restore:hover { color: var(--paper); background: var(--accent); border-color: var(--accent); }

.la-link.is-editing {
    border-color: var(--accent);
    box-shadow: var(--shadow-lift);
    transform: none;
}

.la-editor {
    position: relative;
    z-index: 2;
    padding: 12px;
    border-top: 1px solid var(--rule);
    background: var(--rule-soft);
}

.la-editor label {
    display: block;
    margin-bottom: 9px;
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-editor input,
.la-editor textarea {
    display: block;
    width: 100%;
    margin-top: 4px;
    padding: 7px 9px;
    border: 1px solid var(--rule);
    border-radius: 7px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--body);
    font-size: 13.5px;
    line-height: 1.45;
    resize: vertical;
    outline: none;
    text-transform: none;
    letter-spacing: normal;
}

.la-editor input:focus,
.la-editor textarea:focus { border-color: var(--accent); }

.la-editor-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.la-editor-actions .la-btn { height: 30px; padding: 0 12px; font-size: 13px; }

.la-del {
    font-size: 13px;
    font-weight: 600;
    color: #b4232a;
    text-decoration: none;
}

.la-del:hover { color: #8d1a20; text-decoration: underline; }

/* Feather swaps the placeholder span for an <svg>, which the floating buttons
   rely on. Keep those off the new pages rather than restyling them. */
.la-app .btn-feather { display: none; }

/* ------------------------------------------------------- prose + forms */

.la-doc { max-width: 760px; }

.la-lede {
    margin: 0 0 32px;
    font-size: 18px;
    line-height: 1.6;
    color: var(--ink-soft);
}

/* Each step is a card-catalog entry: a rule above it, the heading sitting on
   that rule. No numbers, because these are things that are true at once
   rather than an order you must follow. */
.la-step {
    padding-top: 22px;
    margin-bottom: 26px;
    border-top: 1px solid var(--rule);
}

.la-step h2 {
    margin: 0 0 8px;
    font-family: var(--display);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -.01em;
}

.la-step p {
    margin: 0 0 10px;
    max-width: 64ch;
    color: var(--ink-soft);
}

.la-step strong { color: var(--ink); }
.la-step em { font-style: normal; color: var(--ink); }

.la-step kbd {
    padding: 1px 6px;
    border: 1px solid var(--rule);
    border-radius: 5px;
    background: var(--card);
    font-family: var(--mono);
    font-size: 12px;
    color: var(--ink);
}

.la-cta {
    display: flex;
    gap: 10px;
    padding-top: 26px;
    border-top: 1px solid var(--rule);
}

.la-form { max-width: 560px; }

.la-form label {
    display: block;
    margin-bottom: 18px;
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-form input,
.la-form textarea {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 10px 12px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--body);
    font-size: 15px;
    line-height: 1.5;
    text-transform: none;
    letter-spacing: normal;
    outline: none;
    resize: vertical;
}

.la-form input:focus,
.la-form textarea:focus {
    border-color: var(--ink-faint);
    box-shadow: 0 0 0 3px rgba(91, 107, 124, .12);
}

.la-problem {
    padding: 11px 14px;
    margin-bottom: 20px;
    border: 1px solid #f0cfb4;
    border-left: 4px solid #d1793a;
    border-radius: 8px;
    background: #fdf5ee;
    color: #8a4a1c;
    font-size: 14px;
}

/* =========================================================== a list's page */

/*  Full width, with the lists rail on the right. The rail is where links get
    filed, so it sits beside the tiles rather than across the page from them. */
/*  The rail sits on the left. It is both the navigation and the place links
    get filed, and reading order puts navigation first. The markup still has
    main before aside, so a screen reader and a keyboard reach the content
    first; only the columns are swapped. */
.la-page {
    display: grid;
    grid-template-columns: 268px minmax(0, 1fr);
    gap: 28px;
    padding: 24px 28px 96px;
    align-items: start;
}

.la-page .la-main { grid-column: 2; grid-row: 1; }
.la-page .la-side { grid-column: 1; grid-row: 1; }

.la-main { min-width: 0; }

/*  A real sidebar, not a card that happens to be sticky.

    The old one was position:sticky with a top offset, which behaves fine until
    the list of lists is taller than the window - then it stops being sticky at
    all and you have to scroll to the very bottom of a page of 200 tiles before
    it comes back. It is its own full-height column now, and the list inside it
    scrolls on its own. */
.la-side {
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    padding: 18px 14px 14px;
    border-right: 1px solid var(--rule);
    background: var(--card);
}

.la-brand {
    display: block;
    padding: 2px 6px 16px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--rule);
}

.la-brand img { display: block; height: 28px; width: auto; }

.la-side h2 {
    margin: 0 0 3px;
    font-family: var(--display);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-side-hint {
    margin: 0 0 14px;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--ink-faint);
}

/*  The only part that scrolls, so the logo and the buttons stay put. */
.la-side-list {
    display: grid;
    gap: 3px;
    align-content: start;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: 4px;
    margin-right: -4px;
}

/*  A scrollbar in the theme's own colors. Firefox takes the two-value form;
    WebKit needs the pseudo-elements. Both are given so neither browser falls
    back to a default bar that ignores the theme. */
.la-side-list {
    scrollbar-width: thin;
    scrollbar-color: var(--rule) transparent;
}

.la-side-list::-webkit-scrollbar { width: 8px; }
.la-side-list::-webkit-scrollbar-track { background: transparent; }

.la-side-list::-webkit-scrollbar-thumb {
    background: var(--rule);
    border-radius: 999px;
    border: 2px solid var(--card);
}

.la-side-list:hover::-webkit-scrollbar-thumb { background: var(--ink-faint); }

.la-side-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px 9px 12px;
    border-radius: 8px;
    color: var(--ink-soft);
    text-decoration: none;
    font-size: 14px;
    font-weight: 600;
    border: 1px solid transparent;
}

/* The spine again, this time as a stub against the left edge of the row. */
.la-side-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--accent);
    opacity: 0;
}

.la-side-item:hover { background: var(--rule-soft); color: var(--ink); }
.la-side-item:hover::before { opacity: .5; }

.la-side-item.is-here {
    background: var(--rule-soft);
    color: var(--ink);
}

.la-side-item.is-here::before { opacity: 1; }

.la-side-item:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-side-type { display: inline-flex; color: var(--accent); flex: none; }
.la-side-type svg { width: 15px; height: 15px; }

.la-side-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.la-side-n {
    font-family: var(--mono);
    font-size: 11.5px;
    font-weight: 500;
    color: var(--ink-faint);
}

/* While a tile is in flight every list becomes visibly a destination. */
body.la-dragging .la-side-item:not(.is-here) {
    border-color: var(--rule);
    background: var(--card);
}

.la-side-item.is-over {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.la-side-item.is-over .la-side-type,
.la-side-item.is-over .la-side-n { color: var(--paper); }
.la-side-item.is-over::before { opacity: 0; }

.la-side-add {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    width: 100%;
    margin-top: 12px;
    padding: 9px 12px;
    border: 1px dashed var(--rule);
    border-radius: 8px;
    background: transparent;
    color: var(--ink-soft);
    font-family: var(--body);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
}

.la-side-add svg { width: 15px; height: 15px; }
.la-side-add:hover { border-color: var(--ink-faint); color: var(--ink); background: var(--rule-soft); }
.la-side-add:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ------------------------------------------------------------ drag states */

.la-link[draggable="true"] { cursor: grab; }
.la-link.is-dragging { opacity: .45; cursor: grabbing; }
.la-link.is-leaving { opacity: .3; pointer-events: none; }

/* A dragged tile must not be intercepted by its own overlay link. */
body.la-dragging .la-open { pointer-events: none; }

.la-toast {
    position: fixed;
    left: 50%;
    bottom: 26px;
    transform: translateX(-50%);
    padding: 9px 17px;
    border-radius: 999px;
    background: var(--ink);
    color: var(--paper);
    font-size: 13.5px;
    box-shadow: var(--shadow-lift);
    z-index: 50;
}

@media (max-width: 1000px) {
    /* The rail becomes a row above the tiles rather than a squeezed column.
       Drag still works; it is simply a shorter distance. */
    .la-page {
        grid-template-columns: minmax(0, 1fr);
        gap: 20px;
        padding: 8px 16px 80px;
    }
    .la-side { position: static; order: -1; }
    .la-side-list { grid-auto-flow: column; grid-auto-columns: minmax(150px, 1fr); overflow-x: auto; }
    .la-side-hint { display: none; }
}

/* ----------------------------------------------------------- recycle bin */

.la-side-item.is-bin {
    margin-top: 8px;
    padding-top: 13px;
    border-top: 1px solid var(--rule);
    border-radius: 0 0 8px 8px;
}

.la-side-item.is-bin::before { top: 13px; }

.la-side-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    width: 100%;
    margin-top: 12px;
    padding: 9px 12px;
    border: 1px solid #f0cfcf;
    border-radius: 8px;
    background: #fdf3f3;
    color: #a8322a;
    font-family: var(--body);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
}

.la-side-empty svg { width: 15px; height: 15px; }
.la-side-empty:hover { background: #fbe8e8; border-color: #e0a9a9; }
.la-side-empty:focus-visible { outline: 2px solid #a8322a; outline-offset: 2px; }

.la-btn-danger {
    background: #c0392b;
    border-color: #c0392b;
    color: #fff;
}

.la-btn-danger:hover { background: #a8322a; border-color: #a8322a; color: #fff; }
.la-btn-danger:disabled { opacity: .45; cursor: default; transform: none; box-shadow: var(--shadow); }

/* ------------------------------------------------------ confirm dialog */

.la-confirm {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(21, 32, 43, .45);
}

.la-confirm-box {
    width: 100%;
    max-width: 420px;
    padding: 24px;
    border-radius: 14px;
    background: var(--card);
    box-shadow: var(--shadow-lift);
}

.la-confirm-box h2 {
    margin: 0 0 8px;
    font-family: var(--display);
    font-size: 18px;
    font-weight: 700;
}

.la-confirm-box p {
    margin: 0 0 18px;
    color: var(--ink-soft);
    font-size: 14.5px;
}

.la-confirm-box label {
    display: block;
    margin-bottom: 20px;
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-confirm-box code {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--ink);
    background: var(--rule-soft);
    padding: 1px 5px;
    border-radius: 4px;
}

.la-confirm-box input {
    display: block;
    width: 100%;
    margin-top: 8px;
    padding: 10px 12px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 14px;
    letter-spacing: .02em;
    text-transform: none;
    outline: none;
}

.la-confirm-box input:focus { border-color: #c0392b; box-shadow: 0 0 0 3px rgba(192, 57, 43, .14); }

/* --------------------------------------------------------- uploading */

.la-upload:hover { color: #fff; background: var(--accent); border-color: var(--accent); }

/*  While a picture is on its way the tile says so, because a Cloudinary round
    trip is long enough that a silent tile reads as a dead button. */
.la-link.is-uploading { pointer-events: none; }

.la-link.is-uploading .la-shot::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, .72);
}

.la-link.is-uploading .la-shot::before {
    content: "";
    position: absolute;
    z-index: 1;
    top: 50%;
    left: 50%;
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
    border: 2px solid var(--rule);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: la-spin .7s linear infinite;
}

@keyframes la-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .la-link.is-uploading .la-shot::before { animation: none; }
}

/* =============================================== list types beyond bookmarks */

/*  A list's type changes what a tile is. The page around it - rail, search,
    dial, drag, bin - is the same everywhere, so only these rules differ. */

/* ------------------------------------------------------------------ gallery */

/*  The pictures are the content. No title, no host, no favicon: a bigger tile,
    a squarer crop, and less gap so the images sit together as a wall rather
    than as a row of cards that happen to contain images. */
.la-is-gallery .la-links {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
}

.la-is-gallery .la-shot { aspect-ratio: 4 / 3; }

.la-is-gallery .la-link {
    border-radius: 12px;
}

.la-is-gallery .la-initial { font-size: 46px; }

/* ------------------------------------------------------------------- to-dos */

/*  A to-do list is lines, not tiles: one column, full width, so a long title
    and its notes have somewhere to go. */
.la-is-todos .la-links {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
    max-width: 860px;
}

.la-is-todos .la-link {
    flex-direction: row;
    align-items: flex-start;
}

.la-is-todos .la-link:hover { transform: none; }

.la-todo {
    display: flex;
    align-items: flex-start;
    gap: 13px;
    width: 100%;
    padding: 14px 16px;
}

/*  Asana's tick: an empty circle that fills when it is done. The check mark is
    always there, in white, so filling the circle is the only thing that
    changes and the control does not jump. */
.la-check {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-top: 1px;
    padding: 0;
    flex: none;
    border: 2px solid var(--rule);
    border-radius: 50%;
    background: transparent;
    color: transparent;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
}

.la-check svg { width: 12px; height: 12px; }

.la-check:hover { border-color: var(--accent); color: color-mix(in srgb, var(--accent) 45%, transparent); }

.la-check.is-done {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.la-check:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-todo .la-text { min-width: 0; flex: 1; }

.la-todo-title {
    position: relative;
    z-index: 2;
    display: inline-block;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--ink);
    text-decoration: none;
}

.la-todo-title:hover { color: var(--accent); text-decoration: underline; }
.la-todo-title:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.la-todo .la-note {
    display: block;
    margin-top: 3px;
    font-size: 13.5px;
    font-style: normal;
    line-height: 1.45;
    color: var(--ink-soft);
}

/*  A ticked line recedes rather than disappearing: still readable, clearly
    behind you. */
.la-link.is-ticked .la-todo-title {
    color: var(--ink-faint);
    text-decoration: line-through;
}

.la-link.is-ticked .la-note { color: var(--ink-faint); }
.la-link.is-ticked { background: var(--rule-soft); }

/*  A to-do row has no picture, so the whole-tile overlay would swallow the
    title's own link and the checkbox. Only the title opens the page here. */
.la-is-todos .la-open { display: none; }

/* ------------------------------------------------- the to-do hover preview */

.la-peek-card {
    position: fixed;
    z-index: 60;
    width: 320px;
    padding: 8px;
    border: 1px solid var(--rule);
    border-radius: 12px;
    background: var(--card);
    box-shadow: var(--shadow-lift);
    pointer-events: none;
}

.la-peek-card img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    border-radius: 8px;
    background: var(--rule-soft);
}

.la-peek-card span {
    display: block;
    margin-top: 7px;
    padding: 0 2px 2px;
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------------------------------------------ dev-ops */

/*  Down is the thing you came to see, so it is the loudest thing on the tile:
    a red edge as well as a red thumb. The checker sorts these to the top. */
.la-is-devops .la-link.is-down {
    border-color: #d5453b;
    box-shadow: 0 0 0 1px #d5453b, var(--shadow);
}

.la-status {
    position: absolute;
    left: 8px;
    bottom: 8px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 26px;
    padding: 0 9px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .96);
    box-shadow: var(--shadow);
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
}

.la-status svg { width: 14px; height: 14px; }
.la-status i { font-style: normal; }

.la-status.is-up { color: #1a7f4b; }
.la-status.is-down { color: #c0392b; }
.la-status.is-wait { color: var(--ink-faint); }

.la-status.is-down { background: #fdecea; }
.la-status.is-up { background: #eaf7f0; }


/* ------------------------------------------------------------- reordering */

/*  The count is the handle. It only looks like one while the pointer is on it,
    so the rail stays a list of names rather than a row of controls. */
.la-side-n[draggable] { cursor: grab; }

.la-side-n[draggable]:hover {
    color: var(--ink);
    background: var(--rule-soft);
    border-radius: 5px;
    padding: 1px 5px;
    margin: -1px -5px;
}

.la-side-item.is-dragging { opacity: .5; }

/*  While lists are being reordered the rows must not also light up as drop
    targets for a link - two different drags, one surface. */
body.la-sorting-lists .la-side-item { background: var(--card); }
body.la-sorting-lists .la-side-item.is-over { background: var(--card); border-color: var(--rule); }

@media (max-width: 1000px) {
    .la-page .la-main,
    .la-page .la-side { grid-column: 1; grid-row: auto; }
}


/* ------------------------------------------------------ the add-link tile */

/*  A quiet tile at the end of the run. Faded until it is approached, so it
    reads as an invitation rather than as another bookmark. */
.la-add-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 150px;
    padding: 18px;
    border: 1px dashed var(--rule);
    border-radius: 10px;
    background: transparent;
    color: var(--ink-faint);
    font-family: var(--body);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
    opacity: .55;
    transition: opacity .14s, border-color .14s, color .14s;
}

.la-add-tile:hover {
    opacity: 1;
    border-color: var(--ink-faint);
    color: var(--ink);
}

.la-add-tile:focus-visible { opacity: 1; outline: 2px solid var(--ink); outline-offset: 2px; }

.la-add-ring {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--rule-soft);
    color: var(--ink-soft);
}

.la-add-ring svg { width: 18px; height: 18px; }

.la-add-tile:hover .la-add-ring { background: var(--ink); color: var(--paper); }

.la-opt {
    font-family: var(--body);
    font-size: 11px;
    letter-spacing: normal;
    text-transform: none;
    color: var(--ink-faint);
}

.la-confirm-box label + label { margin-top: 4px; }


/* ---------------------------------------------------- the sidebar's footer */

.la-side-foot {
    display: flex;
    gap: 8px;
    padding-top: 12px;
    margin-top: 12px;
    border-top: 1px solid var(--rule);
}

.la-side-foot .la-side-add { flex: 1; margin-top: 0; }

.la-side-cog,
.la-side-out {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    flex: none;
    border: 1px dashed var(--rule);
    border-radius: 8px;
    color: var(--ink-soft);
    text-decoration: none;
}

.la-side-cog svg,
.la-side-out svg { width: 16px; height: 16px; }

.la-side-cog:hover,
.la-side-out:hover {
    border-color: var(--ink-faint);
    color: var(--ink);
    background: var(--rule-soft);
}

.la-side-cog:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/*  The page no longer pads the left edge - the sidebar owns it. */
/*  The grid itself has no top padding: the sidebar is a full-height column
    and any padding here pushes it down from the top of the window. The content
    carries its own instead. */
/*  An app shell rather than a document that scrolls.

    The sidebar is a fixed, full-height column and the content scrolls beside
    it. Sizing the sidebar at 100vh inside a document that also scrolls meant
    the root ended up taller than the body by whatever the sidebar and the
    padding disagreed about - a small strip below the fold with nothing in it.
    Pinning the shell to the viewport and scrolling the content instead removes
    the disagreement rather than tuning it.

    The narrow layout undoes all of this: there the rail is a strip above the
    tiles and the document scrolls normally. */
html, body.la-app { height: 100%; }
body.la-app { overflow: hidden; }

/*  The shell is sized against the viewport directly rather than through a
    chain of percentages, and its two columns are stretched to fill it.
    align-items: start left the row content-sized, which makes a percentage
    height on either column indefinite - it silently became auto, the sidebar
    grew past the window to fit every list, and the part below the fold could
    not be reached because the body clips it. Stretching removes the question. */
.la-page {
    height: 100vh;
    height: 100dvh;
    align-items: stretch;
    padding: 0;
    gap: 0;
}

/*  min-height: 0 on both, or a flex or grid child refuses to shrink below its
    content and scrolls the shell instead of itself. */
.la-page .la-side {
    position: static;
    height: auto;
    min-height: 0;
}

.la-page .la-main {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 24px 28px 48px;
}

/*  The content column gets the themed scrollbar too, so the two columns match
    rather than one being styled and the other not. */
.la-page .la-main {
    scrollbar-width: thin;
    scrollbar-color: var(--rule) transparent;
}

.la-page .la-main::-webkit-scrollbar { width: 10px; }
.la-page .la-main::-webkit-scrollbar-track { background: transparent; }

.la-page .la-main::-webkit-scrollbar-thumb {
    background: var(--rule);
    border-radius: 999px;
    border: 3px solid var(--paper);
}

.la-page .la-main:hover::-webkit-scrollbar-thumb { background: var(--ink-faint); }

/*  [hidden] is honored by Bootstrap's reboot with !important, which is the only
    reason these overlays stay hidden - a class selector setting display would
    otherwise win. Say it here so it does not depend on that. */
.la-app [hidden] { display: none !important; }

@media (max-width: 1000px) {
    /*  Back to an ordinary scrolling document. */
    html, body.la-app { height: auto; }
    body.la-app { overflow: visible; }
    .la-page { height: auto; }
    .la-page .la-main { height: auto; overflow: visible; }

    .la-side {
        position: static;
        height: auto;
        border-right: 0;
        border-bottom: 1px solid var(--rule);
        padding: 12px 16px;
    }

    /*  A horizontal strip of lists, cut off when there are more than fit -
        so it can be grabbed and pulled, exactly as the start page's chip row
        can. Same gesture in both places. */
    .la-side-list {
        display: flex;
        gap: 6px;
        overflow-x: auto;
        overflow-y: hidden;
        padding-right: 0;
        margin-right: 0;
        cursor: grab;
        scrollbar-width: none;
    }

    .la-side-list::-webkit-scrollbar { display: none; }

    .la-side-list.is-dragging { cursor: grabbing; user-select: none; }
    .la-side-list.is-dragging .la-side-item { pointer-events: none; }

    .la-side-item {
        flex: none;
        border: 1px solid var(--rule);
        border-radius: 999px;
        padding: 7px 13px 7px 14px;
    }

    .la-side-item::before { display: none; }
    .la-side-item.is-here { border-color: var(--ink); }
    .la-side-item.is-bin { margin-top: 0; padding-top: 7px; border-top: 1px solid var(--rule); }

    .la-brand { padding-bottom: 10px; margin-bottom: 10px; }
    .la-page .la-main { padding: 16px; }
}


/* ================================================================ settings */

.la-set {
    max-width: 640px;
    padding-bottom: 26px;
    margin-bottom: 26px;
    border-bottom: 1px solid var(--rule);
}

.la-set:last-of-type { border-bottom: 0; }

.la-set h2 {
    margin: 0 0 4px;
    font-family: var(--display);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-set-note {
    margin: 0 0 18px;
    max-width: 56ch;
    font-size: 14px;
    color: var(--ink-soft);
}

.la-set-note strong { color: var(--ink); }

/* ------------------------------------------------------------ theme picker */

.la-themes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
    gap: 12px;
}

.la-theme {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding: 12px;
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--card);
    text-align: left;
    cursor: pointer;
}

.la-theme:hover { border-color: var(--ink-faint); }
.la-theme:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-theme.is-on {
    border-color: var(--ink);
    box-shadow: 0 0 0 1px var(--ink);
}

/*  Three bars in the theme's own values - page, card and ink - which says more
    about how it will feel than a single color chip would. */
.la-theme-swatch {
    display: flex;
    gap: 3px;
    width: 100%;
    height: 34px;
    padding: 5px;
    margin-bottom: 8px;
    border: 1px solid var(--t-rule);
    border-radius: 7px;
    background: var(--t-paper);
}

.la-theme-swatch i { flex: 1; border-radius: 3px; }
.la-theme-swatch i:nth-child(1) { background: var(--t-card); border: 1px solid var(--t-rule); }
.la-theme-swatch i:nth-child(2) { background: var(--t-ink); opacity: .85; }
.la-theme-swatch i:nth-child(3) { background: var(--t-rule); }

.la-theme strong { font-size: 14px; font-weight: 600; color: var(--ink); }
.la-theme em { font-style: normal; font-size: 12.5px; line-height: 1.4; color: var(--ink-soft); }

/* ---------------------------------------------------------------- switches */

.la-switch {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 11px 0;
    cursor: pointer;
}

.la-switch + .la-switch { border-top: 1px solid var(--rule-soft); }

.la-switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.la-switch-track {
    position: relative;
    width: 40px;
    height: 23px;
    flex: none;
    margin-top: 1px;
    border-radius: 999px;
    background: var(--rule);
    transition: background .14s;
}

.la-switch-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--card);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
    transition: transform .14s;
}

.la-switch input:checked + .la-switch-track { background: var(--ink); }
.la-switch input:checked + .la-switch-track .la-switch-knob { transform: translateX(17px); }
.la-switch input:focus-visible + .la-switch-track { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-switch-text strong { display: block; font-size: 14.5px; font-weight: 600; }
.la-switch-text em { display: block; margin-top: 1px; font-style: normal; font-size: 13px; color: var(--ink-soft); }

/* ------------------------------------------------------------------- range */

.la-range { display: block; max-width: 420px; }

.la-range span {
    display: block;
    margin-bottom: 8px;
    font-size: 14.5px;
    font-weight: 600;
}

.la-range b { font-family: var(--mono); font-size: 12.5px; font-weight: 500; color: var(--ink-faint); }

.la-range input[type="range"] {
    width: 100%;
    accent-color: var(--ink);
}

.la-side-cog.is-here {
    border-style: solid;
    border-color: var(--ink);
    color: var(--ink);
    background: var(--rule-soft);
}


/* ================================================================= dialogs */

/*  Bootstrap draws the box; these give it the theme's own surface, type and
    spacing so a dialog does not look like it came from somewhere else. Scoped
    under .la-app, which is only the signed-in pages. */

.la-app .modal-content {
    border: 1px solid var(--rule);
    border-radius: 14px;
    background: var(--card);
    box-shadow: var(--shadow-lift);
}

.la-app .modal-backdrop.show { opacity: .45; }

.la-app .modal-header,
.la-app .modal-footer {
    padding: 16px 20px;
    border-color: var(--rule);
}

.la-app .modal-body { padding: 20px; }

.la-app .modal-title {
    font-family: var(--display);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--ink);
}

.la-app .btn-close { filter: var(--close-filter, none); opacity: .5; }
.la-app .btn-close:hover { opacity: 1; }

.la-app .modal .form-control,
.la-app .modal textarea,
.la-app .modal select {
    padding: 9px 11px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--body);
    font-size: 14.5px;
    box-shadow: none;
}

.la-app .modal .form-control:focus,
.la-app .modal textarea:focus,
.la-app .modal select:focus {
    border-color: var(--ink-faint);
    box-shadow: 0 0 0 3px rgba(128, 128, 128, .14);
}

.la-m-label,
.la-app .modal label {
    display: block;
    margin-bottom: 6px;
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.la-app .modal .custom-control-label,
.la-app .modal .form-check-label {
    font-family: var(--body);
    font-size: 14px;
    letter-spacing: normal;
    text-transform: none;
    color: var(--ink);
}

/* ------------------------------------------------------------- the colors */

/*  Two rows of eight. A tick rather than a ring for the chosen one, because a
    ring on a dark swatch and a ring on a light one do not read the same. */
/*  One row whatever the count. A grid of eight wrapped the sixteen swatches
    onto two rows; flex with an equal share each keeps them on one and adapts
    if the palette ever changes length. */
.la-colors {
    display: flex;
    gap: 6px;
    margin-bottom: 14px;
}

.la-colors .la-swatch { flex: 1 1 0; min-width: 0; }

.la-swatch {
    position: relative;
    aspect-ratio: 1;
    padding: 0;
    border: 0;
    border-radius: 7px;
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}

.la-swatch:hover { transform: scale(1.08); }
.la-swatch:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.la-swatch.is-on::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 46%;
    width: 5px;
    height: 9px;
    margin: -6px 0 0 -3px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
    filter: drop-shadow(0 0 1px rgba(0, 0, 0, .5));
}

.la-color-pick {
    display: flex;
    align-items: center;
    gap: 9px;
}

.la-color-dot {
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: 8px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}

.la-color-input {
    flex: 1;
    padding: 8px 11px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 13.5px;
    outline: none;
}

.la-color-input:focus { border-color: var(--ink-faint); }

/*  Huebee draws its own popup; give it the theme's surface so it does not
    arrive as a white card on a dark page. */
.huebee { z-index: 1080; }

.huebee__container {
    border: 1px solid var(--rule);
    border-radius: 10px;
    background: var(--card);
    box-shadow: var(--shadow-lift);
}

.huebee__cursor { border-color: var(--ink); }
.huebee__close-button { fill: var(--ink-soft); }

/* --------------------------------------------------- the pencil in the rail */

.la-side-pencil {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    flex: none;
    padding: 0;
    border: 1px dashed var(--rule);
    border-radius: 8px;
    background: transparent;
    color: var(--ink-soft);
    cursor: pointer;
}

.la-side-pencil svg { width: 15px; height: 15px; }

.la-side-pencil:hover {
    border-color: var(--ink-faint);
    color: var(--ink);
    background: var(--rule-soft);
}

.la-side-pencil:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }


/*  The dialog footers lay their buttons out in a row, with the destructive one
    pushed away from the one you actually meant to press. */
.la-app .modal-footer {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
}

.la-app .modal-footer > * { margin: 0; }
.la-app .modal-footer .la-spacer { flex: 1; }

/* --------------------------------------------------------------- webhooks */

/*  The strip under a webhook list's heading. A webhook list is an ordinary
    list; this is the one line that says where a saved page gets sent. */
.la-hook { margin: 0 0 22px; }

.la-hook-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.la-hook-method {
    flex: 0 0 auto;
    padding: 9px 12px;
    border: 1px solid var(--rule);
    border-radius: 7px;
    background: var(--card);
    color: var(--ink);
    font: inherit;
    font-size: 14px;
}

.la-hook-url {
    flex: 1 1 320px;
    min-width: 0;
    padding: 9px 13px;
    border: 1px solid var(--rule);
    border-radius: 7px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 13px;
}

.la-hook-url:focus, .la-hook-method:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/*  Key and value pairs for a POST body, on their own row under the line. */
.la-hook-extras {
    flex: 1 1 100%;
    grid-template-columns: 1fr 2fr;
    gap: 8px;
    margin-top: 4px;
}

.la-hook-extras input {
    padding: 8px 12px;
    border: 1px solid var(--rule);
    border-radius: 7px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 13px;
}

.la-hook-note { margin: 10px 0 0; font-size: 13px; color: var(--ink-soft); }
.la-hook-note a { color: var(--accent); text-decoration: none; }
.la-hook-note a:hover { text-decoration: underline; }

/*  What the webhook sent, shown in place of the tiles. */
.la-log table { width: 100%; border-collapse: collapse; }

.la-log td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--rule);
    font-size: 14px;
    line-height: 1.6;
    vertical-align: top;
    word-break: break-all;
}

.la-log tr:first-child td { border-top: 1px solid var(--rule); }
.la-log td:first-child { font-family: var(--mono); font-size: 13px; }

.la-log .la-log-when {
    width: 1%;
    white-space: nowrap;
    color: var(--ink-soft);
    font-size: 13px;
    word-break: normal;
}

/* ------------------------------------------------------- the list dialog */

/*  Twice the old modal-sm, so name and type sit side by side rather than
    stacking down a column narrow enough that neither had room. */
.la-modal-wide .modal-dialog { max-width: 640px; }

.la-m-row + .la-m-row { margin-top: 18px; }

/*  Name and type together: the two answers that decide what the list is. */
.la-m-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

@media (max-width: 560px) { .la-m-2 { grid-template-columns: 1fr; } }

.la-m-label {
    display: block;
    margin-bottom: 6px;
    color: var(--ink-soft);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/*  Swatches on their own row, the field they fill in on the next. */
.la-m-row .la-colors { margin-bottom: 10px; }

.la-m-rule {
    margin: 22px 0 18px;
    border: 0;
    border-top: 1px solid var(--rule);
    opacity: 1;
}

/*  Below the rule: the one control here that changes behavior rather than
    appearance, so it should not read as another piece of styling. */
.la-m-toggle { display: flex; align-items: flex-start; gap: 14px; }

.la-m-toggle-text strong { display: block; color: var(--ink); font-size: 14px; }
.la-m-toggle-text span   { display: block; margin-top: 2px; color: var(--ink-soft); font-size: 13px; line-height: 1.5; }

.la-switch { position: relative; flex: none; margin: 2px 0 0; cursor: pointer; }
.la-switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.la-switch-track {
    display: block;
    width: 40px;
    height: 22px;
    padding: 2px;
    border-radius: 999px;
    background: var(--rule);
    transition: background .15s;
}

.la-switch-knob {
    display: block;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--card);
    box-shadow: 0 1px 2px rgba(0,0,0,.25);
    transition: transform .15s;
}

.la-switch input:checked + .la-switch-track { background: var(--accent); }
.la-switch input:checked + .la-switch-track .la-switch-knob { transform: translateX(18px); }
.la-switch input:focus-visible + .la-switch-track { outline: 2px solid var(--ink); outline-offset: 2px; }


/*  Says the limit is close, and is the only thing in the app that links to
    checkout. Quiet at ten left, loud at zero, absent otherwise and absent
    entirely once somebody has paid. */
.la-side-plan {
    display: block;
    margin: 0 12px 10px;
    padding: 11px 13px;
    border: 1px solid var(--rule);
    border-radius: 9px;
    background: var(--rule-soft);
    color: var(--ink);
    text-decoration: none;
}

.la-side-plan strong { display: block; font-size: 13px; }
.la-side-plan span   { display: block; margin-top: 2px; color: var(--ink-soft); font-size: 12px; line-height: 1.45; }
.la-side-plan:hover  { border-color: var(--ink-faint); color: var(--ink); text-decoration: none; }

.la-side-plan.is-full { border-color: #d99a4e; background: rgba(217,154,78,.12); }
.la-side-plan.is-full strong { color: #b9772c; }

/*  A fixed tiles-per-row. The default stays auto-fill, which packs in as many
    as will go; a chosen number stretches them instead. Stepped down on narrow
    screens, because five across on a phone is five slivers. */
/*  Written out per count rather than repeat(var(--n)). A custom property
    inside repeat() is invalid at computed-value time, which drops the whole
    property back to its initial value of none, and none is one column. That is
    what put every list on a single column per row. */
.la-links.is-cols-3, .la-lists.is-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.la-links.is-cols-4, .la-lists.is-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.la-links.is-cols-5, .la-lists.is-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }

@media (max-width: 1080px) {
    .la-links[class*="is-cols-"], .la-lists[class*="is-cols-"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
    .la-links[class*="is-cols-"], .la-lists[class*="is-cols-"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 540px) {
    .la-links[class*="is-cols-"], .la-lists[class*="is-cols-"] { grid-template-columns: minmax(0, 1fr); }
}

/*  Hidden but still draggable: the count in the rail is the reorder handle. */
.la-side-n.is-quiet { color: transparent; }
.la-side-n.is-quiet:hover { color: var(--ink-faint); }

/*  A row of mutually exclusive choices, for a setting that is not a switch. */
.la-choice { margin-bottom: 22px; }

.la-choice-label {
    display: block;
    margin-bottom: 8px;
    color: var(--ink);
    font-size: 14px;
    font-weight: 600;
}

.la-choice-set { display: flex; flex-wrap: wrap; gap: 8px; }

.la-choice-opt {
    padding: 8px 15px;
    border: 1px solid var(--rule);
    border-radius: 999px;
    background: var(--card);
    color: var(--ink-soft);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.la-choice-opt:hover { border-color: var(--ink-faint); color: var(--ink); }

.la-choice-opt.is-on {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--paper);
}

.la-choice-note { display: block; margin-top: 8px; color: var(--ink-soft); font-size: 13px; font-style: normal; }

/*  A message you are meant to act on. It stays until dismissed and is wider,
    because the ones that matter are a sentence rather than a word. */
.la-toast.is-held {
    max-width: 460px;
    border-radius: 10px;
    padding-right: 40px;
    line-height: 1.55;
    text-align: left;
}

.la-toast.is-held a {
    margin: 0 4px;
    color: var(--paper);
    font-weight: 700;
    text-decoration: underline;
}

.la-toast-x {
    position: absolute;
    top: 6px;
    right: 8px;
    padding: 2px 6px;
    border: 0;
    background: none;
    color: inherit;
    font-size: 18px;
    line-height: 1;
    opacity: .7;
    cursor: pointer;
}

.la-toast-x:hover { opacity: 1; }

/*  The tiles-per-row setting does not reach a to-do list. Those are lines, not
    tiles, and two checkboxes side by side is not a shorter list, it is a
    harder one to read. Stated here as well as in the template, because the
    two selectors otherwise tie on specificity and the later one wins. */
.la-is-todos .la-links[class*="is-cols-"] { grid-template-columns: minmax(0, 1fr); }
