/* BrandTelligence licence console.
   Built to the brand guidelines: Urbanist everywhere, JetBrains Mono for eyebrows and technical
   labels, restrained colour, generous whitespace, subtle motion. No emojis — every glyph is an
   inline SVG in the house style. */

/* Tints are rgba(var(--x-rgb), .3), not color-mix().
   The two are identical when mixing with `transparent` — that is all color-mix was doing here, and
   it is exactly "this colour at that alpha" — but color-mix needs Chrome 111 or newer, and a
   browser without it DROPS the whole declaration rather than approximating. Most of those losses
   were only cosmetic. One was not: input:focus also sets `outline: none`, so a dropped ring left a
   keyboard user with no indication of where they were at all.
   rgba works everywhere, says the same thing, and cannot fail that way. */

@import url('https://fonts.googleapis.com/css2?family=Urbanist:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');

:root {
  --white: #ffffff;
  --primary: #09090b;          /* off-black. Never pure #000. */
  --secondary: #71717a;
  /* The three colours that get used at partial opacity are held as RGB triplets, and their solid
     forms are derived from them. One definition per colour, and a tint is rgba(var(--x-rgb), .3)
     rather than color-mix() — same result, and it works in every browser rather than Chrome 111
     and up. See the note at the top of this file. */
  --brand-rgb: 238, 126, 34;
  --brand-2-rgb: 13, 148, 153;
  --neutral-300-rgb: 212, 212, 216;

  --brand: rgb(var(--brand-rgb));
  --brand-2: rgb(var(--brand-2-rgb));
  --brand-3: #8b5cf6;
  --brand-deep: #c5641a;
  --neutral-50: #fafafa;  --neutral-100: #f4f4f5; --neutral-200: #e4e4e7;
  --neutral-300: rgb(var(--neutral-300-rgb)); --neutral-400: #a1a1aa; --neutral-500: #71717a;
  --neutral-600: #52525b; --neutral-700: #3f3f46; --neutral-800: #27272a;
  --neutral-900: #18181b; --neutral-950: #09090b;

  --font: 'Urbanist', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'SFMono-Regular', Menlo, monospace;
  --container: 1320px;
  --gutter: clamp(16px, 3vw, 40px);

  --shadow-emboss-dark: 0px -3px 0px 0px #080808 inset, 0px 1px 0px 0px rgba(255,255,255,.30) inset,
    0px 2.77px 2.21px 0px rgba(0,0,0,.12), 0px 6.65px 5.32px 0px rgba(0,0,0,.13),
    0px 12.52px 10.02px 0px rgba(0,0,0,.14), 0px 22.34px 17.87px 0px rgba(0,0,0,.14);
  --shadow-emboss-light: 0px -3px 0px 0px #e9e9e9 inset, 0px 1px 0px 0px rgba(255,255,255,.7) inset,
    0px 2.77px 2.21px 0px rgba(0,0,0,.12), 0px 3px 3px 0px rgba(0,0,0,.14);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  font-weight: 400;
  font-size: clamp(1rem, .95rem + .25vw, 1.0625rem);
  line-height: 1.5;
  color: var(--primary);
  background: var(--white);
}

.container { max-width: var(--container); margin: 0 auto; padding: 0 var(--gutter); }

h1, h2, h3 { font-weight: 700; letter-spacing: -0.01em; margin: 0; }
h1 { font-size: clamp(1.75rem, 1.2rem + 2vw, 2.5rem); }
h2 { font-size: clamp(1.25rem, 1rem + 1vw, 1.6rem); }
a { color: var(--brand-deep); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Eyebrow — the technical voice. Mono, uppercase, wide tracking. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 12px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--neutral-500);
}
.dark-surface .eyebrow { color: var(--neutral-300); }

/* ---- dark surface: off-black with brand radial glows, never flat ---- */
.dark-surface {
  position: relative; overflow: hidden; color: #fff; border-radius: 40px;
  background:
    radial-gradient(58% 80% at 16% 18%, rgba(var(--brand-rgb), .32), transparent 62%),
    radial-gradient(55% 78% at 86% 80%, rgba(var(--brand-2-rgb), .3), transparent 62%),
    var(--primary);
}
.grid-overlay::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px),
    linear-gradient(rgba(238,126,34,.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13,148,153,.10) 1px, transparent 1px);
  background-size: 40px 40px, 40px 40px, 200px 200px, 200px 200px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, black 25%, transparent 80%);
  mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, black 25%, transparent 80%);
}

/* ---- light utility/auth page: light grid, soft brand glow, bordered WHITE card ----
   The grid is drawn at roughly a third of the strength the brand sheet specifies. At full
   neutral-200 on a near-white ground it reads as ruled paper and competes with the card; the point
   of it is texture you notice only after the thing you came for. A radial mask fades it out towards
   the edges so the corners are clean rather than tiled. */
.light-grid {
  position: relative;
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center; padding: var(--gutter);
  background:
    radial-gradient(60% 55% at 50% 0%, rgba(var(--brand-rgb), .07), transparent 72%),
    var(--neutral-50);
}
.light-grid::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(var(--neutral-300-rgb), .34) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--neutral-300-rgb), .34) 1px, transparent 1px);
  background-size: 48px 48px, 48px 48px;
  -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 45%, black 10%, transparent 78%);
  mask-image: radial-gradient(ellipse 75% 65% at 50% 45%, black 10%, transparent 78%);
}
.light-grid > * { position: relative; }

/* ---- buttons ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  border: 0; cursor: pointer; border-radius: 99px;
  font-family: var(--font); font-weight: 600; font-size: 15px; line-height: 24px; padding: 12px 22px;
  position: relative; overflow: hidden; white-space: nowrap;
  transition: all .3s cubic-bezier(.2,.8,.2,1);
}
.btn:hover { transform: translateY(-2px); }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn-primary {
  color: #fff;
  background: radial-gradient(62.56% 62.56% at 28.14% -10.42%, rgba(255,255,255,.2) 0%, rgba(255,255,255,0) 100%),
              linear-gradient(0deg, #272727, #272727);
  box-shadow: var(--shadow-emboss-dark);
}
.btn-secondary {
  color: var(--primary);
  background: radial-gradient(62.56% 62.56% at 28.14% -10.42%, rgba(255,255,255,.2) 0%, rgba(255,255,255,0) 100%),
              linear-gradient(0deg, #f5f5f5, #f5f5f5);
  box-shadow: var(--shadow-emboss-light);
}
.btn-sm { font-size: 13.5px; padding: 8px 16px; }
/* Destructive actions read as text, not as a red button: revoking a customer should take a
   deliberate read, not a reflex click. */
.btn-danger { color: #b91c1c; background: transparent; box-shadow: none; }
.btn-danger:hover { background: #fef2f2; }
/* The same shape without the warning: a real action that decides nothing dramatic. */
.btn-quiet { color: var(--neutral-600); background: transparent; box-shadow: none; }
.btn-quiet:hover { background: var(--neutral-100); color: var(--primary); }

/* The queued request whose details are sitting in the form below, so it is obvious which one is
   about to be answered — the form is far enough down the page to lose track of that. */
.row-picked > td { background: rgba(var(--brand-rgb), .08); }

/* ---- numbered steps (the public "get the app" page) ---- */
/* The logo at the head of a public page. Was the same inline style copied onto five of them,
   which meant resizing it was five edits and a chance to miss one. Margins stay per-page; only
   the mark itself is shared.
   The hero gets its own size: a mark that reads correctly on a 400px sign-in card is lost above
   a 2.6rem headline on a full-width dark band. */
.brandmark { height: 40px; width: auto; display: block; }
.brandmark-hero { height: clamp(44px, 4.4vw, 62px); }

.step { display: flex; gap: 16px; align-items: flex-start; }
.step-n {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 99px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 14px; font-weight: 500;
  color: var(--brand-deep); background: rgba(var(--brand-rgb), .15);
}
@media (max-width: 480px) { .step { gap: 12px; } }

/* ---- cards, inputs ---- */
.card {
  background: #fff; border: 1px solid var(--neutral-200); border-radius: 22px; padding: 24px;
  transition: transform .3s ease, box-shadow .3s ease;
}
.card-hover:hover { transform: translateY(-4px); box-shadow: 0 22px 48px -22px rgba(0,0,0,.18); }

label { display: block; font-size: 14px; font-weight: 500; color: var(--neutral-700); margin-bottom: 6px; }
/* Every text-like type is listed, because a type that is missing here does not fall back to
   something close — it renders as a raw browser input with no border radius, no padding, a third
   of the width, and none of the focus treatment the rest of the page has. That is how the two
   download-link fields shipped looking broken. */
input[type=text], input[type=email], input[type=password], input[type=number], input[type=date],
input[type=url], input[type=tel], input[type=search], select {
  width: 100%; font-family: var(--font); font-size: 15px; color: var(--primary);
  background: #fff; border: 1px solid var(--neutral-200); border-radius: 10px; padding: 10px 12px;
  transition: border-color .2s ease, box-shadow .2s ease;
}
input:focus, select:focus {
  outline: none;
  border-color: rgba(var(--brand-rgb), .55);
  box-shadow: 0 0 0 3px rgba(var(--brand-rgb), .16);
}
/* ---- password reveal -------------------------------------------------------
   The wrapper and button are injected by console.js, so these rules do nothing until it runs —
   which is the point: with the script blocked the field is a plain password input, unchanged. */
.pw { position: relative; display: block; }
/* Room for the button, so a long password does not run underneath it. */
.pw input { padding-right: 44px; }
.pw-toggle {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: 8px; background: transparent; cursor: pointer;
  color: var(--neutral-500); transition: color .15s ease, background-color .15s ease;
}
.pw-toggle:hover { color: var(--primary); background: var(--neutral-100); }
.pw-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* Edge draws its own reveal control inside password inputs. Two eyes side by side, one of which
   does something slightly different, is worse than either alone. */
input[type=password]::-ms-reveal { display: none; }

.field { margin-bottom: 16px; }
.hint { font-size: 13px; color: var(--neutral-500); margin-top: 6px; }

/* ---- pills ---- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: 99px; padding: 3px 11px; font-size: 12.5px; font-weight: 600;
  background: var(--neutral-100); color: var(--neutral-700);
}
.pill-ok     { background: rgba(var(--brand-2-rgb), .14); color: #0b6f73; }
.pill-warn   { background: rgba(var(--brand-rgb), .16); color: var(--brand-deep); }
.pill-danger { background: #fef2f2; color: #b91c1c; }
.pill-mono   { font-family: var(--font-mono); letter-spacing: .06em; font-size: 12px; }

/* On the dark hero the same pills were dark ink on near-black — "3 of 25 seats in use" and
   "Active" were unreadable. The wash is opened up and the ink lightened to the tint of the same
   brand colour, so a pill still means the same thing on either surface. */
.dark-surface .pill        { background: rgba(255, 255, 255, .10); color: var(--neutral-200); }
.dark-surface .pill-ok     { background: rgba(var(--brand-2-rgb), .3); color: #a8f0f2; }
.dark-surface .pill-warn   { background: rgba(var(--brand-rgb), .3); color: #ffd2a8; }
.dark-surface .pill-danger { background: rgba(185, 28, 28, .34); color: #fecaca; }

/* ---- tables ---- */
table { width: 100%; border-collapse: collapse; }
th {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--neutral-500); text-align: left;
  padding: 10px 12px; border-bottom: 1px solid var(--neutral-200);
}
td { padding: 14px 12px; border-bottom: 1px solid var(--neutral-100); vertical-align: middle; }
tr:last-child td { border-bottom: 0; }
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---- layout pieces ---- */
.topbar { padding: 22px 0; border-bottom: 1px solid var(--neutral-200); }
.row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.spread { justify-content: space-between; }
.stack > * + * { margin-top: 24px; }
.muted { color: var(--neutral-500); }
.small { font-size: 13.5px; }
.mono { font-family: var(--font-mono); }

.notice { border-radius: 14px; padding: 14px 16px; font-size: 14.5px; border: 1px solid; }
.notice-ok    { background: rgba(var(--brand-2-rgb), .08); border-color: rgba(var(--brand-2-rgb), .3); color: #0b6f73; }
.notice-error { background: #fef2f2; border-color: #fecaca; color: #b91c1c; }
.notice-warn  { background: rgba(var(--brand-rgb), .08); border-color: rgba(var(--brand-rgb), .3); color: var(--brand-deep); }

/* The one moment a licence key is ever shown. Deliberately loud, because it cannot be shown again. */
.keybox {
  font-family: var(--font-mono); font-size: clamp(18px, 3vw, 26px); font-weight: 600;
  letter-spacing: .08em; padding: 18px 20px; border-radius: 14px;
  background: var(--neutral-950); color: #fff; word-break: break-all;
}

.icon { width: 1em; height: 1em; flex: 0 0 auto; }

/* Subtle only — fade and a small rise, nothing flashy. */
@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.rise { animation: rise .3s cubic-bezier(.2,.8,.2,1) both; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media (max-width: 768px) {
  .hide-sm { display: none; }
  .card { padding: 18px; border-radius: 18px; }
}

/* ---- email builder ---------------------------------------------------------
   Three columns: what you can add, what you have, and what the selected one does. Collapses to a
   single column early — this is a desktop tool, and pretending otherwise on a phone produces
   three unusable columns instead of one usable one. */
.builder {
  display: grid; grid-template-columns: 220px minmax(0, 1fr) 260px; gap: 20px; margin-top: 22px;
  align-items: start;
}
@media (max-width: 1100px) { .builder { grid-template-columns: 1fr; } }

.bpanel {
  background: #fff; border: 1px solid var(--neutral-200); border-radius: 18px; padding: 18px;
  position: sticky; top: 18px;
}
@media (max-width: 1100px) { .bpanel { position: static; } }

.palette { display: grid; gap: 8px; }
.pchip {
  display: flex; align-items: center; gap: 10px; width: 100%; cursor: grab;
  border: 1px solid var(--neutral-200); background: var(--neutral-50); border-radius: 12px;
  padding: 9px 12px; font-family: var(--font); font-size: 13.5px; font-weight: 500;
  color: var(--neutral-700); text-align: left; transition: all .18s ease;
}
.pchip:hover { border-color: rgba(var(--brand-rgb), .45); color: var(--primary); }
.pchip:active { cursor: grabbing; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  border: 1px solid var(--neutral-200); background: #fff; border-radius: 99px; cursor: pointer;
  padding: 4px 10px; font-family: var(--font-mono); font-size: 11.5px; color: var(--neutral-600);
}
.chip:hover { border-color: rgba(var(--brand-2-rgb), .5); color: var(--brand-2); }

.bcanvas { min-width: 0; }
.canvas {
  background: var(--neutral-100); border-radius: 18px; padding: 18px; min-height: 240px;
  border: 1px dashed var(--neutral-300);
}

/* One block on the canvas. The tools sit inside the row and appear on hover or focus, so the
   layout does not jump and a keyboard user can still reach them. */
.sk-row {
  position: relative; background: #fff; border: 1px solid transparent; border-radius: 12px;
  padding: 12px 14px; margin-bottom: 8px; cursor: pointer; transition: border-color .15s ease;
}
.sk-row:hover { border-color: var(--neutral-300); }
.sk-row.is-sel { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(var(--brand-rgb), .16); }
.sk-row.is-over { border-color: var(--brand-2); border-style: dashed; }
.sk-tools {
  position: absolute; top: 6px; right: 6px; display: flex; gap: 2px; opacity: 0;
  transition: opacity .15s ease;
}
.sk-row:hover .sk-tools, .sk-row:focus-within .sk-tools, .sk-row.is-sel .sk-tools { opacity: 1; }
.sk-tool {
  border: 0; background: var(--neutral-100); border-radius: 7px; padding: 4px; cursor: pointer;
  color: var(--neutral-600); display: inline-flex;
}
.sk-tool:hover { background: var(--neutral-200); color: var(--primary); }

/* Approximations of what each block becomes. Close enough to judge, never claimed to be exact —
   the Preview button renders the real thing. */
.sk-h { font-weight: 700; color: var(--primary); line-height: 1.3; }
.sk-p { font-size: 14px; line-height: 1.6; color: var(--neutral-700); white-space: pre-wrap; }
.sk-btn {
  display: inline-block; background: var(--brand); color: #fff; border-radius: 6px;
  padding: 8px 18px; font-size: 13.5px; font-weight: 600;
}
.sk-key {
  background: var(--neutral-50); border: 1px solid var(--neutral-200); border-radius: 8px;
  padding: 14px; text-align: center; font-family: var(--font-mono); font-size: 16px;
  letter-spacing: .12em; color: var(--primary); word-break: break-all;
}
.sk-notice {
  background: rgba(var(--brand-rgb), .08);
  border: 1px solid rgba(var(--brand-rgb), .28);
  border-radius: 8px; padding: 10px 12px; font-size: 13px; line-height: 1.55;
  color: var(--brand-deep); white-space: pre-wrap;
}
.sk-list { margin: 0; padding-left: 20px; font-size: 14px; line-height: 1.7; color: var(--neutral-700); }
.sk-img {
  display: inline-flex; align-items: center; justify-content: center; height: 90px;
  background: var(--neutral-100); border: 1px dashed var(--neutral-300); border-radius: 8px;
  color: var(--neutral-500); font-size: 12px; max-width: 100%;
}
.sk-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; font-size: 13.5px;
           line-height: 1.6; color: var(--neutral-700); white-space: pre-wrap; }
.sk-div { border-top: 1px solid var(--neutral-200); }
.sk-space { background: repeating-linear-gradient(45deg, var(--neutral-100) 0 6px, transparent 6px 12px);
            border-radius: 4px; }
.sk-foot { font-size: 12px; line-height: 1.6; color: var(--neutral-500); text-align: center;
           white-space: pre-wrap; }

/* Template cards on the list page. */
.tcard { display: block; text-decoration: none; color: inherit; transition: all .2s ease; }
.tcard:hover { border-color: rgba(var(--brand-rgb), .45); transform: translateY(-2px); }
.tcard-go { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px;
            font-size: 13.5px; font-weight: 600; color: var(--brand); }

/* Section navigation. Its own row under the top bar: beside the lockup it read as part of the
   logo and had nowhere to grow. The current section is underlined rather than filled — a solid
   pill here competes with the buttons that actually do things. */
.subnav { border-bottom: 1px solid var(--neutral-200); background: var(--neutral-50); }
.navlink {
  position: relative; display: inline-block;
  font-family: var(--font); font-size: 14px; font-weight: 500; color: var(--neutral-600);
  padding: 13px 14px; text-decoration: none; transition: color .18s ease;
}
.navlink:hover { color: var(--primary); text-decoration: none; }
.navlink.is-here { color: var(--primary); font-weight: 600; }
.navlink.is-here::after {
  content: ''; position: absolute; left: 14px; right: 14px; bottom: -1px; height: 2px;
  background: var(--brand); border-radius: 2px 2px 0 0;
}
@media (max-width: 480px) { .navlink { padding: 11px 10px; font-size: 13.5px; } }

/* ---- the public tour ------------------------------------------------------ */
.tour h2 { margin-top: 0; }

/* The viewer. A tab strip, one picture, and the sentence that explains it. The stage keeps a fixed
   aspect so switching views does not shift the page under the cursor — the commonest way a gallery
   like this feels broken. */
.viewer { margin-top: 26px; }
.viewer-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.vtab {
  border: 1px solid var(--neutral-200); background: #fff; border-radius: 99px; cursor: pointer;
  padding: 9px 18px; font-family: var(--font); font-size: 14px; font-weight: 500;
  color: var(--neutral-600); transition: all .18s ease;
}
.vtab:hover { border-color: var(--neutral-300); color: var(--primary); }
.vtab.is-on {
  background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600;
}
.vtab:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* The stage sizes to the picture rather than the picture to the stage. These screenshots range
   from a 2414x358 strip of grid rows to a 1840x1522 report — a fivefold difference in shape — so a
   fixed aspect either crops half of them or surrounds the rest with a void. The tab strip sits
   ABOVE the stage, so nothing the visitor is aiming at moves when the height changes. */
.viewer-stage {
  display: flex; align-items: center; justify-content: center; min-height: 240px; padding: 14px;
  background: var(--neutral-100); border: 1px solid var(--neutral-200); border-radius: 18px;
}
.viewer-stage img {
  display: block; width: auto; height: auto; max-width: 100%; max-height: 66vh;
  border-radius: 10px; background: #fff;
  box-shadow: 0 18px 44px -26px rgba(0,0,0,.45);
}

.viewer-say { margin-top: 18px; max-width: 66ch; }
.viewer-say h3 { font-size: 1.15rem; margin: 0; }
.viewer-say p { margin: 8px 0 0; color: var(--neutral-600); font-size: 15px; line-height: 1.65; }

.usps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin-top: 26px;
}
.usp {
  position: relative; background: #fff; border: 1px solid var(--neutral-200);
  border-radius: 18px; padding: 24px;
  animation: rise .34s cubic-bezier(.2,.8,.2,1) both;   /* delay is set per card, inline */
  transition: transform .22s cubic-bezier(.2,.8,.2,1), box-shadow .22s cubic-bezier(.2,.8,.2,1),
              border-color .22s cubic-bezier(.2,.8,.2,1);
}
.usp:hover {
  transform: translateY(-3px);
  border-color: rgba(var(--brand-rgb), .34);
  box-shadow: 0 18px 34px -24px rgba(0,0,0,.42);
}
.usp h3 { font-size: 1.02rem; margin: 0 0 8px; }
.usp p { margin: 0; color: var(--neutral-600); font-size: 14.5px; line-height: 1.65; }

/* ---- duotone icons ---------------------------------------------------------
   The app's own welcome-screen construction, ported: a filled silhouette at 28% under its own
   1.7px outline, both drawn in currentColor, with exactly one detail in motion. A composed frame
   rather than a flat tinted square — a soft wash anchored to one hue, a hairline ring, and a
   light catch, which is what stops an icon tile looking like a template.
   Colour is inherited, so `.duo-teal` is the only difference between the two variants. */
.duo {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 14px; margin-bottom: 16px;
  color: var(--brand-deep);                       /* 4.6:1 on white — safe for a glyph and for text */
  background: linear-gradient(180deg, rgba(var(--brand-rgb), .16), rgba(var(--brand-rgb), .03));
  box-shadow: inset 0 0 0 1px rgba(var(--brand-rgb), .20);
}
.duo::after {
  content: ''; position: absolute; inset: 1px 9px auto; height: 1px; border-radius: 1px;
  background: rgba(255,255,255,.75);
}
.duo-teal {
  color: var(--brand-2);
  background: linear-gradient(180deg, rgba(var(--brand-2-rgb), .16), rgba(var(--brand-2-rgb), .03));
  box-shadow: inset 0 0 0 1px rgba(var(--brand-2-rgb), .20);
}
.duo svg { display: block; width: 26px; height: 26px; }

/* Slow and small on purpose: this is decoration on a page somebody reads once, and the
   prefers-reduced-motion rule above stops every one of them dead. */
@keyframes duo-draw    { 0% { stroke-dashoffset: 1; } 55%, 100% { stroke-dashoffset: 0; } }
@keyframes duo-twinkle { 0%, 70%, 100% { opacity: 1; } 82% { opacity: .35; } }
@keyframes duo-slide   { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(1.4px); } }
@keyframes duo-ring    { 0%, 88%, 100% { transform: rotate(0deg); } 92% { transform: rotate(7deg); } 96% { transform: rotate(-5deg); } }
@keyframes duo-pulse   { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .7; transform: scale(.9); } }

/* pathLength="1" on the element makes the dash maths independent of the real path length. */
.duo-draw    { stroke-dasharray: 1; animation: duo-draw 3s cubic-bezier(.2,.8,.2,1) infinite; }
.duo-twinkle { animation: duo-twinkle 3.4s cubic-bezier(.2,.8,.2,1) infinite; }
.duo-slide   { animation: duo-slide 3.2s cubic-bezier(.2,.8,.2,1) infinite; }
.duo-ring    { animation: duo-ring 4.2s cubic-bezier(.2,.8,.2,1) infinite; transform-origin: 12px 5px; }
.duo-pulse   { animation: duo-pulse 3s cubic-bezier(.2,.8,.2,1) infinite; transform-origin: 17.2px 17.4px; }
/* The second half of a pair, offset so the two parts do not move as one block. */
.duo-late    { animation-delay: 420ms; }
