/* MixNight UI. Built by ui/scripts/bundle.mjs from ui/src. */
/* Generated from ui/tokens/tokens.json by scripts/build-tokens.mjs. Do not edit by hand. */
:root{
  --mn-fs-2xs:0.6875rem;
  --mn-fs-xs:0.75rem;
  --mn-fs-sm:0.8125rem;
  --mn-fs-md:0.875rem;
  --mn-fs-base:0.9375rem;
  --mn-fs-lg:1.125rem;
  --mn-fs-xl:1.375rem;
  --mn-fs-2xl:1.75rem;
  --mn-fs-display:clamp(2.75rem, 6.5vw, 5.5rem);
  --mn-fw-regular:400;
  --mn-fw-medium:500;
  --mn-fw-semibold:600;
  --mn-fw-display:700;
  --mn-badge-size:var(--mn-fs-2xs); --mn-badge-weight:var(--mn-fw-medium); --mn-badge-line:1;
  --mn-caption-size:var(--mn-fs-xs); --mn-caption-weight:var(--mn-fw-regular); --mn-caption-line:1.3;
  --mn-meta-size:var(--mn-fs-sm); --mn-meta-weight:var(--mn-fw-regular); --mn-meta-line:1.35;
  --mn-label-size:var(--mn-fs-md); --mn-label-weight:var(--mn-fw-medium); --mn-label-line:1.2;
  --mn-body-size:var(--mn-fs-base); --mn-body-weight:var(--mn-fw-regular); --mn-body-line:1.45;
  --mn-name-size:var(--mn-fs-md); --mn-name-weight:var(--mn-fw-semibold); --mn-name-line:1.2;
  --mn-subhead-size:var(--mn-fs-lg); --mn-subhead-weight:var(--mn-fw-semibold); --mn-subhead-line:1.25;
  --mn-title-size:var(--mn-fs-xl); --mn-title-weight:var(--mn-fw-semibold); --mn-title-line:1.15;
  --mn-page-size:var(--mn-fs-2xl); --mn-page-weight:var(--mn-fw-semibold); --mn-page-line:1.1;
  --mn-display-size:var(--mn-fs-display); --mn-display-weight:var(--mn-fw-display); --mn-display-line:0.98;
  --mn-rad-ctl:0.625rem;
  --mn-rad-card:1.25rem;
  --mn-rad-thumb:0.625rem;
  --mn-rad-sheet:2.25rem;
  --mn-rad-pill:999px;
  --mn-space-1:0.25rem;
  --mn-space-2:0.5rem;
  --mn-space-3:0.75rem;
  --mn-space-4:1rem;
  --mn-space-5:1.25rem;
  --mn-space-6:1.5rem;
  --mn-space-8:2rem;
  --mn-space-10:2.5rem;
  --mn-s1:0.4375rem;
  --mn-s2:0.875rem;
  --mn-s3:1.75rem;
  --mn-size-target:2.75rem;
  --mn-size-icon:1.5rem;
  --mn-size-icon-sm:1.125rem;
  --mn-size-chip:2rem;
  --mn-size-chip-photo:1.5rem;
  --mn-size-control:2.5rem;
  --mn-z-card-ui:3;
  --mn-z-header:40;
  --mn-z-dock:45;
  --mn-z-sheet:80;
  --mn-z-toast:120;
  --mn-heart:#ff4f5e;
}
html[data-theme="neon"]{--mn-heart:#ff3060}
html[data-theme="gold"],html[data-theme="speakeasy"]{--mn-heart:#e2483d}
html[data-theme="laser"],html[data-theme="pub"],html[data-theme="irish"]{--mn-heart:#ff4d5a}
html[data-theme="sunset"]{--mn-heart:#ff3d4f}
html[data-theme="electric"]{--mn-heart:#ff5266}
/* larger screens: section titles step down to the label size (dense panels beside the player) */
@media (min-width:601px),(min-aspect-ratio:1/1){:root{--mn-title-size:var(--mn-fs-md)}}

/* MixNight UI, base. Requires shared/mixnight-theme.css (colours, fonts, motion) and src/tokens.css. */
.mn,.mn *,.mn *::before,.mn *::after{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
.mn{font-family:var(--sans);color:var(--txt);-webkit-font-smoothing:antialiased}
/* type roles: one class per role, size + weight + line height from tokens */
.mn-t-badge{font-size:var(--mn-badge-size);font-weight:var(--mn-badge-weight);line-height:var(--mn-badge-line)}
.mn-t-caption{font-size:var(--mn-caption-size);font-weight:var(--mn-caption-weight);line-height:var(--mn-caption-line);color:var(--dim)}
.mn-t-meta{font-size:var(--mn-meta-size);font-weight:var(--mn-meta-weight);line-height:var(--mn-meta-line);color:var(--dim)}
.mn-t-label{font-size:var(--mn-label-size);font-weight:var(--mn-label-weight);line-height:var(--mn-label-line)}
.mn-t-body{font-size:var(--mn-body-size);font-weight:var(--mn-body-weight);line-height:var(--mn-body-line)}
.mn-t-name{font-size:var(--mn-name-size);font-weight:var(--mn-name-weight);line-height:var(--mn-name-line)}
.mn-t-subhead{font-size:var(--mn-subhead-size);font-weight:var(--mn-subhead-weight);line-height:var(--mn-subhead-line)}
.mn-t-title{font-size:var(--mn-title-size);font-weight:var(--mn-title-weight);line-height:var(--mn-title-line);letter-spacing:-0.01em}
.mn-t-page{font-size:var(--mn-page-size);font-weight:var(--mn-page-weight);line-height:var(--mn-page-line);letter-spacing:-0.02em}
.mn-t-display{font-family:var(--display);font-size:var(--mn-display-size);font-weight:var(--display-heavy);line-height:var(--mn-display-line);letter-spacing:var(--display-heavy-track)}
.mn-icon{width:var(--mn-size-icon);height:var(--mn-size-icon);fill:currentColor;flex:none;display:block}
.mn-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* 30 Oct: the control language (29 Oct sweep, now the library's): every control is a full pill, 36px (40px on touch),
   a soft fill with a hairline. Focus: one ring for keyboard and D-pad (.kbfocus is the apps' D-pad class), thicker on the TV. */
:root{--mn-ctl-h:2.25rem;--mn-ctl-fill:color-mix(in srgb,var(--txt) 6%,transparent);--mn-ctl-line:inset 0 0 0 1px color-mix(in srgb,var(--txt) 10%,transparent);
  --mn-ctl-hover:color-mix(in srgb,var(--txt) 10%,transparent);--mn-ring-w:0.125rem;--mn-ring-o:0.125rem;--mn-sectitle-size:1.25rem}
@media (hover:none),(pointer:coarse){:root{--mn-ctl-h:2.5rem}}
@media (max-width:600px) and (max-aspect-ratio:1/1){:root{--mn-sectitle-size:1.375rem}}
html.tv{--mn-ring-w:0.3rem;--mn-ring-o:0}
:where([class^="mn-"],[class*=" mn-"]):focus-visible,:where([class^="mn-"],[class*=" mn-"]).kbfocus{outline:var(--ring-w,var(--mn-ring-w)) solid var(--focus,var(--accent));outline-offset:var(--ring-o,var(--mn-ring-o))}
:where(.mn-card).kbfocus{transform:scale(1.04);z-index:2}
html.tv :where(.mn-card).kbfocus{transform:scale(1.06)}

/* Squircle: iOS-style continuous corners (Figma 60% smoothing) as a mask of four corners plus a cross, so the corner keeps its size at any box size.
   Fallback is a plain radius. Corners at 10 / 16 / 20px. Note: a mask clips the element's own shadow, so shadows go on a parent. */
.mn-sq10{border-radius:10px;overflow:hidden}
.mn-sq16{border-radius:16px;overflow:hidden}
.mn-sq20{border-radius:20px;overflow:hidden}
@supports ((mask-image:linear-gradient(#000,#000)) or (-webkit-mask-image:linear-gradient(#000,#000))){.mn-sq10{border-radius:0;-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(16 0) scale(-1 1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(16 16) scale(-1 -1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(0 16) scale(1 -1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);-webkit-mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;-webkit-mask-size:16px 16px,16px 16px,16px 16px,16px 16px,100% calc(100% - 30px),calc(100% - 30px) 100%;-webkit-mask-repeat:no-repeat;mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(16 0) scale(-1 1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(16 16) scale(-1 -1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath transform='translate(0 16) scale(1 -1)' d='M0 0c5.601 0 8.401 0 10.54 1.09a10 10 0 0 1 4.37 4.37c1.09 2.139 1.09 4.939 1.09 10.54L0 16Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;mask-size:16px 16px,16px 16px,16px 16px,16px 16px,100% calc(100% - 30px),calc(100% - 30px) 100%;mask-repeat:no-repeat;}.mn-sq16{border-radius:0;-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(25.6 0) scale(-1 1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(25.6 25.6) scale(-1 -1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(0 25.6) scale(1 -1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);-webkit-mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;-webkit-mask-size:25.6px 25.6px,25.6px 25.6px,25.6px 25.6px,25.6px 25.6px,100% calc(100% - 49.2px),calc(100% - 49.2px) 100%;-webkit-mask-repeat:no-repeat;mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(25.6 0) scale(-1 1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(25.6 25.6) scale(-1 -1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25.6 25.6'%3E%3Cpath transform='translate(0 25.6) scale(1 -1)' d='M0 0c8.961 0 13.441 0 16.864 1.744a16 16 0 0 1 6.992 6.992c1.744 3.423 1.744 7.903 1.744 16.864L0 25.6Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;mask-size:25.6px 25.6px,25.6px 25.6px,25.6px 25.6px,25.6px 25.6px,100% calc(100% - 49.2px),calc(100% - 49.2px) 100%;mask-repeat:no-repeat;}.mn-sq20{border-radius:0;-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(32 0) scale(-1 1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(32 32) scale(-1 -1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(0 32) scale(1 -1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);-webkit-mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;-webkit-mask-size:32px 32px,32px 32px,32px 32px,32px 32px,100% calc(100% - 62px),calc(100% - 62px) 100%;-webkit-mask-repeat:no-repeat;mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(32 0) scale(-1 1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(32 32) scale(-1 -1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath transform='translate(0 32) scale(1 -1)' d='M0 0c11.201 0 16.802 0 21.08 2.18a20 20 0 0 1 8.74 8.74c2.18 4.278 2.18 9.879 2.18 21.08L0 32Z'/%3E%3C/svg%3E"),linear-gradient(#000,#000),linear-gradient(#000,#000);mask-position:0 0,100% 0,0 100%,100% 100%,0 50%,50% 0;mask-size:32px 32px,32px 32px,32px 32px,32px 32px,100% calc(100% - 62px),calc(100% - 62px) 100%;mask-repeat:no-repeat;}}

/* Button: tonal (default: soft fill + hairline), primary (txt on bg), accent, ghost; sm / md / lg. Always a full pill. */
.mn-btn{display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;height:var(--mn-ctl-h);padding:0 1rem;border:0;border-radius:var(--mn-rad-pill);
  appearance:none;-webkit-appearance:none;cursor:pointer;white-space:nowrap;
  font-family:var(--sans);font-size:var(--mn-fs-sm);font-weight:var(--mn-fw-medium);color:var(--txt);background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);
  transition:transform var(--dur-1) var(--ease-out),background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),filter var(--dur-2) var(--ease-out)}
.mn-btn:active{transform:scale(.97)}
.mn-btn .mn-icon{width:1.125rem;height:1.125rem}
@media (hover:hover){.mn-btn:hover{background:var(--mn-ctl-hover)}}
.mn-btn--primary{background:var(--txt);color:var(--bg);box-shadow:none;font-weight:var(--mn-fw-semibold)}
@media (hover:hover){.mn-btn--primary:hover{background:var(--txt);filter:brightness(.92)}}
.mn-btn--accent{background:var(--accent);color:var(--accent-ink);box-shadow:none;font-weight:var(--mn-fw-semibold)}
@media (hover:hover){.mn-btn--accent:hover{background:var(--accent);filter:brightness(1.06)}}
.mn-btn--ghost{background:transparent;box-shadow:none;color:var(--dim)}
@media (hover:hover){.mn-btn--ghost:hover{background:var(--hover);color:var(--txt)}}
.mn-btn--sm{height:2rem;padding:0 0.75rem;font-size:var(--mn-fs-sm)}
.mn-btn--lg{height:3rem;padding:0 1.5rem;font-size:var(--mn-fs-base)}
.mn-btn--block{display:flex;width:100%}
.mn-btn[disabled]{opacity:.4;pointer-events:none}

/* Icon button: always round. ghost (arrows, close, row actions), tonal, on-art (over a photo), play (the big circle). */
.mn-iconbtn{display:inline-grid;place-items:center;width:var(--mn-size-target);height:var(--mn-size-target);padding:0;border:0;border-radius:50%;appearance:none;-webkit-appearance:none;cursor:pointer;
  background:transparent;color:var(--dim);transition:transform var(--dur-1) var(--ease-out),background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
.mn-iconbtn .mn-icon{width:1.375rem;height:1.375rem}
@media (hover:hover){.mn-iconbtn:hover{background:var(--hover);color:var(--txt)}}
.mn-iconbtn:active{transform:scale(.92)}
.mn-iconbtn--sm{width:1.875rem;height:1.875rem}.mn-iconbtn--sm .mn-icon{width:1rem;height:1rem}
.mn-iconbtn--tonal{background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);color:var(--txt)}
.mn-iconbtn--onart{width:2.25rem;height:2.25rem;background:rgba(0,0,0,.42);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#fff}
.mn-iconbtn--onart .mn-icon{width:1rem;height:1rem}
.mn-iconbtn--onart.mn-iconbtn--light{background:#fff;color:#0a0a0b}
.mn-iconbtn--play{width:3.25rem;height:3.25rem;background:var(--txt);color:var(--bg)}
.mn-iconbtn--play .mn-icon{width:1.5rem;height:1.5rem}
.mn-iconbtn--play.mn-iconbtn--accent{background:var(--accent);color:var(--accent-ink)}
@media (hover:hover){.mn-iconbtn--play:hover{background:var(--txt);color:var(--bg);filter:brightness(.92)}.mn-iconbtn--play.mn-iconbtn--accent:hover{background:var(--accent);color:var(--accent-ink)}}

/* Text link / breadcrumb: no hover box, colour plus a faint underline */
.mn-link{background:none;border:0;padding:0;cursor:pointer;color:var(--dim);font:inherit;text-decoration:none}
@media (hover:hover){.mn-link:hover{color:var(--txt);text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-decoration-thickness:1px;text-underline-offset:0.2em}}
.mn-crumbs{display:flex;align-items:center;gap:0.5rem;font-size:var(--mn-label-size)}
.mn-crumbs .mn-sep{color:var(--dim2)}
.mn-crumbs [aria-current]{color:var(--txt)}
/* 30 Oct: an icon inside a button; a button whose label folds away on a phone (Shuffle, Guests: icon only, round);
   a selected option button; bigger on the TV */
.mn-btn > svg{width:1rem;height:1rem;fill:currentColor;flex:none}
.mn-btn--lg > svg{width:1.25rem;height:1.25rem}
@media (max-width:600px) and (max-aspect-ratio:1/1){.mn-btn--collapse:not(.mn-btn--primary):not(.mn-btn--accent){width:var(--mn-ctl-h);padding:0}
  .mn-btn--collapse:not(.mn-btn--primary):not(.mn-btn--accent) > span{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}}
.mn-btn.is-on{background:var(--txt);color:var(--bg);box-shadow:none}
html.tv .mn-btn{height:2.75rem;padding:0 1.25rem;font-size:var(--mn-fs-md)}
html.tv .mn-btn--lg{height:3.5rem}
.mn-iconbtn > svg{width:1.125rem;height:1.125rem;fill:currentColor}
.mn-iconbtn--sm > svg{width:1rem;height:1rem}
.mn-iconbtn:disabled{opacity:.3;cursor:default}

/* Heart: one component everywhere. 24px icon in a 44px target, white outline over a see-through dark fill, --mn-heart when saved.
   Markup: <button class="mn-heart [is-on]" aria-pressed><svg class="o">…heart</svg><svg class="f">…heart-fill</svg></button>
   On art: add .mn-heart--onart (absolute, top right). Motion: behaviours/heart.js (pop on save, squeeze on unsave), dip while pressed (CSS). */
.mn-heart{display:inline-grid;place-items:center;width:var(--mn-size-target);height:var(--mn-size-target);padding:0;border:0;background:none;cursor:pointer;color:#fff;-webkit-tap-highlight-color:transparent}
.mn-heart svg{grid-area:1/1;width:var(--mn-size-icon);height:var(--mn-size-icon);fill:currentColor;transition:transform 120ms cubic-bezier(.2,.8,.2,1);transform-origin:50% 55%}
.mn-heart svg.f{color:rgba(0,0,0,.4)}
.mn-heart svg.o{position:relative;z-index:1;color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.35))}
.mn-heart.is-on svg.f{color:var(--mn-heart)}
.mn-heart:active svg{transform:scale(.86)}
.mn-heart,.mn-heart:hover,.mn-heart:focus{background:none;box-shadow:none}
.mn-heart--onart{position:absolute;top:0;right:0;z-index:var(--mn-z-card-ui)}

/* Badge pill: Ready, 1 away, Up next, #2 in queue, Playing. On art it sits top left, centred on the heart's line. */
.mn-badge{display:inline-flex;align-items:center;gap:0.1875rem;height:1.1875rem;padding:0 0.5rem 0 0.4375rem;border-radius:var(--mn-rad-pill);
  font-family:var(--sans);font-size:var(--mn-badge-size);font-weight:var(--mn-badge-weight);line-height:1;white-space:nowrap;background:var(--txt);color:var(--bg)}
.mn-badge .mn-icon{width:0.625rem;height:0.625rem}
.mn-badge--accent{background:var(--accent);color:var(--accent-ink)}
.mn-badge--soft{background:rgba(0,0,0,.5);color:#fff;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
.mn-badge--onart{position:absolute;top:1.375rem;left:0.625rem;transform:translateY(-50%);z-index:var(--mn-z-card-ui)}
.mn-count{display:inline-grid;place-items:center;min-width:1.125rem;height:1.125rem;padding:0 0.3125rem;border-radius:var(--mn-rad-pill);background:var(--accent);color:var(--accent-ink);font-size:var(--mn-fs-2xs);font-weight:600;line-height:1}
.mn-count:empty{display:none}
.mn-badge svg{width:0.625rem;height:0.625rem;fill:currentColor;flex:none}

/* Chip: a 32px pill. Plain (recent searches, filters, tags), photo (spirits, artists: a 24px round photo or initial), selectable (.is-on), swatch (shelf: the colour as a dot). */
/* 30 Oct (Joe): the standard chip is the Tunes tag chip: 32px pill, hairline outline over a faint fill, 13px medium text.
   Selected (.is-on) is solid. A colour only ever goes in the dot (.mn-chip__swatch), never the whole chip. */
.mn-chip{display:inline-flex;align-items:center;gap:0.375rem;height:var(--mn-size-chip);padding:0 0.875rem;border:0;border-radius:var(--mn-rad-pill);appearance:none;-webkit-appearance:none;cursor:pointer;white-space:nowrap;
  background:color-mix(in srgb,var(--txt) 5%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dim) 18%,transparent);color:var(--dim);font-family:var(--sans);font-size:var(--mn-fs-sm);font-weight:var(--mn-fw-medium);
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out)}
@media (hover:hover){.mn-chip:hover{background:color-mix(in srgb,var(--txt) 10%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--txt) 18%,transparent);color:var(--txt)}}
.mn-chip:active{transform:scale(.97)}
.mn-chip.is-on,.mn-chip.is-on:hover{background:var(--txt);box-shadow:none;color:var(--bg)}
.mn-chip--photo{padding-left:0.25rem}
.mn-chip--photo img,.mn-chip__initial{flex:none;width:var(--mn-size-chip-photo);height:var(--mn-size-chip-photo);border-radius:50%;object-fit:cover;background:var(--card2)}
.mn-chip__initial{display:grid;place-items:center;font-size:var(--mn-fs-sm);font-weight:600;color:var(--txt)}
.mn-chip__swatch{flex:none;width:0.625rem;height:0.625rem;border-radius:50%;background:var(--sw,var(--dim));box-shadow:inset 0 0 0 1px rgba(0,0,0,.22)}   /* the hairline keeps pale dots (vodka, soda) visible on a selected chip */
.mn-chip--sm{height:1.75rem;padding:0 0.75rem;font-size:var(--mn-fs-xs)}
.mn-chips{display:flex;flex-wrap:wrap;gap:0.5rem}
.mn-chips--scroll{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
.mn-chips--scroll::-webkit-scrollbar{display:none}
/* 30 Oct: a chip can carry a small count or sub-label; a long chip truncates */
.mn-chip small{margin-left:0.125rem;color:var(--dim2);font-size:var(--mn-fs-xs);font-weight:var(--mn-fw-regular);font-variant-numeric:tabular-nums}
.mn-chip.is-on small{color:inherit;opacity:.7}
.mn-chip{flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis}   /* flex:none: in a scrolling row a chip keeps its width */
.mn-chip svg{width:1rem;height:1rem;flex:none;fill:currentColor}
html.tv .mn-chip{height:2.75rem;padding:0 1.125rem;font-size:var(--mn-fs-md)}

/* Navigation. Top nav pills (Tunes, Drinks, Games), underline tabs (Browse, Albums…), the phone's bottom tab bar. */
.mn-navpills{display:flex;gap:0.25rem}
.mn-navpill{display:inline-flex;align-items:center;gap:0.5rem;height:2.5rem;padding:0 1rem;border:0;border-radius:var(--mn-rad-pill);background:transparent;cursor:pointer;
  color:var(--dim);font-family:var(--sans);font-size:var(--mn-label-size);font-weight:var(--mn-label-weight);transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
.mn-navpill .mn-icon{width:1.25rem;height:1.25rem}
@media (hover:hover){.mn-navpill:hover{background:var(--hover);color:var(--txt)}}
.mn-navpill.is-on{color:var(--txt);font-weight:600}
.mn-tabs{display:flex;gap:1.75rem;border-bottom:1px solid var(--line)}
.mn-tab{position:relative;height:2.75rem;padding:0;border:0;background:none;cursor:pointer;color:var(--dim);font-family:var(--sans);font-size:var(--mn-label-size);font-weight:var(--mn-label-weight)}
.mn-tab.is-on{color:var(--txt);font-weight:600}
.mn-tab.is-on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;border-radius:2px;background:var(--accent)}
@media (hover:hover){.mn-tab:hover{color:var(--txt)}}
.mn-bottomtabs{display:grid;grid-template-columns:repeat(var(--n,5),1fr);border-top:1px solid var(--line);background:var(--bg);padding-bottom:var(--sab,0)}
.mn-bottomtab{position:relative;display:flex;flex-direction:column;align-items:center;gap:0.25rem;padding:0.5rem 0 0.375rem;border:0;background:none;cursor:pointer;color:var(--dim);font-family:var(--sans);font-size:var(--mn-badge-size);font-weight:var(--mn-badge-weight)}
.mn-bottomtab .mn-icon{width:1.5rem;height:1.5rem}
.mn-bottomtab.is-on{color:var(--txt);font-weight:600}
.mn-bottomtab .mn-count{position:absolute;top:0.25rem;left:calc(50% + 0.375rem)}
/* 30 Oct: a bottom tab's icon goes from outline to filled when it's on (give the two svgs .o and .f; a tab with one icon keeps it) */
.mn-bottomtab .mn-icon.f,.mn-bottomtab.is-on .mn-icon.o{display:none}
.mn-bottomtab.is-on .mn-icon.f{display:block}
.mn-bottomtabs--fixed{position:fixed;left:0;right:0;bottom:0;z-index:10;background:color-mix(in srgb,var(--txt) 5%,var(--bg))}

/* Small controls share the control radius; inner pieces are concentric (outer radius minus the inset). */
.mn-seg{display:inline-flex;align-items:stretch;height:var(--mn-ctl-h);padding:0.1875rem;gap:0.125rem;border-radius:var(--mn-rad-pill);background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line)}
.mn-seg > button{flex:1 0 auto;min-width:3rem;height:100%;padding:0 0.875rem;border:0;border-radius:var(--mn-rad-pill);background:transparent;cursor:pointer;color:var(--dim);white-space:nowrap;
  font-family:var(--sans);font-size:var(--mn-fs-sm);font-weight:var(--mn-fw-medium);transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
@media (hover:hover){.mn-seg > button:hover{color:var(--txt)}}
/* the selected option: .is-on (or aria-pressed / aria-selected; .on is still read for the apps' older state code) */
.mn-seg > button:is(.is-on,.on,[aria-pressed="true"],[aria-selected="true"]){background:color-mix(in srgb,var(--txt) 14%,transparent);color:var(--txt)}
.mn-seg--strong > button:is(.is-on,.on,[aria-pressed="true"]){background:var(--txt);color:var(--bg);font-weight:600}
.mn-seg--tonal > button:is(.is-on,.on,[aria-pressed="true"]){background:var(--surface-3);color:var(--txt)}
.mn-seg--sm > button{min-width:0;padding:0 0.625rem;font-size:var(--mn-fs-xs)}
.mn-seg--block{display:flex}
html.tv .mn-seg{height:2.75rem}html.tv .mn-seg > button{font-size:var(--mn-fs-md)}
.mn-stepper{display:inline-flex;align-items:center;height:var(--mn-ctl-h);border-radius:var(--mn-rad-pill);border:0;background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);overflow:hidden}
.mn-stepper button{width:var(--mn-ctl-h);height:100%;border:0;background:none;cursor:pointer;color:var(--txt);font-size:1.125rem;font-weight:500}
.mn-stepper button[disabled]{color:var(--dim2);cursor:default}
@media (hover:hover){.mn-stepper button:not([disabled]):hover{background:var(--hover)}}
.mn-stepper output{min-width:1.75rem;text-align:center;font-weight:600;font-variant-numeric:tabular-nums}
.mn-switch{position:relative;flex:none;width:2.75rem;height:1.625rem;border:0;border-radius:var(--mn-rad-pill);background:var(--surface-3);cursor:pointer;transition:background-color var(--dur-3) var(--ease-out)}
.mn-switch::after{content:"";position:absolute;top:0.125rem;left:0.125rem;width:1.375rem;height:1.375rem;border-radius:50%;background:var(--txt);box-shadow:0 1px 3px rgba(0,0,0,.4);transition:transform var(--dur-3) var(--ease-spring)}
.mn-switch[aria-checked="true"],.mn-switch.is-on{background:var(--accent)}
.mn-switch[aria-checked="true"]::after,.mn-switch.is-on::after{transform:translateX(1.125rem);background:var(--accent-ink)}
html.tv .mn-switch{width:3.25rem;height:2rem}html.tv .mn-switch::after{top:0.1875rem;left:0.1875rem;width:1.625rem;height:1.625rem}html.tv .mn-switch[aria-checked="true"]::after,html.tv .mn-switch.is-on::after{transform:translateX(1.25rem)}   /* the TV: a bigger switch */
/* Slider (31 Oct, as Tunes' volume draws it): the filled part is --v (set it as the value moves). The groove behind can be themed with
   --mn-slider-groove and --mn-slider-groove-sh (Tunes sinks it into the bar). */
.mn-slider{-webkit-appearance:none;appearance:none;width:100%;height:1.5rem;margin:0;background:transparent;cursor:pointer;--v:50%}
.mn-slider::-webkit-slider-runnable-track{height:0.3125rem;border-radius:var(--mn-rad-pill);background:linear-gradient(90deg,var(--txt) var(--v),var(--mn-slider-groove,var(--surface-3)) var(--v));box-shadow:var(--mn-slider-groove-sh,none)}
.mn-slider::-webkit-slider-thumb{-webkit-appearance:none;width:1.125rem;height:1.125rem;margin-top:-0.40625rem;border-radius:50%;background:var(--txt);box-shadow:0 0.125rem 0.375rem rgba(0,0,0,.5)}
.mn-slider::-moz-range-track{height:0.3125rem;border-radius:var(--mn-rad-pill);background:var(--mn-slider-groove,var(--surface-3));box-shadow:var(--mn-slider-groove-sh,none)}
.mn-slider::-moz-range-progress{height:0.3125rem;border-radius:var(--mn-rad-pill);background:var(--txt)}
.mn-slider::-moz-range-thumb{width:1.125rem;height:1.125rem;border:0;border-radius:50%;background:var(--txt)}
.mn-field{display:block}
.mn-field__label{display:block;margin-bottom:0.5rem;font-size:var(--mn-label-size);font-weight:var(--mn-label-weight);color:var(--dim)}
.mn-input{width:100%;height:var(--mn-ctl-h);padding:0 1rem;border:1px solid transparent;border-radius:var(--mn-rad-pill);background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);color:var(--txt);
  font-family:var(--sans);font-size:var(--mn-body-size);outline:none;transition:border-color var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out)}
.mn-input::placeholder{color:var(--dim2)}
.mn-input:focus{border-color:var(--accent);background:var(--surface-1)}
.mn-input[type=search]::-webkit-search-cancel-button,.mn-input[type=search]::-webkit-search-decoration{-webkit-appearance:none;display:none}   /* the browser's own clear button: the search has its own */
/* 30 Oct: search. The pill is the <label> (so a tap anywhere on it focuses the field): a magnifier, then a bare input, then (optionally)
   a clear button. <label class="mn-search"><svg class="mn-icon">…</svg><input class="mn-search__input" type="search"><button class="mn-search__clear">…</button></label>
   Tunes and Drinks get their clear × from shared/mixnight-clear.js instead, which sits in the same place. */
.mn-search{display:flex;align-items:center;gap:0.5rem;min-width:0;height:var(--mn-ctl-h);padding:0 0.375rem 0 1rem;border-radius:var(--mn-rad-pill);background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);color:var(--dim);cursor:text;transition:box-shadow var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out)}
.mn-search:focus-within{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--txt) 32%,transparent)}
.mn-search > svg:first-child,.mn-search > .mn-icon{width:1rem;height:1rem;flex:none;fill:currentColor}
.mn-search__input{flex:1;min-width:0;height:100%;margin:0;padding:0;border:0;outline:0;background:transparent;color:var(--txt);font-family:var(--sans);font-size:var(--mn-fs-sm);cursor:text}
.mn-search__input::placeholder{color:var(--dim)}
.mn-search .mn-search__input,.mn-search .mn-search__input:hover,.mn-search .mn-search__input:focus,.mn-search .mn-search__input:focus-visible{height:100%;margin:0;padding:0;border:0;border-radius:0;outline:0;box-shadow:none;background:transparent}   /* the field is the pill: the input inside never draws its own box */
.mn-search__input::-webkit-search-cancel-button,.mn-search__input::-webkit-search-decoration{-webkit-appearance:none;display:none}
.mn-search__clear{display:none;place-items:center;flex:none;width:2rem;height:2rem;padding:0;border:0;border-radius:50%;background:none;color:var(--dim);cursor:pointer}
.mn-search__clear svg{width:1rem;height:1rem;fill:currentColor}
.mn-search.has-value .mn-search__clear{display:grid}
@media (hover:hover){.mn-search__clear:hover{background:var(--mn-ctl-hover);color:var(--txt)}}
html.tv .mn-search{height:2.75rem}html.tv .mn-search__input{font-size:var(--mn-fs-md)}

/* Media card: cardless. The card is a <div role="button" tabindex="0"> (or an <a>), never a <button>, because it holds a heart <button> and buttons can't nest.
    Art with iOS-style corners, then the name (15/600) and one line (12/400) flush with the art's left edge.
   Art shapes: --square (drinks, categories, albums), --video (songs, 16:9, never cropped), --round (artists).
   UI on the art: .mn-heart--onart (top right), .mn-badge--onart (top left), .mn-card__actions (bottom left, on hover). */
.mn-card{position:relative;display:flex;flex-direction:column;justify-content:flex-start;align-self:start;min-width:0;padding:0;border:0;background:none;text-align:left;cursor:pointer;color:var(--txt);font-family:var(--sans)}
.mn-card__art{position:relative;display:block;width:100%;aspect-ratio:1/1;background:var(--card2);overflow:hidden;isolation:isolate}
.mn-card__art > img{display:block;width:100%;height:100%;object-fit:cover}
.mn-card__art > img.mn-fade{opacity:0;transition:opacity 420ms var(--ease-out)}.mn-card__art > img.mn-fade.is-loaded{opacity:1}   /* opt-in fade: add .mn-fade and call MN.wireImages() */
.mn-card--video .mn-card__art{aspect-ratio:16/9}
.mn-card--round .mn-card__art{border-radius:50%!important;-webkit-mask-image:none!important;mask-image:none!important}
.mn-card__body{padding:0.5rem 0 0.25rem;min-width:0}
.mn-card__name{display:block;font-size:var(--mn-name-size);font-weight:var(--mn-name-weight);line-height:var(--mn-name-line);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-card__line{display:block;margin-top:0.0625rem;font-size:var(--mn-caption-size);font-weight:var(--mn-caption-weight);line-height:var(--mn-caption-line);color:var(--dim);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.mn-card--round .mn-card__body{text-align:center}
.mn-card__actions{position:absolute;left:0.625rem;bottom:0.625rem;z-index:var(--mn-z-card-ui);display:flex;gap:0.375rem;opacity:0;transform:translateY(0.25rem);transition:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out)}
@media (hover:hover){.mn-card:hover .mn-card__actions,.mn-card:focus-within .mn-card__actions{opacity:1;transform:none}}
/* THE card hover, one for every card: the art holds still and brightens a touch. No zoom, no veil. Mouse only.
   (30 Oct, Joe: growing pushed the picture past the row's edge, which cut its top and corners off flat) */
.mn-card__art{transition:transform var(--hover-dur) var(--ease-out),filter var(--hover-dur) var(--ease-out)}
@media (hover:hover) and (pointer:fine){.mn-card:hover .mn-card__art{filter:brightness(1.08)}}
.mn-card:active .mn-card__art{transform:scale(.985)!important;transition-duration:var(--dur-1)}
/* album: a square sleeve (2px, like a record on a shelf) with a soft shadow. Hover is the same as every card */
.mn-card--album .mn-card__art{overflow:visible;background:none;isolation:auto}
.mn-card--album .mn-card__art > img{position:relative;z-index:1;border-radius:2px;box-shadow:0 1px 1px rgba(0,0,0,.4),0 10px 18px -4px rgba(0,0,0,.65)}
.mn-card--album .mn-card__art::before{content:"";position:absolute;inset:4%;border-radius:50%;background:radial-gradient(circle,#ddd 0 9%,#111 9.5% 30%,#0b0b0b 31% 100%);transition:transform 520ms var(--ease-out)}
/* see all: a round chevron block in place of art */
.mn-card--seeall .mn-card__art{display:grid;place-items:center;background:var(--surface-2);color:var(--txt)}
.mn-card--seeall .mn-card__art .mn-icon{width:2.5rem;height:2.5rem}
/* home app card: a raised surface (the one card that keeps a box) */
.mn-appcard{position:relative;display:flex;flex-direction:column;justify-content:flex-end;min-height:14rem;padding:1.375rem;border:1px solid var(--line);border-radius:var(--mn-rad-card);background:var(--card);overflow:hidden;text-align:left;cursor:pointer;color:var(--txt)}
.mn-appcard__k{font-size:var(--mn-meta-size);font-weight:600;color:var(--accent)}
.mn-appcard__n{font-family:var(--display);font-size:2.25rem;font-weight:var(--display-weight);letter-spacing:var(--display-track);line-height:1;margin-top:0.5rem}
.mn-appcard__d{margin-top:0.5rem;font-size:var(--mn-label-size);color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 30 Oct: generated category art (covers.js: a sleeve or a motif) inside a card's art */
.mn-card__art > .cover{position:absolute;inset:0;overflow:hidden}
.mn-card__art > .cover:not(.sleeve) svg{position:absolute;inset:0;width:100%;height:100%;filter:brightness(.85)}
.mn-card__art > .cover .shade,.mn-card__art > .cover .stamp{display:none}
.mn-card--wide .mn-card__art{aspect-ratio:16/7}
/* 31 Oct: a name that may take two lines (song titles); a line that stays on one (the artist under a song) */
.mn-card__name--wrap{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.mn-card__line--one{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}

/* Section header: title (+ chevron link), optional line, optional ‹ › arrows on mouse devices. Title 2px above its line; carousel one gap below. */
.mn-sechead{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.625rem}
.mn-sechead__text{min-width:0;flex:1}
.mn-sechead__title{display:inline-flex;align-items:center;gap:0.25rem;padding:0;border:0;background:none;cursor:pointer;color:var(--txt);font-family:var(--sans);
  font-size:var(--mn-sectitle-size);font-weight:700;line-height:var(--mn-title-line);letter-spacing:-0.01em}
.mn-sechead__title .mn-icon{width:1.125em;height:1.125em;color:var(--txt);transition:transform var(--dur-2) var(--ease-out)}

.mn-sechead__line{display:block;margin-top:0.125rem;font-size:var(--mn-meta-size);color:var(--dim);line-height:var(--mn-meta-line)}
.mn-sechead__arrows{display:none;gap:0.125rem}
@media (hover:hover) and (pointer:fine){.mn-sechead__arrows{display:flex}}
/* Back-title header: chevron + title are one link, the same sizes as the section header it came from */
.mn-backtitle{display:inline-flex;align-items:center;gap:0.125rem;margin-left:-0.5rem;padding:0;border:0;background:none;cursor:pointer;color:var(--txt);font-family:var(--sans);
  font-size:var(--mn-sectitle-size);font-weight:700;line-height:var(--mn-title-line);letter-spacing:-0.01em}
.mn-backtitle .mn-icon{width:1.75rem;height:1.75rem;padding:0.25rem;transition:transform var(--dur-2) var(--ease-out)}

/* Carousel (31 Oct, the one carousel for every app): sits on the page (no band) and bleeds to its edge (--bleed, the page's side padding),
   first card in line with the title, top-aligned, the shared card gap. On a phone it shows two and a half cards (the cut card is the scroll cue);
   elsewhere MN.fitCarousels() sizes the cards to about data-mn-card rem (11 by default) so a card is always cut part-way at the right edge,
   plus one more card on a desktop screen (data-mn-more="0" turns that off). No snapping on touch, the phone's own momentum. Bigger on the TV. */
.mn-carousel{--n:2;--gap:var(--grid-col-gap,0.875rem);display:grid;grid-auto-flow:column;gap:var(--gap);align-items:start;
  grid-auto-columns:var(--mn-carousel-w,calc((100% - var(--n) * var(--gap)) / (var(--n) + 0.5)));
  margin:0 calc(-1 * var(--bleed,var(--mn-space-4)));padding:0.25rem var(--bleed,var(--mn-space-4)) 0.5rem;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-padding-inline:var(--bleed,var(--mn-space-4));scroll-snap-type:x proximity;scrollbar-width:none}
.mn-carousel::-webkit-scrollbar{display:none}
.mn-carousel > *{scroll-snap-align:start;min-width:0}
.mn-carousel::after{content:"";width:1px}
@media (hover:none),(pointer:coarse){.mn-carousel{scroll-snap-type:none}}
@container (min-width:34rem){.mn-carousel{--n:3}}
@container (min-width:48rem){.mn-carousel{--n:4}}
@container (min-width:64rem){.mn-carousel{--n:5}}
html.tv .mn-carousel{grid-auto-columns:var(--mn-carousel-tv,13rem)}
.mn-panel{container-type:inline-size;padding:0 var(--mn-space-4)}
/* Grid of cards (31 Oct, every app): columns at least --min wide (set it on the grid or above it), the shared grid gaps, top-aligned;
   two across on a phone; --min-tv on the TV */
.mn-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--min,9.5rem),100%),1fr));gap:var(--grid-row-gap,1.75rem) var(--grid-col-gap,0.875rem);align-items:start}
.mn-grid > *{min-width:0}
@media (max-width:600px) and (max-aspect-ratio:1/1){.mn-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
html.tv .mn-grid{grid-template-columns:repeat(auto-fill,minmax(var(--min-tv,11rem),1fr))}
/* 30 Oct: a list page's header (a category, an artist, My List): optional hero art, then the title with its count, and actions */
.mn-hero{position:relative;display:block;width:100%;height:clamp(9rem,15vw,12rem);overflow:hidden;border-radius:var(--mn-rad-card);background:var(--card2);isolation:isolate}
.mn-hero > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.mn-hero > .cover{position:absolute;inset:0}
.mn-hero > .cover:not(.sleeve) svg{position:absolute;inset:0;width:100%;height:100%;filter:brightness(.85)}
.mn-hero > .cover .shade,.mn-hero > .cover .stamp{display:none}
.mn-listhead{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem 1rem;min-height:2.75rem;margin:0 0 0.875rem}
.mn-listhead__title{display:flex;align-items:baseline;flex-wrap:wrap;gap:0.125rem 0.625rem;min-width:0;margin:0 auto 0 0;font-size:var(--mn-page-size);font-weight:700;letter-spacing:-0.025em;line-height:1.1;white-space:nowrap}
.mn-listhead__count{font-size:var(--mn-meta-size);font-weight:var(--mn-fw-regular);letter-spacing:0;color:var(--dim);font-variant-numeric:proportional-nums}
.mn-listhead__count:empty{display:none}
html.tv .mn-listhead__title{font-size:2rem}
.mn-listhead__actions{display:flex;align-items:center;gap:0.5rem;flex:none}
/* 30 Oct: the section header in the apps: the title may sit in a heading (h2/h3, reset here); the chevron is any svg after the title;
   the ‹ › arrows sit at the end (mouse, and always on the TV, where they're bigger) */
.mn-sechead__h{margin:0;font:inherit;min-width:0}
.mn-sechead__title{text-align:left;min-width:0}
.mn-sechead__title > span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mn-sechead__title > svg{flex:none;width:var(--sec-chev,1.125em);height:var(--sec-chev,1.125em);fill:currentColor;color:var(--txt)}
span.mn-sechead__title{cursor:default}
.mn-sechead__arrows{margin-left:auto;gap:0.25rem;padding-left:0.5rem}
.mn-sechead__arrows .mn-iconbtn:disabled{opacity:.3;cursor:default;background:transparent}
html.tv .mn-sechead__arrows{display:flex}
html.tv .mn-sechead__arrows .mn-iconbtn{width:2.75rem;height:2.75rem}
html.tv{--mn-sectitle-size:1.5rem}

/* List rows: one row anatomy (thumb · text · actions) for tracks, the queue, album tracks, settings, ingredients and method steps. */
.mn-row{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;column-gap:0.75rem;min-height:3.375rem;padding:0.4375rem;border-radius:0.75rem;color:var(--txt);font-family:var(--sans);
  transition:background-color var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out)}
/* 30 Oct: the row matches Tunes' song rows (the most used): 72px thumb, 14px medium title, 12px line, row actions 36px in the dim colour */
@media (hover:hover){.mn-row--hover:hover{background:var(--hover);cursor:pointer}}
.mn-row--hover:active:not(:has(button:active,.mn-row__grip:active)){transform:scale(.985);background:var(--hover);transition-duration:var(--dur-1)}
.mn-list--divided > .mn-row + .mn-row::before{content:"";position:absolute;left:0.4375rem;right:0.4375rem;top:0;height:1px;background:var(--line);pointer-events:none}   /* hairlines between rows, opt-in */
.mn-row__thumb{display:block;width:4.5rem;height:2.5rem;object-fit:cover;background:var(--card2);border-radius:0.375rem}
.mn-row__thumb--square{width:2.5rem}
.mn-row__text{min-width:0}
.mn-row__title{display:block;font-size:var(--mn-fs-md);font-weight:var(--mn-fw-medium);line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-row__line{display:block;margin-top:0.0625rem;font-size:var(--mn-fs-xs);color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-row__actions{display:flex;align-items:center;gap:0;margin-right:-0.25rem}
.mn-row__actions .mn-iconbtn{width:2.25rem;height:2.25rem;color:var(--dim2)}
.mn-row__actions .mn-iconbtn .mn-icon,.mn-row__actions .mn-iconbtn > svg{width:1.125rem;height:1.125rem;fill:currentColor}
@media (hover:hover){.mn-row:hover .mn-row__actions .mn-iconbtn,.mn-row:focus-within .mn-row__actions .mn-iconbtn{color:var(--txt)}}
.mn-row__value{min-width:2.75rem;text-align:right;color:var(--dim2);font-style:normal;font-size:var(--mn-fs-sm);font-variant-numeric:tabular-nums}
.mn-row.is-playing .mn-row__title{color:var(--accent)}
.mn-row__num{width:1.5rem;text-align:center;font-style:normal;color:var(--dim2);font-size:var(--mn-fs-sm);font-variant-numeric:tabular-nums}
.mn-row.is-playing .mn-row__num{color:var(--accent)}
.mn-row__grip{color:var(--dim2);cursor:grab;display:grid;place-items:center;width:2.25rem;height:2.25rem;touch-action:none}
.mn-row__grip svg{width:1.125rem;height:1.125rem;fill:currentColor}
/* the compact row (an album's tracks): a number in place of the thumb */
.mn-row--compact{min-height:2.75rem;padding-block:0;column-gap:0.5rem}
/* actions that show on hover or focus (mouse); always there on touch */
@media (hover:hover) and (pointer:fine){.mn-row--reveal .mn-row__actions > :not(.mn-playing){opacity:0;transition:opacity var(--dur-2) var(--ease-out)}
  .mn-row--reveal:hover .mn-row__actions > *,.mn-row--reveal:focus-within .mn-row__actions > *,.mn-row--reveal.is-lifting .mn-row__actions > *{opacity:1}}
/* dragging a row to reorder: it lifts in place */
.mn-row.is-lifting{z-index:3;background:var(--surface-1);box-shadow:0 0.75rem 2rem rgba(0,0,0,.55);cursor:grabbing;transition:none}
/* "Playing": a little equaliser and the word, shown on the row that's on */
.mn-playing{display:none;align-items:center;gap:0.4rem;margin-right:0.375rem;padding:0.25rem 0;color:var(--dim);font-size:var(--mn-fs-xs);font-weight:var(--mn-fw-medium);line-height:1;white-space:nowrap}
.is-playing .mn-playing,.mn-playing.is-on{display:inline-flex}
.mn-playing i{display:inline-flex;align-items:flex-end;gap:2px;height:0.625rem}
.mn-playing i b{width:2px;height:30%;border-radius:1px;background:var(--accent);animation:mn-eq 1s ease-in-out infinite}
.mn-playing i b:nth-child(2){animation-delay:-.35s}.mn-playing i b:nth-child(3){animation-delay:-.7s}
@keyframes mn-eq{0%,100%{height:30%}50%{height:100%}}
@media (prefers-reduced-motion:reduce){.mn-playing i b{animation:none;height:60%}}
/* the heart in a row: same component, inline (no absolute) */
.mn-row .mn-heart{position:static}
/* settings row and simple key/value rows */
.mn-row--setting{grid-template-columns:minmax(0,1fr) auto;min-height:3.75rem}
.mn-row--kv{grid-template-columns:minmax(0,1fr) auto;min-height:2.75rem;padding:0.5rem 0;border-radius:0}
.mn-row--kv .mn-row__title{font-weight:var(--mn-fw-regular)}
.mn-row--kv .mn-row__value{color:var(--dim);font-size:inherit;min-width:0}
/* method step */
.mn-step{display:grid;grid-template-columns:1.5rem minmax(0,1fr);gap:0.75rem;align-items:start;padding:0.375rem 0;font-size:var(--mn-body-size);line-height:var(--mn-body-line)}
.mn-step__n{display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:50%;background:var(--txt);color:var(--bg);font-size:var(--mn-fs-xs);font-weight:700}
/* 30 Oct: a guest's own request (Party queue) and the "Added by" line with a face */
.mn-row.is-you .mn-row__num,.mn-row.is-you .mn-row__by{color:var(--accent)}
.mn-row__by{display:flex;align-items:center;gap:0.25rem;margin-top:0.125rem;font-size:var(--mn-caption-size);font-weight:600;color:var(--dim)}
.mn-row__by .mn-avatar{--s:1.25rem;font-size:0.5rem}
.mn-row__lead{display:flex;align-items:center;gap:0.5rem}
/* 30 Oct: the queue row: a play button over the thumb on hover, Auto-DJ's picks dimmed, bigger actions on the TV */
.mn-row__art{position:relative;flex:none;display:block;line-height:0}
.mn-row__play{position:absolute;inset:0;margin:auto;width:1.75rem;height:1.75rem;border-radius:50%;background:#fff;color:#111;display:flex;align-items:center;justify-content:center;opacity:0;transform:scale(.85);transition:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out)}
.mn-row__play svg{width:0.75rem;height:0.75rem;fill:currentColor}
@media (hover:hover) and (pointer:fine){.mn-row:not(.is-lifting):hover .mn-row__play,.mn-row:focus-visible .mn-row__play{opacity:1;transform:none}}
.mn-row.is-auto{opacity:.6}
.mn-row__line em{font-style:normal;color:var(--accent)}
html.tv .mn-row__actions .mn-iconbtn,html.tv .mn-row__grip{width:2.75rem;height:2.75rem}
html.tv .mn-row:focus,html.tv .mn-row.kbfocus{outline:var(--ring-w,var(--mn-ring-w)) solid var(--focus,var(--accent));outline-offset:-2px}

/* Toast: a raised dark card, 14px corners, text colour, hairline edge. Optional Undo. Position is per screen (bottom centre by default). */
.mn-toast{position:fixed;left:50%;bottom:calc(1rem + var(--sab,0px));z-index:var(--mn-z-toast);display:flex;align-items:center;gap:0.75rem;width:max-content;max-width:min(28rem,calc(100vw - 2rem));
  padding:0.75rem 1.125rem;border:1px solid color-mix(in srgb,var(--txt) 14%,transparent);border-radius:0.875rem;background:color-mix(in srgb,var(--txt) 9%,var(--bg));color:var(--txt);
  font-family:var(--sans);font-size:var(--mn-label-size);font-weight:var(--mn-fw-medium);line-height:1.35;text-align:left;box-shadow:0 0.75rem 2rem rgba(0,0,0,.45);
  opacity:0;transform:translate(var(--mn-toast-x,-50%),0.5rem);pointer-events:none;transition:opacity var(--dur-3) var(--ease-out),transform var(--dur-3) var(--ease-out)}
.mn-toast.is-on{opacity:1;transform:translate(var(--mn-toast-x,-50%),0)}
/* the message never blocks taps on what's under it; the action button still works */
.mn-toast__act{pointer-events:auto;flex:none}
.mn-toast__msg{min-width:0}
/* with an action, the button sits the same distance from the top, right and bottom edges */
.mn-toast.has-action{padding:0.375rem 0.375rem 0.375rem 1.125rem}
/* placed by the page (a corner, not the centre): set --mn-toast-x:0 and left / right */
.mn-toast--static{position:relative;left:auto;bottom:auto;opacity:1;transform:none;pointer-events:auto}
/* Empty state */
.mn-empty{display:flex;flex-direction:column;align-items:center;gap:0.75rem;padding:2.5rem 1rem;text-align:center;color:var(--dim)}
.mn-empty .mn-icon{width:2.25rem;height:2.25rem;color:var(--dim2)}
.mn-empty__title{color:var(--txt);font-size:var(--mn-name-size);font-weight:var(--mn-name-weight)}
.mn-empty__text{font-size:var(--mn-meta-size);max-width:22rem}
/* Skeleton: the art's shape in grey with a soft shimmer, plus lines where text will go */
@keyframes mn-shimmer{from{background-position:100% 0}to{background-position:-100% 0}}
.mn-skel{background:linear-gradient(110deg,var(--card2) 30%,color-mix(in srgb,var(--card2) 70%,var(--txt) 6%) 50%,var(--card2) 70%);background-size:200% 100%;animation:mn-shimmer 1.6s linear infinite}
.mn-skel-line{display:block;height:0.625rem;border-radius:var(--mn-rad-pill);margin-top:0.5rem}
.mn-skel-line--name{width:70%;height:0.75rem}
.mn-skel-line--line{width:45%}
@media (prefers-reduced-motion:reduce){.mn-skel{animation:none}}
/* Avatar: artist photo or guest face, initials when there's no picture */
.mn-avatar{display:inline-grid;place-items:center;flex:none;width:var(--s,2.5rem);height:var(--s,2.5rem);border-radius:50%;overflow:hidden;background:var(--card2);color:var(--txt);font-weight:600;font-size:calc(var(--s,2.5rem) * .4)}
.mn-avatar img{width:100%;height:100%;object-fit:cover}
/* 30 Oct: an inline notice (can't reach the bar, offline) and a one-line empty state inside a list */
.mn-notice{padding:0.875rem 1.125rem;border-radius:0.875rem;background:var(--mn-ctl-fill);box-shadow:var(--mn-ctl-line);color:var(--dim);font-size:var(--mn-body-size);line-height:var(--mn-body-line)}
.mn-empty--inline{display:block;padding:0.5rem 0 0.75rem;text-align:left;font-size:var(--mn-body-size)}
.mn-empty b{color:var(--txt);font-weight:600}
.mn-empty__icon{display:grid;place-items:center;font-size:2rem;line-height:1;color:var(--dim2)}
.mn-empty__icon svg{width:2.25rem;height:2.25rem}
.mn-empty--small{padding:0.5rem 0 0;font-size:var(--mn-caption-size);color:var(--dim2)}

/* Sheet / modal (31 Oct, one overlay for every app): a blurred scrim that centres a sheet. Open it with .is-on (.on is still read for
   Tunes' older code); closed, it is hidden outright so nothing inside takes focus or a D-pad press.
   <div class="mn-scrim"><div class="mn-sheet" role="dialog"><div class="mn-sheet__head"><h2 class="mn-sheet__title">…</h2><button class="mn-iconbtn">×</button></div>
   <div class="mn-sheet__body">…</div></div></div>. A bottom sheet (--bottom) pads itself and sits at the foot on a phone. */
.mn-scrim{position:fixed;inset:0;z-index:var(--mn-z-sheet);display:flex;align-items:center;justify-content:center;padding:1.25rem;background:var(--scrim,rgba(0,0,0,.6));
  -webkit-backdrop-filter:blur(0.375rem);backdrop-filter:blur(0.375rem);opacity:0;visibility:hidden;pointer-events:none;transition:opacity var(--dur-3) var(--ease-out),visibility 0s linear var(--dur-3)}
.mn-scrim:is(.is-on,.on){opacity:1;visibility:visible;pointer-events:auto;transition-delay:0s}
html.tv .mn-scrim{-webkit-backdrop-filter:none;backdrop-filter:none}
.mn-sheet{position:relative;display:flex;flex-direction:column;width:min(34rem,100%);max-height:90vh;overflow:auto;overscroll-behavior:contain;padding:0;border:1px solid var(--line2);
  border-radius:var(--mn-rad-card);background:var(--surface-1);color:var(--txt);box-shadow:var(--hl),var(--shadow)}
.mn-sheet__head{display:flex;align-items:center;gap:0.75rem;padding:1.25rem 1.375rem 0.375rem}
.mn-sheet__title{flex:1;margin:0;font-size:var(--mn-page-size);font-weight:var(--mn-page-weight);letter-spacing:-0.02em;line-height:1.45}
.mn-sheet__head .mn-iconbtn{width:var(--mn-ctl-h);height:var(--mn-ctl-h);color:var(--dim)}
.mn-sheet__body{flex:1;min-height:0;overflow:auto;padding:0.25rem 1.375rem 1.75rem}
.mn-sheet__grabber{display:none;width:2.25rem;height:0.3125rem;margin:-0.75rem auto 0.75rem;border-radius:var(--mn-rad-pill);background:var(--surface-3)}
.mn-sheet--bottom{padding:1.5rem}
.mn-sheet--bottom .mn-sheet__head{padding:0;margin-bottom:1rem}
@media (max-width:600px) and (max-aspect-ratio:1/1){.mn-sheet{border:0}}
@media (max-width:600px){
  .mn-sheet--bottom{width:100%;border-radius:var(--mn-rad-sheet) var(--mn-rad-sheet) 0 0;padding-bottom:calc(1.5rem + var(--sab,0px))}
  .mn-sheet--bottom .mn-sheet__grabber{display:block}
  .mn-scrim:has(> .mn-sheet--bottom){align-items:flex-end;padding:0}
  .mn-scrim > .mn-sheet--bottom{transform:translateY(100%);transition:transform var(--dur-4) var(--ease-out)}
  .mn-scrim:is(.is-on,.on) > .mn-sheet--bottom{transform:none}
}
@media (prefers-reduced-motion:reduce){.mn-scrim > .mn-sheet--bottom{transition:none}}
/* Sheet lead and actions (31 Oct, the long-press song menu): what the sheet is about, then a list of full-width actions.
   <div class="mn-sheet__lead"><img class="mn-sheet__lead-art"><div><b class="mn-sheet__lead-title">…</b><span class="mn-sheet__lead-text">…</span></div></div>
   <div class="mn-sheet__actions"><button>icon Label</button>…</div>. An action that is on (.is-on) colours its icon. */
.mn-sheet{--mn-sheet-pad:1.375rem}
.mn-sheet--bottom{--mn-sheet-pad:1.5rem}
.mn-sheet__lead{display:flex;align-items:center;gap:0.75rem;padding:0.25rem 0 0.75rem;border-bottom:1px solid var(--line);margin-bottom:0.25rem}
.mn-sheet__lead > div{min-width:0}
.mn-sheet__lead-art{flex:none;width:5rem;aspect-ratio:16/9;object-fit:cover;border-radius:var(--mn-rad-ctl,0.5rem);background:var(--surface-2)}
.mn-sheet__lead-title{display:block;font-size:var(--mn-fs-base);font-weight:var(--mn-fw-semibold);line-height:1.5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-sheet__lead-text{display:block;margin-top:0.125rem;color:var(--dim);font-size:var(--mn-meta-size)}
.mn-sheet__actions{display:flex;flex-direction:column;margin:0 calc(-1 * var(--mn-sheet-pad))}
.mn-sheet__actions button{display:flex;align-items:center;gap:0.875rem;min-height:3.25rem;padding:0 var(--mn-sheet-pad);border:0;background:none;color:var(--txt);font-family:var(--sans);font-size:var(--mn-fs-base);font-weight:var(--mn-fw-medium);text-align:left;cursor:pointer}
.mn-sheet__actions button svg{flex:none;width:1.5rem;height:1.5rem;fill:currentColor;color:var(--dim)}
.mn-sheet__actions button:is(.is-on,.on) svg{color:var(--accent)}
.mn-sheet__actions button:active{background:var(--surface-2)}
@media (hover:hover) and (pointer:fine){.mn-sheet__actions button:hover{background:var(--hover)}}
/* Option card inside a sheet (Yes, join it / No, set it up here) */
.mn-option{display:block;width:100%;padding:0.875rem 1rem;border:0;border-radius:var(--mn-rad-ctl);background:var(--surface-2);color:var(--txt);text-align:left;cursor:pointer;font-family:var(--sans)}
.mn-option + .mn-option{margin-top:0.5rem}
.mn-option.is-on{background:var(--txt);color:var(--bg)}
.mn-option__title{display:block;font-size:var(--mn-name-size);font-weight:var(--mn-name-weight)}
.mn-option__text{display:block;margin-top:0.25rem;font-size:var(--mn-meta-size);opacity:.75}
/* Action sheet / menu */
.mn-menu{display:flex;flex-direction:column;padding:0.375rem;border-radius:var(--mn-rad-card);background:var(--surface-1);box-shadow:var(--shadow-3);min-width:14rem}
.mn-menu button{display:flex;align-items:center;gap:0.75rem;height:2.75rem;padding:0 0.75rem;border:0;border-radius:var(--mn-rad-ctl);background:none;cursor:pointer;color:var(--txt);font-family:var(--sans);font-size:var(--mn-label-size);text-align:left}
.mn-menu button .mn-icon{width:1.125rem;height:1.125rem;color:var(--dim)}
@media (hover:hover){.mn-menu button:hover{background:var(--hover)}}
.mn-menu hr{border:0;height:1px;margin:0.25rem 0.5rem;background:var(--line)}

/* Player pieces, built from the components above. */
/* Transport (31 Oct, as Tunes draws it): previous / next are bare icons, play is the one filled control, all three the same size.
   Size it per layout with --mn-transport-btn / --mn-transport-play / --mn-transport-icon / --mn-transport-play-icon. */
.mn-transport{--mn-transport-btn:2.75rem;--mn-transport-play:var(--mn-transport-btn);--mn-transport-icon:1.25rem;--mn-transport-play-icon:var(--mn-transport-icon);display:flex;align-items:center;justify-content:center;gap:var(--mn-transport-gap,0.75rem)}
.mn-transport .mn-iconbtn{width:var(--mn-transport-btn);height:var(--mn-transport-btn)}
.mn-transport .mn-iconbtn:not(.mn-iconbtn--play){color:var(--txt)}
.mn-transport .mn-iconbtn > :is(svg,.mn-icon){width:var(--mn-transport-icon);height:var(--mn-transport-icon)}
.mn-transport .mn-iconbtn--play{width:var(--mn-transport-play);height:var(--mn-transport-play);box-shadow:var(--shadow-1,0 1px 2px rgba(0,0,0,.35))}
.mn-transport .mn-iconbtn--play > :is(svg,.mn-icon){width:var(--mn-transport-play-icon);height:var(--mn-transport-play-icon)}
@media (hover:hover){.mn-transport .mn-iconbtn--play:hover{background:var(--accent);color:var(--bg);filter:none}}   /* the theme's colour on hover, like the other active states */
/* on a dark picture (full screen) the bare icons go white */
.mn-transport--onart .mn-iconbtn:not(.mn-iconbtn--play){color:#fff}
@media (hover:hover){.mn-transport--onart .mn-iconbtn:not(.mn-iconbtn--play):hover{background:rgba(255,255,255,.08);color:#fff}}
/* glass (1 Nov, the TV's full-screen overlay, sized for the remote): frosted round buttons over the picture, play solid white */
.mn-transport--glass .mn-iconbtn:not(.mn-iconbtn--play){background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.18);-webkit-backdrop-filter:blur(0.625rem);backdrop-filter:blur(0.625rem);color:#fff}
.mn-transport--glass .mn-iconbtn--play{background:#fff;color:#000;box-shadow:none}
/* Mode button (31 Oct, as Tunes draws it): an icon over a small label, quiet until it is on. <button class="mn-modebtn">svg<small>Theatre</small></button>
   (the label can be bare text too). States: .is-on (.on is still read), --accent (a switch that is on takes the theme colour), .is-warn (muted).
   Size it per layout with --mn-modebtn-h / --mn-modebtn-w / --mn-modebtn-pad / --mn-modebtn-icon. On a dark picture add --onart. */
.mn-modebtn{--mn-modebtn-h:2.75rem;--mn-modebtn-w:auto;--mn-modebtn-pad:0 0.375rem;--mn-modebtn-icon:1.125rem;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:0.125rem;
  width:var(--mn-modebtn-w);min-width:var(--mn-modebtn-h);height:var(--mn-modebtn-h);padding:var(--mn-modebtn-pad);border:1px solid transparent;border-radius:0.75rem;background:transparent;cursor:pointer;color:var(--dim);
  font-family:var(--sans);font-size:var(--mn-badge-size);font-weight:var(--mn-badge-weight);line-height:1;white-space:nowrap;
  transition:transform var(--dur-1) var(--ease-out),background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
.mn-modebtn > :is(svg,.mn-icon){flex:none;width:var(--mn-modebtn-icon);height:var(--mn-modebtn-icon);fill:currentColor}
.mn-modebtn > small{font:inherit;letter-spacing:0;white-space:nowrap}
@media (hover:hover){.mn-modebtn:hover{background:var(--hover);color:var(--txt)}}
.mn-modebtn:active{transform:scale(.93)}
.mn-modebtn:is(.is-on,.on){background:var(--surface-2);color:var(--txt)}
.mn-modebtn--accent:is(.is-on,.on){background:var(--accent-soft);color:var(--accent)}
.mn-modebtn.is-warn{color:var(--red,#ff5d5d)}
.mn-modebtn--onart{color:rgba(255,255,255,.72)}
@media (hover:hover){.mn-modebtn--onart:hover{background:rgba(255,255,255,.08);color:#fff}}
.mn-modebtn--onart:is(.is-on,.on){background:rgba(255,255,255,.1);color:#fff}
.mn-modebtn--onart.mn-modebtn--accent:is(.is-on,.on){background:color-mix(in oklab,var(--accent) 16%,transparent);color:var(--accent)}
/* Progress (31 Oct, as Tunes draws it): a 5px groove; the played part is the child's width (--p, or set it inline). Add --seek for a scrub bar
   (pointer, a taller hit area). Theme the groove with --mn-progress-groove / --mn-progress-groove-sh (Tunes sinks it into the bar). On a dark picture add --onart. */
.mn-progress{position:relative;height:0.3125rem;border-radius:var(--mn-rad-pill);background:var(--mn-progress-groove,var(--surface-3));box-shadow:var(--mn-progress-groove-sh,none)}
.mn-progress > :is(i,b){position:absolute;inset:0 auto 0 0;width:var(--p,0%);background:var(--txt);border-radius:inherit;transition:width .25s linear}
.mn-progress--seek{cursor:pointer}
.mn-progress--seek::before{content:"";position:absolute;inset:-0.875rem 0}
.mn-progress--onart{--mn-progress-groove:rgba(255,255,255,.18)}
.mn-progress--onart > :is(i,b){background:#fff}
/* edge (1 Nov): a hairline along the bottom of a picture (the TV's full screen), square ends, thicker while you point at it or drag */
.mn-progress--edge{--mn-progress-groove:rgba(255,255,255,.15);height:0.1875rem;border-radius:0;transition:height var(--dur-2) var(--ease-out)}
.mn-progress--edge > :is(i,b){background:#fff}
.mn-progress--edge:is(:hover,.scrubbing){height:0.5rem}
/* Progress row: time played, the bar, the length. <div class="mn-progressrow"><span>1:12</span><div class="mn-progress"><i></i></div><span>3:31</span></div> */
.mn-progressrow{display:flex;align-items:center;gap:0.75rem;color:var(--dim);font-family:var(--sans);font-size:var(--mn-fs-sm);font-variant-numeric:tabular-nums}
.mn-progressrow > .mn-progress{flex:1}
.mn-progressrow--onart{color:rgba(255,255,255,.7)}
/* Mini player (31 Oct, as Tunes' bottom bar and TV bar draw it): a thumbnail, the title over the artist, its round buttons (.mn-iconbtn; play is --play)
   and a thin accent line along the top for progress.
   <div class="mn-miniplayer"><div class="mn-miniplayer__art"></div><div class="mn-miniplayer__text"><b>Title</b><span>Artist</span></div>
   <button class="mn-iconbtn mn-iconbtn--play">…</button><button class="mn-iconbtn">…</button><div class="mn-miniplayer__prog" style="width:34%"></div></div>
   Per layout: --mn-miniplayer-btn / --mn-miniplayer-icon (button and icon size), --mn-miniplayer-title / --mn-miniplayer-line (text sizes),
   --mn-miniplayer-btn-fill / --mn-miniplayer-btn-line (the buttons other than play: tonal by default, transparent / none for bare icons). */
.mn-miniplayer{--mn-miniplayer-btn:3rem;--mn-miniplayer-icon:1.25rem;--mn-miniplayer-title:1rem;--mn-miniplayer-line:var(--mn-fs-sm);position:relative;display:flex;align-items:center;gap:0.875rem;min-width:0}
.mn-miniplayer__art{flex:none;background:#000 center/cover;border-radius:var(--mn-rad-thumb);overflow:hidden}
.mn-miniplayer__text{flex:1;min-width:0}
.mn-miniplayer__text > b{display:block;font-size:var(--mn-miniplayer-title);font-weight:var(--mn-fw-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-miniplayer__text > span{display:block;color:var(--dim);font-size:var(--mn-miniplayer-line);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-miniplayer .mn-iconbtn{flex:none;width:var(--mn-miniplayer-btn);height:var(--mn-miniplayer-btn)}
.mn-miniplayer .mn-iconbtn:not(.mn-iconbtn--play){background:var(--mn-miniplayer-btn-fill,var(--mn-ctl-fill));box-shadow:var(--mn-miniplayer-btn-line,var(--mn-ctl-line));color:var(--txt)}
.mn-miniplayer .mn-iconbtn > :is(svg,.mn-icon){width:var(--mn-miniplayer-icon);height:var(--mn-miniplayer-icon);fill:currentColor}
.mn-miniplayer__prog{position:absolute;left:0;top:-1px;width:0;height:2px;border-radius:var(--mn-rad-pill);background:var(--accent)}
/* Now playing (31 Oct, as Tunes draws it): the art beside the title (a heart can sit next to it) over the artist line; a progress row can run underneath.
   <div class="mn-nowplaying"><div class="mn-nowplaying__art" style="background-image:url(…)"></div><div class="mn-nowplaying__text"><div class="mn-nowplaying__title"><span>Title</span><button class="mn-heart">…</button></div>
   <div class="mn-nowplaying__line">Artist</div></div><div class="mn-progressrow">…</div></div>  The art can be an img too. Size the title per layout with --mn-nowplaying-title. */
.mn-nowplaying{--mn-nowplaying-title:clamp(1.5rem,2.6vw,2.5rem);display:grid;grid-template-columns:auto 1fr;gap:0.25rem 0.875rem;align-items:center;min-width:0}
.mn-nowplaying > .mn-progressrow{grid-column:1/-1}
.mn-nowplaying__art{width:3.5rem;height:3.5rem;border-radius:var(--mn-rad-thumb);background:var(--card2,var(--surface-2)) center/cover;object-fit:cover;box-shadow:0 0.375rem 1rem rgba(0,0,0,.4)}
.mn-nowplaying__text{min-width:0}
.mn-nowplaying__title{display:flex;align-items:center;gap:0.375rem;min-width:0}
.mn-nowplaying__title > :not(.mn-heart){min-width:0;font-family:var(--display,var(--sans));font-weight:var(--display-weight,var(--mn-fw-display));letter-spacing:var(--display-track,-0.02em);
  font-size:var(--mn-nowplaying-title);line-height:1.1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity var(--dur-3) var(--ease-out)}
.mn-nowplaying__title > .mn-heart{flex:none;margin:-0.5rem 0}
.mn-nowplaying__line{display:flex;align-items:center;margin-top:0.25rem;color:var(--dim);font-size:var(--mn-fs-base);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-upnext{display:flex;align-items:center;gap:0.625rem;width:15rem;padding:0.375rem;border:0;background:color-mix(in oklab,var(--txt) 6%,transparent);color:var(--txt);text-align:left;cursor:pointer}
.mn-upnext img{width:5.5rem;aspect-ratio:16/9;object-fit:cover;flex:none}
.mn-upnext__title{display:block;font-size:var(--mn-label-size);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mn-upnext__line{display:block;font-size:var(--mn-caption-size);color:var(--dim)}
@media (hover:hover){.mn-upnext:hover{background:color-mix(in oklab,var(--txt) 11%,transparent)}}
