/* ============================================================
   DS atomic catalog — styles for Components/Ds/* and the
   /_dev/ds gallery page.

   Loaded via a plain <link> in index.html (not Blazor scoped CSS)
   because scoped CSS emission in this WASM project has been
   unreliable — see PersonBalanceRow.razor.css comment.
   ============================================================ */


/* ---------- EtButton ---------- */
.et-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    border: 0;
    border-radius: 999px;
    font-family: var(--et-font-family-base);
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    transition: transform .14s, filter .14s, box-shadow .14s;
}
.et-btn:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
/* Design stateMap: disabled drops every shadow (incl. outline/danger inset rings). */
.et-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    box-shadow: none;
}
.et-btn--block { display: flex; width: 100%; }

/* Sizes — md padding is per-variant in the dc map:
   tonal/outline 11px 18px, ghost 10px 14px, all others 12px 20px.
   sm is always 9px 14px at 12.5px. */
.et-btn--md { padding: 12px 20px; font-size: 14px; }
.et-btn--sm { padding: 9px 14px;  font-size: 12.5px; }
.et-btn--md.et-btn--tonal   { padding: 11px 18px; }
.et-btn--md.et-btn--outline { padding: 11px 18px; }
.et-btn--md.et-btn--ghost   { padding: 10px 14px; }

.et-btn-icon { font-size: 15px; line-height: 1; }

/* Primary — plum CTA gradient; token pair matches the design's rest/hover shadows. */
.et-btn--primary {
    background: var(--et-cta-gradient);
    color: #fff;
    box-shadow: var(--et-cta-shadow);
}
.et-btn--primary:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: var(--et-cta-shadow-hover);
}
.et-btn--primary:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}

.et-btn--secondary {
    background: var(--et-color-surface-2);
    color: var(--et-color-ink);
}
.et-btn--secondary:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
}
.et-btn--secondary:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}

.et-btn--success {
    background: var(--et-color-owed);
    color: #fff;
    box-shadow: 0 4px 14px rgba(21, 118, 74, 0.30);
}
.et-btn--success:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(21, 118, 74, 0.38);
}
.et-btn--success:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}

/* Tonal — translucent white overlay fill (design literal, no token). */
.et-btn--tonal {
    background: rgba(255, 255, 255, 0.75);
    color: var(--et-color-ink);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.et-btn--tonal:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
}
.et-btn--tonal:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}

.et-btn--outline {
    background: transparent;
    color: var(--et-color-accent);
    box-shadow: inset 0 0 0 1.5px var(--et-color-accent);
}
.et-btn--outline:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: inset 0 0 0 1.5px var(--et-color-accent), 0 3px 10px rgba(0, 0, 0, 0.10);
}
.et-btn--outline:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: inset 0 0 0 1.5px var(--et-color-accent);
}

.et-btn--ghost {
    background: transparent;
    color: var(--et-color-ink-2);
}
.et-btn--ghost:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
}
.et-btn--ghost:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
}

/* Dark — ink fill with surface text so the variant inverts (stays high-contrast)
   in dark mode; design literals are #1A1917 / #fff. */
.et-btn--dark {
    background: var(--et-color-ink);
    color: var(--et-color-surface);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
}
.et-btn--dark:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.26);
}
.et-btn--dark:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}

/* Danger — outlined destructive (surface fill + owe ring/text). */
.et-btn--danger {
    background: var(--et-color-surface);
    color: var(--et-color-owe);
    box-shadow: inset 0 0 0 1.5px var(--et-color-owe);
}
.et-btn--danger:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: inset 0 0 0 1.5px var(--et-color-owe), 0 3px 10px rgba(196, 57, 45, 0.12);
}
.et-btn--danger:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: inset 0 0 0 1.5px var(--et-color-owe);
}

/* Danger-solid — hover shadow is the dc script's neutral fallthrough
   (0 3px 10px black), not a red one; replicated faithfully. */
.et-btn--danger-solid {
    background: var(--et-color-owe);
    color: #fff;
    box-shadow: 0 6px 16px rgba(196, 57, 45, 0.30);
}
.et-btn--danger-solid:hover:not(:disabled) {
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
}
.et-btn--danger-solid:active:not(:disabled) {
    filter: brightness(0.94);
    transform: translateY(0);
    box-shadow: none;
}


/* ---------- EtIconButton ---------- */
.et-icon-btn {
    position: relative;
    display: grid;
    place-items: center;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background: var(--et-color-surface-2);
    cursor: pointer;
    transition: background .14s, transform .14s;
    flex-shrink: 0;
}
/* Hover/active disc tints are design literals — no hover/active surface token exists yet. */
.et-icon-btn:hover:not(:disabled) { background: #E6E2D8; }
.et-icon-btn:active:not(:disabled) {
    background: #DCD7CC;
    transform: scale(0.95);
}
.et-icon-btn:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.et-icon-btn-emoji { line-height: 1; }
.et-icon-btn-badge {
    position: absolute;
    top: -1px;
    right: -1px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--et-color-owe);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    display: grid;
    place-items: center;
    /* Design says 2px solid #fff — mapped to surface so the ring tracks dark mode. */
    border: 2px solid var(--et-color-surface);
    line-height: 1;
    font-family: var(--et-font-family-base);
}


/* ---------- EtSurface (design: Card) ---------- */
/* Root class stays .et-surface — .et-card is owned by legacy app.css. */
.et-surface {
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-md);
    box-shadow: var(--et-shadow-card);
    border: 1px solid transparent;
    padding: 12px;
    transition: box-shadow .18s;
    font-family: var(--et-font-family-base);
    /* Query container for the rows inside. Atoms branch on the width of the
       card holding them rather than on the viewport, so the same row is
       correct on a phone, in a docked panel and in the group view's narrow
       right column — and the gallery specimen can show the branch instead of
       only asserting it. Inline-size containment only: the height still
       follows the content. */
    container-type: inline-size;
}
/* Form variant — radius 13 kept literal (design says 13, no token). */
.et-surface--form {
    border-radius: 13px;
    box-shadow: none;
    border: 1px solid var(--et-color-border);
    padding: 4px 15px;
}
.et-surface-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 6px 8px;
}
.et-surface--form .et-surface-header { padding: 10px 0 6px; }
.et-surface-title {
    font-size: 15px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-surface-count {
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-3);
}
.et-surface-link {
    border: 0;
    background: none;
    padding: 0;
    font-family: var(--et-font-family-base);
    font-size: 12.5px;
    font-weight: 700;
    color: var(--et-color-accent);
    cursor: pointer;
}
.et-surface-link:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtAvatar ---------- */
.et-avatar {
    border-radius: 50%;
    color: #fff;
    display: grid;
    place-items: center;
    font-family: var(--et-font-family-base);
    font-weight: 600;
    flex-shrink: 0;
}
/* Tone gradients are fixed identity colors (dc values verbatim) — kept
   literal so avatars stay recognizable across palettes and dark mode. */
.et-avatar--plum    { background: linear-gradient(135deg, #9c6dab, #7A4E7A); }
.et-avatar--rose    { background: linear-gradient(135deg, #e088b8, #c94f95); }
.et-avatar--green   { background: linear-gradient(135deg, #5cb985, #2e8b5c); }
.et-avatar--blue    { background: linear-gradient(135deg, #5b9bd5, #2e6db5); }
.et-avatar--mustard { background: linear-gradient(135deg, #f0b362, #d68f2e); }
/* Sand — flat neutral for unbound gift recipients. Identity tone like the
   gradients above, so bg #ECEAE3 / fg #8F8C83 stay literal (dc values). */
.et-avatar--sand    { background: #ECEAE3; color: #8F8C83; }


/* ---------- EtPill ---------- */
.et-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border-radius: 999px;
    font-family: var(--et-font-family-base);
    white-space: nowrap;
}
.et-pill-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
/* owed/owe backgrounds stay literal — no status-bg token for them yet. */
.et-pill--group   { background: var(--et-color-surface-2);   color: var(--et-color-ink-2);  font-weight: 600; padding: 4px 10px; font-size: 11px; }
.et-pill--owed    { background: #e7f4ec;                     color: var(--et-color-owed);   font-weight: 700; padding: 4px 11px; font-size: 12px; }
.et-pill--owe     { background: #fbebe8;                     color: var(--et-color-owe);    font-weight: 700; padding: 4px 11px; font-size: 12px; }
.et-pill--pending { background: var(--et-status-bg-pending); color: var(--et-color-pend);   font-weight: 700; padding: 4px 11px; font-size: 12px; }
.et-pill--sent    { background: var(--et-status-bg-sent);    color: var(--et-color-sent);   font-weight: 700; padding: 4px 11px; font-size: 12px; }
.et-pill--count   { background: transparent;                 color: var(--et-color-ink-3);  font-weight: 500; padding: 0;        font-size: 12px; }
.et-pill--neutral { background: var(--et-status-bg-logged);  color: var(--et-color-neutral);font-weight: 700; padding: 4px 11px; font-size: 12px; }
.et-pill--primary { background: var(--et-color-accent);      color: #fff;                   font-weight: 700; padding: 4px 11px; font-size: 12px; }


/* ---------- EtSectionHeader ---------- */
.et-section-header {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 12px;
    font-family: var(--et-font-family-base);
    /* No container-type here on purpose. Unlike EtGroupHeader (which owns its
       band and can safely become a container), a section header is a bare
       title row that callers drop straight into a page column — it does not
       control the box around it. It shares an ancestor with EtActivityRow:
       .et-surface (and the gallery's .ds-specimen-desktop/-phone) already set
       container-type: inline-size, so the narrow-link branch below rides
       that. A header with no such ancestor simply never matches the query
       and keeps the full label — the right default for an unknown box. */
}
.et-section-header-title {
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--et-color-ink);
}
.et-section-header-count {
    font-size: 12px;
    font-weight: 500;
    color: var(--et-color-ink-3);
}
.et-section-header-link {
    margin-left: auto;
    color: var(--et-color-accent);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    /* The whole point of the short form: once it can win, the arrow must
       never be the one glyph that wraps onto its own line. */
    white-space: nowrap;
}
/* Hover color stays literal — dc says #5B3E6E (deep plum), no token. */
.et-section-header-link:hover { color: #5B3E6E; }
.et-section-header-link:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
/* Both labels are in the DOM; exactly one is display:none at any container
   width, so the hidden one is genuinely gone — no tab stop, no accessibility
   node, no screen reader reading "Korábbi költségek → Korábbiak →" back to
   back. Full is the one shown by default (see the no-container-type note
   above): a header outside any @container ancestor must still read in full. */
.et-section-header-link-short { display: none; }
/* Same 480px threshold as EtGroupHeader/EtActivityRow — one narrow-box
   breakpoint for the whole DS rather than three that drift apart. */
@container (max-width: 480px) {
    .et-section-header-link-full { display: none; }
    .et-section-header-link-short { display: inline; }
}


/* ---------- EtEmptyState ---------- */
.et-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 34px 26px;
    font-family: var(--et-font-family-base);
}
/* Circle fill + inset ring are decorative — dc literals kept on purpose. */
.et-empty-circle {
    position: relative;
    width: 74px;
    height: 74px;
    margin-bottom: 16px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 40%, #F3E8F3, #EDE6EF);
    box-shadow: inset 0 0 0 1px rgba(122, 78, 122, 0.10);
}
.et-empty-emoji { font-size: 34px; line-height: 1; }
.et-empty-title {
    font-size: 16px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
    margin-bottom: 5px;
}
.et-empty-message {
    font-size: 13px;
    color: var(--et-color-ink-2);
    font-weight: 500;
    max-width: 300px;
    line-height: 1.5;
}
.et-empty-cta {
    padding: 11px 20px;
    border: 0;
    border-radius: 12px;
    background: var(--et-cta-gradient);
    color: #fff;
    font-family: var(--et-font-family-base);
    font-weight: 700;
    font-size: 13px;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(122, 78, 122, 0.32);
    transition: transform .14s, filter .14s;
}
.et-empty-cta:hover { filter: brightness(1.06); transform: translateY(-1px); }
.et-empty-cta:active { filter: brightness(0.93); transform: translateY(0); }
.et-empty-cta:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}

/* ---------- EtEmptyState — Card variant ----------
   The in-card form: full-bleed illustration left, text right. The Hero above
   spends 34px of padding and a 74px circle on its own, which is ~207px of
   surface for a two-word "Minden rendezve" — and the phone canvas pays that
   several times per scroll. This lands on 172px, the height of the EtTodoCard
   it sits beside on the desktop Home row, and drops to content height on a
   phone where nothing is beside it to match.

   Reach for it whenever the empty state sits inside a section the user is
   scrolling PAST; keep the Hero when the empty state IS the screen. */
.et-empty-text { display: contents; }
.et-empty--card {
    flex-direction: row;
    align-items: stretch;
    text-align: left;
    padding: 0;
    /* Own radius + clip so the art can bleed into the corners. A caller that
       gives its EtSurface Pad="0" gets a true full-bleed card (the two radii
       coincide); one that leaves the surface padded gets an inset tile, which
       is the right read when the empty state shares the card with other
       content. */
    border-radius: var(--et-card-radius-md);
    overflow: hidden;
    min-height: 172px;
}
.et-empty--card .et-empty-art {
    flex: 0 0 40%;
    /* The library art is 240x160; cover crops rather than letterboxes it, and
       the compositions all keep their subject centred so the crop is safe. */
    position: relative;
    min-width: 0;
}
.et-empty--card .et-empty-art img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.et-empty--card .et-empty-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    /* Flex items floor at min-content; without this a long title refuses to
       shrink and pushes the row wider than the card. */
    min-width: 0;
    padding: 16px 18px;
    gap: 2px;
}
.et-empty--card .et-empty-title { margin-bottom: 0; }
.et-empty--card .et-empty-message { max-width: none; }
/* The message div always renders so the Hero form's spacing is untouched;
   here an empty one would still spend the column gap. */
.et-empty--card .et-empty-message:empty { display: none; }
.et-empty--card .et-empty-cta { margin-top: 12px; }

/* Phone: nothing sits beside the card, so the todo-card height it was
   matching stops being a reason to be tall. The art keeps a slightly larger
   share because the whole card is narrower. */
@media (max-width: 767.98px) {
    .et-empty--card { min-height: 116px; }
    .et-empty--card .et-empty-art { flex-basis: 38%; }
    .et-empty--card .et-empty-text { padding: 14px 16px; }
}


/* ---------- EtChip ---------- */
.et-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
    border: 0;
    background: none;
    padding: 0;
    font-family: var(--et-font-family-base);
    cursor: pointer;
}
.et-chip-emoji { font-size: 13px; line-height: 1; }
.et-chip--quickadd {
    background: var(--et-color-surface-2);
    border-radius: 999px;
    padding: 5px 11px;
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink);
    transition: background-color .15s;
}
.et-chip--quickadd:hover { background-color: #E6E2D8; } /* no token — cf. EtIconButton hover */
.et-chip--link {
    color: var(--et-color-accent);
    font-size: 12px;
    font-weight: 600;
    padding: 5px 6px;
}
.et-chip--suggest {
    border: 1.5px solid var(--et-color-accent);
    color: var(--et-color-accent);
    border-radius: 999px;
    padding: 6px 13px;
    font-size: 12.5px;
    font-weight: 700;
    transition: background-color .15s;
}
.et-chip--suggest:hover { background-color: rgba(122, 78, 122, 0.07); }
.et-chip--filter {
    border: 1.5px solid var(--et-color-accent);
    color: var(--et-color-accent);
    border-radius: 999px;
    padding: 7px 15px;
    font-size: 12.5px;
    font-weight: 700;
    transition: background-color .15s;
}
.et-chip--filter:hover { background-color: rgba(122, 78, 122, 0.07); }
.et-chip--filter.et-chip--active {
    background: var(--et-color-accent);
    color: #fff;
    box-shadow: 0 3px 10px rgba(122, 78, 122, 0.28);
}
.et-chip--filter.et-chip--active:hover { background-color: var(--et-color-accent); }
.et-chip:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtInfoBanner ----------
   Severity palettes are design literals (light-authored banner set,
   no semantic tokens for the tinted fg/border pairs yet). */
.et-info-banner {
    --etib-bg: #EDF2F7;
    --etib-border: #CBD9E6;
    --etib-fg: #44607A;
    background: var(--etib-bg);
    border: 1px solid var(--etib-border);
    border-radius: 14px;
    padding: 14px 16px;
    font-family: var(--et-font-family-base);
}
.et-info-banner--success { --etib-bg: #E7F4EC; --etib-border: #BFE0CC; --etib-fg: #15764A; }
.et-info-banner--warning { --etib-bg: #FBEFD7; --etib-border: #E8C877; --etib-fg: #6B5A2E; }
.et-info-banner--error   { --etib-bg: #F9E5E3; --etib-border: #E5B0A8; --etib-fg: #A63528; }
.et-info-banner-text {
    font-size: 13px;
    color: var(--etib-fg);
    line-height: 1.5;
}
/* Row so a second action (e.g. the /invite copy-link escape hatch) sits
   beside the primary one and wraps on narrow banners. */
.et-info-banner-actions {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.et-info-banner-action {
    display: inline-flex;
    align-items: center;
    background: rgba(255, 255, 255, 0.65);
    border: 1px solid var(--etib-border);
    color: var(--etib-fg);
    border-radius: 999px;
    padding: 7px 14px;
    font-size: 12.5px;
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    transition: background-color .15s;
}
.et-info-banner-action:hover { background-color: rgba(255, 255, 255, 0.95); }
.et-info-banner-action:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtToast ----------
   Floating overlay authored on strong fills — severity colors stay
   literal (white text on saturated bg in both themes). */
.et-toast {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    background: #44607A;
    color: #fff;
    border-radius: 12px;
    padding: 12px 16px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.22);
    font-family: var(--et-font-family-base);
    max-width: 420px;
}
.et-toast--success { background: #15764A; }
.et-toast--warning { background: #B7791F; }
.et-toast--error   { background: #C4392D; }
.et-toast-icon {
    font-size: 14px;
    font-weight: 800;
    flex-shrink: 0;
}
.et-toast-text {
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.4;
}
.et-toast-close {
    border: 0;
    background: none;
    padding: 0;
    color: inherit;
    font-family: inherit;
    font-size: 13px;
    opacity: 0.7;
    cursor: pointer;
    flex-shrink: 0;
    margin-left: 4px;
}
.et-toast-close:hover { opacity: 1; }
.et-toast-close:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* Toast host (Components/Ui/EtToastHost.razor) — what MudSnackbarProvider's
   container used to be. Top-center below 768px so the pills read as floating
   over the page, bottom-right from there up. z-index sits above
   .et-modal-overlay (1500) so a toast fired from a dialog is still visible.
   pointer-events are off on the strip and back on for the pills, so the
   empty gutter never eats a click on the page underneath. */
.et-toast-host {
    position: fixed;
    z-index: 1600;
    top: calc(12px + env(safe-area-inset-top));
    left: 16px;
    right: 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    pointer-events: none;
}
.et-toast-host > * { pointer-events: auto; }
@media (min-width: 768px) {
    .et-toast-host {
        top: auto;
        left: auto;
        right: 24px;
        bottom: 24px;
        align-items: flex-end;
    }
}


/* ---------- EtSkeleton ---------- */
@keyframes et-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .45; }
}
.et-skeleton {
    background: #E9E5DC; /* design literal (sand); darker than surface-2 by intent */
    animation: et-pulse 1.5s ease-in-out infinite;
}
.et-skeleton--text   { border-radius: 6px; }
.et-skeleton--rect   { border-radius: 13px; }
.et-skeleton--circle { border-radius: 50%; }


/* ---------- EtFieldRow ---------- */
.et-field { font-family: var(--et-font-family-base); }
.et-field-attach {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 13px;
    border: 1.5px dashed #D8D4CA; /* dc literal, in-family with border-strong */
    border-radius: 13px;
    color: var(--et-color-ink-2);
    font-weight: 600;
    font-size: 13px;
    cursor: pointer;
    transition: background-color .15s;
}
.et-field-attach:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-field-attach-emoji { font-size: 16px; }
.et-field-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 15px;
    background: var(--et-color-surface);
    border-radius: 13px;
    border: 1px solid var(--et-color-border);
    cursor: pointer;
    transition: box-shadow .15s, border-color .15s;
}
.et-field-card--with-avatar { padding: 12px 14px; }
.et-field-card--input { cursor: text; }
.et-field-card--locked {
    background: var(--et-color-surface-2);
    border-color: transparent;
    cursor: default;
}
.et-field-card--focus {
    border: 1.5px solid var(--et-color-accent);
    box-shadow: 0 0 0 3px rgba(122, 78, 122, 0.15);
}
.et-field-card--error {
    border: 1.5px solid var(--et-color-owe);
    box-shadow: 0 0 0 3px rgba(196, 57, 45, 0.10);
}
.et-field-card--picker:not(.et-field-card--focus):not(.et-field-card--error):hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.et-field-body { flex: 1; min-width: 0; }
.et-field-label {
    font-size: 11px;
    color: var(--et-color-ink-2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.et-field-value {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    display: flex;
    align-items: center;
    gap: 7px;
}
.et-field-label + .et-field-value { margin-top: 2px; }
.et-field-value--empty {
    color: var(--et-color-ink-3);
    font-weight: 500;
}
.et-field-image {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    overflow: hidden;
    flex-shrink: 0;
}
.et-field-image img { width: 100%; height: 100%; object-fit: cover; }
.et-field-emoji { font-size: 15px; }
.et-field-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.et-field-value-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-field-chevron {
    color: var(--et-color-ink-3);
    font-size: 18px;
    flex-shrink: 0;
}
/* Dropdown-trigger chevron (▾/▴) — the triangle glyphs read heavier than
   the navigation ›, so they step down a size. */
.et-field-chevron--dd { font-size: 13px; }
.et-field-lock {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    color: var(--et-color-ink-3);
    font-weight: 600;
    flex-shrink: 0;
}
.et-field-error {
    font-size: 11.5px;
    color: var(--et-color-owe);
    font-weight: 600;
    margin: 6px 2px 0;
}
/* Editable rows compose .et-field-card markup with a real input styled
   like the value text (used by the expense form's input/date fields). */
.et-field-input {
    width: 100%;
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    outline: none;
}
.et-field-input::placeholder {
    color: var(--et-color-ink-3);
    font-weight: 500;
}


/* ---------- EtMiniInput ---------- */
.et-mini-input {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--et-font-family-base);
}
.et-mini-input-label {
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-weight: 600;
}
.et-mini-input-box {
    display: flex;
    align-items: baseline;
    gap: 4px;
    background: var(--et-color-bg);
    border: 1.5px solid var(--et-color-border-strong);
    border-radius: 9px;
    padding: 7px 12px;
    cursor: text;
}
.et-mini-input-field {
    min-width: 2ch;
    border: 0;
    background: none;
    outline: none;
    padding: 0;
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    text-align: center;
}
.et-mini-input-suffix {
    font-size: 12.5px;
    color: var(--et-color-ink-2);
}
.et-mini-input-remove {
    border: 0;
    background: none;
    padding: 0;
    color: var(--et-color-ink-3);
    font-family: inherit;
    font-size: 14px;
    cursor: pointer;
}
.et-mini-input-remove:hover { color: var(--et-color-owe); }
.et-mini-input-remove:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtCheckRow ---------- */
.et-check-row {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--et-font-family-base);
}
/* Mud's bare `button { justify-content:center }` matches this too — the
   centering is wanted here, but declare it so the atom doesn't depend on
   the Mud sheet surviving the migration. */
.et-check-row-box {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: 7px;
    border: 1.6px solid var(--et-color-border-strong);
    background: var(--et-color-surface);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    color: #fff;
    cursor: pointer;
}
.et-check-row-box--on {
    background: var(--et-color-accent);
    border-color: var(--et-color-accent);
}
.et-check-row-box:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-check-row-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    cursor: pointer;
}
.et-check-row-hint {
    font-size: 12px;
    color: var(--et-color-ink-3);
}


/* ---------- EtAmountInput ---------- */
.et-amount-input {
    text-align: center;
    font-family: var(--et-font-family-base);
}
.et-amount-input-label {
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 6px;
}
.et-amount-input-box {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    border-bottom: 2.5px solid var(--et-color-accent);
    padding: 4px 20px 9px;
    cursor: text;
}
.et-amount-input-num {
    border: 0;
    background: none;
    padding: 0;
    min-width: 1ch;
    font-family: inherit;
    font-size: 48px;
    font-weight: 800;
    letter-spacing: -0.04em;
    color: var(--et-color-ink);
    text-align: right;
    outline: none;
}
.et-amount-input-num::placeholder { color: #C4C0B8; } /* dc literal — muted zero */
.et-amount-input-caret {
    font-size: 46px;
    font-weight: 200;
    color: var(--et-color-accent);
    margin: 0 -2px;
    animation: et-caret-blink 1.1s steps(1) infinite;
}
@keyframes et-caret-blink {
    0%, 49% { opacity: 1; }
    50%, 100% { opacity: 0; }
}
.et-amount-input-currency {
    font-size: 24px;
    color: var(--et-color-ink-3);
    font-weight: 700;
}


/* ---------- EtSegmentedControl ---------- */
.et-segmented {
    display: flex;
    background: var(--et-color-surface-2);
    border-radius: 12px;
    padding: 4px;
    gap: 2px;
    font-family: var(--et-font-family-base);
}
.et-segmented-item {
    flex: 1;
    text-align: center;
    padding: 8px;
    border: 0;
    background: none;
    border-radius: 9px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink-2);
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s, color .15s;
}
.et-segmented-item--active {
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.et-segmented-item:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtCategoryPicker ---------- */
.et-category-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-family: var(--et-font-family-base);
}
.et-category-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 13px;
    border: 0;
    border-radius: 999px;
    background: var(--et-color-surface-2);
    color: var(--et-color-ink-2);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s, color .15s, box-shadow .15s;
}
.et-category-chip:hover:not(.et-category-chip--selected) { background: #E6E2D8; }
.et-category-chip--selected {
    background: var(--et-color-accent);
    color: #fff;
    font-weight: 700;
    box-shadow: 0 2px 8px rgba(122, 78, 122, 0.30);
}
.et-category-chip-emoji { font-size: 14px; line-height: 1; }
.et-category-chip:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtPayMethodPicker ---------- */
.et-paymethod {
    display: flex;
    gap: 8px;
    font-family: var(--et-font-family-base);
}
.et-paymethod-item {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 11px;
    border-radius: 11px;
    background: var(--et-color-surface);
    border: 1px solid var(--et-color-border);
    color: var(--et-color-ink-2);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s, color .15s;
}
.et-paymethod-item--active {
    /* dc: #1A1917 / #fff — ink/surface tokens so dark mode inverts
       (same mapping as .et-btn--dark) */
    background: var(--et-color-ink);
    border-color: transparent;
    color: var(--et-color-surface);
}
.et-paymethod-item:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtEmojiGrid ---------- */
/* auto-fill sizes the column count off the box itself instead of a fixed 8,
   with a 44px minmax floor for touch size. A fixed 8-column grid forced a
   44px min-height onto cells that had shrunk to ~36-38px of width on a
   narrow surface (~330-350px track at 390px), which read as squished
   rectangles rather than squares. aspect-ratio now keeps every cell square
   at whatever width auto-fill lands on, so the min-height crutch is gone. */
.et-emoji-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
    gap: 8px;
    font-family: var(--et-font-family-base);
}
.et-emoji-cell {
    width: 100%;
    aspect-ratio: 1 / 1;
    border: 0;
    padding: 0;
    border-radius: 11px;
    display: grid;
    place-items: center;
    font-size: 20px;
    background: var(--et-color-surface);
    box-shadow: inset 0 0 0 1px var(--et-color-border);
    cursor: pointer;
    transition: background .15s, box-shadow .15s;
}
.et-emoji-cell:hover:not(.et-emoji-cell--selected) { background: #F5F2EB; }
.et-emoji-cell--selected {
    background: var(--et-color-accent);
    box-shadow: 0 2px 8px rgba(122, 78, 122, 0.30);
}
.et-emoji-cell:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtColorSwatches ---------- */
.et-swatches {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    font-family: var(--et-font-family-base);
}
.et-swatch {
    width: 44px;
    height: 44px;
    border: 0;
    padding: 0;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.08);
    transition: box-shadow .15s;
}
.et-swatch--selected {
    box-shadow: inset 0 0 0 3px var(--et-color-surface), 0 0 0 3px var(--et-color-ink);
}
.et-swatch:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-swatch-custom {
    background: conic-gradient(from 210deg, #E5484D, #FFB224, #F5D90A, #46A758, #0EA5E9, #7C3AED, #D6409F, #E5484D);
    display: grid;
    place-items: center;
    position: relative;
}
.et-swatch-custom-dot {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 15px;
    font-weight: 600;
    color: #1A1917; /* dc literal — "+" glyph on the white core */
    line-height: 1;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
.et-swatch-custom-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}


/* ---------- EtGroupPicker ---------- */
.et-group-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-family: var(--et-font-family-base);
}
.et-group-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--et-color-surface-2);
    border: 1.5px solid transparent;
    border-radius: 999px;
    color: var(--et-color-ink-2);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color .15s, color .15s, background .15s;
}
.et-group-chip:hover:not(.et-group-chip--selected) { background: #E6E2D8; }
.et-group-chip--selected {
    border-color: var(--et-color-accent);
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-group-chip-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.et-group-chip:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtAmountDisplay ---------- */
.et-amount-display {
    text-align: center;
    font-family: var(--et-font-family-base);
}
.et-amount-display-label {
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 6px;
}
.et-amount-display-num {
    font-size: 46px;
    font-weight: 800;
    letter-spacing: -0.04em;
    color: var(--et-color-ink);
}
.et-amount-display-num--md { font-size: 40px; }
.et-amount-display-num--green { color: var(--et-color-owed); }
.et-amount-display-num--red { color: var(--et-color-owe); }
.et-amount-display-currency {
    font-size: 22px;
    color: var(--et-color-ink-3);
}


/* ---------- EtMetaItem ---------- */
.et-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-family: var(--et-font-family-base);
    white-space: nowrap;
}
.et-meta-item-image {
    width: 18px;
    height: 18px;
    border-radius: 4px;
    object-fit: cover;
}
.et-meta-item-emoji {
    font-size: 13px;
    line-height: 1;
}


/* ---------- EtDonutChart ---------- */
.et-donut-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: var(--et-font-family-base);
}
.et-donut {
    border-radius: 50%;
    display: grid;
    place-items: center;
}
.et-donut-hole {
    width: 62%;
    height: 62%;
    border-radius: 50%;
    background: var(--et-color-bg);
    display: grid;
    place-items: center;
    text-align: center;
}
.et-donut-center-label {
    font-size: 9px;
    color: var(--et-color-ink-3);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.et-donut-center-value {
    font-size: 15px;
    font-weight: 800;
    color: var(--et-color-ink);
}
.et-donut-caption {
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-weight: 600;
}


/* ---------- EtLinkCard ---------- */
.et-link-card {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 10px 13px;
    background: var(--et-color-surface);
    border: 1px solid var(--et-color-border);
    border-radius: 12px;
    font-family: var(--et-font-family-base);
    cursor: pointer;
    text-align: left;
    transition: box-shadow .15s;
}
.et-link-card:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); }
.et-link-card-image {
    width: 30px;
    height: 30px;
    border-radius: 9px;
    overflow: hidden;
    flex-shrink: 0;
}
.et-link-card-image img { width: 100%; height: 100%; object-fit: cover; }
.et-link-card-emoji {
    width: 30px;
    height: 30px;
    border-radius: 9px;
    background: var(--et-color-surface-2);
    display: grid;
    place-items: center;
    font-size: 15px;
    flex-shrink: 0;
}
.et-link-card-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-link-card-kind {
    font-size: 11px;
    color: var(--et-color-ink-3);
    flex-shrink: 0;
}
.et-link-card:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtTimelineStep ----------
   Disc fills are the dc's 8-digit-hex alpha tints of the semantic colors
   (no alpha tokens exist) — fg uses the matching semantic token. */
.et-timeline-step {
    display: flex;
    gap: 12px;
    font-family: var(--et-font-family-base);
}
.et-timeline-rail {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.et-timeline-disc {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: #6b68601f;
    color: var(--et-color-ink-2);
    display: grid;
    place-items: center;
    font-size: 14px;
    flex-shrink: 0;
}
.et-timeline-disc--blue  { background: #1B5CFF1f; color: var(--et-color-sent); }
.et-timeline-disc--green { background: #15764A1f; color: var(--et-color-owed); }
.et-timeline-disc--red   { background: #C4392D1a; color: var(--et-color-owe); }
.et-timeline-line {
    width: 2px;
    flex: 1;
    background: var(--et-color-border);
    margin: 2px 0;
}
.et-timeline-body {
    padding-bottom: 18px;
    flex: 1;
}
.et-timeline-body--last { padding-bottom: 0; }
.et-timeline-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-timeline-time {
    font-size: 11px;
    color: var(--et-color-ink-3);
    margin-top: 2px;
}


/* ---------- EtMemberRow ---------- */
.et-member-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    cursor: pointer;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-member-row:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-member-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-member-row-body { flex: 1 1 auto; min-width: 0; }
.et-member-row-name-line {
    display: flex;
    align-items: center;
    gap: 8px;
}
.et-member-row-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex-shrink: 1;
    min-width: 0;
}
.et-member-row-admin {
    flex-shrink: 0;
    font-size: 12.5px;
    font-weight: 500;
    color: #9C998F; /* dc literal */
}
.et-member-row-sub {
    font-size: 12px;
    color: var(--et-color-ink-2);
    margin-top: 1px;
}
.et-member-row-you {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    padding: 4px 11px;
    border-radius: 999px;
    border: 1.5px solid var(--et-color-accent);
    color: var(--et-color-accent);
}
.et-member-row-menu {
    border: 0;
    background: none;
    padding: 0;
    color: var(--et-color-ink-3);
    font-family: inherit;
    font-size: 18px;
    flex-shrink: 0;
    width: 20px;
    text-align: center;
    cursor: pointer;
}
.et-member-row-menu--inert {
    cursor: default;
    opacity: 0.35;
}
.et-member-row-chevron {
    color: #C8C5BD; /* dc literal chevron grey */
    font-size: 20px;
    line-height: 1;
    flex-shrink: 0;
    margin-left: 4px;
}


/* ---------- EtBalanceRow ---------- */
.et-balance-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    cursor: pointer;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-balance-row:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-balance-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-balance-row-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.et-balance-row-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-balance-row-sub {
    font-size: 11px;
    color: var(--et-color-ink-2);
    font-weight: 500;
    line-height: 1.3;
}
.et-balance-row-amount-wrap {
    flex-shrink: 0;
    text-align: right;
}
.et-balance-row-amount {
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.et-balance-row-amount--owed { color: var(--et-color-owed); }
.et-balance-row-amount--owe { color: var(--et-color-owe); }
.et-balance-row-amount--settled { color: var(--et-color-ink-3); }
.et-balance-row-sign { margin-right: 1px; }
.et-balance-row-chevron {
    color: #C8C5BD;
    font-size: 20px;
    line-height: 1;
    flex-shrink: 0;
    margin-left: 4px;
}


/* ---------- EtDebtRow ---------- */
/* Same rhythm as .et-balance-row, minus every interactive affordance: no
   cursor, no hover tint, no chevron. The row is a statement, not a target. */
.et-debt-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    font-family: var(--et-font-family-base);
}
.et-debt-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-debt-row-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.et-debt-row-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-debt-row-sub {
    font-size: 11px;
    color: var(--et-color-ink-2);
    font-weight: 500;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Neutral ink, not owe/owed red-green: the row describes someone else's debt,
   so a viewer-relative tone would be meaningless here. */
.et-debt-row-amount {
    flex-shrink: 0;
    text-align: right;
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    color: var(--et-color-ink);
}


/* ---------- EtCounterpartyRow ---------- */
.et-cparty-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    cursor: pointer;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-cparty-row:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-cparty-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-cparty-row-avatar {
    position: relative;
    flex-shrink: 0;
}
.et-cparty-row-medal {
    position: absolute;
    bottom: -3px;
    right: -3px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 2px solid var(--et-color-surface);
    display: grid;
    place-items: center;
    font-size: 10px;
}
.et-cparty-row-body { flex: 1 1 auto; min-width: 0; }
.et-cparty-row-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-cparty-row-count {
    font-size: 11.5px;
    color: var(--et-color-ink-2);
    font-weight: 500;
}
.et-cparty-row-chevron {
    color: #C8C5BD;
    font-size: 20px;
    line-height: 1;
    flex-shrink: 0;
    margin-left: 4px;
}


/* ---------- EtShareRow ---------- */
.et-share-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    font-family: var(--et-font-family-base);
}
.et-share-row--divider { border-bottom: 1px solid var(--et-color-border); }
/* Current user's own row — a soft accent fill, same tint language as the chip
   hover. -9px of the list surface's 15px inset leaves the block 6px off the card
   edge, so it reads as a contained row rather than a full-bleed band. Mixed off
   --et-color-accent rather than the hardcoded rgba(122, 78, 122, …) used
   elsewhere: that literal is plum, and it disappears on the dark ground and on
   the non-plum palettes. The divider goes — a hairline running into a rounded
   fill reads as a mistake. */
.et-share-row--me {
    margin: 0 -9px;
    padding: 12px 9px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--et-color-accent) 7%, transparent);
    border-bottom-color: transparent;
}
.et-share-row--me .et-share-row-name { font-weight: 700; }
.et-share-row-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-share-row-you {
    color: var(--et-color-ink-3);
    font-weight: 500;
}
.et-share-row-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    flex-shrink: 0;
}
.et-share-row-amount {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
}
.et-share-row-menu {
    border: 0;
    background: none;
    padding: 0;
    color: var(--et-color-ink-3);
    font-family: inherit;
    font-size: 18px;
    width: 20px;
    text-align: center;
    flex-shrink: 0;
    cursor: pointer;
}
.et-share-row-menu--inert {
    cursor: default;
    opacity: 0.35;
}


/* ---------- EtSplitRow ---------- */
.et-split-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 0;
    font-family: var(--et-font-family-base);
}
.et-split-row--divider { border-bottom: 1px solid var(--et-color-border); }
.et-split-row-name {
    flex: 1;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-split-row-eq-amount {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-split-row-eq-amount--off { color: var(--et-color-ink-3); }
.et-split-row-check {
    width: 24px;
    height: 24px;
    border: 0;
    padding: 0;
    border-radius: 7px;
    background: var(--et-color-surface);
    box-shadow: inset 0 0 0 1.5px var(--et-color-border-strong);
    color: #fff;
    font-family: inherit;
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 700;
    flex-shrink: 0;
    cursor: pointer;
}
.et-split-row-check--on {
    background: var(--et-color-accent);
    box-shadow: none;
}
.et-split-row-check:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-split-row-box {
    display: flex;
    align-items: baseline;
    gap: 4px;
    background: var(--et-color-bg);
    border: 1.5px solid var(--et-color-border-strong);
    border-radius: 9px;
    padding: 7px 12px;
    cursor: text;
}
.et-split-row-percent-wrap .et-split-row-box { gap: 3px; padding: 7px 11px; }
.et-split-row-box-value {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-split-row-box-input {
    border: 0;
    background: none;
    padding: 0;
    min-width: 1ch;
    font-family: inherit;
    text-align: right;
    outline: none;
}
.et-split-row-box-unit {
    font-size: 11px;
    color: var(--et-color-ink-3);
    font-weight: 700;
}
.et-split-row-percent-wrap {
    display: flex;
    align-items: center;
    gap: 9px;
}
.et-split-row-percent-amount {
    font-size: 12px;
    color: var(--et-color-ink-2);
    font-weight: 700;
    width: 52px;
    text-align: right;
}


/* ---------- EtActivityRow ----------
   Pastel thumb fills and micro-avatar gradients are dc literals
   (identity colors, palette-independent). */
.et-activity-row { font-family: var(--et-font-family-base); }
.et-activity-row-main {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 12px 10px;
    border-radius: 12px;
    cursor: pointer;
    transition: background .14s;
}
.et-activity-row-main:hover {
    background: var(--et-color-bg);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.et-activity-row-main:active {
    background: var(--et-color-surface-2);
    box-shadow: none;
}
.et-activity-row-thumb {
    width: 46px;
    height: 46px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    font-size: 20px;
    flex-shrink: 0;
}
.et-activity-row-thumb--rose     { background: #FDECEC; }
.et-activity-row-thumb--blue     { background: #E9F1FE; }
.et-activity-row-thumb--green    { background: #E7F5EC; }
.et-activity-row-thumb--mustard  { background: #FBF1DC; }
.et-activity-row-thumb--lavender { background: #F3E9FB; }
.et-activity-row-thumb--peach    { background: #FBEDE6; }
.et-activity-row-body { flex: 1; min-width: 0; }
.et-activity-row-title-line {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 2px;
}
/* min-width:0 + the ellipsis trio, or a long expense name wraps to a second
   line and the row collides with its neighbour. A flex child defaults to
   min-width:auto, which refuses to shrink below its content. */
.et-activity-row-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-activity-row-group {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 10px;
    font-weight: 600;
    color: var(--et-color-ink-2);
    background: var(--et-color-surface-2);
    padding: 2px 8px;
    border-radius: 999px;
    flex-shrink: 0;
    white-space: nowrap;
}
/* Narrow: the group marker disappears entirely — no pill, no dot. Decision
   2026-08-08 (designer): the filter panel and the surrounding context (a
   group's own activity list, the group view's right column) already carry
   the group, so a phone row spends nothing on it. Diverges from the mobile
   canvas on purpose — the canvas still draws the dot ahead of the title and
   the payer avatar inline in the text line; revisit the canvas if this
   sticks.

   @container, not @media: the row should collapse whenever the BOX it sits in
   is narrow — a phone, but equally a docked side panel or the group view's
   right column. It also makes the branch visible in the gallery specimen,
   which a viewport query cannot be. The container is .et-surface (see the
   note there); 480px is the width below which the row needs to shed weight. */
@container (max-width: 480px) {
    .et-activity-row-group { display: none; }

    /* The payer micro-avatar moves off the text line and onto the category
       thumb's corner as a badge, so the payer line's TEXT starts flush under
       the title instead of carrying an 18px indent. Fixed pixel offsets, not
       percentages — they track .et-activity-row-thumb's fixed 46px box and
       .et-activity-row-main's 12px/10px padding, not the row's width, so
       they hold regardless of how wide the narrow container actually is. */
    .et-activity-row-main { position: relative; }
    .et-activity-row-payer-avatar {
        position: absolute;
        left: 56px; /* 10px padding-left + 46px thumb width */
        top: 58px;  /* 12px padding-top + 46px thumb height */
        transform: translate(-50%, -50%);
        box-shadow: 0 0 0 2px var(--et-color-surface);
    }
}
.et-activity-row-group-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
}
.et-activity-row-payer-line {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 11.5px;
    color: var(--et-color-ink-2);
}
.et-activity-row-payer-avatar {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 8px;
    font-weight: 600;
    flex-shrink: 0;
}
.et-activity-row-payer-avatar--plum    { background: linear-gradient(135deg, #9c6dab, #7A4E7A); }
.et-activity-row-payer-avatar--rose    { background: linear-gradient(135deg, #e088b8, #c94f95); }
.et-activity-row-payer-avatar--green   { background: linear-gradient(135deg, #5cb985, #2e8b5c); }
.et-activity-row-payer-avatar--blue    { background: linear-gradient(135deg, #5b9bd5, #2e6db5); }
.et-activity-row-payer-avatar--mustard { background: linear-gradient(135deg, #f0b362, #d68f2e); }
.et-activity-row-payer-avatar--sand    { background: #ECEAE3; color: #8F8C83; }
.et-activity-row-payer-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-activity-row-payer-text b {
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-activity-row-right {
    text-align: right;
    flex-shrink: 0;
    margin-left: 6px;
}
.et-activity-row-amount {
    font-size: 15px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
}
.et-activity-row-share {
    font-size: 10.5px;
    font-weight: 600;
    white-space: nowrap;
}
.et-activity-row-share--red   { color: var(--et-color-owe); }
.et-activity-row-share--green { color: var(--et-color-owed); }
.et-activity-row-share--muted { color: var(--et-color-ink-3); }
.et-activity-row-divider {
    height: 1px;
    background: var(--et-color-border);
    margin: 2px 12px 0;
}


/* ---------- EtNotifRow ---------- */
/* Top-aligned: a row can grow to three lines (title / meta+pill / reason
   quote), and the avatar, amount and unread dot must stay pinned to the
   first line rather than drift to the vertical middle. */
.et-notif-row {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 11px 16px;
    cursor: pointer;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-notif-row:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-notif-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-notif-row-avatar {
    position: relative;
    flex-shrink: 0;
}
/* Status marker on the avatar. Ring drawn in the surface colour so it reads as
   a cut-out over the avatar in both themes.

   This is the narrow row's status channel: in a narrow container the text pill
   is hidden (see the @container at the end of this block) and the marker
   carries the state alone.
   Glyphs are text, not emoji — an emoji would ignore `color` and muddy the disc. */
.et-notif-row-marker {
    position: absolute;
    right: -3px;
    bottom: -3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    color: #fff;
    border: 2px solid var(--et-color-surface);
    display: grid;
    place-items: center;
    font-size: 9.5px;
    font-weight: 800;
    line-height: 1;
}
.et-notif-row-marker--received     { background: var(--et-color-pend); }
.et-notif-row-marker--sent         { background: var(--et-color-neutral); }
.et-notif-row-marker--confirmed    { background: var(--et-color-owed); }
.et-notif-row-marker--disputed     { background: var(--et-color-owe); }
.et-notif-row-marker--acknowledged { background: var(--et-color-neutral); }
.et-notif-row-marker--waived       { background: var(--et-color-owed); }
.et-notif-row-marker--deleted      { background: var(--et-color-neutral); }

/* Own icon set rather than text glyphs or emoji: one stroke weight, round caps,
   same optical size — so the seven markers read as a family and match the app's
   soft, rounded shapes. Emoji would ignore `color` and muddy a 16px disc. */
.et-notif-row-marker-icon {
    width: 11px;
    height: 11px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.1;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.et-notif-row-marker-fill { fill: currentColor; stroke: none; }

/* Narrow-only: the status marker buys the room the pill gives up — the two
   swap in the same @container at the end of this block. Hidden is the DEFAULT
   rather than the branch, on purpose: a row rendered with no query container
   above it then falls back to the WIDE form (pill visible, marker off), which
   is the safe half. The inverse (`@container (min-width:…) { display:none }`)
   would give a container-less row the narrow form with no way to see it.
   The dispute marker has no --phone modifier, so it stays at every width. */
.et-notif-row-marker--phone { display: none; }
.et-notif-row-body { flex: 1; min-width: 0; padding-top: 1px; }
.et-notif-row-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-notif-row-title--unread { font-weight: 700; }
.et-notif-row-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 7px;
    margin-top: 2px;
}
.et-notif-row-sub {
    font-size: 12px;
    color: var(--et-color-ink-2);
}
/* Status pill. Colours reuse the same semantic tokens as EtPill so all six
   themes stay in sync: pend = amber, owed = green, owe = red, neutral = grey. */
.et-notif-row-status {
    display: inline-flex;
    align-items: center;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
.et-notif-row-status--amber   { background: var(--et-status-bg-pending); color: var(--et-color-pend); }
.et-notif-row-status--green   { background: #e7f4ec;                    color: var(--et-color-owed); }
.et-notif-row-status--red     { background: #fbebe8;                    color: var(--et-color-owe); }
.et-notif-row-status--neutral { background: var(--et-status-bg-logged);  color: var(--et-color-neutral); }
/* Narrow: title + sub + pill + amount does not fit. The avatar marker already
   says the same thing, so the pill goes, the marker comes in and the sub line
   gets the room back.

   @container, not @media: this row's two live homes are boxes, not screens —
   the notifications page card (.et-surface) and the bell dropdown's 340px menu
   (.et-notif-menu, given container-type for exactly this). The old
   min-width:960px / max-width:959.98px pair keyed off the viewport, which got
   the bell wrong in both directions: on a 1440px desktop it kept the pill
   inside a 340px menu, and it hid the pill on a 900px laptop where the
   notifications card is ~850px wide and has room to spare.

   480px, the same threshold EtActivityRow uses. Both are "an avatar + two text
   lines + a trailing amount, plus one optional pill" and start colliding at the
   same width, so the DS keeps ONE narrow-row breakpoint instead of two that
   drift. It also lands the two real containers on opposite sides: the bell menu
   (340px) is always narrow, the notifications card is narrow only on a phone. */
@container (max-width: 480px) {
    .et-notif-row-status { display: none; }
    .et-notif-row-marker--phone { display: grid; }
}
/* Reason quote — italic block with a 2px rule on the left. */
.et-notif-row-reason {
    margin-top: 6px;
    padding: 5px 10px;
    border-left: 2px solid var(--et-color-border);
    background: var(--et-color-surface-2);
    border-radius: 0 7px 7px 0;
    font-size: 11.5px;
    color: var(--et-color-ink-2);
    font-style: italic;
    line-height: 1.35;
}
.et-notif-row-amount {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
    flex-shrink: 0;
    padding-top: 1px;
}
.et-notif-row-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--et-color-accent);
    flex-shrink: 0;
    margin-top: 6px;
}


/* ---------- EtSettleItemRow ---------- */
.et-settle-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 12px 0;
    cursor: pointer;
    font-family: var(--et-font-family-base);
}
.et-settle-row--divider { border-bottom: 1px solid var(--et-color-border); }
/* The row the caller navigated from (expense panel → "Elszámolás X felé").
   Same soft-fill language as .et-share-row--me. */
.et-settle-row--source {
    margin: 0 -9px;
    padding: 12px 9px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--et-color-accent) 7%, transparent);
    border-bottom-color: transparent;
}
.et-settle-row--source .et-settle-row-title { font-weight: 700; }
.et-settle-row-arrow {
    font-size: 16px;
    font-weight: 700;
    width: 14px;
    text-align: center;
    flex-shrink: 0;
}
.et-settle-row-arrow--in { color: var(--et-color-owed); }
.et-settle-row-arrow--out { color: var(--et-color-owe); }
.et-settle-row-image {
    width: 40px;
    height: 40px;
    border-radius: 11px;
    overflow: hidden;
    flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.05);
}
.et-settle-row-image img { width: 100%; height: 100%; object-fit: cover; }
.et-settle-row-body { flex: 1; min-width: 0; }
.et-settle-row-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-settle-row-sub {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    color: var(--et-color-ink-2);
    margin-top: 1px;
}
.et-settle-row-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.et-settle-row-amount {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
    flex-shrink: 0;
}
.et-settle-row-check {
    width: 24px;
    height: 24px;
    border-radius: 7px;
    background: var(--et-color-accent);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 700;
    flex-shrink: 0;
}
.et-settle-row-info {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--et-color-surface-2);
    display: grid;
    place-items: center;
    font-size: 13px;
    color: var(--et-color-ink-2);
    flex-shrink: 0;
}
/* Unselected check state (Checked=false) — empty outline, dimmed content. */
.et-settle-row-check--off {
    background: transparent;
    color: transparent;
    box-shadow: inset 0 0 0 1.5px var(--et-color-border);
}
.et-settle-row--off .et-settle-row-title,
.et-settle-row--off .et-settle-row-amount { color: var(--et-color-ink-3); }
/* Secondary ⓘ as a real button next to the check (Mud's bare button rule
   would restyle it — declare everything). */
.et-settle-row-info--btn {
    border: 0;
    padding: 0;
    font-family: inherit;
    cursor: pointer;
    justify-content: center;
}


/* ---------- EtSettingsRow ---------- */
.et-settings-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 15px 18px;
    cursor: pointer;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-settings-row:hover { background-color: rgba(0, 0, 0, 0.02); }
.et-settings-row--locked {
    cursor: default;
}
.et-settings-row--locked:hover { background-color: transparent; }
.et-settings-row--divider { border-bottom: 1px solid var(--et-color-border); }
.et-settings-row-label {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-settings-row-label--danger { color: var(--et-color-owe); }
/* Colour dot ahead of the value (dc: `dot`) — the profile's Színstílus row
   shows the selected palette's accent so the row reads without opening. */
.et-settings-row-dot {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.et-settings-row-value {
    font-size: 13px;
    color: var(--et-color-ink-3);
    font-weight: 500;
    max-width: 55%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-settings-row-chevron {
    color: #C8C5BD;
    font-size: 18px;
    flex-shrink: 0;
}


/* ---------- EtToggleRow ---------- */
.et-toggle-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    font-family: var(--et-font-family-base);
}
.et-toggle-row--disabled { opacity: 0.45; }
.et-toggle-row--divider { border-bottom: 1px solid var(--et-color-border); }
.et-toggle-row-body { flex: 1; min-width: 0; }
.et-toggle-row-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-toggle-row-hint {
    font-size: 12px;
    color: var(--et-color-ink-2);
    margin-top: 1px;
    line-height: 1.4;
}
.et-toggle-row-track {
    width: 44px;
    height: 26px;
    border: 0;
    padding: 0;
    border-radius: 999px;
    background: #D8D4CA; /* dc literal off-track */
    position: relative;
    cursor: pointer;
    flex-shrink: 0;
    transition: background .15s;
}
.et-toggle-row-track--on { background: var(--et-color-owed); }
.et-toggle-row-track:disabled { cursor: default; }
.et-toggle-row-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    transition: transform .15s;
}
.et-toggle-row-track--on .et-toggle-row-knob { transform: translateX(18px); }
.et-toggle-row-track:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtCrudRow ---------- */
.et-crud-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 8px;
    border-radius: 12px;
    font-family: var(--et-font-family-base);
    transition: background-color .15s;
}
.et-crud-row:hover { background-color: rgba(0, 0, 0, 0.03); }
.et-crud-row--divider { box-shadow: inset 0 -1px 0 var(--et-color-border); }
.et-crud-row-tile {
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: var(--et-color-surface-2);
    display: grid;
    place-items: center;
    font-size: 17px;
    flex-shrink: 0;
}
.et-crud-row-body { flex: 1; min-width: 0; }
.et-crud-row-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-crud-row-sub {
    font-size: 12px;
    color: var(--et-color-ink-2);
    margin-top: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-crud-row-sub--muted { color: var(--et-color-ink-3); }
.et-crud-row-actions {
    display: flex;
    gap: 2px;
    flex-shrink: 0;
}
.et-crud-row-edit,
.et-crud-row-delete {
    width: 30px;
    height: 30px;
    border: 0;
    padding: 0;
    background: none;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-family: inherit;
    font-size: 13.5px;
    cursor: pointer;
    transition: background-color .15s;
}
.et-crud-row-edit { color: var(--et-color-ink-2); }
.et-crud-row-edit:hover { background-color: var(--et-color-surface-2); }
.et-crud-row-delete { color: var(--et-color-owe); }
.et-crud-row-delete:hover { background-color: #F9E5E3; } /* dc literal error tint */
.et-crud-row-edit:focus-visible,
.et-crud-row-delete:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtDangerZone ---------- */
.et-danger-zone {
    background: rgba(192, 57, 43, 0.05);
    border: 1px solid var(--et-color-owe);
    border-radius: 16px;
    padding: 18px 20px;
    font-family: var(--et-font-family-base);
}
.et-danger-zone-title {
    font-size: 15px;
    font-weight: 800;
    color: var(--et-color-owe);
    margin-bottom: 6px;
}
.et-danger-zone-text {
    font-size: 13px;
    color: var(--et-color-ink-2);
    line-height: 1.5;
    margin-bottom: 14px;
    max-width: 760px;
}
.et-danger-zone-actions {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}


/* ---------- EtExpenseSummary ---------- */
.et-expense-summary {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--et-font-family-base);
}
.et-expense-summary-body { flex: 1; min-width: 0; }
.et-expense-summary-title {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-expense-summary-sub {
    font-size: 12px;
    color: var(--et-color-ink-2);
}
.et-expense-summary-amount {
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--et-color-ink);
    white-space: nowrap;
}


/* ---------- EtPartyCard ---------- */
.et-party-card {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 8px;
    background: var(--et-color-surface);
    border: 1px solid var(--et-color-border);
    border-radius: 14px;
    padding: 16px;
    font-family: var(--et-font-family-base);
}
.et-party-card-party {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}
.et-party-card-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-party-card-role {
    font-size: 10px;
    color: var(--et-color-ink-3);
}
.et-party-card-arrow {
    color: var(--et-color-accent);
    font-size: 20px;
}


/* ---------- EtEventCard ---------- */
.et-event-card {
    width: 100%;
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-lg);
    box-shadow: var(--et-shadow-card);
    overflow: hidden;
    font-family: var(--et-font-family-base);
    transition: transform .16s, box-shadow .16s;
}
.et-event-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.10);
}
/* Already happened. Same treatment the legacy carousel gives .uec-past —
   receded, not disabled: recording the expense afterwards is the normal
   case, so the CTA stays live and hover restores full contrast. */
.et-event-card--past {
    opacity: 0.7;
    filter: saturate(0.85);
}
.et-event-card--past:hover {
    opacity: 1;
    filter: none;
}
.et-event-card-media {
    position: relative;
    height: 150px;
    overflow: hidden;
}
.et-event-card-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.et-event-card-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 4px 11px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    backdrop-filter: blur(6px);
    background: rgba(255, 255, 255, 0.92);
    color: #1A1917; /* on white blur chip — fixed */
}
.et-event-card-badge--urgent {
    background: #C4392D;
    color: #fff;
}
.et-event-card-group {
    position: absolute;
    top: 10px;
    left: 10px;
    display: flex;
    align-items: center;
    gap: 5px;
    background: rgba(255, 255, 255, 0.92);
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 600;
    color: #1A1917;
    backdrop-filter: blur(6px);
}
.et-event-card-group-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
}
.et-event-card-body { padding: 13px 15px 15px; }
.et-event-card-title {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin-bottom: 2px;
    color: var(--et-color-ink);
}
.et-event-card-date {
    font-size: 11px;
    color: var(--et-color-ink-2);
    font-weight: 500;
    margin-bottom: 11px;
}
.et-event-card-actions {
    display: flex;
    gap: 7px;
    align-items: center;
}
.et-event-card-cta {
    flex: 1;
    min-width: 0;
}


/* ---------- EtCardStrip ----------
   Horizontal shelf for fixed-width cards. The min-width:0 is belt-and-braces
   only: a scroll container already contributes zero to its ancestors'
   min-content sizing, so the shelf does not blow out a grid track on its own
   (measured — removing it changes nothing). It is here so a future caller
   that wraps the strip in a flex/grid item of its own can't reintroduce an
   automatic minimum. */
.et-card-strip-wrap {
    position: relative;
    min-width: 0;
}
.et-card-strip {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-behavior: smooth;
    /* Breathing room for the card shadow, which the hidden scrollbar no
       longer reserves. The paddles' top offset compensates for it. */
    padding-bottom: 10px;
    /* No visible scrollbar — the paddles and the partially-shown card at the
       edge carry the affordance. Both properties are needed: scrollbar-width
       covers Firefox and Chromium's overlay-scrollbar mode, where the
       pseudo-element rule alone is ignored. */
    scrollbar-width: none;
}
.et-card-strip::-webkit-scrollbar { display: none; }
.et-card-strip > * { flex: 0 0 auto; }

/* Edge fade — the same 28px mask the legacy .uec-carousel / .nac-strip use,
   ported so the shelf reads identically at every width. With the scrollbar
   hidden and the paddles only on hover, this is the one affordance that says
   "more cards this way" BEFORE the user touches anything. It follows
   data-can-scroll-*, so an edge the user has already reached is not faded.
   The paddles live on the wrap, outside the masked box, so they stay crisp.

   The LEFT fade additionally waits for data-user-scrolled="true" (set by
   etDs.attachStrip on a horizontal drag / wheel / paddle click). The events
   shelf opens anchored on the next event still ahead, so past cards sit
   off-screen to the left from the very first paint — a fade there would tell
   a first-time reader "you've already scrolled past something" when they
   haven't touched anything, and it's the only shelf on the page that would
   do so (the todo shelf below always opens on its first card). Once the user
   has moved the strip themselves — in either direction — both edges fade
   normally. The paddles are deliberately NOT gated on this: ‹ has to be
   clickable before there's any way to have scrolled. */
.et-card-strip-wrap[data-can-scroll-right="true"] .et-card-strip {
    -webkit-mask-image: linear-gradient(to right,
        black 0, black calc(100% - 28px), transparent 100%);
            mask-image: linear-gradient(to right,
        black 0, black calc(100% - 28px), transparent 100%);
}
.et-card-strip-wrap[data-user-scrolled="true"][data-can-scroll-left="true"] .et-card-strip {
    -webkit-mask-image: linear-gradient(to right,
        transparent 0, black 28px, black 100%);
            mask-image: linear-gradient(to right,
        transparent 0, black 28px, black 100%);
}
.et-card-strip-wrap[data-user-scrolled="true"][data-can-scroll-left="true"][data-can-scroll-right="true"] .et-card-strip {
    -webkit-mask-image: linear-gradient(to right,
        transparent 0, black 28px,
        black calc(100% - 28px), transparent 100%);
            mask-image: linear-gradient(to right,
        transparent 0, black 28px,
        black calc(100% - 28px), transparent 100%);
}

.et-card-strip-nav {
    position: absolute;
    /* Half the strip's bottom padding, so the paddle centres on the cards
       rather than on the card+scrollbar box. */
    top: calc(50% - 5px);
    transform: translateY(-50%);
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
    opacity: 0;
    pointer-events: none;
    transition: opacity .15s;
    z-index: 2;
}
.et-card-strip-nav--prev { left: 6px; }
.et-card-strip-nav--next { right: 6px; }
/* Revealed on hover, and only on the side that still has cards to reach.
   Keyboard users get them on focus — pointer-events:none doesn't block
   tab focus, only the cursor. */
@media (hover: hover) {
    .et-card-strip-wrap[data-can-scroll-left="true"]:hover .et-card-strip-nav--prev,
    .et-card-strip-wrap[data-can-scroll-right="true"]:hover .et-card-strip-nav--next {
        opacity: 1;
        pointer-events: auto;
    }
}
.et-card-strip-nav:focus-visible {
    opacity: 1;
    pointer-events: auto;
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtTodoCard ---------- */
.et-todo-card {
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-md);
    box-shadow: var(--et-shadow-card);
    padding: 16px 18px;
    font-family: var(--et-font-family-base);
    min-width: 0;
    cursor: pointer;
    transition: transform .16s, box-shadow .16s;
}
.et-todo-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.10);
}
.et-todo-card-head {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-bottom: 8px;
}
.et-todo-card-person {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-todo-card-amount {
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--et-color-ink);
    margin-bottom: 2px;
}
.et-todo-card-status {
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 12px;
}
.et-todo-card-status--amber { color: var(--et-color-pend); }
.et-todo-card-status--red   { color: var(--et-color-owe); }
.et-todo-card-status--green { color: var(--et-color-owed); }
.et-todo-card-actions {
    display: flex;
    gap: 8px;
}
.et-todo-card-cta {
    flex: 1;
    min-width: 0;
}


/* ---------- EtGroupCard ---------- */
/* Geometry is the dc's Csoportok card: radius 20, 96px cover, 16/18/18 body. */
.et-group-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    background: var(--et-color-surface);
    border-radius: 20px;
    box-shadow: var(--et-shadow-card);
    font-family: var(--et-font-family-base);
    color: var(--et-color-ink);
    cursor: pointer;
    min-width: 0;
    transition: transform .16s, box-shadow .16s;
}
.et-group-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--et-shadow-card-hover);
}
/* Cover: badge pinned top-left, icon bottom-left, avatars bottom-right. */
.et-group-card-cover {
    position: relative;
    display: flex;
    align-items: flex-end;
    height: 96px;
    padding: 14px 18px;
    flex-shrink: 0;
}
.et-group-card-badge {
    position: absolute;
    top: 14px;
    left: 18px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.85);
    font-size: 11px;
    font-weight: 700;
    white-space: nowrap;
}
.et-group-card-badge-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.et-group-card-icon {
    font-size: 26px;
    line-height: 1;
}
.et-group-card-avatars {
    display: flex;
    align-items: center;
    margin-left: auto;
    padding-left: 8px;
}
/* The 2px white ring is what makes the stack read as overlapping rather than
   as one blurred blob; the negative margin is skipped on the first face. */
.et-group-card-face {
    border: 2px solid #fff;
    margin-left: -8px;
}
.et-group-card-face:first-child { margin-left: 0; }
.et-group-card-face--more {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--et-color-surface-2);
    color: var(--et-color-ink-2);
    font-size: 11px;
    font-weight: 700;
    flex-shrink: 0;
}
.et-group-card-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    padding: 16px 18px 18px;
}
.et-group-card-name {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-bottom: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-group-card-caption {
    font-size: 12px;
    color: var(--et-color-ink-2);
    margin-bottom: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* margin-top:auto pins the balance row to the card bottom, so the chips line
   up across a stretched grid row however long the captions are. */
.et-group-card-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: auto;
}
.et-group-card-balance-caption {
    font-size: 12px;
    font-weight: 500;
    color: var(--et-color-ink-4);
    white-space: nowrap;
}
.et-group-card-chip {
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
}
/* dc literal chip tints — the same owed fill EtAllocationBanner uses. */
.et-group-card-chip--owed {
    color: var(--et-color-owed);
    background: #E7F4EC;
}
.et-group-card-chip--owe {
    color: var(--et-color-owe);
    background: #FBEBE8;
}
.et-group-card-chip--settled {
    color: var(--et-color-ink-2);
    background: var(--et-color-surface-2);
}


/* ---------- EtAllocationBanner ---------- */
.et-allocation-banner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 11px 14px;
    background: #E7F4EC; /* dc literal owed-tint (cf. EtPill owed bg) */
    border-radius: 11px;
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-owed);
    font-family: var(--et-font-family-base);
}
.et-allocation-banner--warn {
    background: var(--et-status-bg-pending);
    color: var(--et-color-pend);
}


/* ---------- EtPanelHeader ---------- */
.et-panel-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 20px 14px;
    border-bottom: 1px solid var(--et-color-border);
    font-family: var(--et-font-family-base);
}
.et-panel-header-body { flex: 1; }
.et-panel-header-title {
    font-size: 19px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--et-color-ink);
}
.et-panel-header-subtitle {
    font-size: 12px;
    color: var(--et-color-ink-2);
    margin-top: 1px;
}
/* Back shares the close chrome — a round button leading the header (left of
   the title), rendered only when the panel sits on another panel (ShowBack).
   The header's own 12px gap spaces it; no extra margin needed. */
.et-panel-header-close,
.et-panel-header-back {
    width: 34px;
    height: 34px;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background: var(--et-color-surface-2);
    display: grid;
    place-items: center;
    font-family: inherit;
    font-size: 15px;
    color: var(--et-color-ink-2);
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color .15s;
}
.et-panel-header-back {
    /* The ‹ glyph rides low and small at the shared 15px — nudge it. */
    font-size: 20px;
    line-height: 1;
    padding-bottom: 3px;
}
.et-panel-header-close:hover,
.et-panel-header-back:hover { background-color: #E6E2D8; }
.et-panel-header-close:focus-visible,
.et-panel-header-back:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtPanel ----------
   One shell, two forms: the right-hand 460px side panel on a wide box, the
   design's 90%-height bottom sheet on a narrow one. The sheet used to be its
   own component (EtSheetFrame); it had no production caller and the two
   shells had already drifted a few pixels apart, so it is folded in here and
   the SHEET's values won — those are the ones drawn in the mobile design.

   The dc frames the shell with absolute positioning inside the canvas;
   in-app it is a fixed full-viewport layer.

   Why this atom may branch on @container when EtTopBar / EtFilterPanel may
   not: container-type brings layout containment, which makes the element the
   containing block for position:fixed descendants — and this panel really
   does host fixed things (EtDropdown's backdrop and its phone sheet, opened
   from ExpenseNew / GroupNew / RecipientEditPanel). Two facts make it safe:

   1. Overlay mode: .et-panel is already `position: fixed; inset: 0`, so its
      box IS the viewport. Trapping a fixed descendant inside a box that
      already equals the viewport is a no-op, and the query answers the same
      width a media query would. Previewability for free.
   2. Docked mode: the panel fills PanelOutlet's ~460px rail, where the same
      containment WOULD trap those overlays into the rail. So docked gets
      `container-type: normal` — no containment introduced at all. That costs
      nothing, because PanelOutlet only renders its rail from 960px up (it
      answers that breakpoint itself now that MudHidden is gone): a docked
      panel is desktop-only and never needs the sheet.

   Belt and braces, the sheet rules are additionally scoped
   `:not(.et-panel--docked)`, so even if some future ancestor becomes a
   container, a docked panel still cannot morph into a bottom sheet. */
.et-panel {
    position: fixed;
    inset: 0;
    z-index: 1400;
    container-type: inline-size;
    font-family: var(--et-font-family-base);
}
.et-panel--inline { position: absolute; } /* gallery/demo containment */
/* Docked mode (PanelOutlet host): the outlet owns the fixed right rail and
   the slide animation; the panel just fills it. No dimming overlay — the
   background page stays live. container-type off, see (2) above. */
.et-panel--docked {
    position: static;
    inset: auto;
    z-index: auto;
    height: 100%;
    container-type: normal;
}
.et-panel--docked .et-panel-shell {
    position: relative;
    top: auto;
    right: auto;
    bottom: auto;
    width: 100%;
    height: 100%;
}
/* No body scroll lock while the overlay panel is open — a position:fixed
   body breaks iOS keyboard avoidance (focusing an input pans the visual
   viewport and the pan sticks after the keyboard closes: taps land offset
   from the pixels). Instead the background is shielded gesture-side: the
   overlay swallows touch pans (taps still click, so tap-to-close works),
   and the panel's scroll area refuses to chain its overscroll into the
   page. etSheetDrag covers the not-scrollable-content case in JS. */
.et-panel-overlay { touch-action: none; }
.et-panel-scroll { overscroll-behavior-y: contain; }
.et-panel-overlay {
    position: absolute;
    inset: 0;
    background: rgba(26, 25, 23, 0.32);
    backdrop-filter: blur(2px);
    cursor: pointer;
}
.et-panel-shell {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: var(--etp-width, 460px);
    max-width: 100vw;
    background: var(--et-color-bg);
    box-shadow: -12px 0 40px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
}
.et-panel-scroll {
    flex: 1;
    overflow-y: auto;
    scrollbar-width: none;
}
.et-panel-body { padding: 4px 20px 20px; }
.et-panel-footer {
    padding: 14px 20px;
    border-top: 1px solid var(--et-color-border);
    background: rgba(250, 248, 243, 0.92); /* dc literal — bg tint at 92% */
    backdrop-filter: blur(8px);
    flex-shrink: 0;
}
.et-panel-footer-row {
    display: flex;
    gap: 10px;
}
.et-panel-footer-cta {
    flex: 1;
    min-width: 0;
}
.et-panel-footer-note {
    text-align: center;
    font-size: 11px;
    color: var(--et-color-ink-3);
    margin-top: 8px;
}

/* Shared sheet keyframes — kept OUTSIDE the branch below because they have
   two users: this panel's sheet form and .et-dropdown-menu's phone sheet
   (et-sheet-rise); et-fade is used by the sheet overlay here only.
   (app.css used to declare a duplicate et-sheet-rise for the retired
   BottomSheet component; that went with the component in the E round.) */
@keyframes et-sheet-rise {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}
@keyframes et-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Sheet form (narrow box): the side panel becomes the design's BottomSheet90
   with a grabber. Padding and overlay tint come from the old EtSheetFrame —
   the panel's own phone branch had drifted to 0.32 dim and 20px gutters. */
@container (max-width: 640px) {
    .et-panel:not(.et-panel--docked) .et-panel-overlay {
        background: rgba(26, 25, 23, 0.4);
        animation: et-fade 0.2s ease-out;
    }
    .et-panel:not(.et-panel--docked) .et-panel-shell {
        top: auto;
        left: 0;
        width: 100%;
        height: 90%;
        border-top-left-radius: 24px;
        border-top-right-radius: 24px;
        box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.22);
        animation: et-sheet-rise 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
    }
    /* Grabber as a pseudo-element. EtSheetFrame shipped a real
       .et-sheet-grabber div; identical pixels, one DOM node cheaper. */
    .et-panel:not(.et-panel--docked) .et-panel-shell::before {
        content: "";
        width: 40px;
        height: 4px;
        background: #D8D4CA; /* dc literal grabber */
        border-radius: 2px;
        margin: 12px auto 0;
        flex-shrink: 0;
    }
    .et-panel:not(.et-panel--docked) .et-panel-body { padding: 4px 16px 20px; }
    /* The sheet is bottom-anchored (height:90% off `bottom: 0`), so its last
       row sits on the screen edge — on iOS that is where the home indicator
       lives. Only the footer needs the inset: growing the shell instead would
       either open a gap to the dimmed page or push content off the top. */
    .et-panel:not(.et-panel--docked) .et-panel-footer {
        padding: 12px 16px calc(18px + env(safe-area-inset-bottom));
    }
}


/* ---------- EtDialog ---------- */
.et-dialog {
    background: var(--et-color-surface);
    border-radius: 20px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
    max-width: 100%;
    font-family: var(--et-font-family-base);
}
.et-dialog-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 20px 22px 0;
}
.et-dialog-title {
    flex: 1;
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-dialog-title--danger { color: var(--et-color-owe); }
.et-dialog-close {
    width: 30px;
    height: 30px;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background: var(--et-color-surface-2);
    display: grid;
    place-items: center;
    font-family: inherit;
    font-size: 13px;
    color: var(--et-color-ink-2);
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color .15s;
}
.et-dialog-close:hover { background-color: #E6E2D8; }
.et-dialog-close:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-dialog-body { padding: 14px 22px 6px; }
.et-dialog-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 12px 22px 20px;
}
/* Centering overlay for EtDialog hosts (same dim as EtPanel's overlay). */
.et-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 1500;
    background: rgba(26, 25, 23, 0.32);
    backdrop-filter: blur(2px);
    display: grid;
    place-items: center;
    padding: 16px;
}


/* ---------- EtDropdown ---------- */
.et-dropdown {
    position: relative;
    font-family: var(--et-font-family-base);
}
.et-dropdown-anchor { position: relative; z-index: 1; }
/* Transparent hit area that closes the menu on an outside click without a
   visible dim — the field under the menu must stay readable. */
.et-dropdown-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1490;
}
.et-dropdown-menu {
    position: absolute;
    top: calc(100% + 6px);
    z-index: 1495;
    background: var(--et-color-surface);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.04);
    padding: 6px;
    animation: et-dropdown-in 0.14s ease-out;
}
.et-dropdown--stretch .et-dropdown-menu { left: 0; right: 0; }
.et-dropdown--start .et-dropdown-menu { left: 0; width: var(--etdd-width, 260px); }
.et-dropdown--end .et-dropdown-menu { right: 0; width: var(--etdd-width, 260px); }
.et-dropdown-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: var(--etdd-max-height, 320px);
    overflow-y: auto;
}
/* Dropdown items: roomier rows than the compact TopBar menu (~52px with
   a 28px avatar) and a plum-tinted selection with a trailing check. */
.et-dropdown-list .et-group-menu-item { padding: 12px; }
.et-dropdown-list .et-group-menu-item--selected {
    background-color: color-mix(in srgb, var(--et-color-accent) 9%, transparent);
}
.et-dropdown-list .et-group-menu-item--selected::after {
    content: "✓";
    margin-left: auto;
    color: var(--et-color-accent);
    font-weight: 800;
}
/* Sheet header — only rendered visible at the phone breakpoint. */
.et-dropdown-title { display: none; }
@keyframes et-dropdown-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}
/* Phone breakpoint: the anchored menu becomes the mobile design's bottom
   sheet — same markup, same call site. */
@media (max-width: 640px) {
    .et-dropdown-backdrop {
        background: rgba(26, 25, 23, 0.32);
        backdrop-filter: blur(2px);
    }
    .et-dropdown-menu,
    .et-dropdown--start .et-dropdown-menu,
    .et-dropdown--end .et-dropdown-menu {
        position: fixed;
        top: auto;
        bottom: 0;
        left: 0;
        right: 0;
        width: auto;
        border-radius: 24px 24px 0 0;
        padding: 0 10px calc(14px + env(safe-area-inset-bottom));
        box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.22);
        animation: et-sheet-rise 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
    }
    .et-dropdown-menu::before {
        content: "";
        display: block;
        width: 40px;
        height: 4px;
        background: #D8D4CA; /* dc literal — sheet grabber */
        border-radius: 2px;
        margin: 12px auto 0;
    }
    .et-dropdown-title {
        display: block;
        padding: 12px 12px 8px;
        font-size: 15px;
        font-weight: 800;
        letter-spacing: -0.02em;
        color: var(--et-color-ink);
    }
    .et-dropdown-list { max-height: 60vh; }
}


/* ---------- EtTopBar ---------- */
.et-topbar {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 24px;
    background: var(--et-color-surface);
    border-bottom: 1px solid var(--et-color-border);
    font-family: var(--et-font-family-base);
}
.et-topbar-brand {
    display: flex;
    align-items: center;
    gap: 9px;
}
.et-topbar-logo {
    width: 32px;
    height: 32px;
    border-radius: 9px;
    /* Palette accent, not ink: the tile is the one place the active palette
       shows in the chrome. --et-color-surface flips with the theme, so the
       "KK" stays readable on light accents (dark palettes) too. */
    background: var(--et-color-accent);
    color: var(--et-color-surface);
    display: grid;
    place-items: center;
    font-weight: 800;
    font-size: 13px;
}
.et-topbar-name {
    font-weight: 700;
    font-size: 15px;
    color: var(--et-color-ink);
}
.et-topbar-group {
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    cursor: pointer;
}
.et-topbar-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 10px;
}
.et-topbar-avatar {
    border: 0;
    background: none;
    padding: 0;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 0 0 2px var(--et-color-surface), 0 0 0 3.5px var(--et-color-border);
    transition: filter .12s, transform .12s;
}
.et-topbar-avatar:hover { filter: brightness(1.06); }
.et-topbar-avatar:active { transform: scale(0.96); }
.et-topbar-avatar:focus-visible,
.et-topbar-group:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
/* Phone: at 390px the word mark wrapped to a second line and shoved the avatar
   out of the bar. Drop the word mark (the KK tile still identifies the app),
   tighten 12/24 → 12/14 and 14 → 10 gap, and drop the header CTA — on a phone
   the design puts "Új költség" on the bottom bar's + button, not up here.

   @media and NOT @container, deliberately. This is shell, not content: the top
   bar always spans the viewport, so its box width and the screen width are the
   same number and a container query would only add indirection. The decisive
   half is what it would cost: the bar hosts the bell and profile dropdowns,
   and container-type brings layout containment, which makes the container the
   containing block for position:fixed descendants — EtDropdown's backdrop
   (fixed, inset:0) and its phone bottom sheet (fixed, bottom:0) would then be
   trapped inside a 60px-tall bar. Compare EtActivityRow / EtNotifRow, which
   are content, sit in boxes narrower than the screen, and carry nothing fixed.

   Consequence: /_dev/ds cannot fire this branch directly — the specimen's
   phone column is a narrow BOX in a wide viewport, and a media query does not
   care. The gallery instead mirrors these three declarations under
   .ds-specimen-phone .et-topbar, near the DsSpecimen rules below. Keep the
   two blocks in lock-step by hand — nothing enforces it.

   640px is the DS's single phone breakpoint — the same one EtPanel,
   EtDropdown and EtNotificationMenu morph at. */
@media (max-width: 640px) {
    .et-topbar {
        gap: 10px;
        padding: 12px 14px;
    }
    .et-topbar-name { display: none; }
    /* The CTA only; the bell is .et-icon-btn and the avatar is its own class. */
    .et-topbar-right > .et-btn { display: none; }
}


/* ---------- EtGroupHeader ----------
   Band gradient + icon fill/shadow are per-group colors passed inline.

   The compact form used to be a `Compact` C# bool that also switched the
   Settings DOM. It is now one @container branch at the end of this block, so
   the header tightens itself in whatever box it is given. */
.et-group-header {
    font-family: var(--et-font-family-base);
    /* Query container for the branch below. The padding lives on
       .et-group-header-inner and not here because a container cannot query
       ITS OWN width — a rule inside @container never matches the container
       element, so a root-level padding could not participate. Safe to
       contain: the header holds buttons and avatars, nothing position:fixed
       (contrast .et-topbar and .et-filter-panel, which host EtDropdown). */
    container-type: inline-size;
}
.et-group-header-inner { padding: 22px 32px 24px; }
.et-group-header-back {
    display: flex;
    align-items: center;
    gap: 6px;
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 14px;
    cursor: pointer;
}
.et-group-header-main {
    display: flex;
    align-items: center;
    gap: 16px;
}
.et-group-header-icon {
    width: 60px;
    height: 60px;
    border-radius: 18px;
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 26px;
    font-weight: 800;
    flex-shrink: 0;
}
.et-group-header-body { flex: 1; min-width: 0; }
.et-group-header-title {
    font-size: 27px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: #1A1917; /* on the light band — fixed */
}
.et-group-header-meta-line {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 5px;
}
.et-group-header-avatars { display: flex; }
.et-group-header-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 600;
    font-size: 11px;
    border: 2px solid #fff;
}
.et-group-header-avatar + .et-group-header-avatar { margin-left: -8px; }
.et-group-header-avatar--plum    { background: linear-gradient(135deg, #9c6dab, #7A4E7A); }
.et-group-header-avatar--rose    { background: linear-gradient(135deg, #e088b8, #c94f95); }
.et-group-header-avatar--green   { background: linear-gradient(135deg, #5cb985, #2e8b5c); }
.et-group-header-avatar--blue    { background: linear-gradient(135deg, #5b9bd5, #2e6db5); }
.et-group-header-avatar--mustard { background: linear-gradient(135deg, #f0b362, #d68f2e); }
.et-group-header-avatar--sand    { background: #ECEAE3; color: #8F8C83; }
.et-group-header-meta {
    font-size: 12px;
    color: #6B6860; /* on the light band — fixed */
    font-weight: 500;
    margin-left: 2px;
}
.et-group-header-settings { flex-shrink: 0; }
/* Both Settings affordances are in the DOM; exactly one is display:none at any
   width, so the other is genuinely gone — no tab stop, no accessibility node,
   no duplicate "Beállítások" for a screen reader. The gear is the hidden one by
   default so a header with no query container above or around it still shows
   the labelled button, which is the form that works at any width. */
.et-group-header-gear {
    display: none;
    width: 42px;
    height: 42px;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.75);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    place-items: center;
    font-size: 18px;
    cursor: pointer;
}
/* Narrow: 32px of side padding, a 60px tile, a 27px title and a ~140px
   labelled button do not coexist — below ~480px the button starts pushing the
   title into an ellipsis. Same threshold as EtActivityRow and EtNotifRow: the
   DS keeps one narrow-box breakpoint rather than three that drift apart.
   @container and not @media because this is content in the page's main
   column, not shell — it must read the same in a phone, in the group view and
   in the gallery's 390px specimen, none of which agree on viewport width. */
@container (max-width: 480px) {
    .et-group-header-inner { padding: 16px 16px 18px; }
    .et-group-header-icon {
        width: 48px;
        height: 48px;
        border-radius: 14px;
        font-size: 21px;
    }
    .et-group-header-title { font-size: 22px; }
    /* Two classes so the hide wins over .et-btn's own display regardless of
       which block ends up later in the file. */
    .et-group-header-settings .et-group-header-settings-btn { display: none; }
    .et-group-header-gear { display: grid; }
}


/* ---------- EtGroupMenu ---------- */
.et-group-menu {
    background: var(--et-color-surface);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(0, 0, 0, 0.04);
    padding: 6px;
    font-family: var(--et-font-family-base);
}
.et-group-menu--flat { box-shadow: 0 0 0 1px var(--et-color-border); }
.et-group-menu-item {
    display: flex;
    align-items: center;
    /* Explicit even though it's the flex default. It was load-bearing while
       MudBlazor's global `button` rule injected justify-content:center into
       any button class that stayed silent; kept so a future global button
       rule can't re-centre these rows. */
    justify-content: flex-start;
    gap: 9px;
    width: 100%;
    padding: 10px 11px;
    border: 0;
    background: none;
    border-radius: 9px;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--et-color-ink);
    text-align: left;
    cursor: pointer;
    transition: background-color .15s;
}
.et-group-menu-item:hover { background-color: #F5F2EB; } /* dc literal hover tint */
.et-group-menu-item--selected {
    font-weight: 700;
    background-color: #F5F2EB;
}
.et-group-menu-glyph {
    width: 16px;
    text-align: center;
    color: var(--et-color-ink-2);
    font-size: 13px;
}
.et-group-menu-dot-wrap {
    width: 16px;
    display: flex;
    justify-content: center;
}
.et-group-menu-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
}
.et-group-menu-divider {
    height: 1px;
    background: var(--et-color-border);
    margin: 5px 8px;
}
.et-group-menu-new { color: var(--et-color-accent); }
.et-group-menu-plus {
    color: var(--et-color-accent);
    font-size: 15px;
    font-weight: 800;
}
.et-group-menu-item:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: -2px;
}

/* GroupSwitcher = EtDropdown shell + EtGroupMenu rows. Both atoms ship the
   same surface (14px radius, the same shadow pair, 6px padding), so the
   inner menu is flattened and the shell keeps the chrome — that also leaves
   the scroll container on .et-dropdown-list, where a long group list needs
   it, instead of clipping the inner menu's own shadow.
   The shell's roomier item vocabulary (12px rows, plum tint, trailing ✓) is
   reverted to GroupMenu's: the DS shows this menu with the #F5F2EB
   selected row and no checkmark. */
.et-group-switcher-dropdown .et-group-menu {
    background: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}
.et-group-switcher-dropdown .et-dropdown-list .et-group-menu-item { padding: 10px 11px; }
.et-group-switcher-dropdown .et-dropdown-list .et-group-menu-item--selected {
    background-color: #F5F2EB; /* dc literal — GroupMenu selected row */
}
.et-group-switcher-dropdown .et-dropdown-list .et-group-menu-item--selected::after { content: none; }


/* ---------- EtNotificationMenu ---------- */
.et-notif-menu {
    width: 340px;
    background: var(--et-color-surface);
    border-radius: 16px;
    border: 1px solid var(--et-color-border);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.16);
    overflow: hidden;
    font-family: var(--et-font-family-base);
    /* Query container for the EtNotifRows inside — the menu's second home
       besides the notifications page's .et-surface. Without this the rows in
       the bell dropdown would have no container ancestor at all and their
       @container rule would silently never fire: 340px of menu showing the
       wide, pill-carrying row. Safe to contain here — the menu holds only
       rows and labels, no position:fixed descendant. */
    container-type: inline-size;
}
.et-notif-menu-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px 10px;
}
.et-notif-menu-title {
    font-size: 14px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-notif-menu-badge {
    background: var(--et-color-accent);
    color: #fff;
    border-radius: 999px;
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 700;
}
/* The "ÚJ" bucket holds every unread row, so the body scrolls rather than
   growing unbounded. Its ÚJ / KORÁBBI labels are EtListLabel Dense="true"
   (the old .et-notif-menu-section lived here). */
.et-notif-menu-list {
    max-height: 380px;
    overflow-y: auto;
}
.et-notif-menu-loading {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 16px 12px;
}
.et-notif-menu-empty {
    text-align: center;
    padding: 24px 20px 26px;
}
.et-notif-menu-empty-emoji {
    font-size: 32px;
    margin-bottom: 8px;
}
.et-notif-menu-empty-title {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-notif-menu-empty-text {
    font-size: 12px;
    color: var(--et-color-ink-3);
    margin-top: 3px;
    line-height: 1.4;
}
.et-notif-menu-footer {
    display: block;
    width: 100%;
    border: 0;
    background: none;
    border-top: 1px solid var(--et-color-border);
    padding: 12px 16px;
    text-align: center;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--et-color-accent);
    cursor: pointer;
    transition: background-color .15s;
}
.et-notif-menu-footer:hover { background-color: rgba(122, 78, 122, 0.05); }
.et-notif-menu-footer:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: -2px;
}
/* ---------- EtNotificationMenu hosted in an EtDropdown (the TopBar bell) ----------
   The menu already is a surface (radius, border, shadow), so inside a dropdown
   it drops its own chrome and becomes the dropdown's body. Opt-in via
   Class="et-notif-dropdown" on the EtDropdown so other dropdowns are untouched. */
/* The bell sits in the app bar's flex row — keep the anchor at the button's
   own 40px instead of letting it shrink. */
.et-notif-dropdown { flex-shrink: 0; }
.et-notif-dropdown .et-dropdown-menu { padding: 0; overflow: hidden; }
.et-notif-dropdown .et-dropdown-list {
    max-height: none;
    overflow: visible;
    gap: 0;
}
.et-notif-dropdown .et-notif-menu {
    width: 100%;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
}
@media (max-width: 640px) {
    /* Bottom-sheet form: keep the sheet's safe-area inset (the dropdown's own
       mobile rule sets it) and let the taller viewport give the list room. */
    .et-notif-dropdown .et-dropdown-menu {
        padding: 0 0 env(safe-area-inset-bottom);
    }
    .et-notif-dropdown .et-notif-menu-list { max-height: 60vh; }
}


/* ---------- EtFilterPanel ---------- */
.et-filter-panel {
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-md);
    box-shadow: var(--et-shadow-card);
    padding: 12px;
    font-family: var(--et-font-family-base);
}
.et-filter-panel-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 6px;
    cursor: pointer;
}
.et-filter-panel-title {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-filter-panel-helper {
    font-size: 12px;
    color: var(--et-color-ink-3);
}
.et-filter-panel-spacer { flex: 1; }
.et-filter-panel-chevron {
    color: var(--et-color-ink-2);
    font-size: 13px;
}
/* One template for BOTH routes — the read-only picker grid and the
   AdvancedActivityFilters grid inside .et-filter-panel-body.

   --etfp-cols is the WIDE column count. EtFilterPanel writes it as a custom
   property (`style="--etfp-cols:3"`); it used to write the whole
   `grid-template-columns` inline, which no stylesheet rule can override
   without !important — so the read-only route kept three columns at 390px and
   burst out of its box by ~170px. A custom property lets the stylesheet own
   the layout and the component own only the number. AdvancedActivityFilters
   sets nothing, so it takes the 3 fallback, which is what it had before.

   The narrow collapse is intrinsic — auto-fill with a track floor — rather
   than a width query, because both other tools are wrong here:
     - @media keys off the viewport, so it cannot see a narrow panel on a wide
       screen, and it is invisible in the gallery specimen (that is exactly
       what the deleted max-width:640px rule did, and it only ever matched the
       .et-filter-panel-body route anyway).
     - @container would need a query container above this grid, and the only
       candidates are the panel itself or one of its ancestors. Either gets
       layout containment, which makes it the containing block for
       position:fixed descendants — and the ChildContent route puts EtDropdowns
       in this grid, whose backdrop (fixed, inset:0) and phone bottom sheet
       (fixed, bottom:0) are laid out against the viewport. The sheet would
       open at the bottom edge of the filter panel instead of the screen.
   auto-fill answers the same question ("do N pickers still fit?") from the
   real available width, with no container at all. auto-fill and not auto-fit:
   the ChildContent route renders a single picker until a group is chosen, and
   auto-fit would collapse the empty tracks and stretch that one field across
   the whole panel.

   190px is the floor: a picker cell's min-content width measures ~160px, so
   this is the first size at which one is not being squeezed. */
.et-filter-panel-grid {
    display: grid;
    gap: var(--etfp-gap);
    padding: 10px 6px 0;
    --etfp-gap: 10px;
    --etfp-col-min: 190px;
    grid-template-columns: repeat(auto-fill, minmax(
        max(var(--etfp-col-min), 100% / var(--etfp-cols, 3) - var(--etfp-gap)), 1fr));
}
/* Live-picker mode (EtFilterPanel ChildContent): same inset as the grid, but
   the child brings its own layout. */
.et-filter-panel-body { padding: 10px 6px 0; }
/* AdvancedActivityFilters reuses the read-only grid inside the body wrapper,
   which already supplies the inset. */
.et-filter-panel-body > .et-filter-panel-grid { padding: 0; }
.et-filter-panel-dates {
    display: flex;
    gap: 10px;
}
/* Native <input type="date"> inside a picker cell: keep it from forcing the
   grid column wider than its share, and tone down the UA calendar button. */
.et-filter-panel-date .et-field-input { min-width: 0; }
.et-filter-panel-date .et-field-input::-webkit-calendar-picker-indicator {
    margin-left: auto;
    opacity: 0.55;
    cursor: pointer;
}
.et-filter-panel-date {
    flex: 1;
    min-width: 0;
}
.et-filter-panel-clear-row {
    display: flex;
    justify-content: flex-end;
    padding: 10px 6px 2px;
}
.et-filter-panel-clear {
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    color: var(--et-color-owe);
    font-size: 12.5px;
    font-weight: 700;
    cursor: pointer;
}
.et-filter-panel-clear:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}


/* ---------- EtFab ---------- */
/* Centered labelled pill floating over the bottom of the phone screen.
   Canvas literal: bottom 22px, left 50% + translateX(-50%), 13/26 padding,
   radius 999, 14/700 label, 8px gap.

   The 22px is measured in a canvas frame that has no home indicator, so the
   safe-area inset is ours to add — without it the pill lands under the
   indicator on a notched iPhone.

   The gradient IS --et-cta-gradient: the canvas's three stops are the token's
   three stops, character for character. The shadow is NOT --et-cta-shadow.
   That token (0 4px 14px / 0.35) is tuned for a CTA resting ON a surface;
   this pill floats above the page and the canvas asks for 0 10px 28px / 0.5.
   One consumer, so it stays a literal here rather than becoming a fourth CTA
   token — promote it if a second floating CTA ever appears.

   z-index 1101 carries over from the .app-fab this replaces: below the sticky
   app header (app.css .app-topbar, 1102 — deliberately, so the header's own
   dropdown sheets cover the pill), the panel outlet (1350), .et-panel (1400)
   and .et-modal-overlay (1500), so a sheet or dialog still covers it.

   No viewport query lives in this atom on purpose: a display:none media
   query here would also blank the pill in the DS gallery, which runs at
   desktop width. The app hides its own FAB from 960px up in app.css. */
.et-fab {
    position: fixed;
    left: 50%;
    bottom: calc(22px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    z-index: 1101;
    display: flex;
    align-items: center;
    gap: 8px;
    border: 0;
    padding: 13px 26px;
    border-radius: 999px;
    background: var(--et-cta-gradient);
    color: #fff;
    font-family: var(--et-font-family-base);
    font-size: 14px;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 10px 28px rgba(122, 78, 122, 0.5);
    transition: transform .14s, filter .14s, box-shadow .14s;
}
/* Every state below has to restate the centering translate: `transform` is a
   single property, so a bare translateY would drop the -50% and snap the pill
   half its own width to the right. */
.et-fab:hover {
    filter: brightness(1.03);
    transform: translateX(-50%) translateY(-1px);
    box-shadow: 0 12px 32px rgba(122, 78, 122, 0.55);
}
.et-fab:active {
    filter: brightness(0.94);
    transform: translateX(-50%);
    box-shadow: 0 6px 18px rgba(122, 78, 122, 0.45);
}
.et-fab:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 3px;
}
/* Design sets the glyph two steps up from the label — hence its own element. */
.et-fab-icon {
    font-size: 17px;
    font-weight: 800;
    line-height: 1;
}

/* Gallery/demo containment — same trick as .et-panel--inline: a fixed pill
   escapes the specimen card, so the section drops it into a position:relative
   box and switches it to absolute. */
.et-fab--inline { position: absolute; }


/* ---------- EtListLabel ---------- */
/* Uppercase micro-label introducing a run of rows inside a list surface.
   Collapses three hand-rolled copies that had drifted apart:
   .et-notif-menu-section (10px, 8/16/4), .et-notifications-day (10.5px,
   12/16/6) and .et-expenses-month (10.5px, 10/10/4). The canvas says 10.5px,
   so the 10px was the drift; the paddings are reconciled below.

   The horizontal gutter comes from the LIST rather than the atom, because the
   label has to line up with the TEXT of the rows it introduces and the row
   atoms carry different insets: EtNotifRow is 11px/16px, EtActivityRow is
   12px/10px. That is one declaration on the list
   (`--et-list-label-gutter: 10px` on .et-expenses-list) instead of a padding
   variant per list — and it stays right when a list swaps its row atom. */
.et-list-label {
    padding: 8px var(--et-list-label-gutter, 16px) 4px;
    font-family: var(--et-font-family-base);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--et-color-ink-3);
}
/* A second or later group follows a row; the first follows the edge of the
   surface. The canvas gives the former 14px of air above and the latter 8px,
   so the position decides it, not the caller. The --dense exclusion is what
   the Dense parameter buys: in the bell dropdown every group keeps the 8px
   (canvas does the same there) because that menu is a 340x380 scroller and
   6px of air costs a visible row. Written as one :not() chain rather than a
   modifier override so the two rules cannot be reordered into a tie. */
.et-list-label:not(.et-list-label--dense):not(:first-child) {
    padding-top: 14px;
}


/* ============================================================
   /_dev/ds gallery-specific styles (Pages/_Dev/DesignSystem.razor)
   ============================================================ */

.ds-page {
    padding: 32px;
    background: var(--et-color-bg);
    min-height: 100vh;
    font-family: var(--et-font-family-base);
    /* 1240 = the app shell's own max-width, which is what makes a specimen's
       desktop column able to be the real 682px main column rather than
       whatever is left after the phone column. */
    max-width: 1240px;
    margin: 0 auto;
}
.ds-header { margin-bottom: 24px; }
.ds-eyebrow {
    font-size: 12px;
    font-weight: 800;
    color: var(--et-color-ink-3);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-bottom: 6px;
}
.ds-eyebrow-sm {
    font-size: 11px;
    font-weight: 700;
    color: var(--et-color-ink-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 10px;
}
.ds-title {
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--et-color-ink);
    margin: 0 0 4px 0;
}
.ds-lede {
    font-size: 13.5px;
    color: var(--et-color-ink-2);
    margin: 0;
}
.ds-section {
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-lg);
    box-shadow: var(--et-shadow-card);
    padding: 22px 24px;
    margin-bottom: 20px;
}
.ds-section-title {
    font-size: 15px;
    font-weight: 800;
    color: var(--et-color-ink);
    margin-bottom: 16px;
}
.ds-two-col { display: grid; grid-template-columns: 1fr 260px; gap: 20px; }
.ds-color-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
}
.ds-swatch { display: flex; flex-direction: column; gap: 4px; }
.ds-swatch > div:first-child {
    height: 52px;
    border-radius: 11px;
}
.ds-swatch span {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.ds-swatch code {
    font-size: 10.5px;
    color: var(--et-color-ink-3);
    font-family: 'JetBrains Mono', monospace;
}
.ds-shape-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}
.ds-shape-row b {
    font-size: 12px;
    font-weight: 700;
    color: var(--et-color-ink);
    display: block;
}
.ds-caption {
    font-size: 11px;
    color: var(--et-color-ink-3);
    font-weight: 500;
    display: block;
}
.ds-row {
    display: flex;
    align-items: center;
    gap: 12px;
}
.ds-row-align-end {
    display: flex;
    align-items: flex-end;
    gap: 20px;
}
.ds-wrap { flex-wrap: wrap; }
.ds-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
}
.ds-mt { margin-top: 18px; }


/* ---------- Typography specimen (gallery only) ----------
   A type specimen that doesn't state its values is decoration, so every sample
   in TypographySection carries its size/weight/tracking underneath. Mono and
   ink-3 so the annotation cannot be mistaken for the sample: the samples are
   the app's own classes at the app's own sizes, and anything styled like this
   line is measurement, not UI. */
.ds-type-item + .ds-type-item { margin-top: 16px; }
.ds-type-val {
    display: block;
    margin-top: 4px;
    font-family: var(--et-font-mono);
    font-size: 10.5px;
    line-height: 1.5;
    color: var(--et-color-ink-3);
}
/* NOTE: .ds-type-canvasref lived here — a dashed "measured but not shipped"
   block whose only user was the page-hero phone type. That branch is live now
   (.et-page-hero in app.css), the sample was deleted with it, and no other
   section had ever adopted the class. */
.ds-empty-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px;
}
/* NOTE: the old .ds-phone preview frame lived here. It faked the phone branch
   by re-stating each md- media query scoped to a wrapper class, which had to
   be kept in sync by hand with every component block. DsSpecimen's real
   container column replaced it, no razor file referenced it any more, and its
   two .et-notif-row-* lines would have fought the @container rule those
   media queries became — so it is gone rather than left to rot. */


/* ---------- DsSpecimen (gallery only) ----------
   Two columns of the same children: natural width, then a 390px phone
   column. The phone column is a container so @container-branched atoms
   actually flip here — see the note in Pages/_Dev/DsSpecimen.razor. */
/* Both columns are FIXED at a real width rather than fluid. 682px is the
   Home/group main column inside the 1240 shell; 390px is the phone. A fluid
   desktop column would silently become whatever the catalog had left over —
   at one point 478px, below the 480 threshold, so both columns rendered the
   compact row and the specimen showed no difference at all. */
.ds-specimen {
    display: grid;
    grid-template-columns: 682px 390px;
    justify-content: start;
    gap: 20px;
    align-items: start;
    /* Safety net: the tracks are fixed-width on purpose, so when the section
       card is narrower than 682+20+390 (odd zoom levels, stale-cache
       breakpoints), the specimen scrolls inside the card instead of the
       phone frame bleeding past its rounded edge. */
    max-width: 100%;
    overflow-x: auto;
}
.ds-specimen-col { min-width: 0; }
.ds-specimen-label {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--et-color-ink-3);
    margin-bottom: 8px;
}
.ds-specimen-desktop {
    container-type: inline-size;
    min-width: 0;
}
/* The phone column carries the DS background so a transparent atom reads the
   same as it does on a real screen, plus the device-ish inset. */
.ds-specimen-phone {
    container-type: inline-size;
    width: 390px;
    padding: 12px;
    border-radius: 18px;
    background: var(--et-color-bg);
    box-shadow: inset 0 0 0 1px var(--et-color-border);
}
.ds-specimen-note {
    margin-top: 12px;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--et-color-surface-2);
    font-size: 12px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
}
.ds-specimen-note--same { color: var(--et-color-ink-3); }
/* Below the specimen's own footprint the two columns stack rather than
   shrink. Shrinking would be worse than useless here: a squeezed desktop
   column stops standing for 682px, and the container queries inside it would
   start answering a width no real screen produces.

   1280, not the specimen's raw 1092 (682+20+390): the section card's 24px
   side paddings, the page and shell paddings all sit on top of that, so
   between ~1180 and ~1280 the columns still "fit the viewport" while the
   phone frame overflows the .ds-section card on the right. */
@media (max-width: 1279.98px) {
    .ds-specimen { grid-template-columns: 682px; }
    .ds-specimen-col { overflow-x: auto; }
}


/* ---------- EtTopBar gallery mirror (gallery only) ----------
   .et-topbar's phone form is a @media query (see the note above that block),
   which cannot fire inside the specimen's fixed-width phone COLUMN — @media
   keys off the viewport, and the viewport here stays wide. This restates
   that branch's three declarations scoped to .ds-specimen-phone so the
   gallery can preview it. Keep this in lock-step with .et-topbar's
   @media (max-width: 640px) block by hand — nothing enforces the mirror. */
.ds-specimen-phone .et-topbar {
    gap: 10px;
    padding: 12px 14px;
}
.ds-specimen-phone .et-topbar-name { display: none; }
.ds-specimen-phone .et-topbar-right > .et-btn { display: none; }

/* ---------- EtFab gallery absence (gallery only) ----------
   EtFab is a phone-only atom — its three callers all sit in the MudHidden
   phone branch, and on desktop the primary action is the header CTA. The
   specimen's desktop column therefore shows the ABSENCE: the pill is hidden
   and a muted label says why. Showing the pill there read as "this floats
   on desktop too", which is false. */
.ds-specimen-desktop .et-fab { display: none; }
.ds-fab-absent {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 16px;
    text-align: center;
    font-size: 12px;
    color: var(--et-color-ink-3);
}
.ds-specimen-phone .ds-fab-absent { display: none; }

/* ---------- Touch-device input zoom guard ----------
   iOS Safari auto-zooms the page when a focused text control's font-size is
   under 16px, and the user has to pinch back out — so on touch devices every
   sub-16px text control bumps to exactly 16px. Gated on pointer:coarse, not
   width: iPads zoom too, desktop pointers never do, and desktop keeps the
   designed 14px. (.et-amount-input-num is 48px — already safe.) LAST in the
   file on purpose: it must out-cascade the components' own equal-specificity
   font-size declarations above. */
@media (pointer: coarse) {
    .et-field-input,
    .et-mini-input-field,
    .et-split-row-box-value {
        font-size: 16px;
    }
}
