/* The toolkit theme — "Liquid" (docs/UI_GUIDELINES.md), dark only.
   One set of variables; components and services use these, never raw hex.

   Glass on a drifting violet/rose gradient. Honest about what it is: Apple
   documents Liquid Glass for its own platforms and there is no official CSS
   package for it, so this is a web approximation — frosted glass, one blur,
   over a field that moves. The gradient, the pointer highlight and the top
   bar's keep-awake are built in ./liquid.js; call mountLiquid() once at
   startup and the page gets all of them.

   Frost only, no refraction. The SVG displacement map this used to run
   (`backdrop-filter: url()`, ported from rdev/liquid-glass-react) measured
   at half the glass cost and, over a smooth gradient, bent nothing anyone
   could see. One filter, the same in every browser.

   Three things keep it from being soup:
   - Glass only where something genuinely floats. The page's own bands are
     flat, or it is glass on glass on glass and no hierarchy at all.
   - One blur radius and one edge treatment everywhere. Two grades of glass
     read as a mistake.
   - Type is opaque and high contrast. Translucent text on a moving gradient
     is unreadable. */
@import url("https://fonts.googleapis.com/css2?family=Figtree:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap");

:root {
  --mct-bg: #0a0812;
  --mct-surface: #14101f;
  /* Hairlines, not fills. Every rule on this page is drawn over glass or over
     a moving gradient, and a dark opaque line on either reads as a gap in the
     material rather than as an edge of it — so both are a little of the rim
     light the glass already carries. --soft is the console register's quieter
     grade: rows inside a band, where the band's own rule is the loud one. */
  --mct-border: color-mix(in srgb, #fff 10%, transparent);
  --mct-border-soft: color-mix(in srgb, #fff 6%, transparent);
  --mct-text: #f6f4fa;
  --mct-text-dim: #a49cba;
  /* the accent is platform-neutral on purpose: the toolkit's own actions must
     never look like one platform's actions */
  --mct-accent: #fb7185;
  --mct-on-accent: #2a0a12; /* text on accent fills — white fails contrast on rose */
  /* The ground moved but the semantic colours did not: the old green was
     picked against a near-black page, and on this violet one it read three
     ways — vivid as a dot, muddy mixed into an alert, olive on glass. One
     green, lifted until it survives being mixed down, and it is now the only
     green a tick, a switch, a "saved" or a success banner may use.
     Spotify keeps its own, because that one is a logo, not a state. */
  --mct-success: #34e17f;
  --mct-spotify: #1db954;
  --mct-warning: #ffc046;
  --mct-danger: #ff5470; /* errors as text — reads on the dark background */
  /* destructive actions. Deeper and more saturated than the rose accent on
     purpose, so the dangerous control is told apart from the ordinary one
     before the pointer ever reaches it. */
  --mct-destructive: #ff2d55;
  --mct-on-destructive: #2a0a12; /* the fill takes dark text, as accent does */
  /* Platform colors are reserved for explicit platform actions such as
     Connect. Passive identifiers stay neutral. */
  --mct-twitch: #9146ff;
  --mct-youtube: #ff4438;
  --mct-kick: #53fc18; /* fills need dark text (#0a2003) */
  /* the pinned top bar's height — what anything else sticking to the top of
     the viewport has to clear */
  --mct-topbar-h: 52px;
  /* Radius is a scale, not a value: a card is generous, a control is a pill,
     an inset well sits between them. The continuous corner is half of what
     this language is, which is why the old zero/16px rule is gone. */
  --mct-radius: 26px;
  --lq-r-control: 999px;
  --lq-r-well: 16px;
  /* One pixel, because every line here is rim light rather than a drawn
     border — a 2px rule on glass reads as a frame stuck onto the material. */
  --mct-border-w: 1px;
  --mct-gap: 20px;
  --mct-font-display: "Figtree", ui-sans-serif, sans-serif;
  --mct-font-sans: "Figtree", ui-sans-serif, system-ui, sans-serif;
  --mct-font-mono: "JetBrains Mono", ui-monospace, monospace;
  /* One curve for everything a pointer touches, so the whole app feels like
     one hand made it. */
  --mct-ease: cubic-bezier(.2, .8, .2, 1);

  /* The material, defined once. Glass costs the compositor real work and this
     app sits open for a whole broadcast, so every glass surface is listed by
     hand rather than applied broadly, and the count is the budget: panels,
     collapsibles, the console inspector, modals, the top bar. Controls are
     tinted instead. A sixth kind of glass surface is a decision, not a
     detail. */
  /* A milky veil, because a diffuser is not clear. This is what stops the
     colour behind a card arriving at full strength. */
  --lq-tint: color-mix(in srgb, var(--mct-text) 11%, transparent);
  --lq-tint-hi: color-mix(in srgb, var(--mct-text) 17%, transparent);
  /* Diffusing, not enhancing. Real frosted glass scatters light: it spreads
     it, takes a little colour out of it, and gives back slightly less than it
     received — so the filter stays under 100%, and the blur is what actually
     scatters. */
  --lq-frost: blur(20px) saturate(94%) brightness(.97);
  /* What a glass surface paints under its filter, and whether the pointer
     specular is drawn at all. Tokens, so the three ways glass goes away — no
     backdrop-filter support, prefers-reduced-transparency, low power mode —
     each set a few values instead of restating the selector list. */
  --lq-glass-bg: var(--lq-tint);
  --lq-specular: block;
  /* Top rim bright, bottom rim faint, and a soft dark under the top edge so
     the rim reads as a lit bevel rather than as a drawn line. */
  --lq-edge:
    inset 0 1px 0 color-mix(in srgb, #fff 38%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 8%, transparent),
    inset 0 6px 14px -8px color-mix(in srgb, #000 55%, transparent);
  --lq-cast: 0 18px 40px -18px color-mix(in srgb, #000 75%, transparent);
  /* where the specular sits before the pointer has ever moved */
  --lq-x: 50%;
  --lq-y: 30%;
  /* the chat dock's column. An aside stays an aside: the width is the
     component's, not the viewport's (UI_GUIDELINES). */
  --lq-dock-w: 340px;
  color-scheme: dark;
  scrollbar-color: color-mix(in srgb, var(--mct-text) 22%, transparent) transparent;
  scrollbar-width: thin;
}

/* The ground is on <html>; <body> is transparent so the gradient layers below
   it are what shows through every piece of glass. */
html { background: var(--mct-bg); }
body {
  margin: 0;
  background: transparent;
  color: var(--mct-text);
  font-family: var(--mct-font-sans);
  font-size: 15px;
  line-height: 1.6;
  letter-spacing: -.008em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* The gradient. Glass with nothing behind it is a grey rectangle, so this is
   the one part of the theme that cannot be allowed to fail — it is plain CSS,
   no canvas and no shader.

   It is the fallback, not the finished article: liquid.js draws the same
   field as one fragment shader, where the poles are round and their overlaps
   add as light. When that succeeds it sets `data-gl-ok` on <html> and these
   two switch off — left on, they would go on animating and compositing behind
   an opaque canvas nobody can see through, paid for on every frame for
   nothing. Everything that stops the shader (no WebGL, hardware acceleration
   off, a driver that will not compile it) simply leaves this in place.

   Two layers, not one. A single element carrying every pole can only be
   panned, and a pan moves the whole field together — it reads as a slide, not
   as a gradient that is changing. Two layers on different periods and
   opposite directions move the poles relative to each other, which is what
   makes the colours actually mix and separate.

   Transform and opacity only, on oversized fixed layers: GPU work, no
   repaint, no layout. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: -30%;
  z-index: -2;
  pointer-events: none;
  will-change: transform;
}
body::before {
  background:
    radial-gradient(34% 36% at 30% 66%, color-mix(in srgb, var(--mct-accent) 86%, var(--mct-bg)) 0%, transparent 72%),
    radial-gradient(32% 32% at 66% 24%, color-mix(in srgb, color-mix(in srgb, var(--mct-twitch), var(--mct-accent)) 74%, var(--mct-bg)) 0%, transparent 70%),
    var(--mct-bg);
  animation: lq-drift-a 44s ease-in-out infinite alternate;
}
body::after {
  background:
    radial-gradient(36% 34% at 74% 62%, color-mix(in srgb, var(--mct-twitch) 82%, transparent) 0%, transparent 74%),
    radial-gradient(30% 30% at 22% 28%, color-mix(in srgb, var(--mct-accent) 66%, transparent) 0%, transparent 68%);
  /* screen, so the second set of poles adds light to the first rather than
     painting over it */
  mix-blend-mode: screen;
  animation: lq-drift-b 59s ease-in-out infinite alternate;
}
/* The shader is up: the fallback goes away entirely. `display`, not opacity —
   a transparent layer still animates and still composites. */
[data-gl-ok] body::before,
[data-gl-ok] body::after {
  display: none;
}
/* Wide travel on a long clock. The range is what lets the poles cross the
   frame and pass each other; the duration is what keeps that from reading as
   animation. */
@keyframes lq-drift-a {
  0% { transform: translate3d(-9%, 6%, 0) scale(1.02); }
  50% { transform: translate3d(8%, -7%, 0) scale(1.12); }
  100% { transform: translate3d(-5%, -9%, 0) scale(1.05); }
}
@keyframes lq-drift-b {
  0% { transform: translate3d(10%, -7%, 0) scale(1.1); }
  50% { transform: translate3d(-8%, 9%, 0) scale(1.01); }
  100% { transform: translate3d(6%, 7%, 0) scale(1.08); }
}

/* --- the surfaces the browser draws ---------------------------------------
   Left alone they belong to no design at all, and they are the cheapest tell
   that a page was assembled rather than built. */
::selection { background: var(--mct-accent); color: var(--mct-on-accent); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--mct-text) 18%, transparent);
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--mct-text) 30%, transparent);
  background-clip: content-box;
}
/* a link's underline should clear the descenders it crosses */
a, .mct-link { text-underline-offset: .18em; text-decoration-thickness: 1px; }
/* Headings break where the sense breaks, not where the box ends; body text
   never leaves one word alone on the last line. */
h1, h2, h3, h4, .mct-panel > header, .mct-group > h3, .mct-console-head h2 { text-wrap: balance; }
p, .mct-dim { text-wrap: pretty; }
/* Numbers that change in place must not shift the characters beside them: a
   counter ticking from 12,408 to 12,409 should move one glyph, not the row. */
.mct-stat .value,
.mct-table td,
.mct-log { font-variant-numeric: tabular-nums; }

/* --- the glass ------------------------------------------------------------
   One definition, applied to everything that floats.

   The last selector is Clerk's plan card, which floats like any other card
   you pick up. Everything else about that page is told to Clerk in
   clerkLook() rather than drawn over it, but a material is not a colour
   variable, so this one thing is CSS. Three classes deep on purpose: Clerk
   injects its own stylesheet after ours and its card rule carries two
   classes, so a rule that merely ties on specificity loses. */
.mct-panel,
.mct-collapse,
.mct-console-panel,
.mct-modal,
.mct-perf-pop,
.mct-topbar,
.mct-plan.mct-plan .cl-pricingTableCard,
.mct-clerk-card.mct-clerk-card {
  background: var(--lq-glass-bg);
  -webkit-backdrop-filter: var(--lq-frost);
  backdrop-filter: var(--lq-frost);
  border: 0;
  border-radius: var(--mct-radius);
  box-shadow: var(--lq-edge), var(--lq-cast);
}
/* The class is written twice on purpose. Clerk hands these surfaces our class
   AND keeps its own (`.cl-internal-xxx`), and it injects its stylesheet after
   ours — a single class ties and loses. Doubling costs one selector and,
   unlike naming Clerk's class, survives the next time Clerk renames it.

   Clerk's popovers and drawers are portaled to <body>, so none of them is
   inside .mct-console and none of the console-scoped rules above reaches
   them; these need to stand on their own. */
.mct-clerk-card.mct-clerk-card {
  /* Clerk sizes and places these itself. All that changes hands is the
     material — so no width, no padding, and the radius it already scales
     from --lq-r-well stays whatever it made of it. */
  border-radius: var(--mct-radius);
}
/* What a floated Clerk surface sits on. Ours is rgba because ::backdrop
   cannot see custom properties; this one is a real element, so it can. */
.mct-clerk-scrim.mct-clerk-scrim {
  background: color-mix(in srgb, #09060e 70%, transparent);
}
/* The boxes Clerk stacks inside that surface. Glass shows every edge behind
   it, so a stack that reads as one panel while opaque reads as three while
   transparent: this is the flattening. All doubled for the reason above. */
.mct-clerk-bare.mct-clerk-bare {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
}
/* ...except the one that does the clipping, which has to agree with the glass
   about where the corner is — Clerk gives it 32px against the wrapper's 26px,
   and two arcs six pixels apart is the double edge you see on the corner. */
.mct-clerk-clip.mct-clerk-clip {
  background: transparent;
  border-radius: var(--mct-radius);
  box-shadow: none;
}
/* The rail, divided from the page beside it by a line rather than by a panel
   stacked over its edge. On the rail and not on the scroll area: a rail is
   only ever rendered where there IS one, and the seam should not follow a
   scroll area into a drawer that has no rail to divide. */
.mct-clerk-rail.mct-clerk-rail {
  background: transparent;
  border-right: var(--mct-border-w) solid var(--mct-border);
  box-shadow: none;
}
/* Clerk pads its page 32 left and 24 right. Even on its own flat card that is
   a wonky box; on glass, where the edge is visible, the short side reads as
   the content sliding off it. */
.mct-clerk-pad.mct-clerk-pad {
  padding: 28px 32px;
}
/* The specular: a wide, soft hotspot placed by the pointer (liquid.js writes
   --lq-x/--lq-y), clipped to the surface's own shape and sitting under the
   content rather than over it. Only the two surfaces that own their stacking
   context — a <dialog> and a sticky bar must keep the position the browser
   gave them, and neither is a surface a pointer rests on.

   ONE light, not one per card. `background-attachment: fixed` measures the
   gradient against the viewport instead of against each element's own box, so
   every surface on the page shows the part of a single hotspot that falls on
   it — a card near the pointer is bright at the near corner, a card across
   the page is barely lit at all. Sized and placed on the same gradient
   whatever the card is: without this every card had its own full copy of the
   highlight in the same relative spot, which is the tell that there is no
   light source at all, only a texture. */
.mct-panel,
.mct-collapse {
  position: relative;
  isolation: isolate;
}
.mct-panel::after,
.mct-collapse::after {
  content: "";
  display: var(--lq-specular);
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background-attachment: fixed;
  /* Viewport units, because percentages here would resolve against the
     viewport too and read as if they still meant the card. */
  background-image: radial-gradient(
    64vw 58vh at var(--lq-x) var(--lq-y),
    color-mix(in srgb, #fff 8%, transparent) 0%,
    transparent 64%
  );
}
/* Blur is expensive to composite and unwelcome to some people. Every one of
   these keeps the layout and the radius and simply stops being translucent:
   an opaque surface, no filter, no specular. Low power mode (liquid.js,
   `data-perf="low"` on <html>) is two of the same tokens as a switch, plus
   reduced motion — see the end of the file. */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --lq-glass-bg: var(--mct-surface);
    --lq-frost: none;
    --lq-specular: none;
  }
}
/* Low power keeps the glass translucent over the frozen gradient, it just
   stops blurring it. Denser than the live tint, because without the blur
   the tint alone barely separates a card from the ground; opaque cards were
   the first cut and read as black slabs. Reduced transparency above stays
   opaque — that one is a request for exactly that. */
:root[data-perf="low"] {
  --lq-glass-bg: color-mix(in srgb, var(--mct-surface) 30%, var(--lq-tint));
  --lq-frost: none;
  --lq-specular: none;
}
@supports not (backdrop-filter: blur(1px)) {
  :root { --lq-glass-bg: var(--mct-surface); }
}

.mct-sr-only {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* --- shared component classes (used by src/index.tsx) ---------------------
   Controls are pills in the same material as the surfaces they sit on, with
   the same rim: a control here is a smaller piece of the same glass, never a
   different one. No backdrop-filter of their own, though — a button almost
   always sits on a panel that has already blurred the backdrop, so its own
   filter would re-blur an already-blurred result, dozens of times per frame,
   for no visible gain. A stronger tint plus the same lit rim gets there free.

   Height is set, not inferred. Padding plus line-height leaves every button at
   the mercy of its own font metrics, so a row of them comes out a pixel or two
   apart and looks like a mistake — which it is. One height per size tier,
   centred by flex, and the padding only decides the width. */
.mct-btn {
  --lq-h: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--lq-h);
  box-sizing: border-box;
  font-family: var(--mct-font-sans);
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  color: var(--mct-text);
  background: var(--lq-tint-hi);
  border: 0;
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  padding: 0 22px;
  cursor: pointer;
  /* background-color is in here for the segmented control: the fill moving to
     another option cross-fades instead of jumping. The focus ring arrives
     rather than appearing, which is why outline-offset is in the list. */
  transition-property: transform, box-shadow, border-color, background-color,
    color, outline-offset;
  transition-duration: 0.18s;
  transition-timing-function: var(--mct-ease);
}
/* The two attribute selectors are doing real work: this rule and the accent
   fill for a chosen option weigh the same, so without them, pointing at the
   segment that was already selected replaced its accent with a faint grey. */
.mct-btn:hover:not(:disabled, .primary, .twitch, .youtube, .kick, .spotify,
                   [aria-pressed="true"], [aria-current="page"]) {
  background: color-mix(in srgb, var(--mct-text) 21%, transparent);
}
/* Glass compresses. A press that only changes colour is a button; a press
   that gives is a material. */
.mct-btn:active:not(:disabled) {
  transform: scale(0.97);
}
.mct-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* Filled buttons name their fill once, in --mct-fill, so the hover rule can
   re-assert the border the generic hover would otherwise dim to grey. */
.mct-btn.primary { --mct-fill: var(--mct-accent); color: var(--mct-on-accent); }
.mct-btn.twitch { --mct-fill: var(--mct-twitch); color: #fff; }
.mct-btn.youtube { --mct-fill: var(--mct-youtube); color: #fff; }
.mct-btn.kick { --mct-fill: var(--mct-kick); color: #0a2003; }
/* Spotify's green is a logo, not a state, so it keeps its own rather than
   following --mct-success wherever that token goes. */
.mct-btn.spotify { --mct-fill: var(--mct-spotify); color: #06210f; }
/* The filled buttons are glass too, not solid paint: a heavy tint of their own
   colour over a dark anchor, the same lit rim, and their colour thrown onto
   whatever is underneath. The tint is high because these are the loudest
   control on the page and have to stay clearly ahead of both the neutral glass
   and the danger glass; the dark anchor is what keeps their dark label
   readable whichever part of the gradient they happen to sit over.
   One colour rather than a gradient over an underlay: only background-color
   animates, so a two-layer version flashed grey on the way into hover. */
.mct-btn.primary,
.mct-btn.twitch,
.mct-btn.youtube,
.mct-btn.kick,
.mct-btn.spotify {
  border: 0;
  background-color:
    color-mix(in srgb, color-mix(in srgb, var(--mct-fill) 98%, #000) 92%, transparent);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 10%, transparent),
    0 10px 26px -12px var(--mct-fill);
}
.mct-btn.primary:hover:not(:disabled),
.mct-btn.twitch:hover:not(:disabled),
.mct-btn.youtube:hover:not(:disabled),
.mct-btn.kick:hover:not(:disabled),
.mct-btn.spotify:hover:not(:disabled) {
  background-color: var(--mct-fill);
  filter: brightness(1.04);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 48%, transparent),
    0 14px 32px -10px var(--mct-fill);
}
/* Destructive, in the same material as everything else: a piece of glass that
   happens to be tinted red. It escalates under the pointer rather than sitting
   there as a permanent red block — it just escalates from tinted glass to
   solid now, instead of from an outline to a fill.
   The button is red; the label is not. Red-on-red was about 2.6:1 — the colour
   that makes it recognisable as destructive was also the colour making it hard
   to read. The fill keeps the red, deep and anchored dark so a bright bubble
   behind it cannot wash the label out, and the label is a white carrying just
   enough of the hue to belong to it. Hover then flips it: bright fill, dark
   label. */
.mct-btn.danger {
  background-color:
    color-mix(in srgb, color-mix(in srgb, var(--mct-destructive) 85%, #000) 73%, transparent);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 34%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 16%, transparent),
    0 8px 22px -14px var(--mct-destructive);
  color: color-mix(in srgb, var(--mct-destructive) 16%, #fff);
}
.mct-btn.danger:hover:not(:disabled) {
  background-color: var(--mct-destructive);
  color: var(--mct-on-destructive);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 42%, transparent),
    0 10px 26px -12px var(--mct-destructive);
}
/* Connecting an account is that platform's action, so the button wears that
   platform's color (declared with the other fills above) — the toolkit's own
   accent never stands in for one. Kick and Spotify need dark text.
   An anchor that acts as a button: connecting leaves the page. Stated at
   element+class strength because a bare .mct-btn cannot reach it, and without
   this the connect buttons never become flex containers — once the height
   moved out of the padding, their labels sat at the top left. */
a.mct-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

/* One size down, for a button sitting inside a sentence or a row rather than
   among other buttons ("Disconnect", "unblock"). Same chrome, field-sized.
   One up, for the landing's calls to action. */
.mct-btn.small {
  --lq-h: 32px;
  font-size: 13px;
  padding: 0 15px;
}
.mct-btn.big {
  --lq-h: 52px;
  font-size: 16px;
  padding: 0 30px;
}
.mct-btn:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
}

/* Fields. A field is the inverse of a key: cut into the glass, so it takes the
   dark inner shadow and gives the rim back. */
.mct-select,
.mct-input {
  font-family: var(--mct-font-sans);
  font-size: 15px;
  color: var(--mct-text);
  background: color-mix(in srgb, #000 26%, transparent);
  border: 0;
  border-radius: var(--lq-r-well);
  box-shadow:
    inset 0 2px 6px -2px color-mix(in srgb, #000 70%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 14%, transparent);
  caret-color: var(--mct-accent);
  transition-property: transform, box-shadow, border-color, background-color,
    color, outline-offset;
  transition-duration: 0.18s;
  transition-timing-function: var(--mct-ease);
  /* Padding in em, not px: a field's breathing room is a property of its
     text, so a field set larger (or a service that scales its type) keeps
     the same proportions instead of a 13px gap around 20px words. min-height
     rather than height — the box may grow for a second line, never shrink
     below a comfortable target. */
  padding: 0.35em 0.65em;
  min-height: 2.2em;
  box-sizing: border-box;
  /* a field sized in characters (`size=4` for a prefix, `size=26` for a
     channel name) must still fit a phone column */
  max-width: 100%;
}
/* The browser's spin buttons eat a third of a compact numeric field and the
   value clips under them ("100" reading as "10"). Keyboard and wheel still
   step without the chrome. One rule per engine, separate selectors: an
   unknown pseudo-element would void a shared list. */
.mct-input[type="number"]::-webkit-inner-spin-button {
  appearance: none;
  margin: 0;
}
.mct-input[type="number"]::-webkit-outer-spin-button {
  appearance: none;
  margin: 0;
}
.mct-input[type="number"] {
  -moz-appearance: textfield;
}
/* Under a label, a field is on its own line — the label names it, the field
   sits below. Stated here rather than falling out of a width: fields in a bar
   or a flex row are not direct children of a label, so they still flow
   inline. */
label > .mct-input,
label > .mct-select {
  display: block;
  margin-top: 4px;
}
.mct-select {
  cursor: pointer;
}
/* The native dropdown list paints its own surface: some browsers give it a
   light background regardless of color-scheme, turning the inherited light
   text white-on-white. Options declare their colors explicitly. */
option {
  background: var(--mct-surface);
  color: var(--mct-text);
}
/* Fills its grid cell / form row instead of the browser's default 20-ish
   characters — the common case in a settings form. Up to a measure, though:
   a full-bleed console hands a row 1600px, and a field is as wide as what
   goes in it, not as wide as the window. A reward name is a few words; a
   cost is three digits and has no business being 500px of empty box. */
.mct-select.wide,
.mct-input.wide {
  /* block, not the default inline-block: a `.wide` field is the one on its
     own line under a label, and it used to get there only because width:100%
     could not fit beside the words. With a max-width it fits, and the layout
     must not depend on that accident. */
  display: block;
  width: 100%;
  max-width: 48ch;
}
.mct-input[type="number"].wide {
  max-width: 12ch;
}
/* Sliders keep the browser's own track and thumb — nothing hand-built beats
   them for touch and keyboard — dressed in the theme's accent. The browser
   ships them with a horizontal margin of its own, which a width of 100% then
   pushes past the edge of the column: the right end of the last slider in a
   row gets clipped. Width and margin are stated here so no caller has to. */
input[type="range"] {
  accent-color: var(--mct-accent);
  display: block;
  box-sizing: border-box;
  width: 100%;
  margin: 6px 0 0;
}
/* The line under a field that says what it does — one sentence, plain
   language, never wider than the measure it explains. Any <small> inside a
   label is that line, wherever it sits relative to the control. */
label small {
  color: var(--mct-text-dim);
  display: block;
  font-size: 11px;
  line-height: 1.45;
  margin-top: 4px;
  max-width: 48ch;
}
/* No text to pad — 2px of surface is all that keeps the swatch off its own
   border. The height comes from the shared min-height, so a colour field
   lines up with the text fields beside it in a row. */
.mct-input[type="color"] {
  padding: 2px;
}
/* The swatch fills the field. Browsers inset it with their own padding and
   draw a grey border round it, which reads as a colour sample sitting in a
   box rather than a field that IS the colour. One rule per engine: an
   unknown pseudo-element would void a shared selector list. */
.mct-input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}
.mct-input[type="color"]::-webkit-color-swatch {
  border: 0;
  border-radius: calc(var(--lq-r-well) - 2px);
}
.mct-input[type="color"]::-moz-color-swatch {
  border: 0;
  border-radius: calc(var(--lq-r-well) - 2px);
}
/* :not(:disabled), like the buttons: fields in a disabled fieldset are
   :disabled, and a greyed-out section that still lights up under the pointer
   reads as editable. */
.mct-select:hover:not(:disabled),
.mct-input:hover:not(:disabled) {
  background: color-mix(in srgb, #000 34%, transparent);
}
.mct-select:disabled,
.mct-input:disabled {
  cursor: not-allowed;
}
.mct-select:focus-visible,
.mct-input:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
}
.mct-input::placeholder {
  color: var(--mct-text-dim);
  opacity: 1;
}
textarea {
  caret-color: var(--mct-accent);
}

/* A button that reads as a link — a secondary action inside a bar, where a
   full button would shout. Links underline on hover only. */
.mct-link {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--mct-font-sans);
  font-size: 13px;
  color: var(--mct-accent);
  cursor: pointer;
  transition-timing-function: var(--mct-ease);
}
.mct-link:hover {
  text-decoration: underline;
}
.mct-link:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}

/* Secondary text: labels, captions, the line under a control. The only text
   size below body, so services never pick their own. */
.mct-dim {
  color: var(--mct-text-dim);
  font-size: 14px;
}

/* Inline alerts — a slab washed in the status colour with the same lit rim,
   but no filter of its own: it is already an opaque wash, so diffusing what is
   behind it would change nothing anyone can see, and there are usually several
   on a page. Danger by default (broken), .warning for "works, but not for
   long".
   52%, not 30%: at 30% over a surface this dark an amber warning came out as a
   brown slab and a green "saved" as a slab merely less dark than the panel,
   which is the opposite of what a notice is for. 52% is as far as this can go
   while a near-white label still clears 4.5:1 on the lightest of the three. */
.mct-alert {
  --lq-notice: var(--mct-danger);
  border: 0;
  border-radius: var(--lq-r-well);
  background: color-mix(in srgb, var(--lq-notice) 52%, var(--mct-surface));
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, var(--lq-notice) 55%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 18%, transparent);
  color: var(--mct-text);
  font-size: 14px;
  padding: 13px 17px;
}
/* With an × on it: the sentence takes the room it needs and the button sits
   at the top right of it, pulled back into the padding so putting a notice
   away never made the notice taller. */
.mct-alert:has(> .mct-iconbtn) {
  align-items: start;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}
.mct-alert > .mct-iconbtn {
  /* not the dim grey it wears on a panel's chrome: that colour was picked
     against the page, and on a notice's wash it is the one thing here nobody
     can see */
  color: color-mix(in srgb, var(--mct-text) 78%, transparent);
  flex: none;
  font-size: 18px;
  line-height: 1;
  margin: -4px -6px -4px 0;
}
.mct-alert > .mct-iconbtn:hover {
  background: color-mix(in srgb, #000 22%, transparent);
  color: var(--mct-text);
}
.mct-alert.warning {
  --lq-notice: var(--mct-warning);
}
.mct-alert.success {
  --lq-notice: var(--mct-success);
}

/* The card a service's panel renders inside — the one place cards are still
   the layout, because a dashboard panel really is a separate object you can
   pick up and put down. Its glass is declared with the other floating
   surfaces at the top; what is here is only how it is built. */
.mct-panel {
  /* Panel internals respond to the width the panel was given. A four-column
     desktop grid can make a panel phone-narrow even on a very wide viewport,
     so viewport media queries cannot protect its horizontal controls. */
  container-type: inline-size;
  overflow: hidden;
}
.mct-panel > header {
  display: flex;
  align-items: center;
  gap: 10px;
  /* The section's top border plus this header is one 40px board cell. */
  flex: 0 0 calc(40px - var(--mct-border-w));
  flex-wrap: nowrap;
  box-sizing: border-box;
  height: calc(40px - var(--mct-border-w));
  min-height: calc(40px - var(--mct-border-w));
  padding: 5px 18px;
  border-bottom: var(--mct-border-w) solid var(--mct-border);
  font-family: var(--mct-font-display);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.02em;
}
/* A nudge about the panel's own state — "set up →". The header is display/700,
   which a small pointer must not borrow, or it reads as a second title. */
.mct-panel > header .hint {
  font-family: var(--mct-font-sans);
  font-weight: 400;
  font-size: 13px;
}
/* Flex, not inline. These two hold things that are not text — the warning
   mark, the status dot — and as inline boxes they hung their contents off the
   text baseline of their own font size, which put the 15px triangle almost
   4px above the middle of a 40px header while everything around it was
   centred. A flex box has no baseline to hang from. */
.mct-panel > header .hint,
.mct-panel > header .status {
  display: inline-flex;
  align-items: center;
}
/* The warning mark: what is wrong, reduced to a glyph beside the title, with
   the sentence itself a hover away. `cursor: help` and the warning colour are
   the whole affordance — a compact panel has no room to explain that it can
   be hovered, and a mark in that colour is already the convention. */
.mct-panelwarn {
  display: inline-flex;
  align-items: center;
  color: var(--mct-warning);
  cursor: help;
  /* not positioned on purpose: the tip below measures itself against the
     panel, not against this 15px glyph */
  position: static;
}
.mct-panelwarn:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
  border-radius: 3px;
}
/* Pinned to the panel's own edges rather than to the mark, so the sentence is
   the same slab the body used to carry and can never be clipped sideways by
   the panel's overflow. It hangs just under the header, where the banner was.

   Opacity and not `visibility`/`display`: an invisible element is gone from
   the accessibility tree, and the one sentence saying why the panel looks
   idle is the last thing that should be. */
.mct-panel > header .hint .mct-panelwarn > .tip {
  position: absolute;
  top: calc(40px + 8px);
  left: 14px;
  right: 14px;
  z-index: 3;
  padding: 11px 15px;
  border-radius: var(--lq-r-well);
  background: color-mix(in srgb, var(--mct-warning) 52%, var(--mct-surface));
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, var(--mct-warning) 55%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 18%, transparent),
    var(--lq-cast);
  color: var(--mct-text);
  font-family: var(--mct-font-sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -.008em;
  text-align: left;
  opacity: 0;
  pointer-events: none;
  transition: opacity 140ms var(--mct-ease);
}
.mct-panel > header .hint .mct-panelwarn:hover > .tip,
.mct-panel > header .hint .mct-panelwarn:focus-visible > .tip {
  opacity: 1;
}
.mct-panel > header .status {
  margin-left: auto;
}
/* the switch is the panel's own, so it sits past everything the service put
   in the header — and `auto` here covers the case where there is no status */
.mct-panel > header .control {
  margin-left: auto;
  display: inline-flex;
  gap: 2px;
}
.mct-panel > header .status + .control {
  margin-left: 0;
}
.mct-panel > .body {
  padding: 18px;
}
.mct-panel.header-only > header {
  border-bottom: 0;
  flex-basis: calc(40px - var(--mct-border-w) - var(--mct-border-w));
  height: calc(40px - var(--mct-border-w) - var(--mct-border-w));
  min-height: calc(40px - var(--mct-border-w) - var(--mct-border-w));
}
/* Switched off — or closed by the plan. Still on the page, still yours to
   switch back on, but plainly not running: the glass goes, so the panel stops
   being an object on the page, and the title dims. The switch does not,
   because it is the one thing here you still want to press.

   What stays is a flat grey film and the outline. Not glass — no blur, no lit
   rim, nothing that reads as a surface with depth — but not nothing either:
   transparent left the panel as loose text lying on the wallpaper, with
   nothing to say where it begins or that it is the same kind of thing as the
   panel beside it. A few percent of the text colour is enough to read as a
   card that has been turned down, and the hairline ring is drawn inset so it
   costs no layout and follows the same radius. */
.mct-panel.off {
  background: color-mix(in srgb, var(--mct-text) 6%, transparent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: inset 0 0 0 var(--mct-border-w) var(--mct-border);
}
.mct-panel.off::after {
  display: none;
}
.mct-panel.off > header {
  border-bottom: 0;
}
.mct-panel.off > header .title {
  color: var(--mct-text-dim);
}

/* Something typed verbatim inside a sentence: a command, a logged action.
   0.92em rather than a fixed size, so it shrinks with whatever it sits in —
   a console table's 12px row and a panel's 15px prose both get it right. */
.mct-code {
  font-family: var(--mct-font-mono);
  font-size: 0.92em;
  color: var(--mct-text);
}

/* A title that is also a link — a panel naming the service it opens. Takes
   the heading's colour and underlines only on hover, which is a CSS job and
   not two React event handlers mutating style. */
.mct-titlelink {
  color: inherit;
  text-decoration: none;
}
.mct-titlelink:hover {
  text-decoration: underline;
}
.mct-titlelink:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}

/* A name on a platform wears the platform's colour. Mono because the
   identifier gets typed and read out. */
.mct-handle {
  color: var(--mct-text);
  font-family: var(--mct-font-mono);
  font-size: 0.92em;
}
.mct-handle.twitch {
  color: var(--mct-twitch);
}
.mct-handle.kick {
  color: var(--mct-kick);
}
.mct-handle.youtube {
  color: var(--mct-youtube);
}
/* PlatformMark: the platform's logo in the platform's colour, sitting on the
   text's line rather than on its baseline — a logo has no descender. */
.mct-platmark {
  flex: none;
  vertical-align: -0.15em;
}
.mct-platmark.twitch {
  color: var(--mct-twitch);
}
.mct-platmark.kick {
  color: var(--mct-kick);
}
/* Spotify's own green, not the theme's: a handle wears the platform's colour,
   and that green is a logo rather than a state — the same reason the connect
   button keeps it. */
.mct-handle.spotify {
  color: var(--mct-spotify);
}

/* A value you are meant to copy, not read: the field carries it, the button
   takes it. Never bare text you have to select by hand. */
.mct-copy {
  display: flex;
  gap: 8px;
  align-items: center;
}
.mct-copy .mct-input {
  flex: 1;
  min-width: 0;
  font-family: var(--mct-font-mono);
  font-size: 12px;
}

/* The shell's top bar — the same on the dashboard and on a service's own
   site, so signing in and switching account never move. */
/* Pinned: who you are and the way home are true on every scroll position, and
   on a console page long enough to lose the top of, a bar you have to scroll
   back for is a bar you stop using. Sticky, not fixed — it keeps its place in
   the flow, so nothing below needs a matching offset to avoid it. */
/* Square and flush, not a floating card: the bar is the page's own band, and
   glass with a radius at the top of the viewport reads as a card that has got
   stuck there. One lit rule along the bottom in place of the cast. */
.mct-topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 18px;
  border-radius: 0;
  box-shadow: inset 0 -1px 0 var(--mct-border);
  position: sticky;
  top: 0;
  z-index: 20;
  /* The bar must never be left holding a stale backdrop. Chrome snapshots the
     backdrop of this sticky, filtered bar, and on an idle page it can leave a
     horizontal slice of that snapshot empty — the bar then draws its tint over
     nothing and the band stays there until something makes it draw again.
     Measured off three screenshots of it: the band is exactly --lq-tint over
     --mct-bg, to within two levels.

     A moving page hides it, which is the whole reason it looked like a logo
     bug: whatever was repainting kept the snapshot fresh. Nothing else cured
     it — not dropping the refraction, not a compositing layer on the bar
     (that made the empty slice taller), not paint containment on what was
     repainting, not moving the filter onto a child of the bar. Only two
     things did: taking the filter away, and repainting. So the bar repaints:
     liquid.js flips `data-awake` on it twice a second, and the two tints are
     0.4% apart, about a fifth of one 8-bit level, so there is nothing to see.

     A timer, never a CSS animation. The animation this used to be ticked at
     the display's rate, and every tick re-ran this bar's blur across the full
     window width: measured at 62% of the theme's whole GPU cost, and it kept
     going behind OBS after the shader loop had stopped. A stepped animation
     is no better — Chrome keeps ticking a running animation whether or not
     its value changes. */
}
/* ponytail: one 52px bar repaints twice a second forever. Delete it the day
   Chrome stops dropping the slice — the test is to hover the logo, hold the
   mouse still, and watch the top of the page for a pale band. */
.mct-topbar[data-awake] {
  /* relative to whatever the bar is painting, so an opaque bar (reduced
     transparency, low power) also flips between two colours nobody can tell
     apart */
  background-color: color-mix(in srgb, var(--lq-glass-bg), var(--mct-text) 0.4%);
}
.mct-topbar .brand {
  font-family: var(--mct-font-display);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--mct-text);
  margin: 0;
}
.mct-topbar .brand-with-icon {
  display: flex;
  align-items: center;
  gap: 7px;
}
.mct-topbar .brand-icon {
  display: block;
  width: 42px;
  height: 42px;
  object-fit: contain;
  flex: none;
}
.mct-dashboard .mct-topbar {
  padding-top: 5px;
  padding-bottom: 5px;
}
.mct-topbar .brand a {
  color: inherit;
  text-decoration: none;
}
.mct-topbar .brand a:hover {
  text-decoration: underline;
}
.mct-topbar .brand .sep {
  color: var(--mct-text-dim);
}
.mct-topbar .right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* On a phone the bar wraps to two rows — name, then navigation — and two rows
   of desktop padding is a sixth of the screen spent on furniture before any
   content. Tighter, and the name shrinks so "MyCreatorToolkit — Requeue" keeps
   to one line on a 360px screen rather than becoming a third row. */
@media (max-width: 640px) {
  .mct-topbar {
    gap: 8px 10px;
    padding: 8px 12px;
  }
  .mct-topbar .brand {
    font-size: 16px;
  }
  /* The tabs are the navigation: they take the row, the avatar rides at its
     end. More tabs than fit scroll sideways instead of stacking — a wrapped
     pill loses the one-of-these-is-current shape that makes it readable. */
  .mct-topbar .mct-segmented {
    /* shrink, never stretch: a pill widened to the screen is mostly empty pill.
       It gives way when the row is tight and scrolls inside instead. */
    flex: 0 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .mct-topbar .mct-segmented::-webkit-scrollbar {
    display: none;
  }
  .mct-topbar .mct-segmented .mct-btn {
    flex: none;  /* scroll the row rather than squeeze the words in it */
  }
  .mct-topbar .right {
    flex: none;
  }
}

/* A wide column with a narrower one beside it. 380px fits a two-field row
   with a line of explanation under each, so the aside can hold short forms
   and not only lists. */
.mct-columns {
  display: grid;
  gap: var(--mct-gap);
  align-items: start;
}
.mct-columns > .main,
.mct-columns > aside {
  align-content: start;
  display: grid;
  gap: var(--mct-gap);
  min-width: 0;
}
/* Stacked, the aside leads: the rules you came to change are worth more of
   the first screen than the wiring you set up once and forget. */
.mct-columns > aside {
  order: -1;
}
@media (min-width: 1024px) {
  .mct-columns {
    grid-template-columns: minmax(0, 1fr) 380px;
  }
  .mct-columns > aside {
    order: 0;
  }
}
/* Wide enough for a third: the aside stops being a column and its groups
   become columns themselves — Requests beside People, each with room to
   explain itself, instead of one queueing under the other. `display:
   contents` costs the <aside> its landmark, which is a fair trade for a
   layout rule that needs no second component and no props. */
@media (min-width: 1560px) {
  .mct-columns {
    grid-template-columns: minmax(0, 1fr) 380px 380px;
  }
  .mct-columns > aside {
    display: contents;
  }
}

/* Fluid columns: as many as fit at 320px or wider, one on a phone. The
   dashboard's PanelGrid and a setup page's groups are the same layout, so
   the rule lives once. */
.mct-grid {
  display: grid;
  /* auto-fill, not auto-fit: a lone panel keeps its standard width instead of
     stretching the full width of a wide screen. `min()` lets that preferred
     320px floor give way when phone padding leaves a narrower content area,
     rather than making the entire panel hang off the viewport. */
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: var(--mct-gap);
}

/* The dashboard's board: the same fluid columns as .mct-grid, but each panel
   is an object — pick it up by its header and place it on the square grid. The
   column template lives in a style attribute because the component counts
   the columns (a span must clamp to what actually fits); everything visual
   lives here. */
.mct-board {
  display: grid;
  /* no grid gap: the cells are ~40px in both axes, and a gap between every
     one would be all gap — the gutter between panels is each panel's own
     half-gutter margin instead. The negative margin hands the page edge
     back, so the board sits where the old gapped grid sat. */
  margin: calc(var(--mct-gap) / -2);
  /* The board is a grid item of the console's main, and its columns are a
     fixed number of fixed cells — so its automatic minimum size is however
     wide it currently is. Left at `auto` the board cannot shrink: narrowing
     the window leaves it standing at its old width, the width it measures
     itself at stays the old one, the column count never drops, and the
     panels on the right sit outside the window until a reload measures the
     board while it is still empty. It measures what it is given. */
  min-width: 0;
}
.mct-boarditem {
  position: relative;
  min-width: 0;
  margin: calc(var(--mct-gap) / 2);
  /* The panel's natural height chooses a whole-row span. The panel then
     fills that span, so no panel border stops partway through a grid row. */
  align-self: start;
}
/* The declared height fills the measured whole-row span. Content may still
   grow the panel and its occupied rows, so this never becomes a viewport. */
.mct-boarditem > .mct-panel {
  min-height: var(--mct-panel-min-height, 0px);
  height: auto;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}
/* The board grows around panel content; it does not put a scrollbar inside
   the panel. Individual controls may still own overflow where that is their
   actual UI (for example a deliberately scrollable log). */
.mct-boarditem > .mct-panel > .body {
  flex: 1;
  min-height: 0;
  overflow: visible;
}
/* A board panel is exactly as wide as it declares itself, and its body does
   not clip — so anything inside that cannot shrink does not get cut off, it
   hangs over the glass, which looks like a rendering fault rather than a
   panel needing another cell. These are the three things that will not
   shrink on their own inside 300px:

   - a word with nowhere to break: a URL, a track id, a channel name. It
     breaks mid-word here rather than running off the edge, because a panel is
     a glance and the alternative is losing the end of it.
   - a box that is a flex or grid item: its default min-width is its content,
     so one long child holds the whole row open. Only the body's own
     descendants are touched, and only in this direction.
   - a block of code, which has no narrow form. It scrolls in place instead.
     (A `Table` needs no rule here: it already travels inside
     `.mct-tablewrap`, which scrolls sideways wherever it is put.) */
.mct-boarditem > .mct-panel > .body {
  overflow-wrap: anywhere;
}
.mct-boarditem > .mct-panel > .body :where(div, section, p, ul, ol, li, label,
    header, footer, span) {
  min-width: 0;
}
.mct-boarditem > .mct-panel > .body :where(pre) {
  max-width: 100%;
  overflow-x: auto;
}
/* A control is not prose: breaking inside its label gives you a button that
   says "Disconn/ect" and a segmented control spelling "Poi/nts" down three
   lines. Their words stay whole, and the one control that is a row of labels
   and can genuinely outgrow a panel scrolls sideways in place instead. A
   control that still does not fit is a panel that wants another cell, or a
   shorter label — not something for the stylesheet to hide by shattering
   words. */
.mct-boarditem > .mct-panel > .body :where(.mct-btn, .mct-textbtn, .mct-input,
    .mct-select, .mct-segmented, .mct-picker, .mct-node, .mct-badge) {
  overflow-wrap: normal;
}
.mct-boarditem > .mct-panel > .body :where(.mct-segmented) {
  max-width: 100%;
  overflow-x: auto;
}
/* A form control's intrinsic width is not what it shows. A `<select>` is as
   wide as its widest OPTION — "Prevent skip redemptions" while the closed
   control reads "Block…" — and an `<input>` defaults to about twenty
   characters; as flex items neither may shrink below that, so one of them
   beside a button is enough to push the row through the panel's edge. They
   shrink here and ellipsize what they show, which is what a closed control
   does anyway. */
.mct-boarditem > .mct-panel > .body :where(select, input, textarea) {
  max-width: 100%;
  min-width: 0;
}
/* A text-only startup/empty state already gets its breathing room from the
   panel body. Browser paragraph margins would make "Connecting…" one grid
   row taller than the compact content that replaces it, shifting neighbours
   twice during a refresh. */
.mct-boarditem > .mct-panel > .body > p.mct-dim:only-child {
  margin: 0;
}
/* the header is the handle — the cursor says so before anything moves */
.mct-boarditem .mct-panel > header {
  cursor: grab;
}
/* A wide board already drags from the empty part of the panel header, so an
   extra grip adds chrome without adding an interaction. Phones keep the grip
   as their precise, scroll-safe touch target below. */
/* Every rule below means the PANEL's move handle, which is the grip in the
   panel's own header. Scoped to it, because a panel's content may hold
   grips of its own — a to-do list's items and the counters drag their rows
   with useReorder — and those must keep their own look and, above all,
   stay visible on a desktop board. */
.mct-board:not(.mobile) .mct-panel > header .mct-grip {
  display: none;
}
.mct-board.mobile .mct-panel > header,
.mct-board.touch-only .mct-panel > header {
  cursor: default;
}
.mct-board.mobile.reorderable .mct-panel > header .mct-grip {
  cursor: grab;
  display: inline-grid;
  position: relative;
  overflow: hidden;
  touch-action: none;
  user-select: none;
}
.mct-board.mobile.reorderable .mct-panel > header .mct-grip::after {
  content: "";
  position: absolute;
  right: 5px;
  bottom: 3px;
  left: 5px;
  height: 2px;
  border-radius: 2px;
  background: var(--mct-accent);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left;
}
.mct-boarditem.mobile-drag-holding .mct-panel > header .mct-grip {
  color: var(--mct-accent);
  background: color-mix(in srgb, var(--mct-accent) 10%, transparent);
}
.mct-boarditem.mobile-drag-holding .mct-panel > header .mct-grip::after {
  opacity: 1;
  animation: mct-mobile-drag-hold 350ms linear forwards;
}
@keyframes mct-mobile-drag-hold {
  to { transform: scaleX(1); }
}
.mct-board.mobile-reordering .mct-panel > header .mct-grip {
  cursor: grabbing;
}
.mct-mobile-drop-placeholder {
  min-height: var(--mct-panel-min-height, 0px);
  box-sizing: border-box;
  border: 1px dashed color-mix(in srgb, var(--mct-accent) 70%, var(--mct-border));
  border-radius: var(--mct-radius);
  background: color-mix(in srgb, var(--mct-accent) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mct-accent) 8%, transparent);
}
.mct-boarditem.mobile-dragging {
  position: fixed;
  inset: 0 auto auto 0;
  margin: 0;
  opacity: 0.94;
  z-index: 1000;
  will-change: transform;
}
/* Lifted: the rim goes accent and the cast deepens, because a panel in your
   hand is further off the page than one lying on it. */
.mct-boarditem.mobile-dragging > .mct-panel {
  box-shadow:
    inset 0 0 0 1px var(--mct-accent),
    var(--lq-edge),
    0 16px 42px rgba(0, 0, 0, 0.42);
}
/* the panel being dragged fades where it was; the grid reflowing around it is
   the preview of where it will land. Opacity, never layout animation. */
.mct-boarditem.dragging {
  opacity: 0.35;
}
/* A bare icon button for controls that belong to a panel's own chrome — the
   grip and the ×. Ghost until wanted: no border, dim glyph, a soft fill on
   hover. Never for an action with consequences a ghost would understate. */
.mct-iconbtn {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 50%;
  color: var(--mct-text-dim);
  cursor: pointer;
  transition: color 0.15s var(--mct-ease), background-color 0.15s var(--mct-ease);
}
.mct-iconbtn:hover {
  color: var(--mct-text);
  background: color-mix(in srgb, var(--mct-text) 12%, transparent);
}
.mct-grip {
  cursor: grab;
}
/* A row that gets reordered under the reader travels to its new place
   instead of appearing in it — the to-do list sinks an item the moment it
   is ticked, and a jump there loses track of where the item went. Script
   sets the offset and clears it (the panel's useSlide); this is the rule
   that plays it back. It leaves fast and arrives slowly, so the eye can
   follow. Nothing else sets transform on a row, so nothing else animates. */
.mct-row {
  position: relative;
  transition: transform 0.42s var(--mct-ease);
}
/* Dragging a row into place (useReorder). The row in hand fades so the list
   reads as the place it is going rather than the place it left, and the gap
   it would drop into is drawn as a rule on the row it is over — above or
   below, whichever half the pointer is in.
   A pseudo-element, not a box-shadow: these rows are glass, plain, or a
   tinted pill by turns, and a shadow would have to know which. */
.mct-row[data-dragging="true"] {
  opacity: 0.4;
}
.mct-row[data-drop]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--mct-accent);
  pointer-events: none;
}
.mct-row[data-drop="above"]::after {
  top: -1px;
}
.mct-row[data-drop="below"]::after {
  bottom: -1px;
}
/* the grip says "this can be picked up"; the whole row is the handle */
.mct-row[draggable="true"] .mct-grip {
  cursor: grab;
}
.mct-row[data-dragging="true"] .mct-grip {
  cursor: grabbing;
}
/* Row actions that wait for the pointer — the move and remove glyphs on a
   list's items. Drawn on every row they would be the loudest thing on the
   page; ghosted until the row is hovered or holds focus, the row reads as its
   text. Touch has no hover, so there they simply stay. */
.mct-row .mct-rowactions {
  opacity: 0;
  transition: opacity 0.15s;
}
.mct-row:hover .mct-rowactions,
.mct-row:focus-within .mct-rowactions {
  opacity: 1;
}
@media (hover: none) {
  .mct-row .mct-rowactions {
    opacity: 1;
  }
}
/* An action that is just its words — "Clear done", "New list" — for the
   quiet moves that a bordered button would over-announce. Dim until hovered,
   then the text colour and an underline; the danger variant reddens instead,
   so a destructive text action is still told apart before the click. */
.mct-textbtn {
  border: 0;
  background: none;
  padding: 0;
  color: var(--mct-text-dim);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  border-radius: var(--lq-r-control);
  transition-timing-function: var(--mct-ease);
}
.mct-textbtn:hover:not(:disabled) {
  color: var(--mct-text);
  text-decoration: underline;
}
.mct-textbtn.danger:hover:not(:disabled) {
  color: var(--mct-destructive);
}
.mct-textbtn:disabled {
  opacity: 0.5;
  cursor: default;
}
.mct-textbtn:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}

/* --- the chat dock -------------------------------------------------------
   The live chat, parked down the right of the shell. Not a sixth kind of
   glass: it IS a panel (.mct-panel, material and header and all), floated off
   the edges rather than laid into the board — the one panel that follows you
   from page to page.

   The chat inside is an <iframe>, and a frame cannot be translucent: whatever
   the embedded page leaves transparent, the browser paints as that frame's own
   canvas. So the chat is a well — the dark inset every other block of
   somebody else's content sits in — rather than more glass. */
.mct-dock {
  position: fixed;
  top: calc(var(--mct-topbar-h) + 12px);
  right: 12px;
  bottom: 12px;
  width: var(--lq-dock-w);
  max-width: calc(100vw - 24px);
  z-index: 15;
}
.mct-dock > .mct-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  box-sizing: border-box;
}
/* ...but NOT the backdrop work, which is where a panel's cost lives.

   The filter re-runs per element every time the backdrop changes, and the
   backdrop here is the moving gradient. Every other glass surface is a card
   a few hundred pixels tall that shows what is behind it; this one is the
   tallest surface in the app, it never closes, and it is almost entirely
   covered by the chat — an <iframe>, which cannot be translucent. What the
   blur actually reached was a 40px header and a 10px margin, for a full-
   height filter re-run every frame. Tint, rim, radius and shadow stay; the
   filter and the pointer specular go. */
.mct-dock > .mct-panel {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: color-mix(in srgb, var(--mct-surface) 82%, var(--lq-tint));
}
.mct-dock > .mct-panel::after {
  display: none;
}
/* The left edge, draggable. A wide invisible hit area with a thin mark in it:
   the pointer needs the reach, the page does not need another line drawn down
   it. The mark shows up when you are on it, and whenever it has focus. */
.mct-dockgrip {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -8px;
  width: 16px;
  z-index: 1;
  cursor: ew-resize;
  touch-action: none;
}
.mct-dockgrip::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 6px;
  width: 4px;
  height: 46px;
  margin-top: -23px;
  border-radius: var(--lq-r-control);
  background: var(--mct-text);
  opacity: 0;
  transition: opacity 0.15s var(--mct-ease);
}
.mct-dockgrip:hover::before,
.mct-dockgrip:focus-visible::before {
  opacity: 0.55;
}
.mct-dockgrip:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: -2px;
  border-radius: var(--lq-r-control);
}
/* The dock's two header controls are bigger than a panel's usual chrome:
   they are the whole of this column's UI — hide it, or take it out into a
   window — and both are drawn as glyphs rather than icons, which read small.
   30px is as wide as a 40px header takes without crowding its rule. */
.mct-dock > .mct-panel > header .mct-iconbtn {
  width: 30px;
  height: 30px;
  font-size: 19px;
  line-height: 1;
}
.mct-dock > .mct-panel > .body {
  display: flex;
  flex: 1;
  min-height: 0;
  padding: 10px;
}
.mct-dock iframe {
  flex: 1;
  min-height: 0;
  width: 100%;
  border: var(--mct-border-w) solid var(--mct-border-soft);
  border-radius: var(--lq-r-well);
  /* what shows before the frame has painted; the page inside paints the same
     surface (overlay.html, body.dock) because a frame cannot be translucent */
  background: var(--mct-surface);
}
/* the dim line that stands in for the chat says its piece at the top, where
   a first message would be, rather than centred in a column of nothing */
.mct-dock > .mct-panel > .body > p {
  align-self: start;
  font-size: 13px;
  margin: 4px 6px;
}
/* Closed: one tab on the edge, in the material every control wears. Rounded
   towards the page, square against the edge it is hinged on. */
.mct-docktab {
  position: fixed;
  top: 40%;
  right: 0;
  z-index: 15;
  padding: 16px 7px;
  writing-mode: vertical-rl;
  font-family: var(--mct-font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--mct-text);
  background: var(--lq-tint-hi);
  border: 0;
  border-radius: var(--lq-r-control) 0 0 var(--lq-r-control);
  box-shadow: var(--lq-edge);
  cursor: pointer;
  transition: transform 0.18s var(--mct-ease),
    background-color 0.18s var(--mct-ease);
}
.mct-docktab:hover {
  background: color-mix(in srgb, var(--mct-text) 21%, transparent);
  transform: translateX(-2px);
}
.mct-docktab:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}
/* The page hands over the width it costs — the dock is beside the work, never
   on top of it. The PAGE, not the shell: the top bar spans the window whether
   or not the chat is open, because the bar is about the whole app and a bar
   that shortens when a panel opens reads as the panel pushing it. The dock
   hangs below it, so the width it takes comes out of the work underneath.
   Only the wide layout has width to give; under 1024px the dock lies over the
   page, which is what the tab that closes it is for. */
@media (min-width: 1024px) {
  body:has(.mct-dock:not([hidden])) .mct-console {
    padding-right: calc(var(--lq-dock-w) + 24px);
  }
  /* the one control pinned to the same corner: it steps aside, rather than
     hiding behind the column */
  body:has(.mct-dock:not([hidden])) .mct-fab {
    right: calc(var(--lq-dock-w) + 36px);
  }
}
/* A disc pinned to the viewport sits on whatever the viewport has at that
   corner, and with the dock open that corner is a panel rather than the empty
   right of the board. The page cannot stop a fixed control overlapping while
   you scroll past, but it can make sure there is somewhere to put it: the
   content ends a FAB's height above the foot, so scrolled to the bottom — the
   place people leave a dashboard — the button is over empty page. */
body:has(.mct-fab) .mct-console-main {
  padding-bottom: 96px;
}

/* The floating action button: the page's one from-anywhere action, pinned to
   the corner. A disc, built like a primary button — the same lit rim and the
   same accent thrown onto what is underneath. Above the panels, below a
   modal. */
.mct-fab {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 30;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  padding: 0;
  background: var(--mct-accent);
  color: var(--mct-on-accent);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
    0 12px 30px -10px var(--mct-accent);
  transition: transform 0.15s var(--mct-ease), box-shadow 0.15s var(--mct-ease);
}
.mct-fab:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
    0 18px 38px -10px var(--mct-accent);
}
/* The performance switch (PerfFab): the other corner, the same accent disc
   as the page's action so the two read as a pair. While low power is on it
   dims to the control tint with the accent kept for the glyph — a quieter
   button for a quieter page, and the state readable from across the room. */
.mct-perf-fab {
  right: auto;
  left: 24px;
}
.mct-perf-fab[data-on] {
  background: var(--lq-tint-hi);
  color: var(--mct-accent);
  box-shadow: var(--lq-edge), var(--lq-cast);
}
.mct-perf-fab[data-on]:hover { box-shadow: var(--lq-edge), var(--lq-cast); }
/* Its popover — the native one: top layer, light-dismiss and Escape for
   free — pinned above the disc. A glass surface, listed in the guidelines'
   budget: it floats over the board like a modal and is open for seconds. */
.mct-perf-pop {
  position: fixed;
  inset: auto auto 88px 24px;
  margin: 0;
  width: min(300px, calc(100vw - 48px));
  padding: 16px 18px;
  color: var(--mct-text);
  gap: 10px;
}
.mct-perf-pop:popover-open { display: grid; }
.mct-perf-pop::backdrop { background: transparent; }
.mct-perf-pop p { margin: 0; }

/* Folded away, but never a line of grey text pretending to be a link. Its own
   piece of glass, with a display title and a chevron that turns. The whole
   summary row is the target, not just the words. */
.mct-collapse {
  overflow: hidden;
}
.mct-collapse > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 15px 20px;
  cursor: pointer;
  font-family: var(--mct-font-display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.015em;
  color: var(--mct-text);
  list-style: none;
  border-radius: var(--mct-radius);
  transition: background 0.15s var(--mct-ease);
}
.mct-collapse > summary::-webkit-details-marker {
  display: none;
}
.mct-collapse > summary::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  /* a solid triangle, drawn in borders: no icon font, no asset */
  border-left: 7px solid var(--mct-accent);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transition: transform 0.15s;
}
.mct-collapse[open] > summary::before {
  transform: rotate(90deg);
}
.mct-collapse > summary:hover {
  background: color-mix(in srgb, #fff 6%, transparent);
}
.mct-collapse > summary:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: -2px;
}
.mct-collapse[open] > summary {
  border-bottom: var(--mct-border-w) solid var(--mct-border);
  border-radius: var(--mct-radius) var(--mct-radius) 0 0;
}
.mct-collapse > summary .note {
  margin-left: auto;
  font-family: var(--mct-font-sans);
  font-weight: 500;
  font-size: 13px;
  color: var(--mct-text-dim);
}
.mct-collapse > .body {
  padding: 18px 20px;
}

/* What people asked for — a list of names and songs, not console output.
   Who requested it leads, because that is what gets read out loud. */
.mct-requests {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 220px;
  overflow: auto;
}
.mct-requests li {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid color-mix(in srgb, #fff 8%, transparent);
  font-size: 13px;
}
.mct-requests li:last-child {
  border-bottom: 0;
}
/* the name itself is a Handle — this only keeps it on one line */
.mct-requests .who {
  white-space: nowrap;
}
.mct-requests .what {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The console, for when something needs diagnosing. A well, like a field:
   output belongs under the surface, not floating on it. */
.mct-log {
  margin: 8px 0 0;
  padding: 10px 12px;
  max-height: 200px;
  overflow: auto;
  background: color-mix(in srgb, #000 30%, transparent);
  border: 0;
  border-radius: var(--lq-r-well);
  box-shadow: inset 0 2px 6px -2px color-mix(in srgb, #000 70%, transparent);
  font-family: var(--mct-font-mono);
  font-size: 12px;
  line-height: 1.7;
  color: var(--mct-text-dim);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Running or not: a dot and a word, so it survives being read in greyscale. */
.mct-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mct-font-sans);
  font-size: 14px;
  font-weight: 600;
  color: var(--mct-text-dim);
  white-space: nowrap;
}
/* Drawn, not typed. This was the character ●, which Figtree has no glyph for,
   so it arrived from whatever fallback the machine had — a different size and
   a different baseline on every platform, next to the word it belongs to. */
.mct-status > .dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.mct-status.live {
  color: var(--mct-success);
}

/* Getting started: what is done and what is next, as steps rather than a
   paragraph with ticks in it. */
.mct-steps {
  list-style: none;
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
}
.mct-steps li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: 10px;
  align-items: start;
  font-size: 15px;
  color: var(--mct-text);
}
.mct-steps li .mark {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 0;
  background: var(--lq-tint);
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 26%, transparent);
  color: var(--mct-text-dim);
  font-size: 11px;
  font-weight: 700;
}
.mct-steps li.done {
  color: var(--mct-text-dim);
}
.mct-steps li.done .mark {
  background: var(--mct-success);
  box-shadow: 0 4px 12px -5px var(--mct-success);
  color: var(--mct-bg);
}

/* Modal: one task in front of the page. Padding lives on header and body,
   never the dialog itself — the dialog element's own surface is exactly the
   backdrop-click target, so it must have no clickable area of its own. */
.mct-modal {
  padding: 0;
  color: var(--mct-text);
  width: min(600px, calc(100vw - 2 * var(--mct-gap)));
  max-height: calc(100vh - 2 * var(--mct-gap));
  display: none;
  flex-direction: column;
}
.mct-modal[open] {
  display: flex;
}
/* Three plan cards side by side need more than the reading width a column of
   fields wants. Still bounded by the viewport, so a phone gets one column. */
.mct-modal.wide {
  width: min(980px, calc(100vw - 2 * var(--mct-gap)));
}
.mct-modal::backdrop {
  /* plain rgba: custom properties do not reliably reach ::backdrop */
  background: rgba(9, 6, 14, 0.7);
}
.mct-modal > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: var(--mct-border-w) solid var(--mct-border);
}
.mct-modal > header h3 {
  font-family: var(--mct-font-display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.025em;
  margin: 0;
}
.mct-modal > header .close {
  border: 0;
  background: none;
  color: var(--mct-text-dim);
  font-size: 20px;
  line-height: 1;
  padding: 2px 6px;
  cursor: pointer;
}
.mct-modal > header .close:hover {
  color: var(--mct-text);
}
.mct-modal > header .close:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
  border-radius: var(--lq-r-control);
}
.mct-modal > .body {
  padding: 14px 16px 16px;
  overflow: auto;
}
/* A modal's own actions, kept in reach while its body scrolls past them —
   the savebar's trick one level in. Bleeds to the body's edges and cancels
   its bottom padding, so the rows travel under the band rather than beside
   it, and lies the buttons out in a row rather than the savebar's column.

   Opaque, unlike the page's savebar: what passes under this one is a table
   of controls, not a gradient, and a frosted band over it leaves the row
   underneath legible enough to read as a rendering fault. The modal's own
   11% lift goes back on top of a solid ground, so the band still belongs to
   the glass it sits in. */
.mct-modal .body .mct-savebar {
  background: linear-gradient(var(--lq-tint), var(--lq-tint)), var(--mct-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  bottom: -16px;
  display: flex;
  flex-wrap: wrap;
  margin: 0 -16px -16px;
  padding: 12px 16px;
}

/* Two heading levels below a panel's own title: a Group names a column, a
   Section names one thing you can change. Both are display-font and full
   strength — a section title is a heading, not a caption. */
.mct-group > h3 {
  font-family: var(--mct-font-display);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.03em;
  margin: 0 0 2px;
  padding-bottom: 12px;
  border-bottom: var(--mct-border-w) solid var(--mct-border);
}
.mct-section {
  margin-top: 28px;
}
/* 28px separates a section from what came before it. First in its container
   there is nothing before it, and the margin becomes a band of empty panel
   under the header — which is what it was doing at the top of every dashboard
   card whose body opens with a section. A heading above it is a sibling, so a
   section under a Group's title keeps its space.

   The second selector is not a flourish: a closed `<dialog>` is a real
   sibling that paints nothing, and a panel whose body opens with a Modal —
   requeue's setup guide — puts one in front of its first section. The section
   is first to the eye and second to the DOM, and the band came back. */
.mct-section:first-child,
dialog:not([open]) + .mct-section {
  margin-top: 0;
}
/* Sections laid side by side take their spacing from the row's own gap; the
   stacking margin would drop every column but the first by 28px. */
.mct-sections > .mct-section {
  margin-top: 0;
}
/* the Getting started checklist: what follows it (a Group, a form) brings no
   top spacing of its own, so this section carries the gap below itself */
.mct-section.mct-started {
  margin-bottom: 24px;
}
.mct-section > h4 {
  font-family: var(--mct-font-display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--mct-text);
  margin: 0 0 10px;
}
/* A section inside a section — something that belongs to one platform, like
   channel points to Twitch. One step down, still full strength. */
.mct-section .mct-section > h4 {
  font-size: 14px;
}

/* One choice out of a few, exactly one live — a mode, not an action. One pill
   holding borderless buttons; the live one is filled, so "which is on" never
   rests on a border tint. */
.mct-segmented {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border: 0;
  border-radius: var(--lq-r-control);
  background: color-mix(in srgb, #000 24%, transparent);
  box-shadow: inset 0 2px 6px -2px color-mix(in srgb, #000 65%, transparent);
}
/* 34px inside 4px of padding is 42px, the same as a default button, so a
   segmented control lines up with the buttons beside it instead of sitting a
   few pixels proud. */
.mct-segmented .mct-btn {
  --lq-h: 34px;
  border: 0;
  background: none;
  box-shadow: none;
  padding: 0 18px;
}
/* Even: every segment as wide as the widest, with a shared floor, so two
   position controls stacked on a settings page (Top / Middle / Bottom over
   Left / Center / Right) come out button for button the same size. A label
   past the floor widens its whole control evenly rather than one segment. */
.mct-segmented.even {
  display: inline-grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
}
.mct-segmented.even .mct-btn {
  min-width: 6.5em;
}
/* Hovering the option that is already on should do nothing — there is nothing
   to choose — so the live one is excluded rather than greyed. */
.mct-segmented .mct-btn:hover:not(:disabled, [aria-pressed="true"], [aria-current="page"]) {
  background: color-mix(in srgb, var(--mct-text) 13%, transparent);
}
.mct-segmented .mct-btn[aria-pressed="true"],
.mct-segmented .mct-btn[aria-current="page"] {
  background: var(--mct-accent);
  color: var(--mct-on-accent);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 45%, transparent),
    0 6px 16px -8px var(--mct-accent);
}

/* A page with a rail of sections beside its content — the console layout.
   The rail is SideNav; below 1024px it lies down above the content. */
.mct-railpage {
  display: grid;
  gap: var(--mct-gap);
  align-items: start;
}
@media (min-width: 1024px) {
  .mct-railpage {
    grid-template-columns: 200px minmax(0, 1fr);
  }
}

/* The vertical Tabs, flat: no box around the rail — the filled current
   section is the only chrome. It stays put while the content changes. */
.mct-sidenav {
  display: grid;
  gap: 4px;
  align-content: start;
  position: sticky;
  top: var(--mct-gap);
}
.mct-sidenav .mct-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 0;
  background: none;
  box-shadow: none;
  text-align: left;
  padding: 0 14px;
  justify-content: flex-start;
}
/* An option's icon: beside the word, never instead of it. It takes the row's
   own colour, so it dims and lights with the label rather than needing a
   second rule per state. */
.mct-sidenav .mct-btn .icon {
  display: inline-flex;
  flex: none;
}
.mct-sidenav .mct-btn[aria-current="page"] {
  background: var(--mct-accent);
  color: var(--mct-on-accent);
}
@media (max-width: 1023px) {
  .mct-sidenav {
    display: flex;
    position: static;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .mct-sidenav .mct-btn {
    flex: none;
  }
}

/* One number at a glance, flat on the page: display font carries it, the
   dim label under it says what it counts. No box — a count is not a card.
   A row of these heads a page; more than a row is a report, not a glance. */
.mct-stats {
  display: flex;
  gap: 26px 54px;
  flex-wrap: wrap;
}
.mct-stat {
  display: grid;
  gap: 2px;
}
.mct-stat .value {
  font-family: var(--mct-font-display);
  font-size: 38px;
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1.1;
}
.mct-stat .label {
  color: var(--mct-text-dim);
  font-size: 14px;
}
.mct-stat.accent .value {
  color: var(--mct-accent);
}
.mct-stat.success .value {
  color: var(--mct-success);
}

/* Rows of records. Header dim and small; rows separated by hairlines — the
   head's rule is the loud one, and a full-strength line under every row would
   be all fence and no garden. The wrapper scrolls sideways so a narrow phone
   never scrolls the page itself. */
.mct-tablewrap {
  overflow-x: auto;
}
.mct-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.mct-table th {
  text-align: left;
  font-family: var(--mct-font-sans);
  font-weight: 600;
  color: var(--mct-text-dim);
  padding: 6px 10px;
  border-bottom: var(--mct-border-w) solid var(--mct-border);
  white-space: nowrap;
}
.mct-table td {
  padding: 8px 10px;
  border-bottom: 1px solid color-mix(in srgb, #fff 8%, transparent);
  vertical-align: middle;
}
/* A matrix — the plan ladder — names its rows as well as its columns, and a
   row header is a cell in the body, not a second heading band: the hairline
   and the strength of the row it belongs to, and free to wrap. */
.mct-table tbody th {
  border-bottom: 1px solid color-mix(in srgb, #fff 8%, transparent);
  color: var(--mct-text);
  font-weight: 400;
  padding: 8px 10px;
  white-space: normal;
}
/* A row you can open tells you so before you click it. */
.mct-table tbody tr {
  transition: background-color 0.16s var(--mct-ease);
}
.mct-table tr:last-child td,
.mct-table tbody tr:last-child th {
  border-bottom: 0;
}

/* Commands table. The command cell is the wide one — the trigger, what it
   does and its aliases stack there; every other column is one control, so
   they take only what they need and stay out of the way. Rows carrying a
   control need the top of the cell, not its middle. */
.mct-cmd-prefix {
  display: block;
  margin-bottom: 16px;
}
.mct-cmd-prefix small {
  display: block;
  margin-top: 4px;
}
.mct-table td:has(> .mct-switch),
.mct-table td:has(> .mct-select),
.mct-table td:has(> input.mct-input) {
  vertical-align: top;
  white-space: nowrap;
  width: 1%;
}
/* The alias field sits under a description, so it gets a line of its own
   rather than a label beside it that would push the column wider. */
.mct-cmd-alias-label {
  display: block;
  margin-top: 6px;
}
/* Aliases and the reply share a line — the reply gets the wider share, and
   both drop to their own line when the column cannot hold the pair. */
.mct-cmd-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
}
.mct-cmd-fields > label {
  flex: 1 1 18ch;
  min-width: 0;
}
.mct-cmd-fields > .mct-cmd-says {
  flex: 2 1 26ch;
}
.mct-cmd-fields .mct-input {
  margin-top: 2px;
  max-width: none;
}
/* A chat reply is one line by nature — chat carries no newlines — so the box
   starts at one line and grows with what is typed, rather than standing half
   empty on every row. It stops growing before it can push the table around. */
.mct-reply {
  display: block;
  width: 100%;
  resize: vertical;
  field-sizing: content;
  max-height: 7em;
}
/* A save that landed, said beside the field that took it rather than in a
   banner the eye has to go find. It fades itself; nothing to dismiss. */
.mct-saved {
  color: var(--mct-success);
  font-size: 13px;
  /* As tall as the field it answers for, so in a bottom-aligned row the
     words land on the box's line rather than up beside its label. */
  display: flex;
  align-items: center;
  min-height: 2.2em;
}
/* The connect buttons of the bot-account card: a column that shrink-wraps to
   the widest of them, with every button filling it. */
.mct-botaccounts {
  display: inline-grid;
  gap: 8px;
  justify-self: start;
}
.mct-botaccounts > .mct-btn {
  width: 100%;
}
/* The {braces} legend: the name, then where it is known. A grid so the
   names line up into a column you can read down. */
.mct-legend {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  margin: 0 0 10px;
}
.mct-legend dt {
  white-space: nowrap;
}
.mct-legend dd {
  color: var(--mct-text-dim);
  margin: 0;
  min-width: 0;
}
/* where the name works, under what it means: the same line would read as
   part of the explanation */
.mct-legend dd small {
  display: block;
  opacity: 0.7;
}
/* A note somebody may put away: quieter than an alert, since nothing is
   wrong — it is the thing you wish you had known. */
.mct-note {
  align-items: start;
  background: color-mix(in srgb, #000 18%, transparent);
  border: var(--mct-border-w) solid var(--mct-border-soft);
  border-radius: var(--lq-r-well);
  color: var(--mct-text-dim);
  display: flex;
  font-size: 12px;
  gap: 10px;
  line-height: 1.5;
  padding: 9px 10px 9px 12px;
}
.mct-note > div {
  min-width: 0;
}
.mct-note > .mct-iconbtn {
  flex: none;
  font-size: 16px;
  line-height: 1;
}
/* The {braces} legend is reference sitting among settings, so it reads as a
   note rather than another section: a card of its own on a faint surface,
   its label in the page's own voice instead of the register's mono caps, and
   a marker that does not borrow the accent the real sections use. */
.mct-legendfold {
  margin: 2px 0 6px;
}
.mct-console .mct-legendfold > .mct-collapse,
.mct-legendfold > .mct-collapse {
  background: color-mix(in srgb, #000 18%, transparent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: var(--mct-border-w) solid var(--mct-border-soft);
  border-radius: var(--lq-r-well);
  box-shadow: none;
}
.mct-legendfold > .mct-collapse::after {
  display: none;
}
.mct-console .mct-legendfold > .mct-collapse > summary,
.mct-legendfold > .mct-collapse > summary {
  font-family: var(--mct-font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  padding: 8px 12px;
  border-radius: var(--lq-r-well);
  text-transform: none;
}
.mct-legendfold > .mct-collapse > summary::before {
  border-left-color: var(--mct-text-dim);
  border-bottom-width: 4px;
  border-left-width: 6px;
  border-top-width: 4px;
}
.mct-console .mct-legendfold > .mct-collapse[open] > summary,
.mct-legendfold > .mct-collapse[open] > summary {
  border-bottom: 1px solid var(--mct-border-soft);
}
.mct-console .mct-legendfold > .mct-collapse > .body,
.mct-legendfold > .mct-collapse > .body {
  padding: 10px 12px;
}
.mct-legendfold .mct-legend {
  font-size: 12px;
}
/* A service with nothing to list must not leave its heading standing over
   the next service's table. */
.mct-collapse:has(> .body:empty) {
  display: none;
}
.mct-table td > label > .mct-input {
  margin-top: 2px;
  max-width: 22ch;
}

/* A named switch you can open: the name is a button, the switch rides in the
   same pill, and the two together are one control — "this is on" and "there
   is something here to edit". Tinted like every other control, with no filter
   of its own; the switch inside keeps its own material. */
.mct-bubble {
  align-items: center;
  background: var(--lq-tint-hi);
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  display: inline-flex;
  flex: none;
  gap: 8px;
  /* tighter on the switch's side: the track already carries its own margin of
     dark, so equal padding reads as a gap that only opened on the left */
  padding: 4px 6px 4px 13px;
}
.mct-bubble.openable {
  cursor: pointer;
}
.mct-bubble.openable:hover > button {
  text-decoration: underline;
}
/* a list of control rows, each divided from the next — which switches
   belong to which row reads at a glance */
.mct-rows > * + * {
  border-top: 1px solid var(--mct-border-soft);
  padding-top: 8px;
}
.mct-bubble > button {
  background: none;
  border: 0;
  color: var(--mct-text);
  cursor: pointer;
  font-family: var(--mct-font-sans);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  padding: 0;
}
/* a reserved name: the widest text sits invisible in the same grid cell as
   the real one, so the pill is that wide whatever the name says now */
.mct-bubble > button.reserved {
  display: inline-grid;
  justify-items: center;
}
.mct-bubble > button.reserved > span {
  grid-area: 1 / 1;
}
.mct-bubble-reserve {
  visibility: hidden;
}
.mct-bubble > button:hover:not(:disabled) {
  text-decoration: underline;
}
.mct-bubble > button:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}
.mct-bubble > button:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
}

.mct-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
}
.mct-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
/* Two pieces of the same material rather than a tinted rectangle with a dot in
   it. The track is a well cut into the glass: dark, with the shadow falling
   from its top lip inward and a highlight on the bottom lip, which is what a
   channel looks like. The knob is the opposite — a raised piece, lit along its
   own top edge and casting down into the channel. Getting those two lighting
   directions opposed is the whole of it; matched, it reads as two flat shapes.
   Off is not grey-because-nothing-was-styled: the knob is deliberately the dim
   text colour, so off looks decided rather than unfinished. */
.mct-switch .track {
  position: relative;
  /* stated, not inherited: a host page's `* { box-sizing: border-box }` would
     otherwise shrink the padding box the knob is centred in */
  box-sizing: content-box;
  width: 50px;
  height: 28px;
  flex: none;
  border-radius: var(--lq-r-control);
  border: 0;
  background: color-mix(in srgb, #000 38%, transparent);
  box-shadow:
    inset 0 2px 6px -2px color-mix(in srgb, #000 85%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 14%, transparent);
  transition: background-color 0.22s var(--mct-ease), box-shadow 0.22s var(--mct-ease);
}
/* The knob is a lens, not a disc. A flat circle is what keeps a switch looking
   like a diagram of a switch: real glass has a hot spot where the light
   enters, a body falling away from it, and a dark underside where it meets
   what it sits in. The offset highlight is what makes it read as round rather
   than as a filled circle. 3px of track shows on every side: 3 + 22 + 3 fills
   the 28px box, and 3 + 22 + 22 travelled + 3 fills the 50px one.
   It leaves fast and arrives slowly, the way a thrown object does — an
   overshoot was the first instinct and it reads as a toy. */
.mct-switch .track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 26%,
      #fff 0%,
      color-mix(in srgb, var(--mct-text-dim) 35%, #fff) 42%,
      var(--mct-text-dim) 100%);
  box-shadow:
    inset 0 1.5px 1px color-mix(in srgb, #fff 75%, transparent),
    inset 0 -2px 3px color-mix(in srgb, #000 28%, transparent),
    0 2px 6px -1px color-mix(in srgb, #000 75%, transparent);
  transition: transform 0.26s cubic-bezier(.16, 1, .3, 1), background-color 0.2s;
}
/* On: the channel fills and lights, and the knob goes to full white so it
   still reads as the raised piece against a bright track. */
.mct-switch input:checked + .track {
  background: var(--mct-success);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 42%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 22%, transparent),
    0 6px 18px -8px var(--mct-success);
}
.mct-switch input:checked + .track::after {
  transform: translateX(22px);
  /* the lens keeps its form on: the hot spot stays, the body picks up a little
     of the channel's colour where the light passes through it */
  background:
    radial-gradient(circle at 34% 26%,
      #fff 0%,
      #fff 45%,
      color-mix(in srgb, #fff 86%, var(--mct-success)) 100%);
}
.mct-switch input:focus-visible + .track {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
}
/* not yours to flip (a read-level moderator): the state stays readable, the
   affordance honestly withdraws — never a switch that swallows the click */
.mct-switch input:disabled + .track {
  opacity: 0.45;
  cursor: not-allowed;
}
.mct-switch:has(input:disabled) {
  cursor: not-allowed;
}

/* A tick, in the switch's two pieces of material rather than the browser's
   square. Empty, it is a well cut into the glass: dark, the shadow falling
   in from its top lip and a highlight caught on the bottom one — the same
   channel as the switch's track, closed into a circle. Ticked, the well
   fills with the accent and throws a little of its own colour down onto
   what it sits on, and the mark is what is lit inside it.
   Round, not square: it is the same mark the overlay draws on stream, and
   the two have to be recognisably one control.
   Tinted only — no filter. There is one of these per item on a list, which
   is far past what the glass budget will carry (see "The glass budget"). */
.mct-check {
  display: inline-flex;
  /* the mark sits on the FIRST line, not in the middle of a wrapped label:
     a two-line to-do item with the tick floating at its centre reads as a
     tick belonging to neither line */
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  font-size: 15px;
  line-height: 1.45;
  min-width: 0;
}
.mct-check input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.mct-check .mark {
  position: relative;
  /* stated, not inherited: a host page's `* { box-sizing: border-box }`
     would otherwise shrink the box the mark is placed in */
  box-sizing: content-box;
  width: 20px;
  height: 20px;
  flex: none;
  /* on the first line's optical centre, given the 1.45 line-height above */
  margin-top: 1px;
  border-radius: 50%;
  background: color-mix(in srgb, #000 34%, transparent);
  /* the lip is lit the whole way round, not only at the bottom. The switch
     can light one lip because its track is 50px of channel and the shape
     reads anyway; a 20px circle needs its whole edge to stay a circle — and
     the overlay's copy of this composites over gameplay, where a well that
     only reads on a dark backdrop disappears half the time. */
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, #fff 22%, transparent),
    inset 0 2px 5px -2px color-mix(in srgb, #000 85%, transparent),
    inset 0 -1.5px 0 color-mix(in srgb, #fff 26%, transparent);
  transition: background-color 0.2s var(--mct-ease), box-shadow 0.2s var(--mct-ease);
}
/* The mark, centred by construction rather than by nudging two offsets.
   It is the bottom and right edges of a 4.5×8.5 box turned 45°, so the ink
   it actually paints is 9.2 wide and 6 tall — a little under half the
   disc, where the old 5×10 at 2.5px filled better than half and read as a
   tick crammed into a circle.
   Rotating about the box centre leaves the INK centre 1.6px below it (the
   painted corner is the far one), so the box is lifted by that much and
   the ink lands on the middle of the disc. Both transforms carry the same
   chain so the tick grows from where it will finally sit. */
.mct-check .mark::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4.5px;
  height: 8.5px;
  border: solid var(--mct-on-accent);
  border-width: 0 2px 2px 0;
  transform: translate(-50%, -50%) translateY(-1.6px) rotate(45deg) scale(0);
  transition: transform 0.2s var(--mct-ease) 0.04s;
}
.mct-check input:checked + .mark {
  background: var(--mct-accent);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 42%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 22%, transparent),
    0 6px 16px -8px var(--mct-accent);
}
.mct-check input:checked + .mark::after {
  transform: translate(-50%, -50%) translateY(-1.6px) rotate(45deg) scale(1);
}
.mct-check input:focus-visible + .mark {
  outline: 2px solid var(--mct-accent);
  outline-offset: 3px;
}
/* not yours to tick (a read-level moderator): readable, and honestly inert */
.mct-check input:disabled + .mark {
  opacity: 0.45;
  cursor: not-allowed;
}
.mct-check:has(input:disabled) {
  cursor: not-allowed;
}

/* A row in a column of names with one of them open — the to-do rail's
   lists. Tinted, never filtered: there is one per list, and the glass
   budget does not stretch to a surface per row.
   The open one is a pill of tinted glass carrying the accent along its
   leading edge as an ARC, not a bar. On a pill radius a straight 3px rule
   reads as a sticker laid on top; a border on the left alone follows the
   radius and tapers out where the edge turns, which reads as light caught
   on the rim of the material. */
.mct-listrow {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  border-radius: var(--lq-r-control);
  background: transparent;
  transition: background-color 0.18s var(--mct-ease);
}
.mct-listrow:hover {
  background: color-mix(in srgb, var(--mct-text) 6%, transparent);
}
.mct-listrow[data-open="true"] {
  background: var(--lq-tint-hi);
  box-shadow: var(--lq-edge);
}
.mct-listrow[data-open="true"]::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border-left: 3px solid var(--mct-accent);
  pointer-events: none;
}
/* the drop target while a row is being dragged over it: the accent as a
   rule in the gap the row would land in, above or below */

/* One counter as an item in a list: the name, the count, the settings that
   dress it and the button that ends it, with a hairline between it and the
   next one. The console register's rule for rows — a line, not a card: three
   cards inside a page that is already a card is where this stops reading as
   a list at all. The last item drops its line so the list does not end on a
   rule with nothing under it. */
.mct-counter {
  /* the grip's column, so the settings begin under the name rather than at
     the item's own edge */
  --indent: 24px;
  /* the full-strength hairline, not the soft one: soft is for rows inside a
     band, and what is being divided here is one whole counter from the next */
  border-bottom: 1px solid var(--mct-border);
  display: grid;
  gap: 12px;
  /* Closed, a counter is one line and the list is a list: five of them fit
     on a screen, and the one you want to drag is where you can see it. The
     air arrives with the settings, which is when there is something to give
     it to. */
  padding: 7px 0;
}
.mct-counter.open {
  padding: 12px 0 18px;
}
.mct-counter .mct-counter-settings {
  margin-left: var(--indent);
}
/* In the row the stepper is one control among four, not the line itself.
   Wide enough that a seven-figure count still reads whole — the well is what
   is left once the two buttons have taken theirs. */
.mct-counter .mct-stepper {
  flex: none;
  width: 250px;
}
.mct-counter:first-child {
  padding-top: 4px;
}
.mct-counter:last-child {
  border-bottom: 0;
}
/* The item's name, and its rename field: one control, not a title with a
   13px copy of itself in the settings underneath. Display face at heading
   size so the counter is plainly the biggest thing in its own row — a field
   that looked like a field was smaller than the settings below it, which put
   the least important text on the page in the largest type.
   No box until you go near it: this is a heading that happens to be
   editable, and a page of outlined fields reads as a form. */
.mct-counter-name {
  background: none;
  border: 0;
  border-radius: 10px;
  color: var(--mct-text);
  /* the name's width, not the row's: a field the width of the line reads as
     the line, and its focus ring as a box drawn round the whole counter */
  flex: 0 1 15em;
  font-family: var(--mct-font-display);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.02em;
  min-width: 0;
  overflow: hidden;
  padding: 3px 6px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
input.mct-counter-name:hover {
  background: color-mix(in srgb, #fff 6%, transparent);
}
input.mct-counter-name:focus {
  background: color-mix(in srgb, #000 26%, transparent);
  outline: 2px solid var(--mct-accent);
  outline-offset: 1px;
}
/* The rest of the row, as a click target: the quiet way to open a counter,
   for people who aim at the line rather than at the chevron. It is empty,
   and it takes whatever room the name did not. */
.mct-counter-open {
  align-self: stretch;
  background: none;
  border: 0;
  cursor: pointer;
  flex: 1;
  min-width: 8px;
  padding: 0;
}

/* A number you change by one, either way, with the two buttons at the ends
   and the figure between them. The well takes all the room that is left, so
   the buttons are where they were a moment ago whatever the number just did —
   a counter that shifts its own + as it passes 9 is a counter you misclick at
   10. Tabular figures for the same reason, one digit deep.
   A channel cut into the surface rather than a raised chip: this is the one
   thing in the row you are reading, not another thing to press. */
.mct-stepper {
  align-items: stretch;
  display: flex;
  gap: 8px;
  /* wide enough for a seven-figure count, and no wider: a full column of
     empty well behind a two-digit number reads as a text field somebody
     forgot to fill in, and this is one control in a list of counters rather
     than the page's centrepiece */
  max-width: 240px;
}
.mct-stepper > .mct-btn {
  --lq-h: 36px;
  flex: none;
  font-size: 16px;
  min-width: 44px;
}
/* The well, whether it is showing the count or taking a new one: the same
   channel either way, because a field that looks like a field here would be
   a third kind of box in a row that already has two. It is an <input> for
   anyone who may change the count — pressing + forty times to get to forty
   is not a thing to ask of anybody — and a plain span for a read-level
   moderator, who may look at it and no more. */
.mct-stepper > .value {
  background: color-mix(in srgb, #000 26%, transparent);
  border: 0;
  border-radius: var(--lq-r-well);
  box-shadow:
    inset 0 2px 5px -2px color-mix(in srgb, #000 80%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 10%, transparent);
  box-sizing: border-box;
  color: var(--mct-text);
  flex: 1;
  font-family: var(--mct-font-sans);
  font-size: 19px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  height: 36px;
  letter-spacing: -0.01em;
  line-height: 36px;
  min-width: 0;
  overflow: hidden;
  padding: 0 12px;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mct-stepper > input.value:focus {
  outline: 2px solid var(--mct-accent);
  outline-offset: 1px;
}

/* The full signal path remains available to the static landing illustration.
   React dashboard panels do not render it. */
.mct-path {
  display: flex;
  align-items: center;
  gap: 10px;
  /* A path often sits in an implicit grid track inside a 320px dashboard
     panel. Let that track shrink to the panel instead of using every pill's
     max-content width and making the whole module wider than its frame. */
  min-width: 0;
  max-width: 100%;
}
.mct-path .chips {
  display: flex;
  gap: 4px;
  /* Keep the platform nodes on one rail, but share tight space with the
     destination. Individual nodes ellipsize below rather than pushing the
     output (and every later row in the module) through the panel edge. */
  flex: 0 1 auto;
  min-width: 0;
}
/* A node is a chip, not a handle: it names a platform rather than an
   identifier anyone types, so it wears the page's own face and the same
   tinted glass every other pill does. */
.mct-path .node {
  align-items: center;
  box-sizing: border-box;
  display: inline-flex;
  font-family: var(--mct-font-sans);
  font-size: 13px;
  gap: 6px;
  max-width: 100%;
  min-width: 0;
  padding: 6px 14px;
  border-radius: var(--lq-r-control);
  border: 0;
  background: var(--lq-tint);
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 24%, transparent);
  color: var(--mct-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mct-path .node .label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.mct-path .node.out {
  flex: 0 1 auto;
}
/* The one thing on a page that moves on its own: the rail carries something
   while the service is live, so the motion IS the information — a rail that
   carries is running, a still one is not. `.off` gets nothing, and no page
   ever shows a second loop. */
.mct-path .rail {
  flex: 1 1 36px;
  min-width: 16px;
  height: 3px;
  border-radius: 999px;
  background: var(--mct-text-dim);
  position: relative;
  overflow: hidden;
}
.mct-path:not(.off) .rail::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent 0 40%, var(--mct-accent) 46% 54%, transparent 60%);
  animation: mct-carry 2.8s cubic-bezier(.45, 0, .55, 1) infinite;
}
@keyframes mct-carry {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}
.mct-path.off .rail {
  background-color: var(--mct-border);
}
.mct-path.off .node {
  color: var(--mct-text-dim);
  background: color-mix(in srgb, var(--mct-text) 6%, transparent);
}

/* At the grid's narrow end, give the sources their own row instead of
   shaving every label down to a few characters. The destination stays on
   the rail below, and a crowd of sources wraps inside the panel. */
@container (max-width: 400px) {
  .mct-path {
    display: grid;
    grid-template-columns: minmax(16px, 1fr) minmax(0, auto);
    gap: 8px 10px;
  }
  .mct-path .chips {
    flex-wrap: wrap;
    grid-column: 1 / -1;
  }
  .mct-path .rail {
    min-width: 0;
    width: 100%;
  }
}

/* --- the console register --------------------------------------------------
   Operator surfaces (UI_GUIDELINES: "Operator consoles are full-bleed"): the
   dashboard's admin console, a service's standalone console. Structure goes
   flat — a rail flush to the viewport edge, hairlines instead of cards, mono
   micro-labels, display-font heads — while every control keeps its glass.
   Glass on glass has no hierarchy in it, so a console's own bands stay flat
   and only the inspector floats. Lay a page out with <Console>; the classes
   below restyle the shared components only inside that scope. */
.mct-console {
  display: grid;
  align-items: stretch;
}
.mct-console-rail {
  /* One row height, named once: the rows are laid out on it and the capsule
     that marks the current one travels by it. Two copies of 42px would drift
     apart the first time somebody tunes the rail. */
  --rail-row: 42px;
  border-bottom: 1px solid var(--mct-border);
  min-width: 0;
  padding: 0 10px 12px;
}
.mct-console-label {
  color: var(--mct-text-dim);
  display: block;
  font-family: var(--mct-font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  padding: 18px 8px 9px;
  text-transform: uppercase;
}
/* A collapsible rail group: its label is the summary, wearing the same mono
   micro-label as .mct-console-label plus the accent triangle every
   Collapsible turns. The word and the triangle are the whole control — a
   rail draws lines, not boxes. */
.mct-railgroup > summary {
  align-items: center;
  color: var(--mct-text-dim);
  cursor: pointer;
  display: flex;
  font-family: var(--mct-font-mono);
  font-size: 9px;
  font-weight: 700;
  gap: 7px;
  letter-spacing: 0.12em;
  list-style: none;
  padding: 18px 8px 9px;
  text-transform: uppercase;
  user-select: none;
}
.mct-railgroup > summary::-webkit-details-marker {
  display: none;
}
.mct-railgroup > summary::after {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--mct-accent);
  content: "";
  flex: none;
  height: 0;
  transition: transform 0.15s;
  width: 0;
}
.mct-railgroup:not([open]) > summary::after {
  transform: rotate(-90deg);
}
.mct-railgroup > summary:hover {
  color: var(--mct-text);
}
.mct-railgroup > summary:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}

/* the rail's own header: its name, and the control that narrows it */
.mct-console-rail > .head {
  align-items: center;
  display: flex;
  gap: 8px;
  justify-content: space-between;
}
/* Three bars that become a rail: the button says "this column", not
   "hamburger menu", and it is drawn in the same hairline as every rule
   around it. */
.mct-railtoggle {
  align-items: center;
  background: transparent;
  border: 0;
  color: var(--mct-text-dim);
  cursor: pointer;
  display: inline-flex;
  flex: none;
  height: 28px;
  justify-content: center;
  margin-top: 9px;
  padding: 0;
  width: 28px;
}
.mct-railtoggle:hover {
  color: var(--mct-text);
}
.mct-railtoggle:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}
.mct-railtoggle > span {
  border-left: 2px solid currentColor;
  border-right: 6px double currentColor;
  display: block;
  height: 13px;
  width: 13px;
  transition: transform 160ms ease;
}
.mct-railtoggle[aria-expanded="false"] > span {
  transform: scaleX(-1);
}
@media (min-width: 1024px) {
  .mct-console {
    grid-template-columns: 220px minmax(0, 1fr);
    /* The rail narrows, it does not jump. Animating the track itself is what
       keeps the whole thing together: the rail's right edge, the content's
       left edge and every row inside travel on one clock, so there is nothing
       left to synchronise by hand. Both states are a length and a minmax of
       the same two tracks, which is what makes it interpolable at all. */
    transition: grid-template-columns 320ms var(--mct-ease);
  }
  /* one view, no rail: the content takes the whole width */
  .mct-console.solo {
    grid-template-columns: minmax(0, 1fr);
  }
  /* narrowed to its icons — the navigation stays reachable, the content gets
     the other 156px back. Only the wide layout has a width to give. */
  .mct-console.tight {
    grid-template-columns: 64px minmax(0, 1fr);
  }
  /* No side padding, and no reserved gutter, once the rail is down to its
     icons: at 64px both are the difference between a capsule that is round and
     one that is a squeezed lozenge. There is nothing to switch mid-collapse
     either — the rail reserves no gutter in either state, so nothing here has
     to change discretely and the inset travels on the same 320ms clock as the
     track it sits in. */
  .mct-console.tight .mct-console-rail {
    padding: 0 0 18px;
  }
  .mct-console.tight .mct-console-rail > .head {
    justify-content: center;
  }
  /* a group's triangle stays reachable when the rail narrows; only its word
     is clipped below, so the group can still be opened from an icon rail */
  .mct-console.tight .mct-railgroup > summary {
    justify-content: center;
    padding: 14px 0 7px;
  }
  /* The rail's name and each row's word leave the layout without leaving the
     accessibility tree — `display: none` would take them off both, and a clip
     to 1px snaps where the rail glides. Width to nothing on the rail's clock,
     opacity to nothing faster, so the words are gone before the space they
     were in is. `max-width` because a width cannot animate to or from `auto`;
     160px is past the longest label the rail carries. */
  .mct-console-rail .mct-console-label,
  .mct-console-rail .mct-railgroup > summary .label,
  .mct-console-rail .mct-sidenav .mct-btn .label {
    max-width: 160px;
    overflow: hidden;
    white-space: nowrap;
    transition: max-width 320ms var(--mct-ease), opacity 160ms var(--mct-ease),
      padding 320ms var(--mct-ease);
  }
  .mct-console.tight .mct-console-label,
  .mct-console.tight .mct-railgroup > summary .label,
  .mct-console.tight .mct-sidenav .mct-btn .label {
    max-width: 0;
    opacity: 0;
    padding-inline: 0;
  }
  /* the gap goes with the word: 10px of it behind a zero-width label would
     shove every centred icon half a gap off its row */
  .mct-console.tight .mct-sidenav .mct-btn {
    gap: 0;
    justify-content: center;
    min-width: 0;
    padding: 0;
  }
  /* The row still spans the rail — it has to, or the icon would jump to the
     middle of a 220px track at the start of the collapse instead of gliding
     in with it — so its hover wash would be a band the width of the rail
     behind a disc the width of a row. At 64px the icon lighting up is the
     whole of the hover; the disc belongs to the current section alone. */
  .mct-console.tight .mct-sidenav .mct-btn:hover {
    background: none;
  }
  .mct-console-rail {
    align-self: start;
    border-bottom: 0;
    border-right: 1px solid var(--mct-border);
    box-sizing: border-box;
    height: calc(100vh - var(--mct-topbar-h));
    height: calc(100dvh - var(--mct-topbar-h));
    overflow-y: auto;
    overscroll-behavior-y: contain;
    padding: 0 18px 18px;
    position: sticky;
    /* No reservation, in either state. `scrollbar-gutter` cannot be
       transitioned, so a rail that reserves in one state and not the other
       lands its whole contents sideways in one frame at the start of a 320ms
       glide — and one value throughout cannot be the answer here either,
       because the rail has to survive being 64px wide. On the right only, the
       reservation pulls a narrowed rail's centre off by its own width; on both
       edges it takes ~30px of those 64, leaving 14 for a 42px disc, which is
       how a capsule ends up a lozenge. Reserving nothing is symmetric, costs
       the rail nothing at any width, and leaves nothing to switch. The price
       is a nudge when a console with enough sections to scroll grows a classic
       scrollbar — one platform, one moment, the rail's words 15px to the left.
       Every other scroll container here already pays it. */
    top: var(--mct-topbar-h);
    /* the rail's own inset narrows with it, on the same clock as the track */
    transition: padding 320ms var(--mct-ease);
  }
  /* The rail owns scrolling; its complete navigation stack stays in normal
     flow so section spacing cannot react to the document's scroll position. */
  .mct-console-rail .mct-console-nav {
    align-content: start;
    display: grid;
    gap: 0;
  }
  .mct-console-rail .mct-sidenav {
    display: grid;
    gap: 0;
    position: relative;
    /* Reset SideNav's sticky inset: a relative offset moves the rows outside
       their reserved height, clipping the last row in an open RailGroup. */
    top: auto;
  }
  /* The current section is a capsule of glass that travels to it. The rail
     itself stays flat — glass on glass has no hierarchy in it — so the one
     thing on it that floats is the marker, which is the only thing here that
     actually moves. Same material as every control: the stronger tint and the
     same lit rim, no backdrop-filter of its own (the rail has already blurred
     nothing, and a second blur per frame buys nothing on a 42px pill).

     `--i` is the current row's index, written by SideNav; a rail whose current
     section lives in another group sets no `.on` and draws no capsule. */
  .mct-console-rail .mct-sidenav.on::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: var(--rail-row);
    border-radius: calc(var(--rail-row) / 2);
    background: var(--lq-tint-hi);
    box-shadow: var(--lq-edge);
    pointer-events: none;
    transform: translateY(calc(var(--i, 0) * var(--rail-row)));
    /* longer than a control's 0.18s: this is a heavy thing sliding, and the
       eye is meant to follow it from the row it left to the row it reached */
    transition: transform 420ms var(--mct-ease);
  }
  /* Narrowed, the capsule is a disc around one icon, and it is round because
     it is told to be: a width inherited from the rail is a width at the mercy
     of whatever else is taking room there — a classic scrollbar, a reserved
     gutter, a platform that sizes them differently — and 15px off a 64px rail
     is the difference between a disc and a squeezed lozenge. Clamped to the
     row's own height and centred by auto margins against both offsets, so it
     stays round whatever the rail does, and still narrows with it: the clamp
     only bites for the last stretch of the collapse. */
  .mct-console.tight .mct-console-rail .mct-sidenav.on::before {
    margin-inline: auto;
    max-width: var(--rail-row);
  }
}
/* SideNav wearing the console's flat rows: no fill, no hairline, no box. The
   rows are a list of words on the rail's own surface, and the capsule above
   is what says which one you are on — so nothing here may draw an edge that
   competes with it, and nothing may shift when the capsule arrives.

   `position: relative` puts the words over the capsule rather than under it;
   they are opaque, because translucent type on a moving gradient seen through
   glass is exactly as readable as that sounds. */
.mct-console-rail .mct-sidenav .mct-btn {
  align-items: center;
  background: none;
  border: 0;
  border-radius: calc(var(--rail-row) / 2);
  box-shadow: none;
  color: var(--mct-text-dim);
  display: flex;
  font-size: 14px;
  font-weight: 500;
  height: var(--rail-row);
  min-width: 120px;
  padding: 0 14px;
  position: relative;
  text-align: left;
  transition: color 160ms var(--mct-ease), background-color 160ms var(--mct-ease),
    gap 320ms var(--mct-ease), padding 320ms var(--mct-ease);
}
/* Hover is where the capsule could go, so it wears the faintest version of
   it: a wash in the same shape, no rim, no travel. The old 11px indent is
   gone — a row that slides sideways under a capsule sliding down reads as
   two things fighting. */
.mct-console-rail .mct-sidenav .mct-btn:hover {
  background: color-mix(in srgb, var(--mct-text) 7%, transparent);
  color: var(--mct-text);
}
/* The current section: full-contrast word on the capsule, accent icon. The
   label goes white rather than accent because it is sitting on lit glass now
   and white is what reads there — the accent has moved to the icon, and the
   capsule under it is doing the work colour used to do alone. Declared after
   :hover so pointing at the current row does not wash it. */
.mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] {
  background: none;
  box-shadow: none;
  color: var(--mct-text);
}
/* The icon sits a shade behind its label — it is the row's marker, not its
   content — and comes fully up with the row it belongs to. */
.mct-console-rail .mct-sidenav .mct-btn .icon {
  opacity: 0.65;
  transition: opacity 160ms ease, color 160ms var(--mct-ease);
}
.mct-console-rail .mct-sidenav .mct-btn:hover .icon,
.mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] .icon {
  opacity: 1;
}
.mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] .icon {
  color: var(--mct-accent);
}
@media (max-width: 1023px) {
  /* No capsule where the rail lies down: a horizontal strip of chips has no
     one row height to travel by. The current chip is underlined instead —
     the mark the dashboard's mobile page bar already uses. */
  .mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] {
    box-shadow: inset 0 -2px 0 var(--mct-accent);
    color: var(--mct-accent);
  }
}
/* 20px off the top: the rail's own label starts at 18px, so with nothing here
   the content sat flush against the bar while the rail did not. A page whose
   first child is a ConsoleHead gets its 104px band pushed down by the same
   20px, which it wanted anyway. */
/* Full-bleed, no cap: the content takes whatever the rail leaves it. What
   keeps a wide screen readable is the fields' own proportions (em padding,
   a colour swatch sized to a swatch), not a column of dead space beside the
   work. */
.mct-console-main {
  align-content: start;
  display: grid;
  gap: var(--mct-gap);
  min-width: 0;
  padding: 20px 28px 40px;
}
/* A section's head: mono kicker over a display title, detail under it. */
/* Every console page's head is the same height, and that height is whatever
   its words need: no min-height reserving a 104px band a two-line header
   never fills. Shares its padding with .mct-console-pick below, so a page
   titled by a picker and a page titled by text start on the same line. */
.mct-console-head {
  border-bottom: 1px solid var(--mct-border);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 4px 0 18px;
}
.mct-kicker {
  color: var(--mct-text-dim);
  font-family: var(--mct-font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.mct-console-head h2 {
  font-family: var(--mct-font-display);
  font-size: clamp(24px, 2.5vw, 32px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 5px 0 0;
}
.mct-console-head p {
  color: var(--mct-text-dim);
  font-size: 12px;
  margin: 7px 0 0;
}
/* A page whose subject you choose: the picker IS the heading, rather than a
   13px field hiding under one. Same size and face as a ConsoleHead's title,
   underlined in accent so it reads as the one thing on the page to press.
   The native arrow stays — it is the affordance, and it costs no asset. */
.mct-console-pick {
  border-bottom: 1px solid var(--mct-border);
  display: grid;
  gap: 4px;
  justify-items: start;
  padding: 4px 0 18px;
}
/* The button that commits a page follows you down it: on a form long enough
   to scroll, a Save at the far bottom is a Save you have to go looking for —
   and a setting you changed at the top is a setting you cannot tell is
   unsaved. Sticks to the foot of the viewport while the page is still under
   it, then lands in place at the end. Nothing behind it: the button is a
   solid pill and an Alert carries its own ground, so a tinted band only drew
   a rectangle across the page — inset from both edges and with nothing in it
   but one button — that read as a box for no reason. */
.mct-savebar {
  bottom: 0;
  display: grid;
  gap: 8px;
  justify-items: start;
  margin-top: var(--mct-gap);
  padding: 12px 0;
  position: sticky;
  z-index: 2;
}
/* Under a SaveTogether a block's own bar is left holding nothing but the
   outcome of its last save, and until there is one it is not a row of the
   page — it still carries the band's margin and padding. */
.mct-savebar:empty {
  display: none;
}
/* A settings page's Save (SaveBar / SaveTogether) lives in the top-right
   corner, under the top bar, whatever the scroll (decided 2026-09-24): the
   same place on every page, and never scrolled away from. The <form> stays
   in the page's flow — fields join it by id, so where it sits is free — and
   holds only what a SaveTogether block said about its last save. */
.mct-saveform {
  display: grid;
  gap: 8px;
  justify-items: start;
}
.mct-savedock {
  display: grid;
  gap: 8px;
  justify-items: end;
  max-width: min(420px, calc(100vw - 32px));
  position: fixed;
  right: calc(16px + env(safe-area-inset-right));
  top: calc(var(--mct-topbar-h) + 12px);
  z-index: 14;
}
/* the chat dock owns the right edge while it is open: step left of it */
@media (min-width: 1024px) {
  body:has(.mct-dock:not([hidden])) .mct-savedock {
    right: calc(var(--lq-dock-w) + 36px);
  }
}
/* on a phone the page bar hangs under the top bar: clear it too */
@media (max-width: 640px) {
  .mct-dashboard .mct-savedock {
    top: calc(var(--mct-topbar-h) + 56px);
  }
}
/* The button and, while there is anything to lose, the red line saying so —
   the line first, so the button keeps the corner. */
.mct-savebar-row {
  align-items: center;
  display: flex;
  flex-direction: row-reverse;
  flex-wrap: wrap;
  gap: 12px;
}
.mct-unsaved {
  /* a pill of its own ground: it floats over whatever the page has there */
  background: var(--lq-glass-bg);
  -webkit-backdrop-filter: var(--lq-frost);
  backdrop-filter: var(--lq-frost);
  border-radius: 999px;
  color: var(--mct-danger);
  font-size: 13px;
  font-weight: 600;
  padding: 4px 10px;
}
/* A live preview of something that will be shown somewhere else — an OBS
   browser source, an embed. The chequerboard stands in for whatever it will
   be composited over, because a transparent overlay on a dark box looks like
   a broken overlay. Pointer events off: it is a picture of the thing, not
   the thing, and a stray click inside it would do something invisible. */
.mct-preview {
  border: 1px solid var(--mct-border);
  border-radius: var(--lq-r-well);
  margin: 10px 0 0;
  max-width: 860px;
  overflow: hidden;
}
/* No ground here: a browser paints an iframe's canvas opaque whatever the
   embedded page says, so the previewed page paints its own (requeue's overlay
   does it under ?preview) and anything we put behind would never be seen. */
.mct-preview .stage {
  height: 190px;
}
.mct-preview iframe {
  border: 0;
  display: block;
  height: 100%;
  pointer-events: none;
  width: 100%;
}
.mct-preview figcaption {
  border-top: 1px solid var(--mct-border);
  background: var(--mct-bg);
  color: var(--mct-text-dim);
  font-size: 11px;
  padding: 5px 10px;
}
/* A path that names no page. The numeral is the one loud thing — everything
   else on the page stays quiet, and the way out is a real control rather
   than a sentence saying "go back". */
.mct-notfound {
  display: grid;
  gap: 12px;
  justify-items: start;
  max-width: 54ch;
  padding: clamp(24px, 6vh, 64px) 0;
}
.mct-notfound .numeral {
  color: var(--mct-accent);
  font-family: var(--mct-font-display);
  font-size: clamp(72px, 13vw, 132px);
  font-weight: 700;
  letter-spacing: -0.05em;
  line-height: 0.85;
}
.mct-notfound h2 {
  font-family: var(--mct-font-display);
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 600;
  letter-spacing: -0.03em;
  margin: 4px 0 0;
}
.mct-notfound p {
  line-height: 1.55;
  margin: 0;
}
.mct-notfound .actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 6px;
}

/* --- a channel's public page ----------------------------------------------
   What a viewer opens from chat (apps/channel) — the one surface the toolkit
   shows people who are not its users. Liquid, in the 920px page column: a
   viewer came to read, not to work. */
.mct-page {
  box-sizing: border-box;
  display: grid;
  gap: 32px;
  margin: 0 auto;
  max-width: 920px;
  min-width: 0;
  padding: 40px 24px 64px;
}
@media (max-width: 640px) {
  .mct-page {
    gap: 24px;
    padding: 24px 16px 48px;
  }
}
/* A group on the page is its heading, a line about it, and its cards — one
   gap between them all, rather than margins each piece brings of its own. */
.mct-page > .mct-group {
  display: grid;
  gap: 16px;
  min-width: 0;
  /* a #link to a group (the channel page's #shop) lands its heading below
     the top bar, not under it */
  scroll-margin-top: calc(var(--mct-topbar-h) + 16px);
}
.mct-page > .mct-group > * {
  margin: 0;
}

/* Whose page it is: the picture, the name, the chats they stream to. The
   picture is a disc of the same tinted glass as a control, so a channel with
   no picture shows its initial on the material rather than a hole. */
.mct-channelhead {
  /* the picture's size: the disc, its particle canvas and the initial all
     come from this one number */
  --disc: 176px;
  align-items: center;
  display: flex;
  gap: 28px;
  min-width: 0;
}
.mct-channelhead .picture {
  aspect-ratio: 1;
  background: var(--lq-tint-hi);
  border-radius: 50%;
  box-shadow: var(--lq-edge), var(--lq-cast);
  color: var(--mct-text);
  display: grid;
  flex: none;
  font-family: var(--mct-font-display);
  font-size: calc(var(--disc) * 0.42);
  font-weight: 600;
  object-fit: cover;
  place-items: center;
  width: var(--disc);
}
/* The picture as particles (ParticleLogo, round). The engine draws the image
   across 80/88 of its canvas, so the canvas is a little wider than the disc
   and pulled back by the difference: the picture sits where the plain disc
   would, and a pushed particle has a margin to fly into before the canvas
   edge clips it. */
.mct-channelhead .logo {
  flex: none;
  margin: calc(var(--disc) * -4 / 80);
  width: calc(var(--disc) * 88 / 80);
}
.mct-channelhead .logo .picture {
  margin: calc(var(--disc) * 4 / 80);
}
.mct-channelhead > div:not(.logo) {
  min-width: 0;
}
.mct-channelhead h1 {
  font-family: var(--mct-font-display);
  font-size: clamp(32px, 6vw, 44px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
  margin: 0;
  overflow-wrap: anywhere;
}
/* Where they stream, neutral like every passive platform identifier: an
   address, not a brand. */
.mct-channelhead .where {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 16px;
  margin-top: 8px;
}
.mct-channelhead .where a {
  color: var(--mct-text-dim);
  font-family: var(--mct-font-mono);
  font-size: 14px;
  text-decoration: none;
}
.mct-channelhead .where a:hover {
  color: var(--mct-text);
  text-decoration: underline;
}
.mct-channelhead .where a:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}
@media (max-width: 640px) {
  .mct-channelhead {
    --disc: 120px;
    gap: 18px;
  }
}

/* Commands as a viewer reads them: what to type, what it does, who may, what
   it costs. A row each that wraps rather than a table that scrolls sideways —
   this page is opened from a phone at least as often as not. The tags are
   tinted pills, never glass: there can be dozens of them. */
.mct-cmdindex {
  display: grid;
  list-style: none;
  margin: 0;
  padding: 0;
}
.mct-cmdindex > li {
  display: grid;
  gap: 4px;
  min-width: 0;
  padding: 12px 0;
}
.mct-cmdindex > li:first-child {
  padding-top: 0;
}
.mct-cmdindex > li:last-child {
  padding-bottom: 0;
}
.mct-cmdindex > li + li {
  border-top: var(--mct-border-w) solid var(--mct-border-soft);
}
.mct-cmdindex .use {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  min-width: 0;
}
.mct-cmdindex .use > .mct-code {
  font-size: 15px;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.mct-cmdindex .also {
  color: var(--mct-text-dim);
  font-size: 13px;
}
.mct-cmdindex .tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;
}
.mct-cmdindex .tag {
  background: var(--lq-tint);
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  color: var(--mct-text-dim);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 5px 10px;
  white-space: nowrap;
}
.mct-cmdindex .what {
  color: var(--mct-text-dim);
  font-size: 14px;
  margin: 0;
  overflow-wrap: anywhere;
}

/* The skins shop (SkinIndex): a tile per skin, the drawing on a well over
   its name, blurb and the chat line that buys it. The wells are the one
   place a sprite meant for a stream gets a ground of its own. */
.mct-skinindex {
  display: grid;
  gap: var(--mct-gap);
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}
.mct-skinindex > li {
  display: grid;
  gap: 8px;
  min-width: 0;
}
.mct-skinindex .art {
  align-items: end;
  background: var(--lq-tint);
  border-radius: var(--lq-r-well);
  box-shadow: var(--lq-edge);
  display: grid;
  height: 150px;
  justify-items: center;
  padding-bottom: 18px;
}
.mct-skinindex .art svg {
  display: block;
  filter: drop-shadow(0 8px 10px rgba(0, 0, 0, .45));
  height: 108px;
  overflow: visible;
  width: auto;
}
.mct-skinindex .game-royale .art svg, .mct-skinindex .game-fish .art svg {
  height: 96px;
}
.mct-skinindex .game-heist .art svg, .mct-skinindex .game-race .art svg {
  height: 64px;
}
.mct-skinindex .game-orchard .art svg {
  height: 112px;
}
.mct-skinindex .name {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.mct-skinindex .name b {
  font-weight: 700;
  margin-right: auto;
}
.mct-skinindex .tag {
  background: var(--lq-tint);
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  color: var(--mct-text-dim);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 5px 10px;
  white-space: nowrap;
}
.mct-skinindex .tag.rare { color: #7dd3fc; }
.mct-skinindex .tag.epic { color: #c4b5fd; }
.mct-skinindex .tag.legend { color: #fcd34d; }
.mct-skinindex .tag.ultra { background: rgba(36, 137, 230, .22); color: #bae6fd; }
.mct-skinindex .tag.luck { background: rgba(83, 252, 24, .16); color: var(--mct-kick); }
.mct-skinindex .what {
  color: var(--mct-text-dim);
  font-size: 14px;
  margin: 0;
}
.mct-skinindex .use {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  justify-content: space-between;
}
.mct-skinindex .cost {
  color: var(--mct-warning);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.mct-cmdindex .what a {
  color: var(--mct-accent);
  text-decoration: none;
}
.mct-cmdindex .what a:hover {
  text-decoration: underline;
}

/* Picker — our own dropdown. The trigger is a button, so the focus ring is
   the keyboard's alone; a native select takes it on a mouse click too. */
.mct-picker {
  position: relative;
}
.mct-picker > .trigger {
  align-items: center;
  background: var(--lq-tint-hi);
  border: 0;
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  color: var(--mct-text);
  cursor: pointer;
  display: inline-flex;
  font-family: var(--mct-font-sans);
  font-size: 13px;
  gap: 10px;
  padding: 7px 16px;
  transition: background-color 0.15s var(--mct-ease), color 0.15s var(--mct-ease);
}
.mct-picker > .trigger:hover {
  background: color-mix(in srgb, var(--mct-text) 21%, transparent);
}
.mct-picker > .trigger:focus-visible {
  outline: 2px solid var(--mct-accent);
  outline-offset: 2px;
}
/* a solid triangle in borders — the same one the Collapsible turns */
.mct-picker > .trigger .chev {
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--mct-accent);
  flex: none;
  height: 0;
  margin-left: auto;
  transition: transform 0.15s;
  width: 0;
}
.mct-picker > .trigger[aria-expanded="true"] .chev {
  transform: rotate(180deg);
}
/* Opaque, not glass: a menu has to be readable over whatever it covers, and
   this one covers the page's own content rather than the wallpaper. */
.mct-picker > .list {
  background: color-mix(in srgb, var(--mct-surface) 96%, #fff);
  border: var(--mct-border-w) solid var(--mct-border);
  border-radius: var(--lq-r-well);
  box-shadow: var(--lq-cast);
  display: grid;
  left: 0;
  list-style: none;
  margin: 6px 0 0;
  max-height: 320px;
  min-width: 100%;
  overflow: auto;
  padding: 4px;
  position: absolute;
  top: 100%;
  z-index: 20;
}
.mct-picker > .list li {
  border-radius: calc(var(--lq-r-well) * 0.7);
  color: var(--mct-text);
  cursor: pointer;
  font-family: var(--mct-font-sans);
  font-size: 14px;
  padding: 7px 10px;
  white-space: nowrap;
}
/* one highlight, driven by the keyboard and by the pointer alike, so there is
   never a second row that also looks current */
.mct-picker > .list li.active {
  background: color-mix(in srgb, #fff 9%, transparent);
}
.mct-picker > .list li[aria-selected="true"] {
  color: var(--mct-accent);
  font-weight: 600;
}

/* The title variant: the picker is the page's heading, so the trigger wears
   the heading's face and an accent underline instead of a field's box. */
.mct-picker.title > .trigger {
  background: none;
  border: 0;
  border-bottom: 2px solid var(--mct-accent);
  border-radius: 0;
  box-shadow: none;
  font-family: var(--mct-font-display);
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 600;
  gap: 14px;
  letter-spacing: -0.03em;
  padding: 2px 2px 5px 0;
}
.mct-picker.title > .trigger:hover {
  background: none;
  color: var(--mct-accent);
}
.mct-picker.title > .trigger .chev {
  border-left-width: 6px;
  border-right-width: 6px;
  border-top-width: 8px;
}

/* Stats become a metrics row: bordered cells, the label above the number. */
.mct-console .mct-stats {
  border-bottom: 1px solid var(--mct-border);
  display: grid;
  gap: 0;
  grid-auto-columns: minmax(128px, 1fr);
  grid-auto-flow: column;
  overflow-x: auto;
}
.mct-console .mct-stat {
  border-right: 1px solid var(--mct-border);
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  justify-content: flex-end;
  min-width: 0;
  padding: 18px 16px;
}
.mct-console .mct-stat:last-child {
  border-right: 0;
}
.mct-console .mct-stat .value {
  font-family: var(--mct-font-sans);
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.05em;
  line-height: 1.15;
}
.mct-console .mct-stat .label {
  font-family: var(--mct-font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Group and Section titles read as console panel titles. */
.mct-console .mct-group > h3,
.mct-console .mct-section > h4 {
  border-bottom: 1px solid var(--mct-border-soft);
  color: var(--mct-text);
  font-family: var(--mct-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  margin: 0 0 10px;
  padding: 0 0 8px;
  text-transform: uppercase;
}
/* Tables: mono uppercase header, hairline rows, row hover. */
.mct-console .mct-table {
  font-size: 12px;
}
.mct-console .mct-table th {
  border-bottom: 1px solid var(--mct-border);
  font-family: var(--mct-font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.07em;
  padding: 10px 12px;
  text-transform: uppercase;
}
.mct-console .mct-table td {
  border-bottom: 1px solid var(--mct-border-soft);
  padding: 10px 12px;
}
.mct-console .mct-table tbody tr:hover {
  background: color-mix(in srgb, #fff 5%, transparent);
}
/* The inspector: the one thing on a console page that floats, so it is the one
   thing here wearing the glass (declared with the other surfaces above). */
.mct-console-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.mct-console-panel > header {
  align-items: center;
  border-bottom: 1px solid var(--mct-border-soft);
  display: flex;
  gap: 12px;
  justify-content: space-between;
  min-height: 54px;
  padding: 10px 14px;
}
.mct-console-panel > header h3 {
  font-family: var(--mct-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}
.mct-console-panel > .body {
  padding: 14px;
}
/* Collapsibles flatten to a band: full-strength rules top and bottom (the
   list rows around it use the soft hairline, so the band reads as its own
   thing), dim until hovered or open. The accent chevron stays. */
.mct-console .mct-collapse {
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  border-bottom: 1px solid var(--mct-border);
  border-radius: 0;
  border-top: 1px solid var(--mct-border);
  box-shadow: none;
}
.mct-console .mct-collapse::after {
  display: none;
}
.mct-console .mct-collapse > summary {
  color: var(--mct-text-dim);
  font-family: var(--mct-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 11px 0;
  border-radius: 0;
  text-transform: uppercase;
  transition: color 160ms var(--mct-ease);
}
.mct-console .mct-collapse > summary:hover {
  background: none;
  color: var(--mct-text);
}
.mct-console .mct-collapse[open] > summary {
  border-bottom: 1px solid var(--mct-border-soft);
  border-radius: 0;
  color: var(--mct-text);
}
.mct-console .mct-collapse > summary .note {
  font-family: var(--mct-font-mono);
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.05em;
}
.mct-console .mct-collapse > .body {
  padding: 12px 0;
}

/* --- the Plan page's two controls ----------------------------------------
   Clerk's markup, and until here Clerk's paint: told the accent, it fills the
   Subscribe button and the annual-billing track with flat rose. Flat is the
   tell. Every other control in the app is a material — the button is glass
   over a dark anchor throwing its own colour down, the switch is a channel
   cut into the glass with a lens riding in it — and two flat lozenges in the
   middle of that read as a widget someone dropped in.

   So these two are built here rather than named to Clerk, from the same
   declarations .mct-btn.primary and .mct-switch are built from. Everything
   that is only a colour or a typeface still goes through clerkLook(), where
   Clerk can do its own maths on it.

   Each selector carries one step more than it looks like it needs. Clerk
   injects its stylesheet after ours and writes its own rules two and three
   classes deep (`.cl-internal-x[data-variant][data-color]`), so a rule that
   merely ties on specificity loses. */
.mct-plan.mct-plan button.cl-pricingTableCardFooterButton {
  --mct-fill: var(--mct-accent);
  background-color:
    color-mix(in srgb, color-mix(in srgb, var(--mct-fill) 98%, #000) 92%, transparent);
  border: 0;
  border-radius: var(--lq-r-control);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 10%, transparent),
    0 10px 26px -12px var(--mct-fill);
  color: var(--mct-on-accent);
  font-family: var(--mct-font-sans);
  font-size: 14px;
  font-weight: 600;
  min-height: 42px;
  transition-property: transform, box-shadow, background-color;
  transition-duration: 0.18s;
  transition-timing-function: var(--mct-ease);
}
.mct-plan.mct-plan button.cl-pricingTableCardFooterButton:hover:not(:disabled) {
  background-color: var(--mct-fill);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 48%, transparent),
    0 14px 32px -10px var(--mct-fill);
  filter: brightness(1.04);
}
/* Glass compresses, here as everywhere else. */
.mct-plan.mct-plan button.cl-pricingTableCardFooterButton:active:not(:disabled) {
  transform: scale(0.97);
}
/* Under the pointer a card rises a little and its rim brightens — the same
   thing a piece of glass does when you lift it off the page, and the only
   motion on a page that is otherwise a row of three quiet slabs. Transform
   and box-shadow, so it is compositor work and the text never reflows; the
   transition sits on the card rather than on the hover, so it settles back
   as slowly as it rose.
   No hover state at all where the pointer is a finger: a touch device
   resolves :hover by leaving it stuck on whatever was last tapped. */
@media (hover: hover) {
  .mct-plan.mct-plan .cl-pricingTableCard {
    transition: box-shadow 0.28s var(--mct-ease), transform 0.28s var(--mct-ease);
  }
  .mct-plan.mct-plan .cl-pricingTableCard:hover {
    box-shadow:
      inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
      inset 0 -1px 0 color-mix(in srgb, #fff 8%, transparent),
      inset 0 6px 14px -8px color-mix(in srgb, #000 55%, transparent),
      0 26px 54px -20px color-mix(in srgb, #000 80%, transparent);
    transform: translateY(-3px);
  }
  /* the current one keeps its accent rim on the way up, and its glow with it */
  .mct-plan.mct-plan .cl-pricingTableCard:has(.cl-badge):hover {
    box-shadow:
      inset 0 0 0 1px var(--mct-accent),
      var(--lq-edge),
      0 26px 54px -20px color-mix(in srgb, #000 80%, transparent),
      0 26px 54px -22px var(--mct-accent);
  }
}
/* Motion is the decoration here, not the information — the rim and the glow
   say which card is yours without it. */
@media (prefers-reduced-motion: reduce) {
  .mct-plan.mct-plan .cl-pricingTableCard {
    transition: none;
  }
  .mct-plan.mct-plan .cl-pricingTableCard:hover {
    transform: none;
  }
}
/* The plan you are on, said twice: a chip in the header, and a control-shaped
   block where the other cards keep their Subscribe.

   The chip is the loud one — this is the single fact the page exists to tell
   you, and Clerk's default for it is a quiet grey pill. It takes the accent
   fill rather than a tint of it: a state, in the colour of the thing it is a
   state of.

   The block below is not a button. Clerk renders that card's footer slot
   empty — nothing to press on a plan you already have — which left its
   features floating at a different height from its neighbours' and the whole
   row looking accidentally ragged. So the slot is given the footer's own
   border and padding, and a pill of neutral glass with dim text sits in it:
   the shape says "this row has a control", the colour says "not for you to
   press". Both cards' feet are drawn from this one rule, so they cannot
   drift apart. */
.mct-plan.mct-plan .cl-pricingTableCard .cl-badge {
  background-color:
    color-mix(in srgb, color-mix(in srgb, var(--mct-accent) 98%, #000) 92%, transparent);
  border: 0;
  border-radius: var(--lq-r-control);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 48%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 10%, transparent),
    0 8px 20px -12px var(--mct-accent);
  color: var(--mct-on-accent);
  font-family: var(--mct-font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  padding: 6px 13px;
  text-transform: uppercase;
}
/* And the card it sits in takes an accent rim — the same move a panel makes
   when you pick it up: the rim goes accent, and the glass underneath is left
   exactly as it was. Stated as the first shadow in the stack, ahead of the
   edge and the cast rather than instead of them, because the lit bevel is
   what the material is; a border would sit outside it as a drawn frame and
   push the card a pixel wider than its neighbours. The glow at the end is
   the rim's own colour reaching the page, which is what tells the row apart
   at a glance rather than on inspection. */
.mct-plan.mct-plan .cl-pricingTableCard:has(.cl-badge) {
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--mct-accent) 78%, transparent),
    var(--lq-edge),
    var(--lq-cast),
    0 20px 46px -26px var(--mct-accent);
}
.mct-plan.mct-plan .cl-pricingTableCardFooter,
.mct-plan.mct-plan .cl-pricingTableCardBody > div:last-child:not(.cl-pricingTableCardFooter) {
  border-top: 1px solid var(--mct-border-soft);
  margin-top: auto;
  padding: 16px 20px;
}
.mct-plan.mct-plan
  .cl-pricingTableCardBody > div:last-child:not(.cl-pricingTableCardFooter)::after {
  align-items: center;
  background: var(--lq-tint-hi);
  border-radius: var(--lq-r-control);
  box-shadow: var(--lq-edge);
  color: var(--mct-text-dim);
  content: "Current plan";
  display: flex;
  font-family: var(--mct-font-sans);
  font-size: 14px;
  font-weight: 600;
  justify-content: center;
  min-height: 42px;
}
/* The switch: Clerk's three boxes (root, indicator, thumb) doing the job our
   own label/track/::after does. The knob is a real element here rather than a
   pseudo one, which is the only difference that reaches the declarations —
   the lighting, the travel and the 3px of channel showing on every side are
   the switch's, unchanged. */
.mct-plan.mct-plan .cl-switchRoot .cl-switchIndicator {
  background: color-mix(in srgb, #000 38%, transparent);
  border: 0;
  border-radius: var(--lq-r-control);
  box-sizing: content-box;
  box-shadow:
    inset 0 2px 6px -2px color-mix(in srgb, #000 85%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #fff 14%, transparent);
  flex: none;
  height: 28px;
  position: relative;
  transition: background-color 0.22s var(--mct-ease), box-shadow 0.22s var(--mct-ease);
  width: 50px;
}
.mct-plan.mct-plan .cl-switchRoot .cl-switchIndicator[data-checked="true"] {
  background: var(--mct-success);
  box-shadow:
    inset 0 1.5px 0 color-mix(in srgb, #fff 42%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 22%, transparent),
    0 6px 18px -8px var(--mct-success);
}
.mct-plan.mct-plan .cl-switchRoot .cl-switchThumb {
  background:
    radial-gradient(circle at 34% 26%,
      #fff 0%,
      color-mix(in srgb, var(--mct-text-dim) 35%, #fff) 42%,
      var(--mct-text-dim) 100%);
  border-radius: 50%;
  box-shadow:
    inset 0 1.5px 1px color-mix(in srgb, #fff 75%, transparent),
    inset 0 -2px 3px color-mix(in srgb, #000 28%, transparent),
    0 2px 6px -1px color-mix(in srgb, #000 75%, transparent);
  height: 22px;
  left: 3px;
  position: absolute;
  top: 3px;
  transform: none;
  transition: transform 0.26s cubic-bezier(.16, 1, .3, 1), background 0.2s;
  width: 22px;
}
.mct-plan.mct-plan .cl-switchRoot .cl-switchIndicator[data-checked="true"] .cl-switchThumb {
  background:
    radial-gradient(circle at 34% 26%,
      #fff 0%,
      #fff 45%,
      color-mix(in srgb, #fff 86%, var(--mct-success)) 100%);
  transform: translateX(22px);
}

/* The Plan page, unpanelled: the console head titles it, so what is left is a
   standing, two sentences and the ladder, stacked. The button sits on the
   plan's own baseline rather than in a header band above it — it is the one
   thing you can do here, and it belongs beside the thing it changes. */
.mct-planpage {
  display: grid;
  gap: 12px;
  justify-items: start;
}
.mct-planpage .standing {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  margin-bottom: 4px;
}
.mct-planpage .standing .who {
  display: grid;
  gap: 4px;
}
.mct-planpage .standing .plan {
  font-family: var(--mct-font-sans);
  font-size: 28px;
  font-weight: 500;
  letter-spacing: -0.05em;
  line-height: 1.1;
}
.mct-planpage .standing .plan.accent {
  color: var(--mct-accent);
}
/* A ceiling and what is left of it, at the far end of the same line as the
   plan it belongs to. First one takes the gap so a second pool joining later
   queues beside it rather than pushing the row apart again; on a narrow
   screen the row wraps and the margin collapses to nothing. */
.mct-planpage .standing .meter {
  margin-left: auto;
}
/* ...the FIRST one only — :first-of-type would look at the element type, and
   the plan's own block is a span too. A second pool queues beside the first
   instead of being pushed to the other end of the row. */
.mct-planpage .standing .meter ~ .meter {
  margin-left: 0;
}
.mct-planpage .standing .meter .mct-plan-meter {
  margin-top: 0;
}
.mct-planpage .standing .meter .bar {
  max-width: 100%;
  width: 160px;
}
.mct-planpage .mct-tablewrap {
  justify-self: stretch;
  margin-top: 8px;
}

/* The plan ladder's table: a cell in a better plan that differs from the one
   you are on is the whole point of the column, so it is the only thing on
   the row drawn at full strength in the accent. */
.mct-plan-more {
  color: var(--mct-accent);
  font-weight: 600;
}
/* Every plan is on the table now, so the one you HOLD has to be findable at a
   glance: a lit column rather than a word in its heading. A tint down the
   whole run of cells, and the heading carries the bright rim that says where
   the column starts. Background only — the values in it are the same values,
   and colouring them would collide with the accent that means "you'd gain
   this". */
.mct-table td.mct-plan-yours,
.mct-table th:has(> .mct-plan-yours) {
  background: color-mix(in srgb, var(--mct-text) 6%, transparent);
  /* wider than the columns beside it, which is what pulls the lit edge out
     past the words rather than letting it start on top of them */
  padding-left: 22px;
  padding-right: 22px;
}
.mct-table th > .mct-plan-yours {
  color: var(--mct-text);
}
/* The heading is the top of the card, not a label floating above it — the
   column starts where its name does. */
.mct-table th:has(> .mct-plan-yours) {
  /* and the head's rule stops at it: a line across the top of the card would
     read as the card being cut off rather than as the table's own header
     underline continuing behind it */
  border-bottom: 0;
  border-top-left-radius: var(--lq-r-well);
  border-top-right-radius: var(--lq-r-well);
  padding-top: 12px;
}
.mct-table tr:last-child td.mct-plan-yours {
  border-bottom-left-radius: var(--lq-r-well);
  border-bottom-right-radius: var(--lq-r-well);
}
/* The foot of each column: the way onto it. No hairline above the row — the
   buttons are not another record in the list. */
.mct-table tr.mct-plan-actions td,
.mct-table tr.mct-plan-actions th {
  border-bottom: 0;
  padding-top: 14px;
}
/* How much of a ceiling is spent, under the ceiling itself. The bar is the
   glance; the number beside it is the answer, and the one a screen reader
   gets — the bar is aria-hidden. */
.mct-plan-meter {
  align-items: center;
  display: flex;
  font-size: 12px;
  gap: 6px;
  margin-top: 4px;
}
.mct-plan-meter .bar {
  background: color-mix(in srgb, var(--mct-text) 14%, transparent);
  border-radius: 999px;
  flex: 1 1 auto;
  height: 4px;
  max-width: 90px;
  overflow: hidden;
}
.mct-plan-meter .bar > span {
  background: var(--mct-accent);
  border-radius: inherit;
  display: block;
  height: 100%;
}

/* --- dashboard on phones -------------------------------------------------
   The desktop board is projected, never rewritten: one full-width panel per
   row, a horizontal page register, and controls sized for a thumb. */
@media (max-width: 640px) {
  .mct-dashboard {
    min-width: 0;
    --mct-topbar-h: calc(54px + env(safe-area-inset-top));
  }
  .mct-dashboard .mct-topbar {
    box-sizing: border-box;
    flex-wrap: nowrap;
    min-height: var(--mct-topbar-h);
    padding-left: calc(12px + env(safe-area-inset-left));
    padding-right: calc(12px + env(safe-area-inset-right));
    padding-top: calc(8px + env(safe-area-inset-top));
  }
  .mct-dashboard .mct-topbar .brand {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .mct-dashboard .mct-topbar .brand-icon {
    width: 36px;
    height: 36px;
  }
  .mct-dashboard .mct-topbar .right {
    flex: 0 1 auto;
    min-width: 0;
  }
  .mct-dashboard .mct-topbar .right .mct-select {
    font-size: 16px; /* avoids focus zoom in mobile Safari */
    max-width: 32vw;
  }

  /* The desktop rail becomes a sticky, horizontally scrollable page bar. */
  .mct-dashboard .mct-console-rail {
    /* frosted, not opaque: the page bar is stuck over the gradient, and a slab
       of the page's ground there reads as a hole rather than as a bar */
    background: var(--lq-glass-bg);
    -webkit-backdrop-filter: var(--lq-frost);
    backdrop-filter: var(--lq-frost);
    border-bottom-color: var(--mct-border);
    padding-left: calc(12px + env(safe-area-inset-left));
    padding-right: calc(12px + env(safe-area-inset-right));
    position: sticky;
    top: var(--mct-topbar-h);
    z-index: 12;
  }
  .mct-dashboard .mct-console-rail > .head {
    display: none;
  }
  .mct-dashboard .mct-console-nav {
    min-width: 0;
    overflow: hidden;
  }
  .mct-dashboard .mct-console-rail .mct-sidenav {
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .mct-dashboard .mct-console-rail .mct-sidenav::-webkit-scrollbar {
    display: none;
  }
  .mct-dashboard .mct-console-rail .mct-sidenav {
    display: flex;
    gap: 0;
    position: static;
  }
  .mct-dashboard .mct-console-rail .mct-sidenav .mct-btn,
  .mct-dashboard .mct-console-rail .mct-sidenav .mct-btn:hover,
  .mct-dashboard .mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] {
    box-shadow: none;
    flex: none;
    height: 44px;
    min-width: auto;
    padding: 0 12px;
  }
  .mct-dashboard .mct-console-rail .mct-sidenav .mct-btn[aria-current="page"] {
    box-shadow: inset 0 -2px 0 var(--mct-accent);
  }
  .mct-dashboard .mct-console-main {
    gap: 12px;
    padding: 12px calc(12px + env(safe-area-inset-right))
      calc(76px + env(safe-area-inset-bottom))
      calc(12px + env(safe-area-inset-left));
  }

  /* Keep the one-cell header while giving its remaining controls the whole
     available band. Titles ellipsize before controls are ever squeezed. */
  .mct-dashboard .mct-board.mobile .mct-panel > header {
    gap: 6px;
    padding: 2px 10px;
  }
  .mct-dashboard .mct-board.mobile .mct-panel > header .title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .mct-dashboard .mct-board.mobile .mct-panel > header .status,
  .mct-dashboard .mct-board.mobile .mct-panel > header .control {
    flex: none;
  }
  .mct-dashboard .mct-board.mobile .mct-iconbtn {
    height: 32px;
    width: 32px;
  }
  .mct-dashboard .mct-board.mobile .mct-panel > .body {
    padding: 12px;
  }

  .mct-dashboard .mct-input,
  .mct-dashboard .mct-select {
    font-size: 16px; /* avoids focus zoom in mobile Safari */
  }
  .mct-dashboard .mct-console-head,
  .mct-dashboard .mct-console-pick {
    padding-bottom: 14px;
  }
  .mct-dashboard .mct-preview .stage {
    height: 140px;
  }
  .mct-dashboard .mct-modal {
    max-height: calc(100dvh - 16px);
    width: calc(100vw - 16px);
  }
  .mct-dashboard .mct-modal > .body {
    overscroll-behavior: contain;
  }
  .mct-dashboard .mct-fab {
    bottom: calc(12px + env(safe-area-inset-bottom));
    height: 48px;
    right: calc(12px + env(safe-area-inset-right));
    width: 48px;
  }
  .mct-dashboard .mct-perf-fab {
    left: calc(12px + env(safe-area-inset-left));
    right: auto;
  }
  .mct-dashboard .mct-perf-pop {
    inset: auto auto calc(72px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
  }
}

/* --- motion ---------------------------------------------------------------
   Three jobs and no fourth:
     arrival — one staggered entrance when a surface first exists
     answer  — every control responds to a pointer or a key
     state   — the one thing that runs on its own says the service is live
   Nothing decorative loops. Nothing animates on scroll. */

/* One entrance, when a surface first exists: panels, groups and stats rise a
   little as they mount. A panel that appears later (a service coming back, a
   board being added to) animates then, because that IS when it arrived. */
@keyframes mct-arrive {
  from { opacity: 0; transform: translateY(9px); }
}
.mct-board > *, .mct-grid > *, .mct-stats > *, .mct-page > *,
.mct-console-panel, .mct-alert {
  animation: mct-arrive 0.46s var(--mct-ease) backwards;
}
/* The stagger stays under a fifth of a second end to end: enough to read as
   one movement with an order to it, not as a page assembling itself. */
.mct-board > :nth-child(2), .mct-grid > :nth-child(2),
.mct-stats > :nth-child(2), .mct-page > :nth-child(2) { animation-delay: 0.05s; }
.mct-board > :nth-child(3), .mct-grid > :nth-child(3),
.mct-stats > :nth-child(3), .mct-page > :nth-child(3) { animation-delay: 0.1s; }
.mct-board > :nth-child(4), .mct-grid > :nth-child(4),
.mct-stats > :nth-child(4), .mct-page > :nth-child(4) { animation-delay: 0.15s; }
.mct-board > :nth-child(n + 5), .mct-grid > :nth-child(n + 5),
.mct-stats > :nth-child(n + 5), .mct-page > :nth-child(n + 5) { animation-delay: 0.18s; }

/* A disclosure that snaps open is the cheapest-feeling control on a page.
   Chrome 129+ can interpolate the content box; everywhere else this block is
   skipped and the details element behaves exactly as it does today. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .mct-collapse::details-content,
  .mct-railgroup::details-content {
    block-size: 0;
    overflow: clip;
    transition: block-size 0.34s var(--mct-ease), content-visibility 0.34s allow-discrete;
  }
  .mct-collapse[open]::details-content,
  .mct-railgroup[open]::details-content { block-size: auto; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation: none !important;
  }
  /* the rail still has to say "live" without moving */
  .mct-path:not(.off) .rail::after {
    background: var(--mct-accent);
    opacity: 0.5;
  }
  /* and the hold-to-drag bar still has to show the hold completed */
  .mct-boarditem.mobile-drag-holding .mct-panel > header .mct-grip::after {
    transform: scaleX(1);
  }
}
/* The same, as a switch: low power mode (liquid.js) is reduced motion and
   reduced transparency together, chosen from the account menu rather than
   the OS. Restated rather than shared because a media query cannot carry an
   attribute selector. */
:root[data-perf="low"] *,
:root[data-perf="low"] *::before,
:root[data-perf="low"] *::after {
  transition-duration: 0.01ms !important;
  animation: none !important;
}
:root[data-perf="low"] .mct-path:not(.off) .rail::after {
  background: var(--mct-accent);
  opacity: 0.5;
}
:root[data-perf="low"] .mct-boarditem.mobile-drag-holding .mct-panel > header .mct-grip::after {
  transform: scaleX(1);
}
.mct-particle-logo { width: 100%; aspect-ratio: 1; display: grid; place-items: center; }
/* Touching the logo is an interaction, not a text/image selection gesture. */
.mct-particle-logo, .mct-particle-logo * {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.mct-particle-logo canvas, .mct-particle-logo img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
}
/* Gestures beginning on the canvas play with the logo; the surrounding
   panel and page remain available for scrolling. */
.mct-particle-logo canvas { cursor: pointer; touch-action: none; }
.mct-particle-logo canvas[hidden] { display: none; }
/* a profile picture: its plain fallback is a disc too, inset the way the
   particles are (80 of 88) */
.mct-particle-logo.round img { border-radius: 50%; width: calc(100% * 80 / 88); }
.mct-particle-logo canvas:focus-visible { outline: 2px solid var(--mct-accent); outline-offset: 2px; }
.mct-logo-empty {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  text-align: center;
  color: var(--mct-text-dim);
  font-size: 13px;
}

/* The emote picker: a button, and under it a well of emotes to click into
   the reply. A well, not glass — it is part of the field it types into. */
.mct-emotes {
  display: grid;
  gap: 8px;
  justify-items: start;
  min-width: 0;
}
.mct-emotes-well {
  display: grid;
  gap: 8px;
  width: 100%;
  box-sizing: border-box;
  padding: 10px;
  border-radius: var(--lq-r-well);
  background: color-mix(in srgb, #000 18%, transparent);
  border: var(--mct-border-w) solid var(--mct-border-soft);
}
.mct-emotes-list {
  display: grid;
  gap: 10px;
  max-height: 260px;
  overflow-y: auto;
}
.mct-emotes-list h4 {
  margin: 0 0 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--mct-text-dim);
}
.mct-emotes-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
}
.mct-emotes-grid button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  cursor: pointer;
  transition: background-color 0.15s var(--mct-ease);
}
.mct-emotes-grid button:hover,
.mct-emotes-grid button:focus-visible {
  background: color-mix(in srgb, var(--mct-text) 12%, transparent);
}
/* a sub emote the sender may not hold: still offered, visibly less certain */
.mct-emotes-grid button.needs-sub img {
  opacity: 0.55;
}
.mct-emotes-well p {
  margin: 0;
  font-size: 12px;
}
