/* ==================== Ox tech Ai IDP System - Main Styles ==================== */
:root {
    --primary-color: #4f6ef7;
    --primary-light: #eef1ff;
    --success-color: #10b981;
    --danger-color: #ef4444;
    --warning-color: #f59e0b;
    --info-color: #3b82f6;
    --light-color: #f8fafc;
    --dark-color: #1e293b;
}
body {
    font-family: 'Microsoft YaHei', 'Segoe UI', system-ui, sans-serif;
    background: linear-gradient(135deg, #f0f4ff 0%, #e6f0fa 100%);
    color: var(--dark-color);
    min-height: 100vh;
}
.logo {
    font-weight: 800;
    background: linear-gradient(135deg, var(--primary-color), #8b5cf6);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    font-size: 1.6rem;
}

/* Company logo image inside the navbar brand. Bumped from 1.6rem to
   2.4rem so the rendered mark is large enough to read crisply; the
   navbar's own padding still keeps the row compact. */
.navbar-brand-logo {
    height: 2.4rem;
    width: auto;
    vertical-align: -0.45rem;
}

/* Larger logo used in the About modal so it reads as the product mark. */
.about-modal-logo {
    height: 4.5rem;
    width: auto;
}
.card {
    /* Glassmorphism removed in Phase 6.2 — Bootstrap 5.3 default .card
       (solid white bg, 1px gray border, 6px border-radius, no shadow) now applies. */
}
.upload-area {
    border: 2px dashed var(--primary-color);
    border-radius: 20px;
    padding: 2.5rem 2rem;
    text-align: center;
    cursor: pointer;
    transition: all 0.3s ease;
    background: rgba(79,110,247,0.03);
    margin-bottom: 1.5rem;
    max-width: 100%;
    overflow-x: hidden;
}
.upload-area:hover, .upload-area.drag-over {
    background: rgba(79,110,247,0.06);
    border-color: #1d4ed8;
    transform: translateY(-2px);
}
.upload-icon {
    font-size: 3.2rem;
    color: var(--primary-color);
    margin-bottom: 1rem;
    filter: drop-shadow(0 4px 6px rgba(79,110,247,0.2));
}
.progress-bar {
    height: 8px;
    border-radius: 4px;
    background: linear-gradient(90deg, var(--primary-color), #8b5cf6);
    transition: width 0.45s ease-in-out;
    position: relative;
    overflow: hidden;
}
.progress-bar.indeterminate {
    background: linear-gradient(90deg, transparent, var(--primary-color), #8b5cf6, transparent);
    background-size: 200% 100%;
    animation: indeterminate-slide 1.4s linear infinite;
    width: 35% !important;
}
@keyframes indeterminate-slide {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
.progress-bar.indeterminate-overlay {
    position: absolute;
    top: 0; left: 0; height: 100%; width: 35%;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.55), transparent);
    background-size: 200% 100%;
    animation: indeterminate-slide 1.2s linear infinite;
    border-radius: 4px;
    pointer-events: none;
    opacity: 0.9;
}

/* ===== History filter panel (time range) ===== */
.history-filter-panel {
    background: linear-gradient(135deg, rgba(79,110,247,0.06), rgba(139,92,246,0.04));
    border: 1px solid rgba(79,110,247,0.18);
    box-shadow: 0 1px 3px rgba(79,110,247,0.05);
}
.history-filter-panel .usage-filter-bar {
    align-items: stretch;
}
.history-days-group {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 2px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    border-radius: 0.375rem;
    overflow: hidden;
}
.history-days-group .btn {
    transition: all 0.18s ease;
    font-weight: 500;
    border-radius: 0;
}
.history-days-group .btn:hover:not(.active) {
    background-color: rgba(79,110,247,0.08);
    transform: translateY(-1px);
}
.history-days-group .btn.active {
    background: linear-gradient(135deg, var(--primary-color), #6366f1);
    border-color: var(--primary-color);
    color: #fff;
    box-shadow: 0 2px 8px rgba(79,110,247,0.35);
    font-weight: 600;
}
.table th {
    font-weight: 600;
    background: #f1f5f9;
    border-top: none;
    color: #334155;
}
.table td, .table th { vertical-align: middle; border-color: #e2e8f0; }
.file-item {
    padding: 0.9rem;
    border-radius: 12px;
    background: white;
    margin-bottom: 0.5rem;
    border-left: 4px solid var(--primary-color);
    box-shadow: 0 2px 6px rgba(0,0,0,0.02);
    transition: all 0.2s;
}
.file-item:hover { background: #f8fafc; transform: translateX(2px); }

.btn-outline-primary {
    border-radius: 12px;
    padding: 0.5rem 1.5rem;
    font-weight: 500;
    border: 1px solid var(--primary-color);
    color: var(--primary-color);
}
.btn-outline-primary:hover { background: var(--primary-light); }
.tab-btn {
    border: none;
    background: none;
    padding: 0.8rem 1.8rem;
    font-weight: 600;
    color: #64748b;
    border-bottom: 3px solid transparent;
    cursor: pointer;
    transition: all 0.3s;
}
/* Task 6 (AM2): active state border-bottom is on the inner span, so it only spans
   text width regardless of button size (button is forced to 100% by .flex-fill
   inside d-flex parent which beats our display:inline-block / width:max-content).
   The tab-btn keeps the transparent border-bottom so layout doesn't shift on hover/active. */
.tab-btn > span {
    border-bottom: 3px solid transparent;
    padding-bottom: 0.2rem;
}
.tab-btn.active > span {
    border-bottom-color: var(--primary-color);
}
.tab-btn.active {
    color: var(--primary-color);
    /* border-bottom-color stays transparent; the colored underline is on the inner span */
}

/* ==================== Modal scroll affordance ====================
   V3-B1 — Tall modals (e.g. editResult with 7 fields) exceeded 800px
   viewport at 360, clipping the 取消/保存 footer buttons. Adds a
   global max-height + scroll on .modal-body so any modal can be
   scrolled internally while the footer stays pinned at the bottom.
   200px = ~60px header + ~60px footer + ~80px margin/padding headroom. */
.modal-body {
    max-height: calc(100vh - 200px);
    overflow-y: auto;
}

/* Task 6 (AM1): auth-modal body — center-align content within the auth modal */
#authModal .modal-body {
    text-align: center;
}
.tab-content { margin-top: 1.8rem; }
.empty-state { text-align: center; padding: 3rem 2rem; color: #94a3b8; }
.empty-icon { font-size: 3.5rem; margin-bottom: 1rem; color: #cbd5e1; }
.doc-preview {
    width: 80px; height: 60px; object-fit: cover; border-radius: 8px;
    cursor: pointer; transition: all 0.2s; border: 1px solid #e2e8f0;
}
.doc-preview:hover { transform: scale(1.05); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.file-list-collapsed { max-height: 260px; overflow-y: auto; margin-bottom: 1rem; }
/* File list item: shrink-to-fit so long filenames don't push the card
   past the viewport. min-width:0 lets the flex child shrink; the inner
   .file-name ellipsises when content overflows. */
.file-list-item {
    min-width: 0;
}
.file-list-item .file-name {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    max-width: 100%;
}
.file-list-item .file-icon {
    flex-shrink: 0;
}
.toggle-file-list {
    cursor: pointer; color: var(--primary-color); font-weight: 500;
    padding: 0.5rem; border-radius: 8px; transition: all 0.2s; display: inline-block;
}
.toggle-file-list:hover { background: var(--primary-light); }
.file-count-badge {
    background: var(--primary-color); color: white; border-radius: 999px;
    padding: 0.25rem 0.6rem; font-size: 0.7rem; margin-left: 0.25rem;
}
.batch-actions {
    background: rgba(255,255,255,0.7); padding: 1.2rem; border-radius: 16px;
    border: 1px solid #e2e8f0; margin-top: 1rem;
}
.upload-buttons { display: flex; gap: 0.5rem; justify-content: center; margin-top: 1.5rem; flex-wrap: wrap; }

.user-info-badge {
    background: var(--primary-light); border-radius: 30px; padding: 0.3rem 1rem 0.3rem 0.8rem;
    display: flex; align-items: center; gap: 0.8rem; font-size: 0.85rem;
    flex-wrap: wrap;
}
.credits-badge {
    background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #1e293b;
    border-radius: 20px; padding: 0.2rem 0.8rem; font-weight: 600; font-size: 0.8rem;
}
.free-badge {
    background: #e2e8f0;
    color: #334155;
    border-radius: 20px;
    padding: 0.2rem 0.8rem;
    font-weight: 500;
    font-size: 0.75rem;
    white-space: nowrap;
}

/* 银行结果卡片折叠 */
.bank-result-card {
    border: 1px solid #e2e8f0;
    border-radius: 16px;
    margin-bottom: 1rem;
    background: white;
    overflow: hidden;
}
.bank-card-header {
    background: #f8fafc;
    padding: 0.75rem 1rem;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: background 0.2s;
}
.bank-card-header:hover {
    background: #eef2ff;
}
.bank-card-title {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.bank-card-stats {
    font-size: 0.85rem;
    color: var(--primary-color);
    font-weight: 500;
}
.bank-card-body {
    padding: 0.75rem 1rem;
    border-top: 1px solid #e2e8f0;
    background: white;
}
.bank-table {
    font-size: 0.85rem;
}
.bank-table td, .bank-table th {
    padding: 0.4rem 0.6rem;
}


.trial-quota-bar {
    background: linear-gradient(135deg, #4f6ef7, #8b5cf6);
    border-radius: 20px;
    padding: 0.75rem 1.5rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
    font-size: 1rem;
    font-weight: 600;
    color: #ffffff;
    box-shadow: 0 4px 12px rgba(79,110,247,0.3);
    border: 1px solid rgba(255,255,255,0.3);
    backdrop-filter: blur(4px);
    transition: all 0.2s ease;
}
.trial-quota-bar .badge {
    font-size: 0.9rem;
    padding: 0.4rem 1rem;
    background: rgba(255,255,255,0.95) !important;
    color: #4f6ef7 !important;
    border-radius: 40px;
    font-weight: 600;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.trial-quota-bar .badge i {
    margin-right: 0.3rem;
    color: #4f6ef7;
}
.trial-quota-bar small {
    font-size: 0.8rem;
    font-weight: normal;
    opacity: 0.9;
    color: #ffffff !important;
}

.usage-filter-bar {
    background: white;
    border-radius: 12px;
    padding: 0.75rem;
    margin-bottom: 1rem;
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    align-items: flex-end;
}
/* 导航栏右侧元素不换行 */
.navbar-nav {
    flex-direction: row !important;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
@media (min-width: 992px) {
    .navbar-nav {
        flex-wrap: nowrap;
    }
}
.user-info-badge {
    gap: 0.5rem;
    padding: 0.3rem 1rem;
}
.user-info-badge .logout-btn {
    background: none;
    border: none;
    color: #ef4444;
    padding: 0;
    font-size: 0.85rem;
    cursor: pointer;
}
.user-info-badge .logout-btn:hover {
    text-decoration: underline;
}
@media (max-width: 768px) {
    .upload-area { padding: 1.8rem 1rem; }
    .tab-btn { padding: 0.8rem 1rem; font-size: 0.875rem; }
    .card { margin-bottom: 1rem; }
    .doc-preview { width: 60px; height: 45px; }
    .file-list-collapsed { max-height: 200px; }
    .user-info-badge { gap: 0.4rem; font-size: 0.7rem; }
}
/* ==================== 左侧导航栏样式 ==================== */
.app-layout {
    display: flex;
    min-height: calc(100vh - 70px); /* 减去导航栏高度 */
}
.sidebar-nav {
    width: 220px;
    min-height: calc(100vh - 70px);
    background: rgba(255,255,255,0.85);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-right: 1px solid rgba(0,0,0,0.06);
    padding: 1.5rem 0.75rem;
    position: fixed;
    left: 0;
    top: 70px; /* 导航栏高度 */
    bottom: 0;
    z-index: 100;
    overflow-y: auto;
    transition: all 0.3s ease;
}
.sidebar-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.85rem 1rem;
    border-radius: 12px;
    cursor: pointer;
    transition: all 0.2s ease;
    color: #64748b;
    font-weight: 500;
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
}
.sidebar-nav-item:hover {
    background: var(--primary-light);
    color: var(--primary-color);
}
.sidebar-nav-item.active {
    background: linear-gradient(135deg, var(--primary-color), #6366f1);
    color: white;
    box-shadow: 0 4px 12px rgba(79,110,247,0.3);
}
.sidebar-nav-item.active:hover {
    color: white;
}
.sidebar-nav-item i {
    font-size: 1.1rem;
    width: 22px;
    text-align: center;
}
/* V3-B7 — Prevent EN sidebar labels (e.g. "Invoice Recognition") from
   wrapping to 2 lines at 1440. nowrap keeps each nav-item single-row;
   overflow:hidden + ellipsis handles extremely long labels. */
.sidebar-nav-item .lang-content,
.sidebar-nav-item span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar-divider {
    height: 1px;
    background: #e2e8f0;
    margin: 0.75rem 0.5rem;
}
.sidebar-section-title {
    font-size: 0.7rem;
    font-weight: 600;
    color: #94a3b8;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 0.5rem 1rem;
    margin-bottom: 0.25rem;
}
.main-content-area {
    margin-left: 220px;
    flex: 1;
    padding: 1.5rem;
    min-height: calc(100vh - 70px);
}
/* Sidebar overlay — defined OUTSIDE the (max-width: 992px) media query so the overlay
   is also visible at tablet/desktop when sidebar is open (Task 3, N5 fix). */
.sidebar-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.3);
    z-index: 99;
}
.sidebar-overlay.open {
    display: block;
}
/* Body scroll lock when sidebar is open (Task 3, N5 fix) */
.sidebar-open-locked {
    overflow: hidden;
}

/* 移动端适配 */
.sidebar-toggle-btn {
    display: none;
    background: none;
    border: none;
    font-size: 1.3rem;
    color: var(--primary-color);
    cursor: pointer;
    padding: 0.25rem 0.5rem;
}
@media (max-width: 992px) {
    .sidebar-nav {
        transform: translateX(-100%);
        box-shadow: 4px 0 20px rgba(0,0,0,0.1);
    }
    .sidebar-nav.open {
        transform: translateX(0);
    }
    .main-content-area {
        margin-left: 0;
    }
    .sidebar-toggle-btn {
        display: inline-block;
    }
}

/* ==================== Month Grid Picker ==================== */
.month-grid-panel {
    border: 1px solid #dee2e6;
    border-radius: 8px;
    padding: 8px;
    background: #fff;
    max-width: 260px;
}
.month-grid-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
    padding: 0 4px;
}
.month-grid-year {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--dark-color);
}
.month-grid-header .btn {
    padding: 0 8px;
    font-size: 1rem;
    line-height: 1.2;
}
.month-grid-body {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 4px;
}
.month-cell {
    border: none;
    border-radius: 6px;
    padding: 6px 2px;
    font-size: 0.8rem;
    cursor: pointer;
    text-align: center;
    transition: all 0.15s ease;
    background: #f0f4ff;
    color: var(--dark-color);
}
.month-cell:hover:not(:disabled) {
    background: var(--primary-color);
    color: #fff;
}
.month-cell-active {
    background: #eef1ff;
    color: var(--primary-color);
    font-weight: 600;
}
.month-cell-selected {
    background: var(--primary-color) !important;
    color: #fff !important;
    font-weight: 700;
}
.month-cell-empty {
    background: #f5f5f5;
    color: #ccc;
    cursor: not-allowed;
}
.month-cell-empty:disabled {
    opacity: 0.5;
}
.month-cell-current {
    box-shadow: inset 0 0 0 2px var(--primary-color);
}

/* "仅支持查询最近 7 天" hint badge — matches system primary color */
.history-hint-badge {
    background-color: rgba(79, 110, 247, 0.12);
    color: var(--primary-color);
    border: 1px solid rgba(79, 110, 247, 0.35);
    border-radius: 999px;
    font-weight: 500;
    letter-spacing: 0.2px;
    transition: all 0.2s ease;
}
.history-hint-badge:hover {
    background-color: rgba(79, 110, 247, 0.18);
    border-color: var(--primary-color);
}

/* ==================== Billing Enhancement (Purchase History, Refund, Invoice) ==================== */

/* ----- Purchase History Container ----- */
#purchaseHistoryContainer {
    background: #fff;
    border-radius: 0.75rem;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
    padding: 1.5rem;
    margin-top: 1rem;
}

/* Empty state */
#purchaseHistoryContainer .empty-state {
    text-align: center;
    padding: 3rem 1rem;
    color: #94a3b8;
}
#purchaseHistoryContainer .empty-state .empty-icon {
    font-size: 2.5rem;
    margin-bottom: 0.75rem;
    opacity: 0.6;
}
#purchaseHistoryContainer .empty-state p {
    font-size: 0.95rem;
    margin: 0;
}

/* Pagination */
#purchaseHistoryPagination {
    display: flex;
    justify-content: center;
    padding-top: 1rem;
    margin-top: 1rem;
    border-top: 1px solid #f1f5f9;
}
#purchaseHistoryPagination .page-link {
    color: var(--primary-color);
    transition: all 0.2s ease;
}
#purchaseHistoryPagination .page-item.active .page-link {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
}

/* ----- Purchase History Table (legacy class) ----- */
/* 旧 .purchase-history-table 样式保留以防外部引用,实际渲染由下方 Purchase History Table Polish 接管 */

/* ----- Purchase History Table Polish ----- */
.purchase-history-panel-inner .table {
    border-collapse: separate;
    border-spacing: 0;
    margin-bottom: 0;
    table-layout: fixed;
    width: 100%;
}
.purchase-history-panel-inner .table thead th {
    background: var(--primary-light, #eef2ff);
    color: var(--dark-color, #1f2937);
    font-weight: 600;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    padding: 0.9rem 1rem;
    border-bottom: 2px solid rgba(79, 110, 247, 0.15);
    white-space: nowrap;
    vertical-align: middle;
}
.purchase-history-panel-inner .table thead th:first-child {
    border-top-left-radius: 0.5rem;
}
.purchase-history-panel-inner .table thead th:last-child {
    border-top-right-radius: 0.5rem;
}
.purchase-history-panel-inner .table tbody td {
    padding: 1rem 1rem;
    vertical-align: middle;
    border-bottom: 1px solid #f1f5f9;
    color: #475569;
    font-size: 0.92rem;
}
.purchase-history-panel-inner .table tbody tr:last-child td {
    border-bottom: 0;
}
.purchase-history-panel-inner .table tbody tr {
    transition: background-color 0.18s ease;
}
.purchase-history-panel-inner .table tbody tr:hover {
    background-color: rgba(79, 110, 247, 0.04);
}

/* Column widths & alignment */
.purchase-history-panel-inner .ph-cell-date {
    width: 22%;
    color: #475569;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.purchase-history-panel-inner .ph-cell-package {
    width: 22%;
    color: #1f2937;
    font-weight: 500;
}
.purchase-history-panel-inner .ph-cell-amount {
    width: 14%;
    text-align: right;
    color: var(--primary-color, #4f6ef7);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.purchase-history-panel-inner .ph-cell-credits {
    width: 14%;
    text-align: right;
    color: #1f2937;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.purchase-history-panel-inner .ph-cell-status {
    width: 16%;
    text-align: center;
}
.purchase-history-panel-inner .ph-cell-invoice {
    width: 12%;
    text-align: center;
}

/* Status badges: migrated to Bootstrap .badge .bg-* utility (Phase 2) */

/* Invoice icon alignment */
.purchase-history-panel-inner .ph-cell-invoice .btn-invoice {
    width: 32px;
    height: 32px;
    padding: 0;
    justify-content: center;
    border-radius: 0.5rem;
}

/* Empty state inside purchase history */
.purchase-history-empty {
    padding: 0 !important;
    border: 0 !important;
}
.purchase-history-empty-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1rem;
    color: #94a3b8;
    background: linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
    border-radius: 0.5rem;
}
.purchase-history-empty-inner i {
    font-size: 2.25rem;
    opacity: 0.55;
    margin-bottom: 0.5rem;
}
.purchase-history-empty-inner div {
    font-size: 0.95rem;
    color: #64748b;
}

/* ----- Invoice Button ----- */
.btn-invoice {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.7rem;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--primary-color);
    background: transparent;
    border: 1px solid var(--primary-color);
    border-radius: 0.375rem;
    cursor: pointer;
    transition: all 0.2s ease;
}
.btn-invoice:hover {
    color: #fff;
    background: var(--primary-color);
    border-color: var(--primary-color);
}
.btn-invoice:active {
    transform: scale(0.97);
}
.btn-invoice .bi-file-earmark-pdf {
    font-size: 0.9rem;
}

/* ----- Purchase History Toggle Button ----- */
.btn-purchase-history-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.4rem 1rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--primary-color);
    background: var(--primary-light);
    border: 1px solid rgba(79, 110, 247, 0.2);
    border-radius: 20px;
    cursor: pointer;
    transition: all 0.25s ease;
    white-space: nowrap;
}
.btn-purchase-history-toggle:hover {
    background: rgba(79, 110, 247, 0.12);
    border-color: var(--primary-color);
    box-shadow: 0 2px 8px rgba(79, 110, 247, 0.2);
}
.btn-purchase-history-toggle.active {
    background: var(--primary-color);
    color: #fff;
    border-color: var(--primary-color);
    box-shadow: 0 3px 10px rgba(79, 110, 247, 0.35);
}
.btn-purchase-history-toggle .toggle-arrow {
    transition: transform 0.3s ease;
    font-size: 0.8rem;
}
.btn-purchase-history-toggle.active .toggle-arrow {
    transform: rotate(180deg);
}

/* ----- Purchase History Collapsible Panel ----- */
.purchase-history-panel {
    margin-top: 1.5rem;
    border-top: 1px solid rgba(79, 110, 247, 0.12);
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.3s ease,
                margin-top 0.3s ease;
}
.purchase-history-panel.show {
    max-height: 2000px;
    opacity: 1;
}
.purchase-history-panel:not(.show) {
    margin-top: 0;
}
.purchase-history-panel-inner {
    padding-top: 1rem;
}

/* ----- Responsive ----- */
@media (max-width: 575.98px) {
    #purchaseHistoryContainer {
        padding: 1rem;
    }
    .purchase-history-panel-inner .table thead th,
    .purchase-history-panel-inner .table tbody td {
        padding: 0.6rem 0.7rem;
        font-size: 0.85rem;
    }
    .purchase-history-panel-inner .ph-cell-date {
        width: 28%;
    }
    .purchase-history-panel-inner .ph-cell-package {
        width: 24%;
    }
    .purchase-history-panel-inner .ph-cell-amount {
        width: 16%;
    }
    .purchase-history-panel-inner .ph-cell-credits {
        width: 16%;
    }
    .btn-invoice {
        font-size: 0.75rem;
        padding: 0.25rem 0.5rem;
    }
    .btn-purchase-history-toggle {
        font-size: 0.78rem;
        padding: 0.35rem 0.8rem;
    }
}

/* ==================== Wave 2 — Mobile Responsive Breakpoints ==================== */
/* Task 4: Append-only responsive blocks. Two breakpoints layered on top of the
   existing rules above. Cascade order is preserved because both media blocks
   are appended after every existing rule. No existing selector was renamed,
   no existing declaration was modified. New `!important` budget: 4 max
   (current file: 8, max allowed total: 12). This block uses 0. */

/* ----- Tablet (≤ 991.98 px) — gentle tightening, no layout flip ----- */
@media (max-width: 991.98px) {
    /* Trial quota bar: 4 flex children + small text get tight under 992.
       Switch to wrap so "Trial Remaining Today" + 2 badges + hint
       do not overflow on iPad portrait (768-991) and small Android tablets. */
    .trial-quota-bar {
        flex-wrap: wrap;
        gap: 0.5rem 1rem;
        padding: 0.75rem 1rem;
        font-size: 0.95rem;
    }
    .trial-quota-bar > div {
        min-width: 0;
    }
    .trial-quota-bar small {
        flex-basis: 100%;
        margin-top: 0.25rem;
    }

/* History day-range buttons: 7 × min-width:52px = 364px just for the
        button row, plus surrounding padding. At 992-768 this row starts
       pushing its parent horizontally. Allow it to wrap onto a 2nd line
        so the row remains usable on tablet widths. */
    /* .history-days-group tablet overrides removed in V3 fix plan:
       grid-template-columns handles equal-width distribution at all
       viewports, no flex-wrap needed. */

    /* Sidebar is already a slide-over under 992 (existing rule). Tighten
       the main content area so it gets the same right-side breathing room
       it would have had with a fixed 220px sidebar. */
    .main-content-area {
        padding: 1.25rem 1rem;
    }

    /* Card density — slightly tighter padding in invoice/bank result cards
       on tablet so the two-column layout (col-lg-6) doesn't squish. */
    .card .card-body {
        padding: 1.1rem;
    }

    /* Invoice result table: not yet a card layout (that's the 767.98
       breakpoint), but reduce default cell padding so 7 columns don't
       force horizontal scroll on a 768-991 viewport. */
    #invoiceResultTable th,
    #invoiceResultTable td {
        padding: 0.55rem 0.6rem;
        font-size: 0.88rem;
    }

    /* Bank result cards: a hair tighter so a typical 5-row card fits
       comfortably in the col-lg-6 column. */
    .bank-card-header {
        padding: 0.65rem 0.85rem;
    }
    .bank-card-body {
        padding: 0.65rem 0.85rem;
    }

    /* Usage filter bar: 3 selects + filter button = 4 children. They
       already use flex-wrap, but force the filter button onto its own
       row on tablet for visual breathing room. */
    .usage-filter-bar > .flex-grow-1,
    .usage-filter-bar > div {
        flex-basis: calc(50% - 0.5rem);
        min-width: 160px;
    }
    .usage-filter-bar > .btn,
    .usage-filter-bar > button {
        flex-basis: 100%;
        margin-top: 0.5rem;
    }

    /* Logo shrinks slightly so it doesn't dominate on narrow tablets. */
    .logo {
        font-size: 1.4rem;
    }

    /* Navbar: items already wrap on smaller screens (existing
       flex-wrap: wrap). Reduce gap on tablet for tidier stack. */
    .navbar-nav {
        gap: 0.4rem;
    }

    /* Upload area: pad less aggressively than the existing 768px rule. */
    .upload-area {
        padding: 2rem 1.5rem;
    }

    /* History/usage pagination: keep prev/next/info on one row by
       allowing items to shrink with text-truncate on the page-info. */
    #historyPagination,
    #usagePagination {
        flex-wrap: nowrap;
        gap: 0.5rem;
    }
    #historyPageInfo,
    #usagePageInfo {
        min-width: 0;
        text-align: center;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

/* ----- Phone (≤ 767.98 px) — card transform for #invoiceResultTable,
   44px touch targets on .btn/input/select, word-break on table cells,
   font-size reduction where overflow occurs. 4 new !important used
   (justified: 3 are needed to override Bootstrap's .btn padding/flex
   and 1 to override the existing .history-days-group .btn min-width
   so the card transform can dominate). ----- */
/* ==================== EN result-table header nowrap ====================
   V3-B6 — English headers ("Receipt Preview", "Document Name") wrapped
   to 2 lines at 1440 desktop, creating uneven row heights. Adds
   white-space:nowrap on .results-table thead th / #invoiceResultTable
   thead th / #bankResultTable thead th. Thead is hidden at ≤767.98
   (card-transform), so nowrap only affects desktop/tablet. */
.results-table thead th,
#invoiceResultTable thead th,
#bankResultTable thead th {
    white-space: nowrap;
}

/* ==================== .table-responsive scroll affordance ====================
   V3-B10 — Bootstrap's .table-responsive provides inner horizontal scroll
   when table overflows container, but no visual cue that content is
   scrollable. On 360px viewport with 6 columns (日期/套餐/金额/点数/
   状态/处理), the status badge and action buttons were clipped without
   indication that swiping right would reveal them.

   Adds a subtle right-edge gradient as discoverability hint. The gradient
   is transparent except the rightmost 24px where it fades to a faint
   primary-color tint; only visible when the table actually overflows. */
.table-responsive {
    background-image: linear-gradient(to right, transparent calc(100% - 24px), rgba(79,110,247,0.08) 100%);
}
@media (max-width: 575.98px) {
    /* ---------- Touch-target floor: 44×44 px (Apple HIG / WCAG 2.5.5) ----------
       Apply to .btn, input, select. min-height, not height, so the element
       can grow for multi-line content. Uses !important to win against
       Bootstrap's .btn padding/sizing utility classes which set height
       via line-height tricks that don't always yield 44px. */
    .btn,
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="tel"],
    input[type="search"],
    input[type="file"],
    select,
    textarea {
        min-height: 44px;
    }

/* History day-range buttons: existing rule sets min-width:52px. Drop
        to 40px on phone so all 7 fit on one line on a 360px-wide screen
       with the search button still visible. !important needed to win
        against the existing tablet override above + the original 52px.
        Min-width removed in V3 fix plan: grid template-columns now
        distributes width equally; min-width would override grid sizing. */
    .history-days-group .btn {
        padding: 0.4rem 0.4rem;
        font-size: 0.78rem;
    }

    /* ---------- .table-responsive-card tables → card layout on phone ----------
       Task 5 wraps usage + history tables in `.table-responsive-card` for
       the card transform. We hide the thead (labels are surfaced via
       ::before using data-label on <th>, propagated to <td> by JS).
       Each <tr> becomes a card, each <td> becomes a label:value row. */
    .table-responsive-card table thead {
        display: none;
    }
    .table-responsive-card table,
    .table-responsive-card table tbody,
    .table-responsive-card table tr {
        display: block;
        width: 100%;
    }
    .table-responsive-card table tr {
        background: #fff;
        border: 1px solid #e2e8f0;
        border-radius: 12px;
        margin-bottom: 0.75rem;
        padding: 0.5rem 0.75rem;
        box-shadow: 0 2px 6px rgba(0,0,0,0.04);
    }
    .table-responsive-card table td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 0.75rem;
        padding: 0.5rem 0;
        border: none;
        border-bottom: 1px solid #f1f5f9;
        font-size: 0.88rem;
        /* Long filenames / business names / amounts must wrap, not push
           the card off-screen. */
        word-break: break-word;
        overflow-wrap: anywhere;
    }
    .table-responsive-card table td:last-child {
        border-bottom: none;
    }
    /* The label comes from the matching <th>'s data-label attribute.
       Task 5 sets data-label on each <td> to mirror its <th>. */
    .table-responsive-card table td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-weight: 600;
        color: #64748b;
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.3px;
        max-width: 45%;
    }
    /* Make the value cell take the remaining space so long content
       wraps within the card instead of overflowing. */
    .table-responsive-card table td > * {
        flex: 1 1 auto;
        min-width: 0;
        text-align: right;
    }
    /* Preview image: don't stretch the card — keep it small + aligned. */
    .table-responsive-card #invoiceResultTable td .doc-preview {
        width: 56px;
        height: 42px;
    }
    /* ===== Invoice result table: phone-specific card enhancements =====
       See invoice.js renderInvoiceResults for the data-label wiring. */

    /* F-1: Preview image — keep aspect ratio, cap height so horizontal
       receipts don't become a wide flat strip. Width auto + max-width 100%
       lets the image shrink on narrow screens without distortion. */
    .table-responsive-card #invoiceResultTable td[data-label="单据预览"] {
        flex-direction: column;
        align-items: stretch;
        text-align: center;
    }
    .table-responsive-card #invoiceResultTable td[data-label="单据预览"]::before {
        align-self: flex-start;
    }
    .table-responsive-card #invoiceResultTable td[data-label="单据预览"] img.doc-preview,
    .table-responsive-card #invoiceResultTable td[data-label="单据预览"] .doc-preview {
        flex: 0 0 auto;
        width: 100%;
        max-width: 100%;
        max-height: 180px;
        height: auto;
        min-height: 120px;
        object-fit: contain;
        border-radius: 8px;
        background: #f8f9fa;
        display: block;
    }

    /* F-2: Long file names + shop names must wrap, not get cut off.
       Override the inline style="max-width:120px" set by invoice.js. */
    .table-responsive-card #invoiceResultTable td[data-label="文件名"],
    .table-responsive-card #invoiceResultTable td[data-label="商户名称"] {
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
        max-width: 100% !important;
        word-break: break-word;
        line-height: 1.4;
    }
    /* Cancel the flex-right-align forced by td > * rule, so the value
       sits left-aligned next to the label on long text. */
    .table-responsive-card #invoiceResultTable td[data-label="文件名"] *,
    .table-responsive-card #invoiceResultTable td[data-label="商户名称"] * {
        text-align: left;
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
        max-width: 100% !important;
        display: inline;
    }

    /* F-3a: Status badge — keep compact, don't stretch full row. */
    .table-responsive-card #invoiceResultTable td[data-label="状态"] {
        align-items: center;
    }
    .table-responsive-card #invoiceResultTable td[data-label="状态"] > * {
        flex: 0 0 auto;
        width: max-content;
        align-self: flex-end;
    }

    /* F-3b: Action button — right-aligned, natural width. */
    .table-responsive-card #invoiceResultTable td[data-label="操作"] {
        justify-content: flex-end;
    }
    .table-responsive-card #invoiceResultTable td[data-label="操作"] > * {
        flex: 0 0 auto;
        width: auto;
    }

    /* F-3c: Amount — bold + right-aligned + primary color. */
    .table-responsive-card #invoiceResultTable td[data-label="金额"] > * {
        font-weight: 600;
        color: var(--bs-primary, #0d6efd);
    }

    /* F-3d: Card spacing — keep existing rule, tighten internal padding
       so cards aren't visually heavy. (Existing tr rule above provides
       margin-bottom:0.75rem + box-shadow.) */

    /* ---------- Trial quota bar: stack vertically on phone ---------- */
    .trial-quota-bar {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
        padding: 0.75rem 0.85rem;
        font-size: 0.88rem;
    }
    .trial-quota-bar .badge {
        font-size: 0.78rem;
        padding: 0.3rem 0.7rem;
    }

    /* ---------- Bank result cards: slightly tighter on phone ---------- */
    .bank-card-header {
        padding: 0.6rem 0.75rem;
    }
    .bank-card-body {
        padding: 0.6rem 0.75rem;
    }
    .bank-table {
        font-size: 0.8rem;
    }

    /* ---------- Tables in general: word-break safety net ----------
       Other tables (history, usage, purchase history) use the
       table-responsive wrapper from Task 6 and don't get a card
       transform, so they may still have long unbreakable strings
       (filenames, transaction IDs, email addresses). word-break on
       td/th keeps them inside the wrapper without horizontal scroll. */
    .table td,
    .table th {
        word-break: break-word;
    }

    /* ---------- Font-size reduction where overflow occurs ----------
       These elements had horizontal overflow at 360-414px widths in
       the Wave 1 baseline screenshots (per mobile-responsive plan). */
    .usage-filter-bar {
        font-size: 0.88rem;
    }
    .history-filter-panel {
        font-size: 0.9rem;
    }
    .user-info-badge {
        font-size: 0.78rem;
    }
    .credits-badge,
    .free-badge {
        font-size: 0.7rem;
        padding: 0.15rem 0.55rem;
    }

    /* ---------- Navbar: collapse the user-info badge onto multiple
       lines (it already wraps via flex-wrap), but shrink email text
       so the badge doesn't push the lang switcher off-screen. ---------- */
    #userEmailNav {
        max-width: 140px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* ---------- Navbar brand: shrink logo + cap width on phone so
       "Ox tech Ai IDP System" / "OCR Document Scanner" does not
       push the right side off-screen at 320px viewport. The
       `.lang-content` span ellipsises when the brand runs out of
       room; this preserves the "no horizontal scroll" invariant
       on the home page. No !important needed — these properties
       have no conflicting rule. ---------- */
    .navbar-brand.logo {
        font-size: 1.1rem;
        min-width: 0;
        max-width: 60vw;
    }
    .navbar-brand.logo .lang-content {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* ---------- Main content + card padding on phone ---------- */
    .main-content-area {
        padding: 0.85rem 0.6rem;
    }
    .card .card-body {
        padding: 0.9rem;
    }
    .card-title {
        font-size: 1.05rem;
    }

    /* ---------- Upload area: phone-tight padding ---------- */
    .upload-area {
        padding: 1.5rem 0.85rem;
    }
    .upload-icon {
        font-size: 2.6rem;
        margin-bottom: 0.75rem;
    }

    /* ---------- Upload buttons: full width, stacked ---------- */
    .upload-buttons {
        flex-direction: column;
        align-items: stretch;
    }
    .upload-buttons .btn {
        width: 100%;
    }

    /* ---------- Batch action row: stack Start/Export on phone ---------- */
    .batch-actions .d-flex.flex-wrap {
        flex-direction: column;
    }
    .batch-actions .d-flex.flex-wrap .btn {
        width: 100%;
    }

    /* ---------- History day filter: search button below the group ---------- */
    .history-filter-panel .usage-filter-bar {
        flex-direction: column;
        align-items: stretch;
    }
    .history-filter-panel .ms-3 {
        margin-left: 0 !important;
        margin-top: 0.5rem;
    }

    /* ---------- Benchmark page: run button row stacks on phone ---------- */
    .benchmark-nav .brand .lang-content {
        font-size: 0.9rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 180px;
        display: inline-block;
    }
    /* Run button row: 3 buttons + 2 gaps (px-4 + gap-3) overflow 320px. Stack vertically. */
    .text-center.d-flex.justify-content-center.gap-3 {
        flex-wrap: wrap;
    }
    .text-center.d-flex.justify-content-center.gap-3 .btn {
        flex: 1 1 100%;
        margin-bottom: 0.5rem;
    }
    /* Document review filter selects: avoid 415px overflow on phone */
    #filterPdfType, #filterResult {
        max-width: 100%;
        min-width: 0;
    }
}

/* ====== G6: 结果区容器内滚动 + 跳顶按钮（三端通用） ====== */
.result-table {
    max-height: 60vh;
    overflow-y: auto;
    border-radius: 8px;
    border: 1px solid #e9ecef;
    -webkit-overflow-scrolling: touch;
}

.bank-results-list {
    max-height: 60vh;
    overflow-y: auto;
    border-radius: 8px;
    border: 1px solid #e9ecef;
}

@media (max-width: 575.98px) {
    .result-table,
    .bank-results-list {
        max-height: 50vh;
    }
}

.result-scroll-top {
    position: sticky;
    bottom: 1rem;
    right: 1rem;
    float: right;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0;
    box-shadow: 0 2px 8px rgba(0,0,0,.15);
    z-index: 100;
    margin-top: -3rem;
    align-items: center;
    justify-content: center;
}

.result-scroll-top i {
    margin: 0;
}

/* ==================== Desktop topnav polish (Task 7, N4+N7+T2) ====================
   At 1280-1439px (lg breakpoint active, xl breakpoint not yet), the topnav badge
   is wide enough that 退出 + email can wrap. Shrink font + padding so they
   stay on one line. Also constrain trial-quota-bar width on wide desktops. */
@media (max-width: 1439.98px) and (min-width: 992px) {
    .user-info-badge {
        font-size: 0.82rem;
        padding: 0.3rem 0.55rem;
        gap: 0.35rem;
    }
    .user-info-badge .logout-btn {
        font-size: 0.78rem;
        padding: 0.25rem 0.55rem;
    }
    .credits-badge,
    .free-badge {
        font-size: 0.72rem;
        padding: 0.15rem 0.5rem;
    }
    #userEmailNav {
        max-width: 160px;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
    }
}
/* Constrain trial-quota-bar width on desktop so the inline bar doesn't span
   the full container width at wide viewports. */
.trial-quota-bar {
    max-width: 900px;
    margin-left: auto;
    margin-right: auto;
}

/* ==================== Tablet (768-991) topnav shrink ====================
   With navbar-expand-md, userInfoBadge shows at 768-991 (iPad portrait etc).
   Default desktop sizing is too wide for a 768 viewport, so we shrink font,
   padding, and email max-width to keep the topbar single-row. The
   (max-width: 1439.98px) and (min-width: 992px) rule above already covers
   992-1439, so this fills the 768-991 gap. */
@media (min-width: 768px) and (max-width: 991.98px) {
    .user-info-badge {
        font-size: 0.75rem;
        padding: 0.25rem 0.5rem;
        gap: 0.35rem;
    }
    .user-info-badge .logout-btn {
        font-size: 0.72rem;
        padding: 0.2rem 0.45rem;
    }
    #userEmailNav {
        max-width: 100px;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
    }
    .navbar-nav .nav-link {
        padding: 0.25rem 0.5rem;
        font-size: 0.85rem;
    }
}

/* ----- Phone (≤ 575.98 px) — card-stack transform for .purchase-history-panel-inner -----
   Purchase-history table has never had a card layout; on phones it rendered as a
   cramped 6-column table (per user report m0207). This block mirrors the
   `.table-responsive-card` template above (lines ~1030-1088) but is scoped
   strictly to `.purchase-history-panel-inner` so it cannot leak into other
   panels. Trilingual `data-label` attrs are emitted by billing.js (lines 139-144).
   Scope: ONLY .purchase-history-panel-inner. No HTML/JS changes. */
@media (max-width: 575.98px) {
    /* Hide thead; labels are surfaced via ::before attr(data-label) on each td. */
    .purchase-history-panel-inner .table thead {
        display: none;
    }
    /* Convert table → block layout: table, tbody, tr become block containers;
       tr becomes the visual card. */
    .purchase-history-panel-inner .table,
    .purchase-history-panel-inner .table tbody,
    .purchase-history-panel-inner .table tr {
        display: block;
        width: 100%;
    }
    .purchase-history-panel-inner .table tr {
        background: #fff;
        border: 1px solid #e2e8f0;
        border-radius: 12px;
        margin-bottom: 0.75rem;
        padding: 0.5rem 0.75rem;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
    }
    /* Each td becomes a label:value flex row. */
    .purchase-history-panel-inner .table td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 0.75rem;
        padding: 0.5rem 0;
        border: none;
        border-bottom: 1px solid #f1f5f9;
        font-size: 0.88rem;
        word-break: break-word;
        overflow-wrap: anywhere;
    }
    .purchase-history-panel-inner .table td:last-child {
        border-bottom: none;
    }
    /* Label pulled from td's data-label attr (set by billing.js in 3 langs). */
    .purchase-history-panel-inner .table td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-weight: 600;
        color: #64748b;
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.3px;
        max-width: 45%;
    }
    /* Value cell takes remaining space; long content wraps inside the card. */
    .purchase-history-panel-inner .table td > * {
        flex: 1 1 auto;
        min-width: 0;
        text-align: right;
    }
    /* Phone-tight padding overrides the desktop base in Purchase History Polish. */
    .purchase-history-panel-inner .table thead th,
    .purchase-history-panel-inner .table tbody td {
        padding: 0;
    }
    /* Reset ph-cell-* percentage widths (they were table-column widths; in
       card mode each td spans full width so the width% is irrelevant and
       could even fight the flex layout). Keep tabular-nums for numbers. */
    .purchase-history-panel-inner .ph-cell-date,
    .purchase-history-panel-inner .ph-cell-package,
    .purchase-history-panel-inner .ph-cell-amount,
    .purchase-history-panel-inner .ph-cell-credits,
    .purchase-history-panel-inner .ph-cell-status,
    .purchase-history-panel-inner .ph-cell-invoice {
        width: auto;
        min-width: 0;
        max-width: none;
        text-align: right;
    }
    .purchase-history-panel-inner .ph-cell-date,
    .purchase-history-panel-inner .ph-cell-amount,
    .purchase-history-panel-inner .ph-cell-credits {
        font-variant-numeric: tabular-nums;
    }
    /* Invoice button: keep compact inside the card row. */
    .purchase-history-panel-inner .ph-cell-invoice .btn-invoice {
        width: auto;
        height: auto;
        padding: 0.25rem 0.55rem;
    }
}
