@import url('https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@400;500;600;700&display=swap'); :root { font-family: 'Plus Jakarta Sans', system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.6; font-weight: 400; } html[lang='he'], html[dir='rtl'] { font-family: 'Heebo', 'Rubik', 'Noto Sans Hebrew', 'Segoe UI', Arial, sans-serif; } html[lang='ar'] { font-family: 'Noto Sans Arabic', 'Cairo', 'Tajawal', 'Segoe UI', Arial, sans-serif; } :root { color-scheme: light dark; color: var(--text-primary); background-color: var(--bg-light); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } a { font-weight: 500; text-decoration: inherit; } body { margin: 0; min-width: 320px; min-height: 100vh; } h1 { font-size: 1.875rem; font-weight: 700; color: var(--text-primary); margin: 0; letter-spacing: -0.025em; } /* h2 is a real heading again — the old global made EVERY h2 a small uppercase eyebrow, which forced pages to keep resetting it (and left section titles smaller than body text). The eyebrow look is now opt-in via .eyebrow for the section/card labels that actually want it. */ h2 { font-size: 1.25rem; font-weight: 700; color: var(--text-primary); margin: 0; } .eyebrow { font-size: 0.8125rem; font-weight: 600; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin: 0; } h3 { font-size: 1rem; font-weight: 600; color: var(--text-primary); margin: 0; } button { border-radius: 8px; border: 1px solid transparent; padding: 0.6em 1.2em; font-size: 1em; font-weight: 500; font-family: inherit; cursor: pointer; transition: border-color 0.25s; } /* Visible keyboard focus — cross-browser and keyboard-only, so the ring guides Tab navigation without flashing on every mouse click. */ button:focus-visible, a:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--primary, #25d366); outline-offset: 2px; } button:focus:not(:focus-visible) { outline: none; } html { /* Root/overscroll background follows the app theme token, so an explicit dark theme on a light-OS device doesn't reveal a white background above/below the body (overscroll). */ background-color: var(--bg-light); } @media (prefers-color-scheme: light) { /* Guarded with :not([data-theme='dark']): when the OS prefers light but the user explicitly picked the dark theme, the app's own choice must win (otherwise the root is force-whitened). */ :root:not([data-theme='dark']) { color: #213547; background-color: #ffffff; } } /* Global select/dropdown styling */ select { appearance: none; -webkit-appearance: none; -moz-appearance: none; width: 100%; padding: 0.75rem 2.5rem 0.75rem 1rem; font-size: 0.9375rem; font-family: inherit; color: var(--text-primary); background-color: var(--bg-white, #fff); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px; border: 1px solid var(--border, #e2e8f0); border-radius: 8px; cursor: pointer; transition: all 0.2s; } select:hover { border-color: var(--primary, #25d366); } select:focus { outline: none; border-color: var(--primary, #25d366); box-shadow: 0 0 0 3px rgba(37, 211, 102, 0.1); } select:disabled { background-color: var(--bg-light, #f8fafc); color: var(--text-muted, #94a3b8); cursor: not-allowed; } /* GLOBAL MODAL STYLES */ /* Modal Overlay */ .modal-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; animation: fadeIn 0.2s ease; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* Modal Card */ .modal { background: var(--bg-white, #fff); border-radius: 16px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); width: 90%; max-width: 480px; animation: slideUp 0.3s ease; /* Cap height and lay out as a flex column so the body scrolls while the header and footer stay pinned — config-heavy modals no longer push the title/Save button off-screen. */ display: flex; flex-direction: column; max-height: 90vh; overflow: hidden; } /* The install-plugin modal holds the catalog list — a bit wider on desktop for comfortable reading. The responsive rules below (<=768px: 95% width; <=480px: full-width bottom sheet) still apply, so it stays responsive on small screens. Lives here (global modal styles) rather than in a page CSS so it isn't subject to the page-root scoping rule. */ .modal.install-modal { max-width: 680px; } @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .modal-header { display: flex; justify-content: space-between; align-items: center; padding: 1.5rem 1.5rem 1rem; border-bottom: 1px solid var(--border, #e2e8f0); flex-shrink: 0; } .modal-header h2 { font-size: 1.25rem; font-weight: 700; color: var(--text-primary, #1e293b); margin: 0; text-transform: none; letter-spacing: normal; } .modal-body { padding: 1.5rem; /* Scroll the body (not the whole card) so the pinned header/footer stay visible. */ overflow-y: auto; flex: 1 1 auto; } .modal-body > label { display: block; font-size: 0.875rem; font-weight: 600; color: var(--text-secondary, #64748b); margin-bottom: 0.5rem; } .modal-body input { width: 100%; padding: 0.875rem 1rem; border: 1px solid var(--border, #e2e8f0); border-radius: 8px; font-size: 0.9375rem; background: var(--bg-light, #f8fafc); transition: all 0.2s; box-sizing: border-box; } .modal-body input:focus { outline: none; border-color: var(--primary, #25d366); background: var(--bg-white, #fff); box-shadow: 0 0 0 3px rgba(37, 211, 102, 0.1); } /* The rule above is meant for TEXT inputs. Radios/checkboxes would otherwise stretch to width:100% and shove their labels far to the right; reset them back to their native box. The :not() excludes the visually-hidden toggle-switch checkbox (it must stay width:0) so this never ties with the per-page `.toggle-switch input { width:0 }` rule on specificity. */ .modal-body input[type='radio']:not(.toggle-switch input), .modal-body input[type='checkbox']:not(.toggle-switch input) { width: auto; padding: 0; border: none; border-radius: 0; background: none; box-shadow: none; flex: none; } .modal-footer { display: flex; justify-content: flex-end; gap: 0.75rem; padding: 1rem 1.5rem 1.5rem; flex-shrink: 0; } /* Icon Button (modal close X) */ .btn-icon { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; background: var(--bg-light, #f8fafc); border: 1px solid var(--border, #e2e8f0); border-radius: 8px; cursor: pointer; color: var(--text-secondary, #64748b); transition: all 0.2s; flex-shrink: 0; padding: 0; } .btn-icon svg { width: 20px; height: 20px; stroke: var(--text-secondary, #64748b); } .btn-icon:hover { background: rgba(239, 68, 68, 0.12); border-color: rgba(239, 68, 68, 0.3); color: var(--error); } .btn-icon:hover svg { stroke: var(--error); } /* Secondary Button */ .btn-secondary { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1.25rem; background: var(--bg-light, #f8fafc); color: var(--text-secondary, #64748b); border: 1px solid var(--border, #e2e8f0); border-radius: 8px; font-size: 0.9375rem; font-weight: 600; cursor: pointer; transition: all 0.2s; } .btn-secondary:hover:not(:disabled) { background: var(--bg-white, #fff); border-color: var(--text-muted, #94a3b8); color: var(--text-primary, #1e293b); } .btn-secondary:disabled { opacity: 0.5; cursor: not-allowed; } /* Primary Button — canonical definition; page-scoped copies were consolidated here so the primary CTA looks identical on every page (padding/radius/disabled used to drift per page). */ .btn-primary { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1.25rem; background: var(--primary, #25d366); color: #fff; border: none; border-radius: 8px; font-size: 0.9375rem; font-weight: 600; cursor: pointer; transition: all 0.2s; } .btn-primary:hover:not(:disabled) { background: var(--primary-hover, #1da851); } .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; } /* Danger Button — canonical definition (page copies also used two different base reds). */ .btn-danger { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1.25rem; background: var(--error, #ef4444); color: #fff; border: none; border-radius: 8px; font-size: 0.9375rem; font-weight: 600; cursor: pointer; transition: all 0.2s; } .btn-danger:hover:not(:disabled) { background: #b91c1c; } .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; } /* Spin Animation */ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .animate-spin { animation: spin 1s linear infinite; } /* Code element styling */ code { background: var(--bg-light, #f1f5f9); padding: 0.125rem 0.375rem; border-radius: 4px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; color: var(--text-primary, #1e293b); } /* RTL / Hebrew direction support */ /* Keep code, technical identifiers, and numbers LTR even inside RTL containers */ [dir='rtl'] code, [dir='rtl'] .mono, [dir='rtl'] pre { direction: ltr; text-align: left; unicode-bidi: embed; } /* Modal footer: actions should align to the start of the writing direction */ [dir='rtl'] .modal-footer { justify-content: flex-end; flex-direction: row-reverse; } /* Select dropdown caret on the opposite side */ [dir='rtl'] select { padding: 0.75rem 1rem 0.75rem 2.5rem; background-position: left 0.75rem center; } /* Inputs in modals: text aligns naturally */ [dir='rtl'] .modal-body input, [dir='rtl'] .modal-body textarea, [dir='rtl'] input[type='text'], [dir='rtl'] input[type='url'], [dir='rtl'] input[type='password'], [dir='rtl'] input[type='number'], [dir='rtl'] textarea { text-align: right; } /* URLs, emails, phones — force LTR even inside RTL */ [dir='rtl'] input[type='url'], [dir='rtl'] input[type='email'], [dir='rtl'] input[type='tel'] { direction: ltr; text-align: left; } /* Toast container — slide in from the opposite side */ [dir='rtl'] .toast-container { right: auto; left: 1rem; } /* Mobile Responsive - Global */ @media (max-width: 768px) { h1 { font-size: 1.5rem; } .modal { width: 95%; max-width: none; margin: 1rem; border-radius: 12px; } .modal-header { padding: 1.25rem 1.25rem 0.875rem; } .modal-header h2 { font-size: 1.125rem; } .modal-body { padding: 1.25rem; } .modal-footer { padding: 0.875rem 1.25rem 1.25rem; } select { padding: 0.625rem 2.25rem 0.625rem 0.875rem; font-size: 0.875rem; } } @media (max-width: 480px) { h1 { font-size: 1.25rem; } .modal-overlay { align-items: flex-end; } .modal { width: 100%; margin: 0; border-radius: 16px 16px 0 0; /* max-height + body scroll already come from the base .modal rule; the bottom-sheet only changes width/anchoring. (Scrolling lives on .modal-body to avoid a double scrollbar.) */ } }