/* liminal - generic framework styles (app-specific styling belongs in the
   app's own css, e.g. rabid.css, loaded after this so it can override).

   The centrepiece is the "tappable surface" language:
     - .lm-navigable: tap anywhere drills in to the detail page (chevron);
       editing, when offered, is only via the contained pencil - the standard
       list-row species (Table.detailItemProps);
     - .lm-editable: tap anywhere opens the edit dialog - only for hand-rolled
       surfaces with no detail page to drill into (e.g. the wordwiki lexeme
       editor's fact rows).
   The affordances are communicated three ways:
     - a docked marker at the surface's edge: a chevron (drills in) and/or a
       ghosted pencil (.lm-edit-pencil) - the pencil itself a real <button> so
       keyboard and screen-reader users get the same path;
     - a hover tint on devices that hover (desktop);
     - a pressed tint via :active (works on touch, where hover does not).
*/

/* ---------------------------------------------------------------------------
   Tappable surfaces: editable (.lm-editable, tap-anywhere-edits) and navigable
   (.lm-navigable, tap-anywhere-drills-in; editing only via the pencil).  Same
   touch feedback for both - what differs is what the tap does.
--------------------------------------------------------------------------- */

.lm-editable,
.lm-navigable {
    cursor: pointer;
}

/* Pressed feedback - :active fires on touch, unlike :hover.  (Hover tint on
   desktop comes from Bootstrap's .list-group-item-action; surfaces that are
   not list items get it here.) */
.lm-editable:active,
.lm-navigable:active {
    background-color: var(--bs-secondary-bg);
}

@media (hover: hover) {
    .lm-editable:hover,
    .lm-navigable:hover {
        background-color: var(--bs-tertiary-bg);
    }
}

/* A keyboard stop (keyboard-driven-editing.md): a focusable editable surface.
   :focus-visible only, so the ring appears for KEYBOARD focus - a mouse user
   never sees any of this.  scroll-margin keeps a focused row clear of a
   sticky navbar when Tab-traversal scrolls it into view. */
.lm-kbd-stop {
    scroll-margin: 4.5rem 0;
}
.lm-kbd-stop:focus {
    outline: none;
}
.lm-kbd-stop:focus-visible {
    outline: 2px solid rgba(var(--bs-primary-rgb), .55);
    outline-offset: 2px;
    border-radius: .25rem;
}
/* The page-foot keyboard hint (one quiet line; its link opens lmKbdHelp). */
.lm-kbd-hint {
    text-align: center;
    font-size: .85rem;
    margin: 2rem 0 1rem;
}
.lm-kbd-hint .btn-link {
    font-size: inherit;
}

/* The standard edit-affordance marker (and its sibling, the ☰ less-common-
   actions menu button - action.ts actionMenu): icon-only <button>s (quieter
   than text buttons, but still the accessible/backstop path).  Padded out to
   a finger-sized (~44px) tap target. */
.lm-edit-pencil,
.lm-view-eye,
.lm-history-clock,
.lm-menu-button {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: var(--bs-secondary-color);
    padding: 0.625rem;
    margin: -0.375rem -0.375rem -0.375rem 0;  /* big tap target without inflating the row */
    border-radius: 0.375rem;
    line-height: 0;
    text-decoration: none;   /* the pencil is also used as an <a> (lexeme links) */
}
.lm-edit-pencil:hover,
.lm-edit-pencil:focus-visible,
.lm-view-eye:hover,
.lm-view-eye:focus-visible,
.lm-history-clock:hover,
.lm-history-clock:focus-visible,
.lm-menu-button:hover,
.lm-menu-button:focus-visible {
    color: var(--bs-body-color);
    background-color: var(--bs-secondary-bg);
}
.lm-edit-pencil svg,
.lm-view-eye svg,
.lm-history-clock svg,
.lm-menu-button svg {
    width: 1.1rem;
    height: 1.1rem;
}
/* The menu wrapper participates in the line's flex row without adding size.
   (NO line-height:0 here - that would cascade into the dropdown list and
   collapse its items onto each other; the icon button carries its own.) */
.lm-action-menu {
    flex: 0 0 auto;
}
.lm-action-menu .dropdown-menu {
    line-height: var(--bs-body-line-height, 1.5);
}

/* ---------------------------------------------------------------------------
   Parameter dialogs / edit forms
--------------------------------------------------------------------------- */

/* The dialog's submit row.  When the form is taller than the modal body (a
   long edit form on a phone) the row sticks to the bottom of the scrollport,
   so saving never requires scrolling to the end of the form.  The negative
   bottom offset lets it sink into (and cover) the modal-body's own bottom
   padding, so fields scrolling beneath it don't peek through the gap. */
.modal-body .lm-form-actions {
    position: sticky;
    bottom: calc(-1 * var(--bs-modal-padding, 1rem));
    background-color: var(--bs-body-bg);
    padding: 0.75rem 0;
    border-top: var(--bs-border-width) solid var(--bs-border-color);
}

/* ---------------------------------------------------------------------------
   Standard item list (the mobile-first replacement for column tables)

   A .list-group of .lm-item rows: body (primary line + muted secondary line)
   on the left, the pencil docked right.  Long values wrap rather than forcing
   horizontal scroll.
--------------------------------------------------------------------------- */

/* The list container.  Capped: a tap-target row stretched across a wide
   desktop window reads poorly (the pencil ends up a long mouse-travel away
   from the text), so hold the list to a comfortable reading width. */
.lm-list {
    max-width: 42rem;
}

.lm-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.lm-item-body {
    flex: 1 1 auto;
    min-width: 0;          /* allow children to wrap instead of overflowing */
}

.lm-item-primary {
    font-weight: 500;
}

/* Primary-line links (e.g. name -> detail page): a generous tap target so a
   thumb aiming for the link doesn't land on the row's edit action instead. */
.lm-item-primary a {
    display: inline-block;
    padding: 0.25rem 0;
    text-decoration: none;
}
.lm-item-primary a:hover {
    text-decoration: underline;
}

/* A navigable row's TITLE, and the primary navigation signal (design-language.md):
   the reserved accent colour --lm-nav means "this is a link - tap to go there",
   learned once and used app-wide.  The colour is a VARIABLE so each app sets its
   own (rabid: a teal); with none set it falls back to body colour - the
   pre-accent look - so a liminal app that hasn't adopted the accent link is
   unchanged.  Used by every navigable list + the events table. */
.lm-nav-link {
    color: var(--lm-nav, var(--bs-body-color));
    font-weight: 600;
    text-decoration: none;
}
.lm-nav-link:hover,
.lm-nav-link:focus,
.lm-item-primary a.lm-nav-link:hover {
    color: var(--lm-nav-hover, var(--bs-body-color));
    text-decoration: none;
}

/* The navigable counterpart of the pencil: a muted chevron marking a row whose
   whole surface drills in to a detail page (navigableItemProps). */
.lm-nav-chevron {
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
    font-size: 1.5rem;
    line-height: 1;
    padding: 0 0.5rem;
}

.lm-item-secondary {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    overflow-wrap: anywhere;
}
/* Keep secondary-line links (mailto: etc.) quiet - they read as data, not chrome. */
.lm-item-secondary a {
    color: inherit;
    text-decoration: none;
}
.lm-item-secondary a:hover {
    text-decoration: underline;
}

/* ----------------------------------------------------------------------------
   Document-language primitives (liminal design-language.md): the SHARED
   mechanism for list/detail pages that read as documents.  An app adopts the
   look by setting --lm-nav (the accent link); these structural classes are the
   same for every liminal app.
   ---------------------------------------------------------------------------- */

/* A flat, navigable document section - not a framed or filled box.  Items
   separate by whitespace; the accent title (.lm-nav-link) is the navigation
   signal, and the whole section stays clickable as a larger tap target. */
.lm-doc-section {
    padding: 0.65rem 0;
    cursor: pointer;
    max-width: 46rem;
}
.lm-doc-title {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0;
    line-height: 1.3;
}
.lm-doc-title .lm-nav-chevron {
    color: var(--bs-secondary-color);
    font-weight: 400;
    margin-left: 0.15rem;
}
/* Secondary line under the title (members, meta) - quiet, readable. */
.lm-doc-meta {
    color: var(--bs-secondary-color);
    font-size: 0.9rem;
    margin-top: 0.1rem;
}
/* A record's own description on a detail page: clean document body, no callout. */
.lm-doc-lead {
    font-size: 1.08rem;
    line-height: 1.6;
    max-width: 46rem;
}
/* A detail-page section heading (Members, Projects, ...): a quiet document
   section label in a flex head, so it can carry a trailing "+" or count. */
.lm-doc-section-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 1.75rem 0 0.5rem;
}
.lm-doc-section-label {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    margin: 0;
}
/* An embedded subsection: a list nested under a section heading (a composed
   page's Members / Projects / Tasks).  Weight tracks DEPTH - nested item titles
   demote one notch below the section label and indent under it.  Container-
   driven so it survives fragment reloads: a row swapped back inside keeps the
   demotion, which a render-time parameter could not. */
.lm-subsection {
    margin-left: 0.9rem;
}
.lm-subsection .lm-doc-title {
    font-size: 1rem;
    font-weight: 500;
}

/* The OTHER document list format (design-language.md): a DATA TABLE, for many
   uniform records you SCAN and COMPARE (a roster, a schedule) - where aligned
   columns + regular rows read better than flat sections.  A TYPOGRAPHIC table,
   not a spreadsheet grid: a single quiet header rule, comfortable row rhythm, no
   cell borders/striping; the accent-link name is the navigation signal and the
   whole row drills in. */
.lm-data-table {
    width: 100%;
    max-width: 50rem;
    border-collapse: collapse;
}
.lm-data-table > thead th {
    font-weight: 600;
    font-size: 0.78rem;
    color: var(--bs-secondary-color);
    text-align: left;
    padding: 0.2rem 1.25rem 0.4rem 0;
    border-bottom: 1px solid var(--bs-border-color);
}
.lm-data-table td {
    padding: 0.2rem 1.25rem 0.2rem 0;   /* tight row rhythm: reads as one dense table, not separated items */
    line-height: 1.35;
    vertical-align: baseline;
}
.lm-data-table th:last-child,
.lm-data-table td:last-child { padding-right: 0; }
/* A section heading row inside the table (colspan), e.g. Active / Other.  Given
   the standard table-subhead language - a quiet uppercase, letter-spaced label
   with a rule - so it reads as a group header, not stray text in the grid. */
.lm-data-table .lm-data-section > td {
    padding: 1.35rem 0 0.3rem;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--bs-secondary-color);
    border-bottom: 1px solid var(--bs-border-color);
}
/* ...but the FIRST group heading sits right under the column header - no need to
   push it down as far as a mid-table group break. */
.lm-data-table > tbody > tr.lm-data-section:first-child > td {
    padding-top: 0.6rem;
}

/* A navigable table ROW: the whole surface drills in to a detail page.  Bootstrap
   (and our reset) paint per-cell, so tint the cells rather than the <tr>. */
tr.lm-navigable { cursor: pointer; }
@media (hover: hover) {
    tr.lm-navigable:hover > * { background-color: var(--bs-tertiary-bg); }
}
tr.lm-navigable:active > * { background-color: var(--bs-secondary-bg); }

/* ----------------------------------------------------------------------------
   Inline name list (group members as TEXT, not pills)

   A set of people reads as a PURE document phrase - "Hazel, Bob and Carol" -
   followed by one ☰ carrying every membership verb (add me / add member /
   the per-member removes / remove all).  No inline ×, no inline add: the
   names are just names.
---------------------------------------------------------------------------- */

.lm-name-list {
    display: inline;
}
.lm-member {
    white-space: nowrap;
}
/* The membership ☰ flows with the phrase. */
.lm-name-list .lm-action-menu {
    display: inline-block;
    vertical-align: middle;
}

/* ----------------------------------------------------------------------------
   Document links: navigation inside document-weight lines (task blocks,
   assignment lines, name lists) reads as TEXT - the page is a printable
   document with unobtrusive affordances; hover/focus reveals the link-ness.
---------------------------------------------------------------------------- */

.lm-task-block a,
.lm-assign-line a,
.lm-name-list a {
    color: inherit;
    text-decoration: none;
}
.lm-task-block a:hover, .lm-task-block a:focus-visible,
.lm-assign-line a:hover, .lm-assign-line a:focus-visible,
.lm-name-list a:hover, .lm-name-list a:focus-visible {
    text-decoration: underline;
}

/* ----------------------------------------------------------------------------
   Rendered markdown (MarkdownField.render / liminal/markdown.ts): document
   text.  Trim the trailing margin so embedded notes don't pad out their
   container (a dl row, a detail section).
---------------------------------------------------------------------------- */

.lm-markdown > :last-child {
    margin-bottom: 0;
}
.lm-markdown-img {
    max-width: 100%;
}
.lm-markdown-quote {
    border-left: 3px solid var(--bs-border-color);
    padding-left: 0.75rem;
    color: var(--bs-secondary-color);
}

/* ----------------------------------------------------------------------------
   Photos (liminal/photo.ts + ImageField)
---------------------------------------------------------------------------- */

/* Display thumbnail (ImageField.render / detail pages). */
.lm-photo-thumb {
    max-width: 6rem;
    max-height: 6rem;
    border-radius: 0.375rem;
    object-fit: cover;
}

/* The preview inside the photo input control. */
.lm-photo-preview {
    display: block;
    max-width: 10rem;
    max-height: 10rem;
    border-radius: 0.375rem;
    margin-bottom: 0.5rem;
}

/* A small leading thumbnail on a standard list row. */
.lm-row-thumb {
    width: 3rem;
    height: 3rem;
    object-fit: cover;
    border-radius: 0.375rem;
    flex: none;
}

/* A larger presentation image on a detail page. */
.lm-photo-detail {
    display: block;
    max-width: 100%;
    width: 20rem;
    border-radius: 0.5rem;
    margin-bottom: 1rem;
}

/* A framing option in the crop picker: small + bounded so several fit in a row
   and can be compared (they are already the exact aspect - no object-fit). */
.lm-crop-choice {
    display: block;
    max-height: 6rem;
    max-width: 8rem;
    border-radius: 0.25rem;
}

/* --- The change list (change-list.ts) --------------------------------------
   ONE flat event log, reused in every context (single fact / lexeme / global /
   per-user).  Each line reads left-to-right as a log: WHEN, WHO lead (rigid,
   narrow columns - the regular info that says "activity log"), then what
   happened.  See publication-model.md. */

/* The header bar carrying the Editing<->Reviewing switch + filters. */
.lm-review-bar {
    padding: 0.25rem 0;
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
}

.lm-changelist {
    line-height: 1.55;
}

/* Grouped review: one headed block per fact (the approval queue).  The header
   names the field and carries its actions; the body is the fact's events. */
.lm-cl-group { margin-bottom: 0.7rem; }
.lm-cl-group-header {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.1rem 0;
    border-bottom: 1px solid var(--bs-border-color, #e6e8ea);
    margin-bottom: 0.15rem;
}
.lm-cl-group-body { padding-left: 0.25rem; }
/* The grouped list's empty message is always present but hidden while any group
   exists - so when the last group's fragment removes itself, it appears with no
   re-render of the list. */
.lm-changelist-grouped:has(> .lm-cl-group) > .lm-cl-empty { display: none; }

/* One event line: WHEN and WHO lead in fixed columns; then (in multi-fact
   lists) a scannable SUBJECT column; the description fills the rest; an optional
   action menu trails. */
.lm-cl-row {
    display: grid;
    grid-template-columns: 4.2rem 2.2rem minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: 0.5rem;
}
.lm-cl-row.lm-cl-withsubject {
    grid-template-columns: 4.2rem 2.2rem 9rem minmax(0, 1fr) auto;
}
.lm-cl-subject {
    overflow-wrap: anywhere;
}
.lm-cl-field { font-weight: 600; }
.lm-cl-lexeme {
    font-size: 0.85em;
    color: var(--bs-secondary-color, #6c757d);
}
.lm-cl-when {
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--bs-secondary-color, #6c757d);
    white-space: nowrap;
}
.lm-cl-who {
    font-weight: 600;
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    color: var(--bs-secondary-color, #6c757d);
}
.lm-cl-what {
    min-width: 0;
    overflow-wrap: anywhere;
}
.lm-cl-subject {
    font-weight: 600;
}
.lm-cl-verb {
    color: var(--bs-secondary-color, #6c757d);
}
/* Media in a line stays small so the rhythm holds; audio is a one-line player
   and is left alone (approving audio means playing it). */
.lm-cl-what img,
.lm-cl-what object {
    max-height: 2.5rem;
    max-width: 8rem;
    vertical-align: middle;
}
/* A note (comment / revert reason / edit rationale) under its line. */
.lm-cl-note {
    font-size: 0.9em;
    color: var(--bs-secondary-color, #6c757d);
    font-style: italic;
}
/* The baseline (accepted value) reads quietly; the moving events carry weight. */
.lm-cl-baseline  { color: var(--bs-secondary-color, #6c757d); }
.lm-cl-deleted   > .lm-cl-what > .lm-cl-verb { color: var(--bs-danger, #dc3545); }
.lm-cl-added     > .lm-cl-what > .lm-cl-verb { color: var(--bs-success, #198754); }
.lm-cl-approved  > .lm-cl-what > .lm-cl-verb { color: var(--bs-success, #198754); }

/* A change shown as before -> after: a fixed "from/to" label column so the two
   values line up under each other and the difference is apparent at a glance. */
.lm-cl-detail {
    display: grid;
    row-gap: 0.05rem;
}
.lm-cl-dline {
    display: grid;
    grid-template-columns: 2.6rem minmax(0, 1fr);
    column-gap: 0.4rem;
    align-items: baseline;
}
.lm-cl-dlabel {
    font-size: 0.75rem;
    color: var(--bs-secondary-color, #6c757d);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.lm-cl-dval { overflow-wrap: anywhere; }
.lm-cl-from { color: var(--bs-secondary-color, #6c757d); }   /* the prior value, quiet */

/* Within a from/to diff: deleted text struck on the "from" row, inserted text
   highlighted on the "to" row - so a one-letter change pops. */
.lm-diff-del {
    color: #842029;
    text-decoration: line-through;
}
.lm-diff-ins {
    color: #0f5132;
    background: #d1e7dd;
    border-radius: 0.15rem;
    padding: 0 0.05rem;
}
/* Elided unchanged context in a long value's diff. */
.lm-diff-elide { color: var(--bs-secondary-color, #6c757d); }

/* A comment's text, inline (it is the content of a comment event). */
.lm-cl-comment { font-style: italic; }

/* A word chip naming the event KIND (comment / approved / reverted / added /
   deleted) - words not glyphs, lightly coloured. */
.lm-cl-chip {
    display: inline-block;
    font-size: 0.68rem;
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-weight: 600;
    padding: 0 0.32rem;
    border-radius: 0.25rem;
    vertical-align: middle;
    background: var(--bs-secondary-bg, #e9ecef);
    color: var(--bs-secondary-color, #6c757d);
}
.lm-cl-chip-added,
.lm-cl-chip-approved { background: #d1e7dd; color: #0f5132; }
.lm-cl-chip-deleted,
.lm-cl-chip-reverted { background: #f8d7da; color: #842029; }
.lm-cl-chip-commented { background: #e2e3e5; color: #41464b; }
/* A pending edit (the meta editor's changes bar) - the warning family, like
   the pending dot. */
.lm-cl-chip-edited { background: #fff3cd; color: #664d03; }

/* Compact (default) view: a quiet dot on a fact whose current value is not yet
   approved, so editors can spot unaccepted changes without entering review. */
.lm-pending-dot {
    flex: none;
    width: 0.5rem;
    height: 0.5rem;
    margin: 0.35rem 0.4rem 0 0;
    border-radius: 50%;
    background: var(--bs-warning, #ffc107);
}

/* ---------------------------------------------------------------------------
   Refresh debug mode (lmDebugRefresh in liminal-scripts.js): every fragment
   refreshed in the last tx round is marked - green = refreshed and actually
   different, yellow = refreshed but identical (pure over-revalidation).
   Classes are only applied while debug mode is on.
--------------------------------------------------------------------------- */
.lm-debug-refreshed-changed {
    outline: 2px solid rgba(25, 135, 84, 0.7);
    background: rgba(25, 135, 84, 0.08);
}
.lm-debug-refreshed-same {
    outline: 2px solid rgba(255, 193, 7, 0.85);
    background: rgba(255, 193, 7, 0.12);
}
/* The round-summary badge (path taken + changed/unchanged counts). */
#lm-debug-badge {
    position: fixed;
    bottom: 0.5rem;
    left: 0.5rem;
    z-index: 2000;
    padding: 0.2rem 0.55rem;
    border-radius: 0.3rem;
    background: rgba(33, 37, 41, 0.85);
    color: #fff;
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.75rem;
    pointer-events: none;
}

/* Conditional form field hidden by the form-state mechanism (liminal-scripts.js).
   !important beats the wrapper's inline display:contents. */
.lm-cond-hidden { display: none !important; }
