/* ============================================================
   Formulize UI
   ============================================================

   The public tokens, layout classes, components and utilities for building
   markup in Formulize: screen templates, template screens, derived values, text
   elements and theme tweaks. Loaded before Formulize's own stylesheet and before
   the theme's, on every page that loads Formulize's stylesheet (see
   formulize_uiStylesheetPath() in modules/formulize/include/functions.php).

   Naming:
     fz-          public: documented, and safe to build with, in any theme
     lyris-       the Lyris theme's own classes and tokens
     formulize-   Formulize core's internal classes and tokens

   Every public selector is a single class, and there is no !important here.
   Themes write their rules that style core's markup with :where(), so that
   those rules weigh nothing and a public class always beats them.

   ============================================================
   Tokens
   ============================================================

   The public design tokens. The names are Tailwind CSS v4's theme variable
   names, with fz- in front. A theme declares its own values for these in its
   own stylesheet (Lyris and Anari do, in their tokens.css), and the Appearance
   page overrides the ones it offers, so the values below are only what a page
   gets when neither has set them. They are the Formulize design system's
   defaults, the same as Lyris's.
   ============================================================ */

:root {
  /* Colour */
  --fz-color-page:          #f7f7f5;
  --fz-color-surface:       #ffffff;
  --fz-color-surface-2:     #fafaf8;
  --fz-color-surface-3:     #f1f1ed;
  --fz-color-overlay:       rgba(15, 17, 21, 0.45);

  --fz-color-border:        #e6e6e1;
  --fz-color-border-strong: #d1d1cb;
  --fz-color-focus:         #1f2937;

  --fz-color-text:          #14161a;
  --fz-color-text-muted:    #5b6068;
  --fz-color-text-subtle:   #8a8e95;
  --fz-color-on-accent:     #ffffff;

  --fz-color-accent:        #2e3340;
  --fz-color-accent-hover:  #1c2029;
  --fz-color-accent-soft:   #eef0f4;
  --fz-color-accent-soft-2: #dde1ea;
  --fz-color-accent-text:   #2e3340;

  --fz-color-success:       #2a7a4f;
  --fz-color-success-soft:  #e6f1ea;
  --fz-color-warning:       #a86a14;
  --fz-color-warning-soft:  #fbecd2;
  --fz-color-danger:        #b3261e;
  --fz-color-danger-soft:   #f8e1de;
  --fz-color-info:          #2e5fa8;
  --fz-color-info-soft:     #e2ecf8;

  /* Type */
  --fz-font-sans:    system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --fz-font-heading: var(--fz-font-sans);
  --fz-font-mono:    ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Type scale: Tailwind's sizes, each with the line height Tailwind pairs it
     with, plus two steps of Formulize's own that Tailwind has none for:
     xs-plus (13px), between xs and sm, and sm-plus (15px), between sm and base.
     Fixed: the same in every theme. */
  --fz-text-xs:                 0.75rem;
  --fz-text-xs--line-height:    1rem;
  --fz-text-xs-plus:            0.8125rem;
  --fz-text-xs-plus--line-height: 1.25rem;
  --fz-text-sm:                 0.875rem;
  --fz-text-sm--line-height:    1.25rem;
  --fz-text-sm-plus:            0.9375rem;
  --fz-text-sm-plus--line-height: 1.375rem;
  --fz-text-base:               1rem;
  --fz-text-base--line-height:  1.5rem;
  --fz-text-lg:                 1.125rem;
  --fz-text-lg--line-height:    1.75rem;
  --fz-text-xl:                 1.25rem;
  --fz-text-xl--line-height:    1.75rem;
  --fz-text-2xl:                1.5rem;
  --fz-text-2xl--line-height:   2rem;
  --fz-text-3xl:                1.875rem;
  --fz-text-3xl--line-height:   2.25rem;

  --fz-font-weight-normal:   400;
  --fz-font-weight-medium:   500;
  --fz-font-weight-semibold: 600;
  --fz-font-weight-bold:     700;

  --fz-leading-tight:   1.25;
  --fz-leading-snug:    1.375;
  --fz-leading-normal:  1.5;

  --fz-tracking-wide:   0.025em;
  --fz-tracking-wider:  0.05em;

  /* Spacing. Every space and size on the scale is a multiple of this step, as
     in Tailwind: calc(var(--fz-spacing) * 4) is 1rem. Fixed, like the type
     scale: the Appearance page's sizes change the component sizes below, not
     this. */
  --fz-spacing: 0.25rem;

  /* Shape and depth */
  --fz-radius-sm:   0.25rem;
  --fz-radius-md:   0.375rem;
  --fz-radius-lg:   0.5rem;
  --fz-radius-xl:   0.75rem;
  --fz-radius-full: 999px;

  --fz-shadow-xs: 0 1px 0 rgba(15,17,21,.04);
  --fz-shadow-sm: 0 1px 2px rgba(15,17,21,.06), 0 1px 0 rgba(15,17,21,.04);
  --fz-shadow-md: 0 4px 12px rgba(15,17,21,.08), 0 1px 2px rgba(15,17,21,.05);
  --fz-shadow-lg: 0 12px 32px rgba(15,17,21,.14), 0 2px 6px rgba(15,17,21,.06);
  --fz-focus-ring: 0 0 0 3px rgba(46,51,64,.15);

  /* Container widths, Tailwind's (see fz-container) */
  --fz-container-2xl: 42rem;
  --fz-container-6xl: 72rem;
  --fz-container-7xl: 80rem;

  /* Motion */
  --fz-ease-out:      cubic-bezier(.2,.7,.3,1);
  --fz-duration-fast: 120ms;
  --fz-duration:      200ms;
}


/* ============================================================
   Component sizes
   ============================================================

   The sizes of the parts of the interface: how big titles, labels and field
   text are, how tall fields, buttons and list rows are, and how much space
   there is in forms, cards and the drawer. Components read these, so setting
   one changes that part everywhere, and nothing else.

   These are the Default values. The Appearance page's Size presets (Compact,
   Comfortable) and its advanced settings replace them, in the stylesheet it
   generates; the presets' values, and what each token can be set to, are in
   modules/formulize/include/appearance_tokens.json. Keep each value written
   the way that file's type for it is written (a number of spacing steps, a text
   step, a weight, a line height, a number of ch), so the Appearance page can
   read it; ui_catalog.php --check makes sure of it.

   To change a size for one part of a page, set the token on its container:
   style="--fz-row-height: calc(var(--fz-spacing) * 8)".
   ============================================================ */

:root {
  /* Type */
  --fz-title-text:        var(--fz-text-xl);       /* form card, drawer and list titles: 20px */
  --fz-title-text-narrow: var(--fz-text-base);     /* titles at 768px wide and below: 16px */
  --fz-title-weight:      600;
  --fz-title-leading:     1.25;
  --fz-label-text:        var(--fz-text-sm);       /* form labels: 14px */
  --fz-label-weight:      600;
  --fz-field-text:        var(--fz-text-sm);       /* text in form fields, and read-only values */
  --fz-help-text:         var(--fz-text-xs-plus);  /* help text and character counters: 13px */
  --fz-help-leading:      1.5;
  --fz-help-max-width:    65ch;
  --fz-control-text:      var(--fz-text-xs-plus);  /* buttons, menu items, tabs */
  --fz-table-text:        var(--fz-text-xs-plus);  /* list and table cells */
  --fz-table-header-text: var(--fz-text-xs);       /* column headings */

  /* Forms */
  --fz-field-height:      calc(var(--fz-spacing) * 9.5);  /* 38px */
  --fz-field-padding-x:   calc(var(--fz-spacing) * 3);
  --fz-field-gap:         calc(var(--fz-spacing) * 5.5);  /* between fields: 22px */
  --fz-label-gap:         calc(var(--fz-spacing) * 1.5);  /* label above its field: 6px */
  --fz-help-gap:          calc(var(--fz-spacing) * 1.5);  /* a field to its help text: 6px */
  --fz-option-gap:        calc(var(--fz-spacing) * 0.5);  /* between options, each on its own line: 2px */

  /* Buttons and controls */
  --fz-control-height:    calc(var(--fz-spacing) * 8);    /* 32px */
  --fz-control-padding-x: calc(var(--fz-spacing) * 3);
  --fz-menu-item-height:  calc(var(--fz-spacing) * 7.5);  /* 30px */
  --fz-tab-padding-y:     calc(var(--fz-spacing) * 1);
  --fz-tab-padding-x:     calc(var(--fz-spacing) * 3);

  /* Lists */
  --fz-row-height:          calc(var(--fz-spacing) * 10);  /* 40px */
  --fz-cell-padding-x:      calc(var(--fz-spacing) * 3);
  --fz-table-header-height: calc(var(--fz-spacing) * 9);   /* 36px */
  --fz-toolbar-height:      calc(var(--fz-spacing) * 14);  /* list title and selection bars: 56px */
  --fz-toolbar-padding-x:   calc(var(--fz-spacing) * 5);

  /* Cards, drawers and the page */
  --fz-card-padding:      calc(var(--fz-spacing) * 4);
  --fz-card-gap:          calc(var(--fz-spacing) * 3);
  --fz-form-padding:      calc(var(--fz-spacing) * 6);
  --fz-drawer-padding-x:  calc(var(--fz-spacing) * 5);
  --fz-drawer-padding-y:  calc(var(--fz-spacing) * 4);
  --fz-page-padding:      calc(var(--fz-spacing) * 5);
}


/* ============================================================
   Component fonts, colours and corners
   ============================================================

   Which font each kind of text is set in, the colours of each part of the
   interface, and their corners. Like the sizes above, components read these,
   so setting one changes that part everywhere; the Appearance page's advanced
   editor sets them, and what each can be set to is in appearance_tokens.json.

   Each one defaults to the site-wide setting it has always followed: a font is
   the main font (--fz-font-sans) or the secondary one (--fz-font-heading), and
   a colour is one of the palette's, so changing the palette still changes every
   part that hasn't been given a colour of its own. Keep them written that way
   (var(--fz-font-...), var(--fz-color-...), var(--fz-radius-...) or px), so
   the Appearance page can read them.

   --fz-button-primary-hover isn't set directly: it follows
   --fz-button-primary-bg, darkened, when that is changed. */
:root {
  /* Fonts */
  --fz-title-font:        var(--fz-font-heading);  /* form card, list and drawer titles */
  --fz-label-font:        var(--fz-font-heading);  /* field labels */
  --fz-field-font:        var(--fz-font-sans);     /* fields, read-only values, choice options */
  --fz-help-font:         var(--fz-font-sans);
  --fz-control-font:      var(--fz-font-sans);     /* buttons, tabs, menus, list toolbars */
  --fz-table-font:        var(--fz-font-sans);     /* list and table cells */
  --fz-table-header-font: var(--fz-font-sans);     /* column headings */

  /* Text colours */
  --fz-title-color:       var(--fz-color-text);
  --fz-label-color:       var(--fz-color-text);
  --fz-required-color:    var(--fz-color-danger);
  --fz-field-color:       var(--fz-color-text);    /* in fields, and choice options */
  --fz-value-color:       var(--fz-color-text);    /* read-only values */
  --fz-help-color:        var(--fz-color-text-muted);

  /* Forms */
  --fz-field-bg:          var(--fz-color-surface);
  --fz-field-border:      var(--fz-color-border-strong);
  --fz-field-radius:      var(--fz-radius-md);
  --fz-option-accent:     var(--fz-color-accent);  /* a chosen radio button or checkbox */
  --fz-form-bg:           var(--fz-color-surface);
  --fz-form-border:       var(--fz-color-border);
  --fz-form-radius:       var(--fz-radius-lg);

  /* Buttons and controls */
  --fz-button-bg:           var(--fz-color-surface);
  --fz-button-text:         var(--fz-color-text);
  --fz-button-border:       var(--fz-color-border-strong);
  --fz-button-primary-bg:   var(--fz-color-accent);
  --fz-button-primary-text: var(--fz-color-on-accent);
  --fz-button-primary-hover: var(--fz-color-accent-hover);
  --fz-button-radius:       var(--fz-radius-md);
  --fz-tab-bg:              var(--fz-color-surface);
  --fz-tab-text:            var(--fz-color-text-muted);
  --fz-tab-border:          var(--fz-color-border);
  --fz-tab-active-bg:       var(--fz-color-accent);
  --fz-tab-active-text:     var(--fz-color-on-accent);
  --fz-tab-radius:          var(--fz-radius-full);
  --fz-menu-bg:             var(--fz-color-surface);
  --fz-menu-text:           var(--fz-color-text);
  --fz-menu-radius:         var(--fz-radius-lg);

  /* Lists */
  --fz-toolbar-bg:        var(--fz-color-surface);
  --fz-header-bg:         var(--fz-color-surface-2);
  --fz-header-text:       var(--fz-color-text-muted);
  --fz-header-border:     var(--fz-color-border-strong);
  --fz-row-bg:            var(--fz-color-surface);
  --fz-row-text:          var(--fz-color-text);
  --fz-row-hover:         var(--fz-color-surface-2);
  --fz-row-border:        var(--fz-color-border);

  /* Cards and the drawer */
  --fz-card-bg:           var(--fz-color-surface);
  --fz-card-border:       var(--fz-color-border);
  --fz-card-radius:       var(--fz-radius-lg);
  --fz-drawer-bg:         var(--fz-color-surface);
  --fz-drawer-foot-bg:    var(--fz-color-surface-2);
}


/* ============================================================
   Layout classes
   ============================================================

   Classes that arrange their children. They respond to the space they are
   given, not to the size of the screen, so the same markup works full screen,
   in the drawer, on a phone, and embedded in another site.

   The gap is the only space between the children: their top and bottom
   margins are removed. Change the gap with the fz-gap-* utilities below.

   Each class declares its default gap as --fz-gap, and resets --fz-gap-x and
   --fz-gap-y, so a value set on an element further out never leaks in; the gap
   utilities set them again on the same element. fz-auto-grid needs the gap in
   its column calculation, which is why the gap is a custom property here and
   not only the gap property.
   ============================================================ */

.fz-stack,
.fz-cluster,
.fz-auto-grid,
.fz-grid-list,
.fz-with-sidebar,
.fz-switcher {
  --fz-gap-x: initial;
  --fz-gap-y: initial;
  gap: var(--fz-gap-y, var(--fz-gap)) var(--fz-gap-x, var(--fz-gap));
}

.fz-stack > *,
.fz-cluster > *,
.fz-auto-grid > *,
.fz-grid-list > *,
.fz-with-sidebar > *,
.fz-switcher > * {
  margin-block: 0;
}

/* Stack: children one above the other. */
.fz-stack {
  --fz-gap: calc(var(--fz-spacing) * 4);
  display: flex;
  flex-direction: column;
}

/* Cluster: children side by side, vertically centred, wrapping onto new lines
   when they run out of room. */
.fz-cluster {
  --fz-gap: calc(var(--fz-spacing) * 2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

/* Auto grid: equal columns, as many as fit, each at least --fz-auto-grid-min
   wide (10rem, so two fit in the drawer at its narrowest), so fewer columns as
   the space narrows and one when it is narrower than that. The --max-N modifiers cap the number of columns. Set
   --fz-auto-grid-min on the element itself to change the minimum. */
.fz-auto-grid,
.fz-grid-list {
  --fz-gap: calc(var(--fz-spacing) * 4);
  --fz-auto-grid-min: 10rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--fz-auto-grid-min)), 1fr));
}
.fz-auto-grid--narrow,
.fz-grid-list--narrow { --fz-auto-grid-min: 8rem; }
.fz-auto-grid--wide,
.fz-grid-list--wide   { --fz-auto-grid-min: 18rem; }
.fz-auto-grid--max-2,
.fz-grid-list--max-2 { --fz-auto-grid-max: 2; }
.fz-auto-grid--max-3,
.fz-grid-list--max-3 { --fz-auto-grid-max: 3; }
.fz-auto-grid--max-4,
.fz-grid-list--max-4 { --fz-auto-grid-max: 4; }
.fz-auto-grid--max-5,
.fz-grid-list--max-5 { --fz-auto-grid-max: 5; }
.fz-auto-grid--max-6,
.fz-grid-list--max-6 { --fz-auto-grid-max: 6; }
/* With a maximum, a column is never narrower than an equal share of the row
   at that maximum, so no more than that many fit. */
.fz-auto-grid--max-2,
.fz-grid-list--max-2,
.fz-auto-grid--max-3,
.fz-grid-list--max-3,
.fz-auto-grid--max-4,
.fz-grid-list--max-4,
.fz-auto-grid--max-5,
.fz-grid-list--max-5,
.fz-auto-grid--max-6,
.fz-grid-list--max-6 {
  grid-template-columns: repeat(
    auto-fit,
    minmax(
      min(100%, max(
        var(--fz-auto-grid-min),
        (100% - (var(--fz-auto-grid-max) - 1) * var(--fz-gap-x, var(--fz-gap))) / var(--fz-auto-grid-max)
      )),
      1fr
    )
  );
}

/* With sidebar: the first child is a side --fz-sidebar-width wide, the second
   takes the rest. They stack when the main area would be narrower than half
   the space. fz-with-sidebar--end puts the side second.

   The main area's grow factor dwarfs the side's, so the side keeps its width to
   within a fraction of a pixel; the side's own grow factor of 1 is what lets it
   fill the row once the two have stacked. */
.fz-with-sidebar {
  --fz-gap: calc(var(--fz-spacing) * 4);
  --fz-sidebar-width: 16rem;
  display: flex;
  flex-wrap: wrap;
}
.fz-with-sidebar > :where(:first-child) {
  flex-basis: var(--fz-sidebar-width);
  flex-grow: 1;
}
.fz-with-sidebar > :where(:last-child) {
  flex-basis: 0;
  flex-grow: 99999;
  min-inline-size: 50%;
}
.fz-with-sidebar--end > :where(:first-child) {
  flex-basis: 0;
  flex-grow: 99999;
  min-inline-size: 50%;
}
.fz-with-sidebar--end > :where(:last-child) {
  flex-basis: var(--fz-sidebar-width);
  flex-grow: 1;
  min-inline-size: 0;
}

/* Switcher: children in equal columns while the container is wider than
   --fz-switcher-threshold, and all stacked when it isn't: never part way. */
.fz-switcher {
  --fz-gap: calc(var(--fz-spacing) * 4);
  --fz-switcher-threshold: 32rem;
  display: flex;
  flex-wrap: wrap;
}
.fz-switcher > * {
  flex-grow: 1;
  flex-basis: calc((var(--fz-switcher-threshold) - 100%) * 999);
}

/* Container: centred, at most 72rem wide, with space at the sides. */
.fz-container {
  box-sizing: border-box;
  inline-size: 100%;
  max-inline-size: var(--fz-container-6xl);
  margin-inline: auto;
  padding-inline: calc(var(--fz-spacing) * 4);
}
.fz-container--narrow { max-inline-size: var(--fz-container-2xl); }
.fz-container--wide   { max-inline-size: var(--fz-container-7xl); }

/* Spacer: takes up the free space in a row, pushing what follows to the end. */
.fz-spacer { flex: 1 1 auto; }


/* ============================================================
   Components
   ============================================================

   Things to build with. Each has a main class, classes for its parts
   (fz-card__title) and for its variations (fz-card--interactive), and draws
   everything from the tokens, so it follows the theme and the Appearance page,
   including its Size preset. They come before the utilities, so a utility can adjust one.

   Elements inside a component that have no class of their own (a description
   list's dt and dd) are selected through :where(), so that every selector here
   still weighs one class.

   Components that hold text set their own line height rather than inheriting
   the theme's, so they read the same in every theme (Anari's reset sets the
   page's line height to 1).
   ============================================================ */

/* ---- Button ---------------------------------------------------------------
   An action: a <button>, an <a>, or an <input type="submit">. A secondary
   button by default; one modifier for the kind, and one for the size. Its
   height is the control height. */
.fz-btn {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--fz-control-height);
  /* as wide as its label: some themes give every button a minimum width */
  min-width: 0;
  padding: 0 var(--fz-control-padding-x);
  border-radius: var(--fz-button-radius);
  border: 1px solid var(--fz-button-border);
  background: var(--fz-button-bg);
  color: var(--fz-button-text);
  font: inherit;
  font-family: var(--fz-control-font);
  font-size: var(--fz-control-text);
  font-weight: var(--fz-font-weight-medium);
  line-height: var(--fz-leading-normal);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  appearance: none;
  -webkit-appearance: none;
  transition: background var(--fz-duration-fast) var(--fz-ease-out),
              border-color var(--fz-duration-fast) var(--fz-ease-out),
              color var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-btn:hover { background: var(--fz-color-surface-3); }
.fz-btn:focus-visible { outline: none; box-shadow: var(--fz-focus-ring); }
.fz-btn:disabled,
.fz-btn[aria-disabled="true"] {
  opacity: .5;
  cursor: not-allowed;
}

/* The main action: usually one per area. */
.fz-btn--primary {
  background: var(--fz-button-primary-bg);
  color: var(--fz-button-primary-text);
  border-color: var(--fz-button-primary-bg);
}
.fz-btn--primary:hover {
  background: var(--fz-button-primary-hover);
  border-color: var(--fz-button-primary-hover);
}
/* A destructive action, such as delete. */
.fz-btn--danger {
  background: var(--fz-color-danger);
  color: #fff;
  border-color: var(--fz-color-danger);
}
.fz-btn--danger:hover {
  background: color-mix(in srgb, var(--fz-color-danger) 85%, #000);
  border-color: color-mix(in srgb, var(--fz-color-danger) 85%, #000);
}
/* No border or background until hovered: for less important actions. */
.fz-btn--ghost {
  border-color: transparent;
  background: transparent;
}
.fz-btn--ghost:hover { background: var(--fz-color-surface-3); }

.fz-btn--sm {
  height: calc(var(--fz-spacing) * 6.5);
  padding: 0 calc(var(--fz-spacing) * 2);
  font-size: var(--fz-text-xs);
}
.fz-btn--lg {
  height: calc(var(--fz-spacing) * 9);
  padding: 0 14px;
  font-size: var(--fz-text-sm);
}
/* Square, for an icon on its own: as wide as it is tall, at any size. Give it
   an aria-label. */
.fz-btn--icon {
  aspect-ratio: 1;
  width: auto;
  padding: 0;
}
/* The full width of its container. */
.fz-btn--block {
  display: flex;
  width: 100%;
}

/* ---- Toggle -----------------------------------------------------------------
   A switch: a real <input type="checkbox" class="fz-toggle">, drawn as an
   on/off switch. It is still the checkbox, so checking it, the keyboard,
   screen readers and form submission all work as they do for any checkbox.
   Off uses the neutral surface and border; on fills with the accent. */
.fz-toggle {
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  position: relative;
  flex: none;
  display: inline-block;
  vertical-align: middle;
  width: 34px;
  height: 20px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--fz-color-border-strong);
  border-radius: var(--fz-radius-full);
  background: var(--fz-color-surface-3);
  cursor: pointer;
  transition: background var(--fz-duration) var(--fz-ease-out),
              border-color var(--fz-duration) var(--fz-ease-out);
}
.fz-toggle::before {
  content: "";
  position: absolute;
  top: 1px;
  left: 1px;
  width: 16px;
  height: 16px;
  border-radius: var(--fz-radius-full);
  background: var(--fz-color-surface);
  box-shadow: var(--fz-shadow-sm);
  transition: transform var(--fz-duration) var(--fz-ease-out);
}
.fz-toggle:hover { border-color: var(--fz-color-text-subtle); }
.fz-toggle:checked {
  background: var(--fz-color-accent);
  border-color: var(--fz-color-accent);
}
.fz-toggle:checked::before { transform: translateX(14px); }
.fz-toggle:focus-visible {
  outline: none;
  box-shadow: var(--fz-focus-ring);
}
.fz-toggle:disabled {
  cursor: default;
  opacity: .5;
}

/* ---- Form field -------------------------------------------------------------
   A label, a control, and its help text:
     <div class="fz-field">
       <label class="fz-field__label" for="x">Name <span class="fz-field__req">*</span></label>
       <div class="fz-field__body"><input class="fz-input" id="x"> <p class="fz-field__help">…</p></div>
     </div>
   The label sits above the control; fz-field--horizontal puts it beside, and
   stacks them again when there isn't room. */
.fz-field {
  display: flex;
  flex-direction: column;
  gap: var(--fz-label-gap);
}
.fz-field__label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--fz-label-font);
  font-size: var(--fz-label-text);
  font-weight: var(--fz-label-weight);
  line-height: var(--fz-leading-snug);
  text-wrap: pretty;
  color: var(--fz-label-color);
}
/* On a <fieldset>, for a group of choices, with a <legend class="fz-field__label">:
   no border, padding or margin of the fieldset's own. A legend sits outside the
   fieldset's layout, so it carries the gap below it itself. */
.fz-field:where(fieldset) {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.fz-field__label:where(legend) {
  padding: 0;
  margin-bottom: var(--fz-label-gap);
}
/* The required marker, inside the label. */
.fz-field__req {
  color: var(--fz-required-color);
  font-weight: var(--fz-font-weight-bold);
  font-size: 0.95em;
}
/* The control and its help text. */
.fz-field__body {
  display: flex;
  flex-direction: column;
  gap: var(--fz-spacing);
  min-width: 0;
}
.fz-field__help {
  /* --fz-help-gap below the control, one step of which is the body's own gap */
  margin: calc(var(--fz-help-gap) - var(--fz-spacing)) 0 0;
  max-width: var(--fz-help-max-width);
  font-family: var(--fz-help-font);
  font-size: var(--fz-help-text);
  line-height: var(--fz-help-leading);
  color: var(--fz-help-color);
}
/* Label beside the control, lined up with its first line; the two stack when
   the control would get narrower than half the field. */
.fz-field--horizontal {
  --fz-field-label-width: 12rem;
  flex-direction: row;
  flex-wrap: wrap;
  column-gap: calc(var(--fz-spacing) * 4);
}
.fz-field--horizontal > :where(.fz-field__label) {
  flex: 1 1 var(--fz-field-label-width);
  align-self: flex-start;
  padding-top: calc((var(--fz-field-height) - var(--fz-label-text) * var(--fz-leading-snug)) / 2);
}
.fz-field--horizontal > :where(.fz-field__body) {
  flex: 99999 1 0;
  min-width: 50%;
}

/* ---- Form controls ----------------------------------------------------------
   fz-input (a text-like <input>: text, email, number, date…), fz-select and
   fz-textarea share one look: the field height, a
   border that darkens on hover, and the focus ring. aria-invalid="true" marks
   one as invalid. */
.fz-input,
.fz-select,
.fz-textarea {
  box-sizing: border-box;
  width: 100%;
  height: var(--fz-field-height);
  margin: 0;
  padding: 0 var(--fz-field-padding-x);
  border: 1px solid var(--fz-field-border);
  border-radius: var(--fz-field-radius);
  background: var(--fz-field-bg);
  color: var(--fz-field-color);
  font: inherit;
  font-family: var(--fz-field-font);
  font-size: var(--fz-field-text);
  line-height: var(--fz-leading-normal);
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  transition: border-color var(--fz-duration-fast) var(--fz-ease-out),
              box-shadow var(--fz-duration-fast) var(--fz-ease-out),
              background var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-input::placeholder,
.fz-textarea::placeholder { color: var(--fz-color-text-subtle); }
.fz-input:hover:not(:disabled):not(:focus),
.fz-select:hover:not(:disabled):not(:focus),
.fz-textarea:hover:not(:disabled):not(:focus) {
  border-color: var(--fz-color-text-muted);
}
.fz-input:focus,
.fz-select:focus,
.fz-textarea:focus {
  border-color: var(--fz-color-focus);
  box-shadow: var(--fz-focus-ring);
}
.fz-input:disabled,
.fz-select:disabled,
.fz-textarea:disabled {
  background: var(--fz-color-surface-3);
  color: var(--fz-color-text-subtle);
  cursor: not-allowed;
}
.fz-input[aria-invalid="true"],
.fz-select[aria-invalid="true"],
.fz-textarea[aria-invalid="true"] {
  border-color: var(--fz-color-danger);
}
.fz-input[aria-invalid="true"]:focus,
.fz-select[aria-invalid="true"]:focus,
.fz-textarea[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--fz-color-danger) 20%, transparent);
}
/* A dropdown, with its own chevron. */
.fz-select {
  padding-right: 30px;
  cursor: pointer;
  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='%235b6068' 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 8px center;
}
.fz-select[multiple] {
  height: auto;
  padding: calc(var(--fz-spacing) * 1.5) calc(var(--fz-spacing) * 2.5);
  background-image: none;
}
/* Several lines; grows downwards when dragged. */
.fz-textarea {
  height: auto;
  min-height: calc(var(--fz-field-height) * 2.4);
  padding: calc(var(--fz-spacing) * 2) var(--fz-field-padding-x);
  resize: vertical;
}

/* ---- Input group ------------------------------------------------------------
   An fz-input with text or an icon attached before or after it:
     <div class="fz-input-group"><span class="fz-input-group__addon">$</span><input class="fz-input"></div> */
.fz-input-group {
  box-sizing: border-box;
  display: flex;
  align-items: stretch;
  width: 100%;
  height: var(--fz-field-height);
  border: 1px solid var(--fz-color-border-strong);
  border-radius: var(--fz-radius-md);
  background: var(--fz-color-surface);
  overflow: hidden;
  transition: border-color var(--fz-duration-fast) var(--fz-ease-out),
              box-shadow var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-input-group:hover:not(:focus-within) { border-color: var(--fz-color-text-muted); }
.fz-input-group:focus-within {
  border-color: var(--fz-color-focus);
  box-shadow: var(--fz-focus-ring);
}
.fz-input-group > :where(.fz-input) {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.fz-input-group__addon {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--fz-field-padding-x);
  background: var(--fz-color-surface-2);
  color: var(--fz-color-text-subtle);
  font-size: var(--fz-field-text);
  white-space: nowrap;
  user-select: none;
  border-inline-end: 1px solid var(--fz-color-border);
}
.fz-input-group__addon:where(:last-child) {
  border-inline-end: 0;
  border-inline-start: 1px solid var(--fz-color-border);
}

/* ---- Checkbox and radio -----------------------------------------------------
   A real <input type="checkbox" class="fz-checkbox"> or
   <input type="radio" class="fz-radio">, drawn in the theme's colours. */
.fz-checkbox,
.fz-radio {
  box-sizing: border-box;
  position: relative;
  flex: none;
  display: inline-block;
  vertical-align: middle;
  width: 16px;
  height: 16px;
  margin: 0;
  border: 1.5px solid var(--fz-color-border-strong);
  background: var(--fz-color-surface);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  transition: background var(--fz-duration-fast) var(--fz-ease-out),
              border-color var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-checkbox { border-radius: 3px; }
.fz-radio    { border-radius: 50%; }
.fz-checkbox:checked,
.fz-radio:checked {
  background: var(--fz-color-accent);
  border-color: var(--fz-color-accent);
}
.fz-checkbox:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--fz-color-on-accent);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.fz-radio:checked::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--fz-color-on-accent);
}
.fz-checkbox:focus-visible,
.fz-radio:focus-visible {
  outline: none;
  box-shadow: var(--fz-focus-ring);
}
.fz-checkbox:disabled,
.fz-radio:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* ---- Choice -----------------------------------------------------------------
   A checkbox, radio or toggle with its label, the whole of it clickable:
     <label class="fz-choice"><input type="radio" class="fz-radio" name="x"> Yes</label>
   fz-choice-group stacks a set of them. */
.fz-choice {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2);
  color: var(--fz-color-text);
  font-size: var(--fz-field-text);
  line-height: var(--fz-leading-normal);
  cursor: pointer;
}
.fz-choice-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--fz-spacing) * 2);
  margin: 0;
  padding: 0;
  border: 0;
}

/* ---- Card -----------------------------------------------------------------
   A surface for one thing: an entry, a summary, a group of fields. Its
   children are stacked 3 steps apart, with their own margins removed. */
.fz-card {
  --fz-gap: var(--fz-card-gap);
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: var(--fz-gap);
  min-width: 0;
  padding: var(--fz-card-padding);
  background: var(--fz-card-bg);
  border: 1px solid var(--fz-card-border);
  border-radius: var(--fz-card-radius);
  box-shadow: var(--fz-shadow-sm);
  color: var(--fz-color-text);
  line-height: var(--fz-leading-normal);
}
.fz-card > * { margin-block: 0; }

/* A row for the title and any actions, wrapping when out of room. */
.fz-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--fz-spacing) * 2);
}
.fz-card__title {
  margin: 0;
  font-family: var(--fz-font-heading);
  font-size: var(--fz-text-base);
  line-height: var(--fz-leading-snug);
  font-weight: var(--fz-font-weight-semibold);
}
.fz-card__subtitle {
  margin: 0;
  color: var(--fz-color-text-muted);
  font-size: var(--fz-text-xs-plus);
}
/* A row at the bottom, separated by a line. */
.fz-card__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2);
  padding-top: calc(var(--fz-spacing) * 3);
  border-top: 1px solid var(--fz-color-border);
}
/* No padding: for a table or an image that should reach the edges. */
.fz-card--flush {
  padding: 0;
  overflow: hidden;
}

/* The whole card is clickable. fz-card__link goes on the one link the card
   opens, or on an element around it when the link is generated for you
   (viewEntryLink() in a list template); its click area is stretched over the
   card. Other links and controls in the card still work on their own. */
.fz-card--interactive {
  transition: border-color var(--fz-duration-fast) var(--fz-ease-out),
              box-shadow var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-card--interactive:hover {
  border-color: var(--fz-color-border-strong);
  box-shadow: var(--fz-shadow-md);
}
.fz-card--interactive:focus-within {
  box-shadow: var(--fz-focus-ring);
}
.fz-card__link,
.fz-card__link :where(a) {
  color: inherit;
  text-decoration: none;
}
.fz-card__link:hover,
.fz-card__link :where(a):hover {
  text-decoration: underline;
}
.fz-card__link:focus-visible,
.fz-card__link :where(a):focus-visible {
  outline: none;
}
.fz-card__link::after,
.fz-card__link :where(a)::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
/* the stretched link's own ::after is not a link inside the card */
.fz-card__link:not(a)::after { content: none; }
.fz-card--interactive :where(a, button, input, select, textarea, label):where(:not(.fz-card__link, .fz-card__link a)) {
  position: relative;
  z-index: 1;
}

/* ---- Card list and grid list ------------------------------------------------
   A list of entries shown as cards: one below the other (fz-card-list), or in
   columns (fz-grid-list, which works like fz-auto-grid and takes the same
   --max-N, --narrow and --wide modifiers, with its own name). On a <ul> or
   <ol>, with an <li class="fz-card"> for each entry. */
.fz-card-list {
  --fz-gap: calc(var(--fz-spacing) * 3);
  display: flex;
  flex-direction: column;
  gap: var(--fz-gap);
}
.fz-card-list,
.fz-grid-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.fz-card-list > * { margin-block: 0; }

/* ---- Table ------------------------------------------------------------------
   A plain data table: a header row, a line under each row, and rows the row
   height. On a <table>. fz-table--striped shades
   every other row. For a table wider than its container, wrap it in an
   element with fz-overflow-x-auto. */
.fz-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-family: var(--fz-table-font);
  font-size: var(--fz-table-text);
  line-height: var(--fz-leading-normal);
  color: var(--fz-row-text);
}
.fz-table :where(th, td) {
  padding: 0 var(--fz-cell-padding-x);
  text-align: start;
  vertical-align: middle;
  border-bottom: 1px solid var(--fz-row-border);
  /* its own surface, so the table reads the same on the page as in a card */
  background: var(--fz-row-bg);
}
.fz-table :where(tbody td) {
  height: var(--fz-row-height);
}
.fz-table :where(thead th) {
  height: var(--fz-table-header-height);
  font-family: var(--fz-table-header-font);
  font-size: var(--fz-table-header-text);
  font-weight: var(--fz-font-weight-semibold);
  color: var(--fz-header-text);
  background: var(--fz-header-bg);
  border-bottom-color: var(--fz-header-border);
}
.fz-table--striped :where(tbody tr:nth-child(even) td) {
  background: var(--fz-color-surface-3);
}
/* For rows whose cells hold more than a line: a title over a description, a
   list. The cells line up at the top, and have space above and below, since the
   row height no longer centres a single line in them. */
.fz-table--multiline :where(tbody td) {
  padding-block: calc(var(--fz-spacing) * 3);
  vertical-align: top;
}

/* ---- Badge ------------------------------------------------------------------
   A short label: a status, a category, a count. The tone is in the tint and the
   dot; the text stays the normal text colour, so it is readable whatever
   colours the theme or the Appearance page uses. */
.fz-badge {
  --fz-tone: var(--fz-color-text-subtle);
  --fz-tone-soft: var(--fz-color-surface-3);
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--fz-spacing) * 1.5);
  height: calc(var(--fz-spacing) * 5.5);
  padding: 0 calc(var(--fz-spacing) * 2);
  border-radius: var(--fz-radius-full);
  background: var(--fz-tone-soft);
  color: var(--fz-color-text);
  font-size: var(--fz-text-xs);
  line-height: 1;
  font-weight: var(--fz-font-weight-medium);
  white-space: nowrap;
  vertical-align: middle;
}
.fz-badge::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fz-tone);
}
.fz-badge--plain::before { content: none; }
/* An icon on its own: a circle, the same size whatever the icon, so a column of
   them lines up, and what follows them does too. No dot. */
.fz-badge--icon {
  flex: none;
  justify-content: center;
  aspect-ratio: 1;
  padding: 0;
}
.fz-badge--icon::before { content: none; }
.fz-badge--accent  { --fz-tone: var(--fz-color-accent);  --fz-tone-soft: var(--fz-color-accent-soft); }
.fz-badge--info    { --fz-tone: var(--fz-color-info);    --fz-tone-soft: var(--fz-color-info-soft); }
.fz-badge--success { --fz-tone: var(--fz-color-success); --fz-tone-soft: var(--fz-color-success-soft); }
.fz-badge--warning { --fz-tone: var(--fz-color-warning); --fz-tone-soft: var(--fz-color-warning-soft); }
.fz-badge--danger  { --fz-tone: var(--fz-color-danger);  --fz-tone-soft: var(--fz-color-danger-soft); }

/* ---- Callout ----------------------------------------------------------------
   A message set apart from the content around it: instructions, a warning, the
   result of something the user did (give that one role="status"). The tone is
   the tint and the border at the start; the text stays the normal colour. */
.fz-callout {
  --fz-tone: var(--fz-color-accent);
  --fz-tone-soft: var(--fz-color-accent-soft);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: var(--fz-spacing);
  padding: calc(var(--fz-spacing) * 3) calc(var(--fz-spacing) * 4);
  border: 1px solid color-mix(in srgb, var(--fz-tone) 25%, transparent);
  border-inline-start: 4px solid var(--fz-tone);
  border-radius: var(--fz-radius-md);
  background: var(--fz-tone-soft);
  color: var(--fz-color-text);
  line-height: var(--fz-leading-normal);
}
.fz-callout > * { margin-block: 0; }
.fz-callout__title {
  font-weight: var(--fz-font-weight-semibold);
}
.fz-callout--info    { --fz-tone: var(--fz-color-info);    --fz-tone-soft: var(--fz-color-info-soft); }
.fz-callout--success { --fz-tone: var(--fz-color-success); --fz-tone-soft: var(--fz-color-success-soft); }
.fz-callout--warning { --fz-tone: var(--fz-color-warning); --fz-tone-soft: var(--fz-color-warning-soft); }
.fz-callout--danger  { --fz-tone: var(--fz-color-danger);  --fz-tone-soft: var(--fz-color-danger-soft); }

/* ---- Toolbar ----------------------------------------------------------------
   A row with a group at each end, such as a heading and its buttons, wrapping
   when it runs out of room. */
.fz-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--fz-spacing) * 2);
}
.fz-toolbar > * { margin-block: 0; }
.fz-toolbar__start,
.fz-toolbar__end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2);
  min-width: 0;
}
.fz-toolbar__start > *,
.fz-toolbar__end > * { margin-block: 0; }
.fz-toolbar__end { margin-inline-start: auto; }

/* ---- Description list -------------------------------------------------------
   Labelled values: an entry's fields in a card, a summary. On a <dl>; each
   <dt>/<dd> pair may be wrapped in a <div>. Terms and values side by side;
   fz-dl--stacked puts each term above its value.

   It can also go on a <div> around the <dl>. That is for a derived value, whose
   HTML is filtered before it is shown: the filter takes the class off a <dl>,
   and leaves it on a <div>. */
.fz-dl {
  display: grid;
  /* terms take the width they need, but never more than 40%, so values keep
     room to wrap between words even in a narrow card */
  grid-template-columns: fit-content(40%) minmax(0, 1fr);
  gap: calc(var(--fz-spacing) * 2) calc(var(--fz-spacing) * 4);
  margin: 0;
  line-height: var(--fz-leading-normal);
}
.fz-dl > :where(div, dl) { display: contents; }
.fz-dl :where(dt) {
  margin: 0;
  color: var(--fz-color-text-muted);
  font-weight: var(--fz-font-weight-medium);
}
.fz-dl :where(dd) {
  margin: 0;
  min-width: 0;
  overflow-wrap: break-word;
}
.fz-dl--stacked {
  grid-template-columns: minmax(0, 1fr);
  row-gap: var(--fz-spacing);
}
.fz-dl--stacked :where(dd) { margin-bottom: calc(var(--fz-spacing) * 2); }
.fz-dl--stacked :where(dd:last-child) { margin-bottom: 0; }

/* ---- Empty state ------------------------------------------------------------
   What to show where there is nothing to show yet, and what to do about it. */
.fz-empty {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2);
  padding: calc(var(--fz-spacing) * 10) calc(var(--fz-spacing) * 4);
  border: 1px dashed var(--fz-color-border-strong);
  border-radius: var(--fz-radius-lg);
  color: var(--fz-color-text-muted);
  line-height: var(--fz-leading-normal);
  text-align: center;
}
.fz-empty > * { margin: 0; }
.fz-empty__title {
  color: var(--fz-color-text);
  font-size: var(--fz-text-base);
  font-weight: var(--fz-font-weight-semibold);
}

/* ---- Bar list -----------------------------------------------------------------
   A few things compared by a number: for each, a label, a bar as long as its
   share, and the figure. A breakdown by status or by category, on a dashboard.
   Each row is one thing, and its bar's width is its percentage, set in a style
   attribute. The tone is the bar's colour, as it is a badge's tint.

   Made of <div> and <span>, not a list, so the rows can be the grid's own rows
   (display: contents) and the labels, bars and figures line up in columns. */
.fz-bar-list {
  display: grid;
  /* a label wraps rather than take more than half the width, so on a phone a
     long one leaves room for its bar */
  grid-template-columns: fit-content(50%) minmax(0, 1fr) max-content;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2) calc(var(--fz-spacing) * 3);
  line-height: var(--fz-leading-normal);
}
/* a second figure after the first: a count and a percentage, say */
.fz-bar-list--two-values {
  grid-template-columns: fit-content(50%) minmax(0, 1fr) max-content max-content;
}
.fz-bar-list__row {
  --fz-tone: var(--fz-color-accent);
  display: contents;
}
.fz-bar-list__row--info    { --fz-tone: var(--fz-color-info); }
.fz-bar-list__row--success { --fz-tone: var(--fz-color-success); }
.fz-bar-list__row--warning { --fz-tone: var(--fz-color-warning); }
.fz-bar-list__row--danger  { --fz-tone: var(--fz-color-danger); }
.fz-bar-list__row--neutral { --fz-tone: var(--fz-color-text-subtle); }
.fz-bar-list__label {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--fz-spacing) * 2);
  font-weight: var(--fz-font-weight-medium);
}
.fz-bar-list__track {
  display: block;
  height: calc(var(--fz-spacing) * 2.5);
  border-radius: var(--fz-radius-full);
  background: var(--fz-color-surface-3);
  overflow: hidden;
}
.fz-bar-list__bar {
  display: block;
  height: 100%;
  border-radius: var(--fz-radius-full);
  background: var(--fz-tone);
}
.fz-bar-list__value {
  font-weight: var(--fz-font-weight-semibold);
  font-variant-numeric: tabular-nums;
  text-align: end;
  white-space: nowrap;
}

/* ---- Progress -----------------------------------------------------------------
   One bar, as long as how far something has got: a score out of a total, steps
   done, money raised against a goal. Its width is set in a style attribute.
   The tone is the bar's colour, as it is a bar list's. For several bars side
   by side with their labels and figures, use the bar list instead. */
.fz-progress {
  --fz-tone: var(--fz-color-accent);
  box-sizing: border-box;
  display: block;
  height: calc(var(--fz-spacing) * 2.5);
  border-radius: var(--fz-radius-full);
  background: var(--fz-color-surface-3);
  overflow: hidden;
}
.fz-progress--info    { --fz-tone: var(--fz-color-info); }
.fz-progress--success { --fz-tone: var(--fz-color-success); }
.fz-progress--warning { --fz-tone: var(--fz-color-warning); }
.fz-progress--danger  { --fz-tone: var(--fz-color-danger); }
.fz-progress--neutral { --fz-tone: var(--fz-color-text-subtle); }
.fz-progress__bar {
  display: block;
  height: 100%;
  border-radius: var(--fz-radius-full);
  background: var(--fz-tone);
}

/* ---- Disclosure ---------------------------------------------------------------
   Something that opens in place to show more. On a <details>: its <summary> is
   what is clicked, and the rest is what opens. fz-disclosure--plain has no box
   of its own, for one that is inside a card. */
.fz-disclosure {
  box-sizing: border-box;
  padding: calc(var(--fz-spacing) * 2) calc(var(--fz-spacing) * 3);
  border: 1px solid var(--fz-color-border);
  border-radius: var(--fz-radius-md);
  background: var(--fz-color-surface-2);
  line-height: var(--fz-leading-normal);
}
.fz-disclosure > :where(summary) {
  cursor: pointer;
  font-weight: var(--fz-font-weight-medium);
}
.fz-disclosure > :where(:not(summary)) {
  margin-block: calc(var(--fz-spacing) * 2) 0;
}
.fz-disclosure--plain {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
/* It opens and closes by growing and shrinking, in a browser that can animate
   to and from a height of auto; in others it opens and closes at once. What
   opens is clipped only a few pixels outside it, so the focus rings of the
   controls in it are not cut off. */
.fz-disclosure::details-content {
  block-size: 0;
  overflow: clip;
  overflow-clip-margin: 4px;
}
.fz-disclosure[open]::details-content {
  block-size: auto;
}
@media (prefers-reduced-motion: no-preference) {
  .fz-disclosure {
    interpolate-size: allow-keywords;
  }
  .fz-disclosure::details-content {
    transition: block-size var(--fz-duration) var(--fz-ease-out),
                content-visibility var(--fz-duration) allow-discrete;
  }
}

/* ---- Tabs ---------------------------------------------------------------------
   A row of tabs, each showing one panel of a page in place of the others. The
   tabs are buttons in a role="tablist"; the one shown has aria-selected="true".
   Panels are fz-tab-panel, and the ones not shown have the hidden attribute.
   A panel is a plain box: lay out what is in it with a stack inside it, as on
   paper the panels are shown as blocks. Switching them takes a few lines of
   script, kept with the page. On paper the tabs go and every panel prints, one
   after another. */
.fz-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--fz-spacing) * 2);
}
.fz-tabs__tab {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--fz-spacing) * 1);
  padding: var(--fz-tab-padding-y) var(--fz-tab-padding-x);
  border: 1px solid var(--fz-tab-border);
  border-radius: var(--fz-tab-radius);
  background: var(--fz-tab-bg);
  color: var(--fz-tab-text);
  font: inherit;
  font-family: var(--fz-control-font);
  font-size: var(--fz-control-text);
  font-weight: var(--fz-font-weight-medium);
  line-height: var(--fz-leading-normal);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  transition: color var(--fz-duration-fast) var(--fz-ease-out),
              border-color var(--fz-duration-fast) var(--fz-ease-out),
              background-color var(--fz-duration-fast) var(--fz-ease-out);
}
.fz-tabs__tab:hover {
  color: var(--fz-color-text);
  border-color: var(--fz-color-border-strong);
  background: var(--fz-color-surface-2);
}
.fz-tabs__tab:focus-visible { outline: none; box-shadow: var(--fz-focus-ring); }
.fz-tabs__tab[aria-selected="true"] {
  color: var(--fz-tab-active-text);
  border-color: var(--fz-tab-active-bg);
  background: var(--fz-tab-active-bg);
}
@media print {
  .fz-tabs { display: none; }
  .fz-tab-panel[hidden] { display: block; }
  .fz-tab-panel + .fz-tab-panel { margin-block-start: calc(var(--fz-spacing) * 8); }
}

/* ---- Embed --------------------------------------------------------------------
   Something from elsewhere shown in the page: a map, a video, another site's
   form. Around an <iframe>, <video> or <img>, which fills it. The embed has a
   shape of its own, wide by default, so the page doesn't jump when what is in
   it arrives. */
.fz-embed {
  box-sizing: border-box;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--fz-color-border);
  border-radius: var(--fz-radius-lg);
  background: var(--fz-color-surface-2);
}
.fz-embed > :where(iframe, video, img) {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}
.fz-embed--square { aspect-ratio: 1; }

/* ---- Prose --------------------------------------------------------------------
   Running text that someone wrote: an article, instructions, an agreement, the
   contents of a rich text field. Its paragraphs, headings and lists are sized
   and spaced for reading, whatever markup they came with. The elements inside
   need no classes of their own, which is the point: the text can come from an
   editor, and it can be in a derived value, where they could not keep any. */
.fz-prose {
  line-height: var(--fz-leading-normal);
  overflow-wrap: break-word;
}
.fz-prose > :where(*) { margin-block: 0; }
.fz-prose > :where(* + *) { margin-block-start: calc(var(--fz-spacing) * 4); }
.fz-prose :where(h1, h2, h3, h4, h5, h6) {
  font-weight: var(--fz-font-weight-semibold);
  line-height: var(--fz-leading-tight);
}
.fz-prose :where(h1) { font-size: var(--fz-text-2xl); }
.fz-prose :where(h2) { font-size: var(--fz-text-xl); }
.fz-prose :where(h3) { font-size: var(--fz-text-lg); }
.fz-prose :where(h4, h5, h6) { font-size: var(--fz-text-base); }
/* more space above a heading than below it, so it belongs to what follows */
.fz-prose > :where(h1, h2, h3, h4, h5, h6):where(:not(:first-child)) {
  margin-block-start: calc(var(--fz-spacing) * 8);
}
.fz-prose :where(ul, ol) {
  margin-block-end: 0;
  padding-inline-start: calc(var(--fz-spacing) * 6);
}
.fz-prose :where(ul) { list-style-type: disc; }
.fz-prose :where(ul ul) { list-style-type: circle; }
.fz-prose :where(ol) { list-style-type: decimal; }
.fz-prose :where(li) { margin-block: 0; }
.fz-prose :where(li + li, li > ul, li > ol) { margin-block-start: var(--fz-spacing); }
.fz-prose :where(blockquote) {
  margin-inline: 0;
  padding-inline-start: calc(var(--fz-spacing) * 4);
  border-inline-start: 3px solid var(--fz-color-border-strong);
  color: var(--fz-color-text-muted);
}
.fz-prose :where(hr) {
  border: 0;
  border-top: 1px solid var(--fz-color-border);
}
.fz-prose :where(img, video) {
  max-width: 100%;
  height: auto;
}

/* ---- Matrix -------------------------------------------------------------------
   A grid of cells, each coloured by what it stands for: a risk matrix, a heat
   map, a chart of what is free and what is taken. On a <table>, so the rows and
   columns have their headings; each cell's colour is on an element inside its
   <td> (a <span>, or a <button> when the cell can be chosen).

   The tone is a tint, as it is a badge's, and the text stays the normal text
   colour, so a cell reads the same whatever colours the theme or the
   Appearance page uses. */
.fz-matrix {
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: var(--fz-spacing);
  font-size: var(--fz-text-sm);
  line-height: var(--fz-leading-tight);
}
.fz-matrix :where(th) {
  padding: calc(var(--fz-spacing) * 2) var(--fz-spacing);
  font-weight: var(--fz-font-weight-medium);
  text-align: center;
  vertical-align: middle;
  color: var(--fz-color-text-muted);
}
.fz-matrix :where(td) { padding: 0; }
.fz-matrix__cell {
  --fz-tone: var(--fz-color-text-subtle);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1;
  padding: var(--fz-spacing);
  border: 1px solid color-mix(in srgb, var(--fz-tone) 70%, transparent);
  border-radius: var(--fz-radius-md);
  background: color-mix(in srgb, var(--fz-tone) 50%, var(--fz-color-surface));
  color: var(--fz-color-text);
  font: inherit;
  font-weight: var(--fz-font-weight-medium);
  text-align: center;
}
.fz-matrix__cell--info    { --fz-tone: var(--fz-color-info); }
.fz-matrix__cell--success { --fz-tone: var(--fz-color-success); }
.fz-matrix__cell--warning { --fz-tone: var(--fz-color-warning); }
.fz-matrix__cell--danger  { --fz-tone: var(--fz-color-danger); }
/* the cell that is chosen, or the one a value falls in */
.fz-matrix__cell--selected {
  outline: 2px solid var(--fz-color-text);
  outline-offset: 2px;
  font-weight: var(--fz-font-weight-bold);
}
/* a cell that is beside the point, while others are being looked at */
.fz-matrix__cell--muted { opacity: 0.4; }
:where(button).fz-matrix__cell { cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  .fz-btn,
  .fz-toggle,
  .fz-input,
  .fz-select,
  .fz-textarea,
  .fz-input-group,
  .fz-checkbox,
  .fz-radio,
  .fz-toggle::before,
  .fz-card--interactive { transition: none; }
}

/* ============================================================
   Layout utilities
   ============================================================

   Tailwind's layout utilities, with an fz- prefix and Tailwind's meanings:
   fz-grid only sets display: grid, and fz-grid-cols-3 is exactly three
   columns at every width, since there are no screen-size variants. For a
   layout that adapts to its space, use the layout classes above.

   They come after the layout classes, and weigh the same (one class), so on
   the same element a utility wins.
   ============================================================ */

/* Display */
.fz-flex        { display: flex; }
.fz-inline-flex { display: inline-flex; }
.fz-grid        { display: grid; }

/* Flex direction, wrapping, and how children grow and shrink */
.fz-flex-row    { flex-direction: row; }
.fz-flex-col    { flex-direction: column; }
.fz-flex-wrap   { flex-wrap: wrap; }
.fz-flex-nowrap { flex-wrap: nowrap; }
.fz-flex-1      { flex: 1; }
.fz-flex-auto   { flex: auto; }
.fz-flex-none   { flex: none; }
.fz-grow        { flex-grow: 1; }
.fz-shrink-0    { flex-shrink: 0; }

/* Alignment */
.fz-items-start    { align-items: flex-start; }
.fz-items-center   { align-items: center; }
.fz-items-end      { align-items: flex-end; }
.fz-items-baseline { align-items: baseline; }
.fz-items-stretch  { align-items: stretch; }
.fz-justify-start   { justify-content: flex-start; }
.fz-justify-center  { justify-content: center; }
.fz-justify-end     { justify-content: flex-end; }
.fz-justify-between { justify-content: space-between; }
.fz-self-start  { align-self: flex-start; }
.fz-self-center { align-self: center; }
.fz-self-end    { align-self: flex-end; }

/* Grid columns, and how many columns a child spans */
.fz-grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.fz-grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fz-grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fz-grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.fz-grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.fz-grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.fz-col-span-1 { grid-column: span 1 / span 1; }
.fz-col-span-2 { grid-column: span 2 / span 2; }
.fz-col-span-3 { grid-column: span 3 / span 3; }
.fz-col-span-4 { grid-column: span 4 / span 4; }
.fz-col-span-5 { grid-column: span 5 / span 5; }
.fz-col-span-6 { grid-column: span 6 / span 6; }
.fz-col-span-full { grid-column: 1 / -1; }

/* Gap: step N of the spacing scale. Also sets the --fz-gap* custom properties
   the layout classes read. */
.fz-gap-0   { --fz-gap: 0; gap: 0; }
.fz-gap-1   { --fz-gap: calc(var(--fz-spacing) * 1); gap: calc(var(--fz-spacing) * 1); }
.fz-gap-2   { --fz-gap: calc(var(--fz-spacing) * 2); gap: calc(var(--fz-spacing) * 2); }
.fz-gap-3   { --fz-gap: calc(var(--fz-spacing) * 3); gap: calc(var(--fz-spacing) * 3); }
.fz-gap-4   { --fz-gap: calc(var(--fz-spacing) * 4); gap: calc(var(--fz-spacing) * 4); }
.fz-gap-5   { --fz-gap: calc(var(--fz-spacing) * 5); gap: calc(var(--fz-spacing) * 5); }
.fz-gap-6   { --fz-gap: calc(var(--fz-spacing) * 6); gap: calc(var(--fz-spacing) * 6); }
.fz-gap-8   { --fz-gap: calc(var(--fz-spacing) * 8); gap: calc(var(--fz-spacing) * 8); }
.fz-gap-10  { --fz-gap: calc(var(--fz-spacing) * 10); gap: calc(var(--fz-spacing) * 10); }
.fz-gap-12  { --fz-gap: calc(var(--fz-spacing) * 12); gap: calc(var(--fz-spacing) * 12); }
.fz-gap-16  { --fz-gap: calc(var(--fz-spacing) * 16); gap: calc(var(--fz-spacing) * 16); }
.fz-gap-x-0   { --fz-gap-x: 0; column-gap: 0; }
.fz-gap-x-1   { --fz-gap-x: calc(var(--fz-spacing) * 1); column-gap: calc(var(--fz-spacing) * 1); }
.fz-gap-x-2   { --fz-gap-x: calc(var(--fz-spacing) * 2); column-gap: calc(var(--fz-spacing) * 2); }
.fz-gap-x-3   { --fz-gap-x: calc(var(--fz-spacing) * 3); column-gap: calc(var(--fz-spacing) * 3); }
.fz-gap-x-4   { --fz-gap-x: calc(var(--fz-spacing) * 4); column-gap: calc(var(--fz-spacing) * 4); }
.fz-gap-x-5   { --fz-gap-x: calc(var(--fz-spacing) * 5); column-gap: calc(var(--fz-spacing) * 5); }
.fz-gap-x-6   { --fz-gap-x: calc(var(--fz-spacing) * 6); column-gap: calc(var(--fz-spacing) * 6); }
.fz-gap-x-8   { --fz-gap-x: calc(var(--fz-spacing) * 8); column-gap: calc(var(--fz-spacing) * 8); }
.fz-gap-x-10  { --fz-gap-x: calc(var(--fz-spacing) * 10); column-gap: calc(var(--fz-spacing) * 10); }
.fz-gap-x-12  { --fz-gap-x: calc(var(--fz-spacing) * 12); column-gap: calc(var(--fz-spacing) * 12); }
.fz-gap-x-16  { --fz-gap-x: calc(var(--fz-spacing) * 16); column-gap: calc(var(--fz-spacing) * 16); }
.fz-gap-y-0   { --fz-gap-y: 0; row-gap: 0; }
.fz-gap-y-1   { --fz-gap-y: calc(var(--fz-spacing) * 1); row-gap: calc(var(--fz-spacing) * 1); }
.fz-gap-y-2   { --fz-gap-y: calc(var(--fz-spacing) * 2); row-gap: calc(var(--fz-spacing) * 2); }
.fz-gap-y-3   { --fz-gap-y: calc(var(--fz-spacing) * 3); row-gap: calc(var(--fz-spacing) * 3); }
.fz-gap-y-4   { --fz-gap-y: calc(var(--fz-spacing) * 4); row-gap: calc(var(--fz-spacing) * 4); }
.fz-gap-y-5   { --fz-gap-y: calc(var(--fz-spacing) * 5); row-gap: calc(var(--fz-spacing) * 5); }
.fz-gap-y-6   { --fz-gap-y: calc(var(--fz-spacing) * 6); row-gap: calc(var(--fz-spacing) * 6); }
.fz-gap-y-8   { --fz-gap-y: calc(var(--fz-spacing) * 8); row-gap: calc(var(--fz-spacing) * 8); }
.fz-gap-y-10  { --fz-gap-y: calc(var(--fz-spacing) * 10); row-gap: calc(var(--fz-spacing) * 10); }
.fz-gap-y-12  { --fz-gap-y: calc(var(--fz-spacing) * 12); row-gap: calc(var(--fz-spacing) * 12); }
.fz-gap-y-16  { --fz-gap-y: calc(var(--fz-spacing) * 16); row-gap: calc(var(--fz-spacing) * 16); }


/* ============================================================
   Utilities
   ============================================================

   Tailwind's utilities, with an fz- prefix and Tailwind's meanings, drawing on
   the tokens. Each does one thing. They come last, and weigh one class like
   everything else here, so on the same element a utility wins over a layout
   class or a component; within a group, the more specific one comes later
   (fz-m-4 fz-mt-0 leaves the top margin at 0).

   Spacing steps are the scale's: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, each a
   multiple of --fz-spacing. They are fixed, as in Tailwind: the Size preset
   changes the component sizes, not the utilities. s and e are start and
   end, which follow the text direction; l and r are always left and right. In
   a site with right-to-left languages, prefer s and e.
   ============================================================ */

/* ---- Margin ---- */
.fz-m-0     { margin: 0; }
.fz-m-1     { margin: calc(var(--fz-spacing) * 1); }
.fz-m-2     { margin: calc(var(--fz-spacing) * 2); }
.fz-m-3     { margin: calc(var(--fz-spacing) * 3); }
.fz-m-4     { margin: calc(var(--fz-spacing) * 4); }
.fz-m-5     { margin: calc(var(--fz-spacing) * 5); }
.fz-m-6     { margin: calc(var(--fz-spacing) * 6); }
.fz-m-8     { margin: calc(var(--fz-spacing) * 8); }
.fz-m-10    { margin: calc(var(--fz-spacing) * 10); }
.fz-m-12    { margin: calc(var(--fz-spacing) * 12); }
.fz-m-16    { margin: calc(var(--fz-spacing) * 16); }

.fz-mx-0    { margin-inline: 0; }
.fz-mx-1    { margin-inline: calc(var(--fz-spacing) * 1); }
.fz-mx-2    { margin-inline: calc(var(--fz-spacing) * 2); }
.fz-mx-3    { margin-inline: calc(var(--fz-spacing) * 3); }
.fz-mx-4    { margin-inline: calc(var(--fz-spacing) * 4); }
.fz-mx-5    { margin-inline: calc(var(--fz-spacing) * 5); }
.fz-mx-6    { margin-inline: calc(var(--fz-spacing) * 6); }
.fz-mx-8    { margin-inline: calc(var(--fz-spacing) * 8); }
.fz-mx-10   { margin-inline: calc(var(--fz-spacing) * 10); }
.fz-mx-12   { margin-inline: calc(var(--fz-spacing) * 12); }
.fz-mx-16   { margin-inline: calc(var(--fz-spacing) * 16); }

.fz-my-0    { margin-block: 0; }
.fz-my-1    { margin-block: calc(var(--fz-spacing) * 1); }
.fz-my-2    { margin-block: calc(var(--fz-spacing) * 2); }
.fz-my-3    { margin-block: calc(var(--fz-spacing) * 3); }
.fz-my-4    { margin-block: calc(var(--fz-spacing) * 4); }
.fz-my-5    { margin-block: calc(var(--fz-spacing) * 5); }
.fz-my-6    { margin-block: calc(var(--fz-spacing) * 6); }
.fz-my-8    { margin-block: calc(var(--fz-spacing) * 8); }
.fz-my-10   { margin-block: calc(var(--fz-spacing) * 10); }
.fz-my-12   { margin-block: calc(var(--fz-spacing) * 12); }
.fz-my-16   { margin-block: calc(var(--fz-spacing) * 16); }

.fz-ms-0    { margin-inline-start: 0; }
.fz-ms-1    { margin-inline-start: calc(var(--fz-spacing) * 1); }
.fz-ms-2    { margin-inline-start: calc(var(--fz-spacing) * 2); }
.fz-ms-3    { margin-inline-start: calc(var(--fz-spacing) * 3); }
.fz-ms-4    { margin-inline-start: calc(var(--fz-spacing) * 4); }
.fz-ms-5    { margin-inline-start: calc(var(--fz-spacing) * 5); }
.fz-ms-6    { margin-inline-start: calc(var(--fz-spacing) * 6); }
.fz-ms-8    { margin-inline-start: calc(var(--fz-spacing) * 8); }
.fz-ms-10   { margin-inline-start: calc(var(--fz-spacing) * 10); }
.fz-ms-12   { margin-inline-start: calc(var(--fz-spacing) * 12); }
.fz-ms-16   { margin-inline-start: calc(var(--fz-spacing) * 16); }

.fz-me-0    { margin-inline-end: 0; }
.fz-me-1    { margin-inline-end: calc(var(--fz-spacing) * 1); }
.fz-me-2    { margin-inline-end: calc(var(--fz-spacing) * 2); }
.fz-me-3    { margin-inline-end: calc(var(--fz-spacing) * 3); }
.fz-me-4    { margin-inline-end: calc(var(--fz-spacing) * 4); }
.fz-me-5    { margin-inline-end: calc(var(--fz-spacing) * 5); }
.fz-me-6    { margin-inline-end: calc(var(--fz-spacing) * 6); }
.fz-me-8    { margin-inline-end: calc(var(--fz-spacing) * 8); }
.fz-me-10   { margin-inline-end: calc(var(--fz-spacing) * 10); }
.fz-me-12   { margin-inline-end: calc(var(--fz-spacing) * 12); }
.fz-me-16   { margin-inline-end: calc(var(--fz-spacing) * 16); }

.fz-mt-0    { margin-top: 0; }
.fz-mt-1    { margin-top: calc(var(--fz-spacing) * 1); }
.fz-mt-2    { margin-top: calc(var(--fz-spacing) * 2); }
.fz-mt-3    { margin-top: calc(var(--fz-spacing) * 3); }
.fz-mt-4    { margin-top: calc(var(--fz-spacing) * 4); }
.fz-mt-5    { margin-top: calc(var(--fz-spacing) * 5); }
.fz-mt-6    { margin-top: calc(var(--fz-spacing) * 6); }
.fz-mt-8    { margin-top: calc(var(--fz-spacing) * 8); }
.fz-mt-10   { margin-top: calc(var(--fz-spacing) * 10); }
.fz-mt-12   { margin-top: calc(var(--fz-spacing) * 12); }
.fz-mt-16   { margin-top: calc(var(--fz-spacing) * 16); }

.fz-mr-0    { margin-right: 0; }
.fz-mr-1    { margin-right: calc(var(--fz-spacing) * 1); }
.fz-mr-2    { margin-right: calc(var(--fz-spacing) * 2); }
.fz-mr-3    { margin-right: calc(var(--fz-spacing) * 3); }
.fz-mr-4    { margin-right: calc(var(--fz-spacing) * 4); }
.fz-mr-5    { margin-right: calc(var(--fz-spacing) * 5); }
.fz-mr-6    { margin-right: calc(var(--fz-spacing) * 6); }
.fz-mr-8    { margin-right: calc(var(--fz-spacing) * 8); }
.fz-mr-10   { margin-right: calc(var(--fz-spacing) * 10); }
.fz-mr-12   { margin-right: calc(var(--fz-spacing) * 12); }
.fz-mr-16   { margin-right: calc(var(--fz-spacing) * 16); }

.fz-mb-0    { margin-bottom: 0; }
.fz-mb-1    { margin-bottom: calc(var(--fz-spacing) * 1); }
.fz-mb-2    { margin-bottom: calc(var(--fz-spacing) * 2); }
.fz-mb-3    { margin-bottom: calc(var(--fz-spacing) * 3); }
.fz-mb-4    { margin-bottom: calc(var(--fz-spacing) * 4); }
.fz-mb-5    { margin-bottom: calc(var(--fz-spacing) * 5); }
.fz-mb-6    { margin-bottom: calc(var(--fz-spacing) * 6); }
.fz-mb-8    { margin-bottom: calc(var(--fz-spacing) * 8); }
.fz-mb-10   { margin-bottom: calc(var(--fz-spacing) * 10); }
.fz-mb-12   { margin-bottom: calc(var(--fz-spacing) * 12); }
.fz-mb-16   { margin-bottom: calc(var(--fz-spacing) * 16); }

.fz-ml-0    { margin-left: 0; }
.fz-ml-1    { margin-left: calc(var(--fz-spacing) * 1); }
.fz-ml-2    { margin-left: calc(var(--fz-spacing) * 2); }
.fz-ml-3    { margin-left: calc(var(--fz-spacing) * 3); }
.fz-ml-4    { margin-left: calc(var(--fz-spacing) * 4); }
.fz-ml-5    { margin-left: calc(var(--fz-spacing) * 5); }
.fz-ml-6    { margin-left: calc(var(--fz-spacing) * 6); }
.fz-ml-8    { margin-left: calc(var(--fz-spacing) * 8); }
.fz-ml-10   { margin-left: calc(var(--fz-spacing) * 10); }
.fz-ml-12   { margin-left: calc(var(--fz-spacing) * 12); }
.fz-ml-16   { margin-left: calc(var(--fz-spacing) * 16); }

.fz-m-auto  { margin: auto; }
.fz-mx-auto { margin-inline: auto; }
.fz-ms-auto { margin-inline-start: auto; }
.fz-me-auto { margin-inline-end: auto; }
.fz-ml-auto { margin-left: auto; }
.fz-mr-auto { margin-right: auto; }

/* ---- Padding ---- */
.fz-p-0     { padding: 0; }
.fz-p-1     { padding: calc(var(--fz-spacing) * 1); }
.fz-p-2     { padding: calc(var(--fz-spacing) * 2); }
.fz-p-3     { padding: calc(var(--fz-spacing) * 3); }
.fz-p-4     { padding: calc(var(--fz-spacing) * 4); }
.fz-p-5     { padding: calc(var(--fz-spacing) * 5); }
.fz-p-6     { padding: calc(var(--fz-spacing) * 6); }
.fz-p-8     { padding: calc(var(--fz-spacing) * 8); }
.fz-p-10    { padding: calc(var(--fz-spacing) * 10); }
.fz-p-12    { padding: calc(var(--fz-spacing) * 12); }
.fz-p-16    { padding: calc(var(--fz-spacing) * 16); }

.fz-px-0    { padding-inline: 0; }
.fz-px-1    { padding-inline: calc(var(--fz-spacing) * 1); }
.fz-px-2    { padding-inline: calc(var(--fz-spacing) * 2); }
.fz-px-3    { padding-inline: calc(var(--fz-spacing) * 3); }
.fz-px-4    { padding-inline: calc(var(--fz-spacing) * 4); }
.fz-px-5    { padding-inline: calc(var(--fz-spacing) * 5); }
.fz-px-6    { padding-inline: calc(var(--fz-spacing) * 6); }
.fz-px-8    { padding-inline: calc(var(--fz-spacing) * 8); }
.fz-px-10   { padding-inline: calc(var(--fz-spacing) * 10); }
.fz-px-12   { padding-inline: calc(var(--fz-spacing) * 12); }
.fz-px-16   { padding-inline: calc(var(--fz-spacing) * 16); }

.fz-py-0    { padding-block: 0; }
.fz-py-1    { padding-block: calc(var(--fz-spacing) * 1); }
.fz-py-2    { padding-block: calc(var(--fz-spacing) * 2); }
.fz-py-3    { padding-block: calc(var(--fz-spacing) * 3); }
.fz-py-4    { padding-block: calc(var(--fz-spacing) * 4); }
.fz-py-5    { padding-block: calc(var(--fz-spacing) * 5); }
.fz-py-6    { padding-block: calc(var(--fz-spacing) * 6); }
.fz-py-8    { padding-block: calc(var(--fz-spacing) * 8); }
.fz-py-10   { padding-block: calc(var(--fz-spacing) * 10); }
.fz-py-12   { padding-block: calc(var(--fz-spacing) * 12); }
.fz-py-16   { padding-block: calc(var(--fz-spacing) * 16); }

.fz-ps-0    { padding-inline-start: 0; }
.fz-ps-1    { padding-inline-start: calc(var(--fz-spacing) * 1); }
.fz-ps-2    { padding-inline-start: calc(var(--fz-spacing) * 2); }
.fz-ps-3    { padding-inline-start: calc(var(--fz-spacing) * 3); }
.fz-ps-4    { padding-inline-start: calc(var(--fz-spacing) * 4); }
.fz-ps-5    { padding-inline-start: calc(var(--fz-spacing) * 5); }
.fz-ps-6    { padding-inline-start: calc(var(--fz-spacing) * 6); }
.fz-ps-8    { padding-inline-start: calc(var(--fz-spacing) * 8); }
.fz-ps-10   { padding-inline-start: calc(var(--fz-spacing) * 10); }
.fz-ps-12   { padding-inline-start: calc(var(--fz-spacing) * 12); }
.fz-ps-16   { padding-inline-start: calc(var(--fz-spacing) * 16); }

.fz-pe-0    { padding-inline-end: 0; }
.fz-pe-1    { padding-inline-end: calc(var(--fz-spacing) * 1); }
.fz-pe-2    { padding-inline-end: calc(var(--fz-spacing) * 2); }
.fz-pe-3    { padding-inline-end: calc(var(--fz-spacing) * 3); }
.fz-pe-4    { padding-inline-end: calc(var(--fz-spacing) * 4); }
.fz-pe-5    { padding-inline-end: calc(var(--fz-spacing) * 5); }
.fz-pe-6    { padding-inline-end: calc(var(--fz-spacing) * 6); }
.fz-pe-8    { padding-inline-end: calc(var(--fz-spacing) * 8); }
.fz-pe-10   { padding-inline-end: calc(var(--fz-spacing) * 10); }
.fz-pe-12   { padding-inline-end: calc(var(--fz-spacing) * 12); }
.fz-pe-16   { padding-inline-end: calc(var(--fz-spacing) * 16); }

.fz-pt-0    { padding-top: 0; }
.fz-pt-1    { padding-top: calc(var(--fz-spacing) * 1); }
.fz-pt-2    { padding-top: calc(var(--fz-spacing) * 2); }
.fz-pt-3    { padding-top: calc(var(--fz-spacing) * 3); }
.fz-pt-4    { padding-top: calc(var(--fz-spacing) * 4); }
.fz-pt-5    { padding-top: calc(var(--fz-spacing) * 5); }
.fz-pt-6    { padding-top: calc(var(--fz-spacing) * 6); }
.fz-pt-8    { padding-top: calc(var(--fz-spacing) * 8); }
.fz-pt-10   { padding-top: calc(var(--fz-spacing) * 10); }
.fz-pt-12   { padding-top: calc(var(--fz-spacing) * 12); }
.fz-pt-16   { padding-top: calc(var(--fz-spacing) * 16); }

.fz-pr-0    { padding-right: 0; }
.fz-pr-1    { padding-right: calc(var(--fz-spacing) * 1); }
.fz-pr-2    { padding-right: calc(var(--fz-spacing) * 2); }
.fz-pr-3    { padding-right: calc(var(--fz-spacing) * 3); }
.fz-pr-4    { padding-right: calc(var(--fz-spacing) * 4); }
.fz-pr-5    { padding-right: calc(var(--fz-spacing) * 5); }
.fz-pr-6    { padding-right: calc(var(--fz-spacing) * 6); }
.fz-pr-8    { padding-right: calc(var(--fz-spacing) * 8); }
.fz-pr-10   { padding-right: calc(var(--fz-spacing) * 10); }
.fz-pr-12   { padding-right: calc(var(--fz-spacing) * 12); }
.fz-pr-16   { padding-right: calc(var(--fz-spacing) * 16); }

.fz-pb-0    { padding-bottom: 0; }
.fz-pb-1    { padding-bottom: calc(var(--fz-spacing) * 1); }
.fz-pb-2    { padding-bottom: calc(var(--fz-spacing) * 2); }
.fz-pb-3    { padding-bottom: calc(var(--fz-spacing) * 3); }
.fz-pb-4    { padding-bottom: calc(var(--fz-spacing) * 4); }
.fz-pb-5    { padding-bottom: calc(var(--fz-spacing) * 5); }
.fz-pb-6    { padding-bottom: calc(var(--fz-spacing) * 6); }
.fz-pb-8    { padding-bottom: calc(var(--fz-spacing) * 8); }
.fz-pb-10   { padding-bottom: calc(var(--fz-spacing) * 10); }
.fz-pb-12   { padding-bottom: calc(var(--fz-spacing) * 12); }
.fz-pb-16   { padding-bottom: calc(var(--fz-spacing) * 16); }

.fz-pl-0    { padding-left: 0; }
.fz-pl-1    { padding-left: calc(var(--fz-spacing) * 1); }
.fz-pl-2    { padding-left: calc(var(--fz-spacing) * 2); }
.fz-pl-3    { padding-left: calc(var(--fz-spacing) * 3); }
.fz-pl-4    { padding-left: calc(var(--fz-spacing) * 4); }
.fz-pl-5    { padding-left: calc(var(--fz-spacing) * 5); }
.fz-pl-6    { padding-left: calc(var(--fz-spacing) * 6); }
.fz-pl-8    { padding-left: calc(var(--fz-spacing) * 8); }
.fz-pl-10   { padding-left: calc(var(--fz-spacing) * 10); }
.fz-pl-12   { padding-left: calc(var(--fz-spacing) * 12); }
.fz-pl-16   { padding-left: calc(var(--fz-spacing) * 16); }

/* ---- Display ---- */
.fz-block        { display: block; }
.fz-inline-block { display: inline-block; }
.fz-inline       { display: inline; }
.fz-hidden       { display: none; }

/* Hidden on screen, read by screen readers: a label for something only an icon
   shows, for instance. */
.fz-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* The one screen-size switch: 48rem (768px), Lyris's mobile layout and
   Tailwind's md. For layout, prefer the layout classes, which respond to their
   own width. */
@media (max-width: 47.99rem) {
  .fz-hide-on-mobile { display: none; }
}
@media (min-width: 48rem) {
  .fz-show-on-mobile { display: none; }
}

/* ---- Width ---- */
.fz-w-full     { width: 100%; }
.fz-w-auto     { width: auto; }
.fz-w-fit      { width: fit-content; }
.fz-max-w-full { max-width: 100%; }
/* Lets a flex or grid child get narrower than its content, which fz-truncate
   needs inside one. */
.fz-min-w-0    { min-width: 0; }

/* ---- Text ---- */
/* Each size sets its line height too, as Tailwind's do. xs-plus (13px) is
   Formulize UI's own step, between xs and sm. */
.fz-text-xs      { font-size: var(--fz-text-xs); line-height: var(--fz-text-xs--line-height); }
.fz-text-xs-plus { font-size: var(--fz-text-xs-plus); line-height: var(--fz-text-xs-plus--line-height); }
.fz-text-sm      { font-size: var(--fz-text-sm); line-height: var(--fz-text-sm--line-height); }
.fz-text-base    { font-size: var(--fz-text-base); line-height: var(--fz-text-base--line-height); }
.fz-text-lg      { font-size: var(--fz-text-lg); line-height: var(--fz-text-lg--line-height); }
.fz-text-xl      { font-size: var(--fz-text-xl); line-height: var(--fz-text-xl--line-height); }
.fz-text-2xl     { font-size: var(--fz-text-2xl); line-height: var(--fz-text-2xl--line-height); }
.fz-text-3xl     { font-size: var(--fz-text-3xl); line-height: var(--fz-text-3xl--line-height); }

.fz-font-normal   { font-weight: var(--fz-font-weight-normal); }
.fz-font-medium   { font-weight: var(--fz-font-weight-medium); }
.fz-font-semibold { font-weight: var(--fz-font-weight-semibold); }
.fz-font-bold     { font-weight: var(--fz-font-weight-bold); }

.fz-font-sans     { font-family: var(--fz-font-sans); }
.fz-font-heading  { font-family: var(--fz-font-heading); }
.fz-font-mono     { font-family: var(--fz-font-mono); }

.fz-leading-tight  { line-height: var(--fz-leading-tight); }
.fz-leading-snug   { line-height: var(--fz-leading-snug); }
.fz-leading-normal { line-height: var(--fz-leading-normal); }

.fz-text-start  { text-align: start; }
.fz-text-center { text-align: center; }
.fz-text-end    { text-align: end; }
.fz-text-left   { text-align: left; }
.fz-text-right  { text-align: right; }

/* Text colours, by role. The status colours are for short, emphasised text,
   such as a status word or a total, not paragraphs: some themes' status colours
   are too light to read at body text size. */
.fz-text-default   { color: var(--fz-color-text); }
.fz-text-muted     { color: var(--fz-color-text-muted); }
.fz-text-subtle    { color: var(--fz-color-text-subtle); }
.fz-text-accent    { color: var(--fz-color-accent-text); }
.fz-text-on-accent { color: var(--fz-color-on-accent); }
.fz-text-success   { color: var(--fz-color-success); }
.fz-text-warning   { color: var(--fz-color-warning); }
.fz-text-danger    { color: var(--fz-color-danger); }
.fz-text-info      { color: var(--fz-color-info); }

/* One line, cut off with an ellipsis. */
.fz-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fz-text-nowrap     { white-space: nowrap; }
.fz-wrap-break-word { overflow-wrap: break-word; }
.fz-tabular-nums    { font-variant-numeric: tabular-nums; }

/* Capitals, and wider letter spacing to go with them: together with a small
   size and a muted colour, the small label over a figure or a group. */
.fz-uppercase       { text-transform: uppercase; }
.fz-tracking-wide   { letter-spacing: var(--fz-tracking-wide); }
.fz-tracking-wider  { letter-spacing: var(--fz-tracking-wider); }

/* ---- Background ---- */
.fz-bg-page         { background-color: var(--fz-color-page); }
.fz-bg-surface      { background-color: var(--fz-color-surface); }
.fz-bg-surface-2    { background-color: var(--fz-color-surface-2); }
.fz-bg-surface-3    { background-color: var(--fz-color-surface-3); }
.fz-bg-accent       { background-color: var(--fz-color-accent); }
.fz-bg-accent-soft  { background-color: var(--fz-color-accent-soft); }
.fz-bg-success-soft { background-color: var(--fz-color-success-soft); }
.fz-bg-warning-soft { background-color: var(--fz-color-warning-soft); }
.fz-bg-danger-soft  { background-color: var(--fz-color-danger-soft); }
.fz-bg-info-soft    { background-color: var(--fz-color-info-soft); }

/* ---- Border ---- */
/* A 1px border, in the border colour; then a colour class changes its colour. */
.fz-border   { border: 1px solid var(--fz-color-border); }
.fz-border-t { border-top: 1px solid var(--fz-color-border); }
.fz-border-b { border-bottom: 1px solid var(--fz-color-border); }
.fz-border-s { border-inline-start: 1px solid var(--fz-color-border); }
.fz-border-e { border-inline-end: 1px solid var(--fz-color-border); }
.fz-border-0 { border-width: 0; }

.fz-border-strong  { border-color: var(--fz-color-border-strong); }
.fz-border-accent  { border-color: var(--fz-color-accent); }
.fz-border-success { border-color: var(--fz-color-success); }
.fz-border-warning { border-color: var(--fz-color-warning); }
.fz-border-danger  { border-color: var(--fz-color-danger); }
.fz-border-info    { border-color: var(--fz-color-info); }

/* ---- Corner radius ---- */
.fz-rounded-none { border-radius: 0; }
.fz-rounded-sm   { border-radius: var(--fz-radius-sm); }
.fz-rounded-md   { border-radius: var(--fz-radius-md); }
.fz-rounded-lg   { border-radius: var(--fz-radius-lg); }
.fz-rounded-xl   { border-radius: var(--fz-radius-xl); }
.fz-rounded-full { border-radius: var(--fz-radius-full); }

/* ---- Shadow ---- */
.fz-shadow-none { box-shadow: none; }
.fz-shadow-xs   { box-shadow: var(--fz-shadow-xs); }
.fz-shadow-sm   { box-shadow: var(--fz-shadow-sm); }
.fz-shadow-md   { box-shadow: var(--fz-shadow-md); }
.fz-shadow-lg   { box-shadow: var(--fz-shadow-lg); }

/* ---- Overflow ---- */
.fz-overflow-auto   { overflow: auto; }
.fz-overflow-x-auto { overflow-x: auto; }
.fz-overflow-hidden { overflow: hidden; }

/* ---- Lists ---- */
.fz-list-none { list-style-type: none; }

/* ---- Print ---- */
/* For a page that is meant to be printed: what is only on paper (a logo, say),
   what is only on screen (the Print button), where a new sheet starts, and what
   must not be split across two. Tailwind does these with its print: variant;
   there are no variants here, so they are classes. */
.fz-print-only { display: none; }
@media print {
  .fz-print-only         { display: revert; }
  .fz-print-hidden       { display: none; }
  .fz-break-before-page  { break-before: page; }
  .fz-break-inside-avoid { break-inside: avoid; }
}

/* ============================================================
   Hidden
   ============================================================

   The hidden attribute hides anything with one of these classes, even one
   whose class gives it a display of its own: a card or a stack is a flex box,
   which would otherwise win over the browser's own rule for hidden. Last in the
   file, so it beats every class above it; [hidden] weighs as much as a class.
   ============================================================ */

[hidden]:where([class*="fz-"]) { display: none; }
