/* Kassza's own screens and sheets. The generic shell, with the tokens.css
   import, is shell.css, which index.html loads before this file. */

/* ── Paywall sheet body (V6 entitlement) ────────────────────────────
   Components/Domain/PaywallSheet.razor. Re-presented 2026-08-24 (Task 6) on
   EtPanel (ds.css) instead of a fixed-size centered EtDialog — the panel's
   own head/scroll body/footer own the chrome, so only these content blocks
   live here, same division of labour as the PWA guide above. Global rather
   than scoped on purpose: this project loads no scoped-CSS bundle at all
   (see the css note in wwwroot/index.html), so a PaywallSheet.razor.css
   would emit nothing at runtime.

   Layout (redrawn 2026-10-01, spec 2026-10-01-unlock-term-quarter-design.md):
   a tinted status card, the term question + UnlockTermPicker (its own block
   below), the "unlocked until" result row, three facts with check marks, and
   a quiet foot with the coupon link and the recreate note. The status card's
   two lines are still per-state (Wave 3 §6.4 — the "60-day trial reads as
   expired" bug): see PaywallSheet.razor's StatusText/NextText. */
.et-paywall-hero {
    position: relative;
    padding: 16px 16px 15px;
}
/* The gift AI-csomag and monthly allowance above the type slider (owner, 2026-10-06), in the
   hero's surface and the hero's two lines (owner, 2026-10-14): an accent mark like the
   quick-add card's (gold stays the "paid" pair) beside the bold line, the numbers muted below. */
.et-paywall-gift {
    margin-top: 12px;
    padding: 14px 16px 13px;
}
/* The tinted card itself. The event panel's holiday quick-add card
   (EventEditPanel, block below) and the paywall's gift card wear the same
   surface on purpose. */
.et-paywall-hero,
.et-paywall-gift,
.et-event-quickadd {
    border-radius: 16px;
    background:
        radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--et-color-accent) 16%, transparent) 0%, transparent 60%),
        color-mix(in srgb, var(--et-color-accent) 7%, var(--et-color-surface));
    border: 1px solid color-mix(in srgb, var(--et-color-accent) 16%, var(--et-color-border));
}
/* Quick-add card: the hero's mark + bold line share a row, the muted line
   sits below — two lines, not three (owner, 2026-10-02) — as one button
   with a chevron. The mark is accent-tinted, not the gold PRO pair — gold
   means "paid" everywhere else. */
.et-event-quickadd {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 14px 14px 14px 16px;
    font-family: inherit;
    text-align: left;
    color: var(--et-color-ink);
    cursor: pointer;
    transition: filter .15s;
}
.et-event-quickadd:hover { filter: brightness(1.02); }
.et-event-quickadd:active { filter: brightness(0.97); }
.et-event-quickadd:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-event-quickadd-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}
/* Mark + title on one line; flex-wrap lets a very narrow screen still
   degrade to two lines here instead of clipping the title. */
.et-event-quickadd-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.et-event-quickadd-mark,
.et-paywall-gift-mark {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    border-radius: var(--et-radius-pill);
    background: color-mix(in srgb, var(--et-color-accent) 14%, var(--et-color-surface));
    color: var(--et-color-accent);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.et-event-quickadd-title {
    font-size: 16px;
    font-weight: 800;
    line-height: 1.35;
    letter-spacing: -0.01em;
}
.et-event-quickadd-hint {
    margin-top: 2px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
}
.et-event-quickadd-chevron {
    flex-shrink: 0;
    font-size: 24px;
    line-height: 1;
    color: var(--et-color-accent);
}
.et-paywall-hero-mark {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    border-radius: var(--et-radius-pill);
    background: var(--et-color-pro-bg);
    color: var(--et-color-pro-ink);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.08em;
}
/* The mark leads the status line (owner, 2026-10-02): the longest status, the
   paid one with its date, still fits beside it on a 375px phone. The wrap is
   only the safety net for a narrower screen or a larger font. */
.et-paywall-hero-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.et-paywall-status {
    font-size: 16px;
    font-weight: 800;
    line-height: 1.35;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-paywall-next {
    margin-top: 4px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
}
.et-paywall-intro {
    margin: 16px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--et-color-ink);
}
.et-paywall-section-label {
    margin: 20px 0 10px;
    font-size: 13px;
    font-weight: 800;
    color: var(--et-color-ink);
}
/* The no-offer fallback (a stale 402 with no entitlement in hand). */
.et-paywall-price {
    margin-top: 18px;
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
/* What the picked term buys: a quiet row the date stands out of. */
.et-paywall-until {
    margin-top: 12px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 11px 14px;
    border-radius: 12px;
    background: var(--et-color-surface-2);
    font-size: 13px;
    color: var(--et-color-ink-2);
}
.et-paywall-until-value {
    font-weight: 800;
    color: var(--et-color-ink);
    font-variant-numeric: tabular-nums;
}
.et-paywall-facts {
    margin: 20px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 9px;
}
/* Under its own heading (the pack sheet's "Mikor éri meg?", ai-badges spec §5.2) the label's
   bottom margin is the gap. */
.et-paywall-section-label + .et-paywall-facts { margin-top: 0; }
.et-paywall-facts li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--et-color-ink-2);
}
/* An 18px disc on the first line's centre (13px × 1.45 = 18.85px line box).
   A span around the glyph, as .et-term-option-radio does: the padded <svg> it
   replaced was content-box (no global border-box here), so the disc grew to
   24px and hung ~3px below the text. */
.et-paywall-fact-check {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    margin-top: 0.5px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--et-color-owed) 16%, transparent);
    color: var(--et-color-owed);
}
.et-paywall-fact-check svg { width: 12px; height: 12px; }
.et-paywall-foot {
    margin-top: 20px;
    padding-top: 14px;
    border-top: 1px solid var(--et-color-border);
}
.et-paywall-recreate {
    margin-top: 10px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--et-color-ink-3);
}

/* GetAppDialog.razor — the paywall's "buy in the app" card on the web. The store
   buttons are the landing's (landing/b.css .get-store): an ink badge with the store's
   mark, a small "Letöltés" over the store's name. Ink on surface flips with the
   theme, so dark mode gets the light badge the stores' own guidelines show there. */
.et-get-app-stores {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.et-get-app-store {
    flex: 1 1 150px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 10px 16px 10px 14px;
    font-family: inherit;
    text-align: left;
    background: var(--et-color-ink);
    color: var(--et-color-surface);
    border: none;
    border-radius: 14px;
    text-decoration: none;
    cursor: pointer;
}
.et-get-app-store svg { flex-shrink: 0; width: 22px; height: 22px; fill: currentColor; }
.et-get-app-store span { display: flex; flex-direction: column; }
.et-get-app-store small { font-size: 11px; font-weight: 500; line-height: 1.2; opacity: 0.8; }
.et-get-app-store b { font-size: 16px; font-weight: 700; line-height: 1.2; letter-spacing: -0.01em; }

/* ── Unlock term picker (spec 2026-10-01) ─────────────────────────────
   Components/Domain/UnlockTermPicker.razor, on the paywall. Two stacked option cards forming a radio group: a radio dot
   that fills with a check, name + badge, a "who is it for" line, the price on
   the right. The selected card takes the accent border and a soft tint; the
   other stays a plain surface so the choice reads at a glance. Global, as
   every domain component's CSS is here. */
.et-term-picker {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.et-term-option {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    padding: 14px 14px 14px 13px;
    border: 1.5px solid var(--et-color-border);
    border-radius: 16px;
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    font-family: inherit;
    text-align: left;
    justify-content: flex-start;
    cursor: pointer;
    transition: border-color var(--et-motion-fast, 160ms) ease, background-color var(--et-motion-fast, 160ms) ease, box-shadow var(--et-motion-fast, 160ms) ease;
}
.et-term-option:hover { border-color: var(--et-color-border-strong); }
.et-term-option:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-term-option--selected,
.et-term-option--selected:hover {
    border-color: var(--et-color-accent);
    background: color-mix(in srgb, var(--et-color-accent) 6%, var(--et-color-surface));
    box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--et-color-accent) 55%, transparent);
}
.et-term-option-radio {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-top: 1px;
    border-radius: 50%;
    border: 1.5px solid var(--et-color-border-strong);
    background: var(--et-color-surface);
    color: transparent;
}
.et-term-option-radio svg { width: 12px; height: 12px; }
.et-term-option--selected .et-term-option-radio {
    border-color: var(--et-color-accent);
    background: var(--et-color-accent);
    color: #fff;
}
/* A two-column grid: name | price, badge | struck price, then the per-member
   line across both columns — the full card width, so it fits one line. */
.et-term-option-body {
    flex: 1;
    min-width: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 10px;
    row-gap: 3px;
    align-items: center;
}
.et-term-option-per { grid-column: 1 / -1; }
.et-term-option-deal { display: flex; min-width: 0; }
.et-term-option-name {
    font-size: 15px;
    font-weight: 800;
    letter-spacing: -0.01em;
}
.et-term-option-badge {
    padding: 2px 8px;
    border-radius: var(--et-radius-pill);
    background: color-mix(in srgb, var(--et-color-accent) 14%, transparent);
    color: var(--et-color-accent);
    font-size: 11px;
    font-weight: 700;
    white-space: nowrap;
}
.et-term-option-per {
    font-size: 12px;
    color: var(--et-color-ink-3);
}
.et-term-option-amount {
    justify-self: end;
    font-size: 16px;
    font-weight: 800;
    letter-spacing: -0.01em;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.et-term-option-full {
    justify-self: end;
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-3);
    text-decoration: line-through;
    white-space: nowrap;
}

/* Coupon redemption (hand-distributed beta-tester codes) — quiet text link
   that reveals an inline input + Beváltás row, deliberately not a competing
   CTA next to the real purchase button (spec: "Kuponkódom van"). */
.et-paywall-coupon {
    margin-top: 0;
}
.et-paywall-coupon-link {
    background: none;
    border: none;
    padding: 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--et-color-accent);
    text-decoration: underline;
    cursor: pointer;
}
/* The restore link and its ⓘ, whose sheet holds the foot's notes. */
.et-paywall-restore-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.et-paywall-restore-hint {
    margin-top: 2px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--et-color-ink-3);
}
.et-paywall-coupon-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.et-paywall-coupon-input {
    flex: 1;
    min-width: 0;
    padding: 8px 10px;
    border: 1px solid var(--et-color-border);
    border-radius: 8px;
    background: var(--et-color-bg);
    font-family: inherit;
    font-size: 13px;
    color: var(--et-color-ink);
    text-transform: uppercase;
}

/* Sticky group-detail tabs */
.group-detail-tabs {
    position: sticky;
    top: var(--et-appbar-height);
    z-index: 5;
    background: var(--et-color-bg);
}

/* ──────────── V6 "PRO" in-button badge (Task 6, spec §2.4 fix round) ────────────
   Renders INSIDE the button it decorates — GroupDetail's Fab (EtFab's Badge
   slot) and the header "+ Új költség" CTA (MainLayout) — never as a sibling
   or wrapper element. The previous approach wrapped the Fab in
   .et-group-view-fab-wrap so a badge could sit next to it; that wrapper
   survived at >=960px where the rule above only hides .et-fab itself,
   leaving a badge floating alone bottom-center on desktop. A badge that
   lives inside the button's own children can never outlive it.

   Shares the fixed PRO token (--et-color-pro-bg/-ink, ds.css) with the
   header chip and the groups-card label — no more separate hint/lapsed
   tones (spec §2.4 revised 2026-08-24: "one CSS token pair, no per-surface
   colors"). cursor:pointer because both states this renders in (paid ≤60d,
   lapsed) open the paywall on tap.

   Content is rendered through EtProLabel (Wave 3 spec §6.2), same as the
   header chip and the card label — font-weight/letter-spacing here are
   only the .et-pro-rest baseline; the "PRO" prefix itself is bumped to
   .et-pro-mark's heavier weight (ds.css). */
.et-pro-badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--et-color-pro-bg);
    color: var(--et-color-pro-ink);
    font-family: var(--et-font-family-base);
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

/* Payment detail — From → To transfer block. 3x3 grid (caption / avatar /
   name) so the arrow column lands on the avatar row exactly. */
.payment-transfer {
    display: grid;
    grid-template-columns: minmax(88px, 1fr) auto minmax(88px, 1fr);
    grid-template-rows: auto auto auto;
    justify-items: center;
    align-items: center;
    row-gap: 4px;
    column-gap: 32px;
}
.payment-transfer__caption { opacity: 0.7; }

/* Payment detail page — allocation list. Each row: arrow + description +
   amount + date. Reverse arrows pick up the success-green tone to read as
   "credit absorbed" rather than "debt paid". */
.payment-allocations {
    border-top: 1px solid var(--et-color-border);
    padding-top: 8px;
}
.payment-allocation-row {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 6px 0;
    font-size: 0.9em;
}
.payment-allocation-row .pa-arrow {
    font-weight: 600;
    width: 1.2em;
    text-align: center;
    line-height: 1.4;
}
/* Allocation direction tones — shared between the /payments/{id} list and
   the activity row hover meta. Forward = sender paid out (↓, red); reverse
   = sender absorbed credit (↑, green). Global so non-detail-card consumers
   (e.g. .ra-meta payment lines) get the same color treatment without an
   extra wrapper. */
.pa-arrow--forward { color: var(--et-color-owe); font-weight: 600; }
.pa-arrow--reverse { color: var(--et-color-owed); font-weight: 600; }
/* Two-line text stack — primary (who paid) and line2 (group badge +
   description, with hover-revealed category · split · event meta).
   Mirrors the home recent-activity row pattern so the /payments/{id}
   allocation list reads identically to the recent-activity card. */
.payment-allocation-row .pa-text-stack {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.payment-allocation-row .pa-primary {
    display: block;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
/* Line 2: badge + description, with optional meta (category/split/event)
   that fades in on hover. Flex row so the meta sits inline after the
   description and both can ellipsis-truncate when the row is narrow. */
.payment-allocation-row .pa-line2 {
    display: flex;
    align-items: center;
    min-width: 0;
    font-size: 0.85em;
    color: var(--et-color-ink-2);
    overflow: hidden;
}
.payment-allocation-row .pa-line2 .pa-desc {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    flex: 0 1 auto;
}
.payment-allocation-row .pa-desc-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.payment-allocation-row .pa-meta {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.payment-allocation-row .pa-meta::before {
    content: " · ";
    padding: 0 4px;
    opacity: 0.55;
}
@media (hover: hover) {
    .payment-allocation-row--clickable:hover .pa-meta {
        opacity: 1;
    }
}
@media (max-width: 767.98px) {
    .payment-allocation-row .pa-meta { display: none; }
}
.payment-allocation-row .pa-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    flex-shrink: 0;
}
.payment-allocation-row .pa-amount { font-weight: 600; flex-shrink: 0; }
.payment-allocation-row .pa-date { flex-shrink: 0; color: var(--et-color-ink-2); font-size: 0.85em; }
.payment-allocation-row .pa-info { flex-shrink: 0; display: inline-flex; align-items: center; }

/* Clickable variant — whole row opens the expense-detail dialog, with the
   trailing info button as an explicit affordance. Mirrors the settle-screen
   row treatment (cursor + subtle hover tint + inset rounding) so the two
   read the same. */
.payment-allocation-row--clickable {
    cursor: pointer;
    border-radius: 4px;
    padding-inline: 4px;
    margin-inline: -4px;
    transition: background-color 120ms ease;
}
.payment-allocation-row--clickable:hover {
    background-color: var(--et-color-row-hover, rgba(0, 0, 0, 0.04));
}
.payment-allocation-row--clickable:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}

/* Dimmed variant — picker uses this for unselected rows so the amount and
   meta fade back without disappearing. The leading checkbox stays full
   opacity (it's the affordance to bring the row back). */
.payment-allocation-row--dimmed .pa-arrow,
.payment-allocation-row--dimmed .pa-text-stack,
.payment-allocation-row--dimmed .pa-right {
    opacity: 0.45;
    transition: opacity 0.15s ease;
}

/* ==========================================================================
   Hotfix-1 — UX Round 4 post-merge fixes
   ========================================================================== */

/* PersonBalanceRow: long counterparty names (email-style) used to push the
   settle button outside the card. Names now wrap to 2 lines and ellipsis
   beyond; the badge + button stay glued to the right edge via flex-shrink:0. */
.pb-row-name {
    overflow: hidden;
}
.pb-row-display-name {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-word;
    line-height: 1.2;
}

.et-pie-slice {
    transform-origin: center;
    transition: transform 0.18s ease-out;
}
.et-pie:hover .et-pie-slice { transform: scale(0.99); }
.et-pie .et-pie-slice:hover { transform: scale(1.04); }

/* Needs-attention strip — defined globally (not in NeedsAttentionCarousel.razor.css)
   for the same reason as the .uec-* rules above: the Blazor scoped-CSS bundle
   is not wired into index.html, so .razor.css files silently no-op. */
/* Wrap is the positioning context for the absolutely-placed arrows; mirrors
   the .uec-carousel-wrap pattern. Keeping arrows out of the scroll container
   stops scroll-snap from parking the strip at scrollLeft > 0 and frees the
   ~32px of row width the arrows used to consume as flex children. */
.nac-strip-wrap {
    position: relative;
}
.nac-strip {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding: 4px 8px;
    /* See .uec-carousel: scrollbar-width handles Firefox + Chromium overlay
       mode where ::-webkit-scrollbar is ignored. */
    scrollbar-width: none;
}
.nac-strip::-webkit-scrollbar { display: none; }

.nac-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 1;
}
.nac-arrow-left  { left: 0; }
.nac-arrow-right { right: 0; }
@media (hover: hover) {
    .nac-strip-wrap:hover .nac-arrow { opacity: 1; }
}

/* Ack chip on dispute rows/cards — interactive, so it needs a clearly
   actionable affordance. Lifts on hover, presses on click; transitions
   are short so the press feedback feels tactile rather than animated. */
.nac-ack-chip-wrap {
    display: inline-flex;
    cursor: pointer;
}
.nac-ack-chip {
    transition: transform 0.12s ease-out, box-shadow 0.12s ease-out, filter 0.12s ease-out;
    box-shadow: var(--et-shadow-sm);
}
.nac-ack-chip-wrap:hover .nac-ack-chip {
    transform: translateY(-1px);
    box-shadow: var(--et-shadow-md);
    filter: brightness(1.05);
}
.nac-ack-chip-wrap:active .nac-ack-chip {
    transform: translateY(0);
    box-shadow: var(--et-shadow-sm);
    filter: brightness(0.95);
}
.nac-ack-chip-wrap:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
    border-radius: 16px;
}

@media (max-width: 768px) {
    .nac-arrow { display: none; }
}

/* Scroll affordance for both carousel strips. The native scrollbar is
   hidden everywhere and desktop arrows only appear on hover, so without a
   hint the user has no way to know — before interacting — that more cards
   exist beyond the viewport edge. carousel.js toggles the data-can-scroll-*
   attributes from the scroll position; the mask gradient fades the strip
   only on the side that actually has more content, and goes away entirely
   once the user reaches the corresponding end. Applied at every breakpoint
   so the affordance is consistent and complements the desktop arrows. */
.nac-strip[data-can-scroll-right="true"] {
    -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%);
}
.nac-strip[data-can-scroll-left="true"] {
    -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%);
}
.nac-strip[data-can-scroll-left="true"][data-can-scroll-right="true"] {
    -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%);
}

/* Hotfix-5: PersonBalanceRow amount tone. Green = they owe me,
   Red = I owe, neutral = settled / unknown. */
.pb-amount {
    font-weight: 600;
    font-size: 0.95rem;
}
.pb-amount-positive { color: var(--et-color-owed); }
.pb-amount-negative { color: var(--et-color-owe); }
.pb-amount-neutral  { color: var(--et-color-ink); }

/* ──────────── AppBar group switcher (Home redesign 2026-06-29) ────────
   Pill in the AppBar showing overlapping group-color dots + label + caret.
   Sits between the brand and the "+ Új költség" button in the mockup; it is
   the EtDropdown trigger for the DS GroupMenu (see GroupSwitcher.razor).
   `font: inherit` before the font-* overrides keeps the real <button> at the
   metrics the old div had; `justify-content` stays spelled out so no future
   global button rule can re-centre the row. */
.et-group-switcher {
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding: 6px 12px 6px 8px;
    background: var(--et-color-surface-2);
    border: 1.5px solid transparent;
    border-radius: 999px;
    font: inherit;
    font-weight: 700;
    font-size: 0.8125rem;   /* 13px */
    color: var(--et-color-ink);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.et-group-switcher:hover {
    border-color: var(--et-color-border-strong);
}
.et-group-switcher:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-group-switcher-dots {
    display: inline-flex;
}
.et-group-switcher-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1.5px solid var(--et-color-surface-2);
    margin-left: -4px;
}
.et-group-switcher-dot:first-child {
    margin-left: 0;
}
.et-group-switcher-caret {
    color: var(--et-color-ink-3);
    font-size: 0.6875rem;
    margin-left: 2px;
}

/* Compact trigger (header redesign 2026-09-03) — PHONE-ONLY. The trigger
   always renders disc + dots + label (GroupSwitcher.razor); at >=960px the
   disc stays display:none and the pill is the original dots + "Összes"/name
   form. Below 960px the label goes at every route so the pill is equally
   small on Home and on a group screen: a disc when one group is the answer
   (single-group user, or a group-scoped route — .et-group-switcher--compact),
   the bare dot stack otherwise. min-height keeps the two phone forms the
   same height. `justify-content` stays spelled out for the same reason as
   the base rule above — no future global button rule should re-centre it. */
.et-group-switcher-icon {
    display: none;          /* desktop: the original pill, no disc */
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: 50%;
    place-items: center;
    font-size: 0.8125rem;  /* 13px — emoji */
    line-height: 1;
}
/* Initial-letter fallback (no group Icon): white bold text on the group's
   own color, matching the avatar-initial precedent (.et-appbar-avatar-circle). */
.et-group-switcher-icon--fallback {
    font-size: 0.6875rem;  /* 11px */
    font-weight: 700;
    color: #fff;
}
@media (max-width: 959.98px) {
    .et-group-switcher-label { display: none; }
    .et-group-switcher { min-height: 32px; }
    .et-group-switcher--compact {
        padding: 4px 10px 4px 4px;
        gap: 6px;
        justify-content: flex-start;
    }
    .et-group-switcher--compact .et-group-switcher-dots { display: none; }
    .et-group-switcher--compact .et-group-switcher-icon { display: grid; }
}

/* ──────────── Home page section titles (redesign 2026-06-29) ────────
   The greeting hero's own type used to live here (.et-home-hero
   .mud-typography-h5 + .et-home-subtitle). Both moved into the shared
   .et-page-hero trio in shell.css — search "Shared page hero".
   The h5 rule was already unreachable when it was deleted: HomePage mounts
   PageHeader only below md, and PageHeader renders its h5 only at md and up,
   so nothing could ever match both halves of the selector.
   Section titles above each home card are EtSectionHeader (ds.css). The
   .et-home-section-title / -count pair that used to live here was the
   pre-DS version of the same thing, kept alive by a single caller (the
   Tennivaló header) after every other section had moved over. Its extra
   `margin: 20px 2px 12px` is what pushed the left column 4px down and 2px
   right of the right column; the caller now uses the DS atom and the rules
   are gone. */
.et-home-todo-link {
    color: var(--et-color-accent, #7A4E7A);
    text-decoration: underline dotted;
    text-underline-offset: 3px;
    font-weight: 600;
}
.et-home-todo-link:hover {
    color: color-mix(in srgb, var(--et-color-accent, #7A4E7A) 80%, #000);
}

/* AdaptiveCardStrip's phone block (shell.css): the todo shelf's own rules. */
@media (max-width: 959.98px) {
    /* Carousel mode (2+ todos) borrows the events shelf's 220px card. The two
       strips sit directly under one another on the phone canvas, and cards
       sized by their own content made the lower shelf's card widths and its
       peeking next-card disagree with the one above it. Only the todo shelf
       is pinned: grid mode (a single todo) still stretches edge-to-edge,
       because there it IS the section rather than a shelf.
       The padding goes with it — .et-card-strip above has none, so keeping it
       would leave the two shelves' left edges 8px apart and their card tops
       4px apart, which is the other half of "they don't line up". What the
       top padding buys is 3px of clearance for --et-shadow-card's upward
       bleed (0 2px 10px at 5% alpha); the events shelf has clipped exactly
       that all along, so the trade is a shadow nobody can see against an
       alignment everybody can. */
    .nac-strip:not([data-strip-count="1"]) {
        padding-left: 0;
        padding-right: 0;
        padding-top: 0;
        /* 14px, .et-card-strip's gap — with the widths matched, an unequal
           gap would still park the second card 2px off the one above it. */
        gap: 14px;
    }
    .nac-strip:not([data-strip-count="1"]) > .et-todo-card {
        /* box-sizing is load-bearing: this project has no global border-box
           reset, and .et-todo-card pads its own root by 14px a side, so a
           percentage width would measure wider than the strip's content box
           and let the next row peek in.
           One row per page (mobile compaction §2.3): the todo row is now
           short enough that a 220px card would waste two thirds of the
           phone's width on nothing, and the shelf's "there is more" job is
           done by the dot row below it instead of by a peeking neighbour. */
        box-sizing: border-box;
        flex: 0 0 100%;
        width: auto;
    }
    /* …and with exactly one row on screen nothing can peek, so the edge
       fades would only dim a row the user is reading. The dots are the
       affordance here; carousel.js still maintains the attributes for the
       events shelf, which keeps its fades. */
    .nac-strip[data-can-scroll-left="true"],
    .nac-strip[data-can-scroll-right="true"],
    .nac-strip[data-can-scroll-left="true"][data-can-scroll-right="true"] {
        -webkit-mask-image: none;
                mask-image: none;
    }

    /* ── pilot toggle (temporary, removed once the owner decides) ──
       The `card` variant is the shelf as it stood at 1a4d6dd0: 220px cards
       matched to the events shelf, and the edge fade back on because with a
       neighbour peeking there IS something to fade towards. Both rules are
       additions, not edits — the row rules above key on `.et-todo-card` and
       this variant renders `.et-todo-card-lg`, so they simply do not match
       each other and the default shelf is untouched.
       The dot row is not turned off here: NeedsAttentionCarousel does not
       render it under this flag at all, because it did not exist before #452. */
    html[data-todo-card="card"] .nac-strip:not([data-strip-count="1"]) > .et-todo-card-lg {
        /* box-sizing is load-bearing: this project has no global border-box
           reset, and the card pads its own root by 18px a side, so a bare
           width:220px would measure 256 on the outside and miss the event card
           by 36px. */
        box-sizing: border-box;
        width: 220px;
    }
    html[data-todo-card="card"] .nac-strip[data-can-scroll-right="true"] {
        -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%);
    }
    html[data-todo-card="card"] .nac-strip[data-can-scroll-left="true"] {
        -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%);
    }
    html[data-todo-card="card"] .nac-strip[data-can-scroll-left="true"][data-can-scroll-right="true"] {
        -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%);
    }

    /* The `compact` variant (spec 2026-09-24 §4): the row itself, re-laid-out
       into the events shelf's footprint. Same width rule the events shelf uses
       — max(200px, 55%), not the `card` variant's fixed 220 — so the two
       shelves agree about how much of the next card peeks at every phone
       width, which is the whole point of matching them.

       This one DOES have to out-specify the row: .et-todo-card--compact
       still carries .et-todo-card, so the `flex: 0 0 100%` one-per-page rule
       above matches it too. The html prefix is what wins the tie.

       DEFAULT since 2026-09-26, so every rule here also matches a root with no
       data-todo-card at all (pre-paint-theme.js stamps only the non-default
       values). :is() weighs as much as the one attribute it replaced. */
    html:is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip:not([data-strip-count="1"]) > .et-todo-card {
        box-sizing: border-box;
        flex: 0 0 auto;
        width: max(200px, 55%);
    }
    /* ...and it follows the event card's narrower sizes too (2026-09-25), for
       the same reason: the two shelves are one system on the phone. The small
       size is the default event card since 2026-09-26 — same absence rule. */
    html:is(:not([data-event-card]), [data-event-card="compact-small"]):is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip:not([data-strip-count="1"]) > .et-todo-card {
        width: max(190px, 53%);
    }
    html[data-event-card="compact-mini"]:is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip:not([data-strip-count="1"]) > .et-todo-card {
        width: max(165px, 46%);
    }
    /* With a neighbour peeking there IS something to fade towards, so the edge
       fades come back — same three states as the `card` variant above. */
    html:is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip[data-can-scroll-right="true"] {
        -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%);
    }
    html:is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip[data-can-scroll-left="true"] {
        -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%);
    }
    html:is(:not([data-todo-card]), [data-todo-card="compact"]) .nac-strip[data-can-scroll-left="true"][data-can-scroll-right="true"] {
        -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%);
    }
    /* ── end pilot toggle ── */
}

/* ──────────── Accessible focus ring (Task 4) ────────────
   Replaces browser/UA defaults with an accent-colored 3px ring that
   reads on every palette. Uses :focus-visible so the ring only appears
   on keyboard focus (not on every click). */
/* In app.css although it is generic: its border-radius overrides, at equal
   specificity, the corners the Kassza rules above give focusable controls
   (term options, quick-add card, group switcher, carousel arrows, coupon
   input). In shell.css, which loads first, it would lose to them. */
:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--et-color-accent) 75%, transparent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* EtFocusOnNavigate focuses the page's h1 (tabindex="-1") on every page load
   so screen readers land on it. On a fresh load with no click yet — the Google
   sign-in round trip, a reload — the browser counts that as :focus-visible and
   draws the ring above around the heading, which reads as "selected". The
   heading is never a keyboard target, so it never needs the ring. */
h1[tabindex="-1"]:focus {
    outline: none;
}

/* ──────────── Progress ring (Task 9) ──────────── */
.et-progress-ring {
    display: inline-block;
    vertical-align: middle;
}
.et-progress-ring-bg {
    stroke: color-mix(in srgb, var(--et-color-border) 100%, transparent);
}
.et-progress-ring-fg {
    stroke: var(--et-color-accent);
    transition: stroke-dashoffset 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.et-progress-ring-text {
    fill: var(--et-color-ink-2);
    font-family: var(--et-font-sans);
    font-weight: 500;
}
/* Settled state — when value >= total, paint the arc in success-green. */
.et-progress-ring-settled .et-progress-ring-fg {
    stroke: var(--et-color-owed);
}

/* ──────────── Pie chart (Task 14) ──────────── */
.et-pie-slice {
    transform-origin: center;
    transition: transform 0.18s ease-out;
}
.et-pie:hover .et-pie-slice {
    transform: scale(0.99);   /* whole pie subtly shrinks on hover */
}
.et-pie .et-pie-slice:hover {
    transform: scale(1.04);   /* hovered slice pops slightly */
}

/* ── DS expense panel (/expenses/new) page layout ───────────────────
   Spacing follows the design's live "Új költség" screen: 20px between
   major blocks, 10px inside the "További részletek" stack. */
.et-expense-block { margin-bottom: 20px; }
.et-expense-amount { text-align: center; padding: 0 0 20px; }
/* Holds the amount and, when the receipt scan is on, its button. The button sits
   completely out of flow (.et-ai-scan below is absolutely positioned), so the amount
   centres exactly as it did before the scan existed — it never moves for the button
   (owner: "the icon must not move it"). */
.et-expense-amount-row {
    position: relative;
}

/* "✨ AI blokk" (spec 2026-10-05-receipt-scan-design.md §6.1): a 44px round CTA in the
   palette's gradient (#351), its caption under it, pinned to the amount area's right
   edge. `bottom: 0` lines the button's own bottom up with .et-amount-input-box's bottom
   — that box's height is fixed by its font size, not by how many digits it holds, so
   this holds regardless of the typed amount's width, and lands close enough to the
   amount's vertical centre that no separate offset is needed. Being out of flow, it
   never affects the amount's own centring.
   Visible only while the amount is empty (owner: "when I start typing a number, the
   icon fades out; when the field is empty again, it comes back") — opacity + a slight
   scale, ~180ms, compositor-only properties (phone motion rule), off for reduced
   motion. The element stays mounted (ExpenseNew toggles .et-ai-scan--hidden, not the
   element itself) so the fade runs both ways, and the shimmer below only plays while
   .et-ai-scan--idle is present, which ExpenseNew only adds while visible. The hidden
   state is also non-interactive: ExpenseNew pairs this class with tabindex="-1" and
   aria-hidden, and pointer-events here is the visual half of that. */
.et-ai-scan {
    position: absolute;
    /* In from the edge: the ✨ badge overhangs the circle by 6px, and at 0 it sat
       against the panel's padding (owner, 2026-10-08). */
    right: 10px;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    border: 0;
    padding: 0 0 4px;
    background: none;
    font-family: inherit;
    cursor: pointer;
    opacity: 1;
    transform: scale(1);
    transition: opacity 180ms ease, transform 180ms ease;
}
.et-ai-scan--hidden {
    opacity: 0;
    transform: scale(0.85);
    pointer-events: none;
}
.et-ai-scan-orb {
    position: relative;
    width: 44px;
    height: 44px;
}
.et-ai-scan-circle {
    position: relative;
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    overflow: hidden;
    background: var(--et-cta-gradient);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--et-color-accent) 35%, transparent);
    font-size: 20px;
    line-height: 1;
}
.et-ai-scan--idle .et-ai-scan-circle::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.5) 50%, transparent 70%);
    transform: translateX(-100%);
    animation: et-ai-scan-shimmer 3.2s ease-in-out infinite;
}
@keyframes et-ai-scan-shimmer {
    0%, 55% { transform: translateX(-100%); }
    100%    { transform: translateX(100%); }
}
.et-ai-scan-badge {
    position: absolute;
    top: -5px;
    right: -6px;
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--et-color-surface);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    font-size: 11px;
    line-height: 1;
}
.et-ai-scan-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--et-color-ink-2);
    white-space: nowrap;
}
.et-ai-scan:focus-visible .et-ai-scan-circle {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .et-ai-scan--idle .et-ai-scan-circle::after { animation: none; opacity: 0; }
    .et-ai-scan { transition: none; }
}

/* Applied receipt lines stand in for the split tabs: one row, and the way back
   into the sheet. */
.et-receipt-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--et-color-border);
    border-radius: 14px;
    background: var(--et-color-surface);
}
.et-receipt-summary-glyph {
    font-size: 18px;
    line-height: 1;
}
.et-receipt-summary-text {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-receipt-summary-edit {
    flex-shrink: 0;
    border: 0;
    padding: 6px 2px;
    background: none;
    color: var(--et-color-accent);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
/* A Saját kassza's receipt (personal-kassza D32): the category totals under the summary row. */
.et-receipt-summary-categories {
    margin-top: 10px;
    font-size: 13px;
    color: var(--et-color-ink-2);
    font-variant-numeric: tabular-nums;
}
/* The demo receipt's confirmation (D33): the question, then the shared kassza's consequence. */
.et-demo-confirm-text { margin: 0; }
.et-demo-confirm-text + .et-demo-confirm-text { margin-top: 10px; }
.et-expense-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 10px;
}
.et-expense-details {
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* Every other section on the new-expense form is wrapped in
       .et-expense-block (margin-bottom: 20px); this container was the one
       exception, so whatever followed it sat flush against its last row — the
       attachment picker in ExpenseNew. Fixing it here rather than only on the
       next block keeps the form's rhythm uniform and does not depend on which
       element happens to come next. .et-panel-body is a plain block, so this
       collapses with the following block's own margin-top instead of stacking
       into 40px. Harmless for the other user (RecipientEditPanel), where this
       container is the last thing before the panel footer. */
    margin-bottom: 20px;
}
.et-expense-suggest {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}
.et-expense-suggest-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-2);
}
.et-expense-error--center { text-align: center; }
.et-expense-picker-sub {
    font-size: 11px;
    color: var(--et-color-ink-3);
    margin-left: auto;
}
/* The kind chooser's rows (the sheet title's menu): the explanation is a
   sentence, not a date, so it sits under the label instead of beside it. */
.et-expense-kind-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.et-expense-kind-text .et-expense-picker-sub {
    margin-left: 0;
    font-weight: 500;
}
/* Loan / money request: one quiet line under the participant rows saying how
   to use them. The rows' surface leaves 8px instead of 20px above it, so the
   line reads as theirs; the 20px block rhythm resumes below. */
.et-expense-hint {
    margin-bottom: 20px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--et-color-ink-3);
}
/* The same line under one field of the .et-expense-details stack, whose 10px gap spaces it. */
.et-expense-hint--field { margin-bottom: 0; }

/* ── Receipt sheet (ReceiptSheet, spec 2026-10-05-receipt-scan-design.md §6.2) ──
   One card per line: name · quantity · total, the member chips under it. The
   chips wrap rather than scroll, so every member of a line is visible at once —
   the whole job of the sheet is seeing who had what. */
.et-receipt-loading {
    margin-bottom: 12px;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink-2);
}
.et-receipt-skeleton { margin-bottom: 10px; border-radius: 14px; }
/* "Kik között osztjuk szét?" (spec D13) — one toggle chip per member, above everything else in
   the ready state. Reuses the item-line chip vocabulary (.et-receipt-chip*) as-is: on/off is the
   same visual language either way, just with no +/− or "×" count here. */
.et-receipt-participants { margin-bottom: 14px; }
.et-receipt-participants-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 8px;
}
.et-receipt-remaining {
    margin-bottom: 10px;
    font-size: 12px;
    color: var(--et-color-ink-3);
}
/* The PRO pool an unpaid group would get (spec §13), under the limit / not-eligible banner;
   the footer's unlock button is the call to action, so this line stays quiet. */
.et-receipt-upsell {
    margin-top: 12px;
    font-size: 13px;
    color: var(--et-color-ink-2);
}
/* The AI-bérlet under the AI-csomag's line (ai-pass spec §4.2c): the pack stays the offer that
   leads the footer, so the pass is a quiet text link, the paywall's coupon-link look. */
.et-receipt-pass-link {
    display: block;
    margin-top: 6px;
    padding: 0;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    text-align: left;
    color: var(--et-color-accent);
    text-decoration: underline;
    cursor: pointer;
}
.et-receipt-check { margin-bottom: 14px; }
.et-receipt-lines,
.et-receipt-extras {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 18px;
}
.et-receipt-line,
.et-receipt-extra,
.et-receipt-tip {
    padding: 12px 14px;
    border: 1px solid var(--et-color-border);
    border-radius: 14px;
    background: var(--et-color-surface);
}
/* After a failed "Kész" only — the form-validation rule: nothing is red before. */
.et-receipt-line--error {
    border-color: var(--et-color-owe);
    box-shadow: 0 0 0 1px var(--et-color-owe);
}
.et-receipt-line-head,
.et-receipt-edit {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.et-receipt-line-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-receipt-line-qty {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 700;
    color: var(--et-color-ink-3);
}
.et-receipt-line-amount {
    flex-shrink: 0;
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.et-receipt-line-edit,
.et-receipt-line-delete {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 8px;
    padding: 0;
    background: none;
    color: var(--et-color-ink-3);
    font-family: inherit;
    font-size: 15px;
    cursor: pointer;
}
.et-receipt-line-edit--on {
    color: var(--et-color-accent);
    font-weight: 800;
}
.et-receipt-input {
    min-width: 0;
    border: 1.5px solid var(--et-color-border-strong);
    border-radius: 9px;
    padding: 7px 10px;
    background: var(--et-color-bg);
    color: var(--et-color-ink);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    outline: none;
}
.et-receipt-input:focus { border-color: var(--et-color-accent); }
.et-receipt-input--name { flex: 1; }
.et-receipt-input--amount,
.et-receipt-tip-input {
    flex-shrink: 0;
    width: 88px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
/* iOS zooms into a focused control under 16px — the same guard ds.css keeps for
   the DS inputs, which these are not. */
@media (pointer: coarse) {
    .et-receipt-input { font-size: 16px; }
}
.et-receipt-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}
.et-receipt-chip {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    border-radius: var(--et-radius-pill);
    background: var(--et-color-bg);
    box-shadow: inset 0 0 0 1px var(--et-color-border-strong);
}
.et-receipt-chip--on {
    background: color-mix(in srgb, var(--et-color-accent) 12%, var(--et-color-surface));
    box-shadow: inset 0 0 0 1.5px var(--et-color-accent);
}
.et-receipt-chip-main {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    min-height: 34px;
    border: 0;
    padding: 4px 12px 4px 5px;
    background: none;
    color: var(--et-color-ink);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}
/* Short only where the "−" follows and brings its own right padding: a selected
   "Kik között osztjuk szét?" chip has none, and its name ran into the border. */
.et-receipt-chip-main:has(+ .et-receipt-chip-minus) { padding-right: 4px; }
.et-receipt-chip-name {
    max-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-receipt-chip-count {
    font-weight: 800;
    color: var(--et-color-accent);
}
.et-receipt-chip-minus {
    min-height: 34px;
    border: 0;
    padding: 0 12px 0 6px;
    background: none;
    color: var(--et-color-accent);
    font-family: inherit;
    font-size: 17px;
    font-weight: 800;
    cursor: pointer;
}
.et-receipt-chip-all {
    min-height: 34px;
    border: 1.5px dashed var(--et-color-border-strong);
    border-radius: var(--et-radius-pill);
    padding: 0 12px;
    background: none;
    color: var(--et-color-accent);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
.et-receipt-add {
    align-self: flex-start;
    border: 1.5px dashed var(--et-color-border-strong);
    border-radius: 12px;
    padding: 10px 14px;
    background: none;
    color: var(--et-color-accent);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
.et-receipt-caption {
    margin-top: 4px;
    font-size: 12px;
    color: var(--et-color-ink-3);
}
.et-receipt-unit {
    display: inline-flex;
    flex-shrink: 0;
    border-radius: 9px;
    overflow: hidden;
    box-shadow: inset 0 0 0 1.5px var(--et-color-border-strong);
}
.et-receipt-unit-btn {
    min-width: 36px;
    min-height: 36px;
    border: 0;
    padding: 0 10px;
    background: none;
    color: var(--et-color-ink-3);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
.et-receipt-unit--on {
    background: var(--et-color-accent);
    color: #fff;
}
.et-receipt-tip .et-check-row { margin-top: 10px; }
/* Who pays what, live — the same soft accent fill as the detail's own row. */
.et-receipt-people {
    display: flex;
    flex-direction: column;
    gap: 8px;
    border-radius: 14px;
    padding: 12px 14px;
    background: color-mix(in srgb, var(--et-color-accent) 7%, transparent);
}
.et-receipt-person {
    display: flex;
    align-items: center;
    gap: 10px;
}
.et-receipt-person-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-receipt-person-amount {
    font-size: 14px;
    font-weight: 800;
    color: var(--et-color-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* Saját kassza (personal-kassza D32): a line's category chip and the strip's category rows reuse
   the member chip and the person row as they are; only the glyph in the avatar's place is new.
   An emoji draws taller than its line box, so the glyph sits in a box the avatar's size: the
   box, not the glyph, sets the row's height (iOS grew the chip row past the 22px avatar). No
   overflow: hidden — with line-height: 1 it cuts the emoji's bottom off (the event panel's 🎂
   lost its plate that way, R4-04 → R4-09); the fixed width already keeps it out of the text. */
.et-receipt-category-glyph {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 22px;
    height: 22px;
    font-size: 16px;
    line-height: 1;
}
.et-receipt-category-total .et-receipt-category-glyph {
    flex-basis: 28px;
    height: 28px;
    font-size: 18px;
}
/* The start state's two ways in (personal-kassza D33): the user's own receipt or the demo one —
   the line cards' look, the chip's accent ring for the chosen one. */
.et-receipt-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 20px;
}
.et-receipt-option {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--et-color-border);
    border-radius: 14px;
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.et-receipt-option--on {
    border-color: var(--et-color-accent);
    box-shadow: 0 0 0 1px var(--et-color-accent);
    background: color-mix(in srgb, var(--et-color-accent) 7%, var(--et-color-surface));
}
/* The category glyph's box rule: the box sets the height, nothing clips the emoji. */
.et-receipt-option-glyph {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 28px;
    height: 28px;
    font-size: 22px;
    line-height: 1;
}
.et-receipt-option-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.et-receipt-option-title {
    font-size: 14px;
    font-weight: 700;
}
.et-receipt-option-text {
    font-size: 12px;
    color: var(--et-color-ink-3);
}
/* The demo receipt itself, drawn by etDemoReceipt at 600 px and shown as a paper slip. */
.et-demo-receipt {
    display: block;
    width: min(100%, 280px);
    height: auto;
    margin: 0 auto;
    border-radius: 6px;
    background: #fff;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
}

/* ── DS group view (/groups/{id}) layout ────────────────────────────
   Design: "Élő képernyő — Csoport". The header is full-bleed under the
   app bar and the content sits in the design's own 24px 24px 28px pad,
   so both first cancel .main-content's 24px side padding. */
.et-group-view-header,
.et-group-settings-header,
.et-group-view-body {
    margin-left: calc(var(--et-space-6) * -1);
    margin-right: calc(var(--et-space-6) * -1);
}
.et-group-view-body { padding: 24px 24px 28px; }
/* §4.5: the same band on /groups/{id}/settings, so it is full-bleed there too
   — one selector list rather than a second copy of the numbers. The tab row
   follows it directly (the old back row and hero are gone), so the rhythm
   between them lives here instead of on .et-page-hero. */
.et-group-settings-header { margin-bottom: 16px; }
/* Desktop (owner, 2026-09-25): the band is a rounded card in the content
   column, as Kezdőlap's EtPageBand is, rather than a full-bleed strip under the
   top bar — same 16px under the bar, same 18px corner. Below 960px it stays
   edge to edge: that is where the phone shell takes the top bar away and the
   band becomes the topmost thing on screen (under the status bar, installed).
   The body below keeps its own negative margins + padding, which already line
   its content up with the card's edges. */
@media (min-width: 960px) {
    .et-group-view-header,
    .et-group-settings-header {
        margin: 16px 0 0;
        border-radius: 18px;
        overflow: hidden;
    }
    .et-group-settings-header { margin-bottom: 20px; }
}
/* Last-7-free-days notice above the grid (V6 entitlement). EtInfoBanner
   carries no outer margin of its own, and it must not sit inside the grid —
   it is page-level context, not one of the ordered sections. */
.et-group-view-entitlement { margin-bottom: 16px; }
/* The scan-try banner (AiScanTryBanner): the trial banner's gap, and its title on a line of
   its own above the count — the banner's inline bold lead would run the two together. */
.et-ai-scan-try { margin-bottom: 16px; }
.et-ai-scan-try .et-info-banner-text b { display: block; }
.et-group-view-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    column-gap: 22px;
    align-items: start;
}
/* Events span both columns on the first row ("események felül"). The
   min-width:0 only matches its two siblings — the strip inside scrolls with
   or without it (see the note on .et-card-strip-wrap in ds.css). */
.et-group-view-events { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
.et-group-view-main   { grid-column: 1; grid-row: 2; min-width: 0; }
.et-group-view-side   { grid-column: 2; grid-row: 2; min-width: 0; }
/* Scroll container + paddles come from EtCardStrip; only the section rhythm
   and the card footprint are page-level. */
/* 10px + .et-card-strip's own 10px bottom padding = the 20px
   .et-group-view-section spends, so the gap above the Tennivaló header
   matches every other section here. Same arithmetic as
   .et-home-events-strip — the padding is part of the gap. */
.et-group-view-events-strip { margin-bottom: 10px; }
.et-group-view-event { width: 220px; }
.et-group-view-section { margin-bottom: 20px; }
/* For a section header that follows a card directly (the pairwise debts block
   under the expense list) — the same 20px rhythm, applied from above. */
.et-section-header.et-group-view-section-top { margin-top: 20px; }
/* The stacked-todo-card rule that lived here is gone with the hand-rolled
   list: the group view renders NeedsAttentionCarousel now, so the spacing
   between rows is the strip's own gap. */

/* Phone: one column, canvas order. Same 767.98px page-chrome edge as the rest
   of the file (see "Mobile media block (< md)" near the top).

   The DOM above is the desktop one (main column = Tennivaló + Költések +
   pairwise, side column = balances + Tagok), but the phone canvas interleaves
   the two: Események → Tennivaló → Akiknek tartozol → Akik tartoznak →
   Költések → Ki kinek tartozik → Tagok. Rather than duplicate the markup, the
   two column wrappers become `display: contents` so their children join the
   grid directly, and each .et-group-view-sec-* wrapper takes an explicit
   `order`. Classes, not :nth-child — a Blazor re-render must not be able to
   reshuffle the page.

   Dissolving the columns costs no rhythm: they carry grid placement and a
   min-width floor, never margins, so every gap already comes from the
   sections themselves (EtSurface MarginBottom / .et-group-view-section). The
   one exception is Költések, which ends flush on desktop because the pairwise
   header's 26px top margin follows it — on the phone it can also be the last
   thing before Tagok, so the rhythm moves onto the section itself here. */
@media (max-width: 767.98px) {
    /* The full-bleed pair cancels .main-content's side padding, which is 16px
       on a phone, not the 24px the desktop rule above backs out. */
    .et-group-view-header,
    .et-group-settings-header,
    .et-group-view-body {
        margin-left: calc(var(--et-space-4) * -1);
        margin-right: calc(var(--et-space-4) * -1);
    }
    .et-group-view-body { padding: 16px 16px 24px; }

    .et-group-view-grid {
        grid-template-columns: 1fr;
        column-gap: 0;
    }
    .et-group-view-main,
    .et-group-view-side { display: contents; }
    /* min-width floor for the dissolved columns' children — a single-column
       track is minmax(auto, 1fr), so a wide card would otherwise widen it.
       The `>` selectors must target the column wrappers too: their children
       are grid items without being DOM children of the grid. */
    .et-group-view-grid > *,
    .et-group-view-main > *,
    .et-group-view-side > * { min-width: 0; }
    /* Events spans both columns on desktop; in a one-column grid that explicit
       placement would pin it to row 1 and defeat `order`. */
    .et-group-view-grid > .et-group-view-events { grid-column: auto; grid-row: auto; }
    /* Narrower than the 220px desktop card, and proportional so the "there is
       more to the right" cue holds across phone widths: the percentage is of
       the strip's own width, which leaves 55-75% of the next card showing at
       360-430pt (360: 57%, 393: 73%, 430: 75%). The 200px floor keeps the
       smallest phones from squeezing the card into a thumbnail. */
    .et-group-view-event { width: max(200px, 55%); }
    /* ── pilot toggle (temporary, removed once the owner decides) ──
       The large variant is the pre-#450 card, and before #450 the phone shelf
       used the same fixed 220px the desktop one does — the proportional width
       above arrived WITH the compaction. Restoring it here keeps the variant a
       faithful "what main looked like on 2026-09-18", which is the only thing
       the owner is being asked to judge. */
    html[data-event-card="large"] .et-group-view-event { width: 220px; }
    /* The two narrower compact sizes (owner, 2026-09-25). Same shape of rule as
       the default — a share of the strip with a floor — so they stay
       proportional across phones: ~199px and ~183px at 430pt, where the
       default is ~219px and mini fits two whole cards with the third peeking.
       The floors keep the title readable on a 360pt phone. Kezdőlap's shelf
       below repeats them. Small is the DEFAULT since 2026-09-26, so its rule
       also matches a root with no data-event-card (pre-paint-theme.js stamps
       only the non-default values) — and `compact` falls through to the base
       width above. Small was widened on 2026-09-26 (owner: "a bit wider and a
       bit lower"): ~211px at 430pt, between the default and its old 199, over
       a 5:4 media that takes the height back (see Kezdőlap's block). */
    html:is(:not([data-event-card]), [data-event-card="compact-small"]) .et-group-view-event { width: max(190px, 53%); }
    html[data-event-card="compact-mini"] .et-group-view-event { width: max(165px, 46%); }

    /* A one-time kassza's link card leads: sending it is the step after the costs. */
    .et-group-view-sec-share    { order: 0; }
    .et-group-view-sec-events   { order: 1; }
    .et-group-view-sec-todo     { order: 2; }
    .et-group-view-sec-youowe   { order: 3; }
    .et-group-view-sec-categories { order: 3; } /* a Saját kassza's, in the debts' slot (D30) */
    .et-group-view-sec-owesyou  { order: 4; }
    .et-group-view-sec-activity { order: 5; margin-bottom: 20px; }
    .et-group-view-sec-pairwise { order: 6; }
    .et-group-view-sec-members  { order: 7; }
    /* The 20px above now supplies the gap under Költések at every width, so
       the pairwise header must not stack its desktop top margin on top. */
    .et-group-view-sec-pairwise .et-section-header.et-group-view-section-top { margin-top: 0; }
}

/* ── DS home (/home) layout ─────────────────────────────────────────
   Design: "Élő képernyő — Kezdőlap". Same grid as the group view; Home
   has no full-bleed header, so it keeps .main-content's own padding and
   only the grid + events strip are new here. */
.et-home-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    column-gap: 22px;
    align-items: start;
}
/* Events span both columns on the first row ("események felül"). The
   min-width:0 only matches its two siblings — the strip inside scrolls with
   or without it (see the note on .et-card-strip-wrap in ds.css). */
.et-home-events { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
.et-home-main   { grid-column: 1; grid-row: 2; min-width: 0; }
.et-home-side   { grid-column: 2; grid-row: 2; min-width: 0; }
/* Scroll container + paddles come from EtCardStrip; only the section rhythm
   and the card footprint are page-level. */
/* 10px, not the design's 28. The gap the eye reads above the "Tennivaló"
   header is this margin PLUS .et-card-strip's own 10px bottom padding (shadow
   breathing room for the cards, added when the scrollbar was hidden) — so 16
   here still measured 26 against the 20 every other section spends
   (EtSurface MarginBottom="20", and the todo shelf's 4px padding + mb-4).
   Halving it to 10 lands the total on the same 20. */
.et-home-events-strip { margin-bottom: 10px; }
.et-home-event { width: 220px; }
/* Greeting hero: the shared .et-page-hero trio carries the type and the
   rhythm; this is the one page-specific leftover. Home's greeting sits
   closer to the app bar than the other heroes (16 instead of 28) because it
   opens the page with no preceding chrome.
   Doubled up as .et-page-hero.et-home-hero-ds on purpose: .et-page-hero was
   declared LATER in this same file, where a single-class override lost the
   cascade tie and silently took the 28px back (it is in shell.css now,
   which loads first). Since the MudHidden fork died
   this hero DOES reach phone width, and the extra weight would beat the
   hero's phone branch — so that branch restates the phone value at equal
   specificity (search "et-home-hero-ds" in the phone block below). */
.et-page-hero.et-home-hero-ds { padding-top: 16px; }
/* Hidden, not deleted (owner, 2026-09-25): under the plain header the
   "Ma N tennivalód van." line repeats the count the Tennivaló section's own
   heading already shows, and in the installed-app shell it was the page's
   lone first line. The owner is still weighing it, so the markup stays and
   only this rule takes it off the screen. The illustrated band
   (EtPageBand) keeps its subtitle — this class only exists on the plain
   hero. */
.et-home-hero-ds .et-page-hero-subtitle { display: none; }

/* Phone: one column, canvas order — see the twin block on the group view
   above for why `display: contents` + `order` beats duplicating the markup.
   Canvas order here is Események → Tennivaló → Akiknek tartozol → Akik
   tartoznak → Legutóbbi költések → Akikkel együtt költesz, i.e. the activity
   section moves out of the main column down to fifth.

   Same rhythm story as the group view: the column wrappers never carried
   margins, so only Legutóbbi költések — flush-ending because it is last in
   the main column on desktop — needs a bottom margin of its own here. */
@media (max-width: 767.98px) {
    .et-home-grid {
        grid-template-columns: 1fr;
        column-gap: 0;
    }
    .et-home-main,
    .et-home-side { display: contents; }
    /* The dissolved columns' children are grid items but NOT DOM children of
       the grid, so `.et-home-grid > *` alone misses them — and one carousel's
       min-content contribution would widen the single 1fr track past the
       viewport (measured: 441px at 390px). Zero the minimum on all of them. */
    .et-home-grid > *,
    .et-home-main > *,
    .et-home-side > * { min-width: 0; }
    .et-home-grid > .et-home-events { grid-column: auto; grid-row: auto; }
    /* Same footprint rule as the group view's shelf — see the note there. */
    .et-home-event { width: max(200px, 55%); }
    /* pilot toggle (temporary) — same restore as the group view's shelf above. */
    html[data-event-card="large"] .et-home-event { width: 220px; }
    html:is(:not([data-event-card]), [data-event-card="compact-small"]) .et-home-event { width: max(190px, 53%); }
    html[data-event-card="compact-mini"] .et-home-event { width: max(165px, 46%); }
    /* Small is "a bit wider and a bit lower" (owner, 2026-09-26): 5:4 instead
       of the 1:1 every other compact size keeps, so at ~211px wide the card
       stands ~227px tall where it stood 257. The art is the square card/ set,
       so cover crops 20% of its height, and where that 20% comes from decides
       what survives: the drawings stand on the bottom edge with their stars,
       flames and hangers near the top, so a centre crop cuts the ground from
       under them and a bottom crop takes their tops off. 65% keeps both on all
       26 motifs. An uploaded photo is a 3:2 crop, wider than 5:4, so it loses
       only its sides here and the vertical position never comes into play.
       Phone-only like the width above: on desktop every compact value is the
       same 220px square card. */
    html:is(:not([data-event-card]), [data-event-card="compact-small"]) .et-event-card-media { aspect-ratio: 5 / 4; }
    html:is(:not([data-event-card]), [data-event-card="compact-small"]) .et-event-card-media img { object-position: 50% 65%; }
    /* The "Új esemény" tile's floor must stay under the shortest real card or
       it becomes the shelf's height and leaves a band of nothing under every
       card (ds.css, EtEventAddCard). 250 is under the default's cards only:
       small is ~210px tall on a 360pt phone and mini ~219, and mini had been
       14px short of its own floor since #477. */
    html:is(:not([data-event-card]), [data-event-card="compact-small"]) .et-event-add-card { min-height: 200px; }
    html[data-event-card="compact-mini"] .et-event-add-card { min-height: 210px; }
    /* Mini is narrow enough that the 15px title would ellipsise most names and
       the 32px pencil takes a fifth of the row: one step down on both. The
       pencil is EtIconButton's own box, resized here rather than by a new
       parameter, because only this pilot value wants it — and !important
       because EtIconButton writes its Size as an inline style, which no
       selector outranks. */
    html[data-event-card="compact-mini"] .et-event-card-body { padding: 10px 12px; gap: 6px; }
    html[data-event-card="compact-mini"] .et-event-card-title { font-size: 14px; }
    html[data-event-card="compact-mini"] .et-event-card-body .et-icon-btn {
        width: 28px !important;
        height: 28px !important;
    }

    .et-home-sec-events         { order: 1; }
    .et-home-sec-todo           { order: 2; }
    .et-home-sec-youowe         { order: 3; }
    .et-home-sec-owesyou        { order: 4; }
    .et-home-sec-activity       { order: 5; margin-bottom: 20px; }
    .et-home-sec-counterparties { order: 6; }
}

/* ── DS expense detail (/groups/{id}/expenses/{expenseId}) side panel ──
   Design: "Élő képernyő — Költség részletei". Only the glue between DS
   components lives here; the components themselves style from ds.css. */
.et-expense-detail-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 12px;
}
/* R3-09 (D7): the event moved out of the meta chip row into its own
   full-width clickable row so the chevron can signal it opens the event
   summary panel. P14 (owner 2026-09-16): a bare row read as another chip —
   now it reads as a tappable card row, in the same surface+border+radius
   family as .et-link-card (ds.css). The emoji badge borrows that card's
   tinted-square vocabulary (.et-link-card-emoji) sized up for the bigger
   20px glyph. */
.et-expense-detail-event-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    margin-top: 10px;
    padding: 13px 14px;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface-2);
    border-radius: 12px;
    cursor: pointer;
    transition: background-color .15s, border-color .15s;
}
.et-expense-detail-event-row:hover {
    border-color: var(--et-color-accent);
    background-color: color-mix(in srgb, var(--et-color-surface-2) 85%, black 8%);
}
.et-expense-detail-event-row-emoji {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--et-color-surface);
    display: grid;
    place-items: center;
    font-size: 20px;
}
.et-expense-detail-event-row-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
    text-align: left;
}
.et-expense-detail-event-row-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-expense-detail-event-row-caption {
    font-size: 11px;
    color: var(--et-color-ink-3);
}
.et-expense-detail-event-row-chevron {
    flex-shrink: 0;
    color: var(--et-color-accent);
}
.et-expense-detail-divider {
    height: 1px;
    background: var(--et-color-border);
    margin: 20px 2px;
}
/* Donut sits above the share list inside the same Form card, separated by
   the card's hairline (the rows below carry their own dividers). */
.et-expense-detail-donut {
    display: flex;
    justify-content: center;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--et-color-border);
}
.et-expense-detail-related-label { margin-top: 20px; }
/* A Saját kassza's receipt lines (D25): name over its category, amount on the right — the
   share row's type scale, so the two cards under each other read as one family. */
.et-expense-detail-item {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 12px 0;
}
.et-expense-detail-item + .et-expense-detail-item { border-top: 1px solid var(--et-color-border); }
.et-expense-detail-item-main { flex: 1; min-width: 0; }
.et-expense-detail-item-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-expense-detail-item-caption {
    margin-top: 2px;
    font-size: 12px;
    font-weight: 500;
    color: var(--et-color-ink-3);
}
.et-expense-detail-item-amount {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}
.et-expense-detail-related {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.et-expense-detail-lock { margin-top: 18px; }
.et-expense-detail-actions { margin-top: 18px; }
.et-expense-detail-footnote {
    margin-top: 16px;
    font-size: 11px;
    color: var(--et-color-ink-3);
}
.et-expense-detail-dialog-text {
    font-size: 13px;
    color: var(--et-color-ink-2);
    margin-bottom: 12px;
}

/* RevolutTagConfirmPrompt.razor (spec 2026-09-28 D25, PM-14): the typed @name, its
   own line, bold — the one thing in the dialog D25 asks to be "nagyban látszik"
   (shown large) since it's the fact the whole question turns on. */
.et-revolut-tag-confirm-name {
    font-size: 18px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 12px;
}

/* ── Attachment picker (Components/Domain/Attachments/AttachmentPicker.razor,
   AttachmentLightbox.razor) + the ExpenseDetail "Csatolmányok" strip —
   global, not scoped: this project's scoped-CSS bundle isn't wired into
   index.html (see the css note in wwwroot/index.html), so an
   AttachmentPicker.razor.css would emit nothing at runtime — same reasoning
   as the .uec-*/.nac-* blocks above. */
/* Attachment block on the new-expense form. The top margin is the load-bearing
   one: the block is a sibling of .et-expense-details (whose flex gap only
   spaces its own children), so nothing else separates it from the locked group
   row above. 20px matches .et-expense-block's rhythm on the rest of the form. */
.et-expense-attach {
    margin-top: 20px;
    margin-bottom: 20px;
}
.et-attach-input { display: none; }
/* Pick-time "Kép előkészítése…" row — covers the client-side resize, which is
   the only work happening between choosing a file and it landing in the queue. */
.et-attach-preparing {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-accent);
}
.et-attach-preparing-spinner {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 2px solid var(--et-color-line);
    border-top-color: var(--et-color-accent);
    animation: et-attach-thumb-spin .8s linear infinite;
}
.et-attach-queue {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}
.et-attach-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border: 1px solid var(--et-color-border);
    border-radius: 12px;
    background: var(--et-color-surface);
}
.et-attach-thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: 8px;
    /* overflow stays hidden so the image is clipped to the rounded box; the
       spinner below is inset so it does not need to escape. */
    overflow: hidden;
    background: var(--et-color-surface-2);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}
.et-attach-thumb img { width: 100%; height: 100%; object-fit: cover; cursor: pointer; }
.et-attach-thumb-glyph { font-size: 18px; }
/* In-flight ring over the thumbnail, matching .et-profile-avatar-spinner on
   the avatar upload. Indeterminate on purpose — see the note there. */
.et-attach-thumb-spinner {
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.55);
    border-top-color: var(--et-color-accent);
    animation: et-attach-thumb-spin .8s linear infinite;
    pointer-events: none;
}
@keyframes et-attach-thumb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .et-attach-thumb-spinner { animation-duration: 2.4s; }
}
.et-attach-body { min-width: 0; flex: 1; }
.et-attach-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.et-attach-meta { font-size: 11px; color: var(--et-color-ink-3); }
.et-attach-row--failed .et-attach-meta { color: var(--et-color-owe); }
.et-attach-remove {
    flex-shrink: 0;
    border: 0;
    background: none;
    color: var(--et-color-ink-3);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 4px;
}
.et-attach-remove:hover { color: var(--et-color-ink); }

/* Queue-level "n/m feltöltve" — an honest count, not a fake percentage
   (WASM's HttpClient has no upload-progress event, see the AttachmentPicker
   doc comment). */
.et-attach-progress-summary {
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-2);
    margin-top: 8px;
}
/* Per-row indeterminate bar, replacing the old spinner — a sliding fill with
   no percentage, since there is none to show. */
.et-attach-progress {
    flex-shrink: 0;
    position: relative;
    width: 48px;
    height: 4px;
    border-radius: 2px;
    background: var(--et-color-border);
    overflow: hidden;
}
.et-attach-progress-bar {
    position: absolute;
    top: 0;
    left: -40%;
    width: 40%;
    height: 100%;
    border-radius: 2px;
    background: var(--et-color-accent);
    animation: et-attach-progress-slide 1.1s ease-in-out infinite;
}
@keyframes et-attach-progress-slide {
    0%   { left: -40%; }
    100% { left: 100%; }
}
/* tokens.css's global reduced-motion rule only forces animation-duration
   toward 0 (it still runs the animation to its last frame, which here would
   freeze the bar off-screen to the right) — this swaps in an explicit
   static, fully-filled bar instead. */
@media (prefers-reduced-motion: reduce) {
    .et-attach-progress-bar { animation: none; left: 0; width: 100%; }
}

/* Lightbox (AttachmentLightbox.razor) — queued files (data: URLs) and
   already-uploaded attachments (presigned ContentUrl) both render here;
   .et-modal-overlay supplies the dimmed, centering backdrop. */
.et-attach-lightbox {
    position: relative;
    max-width: 90vw;
    max-height: 90vh;
}
.et-attach-lightbox img {
    display: block;
    max-width: 90vw;
    max-height: 90vh;
    border-radius: 12px;
    object-fit: contain;
}
.et-attach-lightbox-close {
    position: absolute;
    top: -14px;
    right: -14px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.et-attach-lightbox-close:hover { color: var(--et-color-owe); }

/* Existing-attachment strip on ExpenseDetail — horizontal, scrollable on
   phone widths. Images render their presigned thumbnail directly; PDFs /
   undecodable images fall back to a 📎 chip with the file name. */
.et-attach-strip {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    padding-bottom: 2px;
}
.et-attach-strip-item { position: relative; flex-shrink: 0; }
.et-attach-strip-image {
    display: block;
    width: 64px;
    height: 64px;
    border-radius: 10px;
    object-fit: cover;
    border: 1px solid var(--et-color-border);
    cursor: pointer;
}
.et-attach-strip-chip {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 64px;
    height: 64px;
    border-radius: 10px;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface-2);
    cursor: pointer;
    font-size: 18px;
    padding: 4px;
}
.et-attach-strip-chip-name {
    font-size: 9px;
    color: var(--et-color-ink-3);
    max-width: 56px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.et-attach-strip-remove {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface);
    color: var(--et-color-ink-3);
    font-size: 10px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.et-attach-strip-remove:hover { color: var(--et-color-owe); }
/* Small "open the real file" affordance over the bottom corner of an image
   thumbnail — the thumbnail itself opens the lightbox now, so this is the
   one dedicated click target for the old "open ContentUrl in a new tab"
   behaviour (avoids two competing actions on the same image). */
.et-attach-strip-expand {
    position: absolute;
    bottom: 4px;
    right: 4px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 0;
    background: rgba(26, 25, 23, 0.55);
    color: #fff;
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.et-attach-strip-expand:hover { background: rgba(26, 25, 23, 0.75); }

/* ── DS payment detail (/payments/{id}) side panel ──────────────────
   Design: "Élő képernyő — Fizetés részletei". Layout glue only; the DS
   atoms (Pill, AmountDisplay, PartyCard, SettleItemRow, TimelineStep)
   style themselves from ds.css. */
.et-payment-detail-status {
    display: flex;
    justify-content: center;
    padding: 0 0 14px;
}
.et-payment-detail-amount { padding-bottom: 20px; }
.et-payment-detail-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin: 14px 2px 20px;
}
.et-payment-detail-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 10px;
}

/* ── DS settle panels (/settle-up/{id}) ─────────────────────────────
   Design: "Élő képernyő — Új fizetés / Emlékeztető". Shares the label
   scale with the payment detail block above. */
.et-settle-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 0 0 16px;
}
.et-settle-hero-line {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    text-align: center;
}
.et-settle-amount { padding-bottom: 20px; }
/* The loan-installment hint under the amount (spec 2026-10-04 loan installments
   §5): an info EtInfoBanner — its look comes from ds.css; here only the gap under
   the number, and the text reads left-aligned like every other banner. */
.et-settle-installment-hint {
    margin-top: 14px;
    text-align: left;
}
.et-settle-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 10px;
}
.et-settle-label--flush { margin-bottom: 0; }
/* Per-direction subtotal, last child inside the list card (DebtBreakdown).
   Receipt language: it shares .et-settle-row's 12px vertical rhythm and sits
   in the same content box, so the number lands in the amount column instead
   of floating in a header line. The rule is --border-strong — one step above
   .et-settle-row--divider — so it reads as "the list ends here", not as one
   more row separator. Only rendered at 2+ items. */
.et-settle-subtotal {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 0;
    border-top: 1px solid var(--et-color-border-strong);
}
.et-settle-subtotal-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink-2);
}
.et-settle-subtotal-amount {
    font-size: 14px;
    font-weight: 800;
    color: var(--et-color-ink);
    white-space: nowrap;
}
.et-settle-label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}
/* Link-style button: both flex axes declared explicitly so no global
   `button { justify-content: center }` rule can re-centre it. */
.et-settle-check-all {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-accent);
    white-space: nowrap;
}
.et-settle-check-all:hover { text-decoration: underline; }
.et-settle-error { margin: -6px 2px 16px; }
.et-settle-note { margin-bottom: 18px; }
.et-settle-notice {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    font-size: 12px;
    color: var(--et-color-ink-3);
    line-height: 1.45;
}
.et-settle-notice-glyph {
    flex-shrink: 0;
    line-height: 1.45;
}

/* Pay-method chooser (spec 2026-09-28 PM-05). The rows are the dropdown's
   .et-group-menu-item with a drawn 18px glyph (the slot widens from the text
   glyph's 16px, as in the bottom bar's + menu) and a quiet second line. The
   Revolut row is an <a>, so it drops the link underline. */
.et-settle-pay-item { text-decoration: none; }
.et-settle-pay-item .et-group-menu-glyph {
    width: 20px;
    display: flex;
    justify-content: center;
    flex-shrink: 0;
}
.et-settle-pay-item .et-group-menu-glyph svg { display: block; }
.et-settle-pay-item-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.et-settle-pay-item-sub {
    font-size: 12px;
    font-weight: 500;
    color: var(--et-color-ink-3);
}

/* Bank transfer rows (PM-07): read-only field cards, each with its copy
   button; the note wraps instead of being cut. The view has the panel to
   itself, with the title in the panel header. */
.et-settle-transfer {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 20px;
}
/* Qvik mode's one-line "where is it in the bank app" (PM-09.2), in the quiet
   voice of .et-settle-notice, first under the header title it explains. */
.et-settle-transfer-hint {
    margin: 0 0 2px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--et-color-ink-3);
}
.et-settle-transfer-row {
    cursor: default;
    padding: 10px 10px 10px 15px;
}
.et-settle-transfer-value {
    margin-top: 2px;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow-wrap: anywhere;
}
.et-settle-transfer-row--note .et-settle-transfer-value {
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.4;
}
.et-settle-transfer-value--missing,
.et-settle-transfer-row--note .et-settle-transfer-value--missing {
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--et-color-ink-3);
}
/* Link-style button: both flex axes declared, so no global button rule can
   re-centre or stretch it (see .et-settle-check-all). */
.et-settle-copy {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    flex-shrink: 0;
    padding: 7px 9px;
    border: 0;
    border-radius: 9px;
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    color: var(--et-color-accent);
    white-space: nowrap;
}
.et-settle-copy:hover { background: color-mix(in srgb, var(--et-color-accent) 8%, transparent); }
.et-settle-copy--done { color: var(--et-color-owed); }
.et-settle-copy svg { display: block; }

/* Revolut QR view (spec 2026-09-28 D31, PM-15.3a): the code centered, capped at
   ~280px, the amount under it, a one-line hint below — no footer button here
   (D17 exception: there's nothing to submit, the payer scans and records the
   payment themselves, D1). */
.et-settle-qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 0 0 8px;
    text-align: center;
}
.et-settle-qr .et-qr-code {
    max-width: 280px;
}
.et-settle-qr-amount {
    font-size: 20px;
    font-weight: 800;
    color: var(--et-color-ink);
}

/* ── New group: the size's two facts under the type control ────────
   Owner, 2026-10-01: the free window and the member cap as pills; both in the
   same green, the owed colour on a 14% tint (owner, 2026-10-02). */
.et-group-new-type-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
.et-group-new-type-fact {
    display: inline-flex;
    align-items: center;
    padding: 6px 12px;
    border-radius: var(--et-radius-pill);
    background: color-mix(in srgb, var(--et-color-owed) 14%, transparent);
    font-size: 12px;
    font-weight: 700;
    color: var(--et-color-owed);
}

/* ── Megjelenés block (GroupNew + the GroupSettings Részletek tab) ──
   Owner, 2026-10-01: the real EtGroupCard (styled by ds.css) fed the form's
   values, the photo link right under it. It closes both forms, under the icon
   and colour pickers (owner, 2026-10-02). The card is its own surface, so the
   block adds no frame. */
.et-group-appearance {
    display: flex;
    flex-direction: column;
    align-items: flex-start; /* the link keeps its own width */
    gap: 8px;
}
/* A preview, not a link: the card's pointer and hover lift would invite a tap
   that goes nowhere. */
/* Doubled up on the wrapper: ds.css loads after this file, so a single-class
   override would lose the tie against .et-group-card:hover. */
.et-group-appearance .et-group-appearance-card {
    align-self: stretch;
    cursor: default;
}
.et-group-appearance .et-group-appearance-card:hover {
    transform: none;
    box-shadow: var(--et-shadow-card);
}
/* The photo link stands alone under the card, not inside a row's hint line,
   so it takes body-copy size instead of the event row's 11px. Doubled up to
   outrank .et-event-image-menu-trigger, which comes later in this file. */
.et-group-appearance .et-group-image-action {
    margin: 0 2px;
    font-size: 13px;
}
/* The saturated identity hero — GroupNew's preview until 2026-09-25, now used
   only by the invite page (InvitePreview.razor, .et-invite-hero), which keeps the
   look on purpose: a visitor has no list card to compare it to. */
.et-group-new-preview-hero {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    /* P13: the hero hosts the plate's photo element (absolute, right 40%,
       slanted), so it has to be the containing block and clip it to its own
       rounded box. The tile and the text keep painting above the picture. */
    position: relative;
    overflow: hidden;
}
.et-group-new-preview-hero > .et-group-new-preview-tile,
.et-group-new-preview-hero > .et-group-new-preview-text { position: relative; z-index: 1; }
.et-group-new-preview-tile {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 11px;
    background: rgba(255, 255, 255, 0.22);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}
.et-group-new-preview-text { min-width: 0; }
.et-group-new-preview-name {
    font-size: 15px;
    font-weight: 800;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.et-group-new-preview-meta {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.82);
    margin-top: 2px;
}

/* ── DS group settings (/groups/{id}/settings) desktop layout ───────
   Design: "Csoport beállításai" élő képernyő + the "Jegyzetek" block.
   Only the glue between DS components lives here — EtCrudRow,
   EtDangerZone, EtMemberRow style themselves from ds.css. */
/* .et-group-settings-back and the .et-page-hero padding reset that went with
   it left with the band (§4.5): the page opens on EtGroupHeader now, whose own
   back button replaces the text row, and there is no hero left to de-pad. The
   shared .et-page-back below still carries the same look for the other pages
   that render it. */
/* Tabs (spec 2026-08-24 §4) replaced the 1fr/1fr desktop grid: only one
   section renders at a time now, so it reads as a single settings form
   rather than a two-column dashboard. Same 680px/centered shape ProfilePage
   uses for its own single-column settings card; max-width:100% already
   collapses this to full-bleed on a phone, so no separate mobile media
   query is needed the way the old grid required one. */
.et-group-settings-tabs {
    width: 680px;
    max-width: 100%;
    margin: 0 auto 20px;
}
.et-group-settings-panel {
    width: 680px;
    max-width: 100%;
    margin: 0 auto;
    min-width: 0;
}
/* Wave 3 spec §5.1: the danger zone now renders inside the Részletek tab
   (see GroupSettings.DsDetailsTab) rather than below the tab panel, so it
   keeps its own top margin to separate it from the section above. The
   two-column grid it used to span — and the .et-group-settings-col rule that
   went with it — left with the tabbed layout. */
.et-group-settings-danger { margin-top: 20px; }

/* Card-internal building blocks. The surrounding EtSurface already supplies
   the 12px card pad, so these only add vertical rhythm. */
.et-group-settings-block { padding: 12px 2px; }
.et-group-settings-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
    margin-bottom: 10px;
}
.et-group-settings-muted {
    font-size: 12px;
    color: var(--et-color-ink-3);
    margin-top: 10px;
}
/* "Kasszatípus: Utazás" on the "Alap adatok" label's own line (spec
   2026-10-04-create-flow-round2-design.md §4.3) — muted and lighter than the bold label it
   follows, so it reads as a fact about the group, not as a second heading. */
.et-group-settings-kassa-type {
    margin-left: 8px;
    font-weight: 500;
    color: var(--et-color-ink-3);
}
.et-group-settings-divider {
    height: 1px;
    background: var(--et-color-border);
    margin: 4px 2px;
}
.et-group-settings-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 14px;
}
.et-group-settings-actions--pad { padding: 0 2px 4px; }
.et-group-settings-menu-danger { color: var(--et-color-owe); }

/* Pending-invite rows: invitee name/email + resend / revoke icon buttons
   (Task 5 — copy-link joining removed, so this is name+address, not a URL). */
.et-group-settings-invite { margin-top: 12px; }
.et-group-settings-invite-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.et-group-settings-invite-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
/* The name line is a flex row since the admin invite badge joined it: the truncation
   moved onto the text span so a long name can't ellipsize the "(admin)" suffix out of
   existence — the suffix is the part that carries information the list has nowhere
   else. Same two-part shape as ds.css's .et-member-row-name-line. */
.et-group-settings-invite-name {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-group-settings-invite-name-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Mirrors .et-member-row-admin (ds.css) — same quiet grey, same weight drop. */
.et-group-settings-invite-admin {
    flex-shrink: 0;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--et-color-ink-3);
}
.et-group-settings-invite-email {
    font-size: 12px;
    color: var(--et-color-ink-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.et-group-settings-invite-meta {
    font-size: 11px;
    color: var(--et-color-ink-3);
    margin-top: 6px;
}

/* Generated magic link inside InviteMemberPanel: one line, cut with an
   ellipsis (owner, 2026-10-05). The DOM holds the whole link, so copy, Share
   and a select-all all take it in full. */
.et-invite-generated {
    padding: 12px;
    border-radius: 12px;
    background: var(--et-color-surface-2);
    border: 1px solid var(--et-color-border);
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--et-color-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    user-select: all;
}
/* The generated link as a QR code, with its one-line hint underneath — the
   settle screen's QR block (.et-settle-qr) at panel scale. */
.et-invite-qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    text-align: center;
}
/* Capped like .et-settle-qr's own QR (same component, same reason): without a
   max-width the base .et-qr-code rule (width:100%) fills the whole sheet body on
   a phone, crowding the hint text and the footer below it. InviteMemberPanel is
   one component shared by this create-flow step and the group view's own invite
   panel, so both get the same cap — not just the one that prompted it. */
.et-invite-qr .et-qr-code {
    max-width: 200px;
}

/* Owner 2026-09-16 revision of R3-05 (P12): the bulk-delete text button (#401)
   is gone. The trash-only icon now shares this row with the year chips,
   right-aligned so it sits in the same column as the EtCrudRow list's own
   delete icons below it (that row pads 8px on the right — see
   .et-crud-row-edit/.et-crud-row-delete — so this toolbar matches that inset
   instead of the block's 2px, per CLAUDE.md's "adjust the caller, not the
   shared component" instinct). Left padding matches .et-group-settings-block,
   the inset of the card's other blocks. */
.et-group-settings-events-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 0 8px 12px 2px;
}
.et-group-settings-events-toolbar .et-year-chips {
    flex: 1 1 auto;
    min-width: 0;
}
@media (max-width: 639.98px) {
    /* If the chips wrap to a second line, keep the icon pinned to the top
       row instead of the default vertical centering pulling it down into
       the middle of a now-taller toolbar. */
    .et-group-settings-events-toolbar {
        align-items: flex-start;
    }
}
/* R5-09: the bulk-delete trash shares EtCrudRow's own delete-button geometry
   (ds.css .et-crud-row-edit/.et-crud-row-delete) so the two land in one
   column instead of merely being commented as such. The razor sets
   Size="40" to match the row's desktop hit-box directly; the glyph itself
   is scaled here to the row's 19px (.et-crud-row-glyph) since EtIconButton's
   drawn "trash" SVG is otherwise a fixed 16px regardless of Size. */
.et-group-settings-events-toolbar .et-icon-btn svg {
    width: 19px;
    height: 19px;
}
/* EtIconButton renders Size as an inline style, which a plain class rule
   can't beat — !important is required to bump it for a phone hit-box, same
   as the row's own buttons do under this exact breakpoint (ds.css). */
@media (max-width: 640px) {
    .et-group-settings-events-toolbar .et-icon-btn {
        width: 44px !important;
        height: 44px !important;
    }
}
/* EventYearChips — the "Idén / Jövőre" pair that replaced the free year field
   (F-04). The events list captions the pair ("Év"); the form uses it without
   a caption. Global rather than scoped: geometry that decides
   whether a chip row reads as a row at all, per CLAUDE.md's emission-gap note. */
.et-year-chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
.et-year-chips-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-2);
}
/* Month + day pickers (EventEditPanel) share one row only below the phone
   breakpoint, where their EtDropdowns are bottom sheets (owner, 2026-10-02).
   On desktop the menu anchors to the field, so the pickers stay full width:
   display: contents keeps them items of the .et-expense-details stack. */
.et-event-date-row { display: contents; }
@media (max-width: 639.98px) {
    .et-event-date-row {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }
}
/* Background-illustration preview row of the event panel. */
.et-group-settings-illu {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--et-color-border);
    border-radius: 12px;
    background: var(--et-color-surface-2);
}
.et-group-settings-illu-thumb {
    width: 76px;
    height: 50px;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: 8px;
    background: var(--et-color-surface);
}
.et-group-settings-illu-body { min-width: 0; }
.et-group-settings-illu-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-group-settings-illu-hint {
    font-size: 11px;
    color: var(--et-color-ink-3);
    margin-top: 3px;
}

/* The picker itself is driven by etDs.clickElement from the menu, so the input
   is never seen; display:none would make some browsers skip the click. */
.et-group-image-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* Event photo row in EventEditPanel (F-41/3) — the illustration row's chrome
   with a 3:2 thumb, the ratio the event image is stored at. */
.et-event-image-thumb {
    width: 76px;
    height: auto;
    aspect-ratio: 3 / 2;
}
/* Link-looking trigger that opens the photo menu, sitting where the row's hint
   line does. justify-content explicit per the DS button rule. */
.et-event-image-menu-trigger {
    display: inline-flex;
    justify-content: flex-start;
    align-items: center;
    margin-top: 3px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 11px;
    color: var(--et-color-accent);
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}
.et-event-image-menu-trigger:disabled {
    color: var(--et-color-ink-3);
    cursor: progress;
}

/* EventEditPanel's "this year / following years" chooser (spec 2026-10-04 D4): the
   rename note under the two rows, in the quiet voice of a menu row's second line
   (.et-settle-pay-item-sub). The 12px side padding lines it up with the rows' text. */
.et-event-scope-note {
    margin: 0;
    padding: 6px 12px 4px;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.45;
    color: var(--et-color-ink-3);
}

/* Admin-transfer picker rows inside the leave dialog. */
.et-group-settings-transfer-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;   /* explicit: never inherit a centred button rule */
    gap: 11px;
    width: 100%;
    padding: 9px 10px;
    margin-bottom: 6px;
    border: 1px solid var(--et-color-border);
    border-radius: 12px;
    background: var(--et-color-surface);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.et-group-settings-transfer-row:hover { background: var(--et-color-surface-2); }
.et-group-settings-transfer-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.et-group-settings-transfer-chevron {
    font-size: 18px;
    color: var(--et-color-ink-4);
}


/* ── DS profile (/profile) desktop layout ───────────────────────────
   Design: "Élő képernyő — Profil" + docs/design_handoff_chunk3/BRIEF.md §2.
   Single 680px column: section labels, the identity header and the glue
   between DS components. EtSurface / EtSettingsRow / EtToggleRow /
   EtDangerZone style themselves from ds.css.
   Shared with NotificationPrefsForm's DS branch, which renders as this
   page's "E-mail értesítések" section. */
/* No top padding: .et-page-hero brings its own 28px (18px on a phone), and
   stacking the two would open a gap no other page has. */
.et-profile {
    width: 680px;
    max-width: 100%;
    margin: 0 auto;
    padding: 0 0 40px;
}

/* Fejléc: avatar + name + email. No edit button — the fields are inline. */
.et-profile-identity {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 24px;
}
/* Tappable avatar — opens the EtDropdown with "Új profilkép" / "Kép
   törlése". A plain button (not a styled div) so it stays focusable and
   keyboard-operable; the disc itself is the EtAvatar child. */
.et-profile-avatar-trigger {
    position: relative;
    border: 0;
    background: none;
    padding: 0;
    border-radius: 50%;
    cursor: pointer;
    flex-shrink: 0;
}
.et-profile-avatar-trigger:disabled { opacity: 0.5; cursor: default; }
.et-profile-avatar-trigger:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
/* Camera badge (F-16): signals the 56px avatar disc is tappable — before
   this there was no visual hint at all. Sits over the trigger's own
   bottom-right corner rather than as a separate control, so the click
   target and the dropdown it opens stay exactly as before. --busy hides
   it: the spinner already communicates "in progress" and two overlapping
   indicators would be noise. */
.et-profile-avatar-badge {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--et-color-surface);
    border: 1px solid var(--et-color-border);
    box-shadow: var(--et-shadow-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    line-height: 1;
    pointer-events: none;
}
.et-profile-avatar-trigger--busy .et-profile-avatar-badge { display: none; }
/* Upload in flight: the picked photo is already showing (client-side resized
   preview), and this ring spins over it. Deliberately indeterminate —
   Blazor WASM's HttpClient reports no upload progress, so a percentage would
   be fabricated. --busy overrides the :disabled dimming: the point is that
   the new picture is visible while it uploads. */
.et-profile-avatar-trigger--busy {
    position: relative;
    opacity: 1;
}
.et-profile-avatar-spinner {
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px solid rgba(0, 0, 0, 0.10);
    border-top-color: var(--et-color-accent);
    animation: et-profile-avatar-spin .8s linear infinite;
    pointer-events: none;
}
@keyframes et-profile-avatar-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .et-profile-avatar-spinner { animation-duration: 2.4s; }
}
.et-profile-avatar-status {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-accent);
    margin-top: 2px;
}
/* Triggered via etDs.clickElement (JS), never a visible control. */
.et-profile-avatar-input { display: none; }
.et-profile-identity-text { min-width: 0; }
.et-profile-identity-name {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-profile-identity-email {
    font-size: 13px;
    color: var(--et-color-ink-3);
    margin-top: 2px;
}

/* Uppercase section label above each card group. */
.et-profile-section {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--et-color-ink-4);
    margin: 0 0 8px 4px;
}
.et-profile-section--danger { color: var(--et-color-owe); }

.et-profile-field { margin-bottom: 10px; }
.et-profile-banner { margin-bottom: 10px; }

.et-profile-caption {
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--et-color-ink-4);
    margin: 0 4px 20px;
}

/* Notification settings (spec 2026-11-03-notification-channels §6): the web's one sentence
   under the E-mail | Push list, with its link-styled button to the get-the-app dialog, and the
   onboarding step's label above its topic list. */
.et-notif-app-note {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    margin: 0 4px 8px;
}
.et-notif-app-note button {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 600;
    color: var(--et-color-accent);
    text-decoration: underline;
    cursor: pointer;
}
.et-notif-setup-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink);
    margin: 14px 4px 8px;
}

/* ── Personal dates + "Profil beállítása" (spec 2026-10-04) ──────────────────────────────
   PersonalDatesFields: each month/day pair side by side at every width. MonthDayPicker's
   .et-event-date-row is display:contents above 640px (EventEditPanel lays its pickers out
   itself), which here would stack the two halves; this block owns its own grid instead. */
.et-personal-dates .et-event-date-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-bottom: 20px;
}
.et-personal-dates-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}
/* Profile's "Melyik csoportjaidba kerüljön be?" sheet: one check row per group, each a 44px
   tap target, the helper line 20px above the card. */
.et-add-dates-helper { margin-bottom: 20px; }
.et-add-dates-groups {
    display: flex;
    flex-direction: column;
}
.et-add-dates-groups .et-check-row { min-height: 44px; }
.et-add-dates-groups .et-check-row + .et-check-row { border-top: 1px solid var(--et-color-border); }
/* PersonalSetup's sheets: the step's one-line helper 20px above the first block; on step 1
   the avatar with its hint beside it, Profile's identity row in miniature — and under the hint,
   while there is no photo, the "Betű-avatart használok" button. */
.et-personal-setup-helper { margin-bottom: 20px; }
.et-personal-setup-identity {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 20px;
}
.et-personal-setup-avatar-side {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
}
.et-personal-setup-avatar-hint {
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-3);
}
.et-personal-setup-add-to-group { min-height: 44px; }
/* Step 5: the Instagram glyph, the handle under it and the one button, centred — a link to
   follow, nothing to fill in. */
.et-personal-setup-instagram {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 8px 0 4px;
}
.et-personal-setup-instagram-glyph {
    width: 48px;
    height: 48px;
    color: var(--et-color-accent);
}
.et-personal-setup-instagram-handle {
    font-size: 16px;
    font-weight: 700;
    color: var(--et-color-ink);
}

/* Prose body of an ⓘ sheet (an EtDropdown, whose list is built for
   .et-group-menu-item rows): its own 12px side padding lines the text up with
   the phone sheet's title, and 8px top + the title's 8px make the 16px under
   a sheet header. Desktop shows no title, so each sheet's first paragraph has
   to read on its own. */
.et-info-sheet {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 8px 12px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
}
.et-info-sheet p { margin: 0; }
.et-info-sheet strong {
    font-weight: 700;
    color: var(--et-color-ink);
}

/* One-time onboarding tip (OnboardingTip): an EtInfoBanner placed between a
   section's header and its content, so it reads as part of that section. The
   header's own 12px margin is the gap above; this is the label rhythm's 10px
   to the content below. Spacing only — the card is the DS banner. */
.et-tip { margin-bottom: 10px; }

/* The creator's "Első lépések" card (FirstStepsCard), hosted inside the onboarding FAB's panel
   (spec 2026-10-02-onboarding-fab) rather than inline on the page. Global rather than scoped
   (the emission gap). An EtSurface with Pad="0" so the rows run edge to edge: its own header row
   (title, n/5), then one row per item in the settings-row vocabulary — 16px sides, never under
   44px tall. */
.et-first-steps { overflow: hidden; }
.et-first-steps .et-surface-header { padding: 12px 16px 4px; }
.et-first-steps .et-surface-count { margin-right: auto; }
.et-first-steps-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    box-sizing: border-box;
    width: 100%;
    min-height: 48px;
    padding: 10px 16px;
    border: 0;
    background: none;
    font-family: var(--et-font-family-base);
    text-align: left;
    color: var(--et-color-ink);
}
button.et-first-steps-row { cursor: pointer; }
button.et-first-steps-row:hover { background-color: rgba(0, 0, 0, 0.02); }
.et-first-steps-row + .et-first-steps-row { border-top: 1px solid var(--et-color-border); }
.et-first-steps-check {
    box-sizing: border-box;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--et-color-border-strong);
    flex-shrink: 0;
    display: grid;
    place-items: center;
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
    color: #fff;
}
.et-first-steps-row--done .et-first-steps-check {
    border-color: var(--et-color-accent);
    background: var(--et-color-accent);
}
.et-first-steps-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.et-first-steps-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-first-steps-row--done .et-first-steps-label {
    font-weight: 500;
    color: var(--et-color-ink-3);
}
.et-first-steps-sub {
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--et-color-ink-3);
}
.et-first-steps-chevron {
    color: #C8C5BD;
    font-size: 18px;
    flex-shrink: 0;
}
/* The personal card's receipt step while the four above are open (spec
   2026-10-05-receipt-scan-design.md §6.7): a reward still out of reach — the 🔒 stands in the
   check ring's place, and the label is muted like a done row's. */
.et-first-steps-row--locked .et-first-steps-check {
    border-color: transparent;
    font-size: 14px;
}
.et-first-steps-row--locked .et-first-steps-label {
    font-weight: 500;
    color: var(--et-color-ink-3);
}

/* The joiner's welcome card (JoinerStepsCard) — FirstStepsCard's sibling, same FAB-hosted panel.
   Reuses every .et-first-steps-row/-check/-text/-label/-sub/-chevron rule above as-is; this block
   only adds the richer header (title + inviter line + reassurance + "Hogyan működik?") that
   EtSurface's single-line Title/Count/Link cannot express, so it is built by hand above the
   shared .et-surface-header meta row (just the count — the FAB's own button already shows
   progress, so there is nothing else in that row any more). */
.et-joiner-steps-intro { padding: 14px 16px 2px; display: flex; flex-direction: column; gap: 4px; }
.et-joiner-steps-title {
    font-size: 15px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-joiner-steps-line {
    font-size: 13px;
    line-height: 1.4;
    color: var(--et-color-ink-3);
}
.et-joiner-steps-how { display: inline-block; margin-top: 4px; }
.et-joiner-steps .et-surface-header { padding: 6px 16px 4px; }

/* ──────────── Onboarding FAB (spec 2026-10-02-onboarding-fab, revised 2026-10-04) ────────────
   The collapsible button that replaces the inline FirstStepsCard/JoinerStepsCard placement.
   Button: a round 52px pill (>=44px hit area), fixed, dragged freely by etDs.attachFab, which
   moves it with a transform during the drag and parks it with inline left/top on the drop —
   the right/bottom here are only the default place, before anything is stored. Shows the
   checklist's count inside a progress ring, or a plain dot when only a tip (no checklist) is
   pending, or nothing — the component doesn't render the button at all then. A small corner
   badge marks a tip the user hasn't opened the sheet for yet. */
.et-onboarding-fab {
    position: fixed;
    right: 16px;
    bottom: calc(var(--et-fab-bottom) + 76px);
    z-index: 1101;
    width: 52px;
    height: 52px;
    min-width: 44px;
    min-height: 44px;
    border: 0;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    background: var(--et-color-surface);
    color: var(--et-color-ink);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    cursor: pointer;
    touch-action: none;
    font-family: var(--et-font-family-base);
}
.et-onboarding-fab-progress {
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
}
/* done/total of the circle, from 12 o'clock (the dash is computed in OnboardingFab). The arc
   changes in place: a dash change is a repaint, not a compositor animation. */
.et-onboarding-fab-ring {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
.et-onboarding-fab-ring circle {
    fill: none;
    stroke-width: 3;
}
.et-onboarding-fab-ring-track { stroke: var(--et-color-border); }
.et-onboarding-fab-ring-arc {
    stroke: var(--et-color-accent);
    stroke-linecap: round;
}
.et-onboarding-fab-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--et-color-accent);
}
.et-onboarding-fab-badge {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    /* Reuses the existing "owe"/destructive red token (ds.css .et-btn--danger) — no new color. */
    background: var(--et-color-owe);
    border: 2px solid var(--et-color-surface);
}

/* One gentle pulse, the first time the button ever has something to show (device-local flag).
   transform/opacity only — CLAUDE.md's compositor-only rule for anything that moves on a phone —
   and it only ever plays once per element (a CSS animation doesn't replay on its own), so the
   class is never removed again. */
@keyframes et-onboarding-fab-pulse {
    0%   { transform: scale(1);    opacity: 1; }
    50%  { transform: scale(1.12); opacity: 0.85; }
    100% { transform: scale(1);    opacity: 1; }
}
.et-onboarding-fab--pulse { animation: et-onboarding-fab-pulse 700ms var(--et-ease-standard) 1; }
@media (prefers-reduced-motion: reduce) {
    .et-onboarding-fab--pulse { animation: none; }
}

/* The sheet: EtDropdown's own markup, so ds.css makes it the phone bottom sheet (and plays both
   exits through .et-dropdown--leaving). It is always in the DOM — the five components inside
   must never remount — so the closed state is this rule, not an absence. */
.et-onboarding-fab-sheet:not(.is-open):not(.et-dropdown--leaving) { display: none; }
/* The page's own background, so the white checklist card keeps its edge, as on a page. The
   list's height cap is set here, on the menu, because etDs.attachFab overrides it inline there. */
.et-onboarding-fab-sheet .et-dropdown-menu {
    background: var(--et-color-bg);
    --etdd-max-height: calc(100vh - 220px);
}
.et-onboarding-fab-sheet .et-dropdown-list { gap: 10px; }
.et-onboarding-fab-sheet .et-tip { margin: 0; }
@media (max-width: 640px) {
    /* 16px under the grabber, as under a header. */
    .et-onboarding-fab-sheet .et-dropdown-list { padding-top: 16px; }
}
/* From 641px a popover anchored to the movable button: etDs.attachFab writes where it opens.
   The fallbacks — no JS yet, or a screen dump — sit above the default bottom-right button. */
@media (min-width: 641px) {
    .et-onboarding-fab-sheet .et-dropdown-menu {
        position: fixed;
        top: var(--et-fab-sheet-top, auto);
        right: var(--et-fab-sheet-right, 16px);
        bottom: var(--et-fab-sheet-bottom, calc(var(--et-fab-bottom) + 76px + 60px));
        left: var(--et-fab-sheet-left, auto);
        width: min(360px, calc(100vw - 32px));
        padding: 10px;
        box-sizing: border-box;
    }
}

.et-profile-actions {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 26px;
}

/* Settings rows that navigate away are wrapped in a real anchor (the legal
   pages are static HTML outside the SPA), so strip the link chrome. */
.et-profile-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

/* Event-reminder offsets, indented under their toggle row. */
.et-profile-reminders {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding: 12px 18px 16px 30px;
}

.et-profile-dialog-text {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--et-color-ink-2);
    margin-bottom: 12px;
}

/* Row-stack cards. EtSurface can't just clip: the Megjelenés / Nyelv cards
   hold EtDropdowns whose menus escape the card bounds, so overflow:hidden is
   only for stacks that don't, and the others round their end rows by hand
   (otherwise the first row's hover tint squares off the card's top corners). */
.et-profile-card { overflow: hidden; }
.et-profile-card-menu > .et-dropdown:first-child .et-settings-row {
    border-top-left-radius: var(--et-card-radius-md);
    border-top-right-radius: var(--et-card-radius-md);
}
.et-profile-card-menu > .et-dropdown:last-child .et-settings-row {
    border-bottom-left-radius: var(--et-card-radius-md);
    border-bottom-right-radius: var(--et-card-radius-md);
}

/* Shared page hero's phone block (shell.css): Kezdőlap's own rule. */
@media (max-width: 767.98px) {
    /* Home's greeting opens 16px under the app bar on desktop, set at
       .et-page-hero.et-home-hero-ds (two classes) far above. That outranks
       the single-class rule at the top of the hero's phone block (shell.css), so the phone's 18px has
       to be restated at equal specificity or Kezdőlap would silently keep the
       desktop value. */
    .et-page-hero.et-home-hero-ds { padding-top: 18px; }
}

/* ──────────── Értesítések (/notifications) page chrome ────────────
   Global, not scoped: index.html never links the scoped-CSS bundle
   (ExpenseTracker.Web.styles.css), so every *.razor.css in this project is
   dead weight. Page blocks live here, DS atoms in ds.css. */
.et-notifications-filters { margin-bottom: 14px; }
/* Pad="0" on the surface lets the rows run edge to edge — EtNotifRow brings
   its own 16px horizontal padding and full-bleed dividers. */
.et-notifications-list { overflow: hidden; }
/* Day headings are EtListLabel; the default 16px gutter already matches
   EtNotifRow's inset, so this list sets no --et-list-label-gutter. */
.et-notifications-more {
    display: flex;
    justify-content: center;
    margin-top: 16px;
}

/* ──────────── Költségek (/activity) page chrome ──────────── */
.et-expenses-filters { margin-bottom: 20px; }
/* Month headings are EtListLabel. Narrower gutter than the atom's 16px
   default because EtActivityRow's own horizontal padding is 10px, not 16 —
   this is what lines the heading up with the emoji thumb below it. */
.et-expenses-list {
    overflow: hidden;
    --et-list-label-gutter: 10px;
}
.et-expenses-more {
    display: flex;
    justify-content: center;
    margin-top: 16px;
}

/* ──────────── Csoportok (/groups) page chrome ────────────
   One render at every width now — the MudHidden fork is gone (mobile-sync
   chunk) and the legacy .gl-grid classes + GroupCard component they fed are
   deleted. The hero is the shared .et-page-hero--split trio, whose phone
   branch (22/13 at 767.98px, above) now actually applies here. */
/* The dc's fixed 3-column grid, gap 18 — it replaces the nine hand-tuned
   .gl-grid-N classes, so a lone group no longer stretches into a full-bleed
   slab. Rows stretch so EtGroupCard's margin-top:auto footer lines the
   balance chips up. Two columns below 1100px, where three cards would push
   the group names into ellipsis; one column below 640px, where a phone's
   EtGroupCard has no room left for its member-name caption line. */
.et-groups-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
    align-items: stretch;
    padding: 8px 0;
}
@media (max-width: 1100px) {
    .et-groups-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 639.98px) {
    .et-groups-grid { grid-template-columns: 1fr; }
}

/* "Új csoport" as the trailing grid tile (owner decision 2026-08-25) —
   replaces the dark hero button. Dashed so it reads as a slot to fill rather
   than an existing group, and sized off the real cards (~130px since the v2
   card, spec 2026-09-24 §5 — it was 152) so the grid row doesn't jump. Hidden below 960px, which is precisely where .et-fab becomes
   visible (see the .et-fab rule above): exactly one create-group affordance at
   every width. */
.et-group-card-new {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-height: 128px;
    padding: 18px;
    /* Same weight/colour as .et-event-add-card's "Új esemény" tile (ds.css) —
       owner, 2026-09-26: "ahogy az új eseménynél is van szaggatott keret, úgy
       az új csoport köré is kéne". var(--et-color-line) read as practically
       invisible against the phone's tinted page (dump sa2-groups-list); the
       event tile's border-strong token is the one that actually reads as a
       dashed frame there. */
    border: 1.5px dashed var(--et-color-border-strong);
    border-radius: var(--et-card-radius-md);
    background: none;
    font-family: var(--et-font-family-base);
    color: var(--et-color-ink-2);
    cursor: pointer;
    transition: border-color .16s, color .16s, background .16s;
}
@media (min-width: 960px) {
    .et-group-card-new { display: flex; }
}
.et-group-card-new:hover {
    border-color: var(--et-color-accent);
    color: var(--et-color-accent);
    background: color-mix(in srgb, var(--et-color-accent) 4%, transparent);
}
.et-group-card-new:focus-visible {
    outline: 2px solid var(--et-color-accent);
    outline-offset: 2px;
}
.et-group-card-new-glyph {
    font-size: 26px;
    font-weight: 300;
    line-height: 1;
}
.et-group-card-new-label {
    font-size: 14px;
    font-weight: 700;
    color: inherit;
}
.et-group-card-new-hint {
    font-size: 12px;
    color: var(--et-color-ink-3);
    text-align: center;
}

/* ──────────── Meghívó elfogadása (/invite/{token}) page chrome ────────────
   Anonymous-reachable route with no page header of its own — the card is
   centered and capped at the design's 480px, banner included. */
.et-invite-page {
    max-width: 480px;
    width: 100%;
    margin: 0 auto;
    padding-top: 16px;
}
.et-invite-banner { margin-bottom: 12px; }
/* Lead line above the group identity ("Meghívást kaptál a csoportba:"). */
.et-invite-lead {
    font-size: 13px;
    color: var(--et-color-ink-2);
    margin-bottom: 10px;
}
/* Loading skeleton only. The loaded card paints .et-invite-hero below instead —
   this keeps the placeholder's circle-plus-two-bars layout, which does not need to
   match the hero's geometry pixel for pixel to read as "something is coming". */
.et-invite-group {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 18px;
}
.et-invite-group-text { min-width: 0; }

/* The group identity, wearing the group's own colour. The band itself is
   .et-group-new-preview-hero — the rules GroupNew's "Előnézet" used until
   2026-09-25, when that preview became the real group card; the invite page is now
   their only user. This wrapper supplies the rounding and the invite page's
   vertical rhythm. */
.et-invite-hero {
    border-radius: 14px;
    overflow: hidden;
    margin-bottom: 18px;
}
/* The already-member card follows the hero with an explanatory line, so it needs
   less breath underneath than the join variants. */
.et-invite-hero--member { margin-bottom: 12px; }
.et-invite-note {
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    margin-bottom: 16px;
}
/* "Add my birthday and name day" above the join button (spec 2026-10-04 D23) — the same
   breath under it as the note above. */
.et-invite-dates { margin-bottom: 16px; }
/* "You're joining as an admin" — a tinted note rather than another grey line, because
   it is the one thing on this card that changes what the visitor is agreeing to. Uses
   the shared accent tokens, so it follows the palette like everything else. */
.et-invite-admin-note {
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    background: var(--et-color-surface-2);
    border-radius: 12px;
    padding: 10px 12px;
    margin-bottom: 16px;
}
/* Passwordless claim screen: greeting heading ("Szia, Anna!"), the "Te vagy
   Anna?" confirmation line above the editable name field (plus the e-mail
   field on a magic link), then the code CTA, "vagy" and Google — the login
   card's order (spec 2026-08-27-passwordless-onboarding-design.md §2.1). */
.et-invite-greeting {
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--et-color-ink);
    margin-bottom: 4px;
}
.et-invite-claim-confirm {
    font-size: 13px;
    color: var(--et-color-ink-2);
    margin-bottom: 12px;
}
.et-invite-claim-fields {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 16px;
}
/* LegalConsentNote — under the sign-up buttons (login card, invite claim). */
.et-legal-consent {
    font-size: 12px;
    line-height: 1.45;
    color: var(--et-color-ink-2);
    text-align: center;
    margin: 16px 2px 0;
}
.et-legal-consent a {
    color: var(--et-color-accent);
    text-decoration: underline;
}

/* LegalUpdateSheet: the variant's paragraph, the changed documents' links one per line, then the
   tick — 20px between the blocks. The tick's label runs to two lines, so the box sits at its top
   (.et-check-row centres it; ds.css loads after this sheet, hence the doubled class). */
.et-legal-update-body { margin-bottom: 20px; }
.et-legal-update-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 20px;
}
.et-legal-update-link {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-accent);
    text-decoration: underline;
}
.et-check-row.et-legal-update-check { align-items: flex-start; }
.et-check-row.et-legal-update-check .et-check-row-label { line-height: 1.45; padding-top: 2px; }

/* Shared by the login card (Pages/Authentication.razor) and the invite claim
   screen, so the two sign-in starts read the same: the "vagy" hairline between
   the one-time code and Google, and the Google button's brand "G"
   (Components/Common/GoogleLogo.razor), set a little wider than .et-btn's 7px. */
.et-or-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 20px 0;
    font-size: 12px;
    font-weight: 600;
    color: var(--et-color-ink-3);
}
.et-or-divider::before,
.et-or-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--et-color-border);
}
/* Doubled class: ds.css loads after app.css, so a lone .et-google-btn loses to .et-btn. */
.et-btn.et-google-btn { gap: 10px; }
.et-google-logo,
.et-apple-logo { flex-shrink: 0; }
/* Google and Apple stacked under the divider (Components/Common/ProviderButtons.razor). */
.et-provider-buttons {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.et-invite-status-title {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
    margin-bottom: 6px;
}
.et-invite-status-body {
    font-size: 13px;
    color: var(--et-color-ink-2);
    margin-bottom: 16px;
}
/* Loading placeholder mirrors the resolved card's rhythm (lead, group row,
   CTA) so the swap doesn't jump. */
.et-invite-skeleton {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.et-invite-skeleton .et-invite-group { margin-bottom: 0; }
.et-invite-skeleton .et-invite-group-text {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
}
/* "Get the app" link under the join card. Phone-only: on desktop the Play
   Store is useless, and the page must not advertise an app the visitor can't
   install where they are. Hidden by default, revealed in the phone branch. */
.et-invite-getapp {
    display: none;
}
@media (max-width: 767.98px) {
    .et-invite-getapp {
        display: block;
        margin: 20px auto 0;
        text-align: center;
        font-size: 13px;
        font-weight: 600;
        color: var(--et-color-ink-2);
        text-decoration: underline;
        text-underline-offset: 3px;
    }
}

/* ──────────── /admin/coupons — operator-only, unlinked page ────────────
   Hand-scale tool (tens of rows), so a plain flex/grid row list rather than
   a real EtSurface-driven data grid — no DS "table" component exists here,
   this mirrors the .person-balance-row style of row list already in this
   file. Global-only by repo convention (Ds catalog components are the same
   way) — no scoped .razor.css. */
.et-admin-coupons-no-access {
    display: flex;
    justify-content: center;
    padding-top: 64px;
}

.et-admin-coupons-create {
    display: flex;
    align-items: flex-start;
    gap: var(--et-space-4);
}

.et-admin-coupons-note-field { flex: 1 1 auto; }

.et-admin-coupons-created-banner {
    display: flex;
    align-items: center;
    gap: var(--et-space-4);
    background: var(--et-color-success-bg, #E6F4EA);
    border: 1px solid var(--et-color-success, #1B8A4B);
}

.et-admin-coupons-created-label { color: var(--et-color-ink-2); }

.et-admin-coupons-created-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
}

.et-admin-coupons-copy-btn {
    border: 1px solid var(--et-color-border);
    background: transparent;
    border-radius: var(--et-radius-pill);
    padding: 2px 10px;
    font-size: 0.8rem;
    color: var(--et-color-ink-2);
    cursor: pointer;
    margin-left: var(--et-space-2);
}

.et-admin-coupons-copy-btn:hover { border-color: var(--et-color-border-strong); }

.et-admin-coupons-table {
    display: flex;
    flex-direction: column;
}

.et-admin-coupons-row {
    display: grid;
    grid-template-columns: 1.4fr 1.4fr 1fr 1fr 1.2fr 1.2fr;
    gap: var(--et-space-4);
    align-items: center;
    padding: var(--et-space-3) 0;
    border-bottom: 1px solid var(--et-color-border);
    font-size: 0.9rem;
}

.et-admin-coupons-row--head {
    font-weight: 700;
    color: var(--et-color-ink-3);
    text-transform: uppercase;
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    border-bottom-color: var(--et-color-border-strong);
}

.et-admin-coupons-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 600;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.et-admin-coupons-unredeemed { color: var(--et-color-ink-3); }

@media (max-width: 767.98px) {
    .et-admin-coupons-row {
        grid-template-columns: 1fr 1fr;
        row-gap: var(--et-space-1);
    }

    .et-admin-coupons-row--head { display: none; }

    .et-admin-coupons-row span:nth-child(3)::before { content: "📅 "; }
    .et-admin-coupons-row span:nth-child(5)::before { content: "👥 "; }
}

/* ──────────── /admin/purchases — operator-only, unlinked page ────────────
   Same plain row list as /admin/coupons above (whose no-access, search-bar and
   field classes it reuses), one column more: the refund action. Global-only,
   like the coupon block. */
.et-admin-crosslink {
    display: inline-block;
    margin: 0 0 var(--et-space-4);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--et-color-accent);
}

.et-admin-purchases-table {
    display: flex;
    flex-direction: column;
}

.et-admin-purchases-row {
    display: grid;
    grid-template-columns: 0.9fr 1.4fr 1.4fr 1.1fr 0.9fr 1.2fr 1fr;
    gap: var(--et-space-4);
    align-items: center;
    padding: var(--et-space-3) 0;
    border-bottom: 1px solid var(--et-color-border);
    font-size: 0.9rem;
}

.et-admin-purchases-row--head {
    font-weight: 700;
    color: var(--et-color-ink-3);
    text-transform: uppercase;
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    border-bottom-color: var(--et-color-border-strong);
}

.et-admin-purchases-strong {
    display: block;
    font-weight: 600;
}

.et-admin-purchases-sub {
    display: block;
    font-size: 0.78rem;
    color: var(--et-color-ink-3);
    overflow-wrap: anywhere;
}

.et-admin-purchases-tx {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.78rem;
    overflow-wrap: anywhere;
}

.et-admin-purchases-refunded {
    color: var(--et-color-ink-3);
    font-size: 0.85rem;
}

.et-admin-purchases-confirm {
    display: flex;
    flex-direction: column;
    gap: var(--et-space-2);
}

.et-admin-purchases-preview {
    margin: var(--et-space-2) 0;
    font-weight: 600;
}

@media (max-width: 767.98px) {
    .et-admin-purchases-row {
        grid-template-columns: 1fr 1fr;
        row-gap: var(--et-space-1);
    }

    .et-admin-purchases-row--head { display: none; }
}

/* ──────────── /admin/stats — operator-only statistics ────────────
   Spec 2026-10-05-admin-stats-design.md. One EtSurface per section holding stat
   tiles, small window tables and two 30-day bar charts. The charts are plain CSS:
   one series each, so the bars wear the palette accent and follow every palette
   and dark mode through the tokens. Global-only, like the other admin blocks. */
.et-admin-crosslinks {
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--et-space-5);
}

.et-admin-stats-lede {
    margin: 0 0 var(--et-space-4);
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--et-color-ink-2);
}

.et-admin-stats-note {
    margin: var(--et-space-3) 0 0;
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--et-color-ink-2);
}

.et-admin-stats-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--et-space-2);
    margin-top: var(--et-space-3);
}

.et-admin-stats-tile {
    min-width: 0;
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--et-color-surface-2);
}

.et-admin-stats-tile-label {
    font-size: 0.75rem;
    line-height: 1.3;
    color: var(--et-color-ink-2);
}

/* Proportional figures: a lone big number, not a column (dataviz stat-tile rule). */
.et-admin-stats-tile-value {
    margin-top: 4px;
    font-size: 1.45rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--et-color-ink);
    overflow-wrap: anywhere;
}

.et-admin-stats-tile-detail {
    margin-top: 2px;
    font-size: 0.75rem;
    color: var(--et-color-ink-2);
}

/* Capped so a number stays within reach of its row label on a wide card. */
.et-admin-stats-table {
    width: 100%;
    max-width: 640px;
    margin-top: var(--et-space-3);
    border-collapse: collapse;
    font-size: 0.88rem;
}

.et-admin-stats-table th,
.et-admin-stats-table td {
    padding: 6px 8px;
    text-align: right;
    border-bottom: 1px solid var(--et-color-border);
    font-variant-numeric: tabular-nums;
}

.et-admin-stats-table th:first-child,
.et-admin-stats-table td:first-child { padding-left: 0; }

.et-admin-stats-table th:last-child,
.et-admin-stats-table td:last-child { padding-right: 0; }

.et-admin-stats-table thead th {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--et-color-ink-2);
    border-bottom-color: var(--et-color-border-strong);
}

.et-admin-stats-table thead td { border-bottom-color: var(--et-color-border-strong); }

.et-admin-stats-table tbody th {
    text-align: left;
    font-weight: 600;
    color: var(--et-color-ink);
}

.et-admin-stats-table-total th,
.et-admin-stats-table-total td { border-bottom: none; }

.et-admin-stats-table-strong {
    display: block;
    font-weight: 600;
}

.et-admin-stats-table-sub {
    display: block;
    font-size: 0.75rem;
    color: var(--et-color-ink-2);
}

/* Bar chart, per the dataviz mark spec: bars at most 24px wide with a 4px rounded
   data end and a square foot, a 2px gap between neighbours, one hairline baseline,
   no gridlines. The whole column is the hover target, not just the painted bar.
   --et-bar-h is the bar's share of the tallest one, set inline per column. */
.et-admin-stats-chart { margin: var(--et-space-4) 0 0; }

.et-admin-stats-chart-title {
    margin-bottom: var(--et-space-2);
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--et-color-ink);
}

.et-admin-stats-bars {
    display: flex;
    align-items: stretch;
    gap: 2px;
    height: 120px;
    padding-top: 18px; /* room for the tallest bar's value */
    border-bottom: 1px solid var(--et-color-border-strong);
}

.et-admin-stats-bar-col {
    position: relative;
    display: flex;
    flex: 1 1 0;
    align-items: flex-end;
    justify-content: center;
    min-width: 0;
}

.et-admin-stats-bar {
    display: block;
    width: 100%;
    max-width: 24px;
    height: max(2px, var(--et-bar-h));
    border-radius: 4px 4px 0 0;
    background: var(--et-color-accent);
    transition: opacity .15s;
}

.et-admin-stats-bar-col:hover .et-admin-stats-bar { opacity: 0.7; }

.et-admin-stats-bar-value {
    position: absolute;
    bottom: calc(var(--et-bar-h) + 2px);
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--et-color-ink-2);
}

/* Today's value sits at the right edge; anchor it there so it never leaves the card. It is
   wider than one column on a phone and today is usually still shorter than yesterday, so it
   rides in the band above the tallest bar instead of on its own bar. */
.et-admin-stats-bar-col:last-child .et-admin-stats-bar-value {
    top: -16px;
    bottom: auto;
    left: auto;
    right: 0;
    transform: none;
}

.et-admin-stats-chart-axis {
    display: flex;
    justify-content: space-between;
    margin-top: 4px;
    font-size: 0.7rem;
    color: var(--et-color-ink-2);
}

.et-admin-stats-chart-data {
    margin-top: var(--et-space-2);
    font-size: 0.8rem;
}

.et-admin-stats-chart-data summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--et-color-accent);
}

@media (max-width: 639.98px) {
    .et-admin-stats-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ──────────── /admin/system — operator-only system status ────────────
   Spec 2026-10-22-admin-system-status-design.md. Tiles, tables and crosslinks reuse the
   .et-admin-stats-* classes above; only the status text/error-list below are new. */
.et-admin-system-status--ok { color: #15764A; font-weight: 600; }
.et-admin-system-status--error { color: #C4392D; font-weight: 600; }
.et-admin-system-status--not-configured { color: var(--et-color-ink-2); }

.et-admin-system-errors {
    margin: var(--et-space-2) 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.82rem;
    line-height: 1.5;
}

.et-admin-system-errors li {
    padding: 6px 0;
    border-bottom: 1px solid var(--et-color-border);
    color: var(--et-color-ink-2);
    overflow-wrap: anywhere;
}

.et-admin-system-errors li:last-child { border-bottom: none; }

/* ──────────── /admin/ai-quota — operator-only AI-quota test tool ────────────
   Spec 2026-10-06-admin-ai-quota-tool-design.md. The search bar, cross-links and
   lede reuse the coupon and stats classes above; each card is an EtSurface with a
   few lines and a row of small buttons. Global-only, like the other admin blocks. */
.et-admin-ai-quota-who {
    margin: 0 0 var(--et-space-2);
    font-size: 0.85rem;
    color: var(--et-color-ink-2);
    overflow-wrap: anywhere;
}

.et-admin-ai-quota-lines {
    display: flex;
    flex-direction: column;
    gap: var(--et-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.95rem;
    font-variant-numeric: tabular-nums;
}

.et-admin-ai-quota-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--et-space-2);
    margin-top: var(--et-space-3);
}

/* ── Event summary panel (/groups/{g}/events/{e}, F-38) ──
   Glue between DS components only — the components style from ds.css. Global
   rather than a .razor.css for the reason the attachment strip above gives:
   this project's scoped bundle isn't wired into index.html. */
.et-event-summary-hero {
    position: relative;
    height: 150px;
    border-radius: var(--et-card-radius-lg);
    overflow: hidden;
    margin-bottom: 14px;
}
.et-event-summary-hero img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* Same chip the card's countdown wears, so the panel reads as the card
   opened up rather than as a different screen. */
.et-event-summary-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-summary-badge--urgent {
    background: #C4392D;
    color: #fff;
}
/* R4-04 — one gutter for the occasion's glyph and the date's, so the two rows
   start in the same column. The width fits the larger of the two — a 19px emoji
   advances ~24px, and 28 leaves it a few pixels of air rather than letting the
   glyph touch the name — and it is reserved even when the event carries no icon:
   an empty gutter keeps the name over the date, which is the whole point, and
   reads as an icon column rather than as a stray indent. */
/* R4-06 (owner 2026-09-17): "a naptár emoji még mindig balrább van mint a
   kategória emoji". The gutter aligned the two ADVANCE boxes, but the glyphs
   inside them were still 19px and 13px, and an emoji's left side bearing scales
   with its font size — so the smaller one's ink started further left. One size
   for both leaves only the difference the emoji font itself draws.
   Note this is as far as CSS can take it: if two emoji in the same font at the
   same size still disagree, the fix is a drawn SVG (round-3 D11 — emoji fonts
   drift across platforms, which is why the bell and the gear are SVGs now). */
.et-event-summary-title,
.et-event-summary-meta { --et-evs-lead: 28px; --et-evs-lead-size: 16px; }
.et-event-summary-title {
    display: flex;
    align-items: baseline;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--et-color-ink);
}
.et-event-summary-icon {
    flex: 0 0 var(--et-evs-lead);
    /* The glyph sits at the gutter's left edge, same as the date's, instead of
       being centred in it — centring two differently sized icons in one column
       leaves their left edges apart again.
       NO overflow:hidden. It was here to stop a wide emoji spilling into the
       name, but an emoji draws TALLER than its line box, and with line-height:1
       the clip cut the bottom off the glyph — a cake missing its plate (owner,
       2026-09-17). It cannot spill sideways anyway: a 16px emoji advances ~19px
       inside a 28px gutter. */
    font-size: var(--et-evs-lead-size);
    /* The title's 19px line box still sets the row height; the glyph only shrinks
       inside it. line-height:1 keeps it from dragging the baseline around. */
    line-height: 1;
}
.et-event-summary-title-text { min-width: 0; }
.et-event-summary-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 8px;
    margin-bottom: 16px;
}
/* The date chip's own emoji takes the same gutter. EtMetaItem's 5px gap is
   zeroed here (and only here) because the gutter already carries the spacing —
   left in, the date's text would land 5px past the title's. Scoped to this row,
   so every other EtMetaItem call site is untouched. */
.et-event-summary-meta .et-meta-item { gap: 0; }
.et-event-summary-meta .et-meta-item-emoji {
    flex: 0 0 var(--et-evs-lead);
    /* Same size as the occasion's glyph above — see the note on the gutter. */
    font-size: var(--et-evs-lead-size);
}
.et-event-summary-total {
    font-size: 16px;
    font-weight: 700;
    color: var(--et-color-ink);
}
.et-event-summary-previous {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
    font-size: 13px;
    color: var(--et-color-ink-2);
}
.et-event-summary-diff {
    font-weight: 700;
    color: var(--et-color-ink-3);
}
.et-event-summary-diff--up { color: var(--et-color-owe); }
.et-event-summary-diff--down { color: var(--et-color-owed); }
.et-event-summary-recipient {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 3px;
    font-size: 13px;
}
.et-event-summary-recipient + .et-event-summary-recipient {
    border-top: 1px solid var(--et-color-border);
}
.et-event-summary-recipient-name { color: var(--et-color-ink); }
.et-event-summary-recipient-amount {
    font-weight: 700;
    color: var(--et-color-ink);
}
/* R4-01 — the viewer's own row. "(Te)" is a quiet qualifier on the name, and
   "Meglepetés" takes the amount's slot: same alignment, deliberately not the
   amount's weight and colour, so a missing figure reads as intent rather than
   as a value that failed to load. */
.et-event-summary-recipient-you {
    color: var(--et-color-ink-3);
    margin-left: 4px;
}
.et-event-summary-recipient-surprise {
    color: var(--et-color-ink-3);
    font-weight: 600;
    white-space: nowrap;
}

/* ── Closed-beta gate card (Components/Common/BetaGateCard.razor) ─────────────
   Temporary: goes out with the gate at public launch. Same 480px centered frame
   as the invite-claim screen — from the visitor's side it is the same moment. */
.et-beta-gate {
    max-width: 480px;
    width: 100%;
    margin: 0 auto;
    padding-top: 16px;
}
.et-beta-gate-title {
    font-size: 19px;
    font-weight: 800;
    color: var(--et-color-ink);
    margin-bottom: 6px;
}
.et-beta-gate-body {
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    margin-bottom: 16px;
}
.et-beta-gate-field { margin-bottom: 14px; }
.et-beta-gate-logout {
    display: flex;
    justify-content: center;
    margin-top: 8px;
}

/* ── "Update the app" (Components/Common/UpdateRequiredScreen.razor) ──────────
   Rendered by AppUpdateGate INSTEAD of the whole app, so it brings its own
   full-screen frame — the boot splash's (shell.css .kk-boot-splash) — with one
   card in the middle. Spec 2026-11-07-min-app-version-gate-design.md D8. */
.et-update-gate {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: var(--et-color-bg, #FAFAF7);
}
.et-update-gate-card {
    max-width: 400px;
    width: 100%;
}
.et-update-gate-title {
    font-size: 19px;
    font-weight: 800;
    color: var(--et-color-ink);
    margin-bottom: 6px;
}
.et-update-gate-body {
    font-size: 13px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    margin-bottom: 16px;
}

/* ════════════ Phone shell: the Kassza screens' own overrides ════════════
   The section itself is in shell.css; these rules name a Kassza screen, so
   they live here, under the same max-width 959.98px gate. */
@media (max-width: 959.98px) {
    /* The same .et-pro-badge the header CTA carries (one token pair, one
       component) — pinned to the disc's shoulder, because a 56px circle has no
       room for it inline. */
    html.et-shell-bar .et-bottom-bar-add-badge {
        position: absolute;
        top: -2px;
        right: -12px;
        padding: 2px 7px;
        font-size: 10px;
    }

    /* Group settings: with the twin gone, the header under the tabs only
       repeated the tab's own name (plus a count the list shows anyway), so the
       tab content starts right below the tabs (owner, 2026-10-02). Same gate:
       on desktop the header stays, because there it carries the action. */
    html.et-shell-bar .et-group-settings-tab-header { display: none; }

    /* GroupsList: with the "Új csoport" FAB gone, the dashed create tile the
       grid already shows from 960px up comes back on — one create affordance,
       inside the collection it adds to. */
    html.et-shell-bar .et-group-card-new { display: flex; }

    /* Home's hero drops the greeting — it is in the header now — and the
       subtitle becomes the page's first line. */
    html.et-shell-bar .et-home-hero-ds .et-page-hero-title { display: none; }
    html.et-shell-bar .et-home-hero-ds .et-page-hero-subtitle { margin: 4px 0 16px; }

    /* The emptied box keeps only the gap under the bar: 16px, the same the
       illustrated band (§10 below) and the group band leave above the first
       section. Its text-hero rhythm — 18px top padding + 16px bottom margin on
       a phone, 28 + 22 up to 960px — stacked into 34–50px of blank with no
       line of text to space (owner, 2026-09-25: "kicsit nagy a margin").
       Padding rather than margin, so the box holds the gap on its own and
       Kezdőlap's subtitle, should it come back, still gets air above it.
       Two classes on the Kezdőlap selector to outrank the hero's own
       .et-page-hero.et-home-hero-ds. */
    html.et-shell-bar .et-page-hero.et-home-hero-ds,
    html.et-shell-bar .et-page-hero--tab {
        padding-top: 16px;
        margin-bottom: 0;
    }
    /* Csoportok's grid adds 8px of its own on top; under the bar it would be
       the one tab whose first card sits lower than the rest. */
    html.et-shell-bar .et-groups-grid { padding-top: 0; }

    /* Értesítések joined 2026-09-26, and its hero is the one --split form in
       this group (it still carries the "Mind olvasott" button below the
       title). The --split row's own 12px gap (the phone branch above) was
       written for two pieces of TEXT plus a button; with the title/subtitle
       hidden by the --tab rule above, that gap would still sit between the
       now-empty text column and the button — a strip of dead air the owner
       explicitly didn't want left over. Zero it so the button sits right
       under the bar's 16px padding, same rhythm as the emptied box on the
       other three tabs.

       Unlike those three, this hero's own content doesn't end at the empty
       box — the button is real, visible content, and the shared --tab rule's
       margin-bottom:0 (above) then left it flush against "További szűrők"
       (owner follow-up: 0px between them). The other three tabs never hit
       this because their hero IS just the spacer; here the spacer and a
       visible control share one box. Restore the button's own breathing
       room — 12px, the same distance the phone branch always gave a
       stacked split row — as this hero's OWN margin-bottom, which wins the
       tie against the shared rule by sitting later in the cascade at equal
       specificity (html.et-shell-bar + one class each). */
    html.et-shell-bar .et-notifications-hero {
        gap: 0;
        margin-bottom: 12px;
    }

    /* And the band runs under the status bar — but only where there IS one to
       run under. This is the half that stays on .et-standalone: a browser has
       chrome of its own above the viewport, so an inset there would open a gap
       under it. Both classes together = installed AND showing the shell, which
       is the only state in which the band is the topmost element on screen.

       Padding on the band itself, not a spacer above it: the gradient is the
       element own background, so it paints through the padding box and runs
       edge to edge behind the clock, with no second element to keep in sync.

       var() before env(): Capacitor SystemBars (insetsHandling "css", the
       default, and what capacitor.config.ts relies on) injects
       --safe-area-inset-* itself, because Android WebViews below 140 answer
       env(safe-area-inset-*) with 0. iOS and newer WebViews define no variable
       and answer env() correctly, so the chain reads the right number on both
       and 0 where there is no inset at all. */
    html.et-standalone.et-shell-bar .app-shell[data-route="group"] .et-group-view-header,
    html.et-standalone.et-shell-bar .app-shell[data-route="group"] .et-group-settings-header {
        --et-gh-inset: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
        padding-top: var(--et-gh-inset);
    }
}

/* ── Member-dates sheet (spec 2026-10-02-member-dates §3) ─────────────────
   One block per member inside MemberDatesPanel: an avatar+name head, then
   the nameday and birthday rows (EtCheckRow + EtDatePicker, or the
   .et-first-steps-row--done treatment reused as-is when the group already
   holds a matching event). Only the parts those shared rows don't already
   cover need rules here. */
.et-member-dates-member {
    padding: 14px 0;
}
.et-member-dates-member + .et-member-dates-member {
    border-top: 1px solid var(--et-color-border);
}
.et-member-dates-member-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}
.et-member-dates-member-name {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
}
/* EtCheckRow is a bare flex line; inside this sheet each one is a tap target of its own,
   so it gets the 44px row height, and the month/day pair under it a gap before the next row. */
.et-member-dates-member .et-check-row {
    min-height: 44px;
}
.et-member-dates-member .et-event-date-row {
    margin-bottom: 8px;
}
.et-member-dates-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 4px 0 10px 34px;
}
/* The entry row on GroupSettings › Események reuses .et-event-quickadd's look
   (the other "opens a sheet" row in this section) — only its own spacing
   needs a rule here. */
.et-member-dates-entry {
    margin-bottom: 20px;
}

/* ── Onboarding part 4: kasszatípus step + event sheet (GroupNew) — spec
   2026-10-02-kassza-types-design.md. Appended at the end (CLAUDE.md's parallel-agent
   convention): another onboarding sub-project's PR appends its own block above or
   below this one, so the merge conflict stays one blank line, not an interleave. ── */

/* Step 2's cards: one column of horizontal cards (art left, text right) at EVERY width —
   the panel is a ~460px rail on desktop too, not a wide page, so a multi-column grid there
   just makes the cards tall and cramped, not more legible. */
.et-kassza-type-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--et-space-3);
}

.et-kassza-type-card {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--et-space-3);
    text-align: left;
    padding: var(--et-space-3);
    border-radius: var(--et-card-radius-md);
    border: 1px solid var(--et-color-border);
    background: var(--et-color-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
    transition: border-color var(--et-motion-fast) var(--et-ease-standard);
}
/* Mouse only: a touch screen keeps :hover on whatever card the finger last crossed while
   scrolling, and that grey border read as a second, half selection (owner, 2026-10-05). */
@media (hover: hover) {
    .et-kassza-type-card:hover {
        border-color: var(--et-color-ink-3);
    }
}
/* A tap selects; "Tovább" opens the sheet (spec 2026-10-04-create-flow-round2-design.md §1).
   The inset ring doubles the 1px border to 2px without moving the card's content. */
.et-kassza-type-card--selected,
.et-kassza-type-card--selected:hover {
    border-color: var(--et-color-accent);
    box-shadow: inset 0 0 0 1px var(--et-color-accent);
}
/* The check badge sits on the card's top-right corner, half outside it, so it never covers
   the name or the description. The panel body's 16px padding leaves room for the overhang.
   Same 24px size and ✓ glyph as the event rows' own tick box. */
.et-kassza-type-check {
    position: absolute;
    top: -8px;
    right: -8px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--et-color-accent);
    color: #fff;
    font-size: 13px;
    font-weight: 800;
    line-height: 1;
    box-shadow: 0 0 0 2px var(--et-color-surface);
}
/* The group SVGs (5:2 canvas) draw their motif anchored to the right ~55% and leave the
   left side transparent (see group-*.svg's own comment) — object-position: right centers
   the crop ON the motif instead of straddling the empty/drawn boundary, which left only a
   sliver of it visible. */
.et-kassza-type-art {
    width: 96px;
    height: 56px;
    flex: 0 0 auto;
    border-radius: var(--et-card-radius-sm);
    object-fit: cover;
    object-position: right center;
    background: var(--et-color-surface-2);
}
.et-kassza-type-body {
    min-width: 0;
}
.et-kassza-type-name {
    font-weight: 600;
    margin-bottom: 2px;
}
.et-kassza-type-desc {
    font-size: 13px;
    line-height: 1.35;
    color: var(--et-color-ink-2);
}

/* The Kind step's "Mi a különbség?" table under the two cards (GroupNew): a row label,
   then the Kassza and the Ideiglenes cell. Two fixed columns, so the ✓ / – marks line up
   down the table whatever the label's length. */
.et-kind-compare-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 92px 92px;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    font-size: 13px;
    line-height: 1.3;
    border-top: 1px solid var(--et-color-border);
}
.et-kind-compare-row:first-child { border-top: 0; }
.et-kind-compare-head {
    font-size: 12px;
    font-weight: 700;
    color: var(--et-color-ink-2);
    text-align: center;
}
.et-kind-compare-label { color: var(--et-color-ink); }
.et-kind-compare-text {
    font-size: 12px;
    color: var(--et-color-ink-2);
    text-align: center;
}
.et-kind-compare-mark {
    font-size: 15px;
    font-weight: 700;
    color: var(--et-color-ink-4);
    text-align: center;
}
.et-kind-compare-mark--yes { color: var(--et-color-accent); }
/* 11px keeps the note on one line from a 375px phone up (measured: ~336px of text);
   at 12px it already wrapped on a 393px one. */
.et-kind-compare-note {
    margin-top: 10px;
    font-size: 11px;
    line-height: 1.35;
    color: var(--et-color-ink-3);
}

/* The event sheet's date-needed rows (EtCrudRow pick row + this month/day picker pair —
   events in this app have no free year field, so this reuses EventEditPanel's own month+day
   EtDropdown pair without its year chips, since a pack row resolves its year automatically
   instead of asking). Padding mirrors the row's own 8px/11px rhythm
   so the pair reads as part of the same row, not a new field card; the divider variant
   closes off the group exactly where the row's own --divider box-shadow would. Always a
   2-column grid (unlike EventEditPanel's own .et-event-date-row, which stacks full-width on
   desktop) — this is a compact row, not a page-filling form field. */
.et-kassza-date-pickers {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    padding: 0 8px 10px 8px;
}
.et-kassza-date-pickers--divider {
    box-shadow: inset 0 -1px 0 var(--et-color-border);
}
.et-kassza-event-error {
    padding: 0 8px 10px 8px;
}

/* Categories step (spec 2026-10-02-kassza-categories-design.md, code review #583):
   EtChip Filter chips instead of a 20-row toggle list, so the whole step fits a 430px
   phone with little or no scrolling — same flex-wrap row .et-member-dates-chips
   already uses for its own filter chips. */
.et-kassza-category-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 20px;
}

/* The one-time kassza's "Kik voltak ott?" (GroupNew, spec 2026-10-06-one-time-kassza-design.md
   §4.1): the name field with a round + inside its right edge, then the names as chips (owner,
   2026-10-06: a full-height "Hozzáadás" pill beside the field was clumsy and narrowed it). The
   card and the + share the grid's one cell, so the + centres on the card alone; the field's
   own wrapper steps aside (display: contents) and its error line takes the second row. */
.et-onetime-name-add { display: grid; grid-template-columns: minmax(0, 1fr); }
.et-onetime-name-add .et-field { display: contents; }
.et-onetime-name-add .et-field-card { grid-column: 1; grid-row: 1; padding-right: 64px; }
.et-onetime-name-add .et-icon-btn {
    grid-column: 1;
    grid-row: 1;
    justify-self: end;
    align-self: center;
    margin-right: 9px;
}
.et-onetime-name-add .et-field-error { grid-column: 1; grid-row: 2; }
.et-onetime-names {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
/* A name may run to 100 characters: it wraps inside its chip rather than past a phone's edge. */
.et-onetime-names .et-chip {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: left;
}
/* OneTimeShareCard (spec 2026-10-06-one-time-kassza-design.md §4.2): the lead, the share button
   and the tick under one another at the form's field rhythm. */
.et-onetime-share .et-check-row { margin-top: 12px; }

/* CountryPicker (spec 2026-10-22-countries-design.md task 4): the flag ahead of each country
   name, in the setup step's and Profile's shared item list. 4:3 source art at a fixed 24×18 —
   .et-group-menu-item's own 9px gap already spaces it from the name, no margin needed here.
   The 1px inset hairline keeps the white Swiss/UK/US flags readable against the menu's own
   near-white surface. */
.et-country-flag {
    width: 24px;
    height: 18px;
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
    flex-shrink: 0;
}

/* marketplace — shop (UI-2, spec 2026-10-29-event-marketplace-design.md). Global on purpose:
   the shop's pages and Components/Domain/Shop/* carry no scoped CSS, so nothing here can fall
   into the scoped-emission gap. */
/* EventShopButton (D21): the shop's entry on the event sheet, under the "Idén összesen" card.
   The card above already leaves 20px; this keeps the same block gap to the section below. */
.et-event-summary-shop { margin-bottom: 20px; }
/* EventShopButton: the shop entry as a CTA card on the palette's gradient (owner: prominent).
   The sheen runs once on appear and moves by transform only (phone motion rule). */
.et-event-shop-button {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 14px 14px 16px;
    border-radius: 20px;
    background: var(--et-cta-gradient);
    color: #fff;
    text-decoration: none;
    box-shadow: var(--et-cta-shadow);
    transition: transform 160ms ease, box-shadow 160ms ease;
}
.et-event-shop-button::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, 0.28) 50%, transparent 70%);
    transform: translateX(-120%);
    animation: et-event-shop-sheen 1.4s 0.4s ease-out 1 both;
    pointer-events: none;
}
@keyframes et-event-shop-sheen { to { transform: translateX(120%); } }
.et-event-shop-button:hover { transform: translateY(-1px); box-shadow: var(--et-cta-shadow-hover, var(--et-cta-shadow)); color: #fff; }
.et-event-shop-button:active { transform: translateY(0); box-shadow: none; }
.et-event-shop-button:focus-visible { outline: 3px solid var(--et-color-accent); outline-offset: 3px; }
.et-event-shop-button-icon {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.18);
    font-size: 26px;
    line-height: 1;
}
.et-event-shop-button-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.et-event-shop-button-title { font-size: 17px; font-weight: 800; line-height: 1.2; }
.et-event-shop-button-hint { font-size: 13px; font-weight: 500; line-height: 1.3; opacity: 0.88; }
.et-event-shop-button-go {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    font-size: 22px;
    font-weight: 700;
    line-height: 1;
    padding-bottom: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .et-event-shop-button, .et-event-shop-button:hover { transition: none; transform: none; }
    .et-event-shop-button::after { animation: none; display: none; }
}
/* ShopProviderHeader (D16): cover band, logo + name + tagline, city and website, the about text. */
.et-shop-provider {
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-lg);
    box-shadow: var(--et-shadow-card);
    overflow: hidden;
}
.et-shop-provider-cover { aspect-ratio: 3 / 1; max-height: 220px; width: 100%; background: var(--et-color-surface-2); }
.et-shop-provider-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.et-shop-provider-body { padding: 16px; }
.et-shop-provider-id { display: flex; align-items: center; gap: 12px; }
.et-shop-provider-logo {
    width: 52px;
    height: 52px;
    flex-shrink: 0;
    border-radius: 50%;
    object-fit: cover;
    background: var(--et-color-surface-2);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
}
.et-shop-provider-names { min-width: 0; }
.et-shop-provider-name { font-size: 18px; font-weight: 800; color: var(--et-color-ink); line-height: 1.2; }
.et-shop-provider-tagline { margin-top: 2px; font-size: 13px; color: var(--et-color-ink-2); }
.et-shop-provider-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: 10px;
    font-size: 13px;
    color: var(--et-color-ink-2);
}
.et-shop-provider-meta a { color: var(--et-color-ink-2); font-weight: 600; }
.et-shop-provider-about {
    margin-top: 10px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    white-space: pre-line;
    overflow-wrap: anywhere;
}
/* A provider's packages in one category (ShopGroupPage, D22): header, note, tiles. */
.et-shop-group { margin-bottom: 20px; }
.et-shop-group-head { margin: 20px 0 10px; }
.et-shop-group-note { margin-top: 2px; font-size: 12px; color: var(--et-color-ink-3); }
.et-shop-products {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 10px;
}
.et-shop-tile {
    display: flex;
    flex-direction: column;
    background: var(--et-color-surface);
    border-radius: var(--et-card-radius-md);
    box-shadow: var(--et-shadow-card);
    overflow: hidden;
    color: var(--et-color-ink);
    text-decoration: none;
}
.et-shop-tile:hover { color: var(--et-color-ink); box-shadow: var(--et-shadow-card-hover); }
.et-shop-tile-media {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    background: var(--et-color-surface-2);
}
.et-shop-tile-media img { width: 100%; height: 100%; object-fit: cover; }
.et-shop-tile-placeholder { font-size: 40px; line-height: 1; }
.et-shop-tile-name { padding: 10px 12px 0; font-size: 14px; font-weight: 700; line-height: 1.3; }
.et-shop-tile-price { padding: 4px 12px 12px; font-size: 14px; font-weight: 800; color: var(--et-color-ink-2); }
/* D25 (ShopPriceTag): the 30-day reference struck through before the price paid, "Közös Kassza ár"
   under them; the tile, the product page and the cart line set the size. */
.et-shop-price-was { margin-right: 6px; font-size: 0.8em; font-weight: 600; color: var(--et-color-ink-3); }
.et-shop-price-kk { display: block; margin-top: 2px; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--et-color-accent); }
/* D20: a voucher tile's mark, between the name and the price. */
.et-shop-tile-voucher { padding: 4px 12px 0; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--et-color-accent); }
/* D24: "Elfogyott" / "Már csak N db" between the name and the price; a sold-out tile's picture fades. */
.et-shop-tile-stock { padding: 4px 12px 0; font-size: 12px; font-weight: 700; color: var(--et-color-pend); }
.et-shop-tile--sold-out .et-shop-tile-stock { color: var(--et-color-owe); }
.et-shop-tile--sold-out .et-shop-tile-media { opacity: 0.5; }
/* Product page: image beside the text on a wide screen, above it on a phone. */
.et-shop-product {
    display: grid;
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
    max-width: 880px;
}
.et-shop-product-media {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-radius: var(--et-card-radius-lg);
    background: var(--et-color-surface-2);
    overflow: hidden;
}
.et-shop-product-media img { width: 100%; height: 100%; object-fit: cover; }
.et-shop-product-media .et-shop-tile-placeholder { font-size: 72px; }
.et-shop-product-group { font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--et-color-ink-3); }
.et-shop-product-name { margin: 4px 0 0; font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.2; color: var(--et-color-ink); }
.et-shop-product-price { margin-top: 10px; font-size: 20px; font-weight: 800; color: var(--et-color-ink); }
.et-shop-product-stock { margin-top: 10px; font-size: 14px; font-weight: 700; color: var(--et-color-pend); }
.et-shop-product-stock--out { color: var(--et-color-owe); }
.et-shop-product-desc { margin-top: 10px; font-size: 14px; line-height: 1.5; color: var(--et-color-ink-2); white-space: pre-line; }
.et-shop-product-note { margin-top: 10px; font-size: 13px; color: var(--et-color-ink-3); }
.et-shop-product-seller { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 13px; color: var(--et-color-ink-2); }
.et-shop-product-seller-logo { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; }
.et-shop-product-buy { display: flex; align-items: center; gap: 10px; margin-top: 20px; }
.et-shop-product-buy .et-btn { flex: 1; }
.et-shop-product-to-cart { margin-top: 10px; }
/* D24: in place of the buy row when the cart already holds every piece left. */
.et-shop-product-all-in-cart { margin-top: 20px; font-size: 14px; font-weight: 600; color: var(--et-color-ink-2); }
@media (max-width: 767.98px) {
    .et-shop-product { grid-template-columns: minmax(0, 1fr); }
}
.et-shop-dialog-text { font-size: 14px; line-height: 1.5; color: var(--et-color-ink-2); }
/* ShopQuantityStepper: − n + in one pill. */
.et-shop-qty {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    border-radius: var(--et-radius-pill);
    background: var(--et-color-surface-2);
}
.et-shop-qty-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    color: var(--et-color-ink);
    cursor: pointer;
}
/* The drawn − and + (ShopQuantityStepper says why not text): the weight of an 18px bold sign. */
.et-shop-qty-btn svg { display: block; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; }
.et-shop-qty-btn:disabled { opacity: 0.4; cursor: default; }
.et-shop-qty-value { min-width: 24px; text-align: center; font-size: 15px; font-weight: 800; color: var(--et-color-ink); }
/* The shop's pages are sub-pages, not tab roots: their "← Vissza" stays in the phone shell, where
   shell.css hides the roots' .et-page-back (the tab is the way back there, not here). */
html.et-shell-bar .et-page-back.et-shop-back { display: inline-flex; }
/* Cart lines, totals and the shared 20px block rhythm. */
.et-shop-block { margin-top: 20px; }
.et-shop-cta { margin-top: 20px; }
.et-shop-line {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr) auto;
    gap: 12px;
    align-items: start;
    padding: 14px 16px;
}
.et-shop-line + .et-shop-line { box-shadow: inset 0 1px 0 var(--et-color-border); }
.et-shop-line-media {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: var(--et-card-radius-sm);
    background: var(--et-color-surface-2);
    overflow: hidden;
    font-size: 26px;
}
.et-shop-line-media img { width: 100%; height: 100%; object-fit: cover; }
.et-shop-line-name { font-size: 14px; font-weight: 700; color: var(--et-color-ink); line-height: 1.3; }
.et-shop-line-unit { margin-top: 2px; font-size: 13px; color: var(--et-color-ink-3); }
/* D24: a line wanting more than is left (the error), or nearly sold out (the note). */
.et-shop-line-error { margin-top: 2px; font-size: 13px; font-weight: 700; color: var(--et-color-owe); }
.et-shop-line-stock { margin-top: 2px; font-size: 13px; font-weight: 600; color: var(--et-color-pend); }
.et-shop-summary-error + .et-shop-summary-line { margin-top: 8px; }
.et-shop-line-controls { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.et-shop-line-controls .et-shop-qty-btn { width: 32px; height: 32px; }
.et-shop-line-remove {
    border: 0;
    padding: 0;
    background: none;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--et-color-ink-2);
    text-decoration: underline;
    cursor: pointer;
}
.et-shop-line-total { font-size: 14px; font-weight: 800; color: var(--et-color-ink); white-space: nowrap; }
.et-shop-line--unavailable .et-shop-line-media,
.et-shop-line--unavailable .et-shop-line-name,
.et-shop-line--unavailable .et-shop-line-total { opacity: 0.45; }
.et-shop-line--unavailable .et-shop-line-total { text-decoration: line-through; }
.et-shop-totals { display: flex; flex-direction: column; gap: 8px; }
.et-shop-totals-row { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; color: var(--et-color-ink-2); }
.et-shop-totals-row--total { padding-top: 8px; border-top: 1px solid var(--et-color-border); font-weight: 800; color: var(--et-color-ink); }
.et-shop-totals-total { font-size: 18px; }
.et-shop-totals-row--refund { color: var(--et-color-owed); font-weight: 700; }
.et-shop-hint { margin-top: 10px; font-size: 12px; color: var(--et-color-ink-3); }
.et-shop-cart, .et-shop-checkout, .et-shop-order { max-width: 720px; }
/* Checkout: a label, 10px, its fields 10px apart; 20px between blocks. */
.et-shop-section-label {
    margin-bottom: 10px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--et-color-ink-3);
}
.et-shop-fields { display: flex; flex-direction: column; gap: 10px; }
.et-shop-hint--flush { margin-top: 0; font-size: 13px; color: var(--et-color-ink-2); }
.et-shop-split-group { margin-top: 10px; }
.et-shop-split-warning { margin-top: 10px; }
.et-shop-summary-line {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 14px;
    color: var(--et-color-ink);
}
.et-shop-summary-line + .et-shop-summary-line { margin-top: 8px; }
/* D20: a voucher line's terms (validity, how to redeem) under the line. */
.et-shop-voucher-terms { margin-top: 4px; font-size: 13px; line-height: 1.5; color: var(--et-color-ink-2); white-space: pre-line; }
.et-shop-voucher-terms + .et-shop-summary-line { margin-top: 8px; }
.et-shop-summary-totals { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--et-color-border); }
.et-shop-pay-note { text-align: center; }
/* ShopSellerBlock (D15): who sells, the complaints contact, the withdrawal sentence and notice. */
.et-shop-seller-title { font-size: 16px; font-weight: 800; color: var(--et-color-ink); }
.et-shop-seller-snapshot { margin-top: 2px; font-size: 12px; color: var(--et-color-ink-3); }
.et-shop-seller-lead { margin-top: 10px; font-size: 14px; line-height: 1.5; color: var(--et-color-ink-2); }
.et-shop-seller-facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    /* No row gap: the line height spaces the rows, so a value that wraps keeps the same
       distance between its own lines as between two rows. */
    gap: 0 12px;
    margin: 10px 0 0;
    font-size: 13px;
    line-height: 1.7;
}
.et-shop-order-facts { margin-top: 0; }
.et-shop-split .et-toggle-row { padding: 0; }
/* A shop page's first label sits 20px under the hero: padding, not margin, which would collapse into the hero's 16px. */
.et-shop-checkout > .et-shop-section-label:first-child { padding-top: 2px; }
.et-shop-order > .et-shop-section-label:first-child { padding-top: 4px; }
.et-shop-seller-facts dt { color: var(--et-color-ink-3); }
.et-shop-seller-facts dd { margin: 0; color: var(--et-color-ink); overflow-wrap: anywhere; }
.et-shop-seller-withdrawal { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--et-color-border); }
.et-shop-seller-subtitle { font-size: 13px; font-weight: 700; color: var(--et-color-ink); }
.et-shop-seller-text { margin-top: 4px; font-size: 13px; line-height: 1.5; color: var(--et-color-ink-2); }
.et-shop-seller-notice {
    margin-top: 8px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--et-color-ink-2);
    white-space: pre-line;
    overflow-wrap: anywhere;
}
.et-shop-seller-link { display: inline-block; margin-top: 8px; font-size: 13px; font-weight: 600; color: var(--et-color-ink); }
/* Order detail and my orders. */
/* The split hero stacks below 768px and would stretch the pill across the page. */
.et-shop-order-status { flex-shrink: 0; align-self: flex-start; }
.et-shop-order-pending { margin-bottom: 20px; }
.et-shop-order-cancel { font-size: 13px; color: var(--et-color-ink-2); }
.et-shop-expense-link { display: flex; }
.et-shop-order-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    color: var(--et-color-ink);
    text-decoration: none;
}
.et-shop-order-row + .et-shop-order-row { box-shadow: inset 0 1px 0 var(--et-color-border); }
.et-shop-order-row:hover { color: var(--et-color-ink); background: var(--et-color-surface-2); }
.et-shop-order-row-main { min-width: 0; }
.et-shop-order-row-name { font-size: 14px; font-weight: 700; }
.et-shop-order-row-meta { margin-top: 2px; font-size: 12px; color: var(--et-color-ink-3); }
.et-shop-order-row-side { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.et-shop-order-row-total { font-size: 14px; font-weight: 800; }
.et-shop-more { display: flex; justify-content: center; }
/* UI-3: "Vásárlásaim" rows like a webshop's — the event above, what in bold, from whom and when
   below; and the order detail's event card. */
.et-shop-order-row-event,
.et-shop-order-row-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.et-shop-order-row-event { margin-bottom: 2px; font-size: 12px; font-weight: 700; color: var(--et-color-ink-2); }
.et-shop-order-event { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.et-shop-order-event-name { min-width: 0; font-size: 15px; font-weight: 700; color: var(--et-color-ink); }
.et-shop-order-event-group { flex-shrink: 0; font-size: 13px; font-weight: 600; color: var(--et-color-ink-2); text-decoration: none; }
.et-shop-seller-website { color: var(--et-color-ink); font-weight: 600; }
/* marketplace — provider portal (UI-1, docs/superpowers/plans/2026-10-30-marketplace-ui-provider.md).
   The portal pages reuse Profile's column (.et-profile), section labels and actions row; only the
   glue that has no precedent lives here. Global, not scoped: geometry-critical, see CLAUDE.md. */

/* A section's fields: 10px apart, 20px to the next label. A flex column, so the gap cannot
   collapse into a child's margin. */
.et-mp-group {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 20px;
}
/* A short explanation between a section label and its fields. */
.et-mp-hint {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--et-color-ink-3);
    margin: -2px 4px 10px;
}
.et-mp-banner { margin-bottom: 20px; }
/* A rejection's reason: the operator's own words, on their own line under the sentence. */
.et-mp-reason {
    margin-top: 6px;
    padding-left: 10px;
    border-left: 3px solid var(--et-color-border);
    color: var(--et-color-ink-2);
    white-space: pre-line;
}

/* MarketplaceTextArea: EtFieldRow's card around a textarea. Doubled with .et-field-card: ds.css
   loads after app.css and its own align-items:center would win the tie. */
.et-field-card.et-mp-textarea-card {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
}
.et-mp-textarea-input {
    width: 100%;
    border: 0;
    background: none;
    padding: 0;
    resize: vertical;
    min-height: 44px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--et-color-ink);
    outline: none;
}
.et-mp-textarea-input::placeholder {
    color: var(--et-color-ink-3);
    font-weight: 500;
}

/* The portal's "← Vissza" stays in the phone shell: shell.css hides .et-page-back there because
   on the Activity / Groups roots the tab is the way back, but a portal page is no tab root. */
html.et-shell-bar .et-page-back.et-mp-back { display: inline-flex; }

/* ProviderPortalFrame: the three tabs under the hero. */
.et-mp-tabs { margin-bottom: 20px; }

/* A dashboard card: title + pill on one line, a sentence under it, the buttons last. */
.et-mp-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.et-mp-card-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--et-color-ink);
    min-width: 0;
}
.et-mp-card-text {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--et-color-ink-2);
    margin-top: 8px;
}
.et-mp-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;
}

/* MarketplaceImagePicker: a square slot is a 64px tile beside its label and buttons; the cover
   is a full-width 3:1 frame above them. */
.et-mp-images {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.et-mp-image {
    display: flex;
    align-items: center;
    gap: 14px;
}
.et-mp-image--cover {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
}
.et-mp-image-frame {
    position: relative;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: var(--et-color-surface-2);
    border: 1px solid var(--et-color-border);
}
.et-mp-image--square .et-mp-image-frame {
    width: 64px;
    height: 64px;
    border-radius: 14px;
}
.et-mp-image--cover .et-mp-image-frame {
    width: 100%;
    aspect-ratio: 3 / 1;
    border-radius: 14px;
}
.et-mp-image-frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.et-mp-image-empty {
    font-size: 22px;
    line-height: 1;
    opacity: 0.55;
}
.et-mp-image-spinner {
    position: absolute;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid var(--et-color-border);
    border-top-color: var(--et-color-accent);
    animation: et-profile-avatar-spin .8s linear infinite;
}
.et-mp-image-body {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex: 1;
    min-width: 0;
    flex-wrap: wrap;
}
.et-mp-image-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
}
.et-mp-image-actions {
    display: flex;
    gap: 8px;
}
.et-mp-hint--flush { margin: 0 4px; }
.et-mp-card-text--lead { margin-top: 0; }

/* Products: one card per group — its head, its product rows, its "new product" foot. */
.et-mp-catalog-group { overflow: hidden; }
.et-mp-catalog-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--et-color-border);
}
.et-mp-catalog-head-text { min-width: 0; }
.et-mp-catalog-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}
.et-mp-tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--et-color-surface-2);
    color: var(--et-color-ink-2);
    font-size: 11.5px;
    font-weight: 600;
}
.et-mp-tag--muted { color: var(--et-color-ink-3); }
.et-mp-product {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 10px 16px;
    border: 0;
    border-bottom: 1px solid var(--et-color-border);
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.et-mp-product:hover { background: var(--et-color-surface-2); }
.et-mp-product--hidden .et-mp-product-thumb,
.et-mp-product--hidden .et-mp-product-name { opacity: 0.55; }
.et-mp-product-thumb {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    overflow: hidden;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--et-color-surface-2);
    font-size: 18px;
}
.et-mp-product-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.et-mp-product-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}
.et-mp-product-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-mp-product-price {
    font-size: 13px;
    color: var(--et-color-ink-2);
    margin-top: 2px;
}
.et-mp-product-hidden { color: var(--et-color-ink-3); }
.et-mp-product-chevron {
    color: var(--et-color-ink-3);
    font-size: 18px;
    flex-shrink: 0;
}
/* D24: a tracked product's count under its row, lined up with its name: −/+ and the open
   checkouts. A sibling of the row's button (a button holds no buttons), so the row gives its rule
   to this strip. */
.et-mp-product--stock { border-bottom: 0; }
.et-mp-product-stock {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    padding: 0 16px 10px 72px;
    border-bottom: 1px solid var(--et-color-border);
    font-size: 12.5px;
    color: var(--et-color-ink-3);
}
.et-mp-product-stock .et-shop-qty-btn { width: 32px; height: 32px; }
.et-mp-product-stock-label { font-weight: 600; color: var(--et-color-ink-2); }
.et-mp-product-sold-out { color: var(--et-color-owe); }
.et-mp-product-sale { color: var(--et-color-accent); }
.et-mp-catalog-empty {
    padding: 14px 16px;
    font-size: 13px;
    color: var(--et-color-ink-3);
    border-bottom: 1px solid var(--et-color-border);
}
.et-mp-catalog-foot { padding: 12px 16px; }
.et-mp-catalog-new { justify-content: flex-start; }

/* The inline editor that takes a group's head or a product's row. */
.et-mp-editor {
    padding: 16px;
    border-bottom: 1px solid var(--et-color-border);
    background: var(--et-color-surface-2);
}
.et-mp-editor .et-mp-group { margin-bottom: 12px; }
.et-mp-editor-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* Orders: one row per order — number and buyer, the delivery line, the total. */
.et-mp-orders { overflow: hidden; }
.et-mp-order-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    padding: 12px 16px;
    border: 0;
    border-bottom: 1px solid var(--et-color-border);
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.et-mp-order-row:last-child { border-bottom: 0; }
.et-mp-order-row:hover { background: var(--et-color-surface-2); }
.et-mp-order-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
}
.et-mp-order-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.et-mp-order-sub {
    font-size: 12.5px;
    color: var(--et-color-ink-3);
    margin-top: 2px;
}
.et-mp-order-total {
    font-size: 14px;
    font-weight: 700;
    color: var(--et-color-ink);
    white-space: nowrap;
}

/* Order detail: the status line, then label / value rows. */
.et-mp-order-status {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 20px;
}
.et-mp-order-when {
    font-size: 13px;
    color: var(--et-color-ink-3);
}
.et-mp-kv {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 16px;
    border-bottom: 1px solid var(--et-color-border);
    font-size: 14px;
}
.et-mp-kv:last-child { border-bottom: 0; }
.et-mp-kv-label { color: var(--et-color-ink-2); min-width: 0; }
.et-mp-kv--line .et-mp-kv-label { color: var(--et-color-ink); font-weight: 600; }
.et-mp-kv-qty { color: var(--et-color-ink-3); font-weight: 500; white-space: nowrap; }
/* D20: a voucher line's terms, under its name. */
.et-mp-voucher-terms { display: block; margin-top: 4px; font-size: 13px; font-weight: 400; line-height: 1.5; color: var(--et-color-ink-2); white-space: pre-line; }
.et-mp-kv-value {
    color: var(--et-color-ink);
    font-weight: 600;
    text-align: right;
    overflow-wrap: anywhere;
}
.et-mp-kv-value a { color: inherit; }
.et-mp-kv--total .et-mp-kv-label,
.et-mp-kv--total .et-mp-kv-value { color: var(--et-color-ink); font-weight: 800; }
.et-mp-kv--note .et-mp-kv-value { font-weight: 500; white-space: pre-line; }
.et-mp-order-actions { gap: 8px; }
/* /marketplace — provider portal */
/* marketplace — UI-3: /admin/providers (AdminProviders.razor). Global, like the other admin pages:
   one card per provider, a label/value grid for the DAC7 facts, an input row
   with its button, and the actions at the card's foot. Spacing: 16px inside a card, 12px between
   its blocks, 20px between cards and to a section label. */
.et-admin-providers { max-width: 760px; }
.et-admin-providers-tabs { margin-bottom: 16px; }
.et-admin-providers-empty { font-size: 14px; color: var(--et-color-ink-2); }
.et-admin-provider-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.et-admin-provider-names { min-width: 0; }
.et-admin-provider-name { font-size: 16px; font-weight: 800; color: var(--et-color-ink); overflow-wrap: anywhere; }
.et-admin-provider-owner { margin-top: 2px; font-size: 13px; color: var(--et-color-ink-3); overflow-wrap: anywhere; }
.et-admin-provider-ready { flex-shrink: 0; }
.et-admin-provider-facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 0 12px;
    margin: 12px 0 0;
    font-size: 13px;
    line-height: 1.7;
}
.et-admin-provider-facts dt { color: var(--et-color-ink-3); }
.et-admin-provider-facts dd { margin: 0; color: var(--et-color-ink); overflow-wrap: anywhere; }
.et-admin-provider-notice { white-space: pre-line; }
.et-admin-provider-rejected { margin-top: 12px; font-size: 13px; color: var(--et-color-ink-2); }
.et-admin-provider-commission { display: flex; align-items: flex-end; gap: 10px; margin-top: 12px; }
.et-admin-provider-commission .et-admin-provider-commission-field { flex: 1 1 auto; min-width: 0; }
.et-admin-provider-hint { margin: 6px 4px 0; font-size: 12px; color: var(--et-color-ink-3); }
.et-admin-provider-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 12px; }
/* /marketplace — UI-3 */

/* shop categories (D22; the teaser rules of 2026-11-03-shop-teaser-design.md). Global like the shop
   block: the sheet's button is EventShopButton's; the categories page, the providers page (its rows
   are category rows with a logo) and the operator page carry no scoped CSS. */
.et-shop-category-list { overflow: hidden; }
.et-shop-category-item + .et-shop-category-item,
.et-shop-provider-row + .et-shop-provider-row { border-top: 1px solid var(--et-color-border); }
.et-shop-category-row {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 12px 16px;
    border: 0;
    background: transparent;
    color: var(--et-color-ink);
    font: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}
.et-shop-category-row:hover { background: var(--et-color-surface-2); color: var(--et-color-ink); }
.et-shop-category-row-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.et-shop-category-row-name { font-size: 15px; font-weight: 700; color: var(--et-color-ink); }
.et-shop-category-row-sub { font-size: 12px; color: var(--et-color-ink-3); }
.et-shop-category-row-chevron { flex-shrink: 0; font-size: 18px; line-height: 1; color: var(--et-color-ink-3); }
.et-shop-category-row[aria-expanded="true"] .et-shop-category-row-chevron { transform: rotate(90deg); }
.et-shop-provider-row-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border-radius: 50%;
    object-fit: cover;
    background: var(--et-color-surface-2);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
    font-size: 20px;
    line-height: 1;
}
.et-shop-category-message {
    padding: 0 16px 16px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--et-color-ink-2);
}
.et-shop-category-message p { margin: 0; }
.et-shop-category-message a { color: var(--et-color-accent); font-weight: 700; overflow-wrap: anywhere; }
/* The partner sentence with the ⓘ (ds.css .et-field-info) beside its first line; the ⓘ reveals
   the tap count under it. */
.et-shop-category-message-text { display: flex; align-items: flex-start; gap: 10px; }
.et-shop-category-message-text p { flex: 1 1 auto; min-width: 0; }
/* ds.css pulls the disc 4px above the box top; 5px here centres it on the 21.7px first line. */
.et-shop-category-message-text .et-field-info { margin-top: -5px; }
.et-shop-category-message .et-shop-category-count { margin-top: 8px; font-weight: 700; color: var(--et-color-ink); }
/* The operator's page (/admin/shop-categories): the provider page's card vocabulary. */
.et-admin-category-lede { margin: 0 4px 12px; }
.et-admin-category-defaults { display: flex; justify-content: flex-start; margin: 0 0 16px; }
.et-admin-category-fields { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.et-admin-category-card--new .et-admin-category-fields { margin-top: 0; }
.et-admin-category-preview { margin-top: -4px; }
.et-admin-category-sort { max-width: 160px; }
.et-admin-category-taps { flex-shrink: 0; }
/* The "Eseménynevek" tab: the filter card, the filters, then the names no filter reaches — one
   card each, a row per filter or name, 12px 16px like the category rows. */
/* The names' search field; a search's summary is the label of the list under it. */
.et-admin-event-search { margin-bottom: 20px; }
.et-admin-event-summary { margin: 0 4px 10px; font-size: 13px; color: var(--et-color-ink-2); }
.et-admin-event-names { overflow: hidden; }
.et-admin-event-name,
.et-admin-filter { padding: 12px 16px; }
.et-admin-event-name + .et-admin-event-name,
.et-admin-filter + .et-admin-filter { border-top: 1px solid var(--et-color-border); }
.et-admin-event-name-title,
.et-admin-filter-title { font-size: 15px; font-weight: 700; color: var(--et-color-ink); overflow-wrap: anywhere; }
/* A filter's categories as pills under its facts. */
.et-admin-filter-categories { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* The category multi-select inside the dropdown: a check row per category, Mégse/Mentés under them. */
.et-admin-filter-picker { display: flex; flex-direction: column; gap: 10px; padding: 10px 6px 4px; }
.et-admin-filter-picker .et-admin-provider-actions { margin-top: 2px; }
/* /shop categories */

/* EnvironmentBadge — staging's "TESZT" marker (spec 2026-11-07-staging-environment-design.md D14):
   a 2px line along the top edge with a tab hanging from its middle, above everything but the
   boot-error bar (#blazor-error-ui, 1300) and the toasts (1600), and it takes no clicks. One fixed
   orange in every theme on purpose: it marks the deployment, not the palette. Production never
   renders the element. */
.et-env-badge {
    position: fixed;
    top: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
    left: 0;
    right: 0;
    z-index: 1290;
    display: flex;
    justify-content: center;
    border-top: 2px solid #C2410C;
    pointer-events: none;
}
.et-env-badge span {
    padding: 0 10px 2px;
    border-radius: 0 0 6px 6px;
    background: #C2410C;
    color: #FFFFFF;
    font-family: var(--et-font-sans);
    font-size: 10px;
    font-weight: 800;
    line-height: 14px;
    letter-spacing: 0.08em;
}
