/* ============================================================ AAMOS Admin — Apple iOS 18 Design System ============================================================ */ /* ── Design Tokens ────────────────────────────────────────── */ :root { /* Backgrounds */ --bg-primary: #F2F2F7; --bg-secondary: #FFFFFF; --bg-tertiary: #E5E5EA; --bg-grouped: #F2F2F7; --bg-card: #FFFFFF; --bg-elevated: #FFFFFF; --bg-overlay: rgba(0, 0, 0, 0.40); /* Labels / Text */ --label-primary: #000000; --label-secondary: #3C3C43CC; /* 80% */ --label-tertiary: #3C3C4399; /* 60% */ --label-quaternary: #3C3C4366; /* 40% */ --label-inverted: #FFFFFF; /* System Colors */ --color-blue: #007AFF; --color-green: #34C759; --color-orange: #FF9500; --color-red: #FF3B30; --color-yellow: #FFCC00; --color-purple: #AF52DE; --color-teal: #5AC8FA; --color-indigo: #5856D6; --color-pink: #FF2D55; /* Semantic aliases */ --color-primary: var(--color-blue); --color-success: var(--color-green); --color-warning: var(--color-orange); --color-danger: var(--color-red); /* Fill layers (iOS system fills) */ --fill-primary: rgba(120, 120, 128, 0.20); --fill-secondary: rgba(120, 120, 128, 0.16); --fill-tertiary: rgba(118, 118, 128, 0.12); --fill-quaternary: rgba(116, 116, 128, 0.08); /* Separators */ --separator: rgba(60, 60, 67, 0.29); --separator-opaque: #C6C6C8; /* Shadows */ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04); --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08), 0 2px 6px rgba(0, 0, 0, 0.06); --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08); --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.06); /* Radius */ --radius-xs: 4px; --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --radius-xl: 20px; --radius-2xl: 24px; --radius-full: 9999px; /* Spacing (8pt grid) */ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px; /* Typography */ --font-family: -apple-system, "SF Pro Display", "SF Pro Text", BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif; --font-mono: "SF Mono", ui-monospace, "Cascadia Code", "Fira Code", Menlo, Consolas, monospace; --text-xs: 11px; --text-sm: 13px; --text-base: 15px; --text-md: 17px; --text-lg: 20px; --text-xl: 22px; --text-2xl: 28px; --text-3xl: 34px; --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700; /* Layout */ --sidebar-width: 240px; --header-height: 52px; --tab-bar-height: 83px; /* includes safe area */ --content-max: 1200px; /* Transitions */ --ease: cubic-bezier(0.4, 0, 0.2, 1); --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); --duration-fast: 150ms; --duration-base: 300ms; --duration-slow: 500ms; --transition: var(--duration-base) var(--ease); } /* ── Dark Mode Tokens ────────────────────────────────────── */ @media (prefers-color-scheme: dark) { :root { --bg-primary: #000000; --bg-secondary: #1C1C1E; --bg-tertiary: #2C2C2E; --bg-grouped: #000000; --bg-card: #1C1C1E; --bg-elevated: #2C2C2E; --bg-overlay: rgba(0, 0, 0, 0.65); --label-primary: #FFFFFF; --label-secondary: rgba(235, 235, 245, 0.60); --label-tertiary: rgba(235, 235, 245, 0.30); --label-quaternary: rgba(235, 235, 245, 0.18); --label-inverted: #000000; --color-blue: #0A84FF; --color-green: #30D158; --color-orange: #FF9F0A; --color-red: #FF453A; --color-yellow: #FFD60A; --color-purple: #BF5AF2; --color-teal: #64D2FF; --color-indigo: #5E5CE6; --color-pink: #FF375F; --fill-primary: rgba(120, 120, 128, 0.36); --fill-secondary: rgba(120, 120, 128, 0.32); --fill-tertiary: rgba(118, 118, 128, 0.24); --fill-quaternary: rgba(116, 116, 128, 0.18); --separator: rgba(84, 84, 88, 0.65); --separator-opaque: #38383A; --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.40); --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.50); --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.60); --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.40); } } /* ── Reset ───────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { font-size: 16px; -webkit-text-size-adjust: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; scroll-behavior: smooth; } body { font-family: var(--font-family); font-size: var(--text-base); font-weight: var(--weight-regular); line-height: 1.5; color: var(--label-primary); background: var(--bg-primary); min-height: 100dvh; overflow-x: hidden; } a { color: var(--color-primary); text-decoration: none; transition: opacity var(--duration-fast) var(--ease); } a:hover { opacity: 0.75; } button, input, select, textarea { font-family: inherit; font-size: inherit; } ul, ol { list-style: none; } img, svg { display: block; } hr { border: none; border-top: 0.5px solid var(--separator); } /* ── App Shell ───────────────────────────────────────────── */ .app-shell { display: flex; min-height: 100dvh; } /* ── Sidebar ─────────────────────────────────────────────── */ .sidebar { width: var(--sidebar-width); min-height: 100dvh; background: var(--bg-secondary); border-right: 0.5px solid var(--separator); display: flex; flex-direction: column; position: fixed; top: 0; left: 0; bottom: 0; z-index: 200; transition: transform var(--transition); overflow-y: auto; overflow-x: hidden; } .sidebar-header { padding: var(--space-6) var(--space-4) var(--space-4); border-bottom: 0.5px solid var(--separator); flex-shrink: 0; } .sidebar-logo { display: flex; align-items: center; gap: var(--space-3); } .sidebar-logo-icon { width: 36px; height: 36px; border-radius: var(--radius-sm); background: var(--color-primary); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .sidebar-logo-text { font-size: var(--text-md); font-weight: var(--weight-semibold); letter-spacing: -0.4px; color: var(--label-primary); } .sidebar-logo-sub { font-size: var(--text-xs); color: var(--label-tertiary); letter-spacing: 0.2px; margin-top: 1px; } .sidebar-section { padding: var(--space-3) 0; flex: 1; } .sidebar-section-title { padding: var(--space-2) var(--space-4) var(--space-1); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--label-tertiary); text-transform: uppercase; letter-spacing: 0.6px; } .sidebar-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-4); margin: 1px var(--space-2); border-radius: var(--radius-sm); color: var(--label-primary); font-size: var(--text-sm); font-weight: var(--weight-medium); cursor: pointer; transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease); text-decoration: none; user-select: none; position: relative; } .sidebar-item:hover { background: var(--fill-quaternary); } .sidebar-item.active { background: rgba(0, 122, 255, 0.12); color: var(--color-primary); } @media (prefers-color-scheme: dark) { .sidebar-item.active { background: rgba(10, 132, 255, 0.20); color: var(--color-primary); } } .sidebar-item-icon { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; opacity: 0.6; transition: opacity var(--duration-fast) var(--ease); } .sidebar-item.active .sidebar-item-icon, .sidebar-item:hover .sidebar-item-icon { opacity: 1; } .sidebar-item-badge { margin-left: auto; } .sidebar-footer { padding: var(--space-4); border-top: 0.5px solid var(--separator); flex-shrink: 0; } /* Sidebar collapse toggle (desktop) */ .sidebar-toggle { width: 24px; height: 24px; border-radius: var(--radius-full); background: var(--bg-tertiary); border: 0.5px solid var(--separator); display: flex; align-items: center; justify-content: center; cursor: pointer; position: absolute; right: -12px; top: 62px; z-index: 10; transition: background var(--duration-fast) var(--ease); } .sidebar-toggle:hover { background: var(--fill-primary); } /* ── Main Content ─────────────────────────────────────────── */ .main-content { flex: 1; margin-left: var(--sidebar-width); min-height: 100dvh; display: flex; flex-direction: column; background: var(--bg-primary); transition: margin-left var(--transition); } .page-header { height: var(--header-height); background: rgba(var(--bg-secondary), 0.85); -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%); border-bottom: 0.5px solid var(--separator); display: flex; align-items: center; padding: 0 var(--space-6); gap: var(--space-4); position: sticky; top: 0; z-index: 100; } .page-header-bg { background: rgba(242, 242, 247, 0.85); } @media (prefers-color-scheme: dark) { .page-header-bg { background: rgba(28, 28, 30, 0.85); } } .page-title { font-size: var(--text-xl); font-weight: var(--weight-bold); letter-spacing: -0.5px; color: var(--label-primary); flex: 1; } .page-subtitle { font-size: var(--text-sm); color: var(--label-secondary); margin-top: 2px; } .page-body { flex: 1; padding: var(--space-6); max-width: var(--content-max); width: 100%; margin: 0 auto; } /* ── KPI Card ─────────────────────────────────────────────── */ .kpi-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-4); } .kpi-card { background: var(--bg-card); border-radius: var(--radius-md); padding: var(--space-5); box-shadow: var(--shadow-card); display: flex; flex-direction: column; gap: var(--space-2); cursor: default; transition: transform var(--duration-fast) var(--ease), box-shadow var(--duration-fast) var(--ease); position: relative; overflow: hidden; } .kpi-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .kpi-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--kpi-accent, var(--color-primary)); border-radius: var(--radius-md) var(--radius-md) 0 0; } .kpi-card--success { --kpi-accent: var(--color-success); } .kpi-card--warning { --kpi-accent: var(--color-warning); } .kpi-card--danger { --kpi-accent: var(--color-danger); } .kpi-card--primary { --kpi-accent: var(--color-primary); } .kpi-card--purple { --kpi-accent: var(--color-purple); } .kpi-label { font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--label-secondary); text-transform: uppercase; letter-spacing: 0.5px; } .kpi-value { font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: -1px; color: var(--label-primary); line-height: 1.1; } .kpi-delta { display: inline-flex; align-items: center; gap: 3px; font-size: var(--text-xs); font-weight: var(--weight-semibold); padding: 2px 6px; border-radius: var(--radius-full); } .kpi-delta--up { color: var(--color-success); background: rgba(52, 199, 89, 0.12); } .kpi-delta--down { color: var(--color-danger); background: rgba(255, 59, 48, 0.12); } .kpi-delta--neutral { color: var(--label-secondary); background: var(--fill-tertiary); } .kpi-meta { font-size: var(--text-xs); color: var(--label-tertiary); margin-top: auto; } /* ── Health Ring ──────────────────────────────────────────── */ .health-ring { --ring-size: 80px; --ring-stroke: 7px; --ring-value: 75; /* 0–100, set via inline style or JS */ --ring-color: var(--color-success); --ring-bg: var(--fill-tertiary); position: relative; width: var(--ring-size); height: var(--ring-size); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; } .health-ring--sm { --ring-size: 56px; --ring-stroke: 5px; } .health-ring--lg { --ring-size: 112px; --ring-stroke: 9px; } .health-ring svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); } .health-ring__track { fill: none; stroke: var(--ring-bg); stroke-width: var(--ring-stroke); } .health-ring__fill { fill: none; stroke: var(--ring-color); stroke-width: var(--ring-stroke); stroke-linecap: round; /* circumference ~= 2π × (r=38) ≈ 238.76 */ stroke-dasharray: 238.76; stroke-dashoffset: calc(238.76 * (1 - var(--ring-value) / 100)); transition: stroke-dashoffset var(--duration-slow) var(--ease), stroke var(--duration-base) var(--ease); } .health-ring--warning { --ring-color: var(--color-warning); } .health-ring--danger { --ring-color: var(--color-danger); } .health-ring--blue { --ring-color: var(--color-primary); } .health-ring__label { position: relative; display: flex; flex-direction: column; align-items: center; line-height: 1.1; z-index: 1; } .health-ring__value { font-size: var(--text-md); font-weight: var(--weight-bold); color: var(--label-primary); letter-spacing: -0.5px; } .health-ring__unit { font-size: var(--text-xs); color: var(--label-tertiary); } /* ── iOS Toggle ───────────────────────────────────────────── */ .ios-toggle { position: relative; display: inline-flex; align-items: center; cursor: pointer; user-select: none; gap: var(--space-3); -webkit-tap-highlight-color: transparent; } .ios-toggle__input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .ios-toggle__track { position: relative; width: 51px; height: 31px; border-radius: var(--radius-full); background: var(--fill-secondary); transition: background var(--duration-base) var(--ease); flex-shrink: 0; } .ios-toggle__input:checked + .ios-toggle__track { background: var(--color-success); } .ios-toggle__input:focus-visible + .ios-toggle__track { outline: 3px solid var(--color-primary); outline-offset: 2px; } .ios-toggle__thumb { position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: var(--radius-full); background: #FFFFFF; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.10); transition: transform var(--duration-base) var(--ease-spring); } .ios-toggle__input:checked ~ .ios-toggle__track .ios-toggle__thumb, .ios-toggle__input:checked + .ios-toggle__track .ios-toggle__thumb { transform: translateX(20px); } /* Thumb is a child of track, so use sibling trick via parent */ .ios-toggle__track .ios-toggle__thumb { transition: transform var(--duration-base) var(--ease-spring); } .ios-toggle--primary .ios-toggle__input:checked + .ios-toggle__track { background: var(--color-primary); } .ios-toggle__label { font-size: var(--text-base); color: var(--label-primary); } .ios-toggle__label-sub { font-size: var(--text-sm); color: var(--label-secondary); margin-top: 1px; } /* ── iOS Table ────────────────────────────────────────────── */ .table-ios { width: 100%; background: var(--bg-card); border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-card); } .table-ios thead { background: var(--bg-tertiary); } .table-ios th { padding: var(--space-3) var(--space-4); text-align: left; font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--label-secondary); text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; border-bottom: 0.5px solid var(--separator); } .table-ios td { padding: var(--space-3) var(--space-4); font-size: var(--text-sm); color: var(--label-primary); border-bottom: 0.5px solid var(--separator); vertical-align: middle; } .table-ios tr:last-child td { border-bottom: none; } .table-ios tbody tr { transition: background var(--duration-fast) var(--ease); } .table-ios tbody tr:hover { background: var(--fill-quaternary); } .table-ios--striped tbody tr:nth-child(even) { background: var(--fill-quaternary); } .table-ios--striped tbody tr:nth-child(even):hover { background: var(--fill-tertiary); } .table-ios th:first-child, .table-ios td:first-child { padding-left: var(--space-5); } .table-ios th:last-child, .table-ios td:last-child { padding-right: var(--space-5); } .table-ios .cell-mono { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--label-secondary); } .table-ios .cell-action { text-align: right; width: 1px; white-space: nowrap; } /* ── Modal Overlay ────────────────────────────────────────── */ .modal-overlay { position: fixed; inset: 0; background: var(--bg-overlay); -webkit-backdrop-filter: blur(8px) saturate(180%); backdrop-filter: blur(8px) saturate(180%); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: var(--space-4); opacity: 0; pointer-events: none; transition: opacity var(--duration-base) var(--ease); } .modal-overlay.open { opacity: 1; pointer-events: all; } .modal { background: var(--bg-card); border-radius: var(--radius-xl); box-shadow: var(--shadow-lg); width: 100%; max-width: 540px; max-height: 90dvh; display: flex; flex-direction: column; overflow: hidden; transform: scale(0.94) translateY(12px); transition: transform var(--duration-base) var(--ease-spring); } .modal-overlay.open .modal { transform: scale(1) translateY(0); } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-5) var(--space-5) var(--space-4); border-bottom: 0.5px solid var(--separator); flex-shrink: 0; } .modal-title { font-size: var(--text-lg); font-weight: var(--weight-semibold); letter-spacing: -0.3px; color: var(--label-primary); } .modal-close { width: 32px; height: 32px; border-radius: var(--radius-full); background: var(--fill-secondary); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--label-secondary); flex-shrink: 0; transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease); } .modal-close:hover { background: var(--fill-primary); color: var(--label-primary); } .modal-body { flex: 1; overflow-y: auto; padding: var(--space-5); -webkit-overflow-scrolling: touch; } .modal-footer { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-top: 0.5px solid var(--separator); flex-shrink: 0; } /* Bottom sheet variant */ .modal-overlay--sheet { align-items: flex-end; padding: 0; } .modal-overlay--sheet .modal { max-width: 100%; border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; transform: translateY(100%); max-height: 85dvh; } .modal-overlay--sheet.open .modal { transform: translateY(0); } .modal-sheet-handle { width: 36px; height: 5px; border-radius: var(--radius-full); background: var(--fill-primary); margin: var(--space-2) auto var(--space-1); flex-shrink: 0; } /* ── Toast / Snackbar ─────────────────────────────────────── */ .toast-container { position: fixed; top: var(--space-4); right: var(--space-4); z-index: 2000; display: flex; flex-direction: column; gap: var(--space-2); pointer-events: none; max-width: 360px; width: calc(100% - 2 * var(--space-4)); } .toast { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) var(--space-4); background: var(--bg-elevated); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); border: 0.5px solid var(--separator); pointer-events: all; cursor: pointer; opacity: 0; transform: translateX(calc(100% + var(--space-4))); transition: opacity var(--duration-base) var(--ease), transform var(--duration-base) var(--ease-spring); } .toast.show { opacity: 1; transform: translateX(0); } .toast.hide { opacity: 0; transform: translateX(calc(100% + var(--space-4))); } .toast__icon { width: 20px; height: 20px; border-radius: var(--radius-full); display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-top: 1px; } .toast--success .toast__icon { background: rgba(52, 199, 89, 0.15); color: var(--color-success); } .toast--warning .toast__icon { background: rgba(255, 149, 0, 0.15); color: var(--color-warning); } .toast--danger .toast__icon { background: rgba(255, 59, 48, 0.15); color: var(--color-danger); } .toast--info .toast__icon { background: rgba(0, 122, 255, 0.15); color: var(--color-primary); } .toast__body { flex: 1; min-width: 0; } .toast__title { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--label-primary); line-height: 1.3; } .toast__message { font-size: var(--text-xs); color: var(--label-secondary); margin-top: 2px; line-height: 1.4; } .toast__dismiss { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--label-tertiary); border: none; background: none; cursor: pointer; padding: 0; border-radius: var(--radius-full); transition: color var(--duration-fast) var(--ease), background var(--duration-fast) var(--ease); } .toast__dismiss:hover { color: var(--label-primary); background: var(--fill-secondary); } /* ── Badge ────────────────────────────────────────────────── */ .badge { display: inline-flex; align-items: center; justify-content: center; padding: 2px 7px; border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: var(--weight-semibold); line-height: 1.4; white-space: nowrap; letter-spacing: 0.1px; } .badge--primary { background: rgba(0, 122, 255, 0.12); color: var(--color-primary); } .badge--success { background: rgba(52, 199, 89, 0.12); color: var(--color-success); } .badge--warning { background: rgba(255, 149, 0, 0.12); color: var(--color-warning); } .badge--danger { background: rgba(255, 59, 48, 0.12); color: var(--color-danger); } .badge--purple { background: rgba(175, 82, 222, 0.12); color: var(--color-purple); } .badge--gray { background: var(--fill-secondary); color: var(--label-secondary); } .badge--filled-primary { background: var(--color-primary); color: #fff; } .badge--filled-success { background: var(--color-success); color: #fff; } .badge--filled-warning { background: var(--color-warning); color: #fff; } .badge--filled-danger { background: var(--color-danger); color: #fff; } /* Dot badge (notification count) */ .badge-dot { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--radius-full); font-size: 11px; font-weight: var(--weight-bold); line-height: 1; background: var(--color-danger); color: #fff; } /* ── Avatar ───────────────────────────────────────────────── */ .avatar { --av-size: 40px; --av-radius: var(--radius-full); width: var(--av-size); height: var(--av-size); border-radius: var(--av-radius); background: var(--fill-secondary); display: inline-flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; font-size: calc(var(--av-size) * 0.4); font-weight: var(--weight-semibold); color: var(--label-primary); letter-spacing: -0.2px; } .avatar--xs { --av-size: 24px; } .avatar--sm { --av-size: 32px; } .avatar--md { --av-size: 40px; } .avatar--lg { --av-size: 48px; } .avatar--xl { --av-size: 64px; } .avatar--2xl { --av-size: 80px; } .avatar--rounded { --av-radius: var(--radius-sm); } .avatar--square { --av-radius: 0; } .avatar img { width: 100%; height: 100%; object-fit: cover; } .avatar--blue { background: rgba(0, 122, 255, 0.15); color: var(--color-primary); } .avatar--green { background: rgba(52, 199, 89, 0.15); color: var(--color-success); } .avatar--orange { background: rgba(255, 149, 0, 0.15); color: var(--color-warning); } .avatar--red { background: rgba(255, 59, 48, 0.15); color: var(--color-danger); } .avatar--purple { background: rgba(175, 82, 222, 0.15); color: var(--color-purple); } .avatar-group { display: flex; flex-direction: row-reverse; } .avatar-group .avatar { border: 2px solid var(--bg-secondary); margin-left: -8px; } .avatar-group .avatar:last-child { margin-left: 0; } /* ── Buttons ──────────────────────────────────────────────── */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: 0 var(--space-5); height: 44px; border-radius: var(--radius-md); font-size: var(--text-base); font-weight: var(--weight-semibold); letter-spacing: -0.2px; border: none; cursor: pointer; text-decoration: none; user-select: none; white-space: nowrap; -webkit-tap-highlight-color: transparent; transition: opacity var(--duration-fast) var(--ease), transform var(--duration-fast) var(--ease), background var(--duration-fast) var(--ease), box-shadow var(--duration-fast) var(--ease); } .btn:active { transform: scale(0.97); opacity: 0.85; } .btn:disabled { opacity: 0.38; cursor: not-allowed; pointer-events: none; } .btn--sm { height: 36px; padding: 0 var(--space-4); font-size: var(--text-sm); border-radius: var(--radius-sm); } .btn--lg { height: 50px; padding: 0 var(--space-6); font-size: var(--text-md); border-radius: var(--radius-lg); } .btn--full { width: 100%; } .btn--icon { width: 44px; padding: 0; border-radius: var(--radius-md); } .btn--icon.btn--sm { width: 36px; } .btn--icon.btn--lg { width: 50px; } .btn-primary { background: var(--color-primary); color: #FFFFFF; } .btn-primary:hover { background: color-mix(in srgb, var(--color-primary) 88%, #000); box-shadow: 0 4px 12px rgba(0, 122, 255, 0.35); } .btn-secondary { background: var(--fill-secondary); color: var(--color-primary); } .btn-secondary:hover { background: var(--fill-primary); } .btn-danger { background: var(--color-danger); color: #FFFFFF; } .btn-danger:hover { background: color-mix(in srgb, var(--color-danger) 88%, #000); box-shadow: 0 4px 12px rgba(255, 59, 48, 0.35); } .btn-success { background: var(--color-success); color: #FFFFFF; } .btn-success:hover { background: color-mix(in srgb, var(--color-success) 88%, #000); } .btn-ghost { background: transparent; color: var(--color-primary); } .btn-ghost:hover { background: var(--fill-quaternary); } .btn-outline { background: transparent; color: var(--color-primary); border: 1.5px solid var(--color-primary); } .btn-outline:hover { background: rgba(0, 122, 255, 0.06); } .btn-outline-danger { background: transparent; color: var(--color-danger); border: 1.5px solid var(--color-danger); } .btn-outline-danger:hover { background: rgba(255, 59, 48, 0.06); } /* Loading state */ .btn.loading { pointer-events: none; opacity: 0.7; } .btn.loading::after { content: ""; width: 16px; height: 16px; border: 2px solid currentColor; border-top-color: transparent; border-radius: var(--radius-full); animation: btn-spin 0.6s linear infinite; } @keyframes btn-spin { to { transform: rotate(360deg); } } /* ── Section Group (iOS grouped style) ───────────────────── */ .section-group { background: var(--bg-card); border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-card); margin-bottom: var(--space-4); } .section-group-header { padding: var(--space-3) var(--space-4) var(--space-2); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--label-secondary); text-transform: uppercase; letter-spacing: 0.5px; } .section-group-footer { padding: var(--space-2) var(--space-4) var(--space-3); font-size: var(--text-xs); color: var(--label-tertiary); line-height: 1.4; } .section-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); min-height: 44px; border-bottom: 0.5px solid var(--separator); transition: background var(--duration-fast) var(--ease); text-decoration: none; color: var(--label-primary); } .section-row:last-child { border-bottom: none; } .section-row--tappable { cursor: pointer; } .section-row--tappable:hover { background: var(--fill-quaternary); } .section-row--tappable:active { background: var(--fill-secondary); } .section-row__icon { width: 28px; height: 28px; border-radius: var(--radius-xs); display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 15px; } .section-row__icon--blue { background: var(--color-primary); color: #fff; } .section-row__icon--green { background: var(--color-success); color: #fff; } .section-row__icon--orange { background: var(--color-warning); color: #fff; } .section-row__icon--red { background: var(--color-danger); color: #fff; } .section-row__icon--purple { background: var(--color-purple); color: #fff; } .section-row__body { flex: 1; min-width: 0; } .section-row__label { font-size: var(--text-base); color: var(--label-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .section-row__detail { font-size: var(--text-sm); color: var(--label-secondary); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .section-row__value { font-size: var(--text-sm); color: var(--label-secondary); flex-shrink: 0; } .section-row__chevron { color: var(--label-quaternary); flex-shrink: 0; } /* ── Wizard Step ──────────────────────────────────────────── */ .wizard { display: flex; flex-direction: column; gap: 0; } .wizard-steps { display: flex; align-items: center; padding: var(--space-4) var(--space-5); gap: 0; counter-reset: wizard-counter; } .wizard-step { display: flex; align-items: center; flex: 1; min-width: 0; counter-increment: wizard-counter; } .wizard-step:last-child { flex: 0; } .wizard-step__indicator { width: 28px; height: 28px; border-radius: var(--radius-full); display: flex; align-items: center; justify-content: center; font-size: var(--text-xs); font-weight: var(--weight-bold); flex-shrink: 0; transition: background var(--duration-base) var(--ease), color var(--duration-base) var(--ease), box-shadow var(--duration-base) var(--ease); position: relative; z-index: 1; } .wizard-step__indicator::before { content: counter(wizard-counter); } /* pending */ .wizard-step .wizard-step__indicator { background: var(--fill-secondary); color: var(--label-tertiary); } /* active */ .wizard-step--active .wizard-step__indicator { background: var(--color-primary); color: #fff; box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.20); } /* completed */ .wizard-step--done .wizard-step__indicator { background: var(--color-success); color: #fff; } .wizard-step--done .wizard-step__indicator::before { content: "✓"; } /* error */ .wizard-step--error .wizard-step__indicator { background: var(--color-danger); color: #fff; } .wizard-step--error .wizard-step__indicator::before { content: "!"; } .wizard-step__connector { flex: 1; height: 2px; background: var(--fill-secondary); margin: 0 var(--space-2); border-radius: 1px; transition: background var(--duration-base) var(--ease); } .wizard-step--done + .wizard-step .wizard-step__connector, .wizard-step--done .wizard-step__connector { background: var(--color-success); } .wizard-step__label { display: none; } /* Show labels on wider screens */ @media (min-width: 640px) { .wizard-step { flex-direction: column; align-items: center; gap: var(--space-2); } .wizard-step__connector { display: none; } .wizard-steps { gap: var(--space-2); } .wizard-step__label { display: block; font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--label-tertiary); text-align: center; white-space: nowrap; } .wizard-step--active .wizard-step__label { color: var(--color-primary); font-weight: var(--weight-semibold); } .wizard-step--done .wizard-step__label { color: var(--color-success); } .wizard-step::after { content: ""; position: absolute; top: 14px; left: calc(50% + 18px); right: calc(-50% + 18px); height: 2px; background: var(--fill-secondary); } } .wizard-panel { display: none; } .wizard-panel--active { display: block; animation: wizard-in var(--duration-base) var(--ease); } @keyframes wizard-in { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: translateX(0); } } .wizard-actions { display: flex; align-items: center; justify-content: space-between; padding: var(--space-4) var(--space-5); border-top: 0.5px solid var(--separator); } /* ── Timeline ─────────────────────────────────────────────── */ .timeline { display: flex; flex-direction: column; gap: 0; padding: var(--space-2) 0; } .timeline-item { display: flex; gap: var(--space-4); position: relative; padding-bottom: var(--space-5); } .timeline-item:last-child { padding-bottom: 0; } .timeline-item__left { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; width: 32px; } .timeline-item__dot { width: 12px; height: 12px; border-radius: var(--radius-full); background: var(--fill-primary); border: 2px solid var(--bg-primary); flex-shrink: 0; z-index: 1; transition: background var(--duration-fast) var(--ease); } .timeline-item--success .timeline-item__dot { background: var(--color-success); } .timeline-item--warning .timeline-item__dot { background: var(--color-warning); } .timeline-item--danger .timeline-item__dot { background: var(--color-danger); } .timeline-item--info .timeline-item__dot { background: var(--color-primary); } .timeline-item__line { flex: 1; width: 1.5px; background: var(--separator); margin-top: 4px; min-height: var(--space-5); } .timeline-item:last-child .timeline-item__line { display: none; } .timeline-item__body { flex: 1; padding-top: 0; min-width: 0; } .timeline-item__header { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; } .timeline-item__title { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--label-primary); line-height: 1.3; } .timeline-item__time { font-size: var(--text-xs); color: var(--label-tertiary); white-space: nowrap; margin-left: auto; } .timeline-item__content { font-size: var(--text-sm); color: var(--label-secondary); margin-top: var(--space-1); line-height: 1.5; } .timeline-item__meta { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); flex-wrap: wrap; } /* ── Form Elements ────────────────────────────────────────── */ .form-group { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); } .form-label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--label-secondary); } .form-input { width: 100%; height: 44px; padding: 0 var(--space-4); background: var(--bg-tertiary); border: 1.5px solid transparent; border-radius: var(--radius-md); font-size: var(--text-base); color: var(--label-primary); outline: none; transition: border-color var(--duration-fast) var(--ease), background var(--duration-fast) var(--ease); -webkit-appearance: none; } .form-input::placeholder { color: var(--label-quaternary); } .form-input:focus { background: var(--bg-secondary); border-color: var(--color-primary); } .form-input--error { border-color: var(--color-danger); } .form-hint { font-size: var(--text-xs); color: var(--label-tertiary); line-height: 1.4; } .form-error { font-size: var(--text-xs); color: var(--color-danger); font-weight: var(--weight-medium); } .form-select { -webkit-appearance: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right var(--space-4) center; padding-right: var(--space-8); } textarea.form-input { height: auto; padding: var(--space-3) var(--space-4); resize: vertical; min-height: 100px; } /* ── Search Bar ───────────────────────────────────────────── */ .search-bar { position: relative; display: flex; align-items: center; } .search-bar__icon { position: absolute; left: var(--space-3); color: var(--label-tertiary); pointer-events: none; z-index: 1; } .search-bar__input { width: 100%; height: 36px; padding: 0 var(--space-4) 0 var(--space-8); background: var(--fill-secondary); border: none; border-radius: var(--radius-md); font-size: var(--text-sm); color: var(--label-primary); outline: none; transition: background var(--duration-fast) var(--ease); -webkit-appearance: none; } .search-bar__input::placeholder { color: var(--label-tertiary); } .search-bar__input:focus { background: var(--fill-primary); } /* ── Progress Bar ─────────────────────────────────────────── */ .progress-bar { height: 6px; background: var(--fill-secondary); border-radius: var(--radius-full); overflow: hidden; } .progress-bar__fill { height: 100%; border-radius: var(--radius-full); background: var(--color-primary); transition: width var(--duration-slow) var(--ease); } .progress-bar--success .progress-bar__fill { background: var(--color-success); } .progress-bar--warning .progress-bar__fill { background: var(--color-warning); } .progress-bar--danger .progress-bar__fill { background: var(--color-danger); } /* ── Skeleton Loading ─────────────────────────────────────── */ .skeleton { background: var(--fill-secondary); border-radius: var(--radius-sm); animation: skeleton-pulse 1.4s ease-in-out infinite; } @keyframes skeleton-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } } /* ── Empty State ──────────────────────────────────────────── */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: var(--space-12) var(--space-6); gap: var(--space-4); } .empty-state__icon { width: 56px; height: 56px; border-radius: var(--radius-lg); background: var(--fill-tertiary); display: flex; align-items: center; justify-content: center; font-size: 28px; color: var(--label-tertiary); } .empty-state__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--label-primary); } .empty-state__body { font-size: var(--text-base); color: var(--label-secondary); max-width: 300px; line-height: 1.5; } /* ── Stat Row ─────────────────────────────────────────────── */ .stat-row { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-3) 0; border-bottom: 0.5px solid var(--separator); } .stat-row:last-child { border-bottom: none; } .stat-row__label { font-size: var(--text-sm); color: var(--label-secondary); flex: 1; } .stat-row__value { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--label-primary); font-family: var(--font-mono); } .stat-row__bar { width: 80px; flex-shrink: 0; } /* ── Code Block ───────────────────────────────────────────── */ .code-block { background: var(--bg-tertiary); border-radius: var(--radius-sm); padding: var(--space-4); overflow-x: auto; font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.6; color: var(--label-primary); border: 0.5px solid var(--separator); position: relative; } .code-block pre { margin: 0; white-space: pre; } code { font-family: var(--font-mono); font-size: 0.875em; background: var(--fill-tertiary); padding: 1px 5px; border-radius: var(--radius-xs); color: var(--label-primary); } /* ── Card ─────────────────────────────────────────────────── */ .card { background: var(--bg-card); border-radius: var(--radius-md); box-shadow: var(--shadow-card); overflow: hidden; } .card-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-4) var(--space-5); border-bottom: 0.5px solid var(--separator); } .card-title { font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--label-primary); letter-spacing: -0.2px; } .card-body { padding: var(--space-5); } .card-footer { padding: var(--space-3) var(--space-5); border-top: 0.5px solid var(--separator); background: var(--fill-quaternary); } /* ── Context Menu / Dropdown ──────────────────────────────── */ .dropdown { position: relative; display: inline-block; } .dropdown-menu { position: absolute; top: calc(100% + 6px); right: 0; min-width: 200px; background: var(--bg-elevated); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); border: 0.5px solid var(--separator); z-index: 500; overflow: hidden; opacity: 0; transform: scale(0.94) translateY(-6px); pointer-events: none; transform-origin: top right; transition: opacity var(--duration-fast) var(--ease), transform var(--duration-fast) var(--ease-spring); } .dropdown-menu.open { opacity: 1; transform: scale(1) translateY(0); pointer-events: all; } .dropdown-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); font-size: var(--text-sm); color: var(--label-primary); cursor: pointer; border-bottom: 0.5px solid var(--separator); transition: background var(--duration-fast) var(--ease); text-decoration: none; } .dropdown-item:last-child { border-bottom: none; } .dropdown-item:hover { background: var(--fill-quaternary); } .dropdown-item--danger { color: var(--color-danger); } .dropdown-separator { height: 0.5px; background: var(--separator); } /* ── Tab Bar (mobile bottom navigation) ─────────────────── */ .tab-bar { display: none; position: fixed; bottom: 0; left: 0; right: 0; height: var(--tab-bar-height); padding-bottom: env(safe-area-inset-bottom, 16px); background: rgba(242, 242, 247, 0.92); -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%); border-top: 0.5px solid var(--separator); z-index: 200; } @media (prefers-color-scheme: dark) { .tab-bar { background: rgba(28, 28, 30, 0.92); } } .tab-bar-inner { display: flex; align-items: center; height: calc(var(--tab-bar-height) - env(safe-area-inset-bottom, 16px)); } .tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: var(--space-1) 0; cursor: pointer; color: var(--label-tertiary); text-decoration: none; transition: color var(--duration-fast) var(--ease); -webkit-tap-highlight-color: transparent; position: relative; } .tab-item.active { color: var(--color-primary); } .tab-item__icon { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; transition: transform var(--duration-fast) var(--ease-spring); } .tab-item:active .tab-item__icon { transform: scale(0.88); } .tab-item__label { font-size: 10px; font-weight: var(--weight-medium); letter-spacing: 0.1px; line-height: 1; } .tab-item__badge { position: absolute; top: 4px; left: calc(50% + 6px); } /* ── Utility Classes ──────────────────────────────────────── */ .text-primary { color: var(--color-primary) !important; } .text-success { color: var(--color-success) !important; } .text-warning { color: var(--color-warning) !important; } .text-danger { color: var(--color-danger) !important; } .text-secondary { color: var(--label-secondary) !important; } .text-tertiary { color: var(--label-tertiary) !important; } .text-xs { font-size: var(--text-xs) !important; } .text-sm { font-size: var(--text-sm) !important; } .text-base { font-size: var(--text-base) !important; } .text-md { font-size: var(--text-md) !important; } .text-lg { font-size: var(--text-lg) !important; } .font-regular { font-weight: var(--weight-regular) !important; } .font-medium { font-weight: var(--weight-medium) !important; } .font-semibold { font-weight: var(--weight-semibold) !important; } .font-bold { font-weight: var(--weight-bold) !important; } .font-mono { font-family: var(--font-mono) !important; } .truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .flex { display: flex; } .flex-col { flex-direction: column; } .items-center { align-items: center; } .justify-between { justify-content: space-between; } .gap-1 { gap: var(--space-1); } .gap-2 { gap: var(--space-2); } .gap-3 { gap: var(--space-3); } .gap-4 { gap: var(--space-4); } .gap-6 { gap: var(--space-6); } .m-0 { margin: 0; } .mt-2 { margin-top: var(--space-2); } .mt-4 { margin-top: var(--space-4); } .mt-6 { margin-top: var(--space-6); } .mb-2 { margin-bottom: var(--space-2); } .mb-4 { margin-bottom: var(--space-4); } .mb-6 { margin-bottom: var(--space-6); } .p-4 { padding: var(--space-4); } .p-5 { padding: var(--space-5); } .p-6 { padding: var(--space-6); } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } /* ── Scrollbars ───────────────────────────────────────────── */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--fill-secondary); border-radius: var(--radius-full); } ::-webkit-scrollbar-thumb:hover { background: var(--fill-primary); } /* ── Animations ───────────────────────────────────────────── */ @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes slide-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } @keyframes slide-down { from { opacity: 0; transform: translateY(-16px); } to { opacity: 1; transform: translateY(0); } } @keyframes scale-in { from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: scale(1); } } .animate-fade-in { animation: fade-in var(--duration-base) var(--ease) both; } .animate-slide-up { animation: slide-up var(--duration-base) var(--ease) both; } .animate-scale-in { animation: scale-in var(--duration-base) var(--ease-spring) both; } /* ── Reduced Motion ───────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } } /* ── Responsive: Tablet (≤ 1024px) ───────────────────────── */ @media (max-width: 1024px) { :root { --sidebar-width: 200px; } } /* ── Responsive: Mobile (≤ 767px) ────────────────────────── */ @media (max-width: 767px) { .sidebar { transform: translateX(-100%); box-shadow: var(--shadow-lg); } .sidebar.open { transform: translateX(0); } .main-content { margin-left: 0; padding-bottom: var(--tab-bar-height); } .tab-bar { display: block; } .page-body { padding: var(--space-4); } .kpi-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-3); } .modal { max-width: 100%; border-radius: var(--radius-xl) var(--radius-xl) 0 0; margin: auto 0 0; } .modal-overlay { align-items: flex-end; } .modal-overlay .modal { transform: translateY(100%); } .modal-overlay.open .modal { transform: translateY(0); } .toast-container { top: auto; bottom: calc(var(--tab-bar-height) + var(--space-3)); right: var(--space-3); left: var(--space-3); max-width: 100%; width: auto; } .table-ios { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; } .wizard-step__label { display: none; } } /* ── Responsive: Large (≥ 1280px) ────────────────────────── */ @media (min-width: 1280px) { .kpi-grid { grid-template-columns: repeat(4, 1fr); } } /* Sidebar overlay for mobile */ .sidebar-overlay { display: none; position: fixed; inset: 0; background: var(--bg-overlay); z-index: 199; opacity: 0; transition: opacity var(--transition); } @media (max-width: 767px) { .sidebar-overlay { display: block; } .sidebar-overlay.open { opacity: 1; } }