/* 
 * Library Cards - Poetry Studio Pro
 * Unified card styling matching library-cards.js structure
 */

/* ============================================================
   GRID LAYOUT
   ============================================================ */

.content-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 20px;
    padding: 20px;
}

/* ============================================================
   BASE CARD STRUCTURE
   ============================================================ */

.unified-card {
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    height: 360px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.4);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    cursor: pointer;
    background: rgba(30,30,30,0.8);
}

.unified-card:hover {
    transform: translateY(-4px);
    box-shadow: 
        0 0 20px rgba(102, 126, 234, 0.5),
        0 0 40px rgba(102, 126, 234, 0.3),
        0 12px 24px rgba(0,0,0,0.6);
}

.card-inner {
    position: relative;
    width: 100%;
    height: 100%;
}

/* ============================================================
   SELECTION CHECKBOX
   ============================================================ */

.card-selector {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 24px;
    height: 24px;
    cursor: pointer;
    z-index: 10;
    accent-color: #667eea;
    opacity: 0.7;
    transition: opacity 0.2s;
}

.card-selector:hover {
    opacity: 1;
}

.unified-card:hover .card-selector {
    opacity: 1;
}

/* ============================================================
   BUILD ORDER BADGE — v2 Build composition §3
   Numbered badge 1, 2, 3, ... appears top-left on visual cards
   when user is scoped INTO a Build container. Indicates slideshow
   play order. Build-tier emerald accent matches container color.
   ============================================================ */

.build-order-badge {
    position: absolute;
    top: 12px;
    left: 12px;
    min-width: 28px;
    height: 28px;
    padding: 0 8px;
    border-radius: 14px;
    background: linear-gradient(135deg, #10b981 0%, #059669 100%);
    color: white;
    font-size: 14px;
    font-weight: 700;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid rgba(255, 255, 255, 0.85);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
    z-index: 10;
    pointer-events: auto;
    user-select: none;
    /* Variable-width — single digit fits in 28px, double digits expand
       smoothly to ~36px, triple digits to ~44px. Tabular-nums keeps the
       digits aligned for clean visual stacking. */
    font-variant-numeric: tabular-nums;
    /* 2026-06-09: badge is now a <button> (click to remove from build).
       Reset native button chrome so it stays visually a badge. */
    cursor: default;
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
    line-height: 1;
}

/* Clickable variant — tapping removes the asset from the current Build.
   Hover/focus shifts toward a red "remove" cue and shows an × so the
   deselect affordance is discoverable without a tooltip. */
.build-order-badge--clickable {
    cursor: pointer;
    transition: background 120ms ease, transform 80ms ease, box-shadow 120ms ease;
}
.build-order-badge--clickable:hover,
.build-order-badge--clickable:focus-visible {
    background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%);
    transform: scale(1.08);
    box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
    outline: none;
}
.build-order-badge--clickable:hover::after,
.build-order-badge--clickable:focus-visible::after {
    content: '×';
    position: absolute;
    top: -6px;
    right: -6px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #b91c1c;
    color: #fff;
    font-size: 12px;
    line-height: 16px;
    text-align: center;
    border: 1.5px solid rgba(255, 255, 255, 0.9);
}
.build-order-badge--clickable:active {
    transform: scale(0.96);
}

/* When card is being dragged to reorder, badge fades to indicate the
   number is about to change (visual confirmation that drag will
   reshuffle the play order). */
.unified-card.dragging .build-order-badge {
    opacity: 0.5;
    transform: scale(0.92);
    transition: opacity 100ms ease, transform 100ms ease;
}

/* Reorder drop indicators — left/right vertical lines on the target
   card showing where the dropped card will land. Build-tier emerald
   to match the badge so the user sees a single coherent color story
   for "this is a Build interaction". */
.unified-card.reorder-target-left {
    box-shadow: inset 4px 0 0 0 #10b981, 0 0 12px rgba(16, 185, 129, 0.5);
    transition: box-shadow 60ms ease;
}
.unified-card.reorder-target-right {
    box-shadow: inset -4px 0 0 0 #10b981, 0 0 12px rgba(16, 185, 129, 0.5);
    transition: box-shadow 60ms ease;
}

/* ============================================================
   THUMBNAIL BACKGROUNDS
   ============================================================ */

.card-thumbnail-video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease, filter 0.3s ease;
    filter: brightness(0.7);
}

.unified-card:hover .card-thumbnail-video {
    transform: scale(1.05);
    filter: brightness(0.5);
}

.card-thumbnail {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: hidden;
}

.card-thumbnail img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease, filter 0.3s ease;
    filter: brightness(0.7);
}

.unified-card:hover .card-thumbnail img {
    transform: scale(1.05);
    filter: brightness(0.5);
}

/* ============================================================
   DARK GRADIENT OVERLAY
   ============================================================ */

.card-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: transparent;
    z-index: 1;
    transition: opacity 0.3s;
}

/* ============================================================
   CONTENT LAYER
   ============================================================ */

.card-content-layer {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    padding: 20px;
}

/* ============================================================
   BADGES (TOP)
   ============================================================ */

.card-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    transition: opacity 0.3s;
}

.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    background: rgba(0,0,0,0.25);
    border-radius: 4px;
    backdrop-filter: blur(6px);
    font-size: 0.85rem;
    color: rgba(255,255,255,0.95);
}

/* AI provenance indicator — faint sparkle on AI-generated cards.
   Low visual weight per spec: visible at a glance but not loud.
   Tooltip on hover ("AI generated") gives full context. */
.badge-ai {
    display: inline-flex;
    align-items: center;
    padding: 4px 8px;
    background: rgba(139, 92, 246, 0.18);
    border: 1px solid rgba(139, 92, 246, 0.35);
    border-radius: 4px;
    font-size: 0.85rem;
    color: rgba(200, 180, 255, 0.85);
    opacity: 0.7;
    pointer-events: auto;
}
.badge-ai:hover {
    opacity: 1;
}

/* Play-voice affordance on poem cards (2026-05-18). Looks like a
 * badge to fit the card-badges row, behaves like a button: cursor
 * pointer, hover lift, a touch of green to read as "playable" vs
 * the neutral info badges (📝 49 words, 📅 May 18). Single-click
 * plays/pauses in place via LibraryCards.playAudio. Per Roughy:
 * "poem card should allow click to play in place. play, stop on
 * the card without shifting the library." */
button.badge-play-voice {
    background: rgba(16, 185, 129, 0.22);
    border: 1px solid rgba(16, 185, 129, 0.45);
    color: rgba(110, 231, 183, 1);
    cursor: pointer;
    font-family: inherit;
    line-height: 1;
    transition: background 0.12s ease, transform 0.08s ease;
}
button.badge-play-voice:hover {
    background: rgba(16, 185, 129, 0.32);
    transform: translateY(-1px);
}
button.badge-play-voice:active {
    transform: translateY(0);
}
button.badge-play-voice:focus-visible {
    outline: 2px solid rgba(16, 185, 129, 0.6);
    outline-offset: 1px;
}

/* ============================================================
   CARD BOTTOM (TITLE + ACTIONS)
   ============================================================ */

.card-bottom {
    margin-top: auto;
}

.card-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0 0 12px 0;
    color: white;
    text-shadow: 2px 2px 8px rgba(0,0,0,0.9);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ============================================================
   TAG PILLS — v2 §13.7
   Asset cards display top 3 tags inline below badges. Source-distinguishing
   marker prefix indicates origin: ◆ container-derived, ▲ AI, no marker = user.
   ============================================================ */

.card-tag-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0 0 8px 0;
    max-height: 50px;
    overflow: hidden;
}

.tag-pill {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.4;
    background: rgba(20, 20, 20, 0.7);
    color: rgba(255, 255, 255, 0.9);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    max-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tag-pill-marker {
    font-size: 9px;
    opacity: 0.85;
    line-height: 1;
}

/* User tags — full opacity, neutral. The user's own intent. */
.tag-pill-user {
    background: rgba(124, 58, 237, 0.45);
    border-color: rgba(168, 85, 247, 0.4);
}

/* Container tags — softer, indigo tint matching collection accent.
   Visually lower-priority because they're auto-derived. */
.tag-pill-container {
    background: rgba(99, 102, 241, 0.30);
    border-color: rgba(99, 102, 241, 0.35);
    color: rgba(255, 255, 255, 0.78);
}
.tag-pill-container .tag-pill-marker {
    color: rgba(199, 210, 254, 0.95);
}

/* AI tags — emerald tint, forward-compat for U-AI-AUTO-TAG. */
.tag-pill-ai {
    background: rgba(16, 185, 129, 0.30);
    border-color: rgba(16, 185, 129, 0.40);
    color: rgba(220, 252, 231, 0.95);
}
.tag-pill-ai .tag-pill-marker {
    color: rgba(167, 243, 208, 1);
}

/* Overflow pill — clickable look, indicates more on hover */
.tag-pill-overflow {
    background: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.7);
    cursor: help;
    font-weight: 600;
}

/* V2 (May 5 2026, tag-pills-mvp) — per-pill ✕ remove button.
   Hidden by default, slides in on hover (desktop) or always visible
   on touch devices (no hover state). Tapping detaches that one tag
   from that one asset. Only rendered on user-source tags on assets
   the current user owns. */
.tag-pill-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    margin-left: 2px;
    padding: 0;
    border: none;
    background: rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.85);
    border-radius: 50%;
    cursor: pointer;
    font-size: 10px;
    line-height: 1;
    font-weight: 600;
    opacity: 0;
    transform: scale(0.8);
    transition: opacity 0.12s ease, transform 0.12s ease, background 0.12s ease;
}
.tag-pill:hover .tag-pill-remove {
    opacity: 1;
    transform: scale(1);
}
.tag-pill-remove:hover {
    background: rgba(239, 68, 68, 0.85);
    color: white;
}
/* Touch / no-hover devices — always show, smaller scale */
@media (hover: none) {
    .tag-pill-remove {
        opacity: 0.7;
        transform: scale(0.95);
    }
}

/* Poem cards have light background — invert pill colors */
.unified-card.poem-card .tag-pill {
    background: rgba(74, 58, 32, 0.18);
    color: rgba(74, 58, 32, 0.85);
    border-color: rgba(74, 58, 32, 0.20);
}
.unified-card.poem-card .tag-pill-user {
    background: rgba(124, 58, 237, 0.20);
    color: rgba(76, 29, 149, 0.95);
    border-color: rgba(124, 58, 237, 0.30);
}
.unified-card.poem-card .tag-pill-container {
    background: rgba(99, 102, 241, 0.18);
    color: rgba(55, 48, 163, 0.85);
}
.unified-card.poem-card .tag-pill-ai {
    background: rgba(16, 185, 129, 0.20);
    color: rgba(6, 78, 59, 0.95);
}

/* Mobile — tighten spacing */
@media (max-width: 768px) {
    .card-tag-pills {
        gap: 3px;
        margin-bottom: 6px;
        max-height: 22px;  /* one row only on phone */
    }
    .tag-pill {
        font-size: 10px;
        padding: 1px 6px;
    }
}

/* ============================================================
   ACTION BUTTONS
   ============================================================ */

.card-actions {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
    background: rgba(0,0,0,0.2);
    backdrop-filter: blur(6px);
    margin: 0 -20px -20px -20px;
    padding: 10px 14px;
    transition: opacity 0.3s;
}

.action-btn {
    background: rgba(255,255,255,0.22);
    border: 1px solid rgba(255,255,255,0.32);
    padding: 6px 10px;
    border-radius: 6px;
    color: white;
    cursor: pointer;
    font-size: 1rem;
    transition: all 0.2s ease;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    flex-shrink: 0;
    min-width: 34px;
    /* Backdrop blur keeps the buttons legible against any card
       gradient (purple shared, indigo private, cyan collection)
       without each button needing per-context tuning. */
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

.action-btn:hover {
    background: rgba(255,255,255,0.38);
    border-color: rgba(255,255,255,0.55);
    transform: scale(1.1);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}

.action-btn.danger {
    border-color: rgba(239, 68, 68, 0.6);
}

.action-btn.danger:hover {
    background: rgba(239, 68, 68, 0.32);
    border-color: rgb(239, 68, 68);
}

/* Armed state — when the user has tapped a destructive button once
   and we're waiting for the second tap to commit. Renders an in-place
   "Tap again to delete" pill at the click site rather than putting the
   confirmation in a corner toast. The button width grows to fit the
   label; a brief pulse animation draws the eye to where the action is.
   Added 2026-05-15 per Roughy's inline-confirm-at-action-point
   direction. */
.action-btn.delete-armed {
    width: auto;
    padding: 4px 10px;
    background: rgba(239, 68, 68, 0.28);
    border-color: rgb(239, 68, 68);
    color: white;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.2px;
    white-space: nowrap;
    animation: armed-pulse 0.8s ease-in-out infinite alternate;
}

.action-btn.delete-armed .armed-label {
    display: inline-block;
}

@keyframes armed-pulse {
    from { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
    to   { box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.18); }
}

/* ============================================================
   VIDEO PLAYER (FULLSCREEN MODE)
   ============================================================ */

.card-video-player {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 50;
    display: none;
}

/* ============================================================
   TEXT CARDS (POEMS)
   ============================================================ */

.unified-card.text-card {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.unified-card.text-card .card-content-layer {
    display: flex;
    flex-direction: column;
    padding: 16px;
    height: 100%;
    box-sizing: border-box;
}

.unified-card.text-card .card-badges {
    margin-bottom: 8px;
}

.poem-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0 0 10px 0;
    color: white;
    text-shadow: 1px 1px 4px rgba(0,0,0,0.5);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.poem-text-area {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    margin-bottom: 12px;
    padding-right: 8px;
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.3) transparent;
}

.poem-text-area::-webkit-scrollbar {
    width: 6px;
}

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

.poem-text-area::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,0.3);
    border-radius: 3px;
}

.poem-preview {
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 0.9rem;
    line-height: 1.5;
    color: rgba(255,255,255,0.95);
    white-space: pre-wrap;
    word-wrap: break-word;
    margin: 0;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.4);
}

.poem-actions {
    background: rgba(0,0,0,0.2);
    backdrop-filter: blur(6px);
    margin: 0 -16px -16px -16px;
    padding: 10px 16px;
    border-radius: 0 0 12px 12px;
}

/* ============================================================
   AUDIO CARDS (VOICE/MUSIC)
   ============================================================ */

.unified-card.audio-card {
    background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}

.unified-card.audio-card .card-content-layer {
    position: relative;
}

.unified-card.audio-card .card-title {
    text-shadow: 1px 1px 4px rgba(0,0,0,0.5);
}

.card-audio-player {
    width: 100%;
    margin: 15px 0;
    border-radius: 8px;
    background: rgba(0,0,0,0.3);
}

.card-audio-player::-webkit-media-controls-panel {
    background: rgba(0,0,0,0.6);
}

.unified-card.audio-card .card-actions {
    background: transparent;
    backdrop-filter: none;
    margin: 15px 0 0 0;
    padding: 0;
}

/* ============================================================
   IMAGE CARDS
   ============================================================ */

.unified-card.image-card .card-thumbnail img {
    filter: brightness(0.6);
}

.unified-card.image-card:hover .card-thumbnail img {
    filter: brightness(0.4);
}

/* ============================================================
   MEDIA MODALS (FULLSCREEN VIEW)
   ============================================================ */

.media-modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: fadeIn 0.2s ease;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.modal-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.95);
    cursor: pointer;
}

.modal-content {
    position: relative;
    z-index: 10001;
    max-width: 95vw;
    max-height: 95vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
}

.modal-close {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 40px;
    height: 40px;
    background: rgba(255,255,255,0.9);
    border: none;
    border-radius: 50%;
    color: #333;
    font-size: 1.5rem;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 300;
    z-index: 10002;
}

.modal-close:hover {
    background: white;
    transform: scale(1.1);
}

.modal-content img,
.modal-content video {
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.5);
    max-width: 100%;
    max-height: 100%;
}

.modal-content h2 {
    margin: 0 0 20px 0;
    text-align: center;
    color: white;
}

/* ============================================================
   LOADING/EMPTY STATES
   ============================================================ */

.empty-state,
.loading-state,
.error-state {
    text-align: center;
    padding: 60px 20px;
    color: #999;
    font-size: 1.1rem;
    grid-column: 1 / -1;
}

.error-state {
    color: #ef4444;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (max-width: 768px) {
    .content-grid {
        grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
        gap: 15px;
        padding: 15px;
    }

    .unified-card {
        height: 320px;
    }

    .card-title {
        font-size: 1rem;
    }

    .action-btn {
        font-size: 1rem;
        padding: 6px 10px;
        min-height: 44px;
    }

    .badge {
        font-size: 0.75rem;
        padding: 3px 8px;
    }
}

@media (max-width: 480px) {
    .content-grid {
        grid-template-columns: 1fr;
    }

    .unified-card {
        height: 300px;
    }

    .card-actions {
        flex-wrap: wrap;
        justify-content: center;
    }
}

/* ============================================================
   CONTAINER CARDS (collections + projects)
   Spec: FEATURE-LIBRARY-CONTAINER-CARDS-SPEC.md §10
   Visual distinction from asset cards: glyph top-left, framed
   thumbnail (inset shadow), subtle tint by purpose, no checkbox.
   ============================================================ */

.container-card {
    /* Subtle inset frame makes the cover image read as a "picture
       inside a folder" rather than edge-to-edge playable content.
       Double box-shadow: existing outer + a soft inner border.
    */
    box-shadow:
        0 4px 12px rgba(0,0,0,0.4),
        inset 0 0 0 1px rgba(255,255,255,0.08),
        inset 0 0 0 6px rgba(0,0,0,0.15);
}

.container-card:hover {
    /* Different hover glow tint per purpose — cyan-green for collection,
       purple for project — matches the fallback gradient backgrounds.
    */
    transform: translateY(-4px);
    box-shadow:
        0 12px 24px rgba(0,0,0,0.6),
        inset 0 0 0 1px rgba(255,255,255,0.15),
        inset 0 0 0 6px rgba(0,0,0,0.2);
}

.container-card.collection-card:hover {
    box-shadow:
        0 0 20px rgba(8, 145, 178, 0.45),
        0 0 40px rgba(5, 150, 105, 0.25),
        0 12px 24px rgba(0,0,0,0.6),
        inset 0 0 0 1px rgba(255,255,255,0.15),
        inset 0 0 0 6px rgba(0,0,0,0.2);
}

.container-card.project-card:hover {
    box-shadow:
        0 0 20px rgba(124, 58, 237, 0.45),
        0 0 40px rgba(79, 70, 229, 0.25),
        0 12px 24px rgba(0,0,0,0.6),
        inset 0 0 0 1px rgba(255,255,255,0.15),
        inset 0 0 0 6px rgba(0,0,0,0.2);
}

/* Large glyph top-left — always visible, semi-transparent.
   Communicates "this is a container" at a glance. */
.container-glyph {
    position: absolute;
    top: 10px;
    left: 14px;
    font-size: 28px;
    line-height: 1;
    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.6));
    opacity: 0.95;
    z-index: 2;
    pointer-events: none;
}

/* Share-state indicators (🌐 public, 🔗 share-link) — top-right corner,
   where asset cards have their checkbox. Container cards have no
   checkbox (see rule below), so this area is free. */
.container-indicators {
    position: absolute;
    top: 10px;
    right: 12px;
    display: flex;
    gap: 4px;
    z-index: 2;
    pointer-events: none;
}

.container-share-indicator {
    font-size: 16px;
    background: rgba(0, 0, 0, 0.45);
    border-radius: 6px;
    padding: 2px 6px;
    backdrop-filter: blur(8px);
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));
}

/* Container cards are not bulk-selectable — bulk operates on assets
   only. Hiding the checkbox entirely (not just opacity:0) prevents
   stray clicks and keeps the top-right area clean for indicators. */
.container-card .card-selector {
    display: none !important;
}

/* Mobile tap-target compliance for action buttons inside container
   cards. The base .action-btn rule already lives above; the container
   context just needs them to stay ≥44px at iPhone widths. */
@media (max-width: 480px) {
    .container-card .action-btn {
        min-height: 44px;
        min-width: 44px;
    }

    .container-glyph {
        font-size: 24px;
    }

    .container-share-indicator {
        font-size: 14px;
    }
}

/* ============================================================
   CONTAINER CARDS v2 (session 14)
   - "Project" / "Collection" label row
   - Per-type asset breakdown chips
   - Drag-drop target states
   ============================================================ */

.container-label {
    text-transform: uppercase;
    letter-spacing: 1.4px;
    font-size: 10px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.65);
    margin-bottom: 2px;
}

.container-counts {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.8);
    margin-bottom: 4px;
}

.container-type-breakdown {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.9);
    margin-bottom: 8px;
}

.container-type-breakdown .type-count {
    background: rgba(0, 0, 0, 0.35);
    padding: 2px 6px;
    border-radius: 4px;
    white-space: nowrap;
    backdrop-filter: blur(4px);
}

.container-type-breakdown .type-count-more {
    font-style: italic;
    opacity: 0.75;
}

/* Drag source feedback */
.unified-card.is-dragging {
    opacity: 0.4;
    cursor: grabbing;
    transform: scale(0.98);
}

/* Sticky target container — emerald ring (Apr 26, 2026 / commit C2).
 * Single-click sets a Project / Sub-project / Build as the target for
 * subsequent bulk operations like "Add to Project". Distinct from
 * drop-target (purple, transient hover) — this state persists across
 * navigation until cleared. */
.container-card.is-target {
    outline: 2px solid #10b981;
    outline-offset: -2px;
    box-shadow:
        0 0 24px rgba(16, 185, 129, 0.45),
        0 8px 16px rgba(0,0,0,0.5),
        inset 0 0 0 1px rgba(16, 185, 129, 0.3);
}

/* Small 🎯 badge in the top-right corner so the target card is
 * immediately scannable in a grid. Only renders when is-target is on. */
.container-card.is-target::after {
    content: '🎯';
    position: absolute;
    top: 8px;
    right: 8px;
    width: 24px;
    height: 24px;
    background: rgba(16, 185, 129, 0.95);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.4);
    pointer-events: none;
    z-index: 5;
}

/* Drop target feedback — valid drop (owner, container) */
.container-card.drop-target {
    outline: 3px solid #a78bfa;
    outline-offset: -3px;
    transform: scale(1.03);
    transition: transform 0.15s ease, outline-color 0.15s ease;
    box-shadow:
        0 0 32px rgba(167, 139, 250, 0.65),
        0 12px 24px rgba(0,0,0,0.6),
        inset 0 0 0 1px rgba(255,255,255,0.15);
}

/* Drop target feedback — forbidden (not owned) */
.container-card.drop-forbidden {
    outline: 3px dashed rgba(239, 68, 68, 0.7);
    outline-offset: -3px;
    cursor: not-allowed;
    box-shadow:
        0 0 24px rgba(239, 68, 68, 0.35),
        0 12px 24px rgba(0,0,0,0.6);
}

@media (max-width: 480px) {
    .container-type-breakdown {
        font-size: 10px;
    }
    .container-type-breakdown .type-count {
        padding: 1px 5px;
    }
}

/* ============================================================
   CONTAINER CARDS v3 (session 14)
   - Poem snippet quoted block (projects only)
   - Owner line ("from Alice")
   - "Updated X ago" line
   - Amplified share badge strip (labeled, not just emoji)
   - Breathing room for type pills
   - Shared-state ring (subtle cue beyond the gradient)
   ============================================================ */

/* Middle-of-card poem snippet — italic quoted block. Only rendered for
   projects that have at least one poem. Text color is light over the
   gradient; adds visual weight and reminds user what this project is. */
.container-snippet {
    font-style: italic;
    font-size: 13px;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.88);
    padding: 12px 14px;
    margin: 16px 14px 0;
    background: rgba(0, 0, 0, 0.28);
    border-left: 3px solid rgba(255, 255, 255, 0.5);
    border-radius: 4px;
    backdrop-filter: blur(6px);
    max-height: 4.2em;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

.container-owner-line {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.65);
    font-style: italic;
    margin-bottom: 1px;
}

.container-updated-line {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.55);
    margin-bottom: 6px;
}

/* Amplified share strip — labeled badges, more readable than the corner
   emoji-only cue. Shown below the updated line, above the count. */
.container-share-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 4px 0 8px;
}

.share-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 10.5px;
    font-weight: 500;
    padding: 2px 8px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.18);
    color: #ffffff;
    letter-spacing: 0.3px;
    backdrop-filter: blur(6px);
    white-space: nowrap;
}

.share-badge.share-public { background: rgba(16, 185, 129, 0.35); }   /* emerald */
.share-badge.share-link   { background: rgba(59, 130, 246, 0.35); }   /* blue */
.share-badge.share-with   { background: rgba(244, 114, 182, 0.35); }  /* pink */

/* Origin pill — provenance for non-owned containers. Tells the user
   "this card is here because someone shared it (or made it public),"
   which makes the missing share / delete buttons read as intentional
   rather than a bug. Sits above the share strip so it's the first
   thing the eye lands on after the card title. Colors picked to
   avoid clashing with the existing emerald/blue/pink share-badge
   palette: amber for direct grant, sky for public discovery. */
.container-origin-pill {
    display: inline-block;
    font-size: 10.5px;
    font-weight: 500;
    padding: 2px 9px;
    border-radius: 10px;
    color: #ffffff;
    letter-spacing: 0.3px;
    backdrop-filter: blur(6px);
    margin: 4px 0 6px;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
.container-origin-pill.origin-shared { background: rgba(245, 158, 11, 0.45); }  /* amber-500 */


/* Container-shared ring: subtle extra outline so even when two cards
   are similar shades, the shared one has a visible 'glow'. Purely
   additive to the gradient swap — reinforces without being loud. */
.container-card.container-shared {
    box-shadow:
        0 0 0 1px rgba(167, 139, 250, 0.4),
        0 4px 12px rgba(0,0,0,0.4),
        inset 0 0 0 1px rgba(255,255,255,0.08),
        inset 0 0 0 6px rgba(0,0,0,0.15);
}

.container-card.container-shared:hover {
    box-shadow:
        0 0 24px rgba(139, 92, 246, 0.55),
        0 0 40px rgba(109, 40, 217, 0.25),
        0 12px 24px rgba(0,0,0,0.6),
        inset 0 0 0 1px rgba(255,255,255,0.15),
        inset 0 0 0 6px rgba(0,0,0,0.2);
}

/* More breathing room for type pills (user asked for spaced-out chips). */
.container-type-breakdown {
    gap: 6px;        /* was 4 */
    margin-top: 2px;
    margin-bottom: 10px;  /* was 8 */
}

.container-type-breakdown .type-count {
    padding: 3px 8px;  /* was 2x6 */
    font-size: 11.5px;
}

@media (max-width: 480px) {
    .container-snippet {
        font-size: 12px;
        padding: 10px 12px;
        margin: 10px 10px 0;
        -webkit-line-clamp: 2;
    }
    .share-badge { font-size: 10px; padding: 1px 6px; }
}

/* ============================================================
   CONTAINER CARDS v4 (session 14 — two-zone layout)
   User feedback: snippet text over colorful cover images was
   unreadable. Fix: split card into top-zone (cover, muted) and
   bottom-zone (solid color, all text). Everything readable
   lives on solid gradient; cover is decorative only.
   ============================================================ */

.container-card {
    /* Flex column — top-zone + bottom-zone stack vertically, each
       taking a share of the card height. Existing .unified-card
       has height set; we just organize the interior. */
    display: flex;
    flex-direction: column;
    padding: 0;            /* zones manage their own padding */
    overflow: hidden;      /* so the cover image can't bleed past rounded corners */
}

/* TOP ZONE — cover image or just a lighter tint of the card gradient.
   Fixed percentage of card height so layout is predictable. Image is
   muted (darkened + desaturated) so text in the bottom zone is clearly
   the protagonist, not fighting with a vivid photo. */
.container-top-zone {
    position: relative;
    height: 40%;           /* 40/60 split favors content over decoration */
    min-height: 90px;
    flex-shrink: 0;
    background-color: rgba(0, 0, 0, 0.12);  /* slight darken if no cover */
    overflow: hidden;
}

/* Note (Apr 25 2026): an earlier attempt grew .collection-card's top
   zone to 48% / 110px to give the promoted headline more room — but
   the parent .unified-card has fixed height: 360px and overflow:
   hidden, so growing the top zone squeezed the bottom zone and
   clipped the action bar (📁 🎬 🔗 🗑). The headline is absolute-
   positioned at bottom: 10px of the top zone — it lands cleanly at
   any zone height, so reverting fixes the clip with no UX downside. */

.container-top-zone.has-cover {
    /* Medium mute: 40% darken (via CSS gradient overlay in inline style)
       plus 70% saturation so colors are still recognizable but calmer.
       Mirrors user's "medium mute" selection. */
    filter: saturate(0.7);
}

.container-top-zone .container-glyph {
    position: absolute;
    top: 10px;
    left: 14px;
    font-size: 32px;       /* slightly larger — it's the hero of the top zone */
    line-height: 1;
    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.75));
    z-index: 2;
    pointer-events: none;
}

.container-top-zone .container-indicators {
    position: absolute;
    top: 10px;
    right: 12px;
    display: flex;
    gap: 4px;
    z-index: 2;
    pointer-events: none;
}

/* Top-zone headline (collections only — Apr 25 2026).
   Promoted from the bottom zone so collections read as visually
   distinct from projects across the grid. Centered in the empty
   real estate below the glyph + indicators. The glyph stays in
   its top-left corner; the headline sits below and centered. */
.container-top-zone .container-top-headline {
    position: absolute;
    left: 14px;
    right: 14px;
    bottom: 10px;
    z-index: 1;
    pointer-events: none;
    text-align: left;
}

.container-top-zone .container-top-label {
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.78);
    margin-bottom: 2px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

.container-top-zone .container-top-title {
    font-size: 1.35rem;
    font-weight: 700;
    color: #ffffff;
    margin: 0;
    line-height: 1.15;
    letter-spacing: -0.2px;
    text-shadow: 0 2px 6px rgba(0, 0, 0, 0.55);
    /* Keep it to two lines max on long names — ellipsis at end. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}

/* BOTTOM ZONE — solid color, holds ALL text/pills/actions.
   This is where the card gets its semantic color (private vs shared).
   Text renders on clean background; no overlay/contrast drama. */
.container-bottom-zone {
    flex: 1 1 auto;
    padding: 12px 14px 10px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* Background inherits card gradient (set inline in style=""), so
       this zone is the card's color. Top zone has its own image or
       tint. Together they give a clean split. */
}

.container-bottom-zone .container-label {
    text-transform: uppercase;
    letter-spacing: 1.4px;
    font-size: 10px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    margin-bottom: 2px;
    text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

.container-bottom-zone .card-title {
    font-size: 1.05rem;
    font-weight: 600;
    margin: 0 0 2px;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0,0,0,0.4);
    line-height: 1.2;
}

/* Snippet sits in the bottom zone on the solid color — italic, quoted.
   Clean over the gradient, no background block needed. Add a subtle
   left-border to read as a quote without a heavy box. */
.container-bottom-zone .container-snippet {
    font-style: italic;
    font-size: 12.5px;
    line-height: 1.35;
    color: rgba(255, 255, 255, 0.92);
    padding: 4px 0 4px 10px;
    margin: 6px 0 4px;
    border-left: 3px solid rgba(255, 255, 255, 0.35);
    background: transparent;      /* override v3 dark block */
    backdrop-filter: none;
    border-radius: 0;
    max-height: 3.2em;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.container-bottom-zone .container-counts {
    font-size: 11.5px;
    color: rgba(255, 255, 255, 0.82);
    margin-top: 4px;
    text-shadow: 0 1px 1px rgba(0,0,0,0.2);
}

/* Owner line, updated line, share strip — no background blocks in
   the bottom zone; they read on solid color directly. */
.container-bottom-zone .container-owner-line,
.container-bottom-zone .container-updated-line {
    font-size: 10.5px;
    line-height: 1.25;
}

.container-bottom-zone .container-share-strip {
    margin: 3px 0 2px;
}

.container-bottom-zone .container-type-breakdown {
    margin-top: 4px;
    margin-bottom: 6px;
}

.container-bottom-zone .card-actions {
    margin-top: auto;       /* pin to bottom of zone */
    padding-top: 6px;
    /* v2 fix (April 27, 2026 — Roughy reported clipping on Project
       cards): the action row was getting squeezed off-card when the
       bottom-zone content grew (snippet + counts + type-breakdown).
       flex-shrink: 0 reserves space; the snippet's max-height is what
       absorbs overflow instead. min-height ensures even the empty
       case keeps room for icons. */
    flex-shrink: 0;
    min-height: 46px;        /* fits 34px button + 6px padding-top + breathing room */
}

/* Override v1/v2/v3 frame/shadow styles that were designed around
   a single-background card. Two-zone version doesn't need the
   inset frame — the top/bottom split is visual frame enough. */
.container-card {
    box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}

.container-card.collection-card:hover {
    box-shadow:
        0 0 20px rgba(8, 145, 178, 0.35),
        0 12px 24px rgba(0,0,0,0.6);
}

.container-card.project-card:hover {
    box-shadow:
        0 0 20px rgba(124, 58, 237, 0.35),
        0 12px 24px rgba(0,0,0,0.6);
}

.container-card.container-shared {
    box-shadow:
        0 0 0 1px rgba(167, 139, 250, 0.4),
        0 4px 12px rgba(0,0,0,0.4);
}

.container-card.container-shared:hover {
    box-shadow:
        0 0 24px rgba(139, 92, 246, 0.55),
        0 0 40px rgba(109, 40, 217, 0.25),
        0 12px 24px rgba(0,0,0,0.6);
}

@media (max-width: 480px) {
    .container-top-zone { min-height: 80px; height: 35%; }
    .container-top-zone .container-glyph { font-size: 26px; }
    .container-bottom-zone { padding: 10px 12px 8px; }
    .container-bottom-zone .container-snippet {
        font-size: 11.5px;
        -webkit-line-clamp: 2;
    }
}


/* ============================================================
   COLLECTION-SPECIFIC PILL (session 14 v6)
   Project-count pill on collection cards. Same .type-count chip
   family as asset-type pills, but visually distinct so it reads
   as container-of-containers not another asset type.
   ============================================================ */

.container-type-breakdown .type-count-project {
    /* Violet tint matches the "shared" purple in the shared-state
       gradient — semantically consistent: both carry meaning about
       structure (shared = relational, project-pill = hierarchical).
       Subtle white ring emphasizes it's a different category of count. */
    background: rgba(139, 92, 246, 0.45);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15) inset;
    font-weight: 600;
}


/* ============================================================
   AI GENERATION SECTION IN EDIT MODAL
   Appears inside editMedia modal when asset.is_ai_generated.
   Collapsible via native <details> element — matches Rule 12
   (no alerts/custom modals for progressive disclosure).
   ============================================================ */

.edit-ai-section {
    margin-top: 16px;
    padding: 12px;
    border-radius: 8px;
    border: 1px solid rgba(139, 92, 246, 0.25);
    background: rgba(139, 92, 246, 0.05);
}
.edit-ai-section summary {
    cursor: pointer;
    color: #c4b5fd;
    font-size: 0.9rem;
    font-weight: 600;
    user-select: none;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 6px;
}
.edit-ai-section summary::-webkit-details-marker { display: none; }
.edit-ai-section summary::before {
    content: "▸";
    transition: transform 0.15s;
    opacity: 0.6;
    font-size: 0.75rem;
}
.edit-ai-section[open] summary::before {
    transform: rotate(90deg);
}
.edit-ai-section-body {
    margin-top: 12px;
}
.edit-ai-section label {
    display: block;
    margin-bottom: 6px;
    color: #888;
    font-size: 0.85rem;
}
.edit-ai-section textarea {
    width: 100%;
    min-height: 72px;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid #333;
    background: #0f0f1e;
    color: white;
    box-sizing: border-box;
    font-family: inherit;
    resize: vertical;
}
.edit-ai-section .ai-source-line {
    margin-top: 8px;
    font-size: 0.75rem;
    color: rgba(255,255,255,0.4);
}
.edit-ai-regen-btn {
    margin-top: 10px;
    padding: 10px 16px;
    border-radius: 8px;
    border: none;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.9rem;
}
.edit-ai-regen-btn:hover { filter: brightness(1.1); }
.edit-ai-regen-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ============================================================
 * Cut card V2 (DESIGN-CUT-CARD-UNIFIED-V1.md §4.2, 2026-05-14)
 *
 * Two visual states for asset_type='clip' cards:
 *   .cut-card-draft     — no file_path; recipe-summary placeholder
 *   (the rendered state reuses the existing .unified-card video
 *    presentation, no new CSS needed)
 *
 * Plus a .cut-card-drop-target ring shown while an asset is being
 * dragged over a Cut card for drop-to-recipe.
 *
 * Flag-gated: only rendered when LibraryCards.cutModelV2Enabled().
 * ============================================================ */

.cut-card.cut-card-draft {
    display: flex;
    flex-direction: column;
    background: rgba(30, 30, 40, 0.85);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 10px;
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.15s ease, transform 0.1s ease;
}

.cut-card.cut-card-draft:hover {
    border-color: rgba(102, 126, 234, 0.6);
    transform: translateY(-1px);
}

.cut-card.cut-card-draft:focus-visible {
    outline: 2px solid #667eea;
    outline-offset: 2px;
}

.cut-card-thumb {
    aspect-ratio: 9 / 16;
    background-size: cover;
    background-position: center;
    background-color: rgba(255, 255, 255, 0.04);
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cut-card-thumb-placeholder {
    background: linear-gradient(135deg, rgba(102, 126, 234, 0.18), rgba(118, 75, 162, 0.18));
}

.cut-card-placeholder-glyph {
    font-size: 40px;
    opacity: 0.4;
    user-select: none;
}

.cut-card-state-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    padding: 3px 8px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.85);
    font-size: 11px;
    font-weight: 500;
    backdrop-filter: blur(4px);
    letter-spacing: 0.02em;
}

.cut-card-body {
    padding: 10px 12px 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.cut-card-title {
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cut-card-recipe-summary {
    color: rgba(224, 224, 224, 0.8);
    font-size: 11.5px;
    line-height: 1.35;
    word-break: break-word;
}

.cut-card-cta {
    color: rgba(102, 126, 234, 0.9);
    font-size: 11.5px;
    font-weight: 500;
    margin-top: 2px;
}

/* Drop-target ring while a draggable hovers over any Cut card */
.cut-card.cut-card-drop-target,
.unified-card.cut-card-drop-target {
    box-shadow:
        0 0 0 2px #667eea,
        0 0 24px rgba(102, 126, 234, 0.45);
    transform: scale(1.015);
    transition: transform 0.08s ease, box-shadow 0.12s ease;
}


/* ═══════════════════════════════════════════════════════════════════════
   LIBRARY REDESIGN V2 — compact container cards (2026-05-10)
   ═══════════════════════════════════════════════════════════════════════
   Per DESIGN-TIER-NAV-CONSOLIDATION-V1.md §0 Decision 5 and the V2 mock
   (mock/library-redesign-v2.html scenes 1-4): container cards should feel
   denser than asset cards — their job is "filing destination", not
   "rich content preview". The asset card grammar (thumbnail-as-background)
   stays as-is; only container cards tighten.
   
   Approach: additive overrides at the bottom of the cascade. We don't
   restructure the markup or remove existing features — we just dial
   down the visual weight and noise floor at idle. Action buttons,
   share badges, snippets all remain available; they just don't shout.
   
   Net effect:
   • Action button row hidden at rest, fades in on hover (was always-on)
   • Poem snippet hidden in containers (it was creating asymmetric
     heights between collections-with-poem vs collections-without)
   • Tighter padding in the bottom zone
   • Smaller, more disciplined typography on counts/updated lines
   ═════════════════════════════════════════════════════════════════════ */

/* The action-button row was always-on — five icon buttons in every
   container card created a busy stripe across the grid. Hide at rest;
   reveal on hover or focus-within. Keeps the actions discoverable
   (mouse over to see them) without making them ambient noise.
   
   Asset cards keep their always-on action row — those buttons are
   the asset-level "remove from container" and "share link" gestures
   which are central to the asset-card workflow. */
/* Container card actions — always visible. Originally Phase 2 (April
   2026) hid these on hover to reduce visual noise, but the regression
   was worse than the noise: users couldn't see what they could do with
   a container at a glance, while asset cards had always-on actions
   right next to them. Restored to symmetry 2026-05-15 EOD per Roughy.
   Asset cards keep their always-on action row — same row, same shape,
   container actions match. */
.container-card .card-actions {
    opacity: 1;
    pointer-events: auto;
}

/* Snippet text inside container cards: hidden. The snippet was a
   nice-to-have that broke grid coherence — when one project had a
   poem and the next didn't, their heights diverged and the grid
   looked irregular. Containers are filing destinations; the
   snippet doesn't help with that decision. */
.container-card .card-poem-snippet {
    display: none;
}

/* Type-breakdown row sat below the headline counts and added a
   second line of meta. The headline already says "3 projects · 47
   assets" — the breakdown ("12 images · 2 videos · ...") is detail
   that belongs in the scoped view, not the card preview. Hide. */
.container-card .container-type-breakdown {
    display: none;
}

/* Tighten the bottom zone padding so the card reads as denser.
   Existing rule has more generous padding for the rich-content
   look; we shrink it. */
.container-card .container-bottom-zone {
    padding: 10px 12px 12px 12px;
}

/* Smaller, calmer counts/updated typography — the meta lines feel
   less competitive with the name. */
.container-card .container-counts {
    font-size: 11px;
    opacity: 0.78;
    margin-top: 4px;
}
.container-card .container-updated-line {
    font-size: 10px;
    opacity: 0.55;
    margin-top: 2px;
}
.container-card .container-owner-line {
    font-size: 10.5px;
    opacity: 0.65;
}

/* Card title (project name) — slightly tighter line-height, no
   wholesale font size change so existing layouts still fit. */
.container-card .card-title {
    line-height: 1.25;
}
