rustio-admin 0.10.1

Django Admin, but for Rust. A small, focused admin framework.
Documentation
/* ============================================================
 * rustio-admin / base / typography
 *
 * Three things in cascade order:
 *
 *   1. @font-face declarations for the four self-hosted families.
 *      Self-hosted (SIL OFL-1.1, see /static/fonts/LICENSE.txt) and
 *      baked into the rustio-admin binary; no CDN round-trip, no
 *      FOUT, no GDPR/tracking surface. Browsers select which Arabic
 *      face to load via `unicode-range` + the per-element
 *      `font-family` resolution rules below.
 *
 *   2. Latin-only display polish + Arabic-aware UI/body typography.
 *
 *   3. Headings, links, paragraphs, code, pre — plus the mobile
 *      readability bump below 600px.
 *
 * Tokens (--rio-font-*, --rio-fs-*, --rio-lh-*, --rio-tracking-*)
 * live in tokens/typography.css.
 * ============================================================ */

/* ---- @font-face — self-hosted, OFL-1.1 ----------------------- */

/* Geist (variable Latin) */
@font-face {
  font-family: "Geist";
  src: url("/static/fonts/Geist-Variable.woff2") format("woff2-variations"),
       url("/static/fonts/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/static/fonts/GeistMono-Variable.woff2") format("woff2-variations"),
       url("/static/fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Tajawal (Arabic UI: compact surfaces) — three static weights;
 * Tajawal has no public variable axis. The unicode-range filters
 * fetches to Arabic codepoints only. */
@font-face {
  font-family: "Tajawal";
  src: url("/static/fonts/Tajawal-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E, U+2010-2011, U+204F, U+2E41;
}
@font-face {
  font-family: "Tajawal";
  src: url("/static/fonts/Tajawal-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E, U+2010-2011, U+204F, U+2E41;
}
@font-face {
  font-family: "Tajawal";
  src: url("/static/fonts/Tajawal-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E, U+2010-2011, U+204F, U+2E41;
}

/* Noto Naskh Arabic (Arabic paragraph body) */
@font-face {
  font-family: "Noto Naskh Arabic";
  src: url("/static/fonts/NotoNaskhArabic-Variable.woff2") format("woff2-variations"),
       url("/static/fonts/NotoNaskhArabic-Variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E, U+2010-2011, U+204F, U+2E41;
}

/* ---- Latin-only display polish ------------------------------- *
 * Auto-applies to Latin headings. Geist's "ss01" + "ss03" + "cv11"
 * tighten figure widths and swap single-storey alternates so
 * headings feel like a designed face. */
.rio-latin,
h1, h2, h3, h4,
.rio-list-title, .rio-form-title, .rio-dash-greeting, .rio-auth-title {
  font-feature-settings: "kern", "calt", "ss01", "ss03", "cv11";
}

/* ---- Arabic-aware typography --------------------------------- *
 * Two contexts:
 *   - UI surfaces  → Tajawal      (compact, geometric, dense UI)
 *   - Body / prose → Noto Naskh   (humanist, paragraph-y)
 * Both unicode-range trigger only on Arabic codepoints, so no
 * Latin-only page pays the download cost. */

/* Arabic UI context — anything tagged lang="ar" or dir="rtl" defaults
 * to Tajawal. Strip Latin-tuned tracking + stylistic alternates so
 * Arabic shaping isn't disrupted. */
:lang(ar),
[dir="rtl"],
[dir="rtl"] *,
.rio-arabic,
.rio-arabic * {
  font-family: var(--rio-font-arabic);
  letter-spacing: 0 !important;
  font-feature-settings: "kern" !important;
  line-height: var(--rio-lh-ui);
}

/* Arabic body context — paragraphs, descriptions, help text.
 * Switch to Noto Naskh + extra leading. Opt-in via lang="ar" on a
 * <p> / blockquote / .rio-prose container, or via .rio-arabic-body. */
p:lang(ar),
li:lang(ar),
blockquote:lang(ar),
.rio-prose:lang(ar),
.rio-prose:lang(ar) p,
.rio-prose:lang(ar) li,
.rio-arabic-body,
.rio-arabic-body * {
  font-family: var(--rio-font-arabic-body);
  line-height: var(--rio-lh-arabic);
  font-size: var(--rio-fs-lg);
  font-weight: var(--rio-fw-regular);
}

/* ---- Headings, links, paragraphs, code ----------------------- */

h1, h2, h3, h4 {
  margin: 0 0 var(--rio-s3);
  line-height: var(--rio-lh-tight);
  letter-spacing: var(--rio-tracking-heading);
  color: var(--rio-text);
}
h1 {
  font-size: var(--rio-fs-h1);            /* 34px */
  font-weight: var(--rio-fw-bold);
  letter-spacing: var(--rio-tracking-display);
}
h2 {
  font-size: var(--rio-fs-h2);            /* 26px */
  font-weight: var(--rio-fw-semibold);
}
h3 {
  font-size: var(--rio-fs-h3);            /* 22px */
  font-weight: var(--rio-fw-semibold);
}
h4 {
  font-size: var(--rio-fs-md);            /* 15px — section subtitle */
  font-weight: var(--rio-fw-semibold);
  letter-spacing: 0;
}

/* Arabic-tagged headings — keep the size scale, drop the negative
 * tracking. Tajawal carries enough weight for display sizes. */
:lang(ar) h1, :lang(ar) h2, :lang(ar) h3, :lang(ar) h4,
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] h4,
h1:lang(ar), h2:lang(ar), h3:lang(ar), h4:lang(ar) {
  letter-spacing: 0;
  font-family: var(--rio-font-arabic);
  font-weight: var(--rio-fw-bold);
}

p { margin: 0 0 var(--rio-s4); }

a { color: var(--rio-accent); text-decoration: none; font-weight: var(--rio-fw-medium); }
a:hover { text-decoration: underline; }

code, kbd, samp {
  font-family: var(--rio-font-mono);
  font-size: 0.875em;                     /* relative to context */
  font-variant-ligatures: none;           /* "==" stays as 2 glyphs */
  font-feature-settings: "kern";
  background: rgba(var(--rio-accent-rgb) / 0.07);
  padding: 0.05em 0.35em;
  border-radius: var(--rio-radius-sm);
  letter-spacing: 0;
}
pre {
  font-family: var(--rio-font-mono);
  font-size: var(--rio-fs-sm);            /* 14px */
  line-height: 1.6;
  font-variant-ligatures: none;
  font-feature-settings: "kern";
  background: var(--rio-surface);
  border: 1px solid var(--rio-border);
  border-radius: var(--rio-radius);
  padding: var(--rio-s3) var(--rio-s4);
  overflow-x: auto;
  margin: 0 0 var(--rio-s4);
}
pre code {
  background: none;
  padding: 0;
  font-size: inherit;
  border-radius: 0;
}

/* Mobile readability bump — push body up to 17px below 600px so
 * thumb-typing forms and reading copy stays comfortable. */
@media (max-width: 600px) {
  html { font-size: 16.5px; }
  .rio-prose { font-size: var(--rio-fs-lg); }
}