fix: font zone classes on tables + body/heading/nav zones in AppShell
- fs-zone-table on OrdersTable + LogisticsReadinessBoard (was missing) - fs-zone-body on main content area - fs-zone-heading on mobile + desktop headers - fs-zone-nav on mobile tab nav - CSS: added arbitrary px size overrides (10px/11px/12px/13px/14px) - CSS: reordered body zone last so table/card/nav/heading win at equal specificity
This commit is contained in:
parent
5e02f61567
commit
f69a52779f
|
|
@ -319,7 +319,7 @@ export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusO
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 fs-zone-table">
|
||||
<Panel className="space-y-4 p-5">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export const OrdersTable = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Panel className="p-0">
|
||||
<Panel className="p-0 fs-zone-table">
|
||||
<div className="space-y-4 border-b border-[var(--color-border)] px-5 py-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||
|
||||
const FontSettingsContext = createContext(null);
|
||||
|
||||
const STORAGE_KEY = "supersam-font-settings";
|
||||
|
||||
// Categories: key → { label, defaultScale, min, max, step, description }
|
||||
export const FONT_CATEGORIES = [
|
||||
{ key: "table", label: "Таблицы", description: "Текст в таблицах и списках", defaultScale: 1.0, min: 0.8, max: 1.5, step: 0.05 },
|
||||
{ key: "card", label: "Карточки", description: "Текст в карточках и панелях", defaultScale: 1.0, min: 0.8, max: 1.5, step: 0.05 },
|
||||
{ key: "nav", label: "Меню и навигация", description: "Пункты меню, вкладки, кнопки", defaultScale: 1.0, min: 0.8, max: 1.5, step: 0.05 },
|
||||
{ key: "heading", label: "Заголовки", description: "Названия секций и страниц", defaultScale: 1.0, min: 0.8, max: 1.6, step: 0.05 },
|
||||
{ key: "body", label: "Основной текст", description: "Обычный текст в интерфейсе", defaultScale: 1.0, min: 0.8, max: 1.5, step: 0.05 },
|
||||
{ key: "small", label: "Мелкий текст", description: "Подписи, метки, временные отметки", defaultScale: 1.0, min: 0.8, max: 1.5, step: 0.05 },
|
||||
];
|
||||
|
||||
const DEFAULT_SETTINGS = FONT_CATEGORIES.reduce((acc, cat) => {
|
||||
acc[cat.key] = cat.defaultScale;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
function loadSettings() {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return { ...DEFAULT_SETTINGS };
|
||||
const parsed = JSON.parse(raw);
|
||||
// Merge with defaults to handle new categories
|
||||
return { ...DEFAULT_SETTINGS, ...parsed };
|
||||
} catch {
|
||||
return { ...DEFAULT_SETTINGS };
|
||||
}
|
||||
}
|
||||
|
||||
function applySettings(settings) {
|
||||
const root = document.documentElement;
|
||||
for (const cat of FONT_CATEGORIES) {
|
||||
root.style.setProperty(`--fs-scale-${cat.key}`, String(settings[cat.key] ?? 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
export const FontSettingsProvider = ({ children }) => {
|
||||
const [settings, setSettings] = useState(loadSettings);
|
||||
|
||||
useEffect(() => {
|
||||
applySettings(settings);
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
|
||||
}, [settings]);
|
||||
|
||||
const updateCategory = (key, scale) => {
|
||||
setSettings((prev) => ({ ...prev, [key]: scale }));
|
||||
};
|
||||
|
||||
const resetAll = () => {
|
||||
setSettings({ ...DEFAULT_SETTINGS });
|
||||
};
|
||||
|
||||
const value = {
|
||||
settings,
|
||||
updateCategory,
|
||||
resetAll,
|
||||
categories: FONT_CATEGORIES,
|
||||
};
|
||||
|
||||
return <FontSettingsContext.Provider value={value}>{children}</FontSettingsContext.Provider>;
|
||||
};
|
||||
|
||||
export const useFontSettings = () => {
|
||||
const context = useContext(FontSettingsContext);
|
||||
if (!context) {
|
||||
throw new Error("useFontSettings must be used within FontSettingsProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ROLE_LABELS } from "../constants/roles";
|
||||
import { Badge } from "../components/UI/Badge";
|
||||
import { Button } from "../components/UI/Button";
|
||||
|
|
@ -47,7 +48,7 @@ export const AppShell = ({
|
|||
<div className="min-h-screen px-3 py-4 sm:px-4 md:px-6 md:py-8">
|
||||
<div className="mx-auto max-w-[1540px] space-y-4 xl:grid xl:grid-cols-[220px_1fr] xl:gap-8 xl:space-y-0">
|
||||
{/* Desktop sidebar */}
|
||||
<Panel className="hidden h-fit flex-col gap-5 p-4 xl:flex">
|
||||
<Panel className="fs-zone-nav hidden h-fit flex-col gap-5 p-4 xl:flex">
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-[0.24em] text-[var(--color-text-muted)]">
|
||||
Панель
|
||||
|
|
@ -81,6 +82,9 @@ export const AppShell = ({
|
|||
{isGuideOpen ? "К рабочей области" : "Справка"}
|
||||
</Button>
|
||||
) : null}
|
||||
<Button variant="ghost" className="mb-2 w-full justify-start" onClick={() => navigate("/settings")}>
|
||||
Настройки
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full justify-start" onClick={onSignOut}>
|
||||
Выйти
|
||||
</Button>
|
||||
|
|
@ -88,9 +92,9 @@ export const AppShell = ({
|
|||
</Panel>
|
||||
|
||||
{/* Main content area */}
|
||||
<div className="min-w-0 space-y-5 pb-20 xl:space-y-8 xl:pb-0">
|
||||
<div className="min-w-0 space-y-5 pb-20 xl:space-y-8 xl:pb-0 fs-zone-body">
|
||||
{/* Mobile header */}
|
||||
<Panel className="p-4 xl:hidden">
|
||||
<Panel className="p-4 xl:hidden fs-zone-heading">
|
||||
<div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
<p className="text-xs uppercase tracking-[0.2em] text-[var(--color-text-muted)]">
|
||||
|
|
@ -117,6 +121,9 @@ export const AppShell = ({
|
|||
</Button>
|
||||
) : null}
|
||||
<PwaInstallButton onInstall={onInstallApp} isInstalled={isInstalled} isInstallAvailable={isInstallAvailable} />
|
||||
<Button size="sm" variant="ghost" onClick={() => navigate("/settings")} aria-label="Настройки">
|
||||
⚙
|
||||
</Button>
|
||||
<ThemeToggle />
|
||||
<Button size="sm" variant="ghost" onClick={onSignOut}>
|
||||
Выйти
|
||||
|
|
@ -127,7 +134,7 @@ export const AppShell = ({
|
|||
|
||||
{/* Mobile tab navigation — STICKY TOP */}
|
||||
{shouldShowMobileNav && (
|
||||
<div className="sticky inset-x-0 top-0 z-40 -mx-3 -mt-4 border-b border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2 backdrop-blur xl:hidden sm:-mx-4 md:-mx-6">
|
||||
<div className="sticky inset-x-0 top-0 z-40 -mx-3 -mt-4 border-b border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2 backdrop-blur xl:hidden sm:-mx-4 md:-mx-6 fs-zone-nav">
|
||||
<div className="flex gap-1 overflow-x-auto" style={{ WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none' }}>
|
||||
{navItems.map((item) => (
|
||||
<Button
|
||||
|
|
@ -153,7 +160,7 @@ export const AppShell = ({
|
|||
)}
|
||||
|
||||
{/* Desktop header */}
|
||||
<Panel className="hidden p-4 md:p-5 xl:block">
|
||||
<Panel className="hidden p-4 md:p-5 xl:block fs-zone-heading">
|
||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<p className="text-sm uppercase tracking-[0.2em] text-[var(--color-text-muted)]">
|
||||
|
|
@ -184,6 +191,9 @@ export const AppShell = ({
|
|||
</Button>
|
||||
) : null}
|
||||
<PwaInstallButton onInstall={onInstallApp} isInstalled={isInstalled} isInstallAvailable={isInstallAvailable} />
|
||||
<Button size="sm" variant="ghost" onClick={() => navigate("/settings")} aria-label="Настройки">
|
||||
⚙
|
||||
</Button>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
10
src/main.jsx
10
src/main.jsx
|
|
@ -4,10 +4,12 @@ import { RouterProvider } from "react-router-dom";
|
|||
import { router } from "./router";
|
||||
import { ThemeProvider } from "./context/ThemeContext";
|
||||
import { AuthProvider } from "./context/AuthContext";
|
||||
import { FontSettingsProvider } from "./context/FontSettingsContext";
|
||||
import ErrorBoundary from "./components/ErrorBoundary";
|
||||
import { initErrorLogging } from "./utils/errorLogger";
|
||||
import { registerPwaServiceWorker } from "./hooks/usePwaStatus";
|
||||
import "./index.css";
|
||||
import "./styles/fontSettings.css";
|
||||
|
||||
registerPwaServiceWorker();
|
||||
initErrorLogging();
|
||||
|
|
@ -15,9 +17,11 @@ initErrorLogging();
|
|||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<ThemeProvider>
|
||||
<AuthProvider>
|
||||
<ErrorBoundary>
|
||||
<RouterProvider router={router} />
|
||||
</ErrorBoundary>
|
||||
<FontSettingsProvider>
|
||||
<ErrorBoundary>
|
||||
<RouterProvider router={router} />
|
||||
</ErrorBoundary>
|
||||
</FontSettingsProvider>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/**
|
||||
* @file SettingsPage.jsx
|
||||
* @description Page for user settings: font size controls for all UI categories.
|
||||
* Settings persist to localStorage via FontSettingsContext.
|
||||
*/
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useFontSettings, FONT_CATEGORIES } from "../context/FontSettingsContext";
|
||||
import { Panel } from "../components/UI/Panel";
|
||||
import { Button } from "../components/UI/Button";
|
||||
|
||||
const PRESETS = [
|
||||
{ label: "Мелкий", scales: { table: 0.85, card: 0.85, nav: 0.85, heading: 0.85, body: 0.85, small: 0.85 } },
|
||||
{ label: "Стандарт", scales: { table: 1.0, card: 1.0, nav: 1.0, heading: 1.0, body: 1.0, small: 1.0 } },
|
||||
{ label: "Крупный", scales: { table: 1.15, card: 1.15, nav: 1.15, heading: 1.2, body: 1.15, small: 1.1 } },
|
||||
{ label: "Очень крупный", scales: { table: 1.3, card: 1.3, nav: 1.25, heading: 1.4, body: 1.3, small: 1.2 } },
|
||||
];
|
||||
|
||||
const Slider = ({ category, value, onChange }) => {
|
||||
const pct = ((value - category.min) / (category.max - category.min)) * 100;
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-baseline justify-between">
|
||||
<div>
|
||||
<span className="font-medium text-[var(--color-text)]">{category.label}</span>
|
||||
<p className="text-xs text-[var(--color-text-muted)]">{category.description}</p>
|
||||
</div>
|
||||
<span className="text-sm font-semibold tabular-nums text-[var(--color-accent)]">
|
||||
{Math.round(value * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min={category.min}
|
||||
max={category.max}
|
||||
step={category.step}
|
||||
value={value}
|
||||
onChange={(e) => onChange(parseFloat(e.target.value))}
|
||||
className="fs-slider flex-1"
|
||||
style={{
|
||||
background: `linear-gradient(to right, var(--color-accent) 0%, var(--color-accent) ${pct}%, var(--color-border) ${pct}%, var(--color-border) 100%)`,
|
||||
}}
|
||||
aria-label={category.label}
|
||||
/>
|
||||
<span className="text-xs tabular-nums text-[var(--color-text-muted)] w-16 text-right">
|
||||
{value.toFixed(2)}×
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const SettingsPage = () => {
|
||||
const { settings, updateCategory, resetAll, categories } = useFontSettings();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const applyPreset = (scales) => {
|
||||
for (const [key, scale] of Object.entries(scales)) {
|
||||
updateCategory(key, scale);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if current settings match a preset
|
||||
const activePreset = PRESETS.findIndex((p) =>
|
||||
Object.entries(p.scales).every(([k, v]) => Math.abs((settings[k] ?? 1.0) - v) < 0.001)
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl space-y-6 px-3 py-4 sm:px-4 md:px-6 md:py-8">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-[0.2em] text-[var(--color-text-muted)]">Настройки</p>
|
||||
<h1 className="mt-1 text-2xl font-bold leading-tight" style={{ fontSize: `calc(1.5rem * var(--fs-scale-heading, 1))` }}>
|
||||
Настройки интерфейса
|
||||
</h1>
|
||||
</div>
|
||||
<Button variant="ghost" onClick={() => navigate(-1)}>
|
||||
← Назад
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Presets */}
|
||||
<Panel className="p-5 space-y-3">
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wider text-[var(--color-text-muted)]">
|
||||
Быстрые пресеты
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
{PRESETS.map((preset, i) => (
|
||||
<button
|
||||
key={preset.label}
|
||||
type="button"
|
||||
onClick={() => applyPreset(preset.scales)}
|
||||
className={[
|
||||
"rounded-[18px] border-2 px-4 py-3 text-center transition",
|
||||
activePreset === i
|
||||
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)] text-[var(--color-text)] font-semibold"
|
||||
: "border-[var(--color-border)] bg-[var(--color-surface-strong)] text-[var(--color-text-muted)] hover:border-[var(--color-accent)] hover:text-[var(--color-text)]",
|
||||
].join(" ")}
|
||||
>
|
||||
<div className="text-sm font-medium">{preset.label}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
{/* Font size sliders */}
|
||||
<Panel className="p-5 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wider text-[var(--color-text-muted)]">
|
||||
Размеры шрифтов
|
||||
</h2>
|
||||
<Button size="sm" variant="ghost" onClick={resetAll}>
|
||||
Сбросить
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
{categories.map((cat) => (
|
||||
<Slider
|
||||
key={cat.key}
|
||||
category={cat}
|
||||
value={settings[cat.key] ?? cat.defaultScale}
|
||||
onChange={(v) => updateCategory(cat.key, v)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Preview */}
|
||||
<div className="rounded-[18px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4 space-y-2">
|
||||
<p className="text-xs uppercase tracking-wider text-[var(--color-text-muted)]">Предпросмотр</p>
|
||||
<div className="fs-zone-heading space-y-1">
|
||||
<h3 className="font-bold" style={{ fontSize: `calc(1.25rem * var(--fs-scale-heading, 1))` }}>
|
||||
Заголовок секции
|
||||
</h3>
|
||||
</div>
|
||||
<div className="fs-zone-nav flex gap-2">
|
||||
<span className="rounded-[14px] bg-[var(--color-accent)] px-3 py-1.5 text-[var(--color-accent-contrast)]"
|
||||
style={{ fontSize: `calc(0.875rem * var(--fs-scale-nav, 1))` }}>
|
||||
Пункт меню
|
||||
</span>
|
||||
<span className="rounded-[14px] bg-[var(--color-surface)] px-3 py-1.5 border border-[var(--color-border)]"
|
||||
style={{ fontSize: `calc(0.875rem * var(--fs-scale-nav, 1))` }}>
|
||||
Вкладка
|
||||
</span>
|
||||
</div>
|
||||
<div className="fs-zone-table rounded-[14px] border border-[var(--color-border)] overflow-hidden">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="bg-[var(--color-surface)]">
|
||||
<th className="px-3 py-2 text-left font-semibold" style={{ fontSize: `calc(0.875rem * var(--fs-scale-table, 1))` }}>Дата</th>
|
||||
<th className="px-3 py-2 text-left font-semibold" style={{ fontSize: `calc(0.875rem * var(--fs-scale-table, 1))` }}>Статус</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr className="border-t border-[var(--color-border)]">
|
||||
<td className="px-3 py-2" style={{ fontSize: `calc(0.875rem * var(--fs-scale-table, 1))` }}>02.07.2026</td>
|
||||
<td className="px-3 py-2" style={{ fontSize: `calc(0.875rem * var(--fs-scale-table, 1))` }}>В работе</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="fs-zone-card rounded-[14px] bg-[var(--color-surface)] p-3">
|
||||
<p style={{ fontSize: `calc(0.875rem * var(--fs-scale-card, 1))` }}>
|
||||
Текст в карточке — описание доставки или заказа.
|
||||
</p>
|
||||
</div>
|
||||
<p className="fs-zone-body text-[var(--color-text)]" style={{ fontSize: `calc(1rem * var(--fs-scale-body, 1))` }}>
|
||||
Основной текст интерфейса.
|
||||
</p>
|
||||
<p className="fs-zone-small text-[var(--color-text-muted)]" style={{ fontSize: `calc(0.75rem * var(--fs-scale-small, 1))` }}>
|
||||
мелкая подпись · временная отметка
|
||||
</p>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<p className="text-center text-xs text-[var(--color-text-muted)]">
|
||||
Настройки сохраняются на этом устройстве
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsPage;
|
||||
|
|
@ -7,6 +7,7 @@ import { GroupDetailPage } from "./pages/GroupDetailPage";
|
|||
import { LoginPage } from "./pages/LoginPage";
|
||||
import { NotFoundPage } from "./pages/NotFoundPage";
|
||||
import { ForbiddenPage } from "./pages/ForbiddenPage";
|
||||
import { SettingsPage } from "./pages/SettingsPage";
|
||||
import { useAuth } from "./context/AuthContext";
|
||||
|
||||
/**
|
||||
|
|
@ -66,6 +67,14 @@ export const router = createBrowserRouter([
|
|||
</RequireAuth>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
element: (
|
||||
<RequireAuth>
|
||||
<SettingsPage />
|
||||
</RequireAuth>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <NotFoundPage />,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
/* Font size scale variables — applied by FontSettingsContext */
|
||||
:root {
|
||||
--fs-scale-table: 1.0;
|
||||
--fs-scale-card: 1.0;
|
||||
--fs-scale-nav: 1.0;
|
||||
--fs-scale-heading: 1.0;
|
||||
--fs-scale-body: 1.0;
|
||||
--fs-scale-small: 1.0;
|
||||
}
|
||||
|
||||
/* Slider styling */
|
||||
.fs-slider {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fs-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent);
|
||||
border: 3px solid var(--color-surface-strong);
|
||||
cursor: pointer;
|
||||
transition: transform 120ms ease;
|
||||
}
|
||||
|
||||
.fs-slider::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.fs-slider::-moz-range-thumb {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent);
|
||||
border: 3px solid var(--color-surface-strong);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* ── Zone overrides ──────────────────────────────────────────────────────
|
||||
.fs-zone-* wrappers override Tailwind text-* classes inside them.
|
||||
Specificity: .fs-zone-X .text-Y (0,2,0) > .text-Y (0,1,0).
|
||||
This lets us scale fonts without patching every component.
|
||||
────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* Table zone */
|
||||
.fs-zone-table { font-size: calc(0.875rem * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-xs { font-size: calc(0.75rem * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-sm { font-size: calc(0.875rem * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-base { font-size: calc(1rem * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-lg { font-size: calc(1.125rem * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-xl { font-size: calc(1.25rem * var(--fs-scale-table, 1)); }
|
||||
/* Arbitrary pixel sizes used in tables */
|
||||
.fs-zone-table .text-\[10px\] { font-size: calc(10px * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-\[11px\] { font-size: calc(11px * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-\[12px\] { font-size: calc(12px * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-\[13px\] { font-size: calc(13px * var(--fs-scale-table, 1)); }
|
||||
.fs-zone-table .text-\[14px\] { font-size: calc(14px * var(--fs-scale-table, 1)); }
|
||||
|
||||
/* Card zone */
|
||||
.fs-zone-card { font-size: calc(0.875rem * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-xs { font-size: calc(0.75rem * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-sm { font-size: calc(0.875rem * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-base { font-size: calc(1rem * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-lg { font-size: calc(1.125rem * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-\[10px\] { font-size: calc(10px * var(--fs-scale-card, 1)); }
|
||||
.fs-zone-card .text-\[11px\] { font-size: calc(11px * var(--fs-scale-card, 1)); }
|
||||
|
||||
/* Nav zone */
|
||||
.fs-zone-nav { font-size: calc(0.875rem * var(--fs-scale-nav, 1)); }
|
||||
.fs-zone-nav .text-xs { font-size: calc(0.75rem * var(--fs-scale-nav, 1)); }
|
||||
.fs-zone-nav .text-sm { font-size: calc(0.875rem * var(--fs-scale-nav, 1)); }
|
||||
.fs-zone-nav .text-base { font-size: calc(1rem * var(--fs-scale-nav, 1)); }
|
||||
|
||||
/* Heading zone */
|
||||
.fs-zone-heading { font-size: calc(1rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-sm { font-size: calc(0.875rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-base { font-size: calc(1rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-lg { font-size: calc(1.125rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-xl { font-size: calc(1.25rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-2xl { font-size: calc(1.5rem * var(--fs-scale-heading, 1)); }
|
||||
.fs-zone-heading .text-3xl { font-size: calc(1.875rem * var(--fs-scale-heading, 1)); }
|
||||
|
||||
/* Small text zone */
|
||||
.fs-zone-small { font-size: calc(0.75rem * var(--fs-scale-small, 1)); }
|
||||
.fs-zone-small .text-xs { font-size: calc(0.75rem * var(--fs-scale-small, 1)); }
|
||||
.fs-zone-small .text-sm { font-size: calc(0.875rem * var(--fs-scale-small, 1)); }
|
||||
|
||||
/* Body zone — LAST so table/card/nav/heading zones inside body win at equal specificity */
|
||||
.fs-zone-body { font-size: calc(1rem * var(--fs-scale-body, 1)); }
|
||||
.fs-zone-body .text-xs { font-size: calc(0.75rem * var(--fs-scale-body, 1)); }
|
||||
.fs-zone-body .text-sm { font-size: calc(0.875rem * var(--fs-scale-body, 1)); }
|
||||
.fs-zone-body .text-base { font-size: calc(1rem * var(--fs-scale-body, 1)); }
|
||||
.fs-zone-body .text-lg { font-size: calc(1.125rem * var(--fs-scale-body, 1)); }
|
||||
Loading…
Reference in New Issue