Files
magistr/frontend/ui-foundation.css

422 lines
10 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Единая визуальная основа Magistr.
*
* Файл подключается последним во всех пользовательских оболочках и задаёт
* общие инварианты: типографику, размеры элементов управления, фокус,
* радиусы, ритм и поведение на узких экранах. Локальные CSS отвечают только
* за компоновку и предметные компоненты конкретного раздела.
*/
:root {
--ui-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--ui-font-display: var(--ui-font-sans);
--ui-font-mono: "Cascadia Mono", "SFMono-Regular", Consolas, monospace;
--ui-control-sm: 32px;
--ui-control-md: 40px;
--ui-control-lg: 48px;
--ui-radius-control: 8px;
--ui-radius-field: 10px;
--ui-radius-panel: 16px;
--ui-radius-large: 24px;
--ui-space-1: 4px;
--ui-space-2: 8px;
--ui-space-3: 12px;
--ui-space-4: 16px;
--ui-space-5: 20px;
--ui-space-6: 24px;
--ui-space-8: 32px;
--ui-shadow-panel: 0 12px 32px rgba(15, 23, 42, 0.08);
--ui-shadow-floating: 0 20px 56px rgba(15, 23, 42, 0.18);
--ui-transition: 160ms cubic-bezier(0.2, 0, 0, 1);
--ui-focus-ring: var(--button-focus-ring, rgba(79, 70, 229, 0.35));
/* Совместимость с уже существующими токенами разделов. */
--button-radius: var(--ui-radius-control);
}
html {
color-scheme: dark;
font-size: 16px;
text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html[data-theme="light"] {
color-scheme: light;
}
body {
font-family: var(--ui-font-sans);
font-size: 1rem;
line-height: 1.5;
text-rendering: optimizeLegibility;
}
button,
input,
select,
textarea {
font: inherit;
letter-spacing: inherit;
}
button,
[role="button"],
a {
-webkit-tap-highlight-color: transparent;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--ui-font-display);
font-weight: 700;
line-height: 1.18;
letter-spacing: -0.025em;
text-wrap: balance;
}
p,
li,
dd {
text-wrap: pretty;
}
time,
input[type="date"],
input[type="time"],
.schedule-overview-next-time,
.academic-year-code,
.version-number,
.metric-value {
font-variant-numeric: tabular-nums;
}
::selection {
background: color-mix(in srgb, var(--accent, #4f46e5) 28%, transparent);
}
/* ===== Доступный фокус ===== */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
outline: 2px solid var(--accent, #4f46e5);
outline-offset: 2px;
}
:where(input, select, textarea):focus-visible {
border-color: var(--accent, #4f46e5);
box-shadow: 0 0 0 3px var(--ui-focus-ring);
}
/* ===== Кнопки ===== */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--ui-space-2);
min-width: 0;
min-height: var(--ui-control-md);
padding: 0 var(--ui-space-4);
border: 1px solid var(--button-secondary-border, var(--panel-border, var(--bg-card-border)));
border-radius: var(--ui-radius-control);
font-family: var(--ui-font-sans);
font-size: 0.875rem;
font-weight: 650;
line-height: 1;
text-align: center;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
user-select: none;
transition:
background-color var(--ui-transition),
border-color var(--ui-transition),
color var(--ui-transition),
box-shadow var(--ui-transition),
transform var(--ui-transition);
}
.btn:hover:not(:disabled):not([aria-disabled="true"]) {
transform: translateY(-1px);
}
.btn:active:not(:disabled):not([aria-disabled="true"]) {
transform: translateY(0);
}
.btn:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--ui-focus-ring);
}
.btn:disabled,
.btn[aria-disabled="true"] {
cursor: not-allowed;
opacity: 0.62;
transform: none;
}
.btn-sm {
min-height: var(--ui-control-sm);
padding-inline: var(--ui-space-3);
font-size: 0.8125rem;
}
.btn-md {
min-height: var(--ui-control-md);
padding-inline: var(--ui-space-4);
font-size: 0.875rem;
}
.btn-lg {
min-height: var(--ui-control-lg);
padding-inline: var(--ui-space-5);
font-size: 0.9375rem;
font-weight: 700;
}
.btn-icon-sm,
.btn-icon-md {
flex: 0 0 auto;
padding: 0;
border-radius: var(--ui-radius-control);
}
.btn-icon-sm {
width: var(--ui-control-sm);
height: var(--ui-control-sm);
min-height: var(--ui-control-sm);
}
.btn-icon-md {
width: var(--ui-control-md);
height: var(--ui-control-md);
min-height: var(--ui-control-md);
}
.btn-primary {
border-color: var(--button-primary-border, var(--accent, #4f46e5));
background: var(--button-primary-bg, var(--accent, #4f46e5));
color: var(--button-primary-text, #fff);
}
.btn-primary:hover:not(:disabled) {
border-color: var(--button-primary-border, var(--accent-strong, var(--accent-hover, #4338ca)));
background: var(--button-primary-bg-hover, var(--accent-strong, var(--accent-hover, #4338ca)));
color: var(--button-primary-text, #fff);
}
.btn-secondary {
border-color: var(--button-secondary-border, var(--panel-border, var(--bg-card-border)));
background: var(--button-secondary-bg, var(--panel, var(--bg-card)));
color: var(--button-secondary-text, var(--text, var(--text-primary)));
}
.btn-secondary:hover:not(:disabled) {
border-color: color-mix(in srgb, var(--accent, #4f46e5) 38%, var(--button-secondary-border, var(--panel-border, var(--bg-card-border))));
background: var(--button-secondary-bg-hover, var(--bg-hover, color-mix(in srgb, var(--accent, #4f46e5) 7%, var(--panel, var(--bg-card)))));
color: var(--button-secondary-text, var(--text, var(--text-primary)));
}
.btn-ghost {
border-color: var(--button-ghost-border, transparent);
background: transparent;
color: var(--text-secondary, var(--muted));
}
.btn-ghost:hover:not(:disabled) {
border-color: var(--button-ghost-border, var(--panel-border, var(--bg-card-border)));
background: var(--button-ghost-bg-hover, var(--bg-hover, rgba(148, 163, 184, 0.1)));
color: var(--text-primary, var(--text));
}
.btn-danger {
border-color: var(--button-danger-border, #b91c1c);
background: var(--button-danger-bg, #dc2626);
color: #fff;
}
.btn-danger-subtle {
border-color: var(--button-danger-subtle-border, rgba(239, 68, 68, 0.28));
background: var(--button-danger-subtle-bg, rgba(239, 68, 68, 0.12));
color: var(--button-danger-subtle-text, #b91c1c);
}
.btn-danger-subtle:hover:not(:disabled) {
border-color: var(--button-danger-subtle-border, rgba(239, 68, 68, 0.38));
background: var(--button-danger-subtle-bg-hover, rgba(239, 68, 68, 0.18));
color: var(--button-danger-subtle-text, #b91c1c);
}
.input-wrapper .toggle-password {
border-color: transparent;
background: transparent;
color: var(--text-placeholder, var(--muted));
}
/* ===== Поля форм ===== */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
select,
textarea {
border-radius: var(--ui-radius-field);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
select {
min-height: var(--ui-control-md);
}
textarea {
min-height: 96px;
line-height: 1.5;
resize: vertical;
}
input::placeholder,
textarea::placeholder {
color: var(--text-placeholder, var(--muted));
opacity: 1;
}
label {
line-height: 1.35;
}
/* ===== Поверхности и ритм ===== */
.card,
.settings-card,
.toolbar,
.schedule-overview,
.teacher-absence-panel,
.preference-board,
.preference-card,
.request-ledger-head,
.request-dialog {
border-radius: var(--ui-radius-panel);
}
.card,
.settings-card,
.toolbar,
.schedule-overview {
box-shadow: var(--ui-shadow-panel);
}
.card:hover {
transform: none;
box-shadow: var(--ui-shadow-panel);
}
.card-header-row,
.settings-header-row,
.dashboard-card-header,
.preference-board-head {
gap: var(--ui-space-4);
}
.form-row,
.filter-row,
.actions,
.week-nav {
column-gap: var(--ui-space-3);
}
table {
font-variant-numeric: tabular-nums;
}
th {
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.035em;
}
.table-actions-cell {
text-align: right;
}
.table-actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: var(--ui-space-2);
}
.schedule-visual-lesson {
padding-right: 2.55rem;
}
/* ===== Унифицированные кнопки закрытия ===== */
.modal-close,
.version-modal-close,
.settings-modal-close {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--ui-control-md);
height: var(--ui-control-md);
min-height: var(--ui-control-md);
padding: 0;
border: 1px solid var(--button-ghost-border, var(--panel-border, var(--bg-card-border)));
border-radius: var(--ui-radius-control);
background: transparent;
color: var(--text-secondary, var(--muted));
font-family: var(--ui-font-sans);
font-size: 1.35rem;
line-height: 1;
cursor: pointer;
transition: background-color var(--ui-transition), border-color var(--ui-transition), color var(--ui-transition);
}
.modal-close:hover,
.version-modal-close:hover,
.settings-modal-close:hover {
border-color: color-mix(in srgb, var(--error, #ef4444) 35%, transparent);
background: color-mix(in srgb, var(--error, #ef4444) 10%, transparent);
color: var(--error, #ef4444);
}
.modal-close--static {
position: static;
flex: 0 0 auto;
}
/* ===== Скролл и движение ===== */
* {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--text-secondary, var(--muted)) 42%, transparent) transparent;
}
@media (max-width: 640px) {
.shell {
padding: var(--ui-space-4);
}
.actions .btn:not(.btn-icon-sm):not(.btn-icon-md) {
flex: 1 1 auto;
}
.modal-content,
.request-dialog,
.version-modal-card {
border-radius: var(--ui-radius-panel);
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}