/* One card for every list of entities (entity-card.js): title and one line of
   details on the left, state indicator and the "⋯" menu on the right. Nothing
   re-flows in a narrow column — the menu becomes a bottom sheet instead.
   Load BEFORE responsive.css, like every other module. */

.ent-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
    list-style: none;
    margin: 0;
}

.ent-card {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "body act";
    align-items: center;
    column-gap: 14px;
    min-height: 78px;
    padding: 12px 14px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: var(--shadow-card);
    transition: border-color 0.15s ease, background-color 0.15s ease;
    /* No overflow clipping: the "⋯" dropdown hangs out of the card. */
}
.ent-card:has(> .ent-lead) {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "lead body act";
    column-gap: 12px;
}
.ent-card.is-muted { background: var(--bg-subtle); opacity: 0.85; }
.ent-card.is-open { cursor: pointer; }
.ent-card:hover { border-color: var(--border-strong); }
.ent-card.is-open:hover { border-color: var(--accent); }
.ent-card.is-open a, .ent-card.is-open button { cursor: pointer; }

.ent-lead {
    grid-area: lead;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    border: 1px solid var(--border);
    background: var(--bg-subtle);
    color: var(--text);
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    background-size: cover;
    background-position: center;
}
.ent-lead.is-icon { color: var(--text-muted); }

.ent-body { grid-area: body; display: grid; gap: 5px; min-width: 0; }
/* One line, cut with an ellipsis. Every card is then the same box whatever the
   name is: a long source title used to wrap to two lines and push the card
   taller than its neighbours. The full name stays in the `title` attribute. */
.ent-title {
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-decoration: none;
}
a.ent-title:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
a.ent-title:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.ent-card.is-muted .ent-title { color: var(--text-muted); }

/* Second line: plain text, parts separated by "·". A status leads with its dot. */
.ent-meta {
    margin: 0;
    font-size: 12.5px;
    line-height: 20px;
    color: var(--text-muted);
    /* Also one line: nothing wraps, so the status dot can never be torn off its
       word onto a line of its own, and the row keeps the same height in every
       card. What does not fit is cut with an ellipsis. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ent-meta .ent-sep { color: var(--text-subtle); padding-inline: 6px; }
.ent-meta .is-empty { color: var(--text-subtle); font-style: italic; }
/* A URL or a port: mono so it reads as a technical value. It needs no wrapping
   rule of its own any more — the line never wraps, it is cut. */
.ent-meta .is-mono { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: 12px; }
.ent-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--text-subtle);
    vertical-align: 1px;
}
.ent-dot[data-dot="ok"] { background: var(--toggle-on); }
.ent-dot[data-dot="warn"] { background: var(--warning); }
.ent-dot[data-dot="bad"] { background: var(--danger); }

.ent-act { grid-area: act; display: flex; align-items: center; gap: 4px; }

/* One icon button. "On" is the app's amber — the colour of a lit indicator. */
.ent-ia {
    width: 32px;
    height: 32px;
    padding: 0;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
.ent-ia:hover { border-color: var(--border-strong); background: var(--bg-subtle); color: var(--text); }
.ent-ia:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.ent-ia.is-on, .ent-ia.is-on:hover { border-color: var(--warning); background: var(--warning-bg); color: var(--warning); }
.ent-menu-btn { border-color: transparent; }
.ent-menu-btn:hover, .ent-menu-btn[aria-expanded="true"] { border-color: var(--border); background: var(--bg-subtle); color: var(--text); }

/* Desktop "⋯" dropdown. Lives in <body> and is anchored to the viewport by
   entity-card.js, so nothing can clip it — the same menu opens from a card and
   from a row of the sources table, and that table scrolls. */
.ent-menu {
    position: fixed;
    z-index: 130;
    min-width: 210px;
    padding: 6px;
    display: grid;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: var(--shadow-dropdown);
    animation: entMenuIn 0.12s ease-out;
}
@keyframes entMenuIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.ent-menu-item, .ent-sheet-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 10px;
    border: none;
    border-radius: 4px;
    background: transparent;
    font-family: inherit;
    font-size: 13px;
    color: var(--text);
    text-align: left;
    cursor: pointer;
    transition: background-color 0.12s ease;
}
.ent-menu-item svg, .ent-sheet-item svg { width: 16px; height: 16px; flex: none; color: var(--text-muted); }
.ent-menu-item:hover, .ent-sheet-item:hover,
.ent-menu-item:focus-visible, .ent-sheet-item:focus-visible { background: var(--bg-subtle); outline: none; }
.ent-menu-item.is-danger, .ent-sheet-item.is-danger,
.ent-menu-item.is-danger svg, .ent-sheet-item.is-danger svg { color: var(--danger); }
.ent-menu-item.is-danger:hover, .ent-sheet-item.is-danger:hover { background: var(--danger-bg); }
.ent-menu-sep { height: 1px; margin: 4px -6px; background: var(--border); }

/* Phone: the same menu as a bottom sheet — grab bar, card title, big rows. */
.ent-sheet-backdrop {
    position: fixed;
    inset: 0;
    z-index: 120;
    background: rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity 0.22s ease;
}
html[data-theme="dark"] .ent-sheet-backdrop { background: rgba(0, 0, 0, 0.6); }
.ent-sheet-backdrop.open { opacity: 1; }
.ent-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 121;
    display: grid;
    max-height: 70vh;
    overflow-y: auto;
    padding: 6px 10px max(16px, calc(16px + env(safe-area-inset-bottom)));
    background: var(--bg-elevated);
    border-top: 1px solid var(--border);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -4px 28px rgba(0, 0, 0, 0.18);
    transform: translateY(100%);
    transition: transform 0.24s cubic-bezier(0.2, 0.8, 0.25, 1);
}
.ent-sheet.open { transform: translateY(0); }
.ent-sheet-grab {
    width: 36px;
    height: 4px;
    margin: 6px auto 10px;
    border-radius: 2px;
    background: var(--border-strong);
}
.ent-sheet-title {
    margin: 0 -10px 6px;
    padding: 0 20px 10px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    border-bottom: 1px solid var(--border);
}
.ent-sheet-item { min-height: 46px; padding: 0 12px; gap: 12px; font-size: 15px; border-radius: 8px; }
.ent-sheet-item svg { width: 18px; height: 18px; }

/* Delete and other loud actions: the whole card turns red and keeps its title,
   so what is about to go is still on screen. */
.ent-card.is-confirm {
    background: var(--danger-bg);
    border-color: var(--danger);
    box-shadow: none;
    cursor: default;
}
.ent-card.is-confirm .ent-ask {
    margin: 0;
    font-size: 12.5px;
    line-height: 20px;
    color: var(--danger);
}
/* Turning into a confirm must not resize the card: title, details and question
   are each one line, so the card is the same box in both states and across the
   whole list, whatever the text. The min-height holds the row on a card whose
   details are empty. */
.ent-meta,
.ent-card.is-confirm .ent-ask {
    min-height: 20px;
}
.ent-card.is-confirm .ent-ask {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ent-btn {
    height: 32px;
    padding: 0 12px;
    flex: none;
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-elevated);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
}
.ent-btn:hover { border-color: var(--border-strong); }
.ent-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.ent-btn.is-danger-solid {
    background: var(--danger);
    border-color: var(--danger);
    color: var(--bg-elevated);
}
.ent-btn.is-danger-solid:hover { filter: brightness(1.08); }

/* Skeleton — a card-shaped placeholder. */
.ent-card.is-skel { box-shadow: none; cursor: default; }
.ent-skel { display: block; height: 10px; border-radius: 4px; background: var(--bg-subtle); }
.ent-skel.is-title { width: 46%; height: 12px; }
.ent-skel.is-meta { width: 70%; }
.ent-skel.is-btn { width: 32px; height: 32px; border-radius: 4px; }
@media (prefers-reduced-motion: no-preference) {
    .ent-skel {
        background: linear-gradient(90deg, var(--bg-subtle) 0%, var(--border) 50%, var(--bg-subtle) 100%);
        background-size: 200% 100%;
        animation: entSkel 1.4s ease-in-out infinite;
    }
    @keyframes entSkel { to { background-position: -200% 0; } }
}
