/* =============================================================
   dryl-erweitert.css — isolierte Komponenten-Styles (.razor.css)
   aus dem Upstream, unverändert zusammengeführt. Nötig, weil
   diese Styles NICHT in dryl.css stecken (Blazor CSS-Isolation).
   Je Komponente ein Block; Quelle steht im Block-Kommentar.
   ============================================================= */

/* ── DrylDivider (Quelle: Components/Layout/DrylDivider.razor.css) ── */
/* Labelled horizontal divider: line — text — line.
   The plain .divider / .divider-v primitives live in dryl.css. */
.divider-labelled {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: 100%;
}

.divider-labelled-line {
    flex: 1 1 0;
    height: 1px;
    background: var(--line);
}

.divider-labelled-text {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--fg-dim);
    white-space: nowrap;
}

/* ── DrylInputPassword (Quelle: Components/Inputs/DrylInputPassword.razor.css) ── */
.pwd-toggle {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-content: center;
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    color: var(--fg-dim);
    cursor: pointer;
    padding: 0;
    border-radius: var(--r-xs);
    transition: color var(--dur-fast) var(--ease-out),
                background var(--dur-fast) var(--ease-out);
}

.pwd-toggle:hover {
    color: var(--fg);
    background: var(--glass-2);
}

.pwd-toggle:focus-visible {
    outline: 2px solid rgba(124, 92, 255, 0.5);
    outline-offset: 1px;
}

.pwd-toggle:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ── DrylKbd (Quelle: Components/Data/DrylKbd.razor.css) ── */
/* Keyboard-shortcut chips. */

.kbd-group {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
}

.kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 var(--sp-1);
    font-family: var(--font-mono);
    font-size: 11px;
    line-height: 1;
    color: var(--fg-muted);
    background: var(--glass-2);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-xs);
    box-shadow: 0 1px 0 var(--line-strong);
}

.kbd-sep {
    color: var(--fg-dim);
    font-size: 11px;
    line-height: 1;
}

/* ── DrylSkeleton (Quelle: Components/Feedback/DrylSkeleton.razor.css) ── */
/* ── DrylSkeleton ─────────────────────────────────────────────
   Extends the global .skel shimmer primitive from dryl.css with:
   • Size-token system (sz-sm / sz-md / sz-lg) via CSS custom props
   • Variant-specific shapes and layouts
   • AI-state shimmer mutations:
       Thinking  → faster shimmer (urgent computing feel)
       Streaming → violet-cyan gradient (AI writing content)
       Generated → fade to transparent (reveal real content)
   ──────────────────────────────────────────────────────────── */

/* ─── Host wrapper ──────────────────────────────────────────── */
.skel-wrap {
    display:        flex;
    flex-direction: column;
    gap:            var(--sp-2);
    width:          100%;
    min-width:      0;
}

/* ─── Size tokens — cascade to children via custom properties ─ */
.skel-wrap.sz-sm {
    --sk-line-h:        10px;
    --sk-circle-d:      32px;
    --sk-rect-h:        80px;
    --sk-header-avatar: 28px;
}
.skel-wrap.sz-md {
    --sk-line-h:        14px;
    --sk-circle-d:      48px;
    --sk-rect-h:       120px;
    --sk-header-avatar: 36px;
}
.skel-wrap.sz-lg {
    --sk-line-h:        18px;
    --sk-circle-d:      64px;
    --sk-rect-h:       160px;
    --sk-header-avatar: 44px;
}

/* Size-responsive blocks */
.skel-wrap .skel        { height: var(--sk-line-h,   14px);  }
.skel-wrap .skel-circle { height: var(--sk-circle-d, 48px); width: var(--sk-circle-d, 48px); }
.skel-wrap .skel-rect   { height: var(--sk-rect-h,  120px); }

/* ─── Variant border-radius on wrapper (AI ring traces this) ─ */
.skel-wrap.v-avatar {
    width:           var(--sk-circle-d, 48px);
    height:          var(--sk-circle-d, 48px);
    border-radius:   50%;
    display:         inline-flex;
    flex-direction:  row;
    align-items:     center;
    justify-content: center;
    flex-shrink:     0;
}

.skel-wrap.v-card  { border-radius: var(--r-lg); }
.skel-wrap.v-image { border-radius: var(--r-md); }

/* ─── Shapes ────────────────────────────────────────────────── */
.skel-circle {
    border-radius: 50%;
    flex-shrink:   0;
}

.skel-rect {
    border-radius: var(--r-md);
    width:         100%;
    display:       block;
}

/* Card-header avatar — smaller than the standalone Avatar variant */
.skel-card-avatar {
    border-radius: 50%;
    width:         var(--sk-header-avatar, 36px);
    height:        var(--sk-header-avatar, 36px);
    flex-shrink:   0;
}

/* ─── Composite layouts ─────────────────────────────────────── */
.skel-text-block {
    display:        flex;
    flex-direction: column;
    gap:            var(--sp-2);
    width:          100%;
}

.skel-card-layout {
    display:        flex;
    flex-direction: column;
    gap:            var(--sp-3);
    width:          100%;
}

.skel-card-header {
    display:     flex;
    align-items: center;
    gap:         var(--sp-3);
}

.skel-card-header-text {
    display:        flex;
    flex-direction: column;
    gap:            var(--sp-2);
    flex:           1 1 auto;
    min-width:      0;
}

/* ─── Shimmer stagger — lines shimmer at offset phases ────────
   The shimmer lives on the .skel::before strip (transform-driven,
   compositor-friendly — see the primitive in dryl.css), so every
   duration/delay/gradient mutation targets the pseudo, not the host. */
.skel-text-block     .skel:nth-child(2)::before { animation-delay: 0.12s; }
.skel-text-block     .skel:nth-child(3)::before { animation-delay: 0.24s; }
.skel-text-block     .skel:nth-child(4)::before { animation-delay: 0.36s; }
.skel-text-block     .skel:nth-child(5)::before { animation-delay: 0.48s; }
.skel-text-block     .skel:nth-child(6)::before { animation-delay: 0.60s; }
.skel-card-header-text .skel:nth-child(2)::before { animation-delay: 0.10s; }

/* ─── AI state: Thinking — faster shimmer ──────────────────── */
.skel-wrap.ai-aura.ai-thinking .skel::before {
    animation-duration: 0.8s;
}

/* ─── AI state: Streaming — violet-cyan shimmer ─────────────
   The gradient shifts from neutral white to accent violet→cyan,
   communicating that AI content is actively flowing into these
   placeholder blocks. Uses --accent-a / --accent-b values only
   (no new colors invented, per CLAUDE.md §2.10 and §2.1).
   Host gets the gradient's edge tint as base; the sliding strip
   carries the gradient (40% tile = the primitive's 200%-of-host
   geometry on the 500%-wide strip).
   ─────────────────────────────────────────────────────────── */
.skel-wrap.ai-aura.ai-streaming .skel {
    background: rgba(124, 92, 255, 0.06);
}
.skel-wrap.ai-aura.ai-streaming .skel::before {
    background: linear-gradient(
        90deg,
        rgba(124, 92, 255, 0.06) 0%,
        rgba(34, 211, 238, 0.18) 50%,
        rgba(124, 92, 255, 0.06) 100%
    );
    background-size: 40% 100%;
    animation-duration: 1.2s;
}

/* ─── AI state: Generated — fade blocks to reveal real content ─ */
.skel-wrap.ai-aura.ai-generated .skel {
    animation: skel-block-out var(--dur-slow) var(--ease-out) both;
}

@keyframes skel-block-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* ─── Reduced motion ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    .skel-wrap.ai-aura.ai-thinking .skel::before  { animation-duration: 1.4s; }
    .skel-wrap.ai-aura.ai-streaming .skel::before { animation-duration: 1.4s; }
    .skel-wrap.ai-aura.ai-generated .skel { animation: none; opacity: 0.25; }
    .skel-text-block     .skel::before,
    .skel-card-header-text .skel::before          { animation-delay: 0s; }
}

/* ── DrylSpinner (Quelle: Components/Feedback/DrylSpinner.razor.css) ── */
/* ── DrylSpinner ─────────────────────────────────────────────
   All dimensions reference tokens defined on the wrapper so they
   cascade to every child without repeating the size values.
   Continuous animation durations are NOT --dur-* (those are for
   interaction transitions). Looping spinner durations are defined
   here as intentional motion-design values.
   ──────────────────────────────────────────────────────────── */

.spinner-wrap {
    /* Size tokens — overridden per size modifier */
    --sz:      var(--sp-5);  /* Medium = 24 px */
    --track-w: 2px;

    display:         inline-flex;
    align-items:     center;
    justify-content: center;
    position:        relative;
    flex-shrink:     0;
    width:           var(--sz);
    height:          var(--sz);
    border-radius:   50%;
}

.spinner-wrap.sz-sm { --sz: var(--sp-4); --track-w: 1.5px; } /* 16 px */
.spinner-wrap.sz-lg { --sz: var(--sp-6); --track-w: 3px;   } /* 32 px */

/* Dots need a wider, pill-shaped container so the AI ring wraps a capsule */
.spinner-wrap.v-dots {
    width:         auto;
    padding-inline: calc(var(--sz) * 0.25);
    border-radius: var(--r-pill);
}


/* ── Ring variant ─────────────────────────────────────────── */

.spinner-ring {
    width:         100%;
    height:        100%;
    border-radius: 50%;
    /* Gradient arc: bright cyan tip → violet body → transparent tail */
    background: conic-gradient(
        from 0deg,
        var(--accent-b)  0%,
        var(--accent-a) 50%,
        transparent     75%,
        transparent    100%
    );
    /* Mask punches out the centre, leaving only the track */
    mask:         radial-gradient(farthest-side, transparent calc(100% - var(--track-w)), #fff calc(100% - var(--track-w) + 1px));
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--track-w)), #fff calc(100% - var(--track-w) + 1px));
    animation: dryl-spin 0.9s linear infinite;
}

@keyframes dryl-spin { to { transform: rotate(360deg); } }

/* Ring responds to AI state: slow breathing on Thinking, sprint on Streaming */
.ai-aura.ai-active    .spinner-ring { animation-duration: 1.4s; }
.ai-aura.ai-thinking  .spinner-ring { animation-duration: 2s; }
.ai-aura.ai-streaming .spinner-ring { animation-duration: 0.6s; }
.ai-aura.ai-generated .spinner-ring { animation: none; opacity: 0.55; }


/* ── Dots variant ─────────────────────────────────────────── */

.spinner-dots {
    display:         flex;
    gap:             var(--sp-1);
    align-items:     center;
    justify-content: center;
}

.spinner-dot {
    width:         calc(var(--sz) * 0.28);
    height:        calc(var(--sz) * 0.28);
    border-radius: 50%;
    animation:     dryl-dot-pulse 1.5s var(--ease-in-out) infinite;
}

.spinner-dot:nth-child(1) { background: var(--accent-a); animation-delay: 0s;     }
.spinner-dot:nth-child(2) { background: var(--accent-b); animation-delay: 0.24s;  }
.spinner-dot:nth-child(3) { background: var(--accent-a); animation-delay: 0.48s;  }

@keyframes dryl-dot-pulse {
    0%, 100% { transform: scale(0.5);  opacity: 0.35; }
    45%      { transform: scale(1);    opacity: 1;    }
}

.ai-aura.ai-active    .spinner-dot { animation-duration: 2s;   }
.ai-aura.ai-thinking  .spinner-dot { animation-duration: 2.6s; }
.ai-aura.ai-streaming .spinner-dot { animation-duration: 0.85s; }
.ai-aura.ai-generated .spinner-dot { animation: none; transform: scale(1); opacity: 1; }


/* ── Pulse variant ─────────────────────────────────────────── */

.spinner-pulse {
    position: relative;
    width:    100%;
    height:   100%;
}

.spinner-pulse-ring {
    position:      absolute;
    inset:         0;
    border-radius: 50%;
    border:        1px solid;
    opacity:       0;
    animation:     dryl-pulse-ring 2.2s var(--ease-out) infinite;
}

.spinner-pulse-ring:nth-child(1) { border-color: var(--accent-a); animation-delay: 0s;    }
.spinner-pulse-ring:nth-child(2) { border-color: var(--accent-b); animation-delay: 0.75s; }

.spinner-pulse-core {
    position:      absolute;
    top:           50%;
    left:          50%;
    width:         30%;
    height:        30%;
    border-radius: 50%;
    background:    var(--accent-grad);
    box-shadow:    0 0 6px var(--accent-soft), 0 0 14px rgba(124, 92, 255, 0.45);
    transform:     translate(-50%, -50%);
    animation:     dryl-pulse-core 2.2s var(--ease-in-out) infinite;
}

@keyframes dryl-pulse-ring {
    0%   { transform: scale(0.2); opacity: 0.9; }
    100% { transform: scale(1);   opacity: 0;   }
}

@keyframes dryl-pulse-core {
    0%, 100% { opacity: 0.6; }
    50%      { opacity: 1;   }
}

.ai-aura.ai-active    .spinner-pulse-ring  { animation-duration: 3s; }
.ai-aura.ai-active    .spinner-pulse-core  { box-shadow: var(--glow-accent); animation-duration: 3s; }
.ai-aura.ai-thinking  .spinner-pulse-ring  { animation-duration: 3.6s; border-width: 1.5px; }
.ai-aura.ai-thinking  .spinner-pulse-core  { box-shadow: var(--glow-accent); animation-duration: 1.4s; }
.ai-aura.ai-streaming .spinner-pulse-ring  { animation-duration: 1.3s; }
.ai-aura.ai-streaming .spinner-pulse-core  { animation-duration: 0.9s; }
.ai-aura.ai-generated .spinner-pulse-ring  { animation: none; opacity: 0; }
.ai-aura.ai-generated .spinner-pulse-core  { animation: none; opacity: 1; box-shadow: var(--glow-accent); transform: translate(-50%, -50%) scale(1); }


/* ── Reduced motion ──────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .spinner-ring,
    .spinner-dot,
    .spinner-pulse-ring,
    .spinner-pulse-core { animation: none; }

    .spinner-ring                    { opacity: 0.7; }
    .spinner-dot                     { opacity: 0.7; transform: scale(1); }
    .spinner-pulse-ring:nth-child(1) { opacity: 0.45; transform: scale(0.75); }
    .spinner-pulse-core              { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* ── DrylStat (Quelle: Components/Data/DrylStat.razor.css) ── */
.stat {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    min-height: 132px;
}

.stat-head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.stat-icon {
    display: inline-flex;
    color: var(--accent-a);
}

.stat-label {
    font-size: 12px;
    color: var(--fg-muted);
}

.stat-value-row {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

.stat-value {
    font-size: 32px;
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1;
    color: var(--fg);
}

.stat-delta {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-family: var(--font-mono);
    font-size: 11px;
}

.stat-delta--up { color: var(--success); }
.stat-delta--down { color: var(--danger); }
.stat-delta--neutral { color: var(--fg-dim); }

.stat-spark {
    margin-top: auto;
}

/* ── DrylTypo (Quelle: Components/Layout/DrylTypo.razor.css) ── */
/* Type steps mirror the element scale in dryl.css (TYPE section) so the
   look rides a class and stays independent of the rendered tag.
   Colours use --fg* tokens; only the size scale carries px literals,
   matching how dryl.css declares h1–h4. */
.typo { margin: 0; }

.typo-h1 { font-size: 56px; line-height: 1.05; letter-spacing: -0.035em; font-weight: 700; color: var(--fg); }
.typo-h2 { font-size: 32px; line-height: 1.15; letter-spacing: -0.025em; font-weight: 600; color: var(--fg); }
.typo-h3 { font-size: 20px; line-height: 1.3;  letter-spacing: -0.02em;  font-weight: 600; color: var(--fg); }
.typo-h4 { font-size: 15px; line-height: 1.4;  letter-spacing: -0.02em;  font-weight: 600; color: var(--fg); }

.typo-lead { font-size: 17px; line-height: 1.55; color: var(--fg-muted); max-width: 64ch; }
.typo-body { font-size: 14px; line-height: 1.5;  color: var(--fg-muted); }
.typo-caption { font-size: 12px; line-height: 1.4; color: var(--fg-dim); }

.typo-eyebrow {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--fg-dim);
    font-weight: 500;
}

/* ── DrylAspectRatio (Quelle: Components/Layout/DrylAspectRatio.razor.css; Blazor-::deep zu Nachfahren-Selektoren umgeschrieben) ── */
/* Grid/flex parents default to "stretch", which forces the box to the row's/line's
   content height and silently overrides the aspect-ratio above. Opting out of stretch
   lets the browser size the box purely from aspect-ratio + the (stretched) width. */
.aspect {
    align-self: start;
}

/* Any direct child fills the ratio box edge to edge. */
.aspect > * {
    width: 100%;
    height: 100%;
    display: block;
}

/* Media elements additionally crop to cover instead of stretching/distorting. */
.aspect > img,
.aspect > video,
.aspect > iframe {
    object-fit: cover;
    border: 0;
}

/* ── DrylChipInput (Quelle: Components/Inputs/DrylChipInput.razor.css) ── */
.chip-input-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-3);
    min-height: 42px;
    width: 100%;
    background: var(--glass-1);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    cursor: text;
    box-sizing: border-box;
    transition: border-color var(--dur-med) var(--ease-out),
                background var(--dur-med) var(--ease-out),
                box-shadow var(--dur-med) var(--ease-out);
}

.chip-input-inner:hover:not(.chip-input-inner--disabled) {
    border-color: var(--line-hover);
}

.chip-input-inner:focus-within:not(.chip-input-inner--disabled) {
    border-color: var(--accent-line);
    background: var(--glass-2);
    box-shadow: 0 0 0 1px var(--accent-line),
                0 0 0 4px rgba(124, 92, 255, 0.12),
                0 0 24px rgba(124, 92, 255, 0.18);
}

.chip-input-inner--error {
    border-color: var(--danger);
}

.chip-input-inner--error:focus-within {
    border-color: var(--danger);
    box-shadow: 0 0 0 4px rgba(248, 113, 113, 0.12);
}

.chip-input-inner--success {
    border-color: var(--success);
}

.chip-input-inner--success:focus-within {
    border-color: var(--success);
    box-shadow: 0 0 0 4px rgba(52, 211, 153, 0.12);
}

.chip-input-inner--disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.chip-input-field {
    flex: 1;
    min-width: 100px;
    height: 24px;
    padding: 0;
    margin: 0;
    background: transparent;
    border: none;
    color: var(--fg);
    font: 400 13px/1 var(--font-sans);
    outline: none;
    caret-color: var(--accent-a);
}

.chip-input-field::placeholder {
    color: var(--fg-dim);
}

.chip-input-field:disabled {
    cursor: not-allowed;
}

/* ── DrylCodeBlock (Quelle: Components/Data/DrylCodeBlock.razor.css; Blazor-::deep zu Nachfahren-Selektoren umgeschrieben) ── */
/* DrylCodeBlock — glass code surface with language label + copy. */

.code-block {
    position: relative;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--glass-1);
    overflow: hidden;
}

.code-block-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
    border-bottom: 1px solid var(--line);
    background: var(--glass-2);
}

.code-block-lang {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--fg-dim);
}

.code-block-body {
    display: flex;
    align-items: stretch;
    overflow-x: auto;
}

.code-block-gutter {
    margin: 0;
    padding: var(--sp-3) var(--sp-2) var(--sp-3) var(--sp-3);
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.55;
    text-align: right;
    color: var(--fg-faint);
    user-select: none;
    border-right: 1px solid var(--line);
    white-space: pre;
}

.code-block-pre {
    margin: 0;
    padding: var(--sp-3) var(--sp-4);
    flex: 1 1 auto;
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--fg);
    white-space: pre;
    overflow-x: auto;
}

.code-block-pre code {
    font-family: inherit;
    background: none;
    padding: 0;
    color: inherit;
}

/* Syntax tokens — mapped onto the existing DRYL palette, no invented colors. */
.code-block-pre .tok-keyword { color: var(--accent-a); }
.code-block-pre .tok-type    { color: var(--accent-b); }
.code-block-pre .tok-string  { color: var(--success); }
.code-block-pre .tok-number  { color: var(--warning); }
.code-block-pre .tok-comment { color: var(--fg-faint); font-style: italic; }
.code-block-pre .tok-punct   { color: var(--fg-muted); }

/* ── DrylDescriptionItem (Quelle: Components/Data/DrylDescriptionItem.razor.css) ── */
.desc-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.desc-item--inline {
    flex-direction: row;
    align-items: baseline;
    gap: var(--sp-3);
}

.desc-term {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    font-size: 12px;
    color: var(--fg-muted);
}

.desc-item--inline .desc-term {
    flex: none;
    min-width: 120px;
}

.desc-value {
    margin: 0;
    font-size: 14px;
    color: var(--fg);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* ── DrylDescriptionList (Quelle: Components/Data/DrylDescriptionList.razor.css) ── */
.cq { container-type: inline-size; }

.desc-list {
    display: grid;
    grid-template-columns: repeat(var(--desc-cols, 1), minmax(0, 1fr));
    gap: var(--sp-4) var(--sp-6);
    margin: 0;
}

/* Multi-column lists collapse to a single column once their slot gets
   narrow (phone, or a tight column on desktop) so values never squeeze. */
@container (max-width: 480px) {
    .desc-list { grid-template-columns: 1fr; }
}

/* ── DrylEmptyState (Quelle: Components/Feedback/DrylEmptyState.razor.css) ── */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--sp-3);
    padding: var(--sp-7) var(--sp-5);
    color: var(--fg-muted);
}

.empty-state--sm {
    padding: var(--sp-5) var(--sp-4);
    gap: var(--sp-2);
}

/* AI mode: frame the placeholder as a glass surface so the rotating
   gradient ring (.ai-aura-ring inherits border-radius) has a host to wrap. */
.empty-state.ai-aura {
    border-radius: var(--r-lg);
    background: var(--glass-1);
    border: 1px solid var(--line);
}

.empty-icon {
    display: inline-grid;
    place-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--glass-2);
    border: 1px solid var(--line);
    color: var(--fg-dim);
}

.empty-state--sm .empty-icon {
    width: 40px;
    height: 40px;
}

.empty-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--fg);
}

.empty-state--sm .empty-title {
    font-size: 14px;
}

.empty-description {
    font-size: 13px;
    color: var(--fg-dim);
    max-width: 42ch;
    line-height: 1.5;
}

.empty-actions {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-2);
    flex-wrap: wrap;
    justify-content: center;
}

/* ── DrylFormField (Quelle: Components/Inputs/DrylFormField.razor.css) ── */
.field-required {
    margin-left: 2px;
    color: var(--accent-a);
}

/* ── DrylImage (Quelle: Components/Data/DrylImage.razor.css; Blazor-::deep zu Nachfahren-Selektoren umgeschrieben) ── */
/* ── DrylImage ─────────────────────────────────────────────────
   A responsive image frame. Two layout modes:
     • --ratio   : the frame owns an aspect-ratio; the image fills it
                   absolutely (object-fit) — no layout shift.
     • --natural : the frame wraps the image's intrinsic height; while
                   loading, the skeleton defines the box and the image
                   sits behind it until it loads.
   AI inner effects build only on tokens + the shared .ai-aura* family.
   No overflow:hidden — children round to the frame so the .ai-aura-glow
   can still breathe outside the box. */

.img-wrap {
    position: relative;
    display: block;
    width: 100%;
    background: var(--glass-1);
}

/* Keep the rotating ring flush inside the frame (it isn't clipped). */
.img-wrap .ai-aura-ring { inset: 0; }

/* ─── Rounding (children inherit) ───────────────────────────── */
.img-wrap--r-none { border-radius: 0; }
.img-wrap--r-sm   { border-radius: var(--r-sm); }
.img-wrap--r-md   { border-radius: var(--r-md); }
.img-wrap--r-lg   { border-radius: var(--r-lg); }
.img-wrap--r-full { border-radius: var(--r-pill); }

.img-wrap--border { border: 1px solid var(--line); }
.img-wrap--shadow { box-shadow: var(--shadow-sm); }

/* ─── The image ─────────────────────────────────────────────── */
.img-el {
    display: block;
    width: 100%;
    border-radius: inherit;
    background: var(--glass-1);
    opacity: 0;
    transition: opacity var(--dur-med) var(--ease-out);
}
.img-el.is-loaded { opacity: 1; }

/* Ratio mode — frame has aspect-ratio (set inline); image fills it. */
.img-wrap--ratio .img-el {
    position: absolute;
    inset: 0;
    height: 100%;
}

/* Natural mode — image flows once loaded; before that it sits behind
   the in-flow skeleton so it contributes no extra height. */
.img-wrap--natural .img-el { height: auto; }
.img-wrap--natural .img-el:not(.is-loaded) {
    position: absolute;
    inset: 0;
    height: 100%;
}

/* ─── Skeleton overlay ──────────────────────────────────────── */
.img-skel { z-index: 2; border-radius: inherit; }
.img-wrap--ratio .img-skel { position: absolute; inset: 0; }
.img-wrap--ratio .img-skel .skel-wrap,
.img-wrap--ratio .img-skel .skel-rect { height: 100%; }
.img-wrap--natural .img-skel { position: static; }

/* ─── Error fallback ────────────────────────────────────────── */
.img-fallback {
    z-index: 2;
    border-radius: inherit;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-6);
    min-height: 120px;
    background: var(--glass-1);
    border: 1px dashed var(--line-strong);
    color: var(--fg-dim);
    text-align: center;
}
.img-wrap--ratio .img-fallback { position: absolute; inset: 0; }
.img-fallback-text { font-size: 12.5px; color: var(--fg-muted); }

/* ─── AI · Thinking — drifting violet→cyan cloud over the image ─ */
.img--thinking::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: 2;
    background:
        radial-gradient(60% 60% at 30% 30%, var(--accent-soft), transparent 70%),
        radial-gradient(55% 55% at 75% 68%, rgba(34, 211, 238, 0.20), transparent 70%);
    background-size: 180% 180%, 165% 165%;
    mix-blend-mode: screen;
    animation: img-think 7s var(--ease-in-out) infinite alternate;
}
@keyframes img-think {
    from { background-position: 0% 0%, 100% 100%; opacity: 0.7; }
    to   { background-position: 100% 100%, 0% 0%; opacity: 1; }
}

/* ─── AI · Streaming — sharpen from blur ────────────────────── */
.img-el--stream-auto {
    animation: img-sharpen var(--img-blur-dur, 2000ms) var(--ease-out) forwards;
}
@keyframes img-sharpen {
    from { filter: blur(12px); }
    to   { filter: blur(0); }
}
/* Progress-driven: blur amount is set inline; just ease between values. */
.img-el--stream-progress { transition: filter var(--dur-med) var(--ease-out); }

/* ─── AI · Generated — one-shot scale-in reveal ─────────────── */
.img--generated .img-el {
    animation: img-reveal var(--dur-slow) var(--ease-out) both;
}
@keyframes img-reveal {
    from { opacity: 0; transform: scale(1.03); }
    to   { opacity: 1; transform: scale(1); }
}

/* ─── Reduced motion ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    .img--thinking::after { animation: none; }
    .img-el--stream-auto  { animation: none; filter: none; }
    .img--generated .img-el { animation: none; }
}

/* ── DrylNotifications (Quelle: Components/Feedback/DrylNotifications.razor.css) ── */
/* DrylNotifications — bell trigger + inbox panel. Tokens only. */

/* ── Bell trigger ── */
.notif-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: var(--r-md);
    border: 1px solid var(--line);
    background: var(--glass-1);
    color: var(--fg-muted);
    cursor: pointer;
    transition:
        border-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out),
        background var(--dur-fast) var(--ease-out);
}
.notif-bell:hover {
    border-color: var(--line-strong);
    color: var(--fg);
    background: var(--glass-2);
}
.notif-bell.is-active {
    border-color: var(--accent-line);
    color: var(--fg);
}
.notif-bell:focus-visible {
    outline: none;
    border-color: var(--accent-line);
    box-shadow: 0 0 0 2px var(--accent-soft);
}

.notif-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    color: var(--fg);
    background: var(--accent-grad);
    border-radius: var(--r-pill);
    box-shadow: 0 0 0 2px var(--bg-1);
}

/* ── Panel ── */
.notif-panel {
    width: 340px;
    max-width: 92vw;
}
.notif-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--line);
}
.notif-panel-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--fg);
}
.notif-panel-actions {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
}
.notif-action {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 4px 8px;
    background: transparent;
    border: 0;
    border-radius: var(--r-sm);
    color: var(--fg-dim);
    font-size: 11px;
    cursor: pointer;
    transition:
        color var(--dur-fast) var(--ease-out),
        background var(--dur-fast) var(--ease-out);
}
.notif-action:hover {
    color: var(--fg);
    background: var(--glass-1);
}
.notif-action:focus-visible {
    outline: none;
    color: var(--fg);
    box-shadow: 0 0 0 2px var(--accent-soft);
}

.notif-empty {
    padding: var(--sp-4) var(--sp-3) var(--sp-6);
}

/* ── List + items ── */
.notif-list {
    list-style: none;
    margin: 0;
    padding: var(--sp-2);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}
.notif-item {
    position: relative;
    display: flex;
    align-items: stretch;
    border-radius: var(--r-md);
    transition: background var(--dur-fast) var(--ease-out);
}

/* AI-provenance rows carry the shared aura. Keep the rotating ring and glow INSIDE the
   card's rounded bounds (same treatment as DrylTable / DrylToast) — otherwise the outer
   glow bleeds sideways and the DrylScrollArea's straight edges clip it into a hard,
   square-cornered box around each rounded card. */
.notif-item.ai-aura .ai-aura-ring { inset: 0; }
.notif-item.ai-aura .ai-aura-glow {
    box-shadow:
        inset 0 0 0 1px var(--accent-line),
        inset 0 0 24px rgba(124, 92, 255, 0.16),
        inset 0 0 48px rgba(34, 211, 238, 0.07);
}
.notif-item:hover {
    background: var(--glass-1);
}
.notif-item.is-unread,
.notif-item.is-unread:hover {
    background: var(--accent-soft);
}

.notif-item-main {
    flex: 1 1 auto;
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3);
    min-width: 0;
    background: transparent;
    border: 0;
    border-radius: var(--r-md);
    text-align: left;
    color: inherit;
    cursor: pointer;
}
.notif-item-main:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent-line);
}

.notif-item-icon {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--r-sm);
    background: var(--glass-2);
    border: 1px solid var(--line);
    color: var(--fg-muted);
}
.notif-item-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.notif-item-title {
    font-size: 13px;
    font-weight: 500;
    color: var(--fg);
}
.notif-item-message {
    font-size: 12px;
    color: var(--fg-muted);
    line-height: 1.45;
}
.notif-item-time {
    margin-top: 2px;
    font-size: 11px;
    color: var(--fg-dim);
    font-family: var(--font-mono);
}

.notif-item-dot {
    flex: none;
    align-self: center;
    width: 8px;
    height: 8px;
    border-radius: var(--r-pill);
    background: var(--accent-grad);
    box-shadow: 0 0 6px var(--accent-line);
}

.notif-item-dismiss {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    margin: var(--sp-2) var(--sp-2) var(--sp-2) 0;
    background: transparent;
    border: 0;
    border-radius: var(--r-xs);
    color: var(--fg-dim);
    cursor: pointer;
    opacity: 0;
    transition:
        opacity var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out),
        background var(--dur-fast) var(--ease-out);
}
.notif-item:hover .notif-item-dismiss,
.notif-item-dismiss:focus-visible {
    opacity: 1;
}
.notif-item-dismiss:hover {
    color: var(--fg);
    background: var(--glass-2);
}
.notif-item-dismiss:focus-visible {
    outline: none;
    color: var(--fg);
    box-shadow: 0 0 0 2px var(--accent-soft);
}

/* ── DrylRating (Quelle: Components/Inputs/DrylRating.razor.css) ── */
.rating-wrapper {
    position: relative;
    display: inline-flex;
    border-radius: var(--r-md);
}

.rating-group {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
}

.rating-btn {
    display: inline-grid;
    place-content: center;
    padding: var(--sp-1);
    background: transparent;
    border: none;
    color: var(--fg-dim);
    cursor: pointer;
    border-radius: var(--r-xs);
    transition: color var(--dur-fast) var(--ease-out),
                filter var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-spring);
}

.rating-btn:hover:not(:disabled),
.rating-btn:focus-visible:not(:disabled) {
    color: var(--warning);
    transform: scale(1.15);
}

.rating-btn--filled {
    color: var(--warning);
}

.rating-btn:focus-visible {
    outline: 2px solid var(--accent-line);
    outline-offset: 2px;
}

.rating-btn:disabled {
    cursor: default;
    opacity: 0.55;
}

/* ── AI mode — stars carry the state, no wrapper frame ── */

.rating-wrapper.ai-aura .rating-btn--filled {
    color: var(--accent-a);
    filter: drop-shadow(0 0 5px rgba(124, 92, 255, 0.65));
}

.rating-wrapper.ai-aura .rating-btn:not(.rating-btn--filled) {
    color: rgba(124, 92, 255, 0.28);
}

.rating-wrapper.ai-aura .rating-btn:hover:not(:disabled) {
    color: var(--accent-b);
    filter: drop-shadow(0 0 8px rgba(34, 211, 238, 0.8));
    transform: scale(1.15);
}

/* Thinking — slow breathing glow */
@keyframes rating-star-breathe {
    0%, 100% { filter: drop-shadow(0 0 3px rgba(124, 92, 255, 0.35)); opacity: 0.55; }
    50%       { filter: drop-shadow(0 0 11px rgba(124, 92, 255, 1));   opacity: 1; }
}

.rating-wrapper.ai-thinking .rating-btn--filled {
    animation: rating-star-breathe 2s var(--ease-in-out) infinite;
}

/* Streaming — violet→cyan wave left to right */
@keyframes rating-star-stream {
    0%, 100% { color: var(--accent-a); filter: drop-shadow(0 0 4px rgba(124, 92, 255, 0.6)); }
    50%       { color: var(--accent-b); filter: drop-shadow(0 0 9px  rgba(34,  211, 238, 0.9)); }
}

.rating-wrapper.ai-streaming .rating-btn--filled {
    animation: rating-star-stream 1.8s var(--ease-in-out) infinite;
}

.rating-wrapper.ai-streaming .rating-btn:nth-child(2).rating-btn--filled  { animation-delay: 0.14s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(3).rating-btn--filled  { animation-delay: 0.28s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(4).rating-btn--filled  { animation-delay: 0.42s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(5).rating-btn--filled  { animation-delay: 0.56s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(6).rating-btn--filled  { animation-delay: 0.70s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(7).rating-btn--filled  { animation-delay: 0.84s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(8).rating-btn--filled  { animation-delay: 0.98s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(9).rating-btn--filled  { animation-delay: 1.12s; }
.rating-wrapper.ai-streaming .rating-btn:nth-child(10).rating-btn--filled { animation-delay: 1.26s; }

/* Generated — one-shot flash: white → cyan → violet settle */
@keyframes rating-star-generated {
    0%   { color: var(--knob);    filter: drop-shadow(0 0 18px color-mix(in srgb, var(--knob) 90%, transparent)) drop-shadow(0 0 8px rgba(34,211,238,0.8)); }
    35%  { color: var(--accent-b); filter: drop-shadow(0 0 12px rgba(34,  211, 238, 0.85)); }
    100% { color: var(--accent-a); filter: drop-shadow(0 0 5px  rgba(124, 92,  255, 0.6)); }
}

.rating-wrapper.ai-generated .rating-btn--filled {
    animation: rating-star-generated var(--dur-slow) var(--ease-out) forwards;
}

.rating-wrapper.ai-generated .rating-btn:nth-child(2).rating-btn--filled  { animation-delay: 0.05s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(3).rating-btn--filled  { animation-delay: 0.10s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(4).rating-btn--filled  { animation-delay: 0.15s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(5).rating-btn--filled  { animation-delay: 0.20s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(6).rating-btn--filled  { animation-delay: 0.25s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(7).rating-btn--filled  { animation-delay: 0.30s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(8).rating-btn--filled  { animation-delay: 0.35s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(9).rating-btn--filled  { animation-delay: 0.40s; }
.rating-wrapper.ai-generated .rating-btn:nth-child(10).rating-btn--filled { animation-delay: 0.45s; }

@media (prefers-reduced-motion: reduce) {
    .rating-wrapper.ai-aura .rating-btn--filled { animation: none; }
}

/* ── DrylScrollArea (Quelle: Components/Layout/DrylScrollArea.razor.css) ── */
/* Container-scoped scroll region with a thin DRYL accent scrollbar. */

.scroll-area {
    overflow-y: auto;
    overflow-x: hidden;
    /* Firefox */
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
}

.scroll-area--horizontal {
    overflow-x: auto;
    overflow-y: hidden;
}

/* WebKit / Chromium */
.scroll-area::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

.scroll-area::-webkit-scrollbar-track {
    background: transparent;
}

.scroll-area::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border-radius: var(--r-pill);
    border: 2px solid transparent;
    background-clip: padding-box;
    transition: background var(--dur-fast) var(--ease-out);
}

.scroll-area::-webkit-scrollbar-thumb:hover {
    background: var(--accent-line);
    background-clip: padding-box;
    border: 2px solid transparent;
}

/* ── DrylSegmentedControl (Quelle: Components/Inputs/DrylSegmentedControl.razor.css) ── */
/* ── Segmented control ──────────────────────────────────────────────
   A glass track with equal-width segments and a single gliding accent
   indicator. Grid (not flex) so every segment is the same width even
   when the track shrink-wraps its content — the indicator's pure-CSS
   position maths rely on equal columns. */

.seg {
    position: relative;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    width: fit-content;
    max-width: 100%;
    padding: var(--sp-1);
    background: var(--glass-1);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    isolation: isolate;
}

.seg--block {
    width: 100%;
}

/* The sliding selection surface. Its width is one column; translateX moves
   it by whole-column steps (set inline from the selected index). Because an
   absolutely positioned element resolves % width against the padding box,
   subtracting the track padding yields exactly the segment width. */
.seg-indicator {
    position: absolute;
    z-index: 0;
    top: var(--sp-1);
    bottom: var(--sp-1);
    left: var(--sp-1);
    width: calc((100% - 2 * var(--sp-1)) / var(--seg-count));
    border-radius: var(--r-sm);
    background: var(--glass-3);
    border: 1px solid var(--accent-line);
    box-shadow: 0 0 0 1px var(--accent-line), 0 0 20px color-mix(in srgb, var(--accent-a) 18%, transparent);
    transition: transform var(--dur-med) var(--ease-spring);
    pointer-events: none;
}

.seg-item {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    border: 0;
    background: transparent;
    color: var(--fg-muted);
    font-family: var(--font-sans);
    font-weight: 500;
    letter-spacing: -0.005em;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    border-radius: var(--r-sm);
    transition: color var(--dur-fast) var(--ease-out);
}

.seg-item:hover { color: var(--fg); }

.seg-item--selected { color: var(--fg); font-weight: 600; }

.seg-item:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--accent-soft);
}

.seg-item:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    color: var(--fg-muted);
}

.seg-icon { flex-shrink: 0; }

/* ── Sizes — mirror the DrylButton height scale ── */
.seg--sm .seg-item { height: 30px; padding: 0 12px; font-size: 12px; }
.seg--md .seg-item { height: 38px; padding: 0 16px; font-size: 13px; }
.seg--lg .seg-item { height: 46px; padding: 0 22px; font-size: 14px; }

@media (prefers-reduced-motion: reduce) {
    .seg-indicator { transition: none; }
}

/* ── DrylSparkline (Quelle: Components/Data/DrylSparkline.razor.css) ── */
.spark {
    display: block;
    overflow: visible;
}

.spark-line {
    fill: none;
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.spark-area {
    stroke: none;
    opacity: 0.18;
}

.spark-dot {
    fill: var(--accent-b);
}

.spark-stop-a { stop-color: var(--accent-a); }
.spark-stop-b { stop-color: var(--accent-b); }

/* ── DrylStepper (Quelle: Components/Layout/DrylStepper.razor.css) ── */
/* ── Root ───────────────────────────────────────────────── */

.stepper {
    display: flex;
    flex-direction: column;
    gap: 0;
}

/* ── Track (header row / column) ────────────────────────── */

.stepper--horizontal .stepper-track {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    /* On a narrow slot the steps would crush their labels to an ellipsis;
       give each a min width and let the track scroll horizontally instead. */
    overflow-x: auto;
    scrollbar-width: none;
}

.stepper--horizontal .stepper-track::-webkit-scrollbar { display: none; }

.stepper--vertical .stepper-track {
    display: flex;
    flex-direction: column;
    align-items: stretch;
}

/* ── Step header ─────────────────────────────────────────── */

.step-header {
    /* Reset native <button> chrome — DrylStepper draws its own surface. */
    appearance: none;
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    text-align: inherit;
    width: 100%;

    display: flex;
    align-items: center;
    gap: var(--sp-3);
    cursor: pointer;
    position: relative;
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-md);
    transition: background var(--dur-fast) var(--ease-out);
    user-select: none;
}

.step-header:hover:not(:disabled) {
    background: var(--glass-1);
}

.step-header:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Keyboard focus ring — the accent ring from dryl.css, scoped to the header. */
.step-header:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--accent-a);
}

/* Visually-hidden live region: announces the active step to screen readers. */
.stepper-live {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Horizontal: each header takes equal space, centers content vertically.
   A min width keeps labels readable on narrow slots; when the steps no longer
   fit, the track scrolls (above) instead of crushing every label. */
.stepper--horizontal .step-header {
    flex: 1 0 6rem;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--sp-2) var(--sp-2);
}

/* Vertical: header fills full width, row layout */
.stepper--vertical .step-header {
    flex-direction: row;
    align-items: center;
    padding: var(--sp-3) var(--sp-3);
}

/* AI aura requires explicit border-radius on the host */
.step-header.ai-aura {
    border-radius: var(--r-md);
}

/* ── Step indicator (the circle) ────────────────────────── */

.step-indicator {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: all var(--dur-med) var(--ease-out);
    position: relative;
    z-index: 1;
}

.step-indicator.is-pending {
    background: transparent;
    border: 2px dashed var(--line-strong);
    color: var(--fg-dim);
}

.step-indicator.is-active {
    background: transparent;
    border: 2px solid transparent;
    box-shadow: 0 0 0 2px var(--accent-a), 0 0 12px rgba(124, 92, 255, 0.4);
    color: var(--fg);
}

.step-indicator.is-completed {
    background: var(--success);
    border: none;
    color: var(--bg-0);
}

.step-indicator.is-error {
    background: var(--danger);
    border: none;
    color: var(--bg-0);
}

.step-number {
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
}

/* ── Connector line ──────────────────────────────────────── */

.step-connector {
    background: var(--line-strong);
    position: absolute;
    transition: background var(--dur-med) var(--ease-out);
}

/* Horizontal connector: runs right from the center of this indicator */
.stepper--horizontal .step-connector {
    height: 1px;
    /* Center of indicator is at 50% of header width.
       Start after the indicator + a small gap, end at the right edge. */
    top: calc(var(--sp-2) + 16px); /* top-padding + half of 32px indicator */
    left: calc(50% + 16px + var(--sp-1));
    right: calc(-50% + 16px + var(--sp-1));
}

/* Vertical connector: runs down from the bottom of this indicator */
.stepper--vertical .step-connector {
    width: 1px;
    /* left = left-padding + half indicator width */
    left: calc(var(--sp-3) + 16px);
    top: calc(var(--sp-3) + 32px);  /* top-padding + full indicator height */
    bottom: calc(-1 * var(--sp-3));
}

/* Completed connector gets accent color */
.step-header.is-completed .step-connector {
    background: var(--success);
}

/* ── Label group ─────────────────────────────────────────── */

.step-label-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.step-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--fg-muted);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.step-header.is-active .step-label,
.step-header.is-completed .step-label {
    color: var(--fg);
}

.step-description {
    font-size: 11px;
    color: var(--fg-dim);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Step panel (active body) ───────────────────────────── */

.step-panel {
    padding: var(--sp-4) 0;
    animation: menu-in var(--dur-med) var(--ease-out) both;
}

/* Vertical: indent body to align under the label (past the indicator) */
.stepper--vertical .step-panel {
    padding-left: calc(var(--sp-3) + 32px + var(--sp-3));
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-5);
}

/* Horizontal: top border to separate from the track */
.stepper--horizontal .step-panel {
    border-top: 1px solid var(--line);
    padding-top: var(--sp-4);
    margin-top: var(--sp-2);
}

/* ── DrylTimeline (Quelle: Components/Data/DrylTimeline.razor.css) ── */
.timeline {
    display: flex;
    flex-direction: column;
}

/* ── DrylTimelineItem (Quelle: Components/Data/DrylTimelineItem.razor.css) ── */
.timeline-item {
    display: flex;
    gap: var(--sp-3);
}

.timeline-gutter {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: none;
}

.timeline-marker {
    position: relative;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: inline-grid;
    place-content: center;
    flex: none;
    background: var(--glass-2);
    border: 1px solid var(--line-strong);
    color: var(--fg-muted);
}

.timeline-marker--accent  { border-color: var(--accent-line);          color: var(--accent-a); }
.timeline-marker--success { border-color: rgba(52,211,153,0.5);        color: var(--success); }
.timeline-marker--warning { border-color: rgba(251,191,36,0.5);        color: var(--warning); }
.timeline-marker--danger  { border-color: rgba(248,113,113,0.5);       color: var(--danger); }

.timeline-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.timeline-line {
    flex: 1 1 auto;
    width: 1px;
    background: var(--line);
    min-height: 14px;
    margin: 4px 0;
}

.timeline-item:last-child .timeline-line {
    display: none;
}

.timeline-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding-bottom: var(--sp-5);
}

.timeline-item:last-child .timeline-body {
    padding-bottom: 0;
}

.timeline-head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
    flex-wrap: wrap;
}

.timeline-title {
    font-size: 14px;
    font-weight: 500;
    color: var(--fg);
}

.timeline-time {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--fg-dim);
}

.timeline-content {
    font-size: 13px;
    color: var(--fg-muted);
    line-height: 1.5;
}

/* ── DrylValidationSummary (Quelle: Components/Inputs/DrylValidationSummary.razor.css) ── */
.validation-summary {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border: 1px solid rgba(248, 113, 113, 0.4);
    border-radius: var(--r-md);
    background: rgba(248, 113, 113, 0.08);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
}

.validation-summary-icon {
    display: inline-flex;
    flex: none;
    margin-top: 1px;
    color: var(--danger);
}

.validation-summary-body {
    min-width: 0;
}

.validation-summary-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--fg);
    margin-bottom: 4px;
}

.validation-summary-list {
    margin: 0;
    padding-left: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.validation-summary-list li {
    font-size: 13px;
    color: var(--fg-muted);
}

/* ── DrylPopover (Quelle: Components/Surfaces/DrylPopover.razor.css) ── */
.popover-anchor {
    position: relative;
    display: inline-block;
}

.popover-anchor--block {
    display: block;
    width: 100%;
}

.popover-trigger {
    display: inline-flex;
}

.popover-anchor--block .popover-trigger {
    display: flex;
    width: 100%;
}

/* The panel wrapper is always rendered (so Blazor never removes the node and
   JS can safely portal it to <body>), and positioned with position:fixed by
   dryl.popover (JS) so it escapes any ancestor overflow / backdrop-filter
   containing block such as a glass card.

   Visibility is a two-key gate: the panel only shows once Blazor has opened it
   (.is-open) AND JS has placed it in the viewport (.is-positioned). On open
   this hides the one-frame mis-position flash (interop is a network roundtrip
   on Blazor Server); on close, dropping .is-open hides it atomically with the
   content removal, so no empty surface box ever flashes. */
.popover-panel {
    position: fixed;
    z-index: var(--z-popover);
    visibility: hidden;
    /* Never exceed the viewport on a phone (the panel is fixed-positioned). */
    max-width: calc(100vw - var(--sp-4));
}
.popover-panel.is-open.is-positioned {
    visibility: visible;
}

/* Default surface (opt out with Surface="false").
   Dropdowns float over page content, so the fill is opaque (--bg-2),
   matching the library's existing menu / select / date panels.
   The base min-width lives here so content-sized panels (Surface=false)
   can hug their own content instead of being padded out. */
.popover-panel--surface {
    min-width: 180px;
    background: var(--bg-2);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-2);
}

/* Match the trigger width (dropdowns / selects). The explicit width is set
   by JS from the anchor's measured width; here we only drop the surface
   min-width so the panel can shrink to a narrow trigger. */
.popover-panel--match {
    min-width: 0;
}

/* Placement is computed in JS (dryl.popover) against the viewport — the
   placement modifier classes are kept as styling hooks only. */

/* Entrance — the panel node is reused across opens, so the animation is bound
   to the reveal state (.is-positioned is (re)added by JS on each open) rather
   than to the node mounting, otherwise it would only ever play once. */
.popover-panel.is-open.is-positioned {
    animation: popover-in var(--dur-fast) var(--ease-out);
}

@keyframes popover-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .popover-panel.is-open.is-positioned { animation: none; }
}

/* ── DrylSelect (Quelle: Components/Inputs/DrylSelect.razor.css) ── */
/* ── Trigger div overrides ───────────────────────────────── */

/* The global .select class provides the base input styles.
   These scoped rules add flex layout and open/disabled states. */

.select {
    display: flex;
    align-items: center;
}

.select span {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.select-placeholder {
    color: var(--fg-dim);
}

/* Mirrors :focus ring while the panel is open */
.select.select--open {
    border-color: var(--accent-line);
    background: var(--glass-2);
    box-shadow: 0 0 0 4px rgba(124, 92, 255, 0.12), 0 0 24px rgba(124, 92, 255, 0.18);
}

.select.select--disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ── Dropdown panel ──────────────────────────────────────── */

/* Positioning is provided by the DrylPopover wrapper; this is just the surface. */
.select-panel {
    width: 100%;
    background: var(--bg-2);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-1) 0;
    max-height: 240px;
    overflow-y: auto;
    outline: none;

    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
}

.select-panel::-webkit-scrollbar       { width: 4px; }
.select-panel::-webkit-scrollbar-track { background: transparent; }
.select-panel::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 2px; }

/* ── Option rows ─────────────────────────────────────────── */

.select-option {
    display: flex;
    align-items: center;
    width: 100%;
    padding: var(--sp-2) var(--sp-4);
    background: transparent;
    color: var(--fg-muted);
    font-size: 13px;
    font-weight: 400;
    line-height: 1.4;
    cursor: pointer;
    user-select: none;
    transition: background var(--dur-fast) var(--ease-out),
                color      var(--dur-fast) var(--ease-out);
}

.select-option:hover,
.select-option.is-highlighted {
    background: var(--glass-2);
    color: var(--fg);
}

.select-option.is-selected {
    color: var(--fg);
}

/* Accent dot on the selected item */
.select-option.is-selected::after {
    content: '';
    display: block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent-a);
    margin-left: auto;
    flex-shrink: 0;
}

/* ── Empty state ─────────────────────────────────────────── */

.select-empty {
    padding: var(--sp-3) var(--sp-4);
    color: var(--fg-dim);
    font-size: 13px;
    text-align: center;
}

/* ── Breadcrumbs — Pfad-Navigation (portiert aus
   DrylBreadcrumbs.razor.css, scoped Styles 1:1 übernommen) ──── */
.breadcrumbs-nav {
    display: flex;
    min-width: 0;
}

.breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-1);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 13px;
}

.breadcrumb-item {
    display: inline-flex;
    align-items: center;
    min-width: 0;
}

.breadcrumb-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 2px 6px;
    border-radius: var(--r-xs);
    color: var(--fg-muted);
    text-decoration: none;
    transition: color var(--dur-fast) var(--ease-out),
                background var(--dur-fast) var(--ease-out);
    white-space: nowrap;
}

.breadcrumb-link:hover {
    color: var(--fg);
    background: var(--glass-2);
}

.breadcrumb-current {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 2px 6px;
    color: var(--fg);
    font-weight: 500;
    white-space: nowrap;
}

.breadcrumb-sep {
    display: inline-flex;
    align-items: center;
    color: var(--fg-faint);
    pointer-events: none;
}

.breadcrumb-ellipsis {
    color: var(--fg-muted);
    padding: 2px 4px;
}

/* ── DrylMessage (Quelle: Components/Surfaces/DrylMessage.razor.css) ── */
/* Einzelne Chat-Nachrichtenblase. User-Nachrichten rechtsbündig mit
   akzentgetönter Blase, Assistant-Nachrichten linksbündig auf Glas,
   System-Zeilen zentriert und gedämpft. Der KI-Aura-Rahmen und die
   Streaming-Token (ai-aura / stream-token) sind bewusst weggelassen —
   sie sind Zeitgeber-/JS-getrieben; die statische Seite zeigt nur den
   Ruhezustand. */
.chat-msg {
    display: flex;
    gap: var(--sp-3);
    align-items: flex-start;
    max-width: 100%;
}

.chat-msg--user { flex-direction: row-reverse; }
.chat-msg--assistant { flex-direction: row; }

.chat-msg-avatar { flex: none; }

.chat-msg-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    max-width: 78%;
}

.chat-msg--user .chat-msg-body { align-items: flex-end; }

.chat-msg-meta {
    display: flex;
    gap: var(--sp-2);
    align-items: baseline;
    font-size: 11px;
}

.chat-msg-author { color: var(--fg-muted); font-weight: 500; }
.chat-msg-time { color: var(--fg-dim); font-family: var(--font-mono); }

.chat-bubble {
    position: relative;
    border-radius: var(--r-md);
    padding: var(--sp-3) var(--sp-4);
    font-size: 14px;
    line-height: 1.55;
    color: var(--fg);
    overflow-wrap: anywhere;
}

/* Vertikaler Rhythmus zwischen gestapelten Blöcken einer zusammengesetzten
   Blase; feuert nur zwischen Geschwistern, eine einzelne Textblase bleibt
   unberührt. (Upstream nutzt hier ::deep für die Blazor-Scope-Grenze — in
   Vanilla reicht der direkte Kindselektor.) */
.chat-bubble-content > * + * { margin-top: var(--sp-3); }

.chat-bubble--assistant {
    background: var(--glass-2);
    border: 1px solid var(--line);
    border-top-left-radius: var(--r-xs);
}

.chat-bubble--user {
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    border-top-right-radius: var(--r-xs);
}

.chat-msg--system { justify-content: center; }

.chat-system-line {
    font-size: 12px;
    color: var(--fg-dim);
    text-align: center;
}

/* Tipp-Indikator */
.chat-typing {
    display: inline-flex;
    gap: 4px;
    align-items: center;
    padding: 2px 0;
}

.chat-typing span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--fg-muted);
    animation: chat-typing-bounce 1.2s var(--ease-in-out) infinite;
}

.chat-typing span:nth-child(2) { animation-delay: 0.15s; }
.chat-typing span:nth-child(3) { animation-delay: 0.30s; }

@keyframes chat-typing-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
    30% { transform: translateY(-4px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .chat-typing span { animation: none; opacity: 0.6; }
}

/* ============== SLIDER (DrylSlider) ==============
   Upstream ist ein <input type="range"> mit der scoped Klasse
   .dryl-slider; das Glashaus zeigt einen eigenständigen
   role="slider"-Regler (Zeiger-Drag + Pfeiltasten in
   dryl-vanilla.js). Der Füllstand läuft — wie beim Gradient-Trick
   des Upstreams — rein über die CSS-Variable --pct (Fill-Breite +
   Thumb-Position). Nur hier definiert: .slider-track / .slider-fill
   / .slider-thumb. Die .slider-wrap / .slider-header / .slider-value
   kommen unverändert aus dryl.css. */

.slider-track {
  position: relative;
  height: 4px;
  margin: 8px 0;
  border-radius: var(--r-pill);
  background: var(--glass-3);
  cursor: pointer;
  outline: none;
  touch-action: none;
}

.slider-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--pct, 0%);
  border-radius: var(--r-pill);
  background: linear-gradient(to right, var(--accent-a), var(--accent-b));
}

.slider-thumb {
  position: absolute;
  top: 50%;
  left: var(--pct, 0%);
  width: 18px;
  height: 18px;
  border-radius: var(--r-pill);
  background: var(--knob);
  transform: translate(-50%, -50%);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--backdrop) 83.333%, transparent);
  transition: box-shadow var(--dur-fast) var(--ease-out),
              transform  var(--dur-fast) var(--ease-spring);
}

.slider-track:focus-visible .slider-thumb {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent-a) 35%, transparent),
              0 1px 4px color-mix(in srgb, var(--backdrop) 83.333%, transparent);
  transform: translate(-50%, -50%) scale(1.1);
}

.slider-track:active .slider-thumb {
  transform: translate(-50%, -50%) scale(1.1);
}

.slider-track.is-disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

@media (prefers-reduced-motion: reduce) {
  .slider-thumb { transition: none; }
}

/* ── DrylDatePicker (Quelle: Components/Inputs/DrylDatePicker.razor.css) ── */
/* Kalender-Fläche. Positionierung liefert der DrylPopover-Wrapper; dies ist
   nur die Oberfläche. Das Gitter selbst baut dryl.datepicker (JS) zur
   Laufzeit in die .date-panel — die date-*-Innenklassen tauchen daher nicht
   im Seiten-Quelltext auf, werden aber hier für die Darstellung definiert.
   Range-Modus bewusst ausgelassen (Glashaus: Einzeldatum). */
.date-panel {
    min-width: 280px;
    background: var(--bg-2);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-3);
    outline: none;
}

/* ── Monats-Navigation ──────────────────────────────────── */
.date-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--sp-3);
}

.date-month-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--fg);
}

/* ── Gitter ─────────────────────────────────────────────── */
.date-grid {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
}

.date-weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: var(--sp-1);
    margin-bottom: 2px;
}

.date-weekday {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--fg-dim);
    text-align: center;
    padding: 2px 0;
}

.date-week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: var(--sp-1);
}

/* ── Tages-Zellen ───────────────────────────────────────── */
.date-cell {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
    border: none;
    background: transparent;
    color: var(--fg-muted);
    font-size: 12px;
    font-weight: 400;
    cursor: pointer;
    padding: 0;
    transition: background var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
    line-height: 1;
}

.date-cell:hover:not(.is-disabled):not(.date-cell--empty) {
    background: var(--glass-2);
    color: var(--fg);
}

.date-cell:focus-visible {
    outline: 2px solid var(--accent-b);
    outline-offset: 1px;
}

.date-cell--empty {
    cursor: default;
}

/* Heute */
.date-cell.is-today {
    border: 1px solid var(--accent-line);
    color: var(--fg);
}

/* Ausgewählter Tag */
.date-cell.is-selected {
    background: var(--accent-grad);
    color: var(--fg);
    font-weight: 600;
}

/* Gesperrt (außerhalb Min/Max) */
.date-cell.is-disabled {
    opacity: 0.25;
    cursor: not-allowed;
    pointer-events: none;
}

/* ── DrylTimePicker (Quelle: Components/Inputs/DrylTimePicker.razor.css) ── */
/* Positioning is provided by the DrylPopover wrapper; this is just the surface
   (the popover opts out of its own surface, so .time-panel paints the glass). */
.time-panel {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-3);
    background: var(--bg-2);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
}

.time-columns {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-1);
}

.time-col {
    display: flex;
    flex-direction: column;
    width: 56px;
    max-height: 200px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
    border-radius: var(--r-sm);
    gap: 2px;
    padding: 2px;
}

.time-col::-webkit-scrollbar {
    width: 4px;
}
.time-col::-webkit-scrollbar-track {
    background: transparent;
}
.time-col::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border-radius: 2px;
}

.time-col-sep {
    padding: 8px 0;
    color: var(--fg-dim);
    font-size: 16px;
    font-weight: 600;
    align-self: flex-start;
    margin-top: 4px;
    user-select: none;
}

.time-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 32px;
    flex-shrink: 0;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--r-xs);
    color: var(--fg-muted);
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}

.time-cell:hover {
    background: var(--glass-2);
    color: var(--fg);
}

.time-cell.is-selected {
    background: var(--accent-soft);
    color: var(--fg);
    font-weight: 600;
}

.time-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-2);
    padding-top: var(--sp-2);
    border-top: 1px solid var(--line);
}

/* ── DrylAutocomplete (Quelle: Components/Inputs/DrylAutocomplete.razor.css) ── */
/* Panel und Optionsreihen der filternden Combobox. Positionierung liefert
   der Popover-Wrapper (dryl.popover portalt das .popover-panel); hier nur
   die Fläche und die Reihen — analog zum DrylSelect-Block darüber. */

.autocomplete-panel {
    width: 100%;
    background: var(--bg-2);
    backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-1) 0;
    max-height: 240px;
    overflow-y: auto;
    outline: none;

    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
}

.autocomplete-panel::-webkit-scrollbar       { width: 4px; }
.autocomplete-panel::-webkit-scrollbar-track { background: transparent; }
.autocomplete-panel::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 2px; }

/* ── Option rows ─────────────────────────────────────────── */

.autocomplete-option {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-2) var(--sp-4);
    background: transparent;
    color: var(--fg-muted);
    font-size: 13px;
    font-weight: 400;
    line-height: 1.4;
    cursor: pointer;
    user-select: none;
    transition: background var(--dur-fast) var(--ease-out),
                color      var(--dur-fast) var(--ease-out);
}

.autocomplete-option:hover,
.autocomplete-option.is-highlighted {
    background: var(--glass-2);
    color: var(--fg);
}

/* Aktuell gebundener Wert in der Liste */
.autocomplete-option.is-selected {
    color: var(--fg);
}

.autocomplete-option.is-selected::after {
    content: '';
    display: block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent-a);
    margin-left: auto;
    flex-shrink: 0;
}

/* ── Leerzustand ─────────────────────────────────────────── */

.autocomplete-empty {
    padding: var(--sp-3) var(--sp-4);
    color: var(--fg-dim);
    font-size: 13px;
    text-align: center;
}

/* ── DrylMultiSelect (Quelle: Components/Inputs/DrylMultiSelect.razor.css) ── */
/* Trigger: wie .select, aber die Höhe wächst mit den Chips (min-height,
   height:auto) statt sie zu klippen. Chips (.chip*/.multiselect-chips),
   Panel (.select-panel) und Optionen (.select-option) kommen aus
   dryl.css bzw. dem DrylSelect-Block darüber — hier nur das, was der
   MultiSelect zusätzlich braucht. */

.multiselect-trigger {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 38px;
    height: auto;
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--r-md);
    background: var(--glass-1);
    border: 1px solid var(--line-strong);
    color: var(--fg);
    font: 400 13px/1 var(--font-sans);
    cursor: pointer;
    transition: border-color var(--dur-med) var(--ease-out),
                background   var(--dur-med) var(--ease-out),
                box-shadow   var(--dur-med) var(--ease-out);
    outline: none;
}

.multiselect-trigger:hover { border-color: var(--line-hover); }

/* Spiegelt den :focus-Ring, solange das Panel offen ist. */
.multiselect-trigger:focus,
.multiselect-trigger.select--open {
    border-color: var(--accent-line);
    background: var(--glass-2);
    box-shadow: 0 0 0 4px rgba(124, 92, 255, 0.12), 0 0 24px rgba(124, 92, 255, 0.18);
}

.multiselect-trigger:focus-visible { outline: none; }

.multiselect-trigger.select--disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* .input-error / .input-success in dryl.css treffen nur .input/.textarea/.select —
   dieselben Token-Werte für den MultiSelect-Trigger nachbilden. */
.multiselect-trigger.input-error { border-color: rgba(248, 113, 113, 0.5); }
.multiselect-trigger.input-error:focus,
.multiselect-trigger.input-error.select--open {
    border-color: var(--danger);
    background: var(--glass-2);
    box-shadow: 0 0 0 4px rgba(248, 113, 113, 0.12), 0 0 24px rgba(248, 113, 113, 0.18);
}

.multiselect-trigger.input-success { border-color: rgba(52, 211, 153, 0.5); }
.multiselect-trigger.input-success:focus,
.multiselect-trigger.input-success.select--open {
    border-color: var(--success);
    background: var(--glass-2);
    box-shadow: 0 0 0 4px rgba(52, 211, 153, 0.12), 0 0 24px rgba(52, 211, 153, 0.18);
}

.multiselect-placeholder { color: var(--fg-dim); }

/* Optionen: Platz für die Checkbox-Spalte, Akzent-Punkt (DrylSelect)
   unterdrücken — der Auswahlzustand liest sich hier über die Checkbox. */
.multiselect-option { gap: var(--sp-3); }
.multiselect-option.is-selected::after { display: none; }

.multiselect-check {
    flex-shrink: 0;
    pointer-events: none;
}

/* InputMask — strukturierte Eingabe in Monospace für gleichmäßige
   Zeichenabstände (IBAN, Karten-, Telefonnummern lesen sich so
   Block für Block). Upstream: DrylInputMask.razor.css (dort auf
   .input scoped; hier als eigene Klasse, damit nur Masken-Felder
   die Mono-Optik bekommen). */
.input-mask {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
}

/* --------------------------------------------------------------
 * InputOtp — segmentiertes Einmal-Code-Feld (OTP / 2FA).
 * Portiert aus DrylInputOtp.razor.css (scoped). Jede Ziffer sitzt
 * in einem eigenen Kästchen; Fokus-Ring und Zustände über Tokens.
 * -------------------------------------------------------------- */
.otp-wrapper {
  position: relative;
  display: inline-flex;
  border-radius: var(--r-md);
}

/* Struktureller Rahmen je Kästchen (Host für die AI-Aura, Phase 3) */
.otp-box-wrap {
  position: relative;
  border-radius: var(--r-sm);
}

.otp-boxes {
  display: flex;
  gap: var(--sp-2);
}

.otp-box {
  width: 44px;
  height: 52px;
  padding: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--fg);
  background: var(--glass-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  outline: none;
  caret-color: var(--accent-a);
  transition: border-color var(--dur-med) var(--ease-out),
              background var(--dur-med) var(--ease-out),
              box-shadow var(--dur-med) var(--ease-out);
  -moz-appearance: textfield;
}

.otp-box::-webkit-outer-spin-button,
.otp-box::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.otp-box:hover:not(:disabled) {
  border-color: var(--line-hover);
}

.otp-box:focus:not(:disabled) {
  border-color: var(--accent-line);
  background: var(--glass-2);
  box-shadow: 0 0 0 1px var(--accent-line),
              0 0 0 4px rgba(124, 92, 255, 0.12),
              0 0 24px rgba(124, 92, 255, 0.18);
}

.otp-box:focus-visible { outline: none; }

.otp-box--error {
  border-color: var(--danger);
}

.otp-box--error:focus {
  border-color: var(--danger);
  box-shadow: 0 0 0 4px rgba(248, 113, 113, 0.12);
}

.otp-box--success {
  border-color: var(--success);
}

.otp-box--success:focus {
  border-color: var(--success);
  box-shadow: 0 0 0 4px rgba(52, 211, 153, 0.12);
}

.otp-box:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── DrylFileUpload (Quelle: Components/Inputs/DrylFileUpload.razor.css) ── */
/* Unsichtbares Overlay, das die ganze Drop-Zone klickbar macht: ein
   <input type="file"> deckt die .file-drop lückenlos ab, sodass ein
   Klick irgendwo in der Zone den nativen Dateidialog öffnet. Die
   Zonen-/Listen-Styles (.file-drop, .file-list, .file-item …) stehen
   bereits in dryl.css; nur dieses Overlay kam aus der CSS-Isolation. */
.file-input-overlay {
    position: absolute;
    inset: 0;
    opacity: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
    z-index: 1;
}

.file-input-overlay:disabled {
    cursor: not-allowed;
    pointer-events: none;
}


/* ── DrylChat (Quelle: Components/Surfaces/DrylChat.razor.css) ── */
/* Die Konversations-Fläche: ein Glas-Panel mit scrollbarem
   Nachrichten-Log und optionaler, angehefteter Eingabezeile (Footer).
   Die einzelnen Blasen (.chat-msg / .chat-bubble …) sind weiter oben in
   dieser Datei definiert (DrylMessage) und werden hier nur eingebettet.
   Der KI-Aura-Rahmen ums ganze Panel (Ai=…) ist Zeitgeber-getrieben und
   bleibt in der statischen Seite weg — gezeigt wird der Ruhezustand. */
.chat {
    position: relative;
    display: flex;
    flex-direction: column;
    height: var(--chat-height, 480px);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--glass-1);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    box-shadow: var(--shadow-md);
}

.chat-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    padding: var(--sp-5);
}

.chat-footer {
    flex: 0 0 auto;
    padding: var(--sp-3) var(--sp-4) var(--sp-4);
    border-top: 1px solid var(--line-soft);
}

/* ── DrylChatComposer (Quelle: Components/Surfaces/DrylChatComposer.razor.css) ── */
/* Die Eingabezeile im Footer: eine wachsende Textarea plus Sende-Knopf.
   Enter-zum-Senden und das Mitwachsen der Textarea sind upstream
   JS-getrieben (dryl.chat.attachComposer) — auf der statischen Seite
   zeigen wir nur den Ruhezustand samt Fokus-Rahmen. */
.chat-composer {
    position: relative;
    display: flex;
    align-items: flex-end;
    gap: var(--sp-2);
    padding: var(--sp-2);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    background: var(--glass-1);
    transition: border-color var(--dur-fast) var(--ease-out);
}

.chat-composer:focus-within {
    border-color: var(--accent-line);
}

.chat-composer-input {
    flex: 1 1 auto;
    min-width: 0;
    resize: none;
    border: none;
    background: transparent;
    color: var(--fg);
    font-family: var(--font-sans);
    font-size: 14px;
    line-height: 1.5;
    padding: 8px 6px;
    max-height: 160px;
    overflow-y: auto;
    outline: none;
}

.chat-composer-input::placeholder {
    color: var(--fg-dim);
}

.chat-composer-input:disabled {
    color: var(--fg-dim);
    cursor: not-allowed;
}

/* ── CommandPalette — Cmd/Strg+K-Launcher ────────────────────────────────────
   Portiert aus DRYL.Components/Components/Navigation/DrylCommandPalette.razor.css.
   Der Overlay-Unterbau (.dialog-backdrop) kommt aus dryl.css; hier nur die
   Panel-, Such- und Zeilen-Klassen. AI-Panel/Aura/Argument-Fill des Upstreams
   sind bewusst nicht übernommen (siehe Seite/Notizen). */

/* ── Palette-Panel ──────────────────────────────────────────────────────────── */
.cmd-palette {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 640px;
  max-width: calc(100vw - var(--sp-8));
  max-height: min(80vh, 680px);
  border-radius: var(--r-lg);
  background: var(--panel-grad-strong);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lg), 0 0 80px color-mix(in srgb, var(--accent-a) 14%, transparent);
  overflow: hidden;
  animation: cmd-in var(--dur-med) var(--ease-spring);
}

@keyframes cmd-in {
  from { opacity: 0; transform: scale(0.97) translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* ── Suchzeile ──────────────────────────────────────────────────────────────── */
.cmd-search-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4);
  flex: 0 0 auto;
}

.cmd-search-icon {
  color: var(--fg-dim);
  flex: 0 0 auto;
  pointer-events: none;
  transition: color var(--dur-fast) var(--ease-out);
}

.cmd-search-row:focus-within .cmd-search-icon {
  color: var(--fg-muted);
}

.cmd-search-input {
  flex: 1 1 auto;
  background: transparent;
  border: none;
  outline: none;
  color: var(--fg);
  font: 400 15px / 1.4 var(--font-sans);
  caret-color: var(--accent-a);
  min-width: 0;
}

.cmd-search-input::placeholder {
  color: var(--fg-dim);
}

.cmd-search-kbd {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  padding: 3px var(--sp-2);
  border-radius: var(--r-xs);
  border: 1px solid var(--line-strong);
  background: var(--glass-1);
  color: var(--fg-dim);
  user-select: none;
  white-space: nowrap;
}

/* ── Trenner ────────────────────────────────────────────────────────────────── */
.cmd-divider {
  height: 1px;
  background: var(--line);
  flex: 0 0 auto;
}

/* ── Trefferliste ───────────────────────────────────────────────────────────── */
.cmd-results {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--sp-1) 0;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}

.cmd-results::-webkit-scrollbar {
  width: 4px;
}

.cmd-results::-webkit-scrollbar-track {
  background: transparent;
}

.cmd-results::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 2px;
}

/* Gruppenkopf — aria-hidden, nicht fokussierbar */
.cmd-category {
  padding: var(--sp-2) var(--sp-4) var(--sp-1);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
  user-select: none;
}

/* ── Ergebnis-Zeile ─────────────────────────────────────────────────────────── */
.cmd-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  user-select: none;
  transition:
    background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.cmd-item:hover,
.cmd-item.is-focused {
  background: var(--glass-2);
  color: var(--fg);
}

.cmd-item.is-focused {
  box-shadow: inset 0 0 0 1px var(--accent-line);
}

/* KI-Absicht — Akzenttönung auf dem Icon */
.cmd-item--ai .cmd-item-icon {
  color: var(--accent-a);
  border-color: rgba(124, 92, 255, 0.25);
}

.cmd-item-icon {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-xs);
  background: var(--glass-2);
  border: 1px solid var(--line);
  color: var(--fg-dim);
  flex-shrink: 0;
  transition:
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.cmd-item:hover .cmd-item-icon,
.cmd-item.is-focused .cmd-item-icon {
  color: var(--fg-muted);
  border-color: var(--line-strong);
}

.cmd-item-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.cmd-item-label {
  color: inherit;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cmd-item-desc {
  font-size: 11px;
  color: var(--fg-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.35;
}

.cmd-item-trailing {
  color: var(--fg-faint);
  flex: 0 0 auto;
  transition: color var(--dur-fast) var(--ease-out);
}

.cmd-item:hover .cmd-item-trailing,
.cmd-item.is-focused .cmd-item-trailing {
  color: var(--fg-dim);
}

.cmd-item-trailing--ai {
  color: var(--accent-a);
  opacity: 0.7;
}

.cmd-item:hover .cmd-item-trailing--ai,
.cmd-item.is-focused .cmd-item-trailing--ai {
  opacity: 1;
}

/* Pro-Zeile-Kürzel */
.cmd-item-shortcut {
  flex: 0 0 auto;
  margin-left: var(--sp-2);
  padding: 2px var(--sp-2);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  color: var(--fg-dim);
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--glass-1);
  white-space: nowrap;
}

/* Destruktive Zeile — nur das Label akzentuieren, nie die Fläche füllen (Regel 2.4). */
.cmd-item--danger .cmd-item-label {
  color: var(--danger, var(--fg));
}

/* Deaktivierte Zeile */
.cmd-item.is-disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* Leerzustand */
.cmd-empty {
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
  color: var(--fg-dim);
  font-size: 13px;
}

/* ── Reduzierte Bewegung ────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .cmd-palette {
    animation: none;
  }
}

/* --------------------------------------------------------------
 * TreeView — hierarchischer Baum (DrylTreeView + DrylTreeNode).
 * Aus den scoped .razor.css der beiden Upstream-Komponenten
 * zusammengeführt; im Blazor-Original waren .tree/.tree-view und
 * die .tree-*-Knotenklassen auf zwei Dateien verteilt. Keine
 * dieser Klassen existiert in dryl.css, deshalb hier vollständig.
 * Tiefe steuert die Variable --tree-depth pro Zeile.
 * -------------------------------------------------------------- */
.tree {
  list-style: none;
  margin: 0;
  padding: var(--sp-2);
  display: flex;
  flex-direction: column;
}

.tree-group {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

/* Ein explizites `display` überstimmt das UA-display:none des
   hidden-Attributs — eingeklappte Gruppen müssen sich hier wieder
   ausblenden. */
.tree-group[hidden] {
  display: none;
}

.tree-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 6px var(--sp-2);
  padding-left: calc(var(--sp-3) + var(--tree-depth, 0) * 18px);
  border-radius: var(--r-sm);
  color: var(--fg-muted);
  cursor: pointer;
  user-select: none;
  outline: none;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.tree-row:hover {
  background: var(--glass-2);
  color: var(--fg);
}

.tree-row:focus-visible {
  box-shadow: 0 0 0 2px var(--accent-soft);
}

.tree-row.is-selected {
  background: var(--accent-soft);
  color: var(--fg);
}

.tree-toggle,
.tree-toggle-spacer {
  width: 18px;
  height: 18px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.tree-toggle {
  color: var(--fg-dim);
  border-radius: var(--r-xs);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.tree-toggle:hover {
  color: var(--fg);
}

.tree-toggle.is-open {
  transform: rotate(90deg);
}

.tree-icon {
  display: inline-flex;
  color: var(--fg-dim);
}

.tree-row.is-selected .tree-icon {
  color: var(--accent-a);
}

.tree-label {
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── DrylReconnectModal (Quelle: Components/Surfaces/DrylReconnectModal.razor.css) ── */
/* On-brand-Ersatz für Blazor Servers Standard-Reconnect-Overlay. Im
   Upstream ist die Wurzel ein position:fixed-Overlay, dessen Sichtbarkeit
   und Zustände (reconnecting / failed / rejected) allein von den
   State-Klassen abhängen, die Blazors eigenes JS zur Laufzeit auf
   #components-reconnect-modal toggelt (der Circuit ist tot, kein C# läuft).
   Fürs Glashaus werden die Zustände STATISCH im Seitenfluss gezeigt:
   .reconnect-demo ersetzt das fixe Overlay durch eine eingebettete
   Bühnen-Fläche mit derselben Overlay-Optik; .reconnect-state ist hier
   sichtbar statt display:none. Karte und Innenleben sind 1:1 aus dem
   Upstream übernommen. */

/* Eingebettete Overlay-Fläche (ersetzt das fixe .reconnect-overlay). */
.reconnect-demo {
    width: 100%;
    display: grid;
    place-items: center;
    padding: var(--sp-6) var(--sp-5);
    border-radius: var(--r-lg);
    background: var(--backdrop);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
    backdrop-filter: blur(6px) saturate(120%);
}

/* ── Karte ──────────────────────────────────────────────── */
.reconnect-card {
    position: relative;
    width: min(400px, 100%);
    padding: var(--sp-6) var(--sp-6) var(--sp-5);
    border-radius: var(--r-lg);
    background: var(--panel-grad);
    border: 1px solid var(--line-strong);
    box-shadow: var(--shadow-lg),
                0 0 80px color-mix(in srgb, var(--accent-a) 25%, transparent);
    color: var(--fg);
    text-align: center;
}

/* ── Zustandsblock (im Glashaus dauerhaft sichtbar) ─────── */
.reconnect-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-3);
}

/* ── Reconnecting-Spinner ───────────────────────────────── */
.reconnect-spinner {
    position: relative;
    width: 46px;
    height: 46px;
    display: inline-grid;
    place-items: center;
    margin-bottom: var(--sp-1);
}
.reconnect-spinner-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 3px solid var(--accent-soft);
    border-top-color: var(--accent-a);
    border-right-color: var(--accent-b);
    animation: reconnect-spin 0.9s linear infinite;
}
.reconnect-spinner-core {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--accent-grad);
    box-shadow: var(--glow-accent);
    animation: reconnect-breathe 1.6s var(--ease-in-out) infinite;
}

/* ── Glyphen für failed / rejected ──────────────────────── */
.reconnect-glyph {
    display: inline-grid;
    place-items: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    margin-bottom: var(--sp-1);
    border: 1px solid var(--line);
}
.reconnect-glyph-warn {
    color: var(--warning);
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border-color: color-mix(in srgb, var(--warning) 32%, transparent);
}
.reconnect-glyph-danger {
    color: var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    border-color: color-mix(in srgb, var(--danger) 32%, transparent);
}

/* ── Text ───────────────────────────────────────────────── */
.reconnect-text {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--fg);
    line-height: 1.5;
}
.reconnect-counter {
    margin: 0;
    font-size: 12px;
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
}
.reconnect-counter-sep {
    opacity: 0.5;
    margin: 0 2px;
}
.reconnect-next {
    margin: 0;
    font-size: 12px;
    color: var(--fg-dim);
    font-variant-numeric: tabular-nums;
}
.reconnect-action {
    margin-top: var(--sp-2);
}

/* ── Keyframes (global; eindeutig benannt) ──────────────── */
@keyframes reconnect-spin {
    to { transform: rotate(360deg); }
}
@keyframes reconnect-breathe {
    0%, 100% { opacity: 0.55; transform: scale(0.8); }
    50%      { opacity: 1;    transform: scale(1); }
}

/* ── Reduced Motion — der Spinner IST das „arbeitet noch"-Signal
      und behält eine langsame Drehung; Dekoratives (Atem-Kern) fällt weg. */
@media (prefers-reduced-motion: reduce) {
    .reconnect-spinner-ring { animation-duration: 1.8s; }
    .reconnect-spinner-core { animation: none; opacity: 1; }
}

/* ============== TOOL CALL (DrylToolCall) ==============
   Agenten-Werkzeugaufruf mit Status-Pille und aufklappbarem
   Körper (Eingabe/Ausgabe). Portiert aus der isolierten
   DrylToolCall.razor.css; die Sichtbarkeit des Körpers und die
   Chevron-Drehung laufen im Glashaus über .is-open am
   .tool-call-Element (statt über Conditional-Rendering wie im
   Blazor-Original). */
.tool-call {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--glass-1);
}

.tool-call-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  color: var(--fg);
  font: inherit;
  border-radius: var(--r-md);
}
.tool-call-head:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-line);
}

.tool-call-icon {
  display: inline-flex;
  color: var(--accent-b);
  flex: none;
}

.tool-call-name {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tool-call-status {
  margin-left: auto;
  flex: none;
}

.tool-call-chevron {
  display: inline-flex;
  color: var(--fg-dim);
  flex: none;
  transition: transform var(--dur-med) var(--ease-in-out);
}
.tool-call.is-open .tool-call-chevron { transform: rotate(180deg); }

.tool-call-body {
  display: none;
  flex-direction: column;
  gap: var(--sp-3);
  padding: 0 var(--sp-3) var(--sp-3);
}
.tool-call.is-open .tool-call-body { display: flex; }

.tool-call-section {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.tool-call-section-label {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

@media (prefers-reduced-motion: reduce) {
  .tool-call-chevron { transition: none; }
}

/* ============================================================
   ToolCallGroup — ruhige, einklappbare Zusammenfassung über einem
   Stapel Werkzeugaufrufe (Upstream DrylToolCallGroup.razor.css).
   NUR die Gruppen-Klassen; die Karten-Klassen (.tool-call*) liefert
   das ToolCall-Fragment oben, die KI-Aura/-Indikator-Klassen dryl.css.
   ============================================================ */

.tool-group {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--glass-1);
}

.tool-group--error {
  border-color: color-mix(in srgb, var(--danger) 30%, transparent);
}

.tool-group-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  color: var(--fg-muted);
  font: inherit;
  border-radius: var(--r-md);
  transition: color var(--dur-fast) var(--ease-out);
}
.tool-group-head:hover { color: var(--fg); }
.tool-group-head:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-line);
}

.tool-group-icon {
  display: inline-flex;
  color: var(--accent-b);
  flex: none;
}

.tool-group-label {
  font-size: 13px;
  color: inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Live-Ticker: der Name des laufenden Werkzeugs liest sich als Code. */
.tool-group-label--ticker {
  font-family: var(--font-mono);
  color: var(--fg);
}

.tool-group-status {
  margin-left: auto;
  flex: none;
}

.tool-group-chevron {
  display: inline-flex;
  color: var(--fg-dim);
  flex: none;
  transition: transform var(--dur-med) var(--ease-in-out);
}
.tool-group-chevron--open { transform: rotate(180deg); }

/* Aufklappen: die Spur animieren, nie den Inhalt quetschen. */
.tool-group-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-med) var(--ease-in-out);
}
.tool-group.is-open .tool-group-body { grid-template-rows: 1fr; }

.tool-group-body-inner { overflow: hidden; }

.tool-group-body-content {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: 0 var(--sp-2) var(--sp-2);
}

@media (prefers-reduced-motion: reduce) {
  .tool-group-body { transition: none; }
  .tool-group-chevron { transition: none; }
}


/*  AiCanvas — Artefakt-Host. Portiert aus DrylAiCanvas.razor.css (Agents-Paket,
    wwwroot/.razor.css liegt NICHT in dryl.css). Nur Tokens; die glass-card-Basis
    (Hintergrund, Rahmen, Radius, Backdrop-filter) kommt aus dryl.css. Die
    ::deep-Selektoren der Scoped-CSS sind zu flachen Klassen aufgelöst, weil im
    Glashaus keine Blazor-Style-Isolation greift. */

.ai-canvas {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.canvas-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--line);
}

.canvas-title {
  color: var(--fg);
  font-weight: 600;
}

.canvas-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-4);
  overflow: auto;
}

/* Visuell versteckt, aber von Screenreadern vorgelesen (1px-Clip-Muster). */
.canvas-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Titel eines card-Knotens im Artefakt (Upstream: ::deep .canvas-card-title). */
.canvas-card-title {
  color: var(--fg);
  font-weight: 600;
  margin-bottom: var(--sp-2);
}


/* ============================================================================
   HandoffTrace — Zeitleiste eines Multi-Agenten-Laufs (portiert aus
   DRYL.Components.Agents/Agents/DrylHandoffTrace.razor.css). Diese Styles
   liegen im Upstream im Agents-Paket (scoped .razor.css) und NICHT in
   dryl.css — darum hier isoliert übernommen. Knoten/Icons/Badge/AiIndicator
   und die ai-aura*-Vokabeln stammen unverändert aus dryl.css.

   Blazor-CSS-Isolation nutzt "::deep" für Kind-Komponenten; in der
   Vanilla-Fassung sind das schlichte Nachfahren-Selektoren.
   ============================================================================ */

.handoff-trace {
  display: flex;
  flex-direction: column;
}

/* Eine Spur je Agent: Schiene (Konnektor + Knoten) neben dem Glaskörper. */
.handoff-step {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--sp-3);
  animation: handoff-enter var(--dur-med) var(--ease-out) backwards;
}

@keyframes handoff-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* Zustands-Marker der Spur (StepCss im Upstream): das Sichtbare hängt am
   Knoten (.handoff-node--*) bzw. Körper — die Spur-Klasse selbst ist nur ein
   Styling-Hook. --failed trägt zusätzlich die Körper-Randfarbe (siehe unten). */
.handoff-step--active,
.handoff-step--done { /* Hook — Styling über .handoff-node--active/--done */ }

/* ── Schiene: Konnektor-Linie + nummerierter Knoten ─────────── */

.handoff-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.handoff-connector {
  width: 1px;
  flex: 0 0 var(--sp-5);
  background: var(--line-strong);
  transition: background var(--dur-slow) var(--ease-in-out);
}

/* Der Staffelstab ist übergeben — die Linie nimmt den Akzent auf. */
.handoff-connector--done {
  background: var(--accent-line);
}

.handoff-node {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--sp-6);
  height: var(--sp-6);
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  background: var(--glass-1);
  color: var(--fg-dim);
  font-size: 11px;
  font-weight: 600;
  transition:
    border-color var(--dur-med) var(--ease-out),
    color var(--dur-med) var(--ease-out),
    box-shadow var(--dur-med) var(--ease-out),
    transform var(--dur-med) var(--ease-spring);
}

.handoff-node--active {
  border-color: var(--accent-line);
  color: var(--fg);
  box-shadow: 0 0 12px var(--accent-soft);
  transform: scale(1.08);
}

.handoff-node--done {
  border-color: var(--accent-line);
  color: var(--accent-b);
}

.handoff-node--failed {
  border-color: var(--danger);
  color: var(--danger);
}

/* ── Körper: Glasspur mit Kopf, Nutzung, Fehler, Inhalt ─────── */

.handoff-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  margin-bottom: var(--sp-2);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--glass-1);
  transition: border-color var(--dur-med) var(--ease-out);
}

.handoff-step--failed .handoff-body {
  border-color: color-mix(in srgb, var(--danger) 35%, transparent);
}

.handoff-step:last-child .handoff-body {
  margin-bottom: 0;
}

.handoff-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.handoff-name {
  color: var(--fg);
  font-weight: 600;
}

/* Status-Wechsel (Pending → Running → Done/Failed) blenden ein, ohne zu springen. */
.handoff-status .badge,
.handoff-status .ai-indicator {
  animation: handoff-status-in var(--dur-fast) var(--ease-out) both;
}

@keyframes handoff-status-in {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: none; }
}

.handoff-content {
  color: var(--fg-muted);
}

/* Nebenläufiger Fan-out: Spuren stehen einzeln, getrennt statt verbunden. */
.handoff-trace--concurrent .handoff-step + .handoff-step {
  margin-top: var(--sp-2);
}

@media (prefers-reduced-motion: reduce) {
  .handoff-step,
  .handoff-status .badge,
  .handoff-status .ai-indicator {
    animation: none;
  }

  .handoff-node,
  .handoff-connector,
  .handoff-body {
    transition: none;
  }

  .handoff-node--active {
    transform: none;
  }
}


/* ── DrylAiField ─────────────────────────────────────────────────────────
   ✨-Auslöser-Saum um ein bestehendes Textfeld: Review-Chips, Mini-Prompt-
   Zeile und versteckte Live-Region. Portiert aus
   DRYL.Components.Agents/Field/DrylAiField.razor.css (Agents-Paket, liegt
   NICHT in dryl.css). Nur Tokens. Ring/Halo/Bloom (.ai-aura*), Feld
   (.textarea-wrapper/.input), Button und Popover kommen unverändert aus
   dryl.css bzw. dryl-erweitert.css. `::deep .field` wurde zum normalen
   Nachfahren-Selektor .ai-field-prompt .field (kein Blazor-Scope hier). */

.ai-field {
  position: relative;
  display: block;
}

.ai-field-host {
  position: relative;
}

/* ✨-Auslöser: blendet bei :hover / :focus-within ein und bleibt sichtbar,
   solange ein Lauf läuft oder ein Vorschlag geprüft wird (.ai-field--on). */
.ai-field-trigger {
  position: absolute;
  top: var(--sp-2);
  right: var(--sp-2);
  z-index: 2;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.ai-field:hover .ai-field-trigger,
.ai-field:focus-within .ai-field-trigger,
.ai-field--on .ai-field-trigger {
  opacity: 1;
  transform: scale(1);
}

/* Mini-Prompt-Zeile (rendert im portalten Popover-Panel). */
.ai-field-prompt {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 280px;
}

.ai-field-prompt .field {
  flex: 1;
}

/* Übernehmen / Verwerfen. */
.ai-field-review {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding-top: var(--sp-2);
}

.ai-field-error {
  margin-top: var(--sp-1);
}

/* Visuell versteckte aria-live-Region. */
.ai-field-live {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .ai-field-trigger {
    transition: none;
  }
}
