.app-shell { display: grid; grid-template-rows: var(--header-height) 1fr; height: 100vh; height: 100dvh; min-height: 0; overflow: hidden; background: var(--bg-page); } @keyframes page-enter { from { opacity: 0; transform: translateY(10px) scale(0.995); } to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes panel-enter { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } @keyframes row-enter { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: translateX(0); } } @keyframes shimmer { from { background-position: 120% 0; } to { background-position: -120% 0; } } @keyframes notice-pop { 0%, 100% { transform: scale(1); } 45% { transform: scale(1.18); } } @keyframes progress-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } } @keyframes autocomplete-pop-enter { from { opacity: 0; transform: translateY(-6px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes autocomplete-pop-enter-up { from { opacity: 0; transform: translateY(6px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } } .header { display: grid; grid-template-columns: 248px 1fr; height: var(--header-height); border-bottom: 1px solid var(--border); background: var(--bg-header); transition: grid-template-columns var(--motion-slow) var(--ease-emphasized); } .brand { display: flex; align-items: center; gap: var(--space-3); height: var(--header-height); padding: 0 var(--space-6); border-right: 1px solid var(--border); background: var(--bg-sidebar); } .brand-mark { display: grid; width: 38px; height: 38px; place-items: center; border-radius: var(--radius-control); background: var(--brand-gradient); color: var(--active-contrast); transition: transform var(--motion-base) var(--ease-emphasized), box-shadow var(--motion-base) var(--ease-standard); } .brand:hover .brand-mark { box-shadow: var(--brand-shadow); transform: rotate(-6deg) scale(1.05); } .brand-title { display: block; color: var(--text-primary); font-size: var(--admin-font-size); font-weight: 650; } .brand-meta { display: block; margin-top: calc(var(--space-1) / 2); color: var(--text-tertiary); font-size: var(--admin-font-size); } .header-tools { display: flex; min-width: 0; align-items: center; justify-content: space-between; gap: var(--space-4); padding: 0 var(--space-6); } .header-left-tools, .header-right-tools { display: flex; min-width: 0; align-items: center; gap: var(--space-3); } .header-right-tools { margin-left: auto; justify-content: flex-end; } .app-switch { flex: 0 0 156px; } .timezone-switch { flex: 0 0 124px; } .app-switch .MuiOutlinedInput-root, .timezone-switch .MuiOutlinedInput-root { background: var(--bg-input); } .app-switch .MuiSelect-select, .timezone-switch .MuiSelect-select { font-weight: 650; } .header-location { display: inline-flex; min-width: 74px; height: var(--control-height); align-items: center; justify-content: center; padding: 0 var(--space-4); border: 1px solid var(--primary-border); border-radius: var(--radius-control); background: var(--primary-hover); box-shadow: var(--shadow-soft), var(--active-inset); color: var(--text-primary); font-size: var(--admin-font-size); font-weight: 650; white-space: nowrap; } .search-box { display: flex; flex: 1 1 420px; min-width: 180px; max-width: 520px; height: var(--control-height); align-items: center; gap: var(--space-3); padding: 0 var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--bg-input); backdrop-filter: var(--glass-blur); color: var(--text-tertiary); -webkit-backdrop-filter: var(--glass-blur); transition: border-color var(--motion-base) var(--ease-standard), background var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .search-box:focus-within { border-color: var(--primary-border-active); background: var(--bg-input-strong); transform: translateY(-1px); } .search-box svg { transition: color var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .search-box:focus-within svg { color: var(--primary); transform: scale(1.08); } .search-trigger { display: flex; width: min(360px, 34vw); min-width: 260px; height: var(--control-height); align-items: center; gap: var(--space-3); padding: 0 var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--bg-input); backdrop-filter: var(--glass-blur); color: var(--text-tertiary); cursor: pointer; text-align: left; -webkit-backdrop-filter: var(--glass-blur); transition: border-color var(--motion-base) var(--ease-standard), background var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .search-trigger span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .search-trigger:hover, .search-trigger:focus-visible { border-color: var(--primary-border-active); background: var(--bg-input-strong); color: var(--text-primary); transform: translateY(-1px); } .search-box input { width: 100%; height: 20px; min-width: 0; padding: 0; border: 0; background: transparent; color: var(--text-primary); font-size: var(--admin-font-size); line-height: 20px; outline: 0; } .search-box input::placeholder { color: var(--text-tertiary); } .time-select { width: 116px; height: var(--control-height); border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--bg-input); backdrop-filter: var(--glass-blur); color: var(--text-secondary); -webkit-backdrop-filter: var(--glass-blur); } .icon-button { display: inline-grid; width: var(--control-height); height: var(--control-height); place-items: center; border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--bg-card); color: var(--text-secondary); cursor: pointer; transition: background var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard), box-shadow var(--motion-fast) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .icon-button:hover { border-color: var(--primary-border-strong); background: var(--bg-hover); box-shadow: var(--shadow-soft); color: var(--text-primary); transform: translateY(-1px); } .icon-button:active { box-shadow: none; transform: translateY(0) scale(0.96); } .icon-button--notice { position: relative; } .icon-button--notice span { position: absolute; top: -5px; right: -5px; display: grid; min-width: 17px; height: 17px; place-items: center; border-radius: var(--radius-pill); background: var(--danger); color: var(--active-contrast); font-size: var(--admin-font-size); font-weight: 700; animation: notice-pop 1500ms var(--ease-emphasized) infinite; } .user-pill { display: flex; height: var(--control-height); align-items: center; gap: 0; padding: 0 var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-control); background: transparent; color: var(--text-secondary); cursor: pointer; font-size: var(--admin-font-size); transition: border-color var(--motion-base) var(--ease-standard), background var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard); } .user-pill:hover { border-color: var(--primary-border); background: var(--primary-hover); color: var(--text-primary); } .user-pill:active { transform: scale(0.98); } .user-menu .MuiPaper-root { min-width: 132px; margin-top: var(--space-2); } .user-menu__item { display: flex; gap: var(--space-2); min-height: var(--control-height); color: var(--text-secondary); font-size: var(--admin-font-size); } .user-menu__item:hover { color: var(--text-primary); } .body-grid { display: grid; grid-template-columns: 248px 1fr; height: 100%; min-height: 0; overflow: hidden; transition: grid-template-columns var(--motion-slow) var(--ease-emphasized); } .sidebar { position: relative; z-index: var(--z-sidebar); display: flex; height: 100%; min-height: 0; flex-direction: column; overflow: hidden; padding: var(--space-4) var(--space-3); border-right: 1px solid var(--border); background: var(--bg-sidebar); } .app-shell--sidebar-collapsed .header, .app-shell--sidebar-collapsed .body-grid { grid-template-columns: 84px 1fr; } .app-shell--sidebar-collapsed .brand { gap: 0; justify-content: center; padding: 0; } .brand-text, .nav-label { display: inline-grid; min-width: 0; max-width: 160px; opacity: 1; overflow: hidden; transform: translateX(0); transition: max-width var(--motion-slow) var(--ease-emphasized), opacity var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .app-shell--sidebar-collapsed .brand-text, .sidebar--collapsed .nav-label { max-width: 0; opacity: 0; pointer-events: none; transform: translateX(-6px); } .sidebar--collapsed { overflow: visible; padding: var(--space-4) var(--space-3); } .sidebar--collapsed .nav-item { width: 44px; justify-content: center; justify-self: center; padding: 0; } .nav-list { display: grid; flex: 1; gap: var(--space-2); min-height: 0; align-content: start; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding-right: var(--space-1); scrollbar-gutter: stable; } .sidebar--collapsed .nav-list { overflow: visible; padding-right: 0; } .nav-group { display: grid; position: relative; gap: 0; } .nav-item { position: relative; display: flex; width: 100%; height: 40px; align-items: center; gap: 10px; padding: 0 var(--space-3); border-radius: var(--radius-control); background: transparent; color: var(--text-secondary); cursor: pointer; overflow: hidden; transition: background var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard), gap var(--motion-slow) var(--ease-emphasized), padding var(--motion-slow) var(--ease-emphasized), width var(--motion-slow) var(--ease-emphasized), transform var(--motion-base) var(--ease-emphasized); } .nav-item svg { flex: 0 0 auto; color: currentColor; font-size: 20px; } .nav-item--parent { padding-right: var(--space-3); font-weight: 650; } .nav-item--open:not(.nav-item--active) { background: var(--primary-surface); color: var(--text-secondary); } .nav-expand { margin-left: auto; color: currentColor; transition: color var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .nav-item--open .nav-expand, .nav-item:hover .nav-expand { color: currentColor; } .nav-item--expanded .nav-expand { transform: rotate(180deg); } .nav-children { display: grid; position: relative; grid-template-rows: 0fr; margin: 0; opacity: 0; overflow: hidden; padding-left: var(--space-7); pointer-events: none; transform: translateY(-4px); transition: grid-template-rows var(--motion-slow) var(--ease-emphasized), opacity var(--motion-base) var(--ease-standard), transform var(--motion-slow) var(--ease-emphasized); } .nav-children::before { position: absolute; top: var(--space-1); bottom: var(--space-1); left: var(--space-4); width: 1px; background: var(--border-soft); content: ""; } .nav-children--open { grid-template-rows: 1fr; margin-top: var(--space-2); opacity: 1; pointer-events: auto; transform: translateY(0); } .nav-children__inner { display: grid; gap: var(--space-1); min-height: 0; overflow: hidden; } .nav-item--child { height: 34px; padding: 0 var(--space-3); font-size: var(--admin-font-size); font-weight: 600; } .nav-item--child svg { font-size: 16px; } .nav-item--child::before { display: none; } .sidebar--collapsed .nav-children, .sidebar--collapsed .nav-item--parent .nav-expand { display: none !important; } .sidebar--collapsed .nav-item--open, .sidebar--collapsed .nav-item--open:hover, .sidebar--collapsed .nav-item--flyout-open, .sidebar--collapsed .nav-item--flyout-open:hover { background: var(--active-gradient); box-shadow: var(--active-inset); color: var(--active-contrast); } .nav-flyout { position: absolute; top: 0; left: calc(100% + var(--space-3)); z-index: var(--z-popover); display: grid; width: 168px; gap: var(--space-1); padding: var(--space-2); border: 1px solid var(--primary-border); border-radius: var(--radius-control); background: var(--bg-flyout); box-shadow: var(--shadow-panel); animation: panel-enter var(--motion-base) var(--ease-emphasized) both; } .nav-flyout::before { position: absolute; top: 16px; left: -6px; width: 10px; height: 10px; border-bottom: 1px solid var(--primary-border); border-left: 1px solid var(--primary-border); background: var(--bg-flyout); content: ""; transform: rotate(45deg); } .nav-flyout__title { padding: var(--space-1) var(--space-2) var(--space-2); color: var(--text-tertiary); font-size: var(--admin-font-size); font-weight: 650; } .nav-flyout__item { display: flex; height: var(--control-height); align-items: center; gap: var(--space-3); padding: 0 var(--space-3); border-radius: var(--radius-control); background: transparent; color: var(--text-secondary); cursor: pointer; font-size: var(--admin-font-size); text-align: left; transition: background var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .nav-flyout__item:hover, .nav-flyout__item--active { background: var(--primary-surface); color: var(--text-primary); transform: translateX(2px); } .nav-item::before { position: absolute; inset: 8px auto 8px 0; width: 3px; border-radius: 0 var(--radius-pill) var(--radius-pill) 0; background: var(--primary); content: ""; opacity: 0; transform: translateX(-4px); transition: opacity var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .nav-item:hover { background: var(--bg-hover); color: var(--text-secondary); transform: translateX(2px); } .nav-item--child:hover { transform: none; } .nav-item--active, .nav-item--active:hover { background: var(--active-gradient); box-shadow: var(--active-inset); color: var(--active-contrast); } .nav-item--child.nav-item--active, .nav-item--child.nav-item--active:hover { background: var(--primary); box-shadow: 0 8px 18px rgba(37, 99, 235, 0.2); color: var(--active-contrast); transform: none; } .nav-item:hover::before, .nav-item--active::before { opacity: 1; transform: translateX(0); } .nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .workspace { position: relative; min-width: 0; min-height: 0; overflow: auto; padding: var(--space-6); } .page-transition { animation: page-enter var(--motion-slow) var(--ease-emphasized) both; } .page-load-boundary { position: relative; min-height: 0; } .page-load-boundary__content { min-height: 0; } .page-load-boundary__content--hidden { position: absolute; inset: 0; width: 100%; visibility: hidden; pointer-events: none; } .page-skeleton { display: grid; height: calc(100vh - var(--header-height) - var(--space-8) - var(--space-4)); height: calc(100dvh - var(--header-height) - var(--space-8) - var(--space-4)); grid-template-rows: 38px minmax(96px, 0.7fr) minmax(160px, 1fr) minmax(200px, 1.2fr); gap: var(--space-4); animation: page-enter var(--motion-slow) var(--ease-emphasized) both; } .page-skeleton__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); } .page-skeleton__title { width: min(220px, 36%); height: 30px; } .page-skeleton__actions { display: flex; gap: var(--space-3); } .page-skeleton__actions .page-skeleton__block { width: 96px; height: var(--control-height); } .page-skeleton__kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--space-4); } .page-skeleton__charts { display: grid; grid-template-columns: minmax(280px, 1.15fr) repeat(2, minmax(260px, 1fr)) minmax(260px, 0.95fr); gap: var(--space-4); min-height: 0; } .page-skeleton__content { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: var(--space-4); min-height: 0; } .page-skeleton__block { position: relative; width: 100%; height: 100%; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-card); background-color: var(--skeleton-surface); opacity: 1; transform: translateZ(0); animation: panel-enter var(--motion-slow) var(--ease-emphasized) both; } .page-skeleton__block::after { background: var(--skeleton-gradient); } .page-skeleton__kpi:nth-child(2), .page-skeleton__charts .page-skeleton__block:nth-child(2), .page-skeleton__content .page-skeleton__block:nth-child(2) { animation-delay: 40ms; } .page-skeleton__kpi:nth-child(3), .page-skeleton__charts .page-skeleton__block:nth-child(3) { animation-delay: 80ms; } .page-skeleton__kpi:nth-child(4), .page-skeleton__charts .page-skeleton__block:nth-child(4) { animation-delay: 120ms; } .page-skeleton__kpi:nth-child(5) { animation-delay: 160ms; } .search-dialog { overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-dialog); background: var(--bg-card); background-image: none; box-shadow: var(--shadow-dialog); animation: panel-enter var(--motion-slow) var(--ease-emphasized) both; } .search-dialog__head { padding: var(--space-5); border-bottom: 1px solid var(--border); background: var(--bg-card-strong); } .search-dialog__input { max-width: none; width: 100%; height: 44px; } .search-dialog__list { display: grid; gap: var(--space-2); max-height: min(56vh, 520px); overflow: auto; padding: var(--space-3); } .search-dialog__item { min-height: 64px; border: 1px solid transparent; border-radius: var(--radius-card); color: var(--text-primary); transition: background var(--motion-base) var(--ease-standard), border-color var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-emphasized); } .search-dialog__item:hover { border-color: var(--primary-border-strong); background: var(--primary-hover); transform: translateX(3px); } .search-dialog__primary { color: var(--text-primary); font-size: var(--admin-font-size); font-weight: 650; } .search-dialog__secondary { color: var(--text-tertiary); font-size: var(--admin-font-size); } .search-dialog__empty { display: grid; min-height: 120px; place-items: center; color: var(--text-tertiary); font-size: var(--admin-font-size); }