/* ==========================================================================
   Checklister — base
   Tokens, reset, typography, and the handful of components every page uses.
   Plain CSS on purpose: no build step, no framework, no utility classes.
   ========================================================================== */

/* Atkinson Hyperlegible (SIL OFL), Braille Institute of America — vendored in
   assets/vendor/atkinson/ beside Vue and jsQR, licence included.

   Chosen for the brief rather than for the look of it: it was drawn to be read
   at a glance by people with low vision, which is the same problem a cleaner
   has holding a phone at arm's length in a dim corridor. Its letterforms are
   deliberately hard to confuse with one another — which matters when the thing
   on screen is a short code like BIRCH-4KQ2 and getting it wrong opens the
   wrong lodge. 34KB for four files, swap-loaded behind the system stack. */
@font-face {
  font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/vendor/atkinson/atkinson-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/vendor/atkinson/atkinson-400-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+2020, U+20A0-20AB, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/vendor/atkinson/atkinson-700-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible"; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/vendor/atkinson/atkinson-700-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+2020, U+20A0-20AB, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* The product replaces a sheet of paper taped up by the door, so the page is
     a sheet: a barely-warm white ground (not cream — cream is a costume), a
     true white for anything that is meant to read as printed, and a rule light
     enough to be a fold but dark enough to actually see. */
  --paper:        #fbfbf9;
  --paper-raised: #ffffff;
  --paper-sunken: #f2f2ee;
  --paper-veil:   rgba(251, 251, 249, .86);             /* sticky bars, over blur */
  --ink:          #16201f;                              /* a very dark teal-grey, not a tinted black */
  --ink-soft:     #4f5b59;
  --ink-faint:    #808c8a;
  --rule:         #e0e2dd;
  --rule-strong:  #c6cac4;

  /* Brand is the teal, and it is pitched to sit beside the logo. Sampling the
     mark settles what that means: it holds no green-teal at all, its lightest
     region is a cyan at hue ~185, and every colour in it lands at L .37-.44.
     The old #0f766e was hue 178 at L .25 — near enough in hue, far darker and
     duller, which is why the mark looked borrowed from another product on
     paper and fine against the dark ground.

     So --brand is the fill and it is as light as the palette can go, which is
     not a matter of taste: --brand is *also* every teal border, icon, rule and
     focus ring on paper, and a UI graphic needs 3:1. #0a9fae sits on that
     floor at 3.08. One step lighter and the ring around a focused field stops
     being visible, which is a real thing to lose for a colour.

     Letters on that fill are white, which is a decision taken with the number
     in view rather than around it: white on #0a9fae is 3.19:1, under the 4.5
     a button label wants. The gradient is arranged to give it what it can —
     --brand is the *top* of it and it darkens downward, so the button reads
     as the bright cyan while the white sits on 3.19 to 3.77 rather than on
     the 2.63 a lighter top would have handed it. Hover darkens for the same
     reason. If this ever needs to pass, the fix is dark ink on the fill
     (4.98:1), not a duller teal.

     Every place teal is *words on paper* takes --brand-text, the same hue
     three steps down, clearing 4.5:1. Splitting the two is the whole reason
     the fill can be this light; putting a link back on --brand undoes it.

     Violet is the *second* voice — chrome, accents, the things that frame the
     work rather than the work itself. Green stays reserved for "done", the one
     colour a cleaner reads at arm's length without thinking. */
  --brand:        #0a9fae;                             /* fills, borders, icons, rings */
  --brand-text:   #007e8a;                             /* teal as words on paper */
  --brand-dark:   #00646f;
  --brand-tint:   #e6f7fa;
  --brand-ink:    #ffffff;                              /* text on a brand fill */
  --brand-grad:   linear-gradient(165deg, #0a9fae, #0891a0);
  /* Hover is a gradient too, and that is not decoration: background-image
     cannot interpolate, so it flips at the halfway point of the transition.
     Against a flat hover colour the image vanished while the colour under it
     was still half transparent, and the page showed through the button for
     70ms — the flicker. Two opaque gradients never leave a gap. */
  --brand-grad-hover:  linear-gradient(165deg, #0891a0, #067d8b);

  --accent:       #7c3aed;
  --accent-dark:  #6d28d9;
  --accent-lift:  #a78bfa;
  --accent-tint:  #f1ecfe;
  --accent-ink:   #ffffff;
  --accent-grad:  linear-gradient(165deg, #8b5cf6, #6d28d9);
  --accent-grad-hover: linear-gradient(165deg, #7c3aed, #5b21b6);
  --accent-wash:  radial-gradient(120% 100% at 10% 0%, rgba(124, 58, 237, .085), transparent 60%);
  --accent-row:   rgba(124, 58, 237, .055);             /* table hover, barely there */

  /* The mark, and the one place the two colours are allowed to touch. */
  --duo-grad:     linear-gradient(140deg, #12c2d4 0%, #7c3aed 100%);

  --done:         #15803d;                              /* the tick. saturated on purpose */
  --done-tint:    #e4f5e9;
  --warn:         #a85f08;
  --warn-tint:    #fdf1e0;
  --danger:       #c22f2a;
  --danger-tint:  #fcecea;

  --focus:        #0a9fae;
  --ring:         0 0 0 3px rgba(10, 159, 174, .22);

  /* Geometry */
  /* Small radii, and only where the thing is genuinely an object or a control.
     One 16px radius on everything is what makes every SaaS page the same page. */
  --radius:       6px;
  --radius-lg:    12px;
  --radius-pill:  999px;
  /* Near-flat by default: a rule around a white surface already says "this is
     a thing". --shadow-lg is for the two objects that genuinely float — the
     phone in a product shot and the sheet taped to the hero. */
  --shadow:       0 1px 2px rgba(22, 32, 31, .04);
  --shadow-lg:    0 2px 4px rgba(22, 32, 31, .05), 0 18px 36px -20px rgba(22, 32, 31, .4);
  --measure:      68ch;

  /* Type */
  --font-body: "Atkinson Hyperlegible", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:        #121616;
    --paper-raised: #1a1f1e;
    --paper-sunken: #0d1111;
    --paper-veil:   rgba(18, 22, 22, .86);
    --ink:          #e9edea;
    --ink-soft:     #a2afac;
    --ink-faint:    #77837f;
    --rule:         #29302e;
    --rule-strong:  #3a4341;

    --brand:        #2dd4bf;
    --brand-text:   #2dd4bf;                           /* a dark ground needs no second step */
    --brand-dark:   #5eead4;
    --brand-tint:   #10312e;
    --brand-ink:    #06201e;
    --brand-grad:   linear-gradient(165deg, #2dd4bf, #14b8a6);
    --brand-grad-hover:  linear-gradient(165deg, #5eead4, #2dd4bf);

    --accent:       #a78bfa;
    --accent-dark:  #c4b5fd;
    --accent-lift:  #8b5cf6;
    --accent-tint:  #241c3d;
    --accent-ink:   #180f2e;
    --accent-grad:  linear-gradient(165deg, #a78bfa, #8b5cf6);
    --accent-grad-hover: linear-gradient(165deg, #c4b5fd, #a78bfa);
    --accent-wash:  radial-gradient(120% 100% at 10% 0%, rgba(139, 92, 246, .15), transparent 60%);
    --accent-row:   rgba(139, 92, 246, .1);

    --duo-grad:     linear-gradient(140deg, #2dd4bf 0%, #8b5cf6 100%);

    --done:         #4ade80;
    --done-tint:    #102c1c;
    --warn:         #f2ae65;
    --warn-tint:    #33240f;
    --danger:       #f58f8a;
    --danger-tint:  #331816;

    --focus:        #2dd4bf;
    --ring:         0 0 0 3px rgba(45, 212, 191, .28);
    --shadow:       0 1px 2px rgba(0, 0, 0, .35);
    --shadow-lg:    0 2px 6px rgba(0, 0, 0, .5), 0 24px 48px -22px rgba(0, 0, 0, .9);
  }
}

/* --- Reset (light touch) ------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.6 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { line-height: 1.14; margin: 0 0 .5em; font-weight: 700; letter-spacing: -.028em; }
h1 { font-size: 2.4rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.1rem; letter-spacing: -.015em; }
p, ul, ol { margin: 0 0 1em; }
p { max-width: var(--measure); }

a { color: var(--brand-text); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--brand-dark); }

img, svg, video { max-width: 100%; height: auto; }

small, .small { font-size: .85rem; }
.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.mono  { font-family: var(--font-mono); }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --- Layout -------------------------------------------------------------- */

.wrap      { width: 100%; max-width: 1140px; margin-inline: auto; padding-inline: 20px; }
.wrap-slim { width: 100%; max-width: 640px;  margin-inline: auto; padding-inline: 20px; }
.stack > * + * { margin-top: 1rem; }
.row { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; }
.row-between { display: flex; gap: .75rem; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.grow { flex: 1 1 auto; min-width: 0; }
.hidden { display: none !important; }

/* --- The mark -------------------------------------------------------------
   In base.css rather than in one of the layers: the wordmark sits in the
   header of every page, marketing and signed-in alike, and it lived in
   marketing.css for long enough that the app pages were rendering it
   unstyled.
   ------------------------------------------------------------------------ */

.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  font-weight: 750; font-size: 1.05rem; letter-spacing: -.02em;
  color: var(--ink); text-decoration: none;
}
.brand:hover { color: var(--ink); }
/* The mark is the drawn logo, and it is a picture rather than a glyph in a
   box: it carries its own colour, so it wears the same file on paper, on the
   dark rail and in the dark scheme, and nothing here has to tint it. It is
   28px rather than the 26px the drawn box was, because the file carries a
   margin of its own inside the square. */
.brand-mark {
  width: 28px; height: 28px; flex: none;
  object-fit: contain;
}

/* --- Buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  padding: .58em 1.05em;
  font: inherit; font-weight: 600; line-height: 1.25;
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  box-shadow: 0 1px 1.5px rgba(22, 27, 33, .04);
  cursor: pointer;
  text-decoration: none;
  transition: background .14s, border-color .14s, box-shadow .14s, transform .06s, color .14s;
}
.btn:hover { background: var(--paper-sunken); border-color: var(--rule-strong); color: var(--ink); }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }

.btn-primary {
  background: var(--brand-grad);
  border-color: transparent;
  color: var(--brand-ink);
  box-shadow: 0 1px 2px rgba(4, 48, 54, .3), 0 8px 18px -10px rgba(10, 159, 174, .65);
}
.btn-primary:hover {
  background: var(--brand-grad-hover); border-color: transparent; color: var(--brand-ink);
  box-shadow: 0 1px 2px rgba(4, 48, 54, .34), 0 10px 22px -10px rgba(10, 159, 174, .75);
}

/* The second voice: violet, for an action that sits beside the primary one
   rather than competing with it. */
.btn-accent {
  background: var(--accent-grad); border-color: transparent; color: var(--accent-ink);
  box-shadow: 0 1px 2px rgba(76, 29, 149, .28), 0 8px 18px -10px rgba(124, 58, 237, .6);
}
.btn-accent:hover { background: var(--accent-grad-hover); border-color: transparent; color: var(--accent-ink); }

.btn-danger { color: var(--danger); border-color: var(--rule-strong); background: transparent; box-shadow: none; }
.btn-danger:hover { background: var(--danger-tint); color: var(--danger); border-color: var(--danger); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-soft); box-shadow: none; }
.btn-ghost:hover { background: var(--paper-sunken); color: var(--ink); }

.btn-lg { padding: .82em 1.55em; font-size: 1.05rem; border-radius: var(--radius); }
.btn-sm { padding: .38em .72em; font-size: .875rem; }
.btn-block { display: flex; width: 100%; }

/* --- Forms --------------------------------------------------------------- */

label { display: block; font-weight: 600; font-size: .89rem; margin-bottom: .35em; }
.field + .field { margin-top: 1.1rem; }
.field-hint { font-size: .85rem; color: var(--ink-soft); margin: .4em 0 0; max-width: 62ch; }

/* --- The hint ------------------------------------------------------------
   The long explanation, folded away behind a small i.

   Every console screen had grown two or three paragraphs telling the reader
   what the thing on it was for, which is the shape of documentation rather
   than the shape of a tool: the paragraph is the part people skip, and it
   pushed the list or the sheet — the thing they came for — down the page. So
   the short line stays in the open and the reasoning goes behind the icon.

   It is the platform's own popover, which is what buys it for free: no
   JavaScript at all (`popovertarget` does the toggling), Esc and a click
   outside dismiss it, only one is open at a time, and it renders in the top
   layer — so it is not clipped by `.card-flush`'s `overflow: hidden`, which
   is exactly what ruled out an absolutely positioned panel. A disclosure
   opening in flow was tried first and pushed the page around underneath the
   reader, which is the thing this is meant to stop.

   Placement rides the *implicit* anchor: a popover invoked by
   `popovertarget` takes that button as its anchor with no `anchor-name` to
   keep unique, so twenty-four hints on four pages need no ids beyond the one
   the invoker already carries. Where anchor positioning is missing the
   popover keeps its own default and lands centred in the viewport — a small
   card in the middle of the screen, which is a fair reading of the same
   thing rather than a broken one, so there is nothing to polyfill.
   ------------------------------------------------------------------------ */

/* The i itself: a button, not a link — it goes nowhere. --ink-faint at rest
   so it reads as available rather than as something owed, violet on hover
   and while open because it frames the work rather than being it. */
.hint {
  display: inline-flex; align-items: center;
  padding: 0; margin: 0 0 0 .1em;
  border: 0; background: none;
  color: var(--ink-faint);
  cursor: pointer;
  vertical-align: -.15em;
}
.hint:hover { color: var(--accent); }
.hint .ico::before { width: 1.05em; height: 1.05em; }

/* An i earns its place only where a reader has a real question the screen does
   not already answer, and it hangs off the control that raises it: a picker's
   legend, a card's title, the line under a field. There were thirty of these
   and there are ten, and both cuts came from the same test.

   The first cut was the line each one used to sit on. A `.hint-line` was a
   paragraph whose whole job was to carry the button, so it had to be given
   something to say, and what it got was a handle: "How a checklist starts",
   "What deleting does". That is a paragraph of documentation with the
   paragraph taken out.

   The second cut was the content. Half of what was left explained the product
   rather than answering anything: the i on the Checklists heading opened with
   how a checklist is triggered, which is decision 7 in this file and not a
   question anybody has while reading a list of checklists. Others restated the
   line directly under them, or the rail note beside them. So: no i on a page
   heading, and none on a control whose own words already say it.

   The i's that stayed all answer something sharp. Ticking people on a
   checklist gives them nothing to do. Somebody posted nowhere counts as
   everywhere. Pieter is missing from the group picker. Replace and Turn off do
   different things to a link people already hold.

   The label rows are flex containers, so the i is a flex item there and their
   own gap spaces it; it only needs pulling back off its inline margin. */
.picker-legend .hint, .rail-title .hint { margin-left: -.15em; }

/* Where the i cannot go inside the text at all: a <label> that already wraps a
   control, where a button within it would work that control on the way past.
   The row holds the two side by side so the i still sits beside the words. */
.hint-host { display: flex; align-items: center; gap: .3rem; }

/* The panel. --shadow-lg, which is otherwise kept for the two objects that
   genuinely float, and this is the third: it is in the top layer, over the
   page rather than on it, and the rule alone would leave it reading as a card
   that had come loose. No margin here — the UA's own `inset: 0; margin: auto`
   is what centres the unanchored fallback, so it is only overridden below. */
.hint-pop {
  width: min(30rem, calc(100vw - 2rem));
  max-height: min(24rem, calc(100vh - 2rem));
  overflow-y: auto;
  padding: .9rem 1rem;
  font-size: .875rem; line-height: 1.55; color: var(--ink-soft);
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.hint-pop p { margin: 0; max-width: none; }
.hint-pop p + p { margin-top: .7em; }
.hint-pop strong { color: var(--ink); }

@supports (position-area: block-end) {
  .hint-pop {
    /* Below the i and running rightwards, falling back up and leftwards as the
       viewport runs out — a hint in the rail is 320px from the right edge. */
    inset: auto;
    position-area: block-end span-inline-end;
    position-try-fallbacks:
      block-end span-inline-start,
      block-start span-inline-end,
      block-start span-inline-start;
    margin: .4rem 0;
  }
}

input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="search"], input[type="tel"], input[type="date"], input[type="time"],
select, textarea {
  width: 100%;
  padding: .6em .75em;
  font: inherit;
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  transition: border-color .14s, box-shadow .14s;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; border-color: var(--brand); box-shadow: var(--ring);
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--brand); width: auto; }
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px; box-shadow: none;
}
textarea { min-height: 5em; resize: vertical; }
input:disabled, select:disabled, textarea:disabled { background: var(--paper-sunken); color: var(--ink-faint); }

fieldset { border: 1px solid var(--rule); border-radius: var(--radius); padding: 1rem; margin: 0 0 1rem; }
legend { font-weight: 650; padding-inline: .4em; }

/* --- Surfaces ------------------------------------------------------------ */

.card {
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  padding: 1.35rem;
  box-shadow: var(--shadow);
}
.card + .card { margin-top: 1rem; }
.card-flush { padding: 0; overflow: hidden; }

.notice {
  position: relative;
  border: 1px solid var(--rule);
  background: var(--brand-tint);
  border-radius: var(--radius-lg);
  padding: .85rem 1.1rem .85rem 1.25rem;
  overflow: hidden;
  /* A notice is often a <p>, and the measure that keeps prose readable would
     otherwise stop the banner short of the column it sits in. */
  max-width: none;
}
.notice::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: var(--brand); }
.notice > :last-child { margin-bottom: 0; }
.notice-error { background: var(--danger-tint); }
.notice-error::before { background: var(--danger); }
.notice-warn  { background: var(--warn-tint); }
.notice-warn::before { background: var(--warn); }
.notice-done  { background: var(--done-tint); }
.notice-done::before { background: var(--done); }

.tag {
  display: inline-flex; align-items: center; gap: .35em;
  padding: .2em .65em;
  font-size: .765rem; font-weight: 650; letter-spacing: .015em;
  border-radius: var(--radius-pill);
  background: var(--paper-sunken); color: var(--ink-soft);
  border: 1px solid var(--rule);
  white-space: nowrap;
}
.tag + .tag { margin-left: .3rem; }
.tag-done   { background: var(--done-tint);   color: var(--done);   border-color: transparent; }
.tag-open   { background: var(--warn-tint);   color: var(--warn);   border-color: transparent; }
.tag-late   { background: var(--danger-tint); color: var(--danger); border-color: transparent; }
.tag-req    { background: var(--brand-tint);  color: var(--brand-dark); border-color: transparent; }
.tag-accent { background: var(--accent-tint); color: var(--accent); border-color: transparent; }
.tag-warn   { background: var(--warn-tint);   color: var(--warn);   border-color: transparent; }

/* --- Tables -------------------------------------------------------------- */

.table-scroll { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: .93rem; }
table.data th, table.data td { padding: .72rem .9rem; text-align: left; border-bottom: 1px solid var(--rule); }
table.data thead th {
  font-size: .82rem; color: var(--ink-faint); font-weight: 700;
  background: var(--paper-sunken);
  border-bottom: 1px solid var(--rule-strong);
}
table.data tbody tr { transition: background .12s; }
table.data tbody tr:hover { background: var(--accent-row); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* The row is the link. Every console list is a list and a page per thing, so
   there was never more than one thing to press in a row and an Edit button at
   the end of each line was a column of chrome saying what the row already is.
   The name is a real anchor pointing at the `?id=` the page reads — that is
   what Tab reaches, what a middle-click opens in a tab and what a screen reader
   announces — and the rest of the line repeats it with a click handler. Same
   gesture as `.rail-row` one room over, down to leaving the name unmarked and
   letting the row's own hover say it is a target. */
/* The cursor is named on the cells as well as on the row: a `<tr>` paints no box
   of its own, so a browser can resolve the pointer from the `<td>` under it and
   leave the arrow unchanged if only the row is asked. */
table.data tbody tr.row-link,
table.data tbody tr.row-link td { cursor: pointer; }
table.data .row-name { color: inherit; text-decoration: none; }

/* --- Utilities ----------------------------------------------------------- */

.skip-link {
  position: absolute; left: -9999px;
  background: var(--brand); color: var(--brand-ink); padding: .6em 1em; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; top: 0; z-index: 100; }

.spinner {
  width: 1em; height: 1em; border-radius: 50%; flex: none;
  border: 2px solid var(--rule-strong); border-top-color: var(--brand);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

[v-cloak] { display: none; }
