rustio-admin 0.19.0

Django Admin, but for Rust. A small, focused admin framework.
Documentation
/* ============================================================
 * rustio-admin / components / buttons
 *
 * Five variants: default neutral, --primary (accent fill), --danger
 * (red fill), --ghost (transparent), --danger-ghost (transparent
 * red). Plus a --sm modifier for inline row actions.
 *
 * Buttons feel calm and tactile, not glossy. We change colour and
 * surface on hover (instead of dimming with opacity) — that reads
 * as deliberate UI feedback rather than a flashy SaaS hover.
 * ============================================================ */

.rio-button {
  /* v0.16 — 44px touch-target height (10/16 padding + 16px text at
   * 1.6 line-height), 16px label. Buttons feel substantial without
   * being chunky. */
  display: inline-flex;
  align-items: center;
  gap: var(--rio-s2);                          /* 8px icon → label */
  min-height: 44px;
  padding: var(--rio-s2) var(--rio-s4);        /* 8px / 16px */
  background: var(--rio-surface);
  color: var(--rio-text);
  border: 1px solid var(--rio-border);
  border-radius: var(--rio-radius-sm);
  font-size: var(--rio-fs-md);                 /* 16px */
  font-weight: var(--rio-fw-semibold);
  letter-spacing: 0.005em;
  line-height: var(--rio-lh-ui);               /* 1.6 */
  cursor: pointer;
  text-decoration: none;
  box-shadow: var(--rio-shadow-xs);
  transition: background-color 0.12s, border-color 0.12s, color 0.12s,
              box-shadow 0.12s, transform 0.06s;
}
.rio-button:hover {
  /* v0.16 — neutral button hover lifts to accent-soft (teal-50)
   * instead of surface-3. Gives every button a clean accent touch
   * on interaction — the "accent everywhere" thread that fixes the
   * old monochromatic feel. */
  background: var(--rio-accent-soft);
  border-color: var(--rio-accent-border);
  color: var(--rio-accent-hover);
  text-decoration: none;
}
.rio-button:focus-visible {
  outline: none;
  border-color: var(--rio-accent);
  box-shadow: var(--rio-shadow-xs),
              0 0 0 4px var(--rio-accent-border);
}
.rio-button:active { transform: translateY(1px); }
.rio-button:disabled { opacity: 0.5; cursor: not-allowed; }

/* Primary action — Stripe / Linear style: a subtle vertical
 * gradient (≈ 8 % delta) for weight, an inset top highlight for
 * the "lifted button" affordance, accent-coloured drop shadow.
 * The gradient is invisible at a glance but the eye reads it as
 * deliberate engineering. (Principle 11 — gravity, not flash.) */
.rio-button--primary {
  color: #fff;
  background-color: var(--rio-accent);
  background-image: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--rio-accent) 92%, white) 0%,
    var(--rio-accent) 100%
  );
  border-color: color-mix(in srgb, var(--rio-accent) 80%, black);
  box-shadow: 0 1px 2px rgb(var(--rio-accent-rgb) / 0.30),
              inset 0 1px 0 rgb(255 255 255 / 0.14);
}
.rio-button--primary:hover {
  background-image: linear-gradient(
    to bottom,
    var(--rio-accent) 0%,
    var(--rio-accent-hover) 100%
  );
  border-color: var(--rio-accent-hover);
  color: #fff;
}
.rio-button--primary:focus-visible {
  border-color: color-mix(in srgb, var(--rio-accent) 80%, black);
  box-shadow: 0 1px 2px rgb(var(--rio-accent-rgb) / 0.30),
              inset 0 1px 0 rgb(255 255 255 / 0.14),
              0 0 0 3px rgb(var(--rio-accent-rgb) / 0.30);
}
.rio-button--danger {
  background: var(--rio-danger);
  color: #fff;
  border-color: var(--rio-danger);
}
.rio-button--danger:hover { color: #fff; }
.rio-button--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--rio-text-muted);
  box-shadow: none;
}
.rio-button--ghost:hover {
  color: var(--rio-text-strong);
  background: var(--rio-surface-3);
  border-color: transparent;
}
.rio-button--danger-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--rio-danger);
  box-shadow: none;
}
.rio-button--danger-ghost:hover {
  background: var(--rio-danger-bg);
  border-color: transparent;
}

/* Compact button for inline row actions (Edit / Delete in table
 * rows, etc.). Matches the proportions of a body-text affordance
 * rather than a primary CTA. */
.rio-button--sm {
  padding: 0.3rem 0.55rem;
  font-size: var(--rio-fs-sm);
  gap: 0.3rem;
}
.rio-button--sm .rio-icon { width: 14px; height: 14px; }

/* RTL icon directionality. The icons renderer
 * (`admin::icons::render_inline`) appends
 * `rio-icon--directional` to glyphs whose shape carries a
 * left/right direction — currently `arrow-left` and `log-out`.
 * Under `[dir="rtl"]` these flip horizontally so a "Back" arrow
 * points the way the user reads from. Vertical chevrons
 * (`chevron-down`) and symbol icons (`home`, `users`, `database`)
 * are NOT marked directional and stay unchanged in either
 * direction — mirroring them would produce wrong-handed glyphs. */
[dir="rtl"] .rio-icon--directional {
  transform: scaleX(-1);
}