/* =============================================================================================
   No Cover Charge · design system
   Linked from GuitarSuperSystem/wwwroot/index.html (app) and GuitarSuperSystem.Web/Components/App.razor
   (web) right after app.min.css, before the per-workstream sheets (ncc-licks, ncc-backstage, ncc-social,
   ncc-learn, ncc-account).

   Owned by Foundation. Feature styles go in the owning workstream's ncc-*.css, scoped under the page
   root class and written with these tokens. Plain CSS on purpose: Tailwind does not compile this file,
   so nothing here needs an app.min.css regen.

   Cascade: app.min.css declares the layers (theme, base, components, utilities). Element defaults sit in
   @layer base and reusable classes in @layer components, so a Tailwind utility on the same element still
   wins. The icon class, the shell overrides and the motion kit are unlayered on purpose: they have to beat
   the legacy utilities on <main> (py-4, px-4) and keep icons at the size Google's stylesheet gave them.

   Motion rule: base styles are the FINAL state; keyframes carry only the "from" state, so the
   reduced-motion switch (section 8) never leaves anything hidden.

   Contents
     0. Fonts            3. Icons            5b. Components (N*), toasts, launch cover, gates, reconnect
     1. Tokens           4. Type             6. Shell (main, page, top bar, sidebar, tab bar, You sheet, 404)
     2. Base             5. Controls         7. Motion kit       8. Reduced motion
   ============================================================================================= */

/* 0. FONTS ----------------------------------------------------------------------------------- */
/* Self-hosted so brand type and icons work offline and never flash (the Google @import in app.css
   landed mid-file and was dropped). woff2 from Google Fonts; licences in ncc/fonts. Space Grotesk blocks
   briefly instead of swapping and is preloaded by both hosts; Inter swaps. */
@font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 300 700; font-display: block; src: url("fonts/space-grotesk-latin-ext-var.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 300 700; font-display: block; src: url("fonts/space-grotesk-latin-var.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap; src: url("fonts/inter-latin-ext-var.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap; src: url("fonts/inter-latin-var.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* Material Symbols Outlined: every icon, cut down on the axes instead (weight 400, optical size 24,
   grade 0, FILL 0..1). Any icon name works, so no feature has to wait for a new icon subset; the old
   Google link pulled all axes (1.1 MB), this is 0.46 MB. */
@font-face { font-family: "Material Symbols Outlined"; font-style: normal; font-weight: 400; font-display: block; src: url("fonts/material-symbols-outlined.woff2") format("woff2"); }

/* 1. TOKENS ----------------------------------------------------------------------------------- */
:root {
  color-scheme: dark;

  /* surfaces: --n-bg is the one ink for html, body, #app, the native WebView layers, the splash and
     theme-color. --n-sunken is the only darker black (input wells). */
  --n-bg: #131313;
  --n-sunken: #0e0e0e;
  --n-card: #1b1c1c;
  --n-card-2: #232424;
  --n-card-3: #2a2a2a;
  --n-line: rgba(255,255,255,.08);
  --n-line-2: rgba(255,255,255,.14);
  --n-line-3: rgba(255,255,255,.24);
  --n-glass: rgba(19,19,19,.82);
  --n-glass-fx: blur(22px) saturate(1.5);
  --n-scrim: rgba(0,0,0,.58);

  /* text */
  --n-text: #e4e2e1;
  --n-text-hi: #fff;
  --n-text-2: #a1a1aa;
  --n-text-3: #8e8e96;   /* 5.25:1 on --n-card: the floor for timestamps and meta */
  --n-text-4: #52525b;   /* decoration only, never readable copy */

  /* brand */
  --n-red: #E8232B;
  --n-red-press: #CF1D24;
  --n-red-wash: rgba(232,35,43,.14);
  --n-red-line: rgba(232,35,43,.38);
  --n-pink: #F6A7AA;
  --n-on-red: #fff;

  /* semantic */
  --n-go: #4ade80;     --n-go-wash: rgba(74,222,128,.14);
  --n-amber: #fbbf24;  --n-amber-wash: rgba(251,191,36,.14);
  --n-danger: #ff8a8e; --n-danger-wash: rgba(232,35,43,.12);

  /* type */
  --n-font-display: "Space Grotesk", system-ui, -apple-system, sans-serif;
  --n-font-body: "Inter", system-ui, -apple-system, sans-serif;
  --n-fs-title: 28px;
  --n-fs-h2: 20px;
  --n-fs-h3: 16px;
  --n-fs-body: 15px;
  --n-fs-small: 13px;
  --n-fs-meta: 12px;
  --n-fs-kicker: 11px;
  --n-fs-micro: 10px;    /* badges only */
  --n-ls-title: -.02em;
  --n-ls-kicker: .14em;
  --n-ls-btn: .08em;

  /* shape */
  --n-r-xs: 6px;         /* badges */
  --n-r-sm: 10px;        /* inputs, thumbs */
  --n-r-md: 14px;        /* cards, buttons, list groups */
  --n-r-lg: 18px;        /* feature and hero cards */
  --n-r-sheet: 24px;
  --n-r-pill: 999px;

  /* space */
  --n-1: 4px; --n-2: 8px; --n-3: 12px; --n-4: 16px; --n-5: 20px; --n-6: 24px; --n-8: 32px; --n-10: 40px;
  --n-gutter: 16px;
  --n-page-top: 12px;
  --n-section: 28px;
  --n-stack: 12px;
  --n-max: 960px;
  --n-max-wide: 1200px;

  /* chrome. --ncc-safe-t/-b are written by the Android host (MainActivity) from the WebView's window
     insets, because Android WebView reports env(safe-area-inset-*) as 0. */
  --n-safe-t: max(env(safe-area-inset-top, 0px), var(--ncc-safe-t, 0px));
  --n-safe-b: max(env(safe-area-inset-bottom, 0px), var(--ncc-safe-b, 0px));
  --n-topbar-h: 56px;
  --n-tab-h: 64px;
  --n-tab-gap: 10px;
  /* room the floating tab bar takes at the bottom of <main> on phones */
  --n-tab-room: calc(var(--n-tab-h) + var(--n-tab-gap) + var(--n-safe-b) + 16px);

  /* elevation */
  --n-shadow-float: 0 18px 50px rgba(0,0,0,.55);
  --n-shadow-sheet: 0 -18px 60px rgba(0,0,0,.6);
  --n-shadow-card: 0 12px 40px rgba(0,0,0,.45);

  /* z-index */
  --n-z-raised: 2;
  --n-z-topbar: 40;
  --n-z-player: 49;
  --n-z-tabbar: 50;
  --n-z-push: 60;
  --n-z-sheet: 1000;
  --n-z-toast: 1100;
  --n-z-full: 9000;

  /* motion */
  --n-pop: cubic-bezier(.2,.9,.25,1.15);    /* chips, likes, stamps */
  --n-out: cubic-bezier(.16,1,.3,1);        /* entries, counts */
  --n-glide: cubic-bezier(.32,.72,0,1);     /* sheets, navigation, the puck */
  --n-tempo: 1;                             /* QA slow-mo: set .5 or .1 on <html> */
  --n-dur-fast: calc(160ms / var(--n-tempo));
  --n-dur: calc(280ms / var(--n-tempo));
  --n-dur-slow: calc(560ms / var(--n-tempo));
}
@media (min-width: 768px) { :root { --n-gutter: 24px; } }
@media (min-width: 1024px) { :root { --n-gutter: 32px; --n-fs-title: 36px; --n-tab-room: 40px; } }

/* 2. BASE ------------------------------------------------------------------------------------- */
@layer base {
  html, body { background: var(--n-bg); color: var(--n-text); overscroll-behavior-y: none; }
  body {
    font: 400 var(--n-fs-body)/1.5 var(--n-font-body);
    -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
    -webkit-tap-highlight-color: transparent;
  }
  h1, h2, h3, h4, h5, h6 { font-family: var(--n-font-display); }
  /* Links are --n-pink (app.css base, next to the Tailwind element defaults). */
  :focus-visible { outline: 2px solid var(--n-pink); outline-offset: 2px; }
  /* FocusOnNavigate focuses each page's h1 (tabindex=-1); WebKit treats that as :focus-visible and
     would ring every title. Programmatic-only targets never show the ring. */
  :where([tabindex="-1"]):focus-visible { outline: none; }
  /* 16px fields on phones so iOS Safari doesn't zoom into them. */
  @media (max-width: 767px) {
    :where(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) { font-size: 16px; }
  }
}
::selection { background: var(--n-red); color: #fff; }

/* In the app (MAUI host, html.is-native, set by ncc-ui.js) a long-press on the chrome is a press, not a
   web gesture: no stray text selection and no WebKit callout on the bars, buttons, chips, pressable cards
   and sheet headers, nor on in-app links (their callout offers to open or copy an internal app://
   address). Content stays selectable and copyable: post and comment bodies, DMs, lesson text, errors,
   and a link to another site keeps its Copy link callout. Fields, and anything marked .n-selectable,
   stay selectable inside chrome too. The web keeps browser behaviour. */
html.is-native :where(.n-topbar, .n-side, .ncc-tabbar, .ncc-nav-notice, .n-sheet__grab, .n-sheet__head, button, [role="button"],
  [role="tab"], [role="menuitem"], .n-btn, .n-chip, .n-seg, .n-icon-btn, .n-card--press, .n-avatar, .n-badge) {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-user-drag: none;
}
html.is-native :where(a[href^="/"]) { -webkit-touch-callout: none; -webkit-user-drag: none; }
html.is-native :where(input, textarea, select, [contenteditable], .n-selectable) { -webkit-user-select: text; user-select: text; }

/* 3. ICONS ------------------------------------------------------------------------------------ */
/* Same rule Google's stylesheet shipped, unlayered like it was, so every existing icon keeps its size. */
.material-symbols-outlined {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  font-feature-settings: "liga";
  -webkit-font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
  font-synthesis: none;
}
/* NIcon: size from --n-icon-size, so a component sets it on its container (this rule is unlayered
   like the one above, which a layered "x .n-icon { font-size }" could never beat). An explicit
   Size on NIcon is an inline style and wins over both. */
.n-icon { font-size: var(--n-icon-size, 24px); }

/* 4. TYPE ------------------------------------------------------------------------------------- */
/* Member screens: sentence-case titles with a small uppercase kicker. Uppercase 900 belongs to the
   guest hero and the paywall only. Nothing readable goes below 11px. */
@layer components {
  .n-title { font: 700 var(--n-fs-title)/1.1 var(--n-font-display); letter-spacing: var(--n-ls-title); color: var(--n-text); text-wrap: balance; }
  .n-h2 { font: 700 var(--n-fs-h2)/1.2 var(--n-font-display); letter-spacing: -.01em; color: var(--n-text); }
  .n-h3 { font: 700 var(--n-fs-h3)/1.3 var(--n-font-display); color: var(--n-text); }
  .n-body { font-size: var(--n-fs-body); line-height: 1.5; }
  .n-small { font-size: var(--n-fs-small); line-height: 1.45; color: var(--n-text-2); }
  .n-meta { font-size: var(--n-fs-meta); line-height: 1.4; color: var(--n-text-3); font-variant-numeric: tabular-nums; }
  .n-kicker {
    font: 700 var(--n-fs-kicker)/1.2 var(--n-font-display); letter-spacing: var(--n-ls-kicker);
    text-transform: uppercase; color: var(--n-text-2);
  }
  .n-kicker--pink { color: var(--n-pink); }
  .n-num { font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
}

/* 5. CONTROLS --------------------------------------------------------------------------------- */
@layer components {
  /* NButton: .n-btn + kind (--primary, --secondary, --ghost, --danger, --link) + size (--sm, --lg) */
  .n-btn {
    --bg: var(--n-card-2); --fg: var(--n-text); --bd: transparent;
    position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 44px; padding: 0 18px; border: 1px solid var(--bd); border-radius: var(--n-r-md);
    background: var(--bg); color: var(--fg); white-space: nowrap; text-decoration: none; cursor: pointer;
    font: 700 13px/1 var(--n-font-display); letter-spacing: var(--n-ls-btn); text-transform: uppercase;
    -webkit-user-select: none; user-select: none;
    transition: scale var(--n-dur-fast) ease, background-color var(--n-dur) ease, border-color var(--n-dur) ease, opacity var(--n-dur) ease;
  }
  .n-btn:active { scale: .97; }
  .n-btn:disabled, .n-btn[aria-disabled="true"] { opacity: .45; cursor: default; scale: none; }
  .n-btn[aria-busy="true"] { cursor: progress; }
  .n-btn--sm { min-height: 36px; padding: 0 14px; font-size: 12px; }
  .n-btn--lg { min-height: 50px; padding: 0 22px; font-size: 14px; }
  .n-btn--block { display: flex; width: 100%; }
  .n-btn--primary { --bg: var(--n-red); --fg: var(--n-on-red); }
  .n-btn--primary:active { --bg: var(--n-red-press); }
  @media (hover: hover) { .n-btn--primary:hover:not(:disabled) { --bg: var(--n-red-press); } }
  .n-btn--secondary { --bg: var(--n-card-2); --fg: var(--n-text); }
  .n-btn--ghost { --bg: transparent; --fg: var(--n-text); --bd: var(--n-line-2); }
  @media (hover: hover) { .n-btn--ghost:hover:not(:disabled) { --bd: var(--n-line-3); } }
  .n-btn--danger { --bg: var(--n-danger-wash); --fg: var(--n-danger); }
  .n-btn--link { --bg: transparent; --fg: var(--n-pink); min-height: 44px; padding: 0 4px; }

  /* NChip: quiet by default; .on is the selected state, .tag the red-wash label */
  .n-chip {
    display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 14px; flex: none;
    border-radius: var(--n-r-pill); border: 1px solid var(--n-line); background: var(--n-card); color: var(--n-text-2);
    font: 600 12px/1 var(--n-font-body); white-space: nowrap; text-decoration: none; cursor: pointer;
    transition: color var(--n-dur) ease, background-color var(--n-dur) ease, border-color var(--n-dur) ease, scale var(--n-dur-fast) ease;
  }
  .n-chip:active { scale: .96; }
  .n-chip.on { background: var(--n-red); border-color: var(--n-red); color: #fff; }
  .n-chip.tag { background: var(--n-red-wash); border-color: var(--n-red-line); color: var(--n-pink); }

  /* NSegmented: --n = segments, --i = selected index; the puck slides under the selection */
  .n-seg {
    --n: 2; --i: 0; position: relative; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr));
    padding: 4px; border-radius: var(--n-r-pill); background: var(--n-card); border: 1px solid var(--n-line); isolation: isolate;
  }
  .n-seg__puck {
    position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px; width: calc((100% - 8px) / var(--n));
    border-radius: var(--n-r-pill); background: var(--n-card-3); border: 1px solid var(--n-line-2);
    transform: translateX(calc(var(--i) * 100%)); transition: transform calc(320ms / var(--n-tempo)) var(--n-pop);
  }
  .n-seg__opt {
    min-height: 36px; padding: 0 12px; border: 0; border-radius: var(--n-r-pill); background: none; cursor: pointer;
    color: var(--n-text-2); font: 600 13px/1 var(--n-font-body); transition: color var(--n-dur) ease;
  }
  .n-seg__opt[aria-pressed="true"], .n-seg__opt[aria-selected="true"] { color: var(--n-text-hi); }

  /* Inputs: light text in a sunken well */
  .n-input {
    width: 100%; min-height: 44px; padding: 10px 12px; border-radius: var(--n-r-sm);
    background: var(--n-sunken); color: var(--n-text); border: 1px solid var(--n-line-2);
    font: 400 15px/1.4 var(--n-font-body); caret-color: var(--n-red); -webkit-appearance: none; appearance: none;
    transition: border-color var(--n-dur) ease;
  }
  .n-input::placeholder { color: var(--n-text-3); }
  .n-input:focus { border-color: var(--n-red); outline: none; }
  textarea.n-input { min-height: 96px; resize: vertical; }

  /* NCard */
  .n-card { position: relative; border-radius: var(--n-r-md); background: var(--n-card); border: 1px solid var(--n-line); }
  .n-card--pad-sm { padding: 12px; }
  .n-card--pad { padding: 16px; }
  .n-card--feature {
    border-radius: var(--n-r-lg); border-color: var(--n-red-line);
    background: radial-gradient(120% 90% at 0% 0%, rgba(232,35,43,.22) 0%, rgba(232,35,43,0) 60%), var(--n-card);
  }
  .n-card--inset { background: var(--n-sunken); }
}
@media (max-width: 767px) {
  .n-input { font-size: 16px; }
}

/* 5b. COMPONENTS ------------------------------------------------------------------------------ */
/* Styles for the N* components (GuitarSuperSystem.Shared/Components/N). Layered with the controls so a
   utility class on the same element still wins. /admin/ui-kit renders every one of them. */
@layer components {
  /* NIcon */
  .n-icon { flex: none; }
  .n-icon--fill { font-variation-settings: "FILL" 1; }

  /* NButton extras: icon size, loading state (the label stays in flow so the width never jumps) */
  .n-btn { --n-icon-size: 18px; }
  .n-btn__label { display: inline-flex; align-items: center; gap: 8px; }
  .n-btn.is-loading .n-btn__label { visibility: hidden; }
  .n-btn__spin { position: absolute; inset: 0; display: grid; place-items: center; }
  .n-btn--primary .n-spinner { border-color: rgba(255,255,255,.35); border-top-color: #fff; }

  /* NIconButton: 44px target whatever the drawn size */
  .n-icon-btn {
    position: relative; display: inline-grid; place-items: center; flex: none; width: 44px; height: 44px; padding: 0;
    border: 0; border-radius: 50%; background: none; color: var(--n-text-2); cursor: pointer; text-decoration: none;
    transition: color var(--n-dur) ease, background-color var(--n-dur) ease, scale var(--n-dur-fast) ease;
  }
  .n-icon-btn, .n-back { --n-icon-size: 24px; }
  .n-icon-btn:active { scale: .92; }
  @media (hover: hover) { .n-icon-btn:hover:not(:disabled) { color: var(--n-text); background: var(--n-card); } }
  .n-icon-btn.on, .n-icon-btn[aria-pressed="true"], .n-icon-btn[aria-expanded="true"] { color: var(--n-pink); }
  .n-icon-btn--filled { background: var(--n-card-2); color: var(--n-text); }
  .n-icon-btn--sm { width: 36px; height: 36px; }
  .n-icon-btn--sm::after { content: ""; position: absolute; inset: -4px; }
  .n-icon-btn:disabled { opacity: .45; cursor: default; scale: none; }
  .n-icon-btn__dot { position: absolute; top: 9px; right: 9px; width: 8px; height: 8px; border-radius: 50%; background: var(--n-red); box-shadow: 0 0 0 2px var(--n-bg); }
  .n-icon-btn__badge { position: absolute; top: 3px; right: 1px; }

  /* NBackButton */
  .n-back {
    display: inline-flex; align-items: center; gap: 6px; min-width: 44px; min-height: 44px; margin-left: -10px; padding: 0 10px;
    border: 0; border-radius: var(--n-r-pill); background: none; color: var(--n-text); cursor: pointer; text-decoration: none;
  }
  .n-back__label { font: 700 var(--n-fs-kicker)/1 var(--n-font-display); letter-spacing: var(--n-ls-kicker); text-transform: uppercase; color: var(--n-text-2); }
  @media (hover: hover) { .n-back:hover { background: var(--n-card); } }

  /* NPageHeader: kicker, sentence-case title, optional sub line and trailing actions */
  .n-ph { margin: 0 0 var(--n-6); }
  .n-ph__back { margin-bottom: 2px; }
  .n-ph__row { display: flex; align-items: center; gap: 12px; }
  .n-ph__titles { flex: 1 1 auto; min-width: 0; }
  .n-ph__titles > .n-kicker { display: block; margin-bottom: 6px; }
  .n-ph__titles > .n-title { margin: 0; }
  .n-ph__sub { margin: 6px 0 0; }
  .n-ph__trail { flex: none; display: flex; align-items: center; gap: 4px; margin-right: -10px; }

  /* NSectionHeader */
  .n-sh { display: flex; align-items: baseline; gap: 8px; margin: 0 0 var(--n-3); }
  .n-sh__title { margin: 0; font: 700 17px/1.3 var(--n-font-display); color: var(--n-text); }
  .n-sh__count { font: 600 14px/1 var(--n-font-body); color: var(--n-text-3); font-variant-numeric: tabular-nums; }
  .n-sh__more {
    margin-left: auto; align-self: center; display: inline-flex; align-items: center; gap: 2px; min-height: 44px; margin-block: -12px;
    padding: 0 2px; border: 0; background: none; color: var(--n-pink); font: 600 13px/1 var(--n-font-body); text-decoration: none; cursor: pointer;
  }
  .n-sh__more { --n-icon-size: 18px; }
  .n-sh__trail { margin-left: auto; align-self: center; }

  /* NCard extras */
  .n-card--media { overflow: hidden; }
  .n-card--media > .n-img:first-child { border-radius: 0; }
  a.n-card, .n-card[role="button"] { display: block; color: inherit; text-decoration: none; cursor: pointer; }
  .n-card--press { transition: scale var(--n-dur-fast) ease, border-color var(--n-dur) ease; }
  .n-card--press:active { scale: .985; }
  @media (hover: hover) { .n-card--press:hover { border-color: var(--n-line-2); } }

  /* NChip extras + NChipRail (bleeds to the gutter and fades at the edges) */
  .n-chip { --n-icon-size: 16px; }
  .n-chip .n-icon { margin-left: -2px; }
  .n-chip__count { color: var(--n-text-3); font-variant-numeric: tabular-nums; }
  .n-chip.on .n-chip__count { color: rgba(255,255,255,.8); }
  @media (hover: hover) { .n-chip:not(.on, .tag):hover { border-color: var(--n-line-2); color: var(--n-text); } }
  .n-rail {
    display: flex; gap: 8px; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    margin-inline: calc(var(--n-gutter) * -1); padding: 2px var(--n-gutter); scroll-padding-inline: var(--n-gutter);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--n-gutter), #000 calc(100% - var(--n-gutter)), transparent);
    mask-image: linear-gradient(90deg, transparent, #000 var(--n-gutter), #000 calc(100% - var(--n-gutter)), transparent);
  }
  .n-rail::-webkit-scrollbar { display: none; }
  .n-rail--sticky { position: sticky; top: calc(var(--n-safe-t) + var(--n-topbar-h)); z-index: var(--n-z-raised); background: var(--n-bg); padding-block: 8px; }

  /* NBadge: difficulty, count, status (10px is for badges only) */
  .n-badge {
    display: inline-flex; align-items: center; gap: 3px; height: 20px; padding: 0 7px; border-radius: var(--n-r-xs); vertical-align: middle;
    background: var(--n-card-3); color: var(--n-text-2); white-space: nowrap;
    font: 700 var(--n-fs-micro)/1 var(--n-font-display); letter-spacing: .08em; text-transform: uppercase;
  }
  .n-badge { --n-icon-size: 12px; }
  .n-badge--go { background: var(--n-go-wash); color: var(--n-go); }
  .n-badge--amber { background: var(--n-amber-wash); color: var(--n-amber); }
  .n-badge--pink { background: var(--n-red-wash); color: var(--n-pink); }
  .n-badge--pro { background: var(--n-red-wash); color: var(--n-pink); box-shadow: inset 0 0 0 1px var(--n-red-line); }
  .n-badge--count {
    justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--n-r-pill); background: var(--n-red); color: #fff;
    font: 700 11px/1 var(--n-font-body); letter-spacing: 0; text-transform: none; font-variant-numeric: tabular-nums;
  }

  /* NAvatar: photo, or the initial in pink on --n-card-2 */
  .n-avatar {
    --s: 36px; position: relative; display: inline-grid; place-items: center; flex: none; width: var(--s); height: var(--s);
    border-radius: 50%; background: var(--n-card-2); color: var(--n-pink); text-decoration: none; -webkit-user-select: none; user-select: none;
    font: 700 calc(var(--s) * .42)/1 var(--n-font-display); text-transform: uppercase;
  }
  .n-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
  .n-avatar.is-ring { box-shadow: 0 0 0 2px var(--n-bg), 0 0 0 4px var(--n-pink); }
  .n-avatar__dot {
    position: absolute; top: 0; right: 0; width: max(8px, calc(var(--s) * .24)); height: max(8px, calc(var(--s) * .24));
    border-radius: 50%; background: var(--n-red); box-shadow: 0 0 0 2px var(--n-bg);
  }

  /* NImg: fixed-ratio box, brand placeholder underneath, fade in on load, placeholder again on error */
  .n-img { position: relative; display: block; overflow: hidden; aspect-ratio: var(--ratio, 16 / 9); border-radius: var(--n-r-sm); background: var(--n-card-2); }
  .n-img__ph {
    position: absolute; inset: 0; display: grid; place-items: center; color: var(--n-text-4);
    font: 700 italic clamp(14px, 18%, 28px)/1 var(--n-font-display); letter-spacing: -.02em;
  }
  .n-img > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity calc(320ms / var(--n-tempo)) ease; }
  .n-img > img.is-in { opacity: 1; }
  .n-img > img.is-broken { visibility: hidden; }

  /* NListGroup + NListRow (generalised from Settings) */
  .n-list { margin: 0 0 var(--n-5); }
  .n-list__title { display: block; margin: 0 6px 8px; }
  .n-list__card { overflow: hidden; border-radius: var(--n-r-md); background: var(--n-card); border: 1px solid var(--n-line); }
  .n-list__foot { margin: 8px 6px 0; }
  .n-row {
    display: flex; align-items: center; gap: 13px; width: 100%; min-height: 52px; padding: 11px 14px; border: 0; border-top: 1px solid var(--n-line);
    background: none; color: var(--n-text); font: 500 15px/1.3 var(--n-font-body); text-align: left; text-decoration: none;
  }
  .n-row:first-child { border-top: 0; }
  a.n-row, button.n-row { cursor: pointer; transition: background-color var(--n-dur-fast) ease; }
  a.n-row:active, button.n-row:active { background: var(--n-card-2); }
  @media (hover: hover) { a.n-row:hover, button.n-row:hover { background: var(--n-card-2); } }
  .n-row__icon { flex: none; display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--n-r-sm); background: var(--n-red-wash); color: var(--n-red); }
  .n-row__icon { --n-icon-size: 18px; }
  .n-row__main { flex: 1 1 auto; min-width: 0; }
  .n-row__label { display: block; }
  .n-row__sub { display: block; margin-top: 2px; color: var(--n-text-2); font-size: var(--n-fs-small); font-weight: 400; }
  .n-row__val { display: inline-flex; align-items: center; gap: 4px; min-width: 0; max-width: 55%; color: var(--n-text-3); font-size: 14px; }
  .n-row__val > span:not(.n-icon) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .n-row__chev { font-size: 18px; color: var(--n-text-4); }
  .n-row.is-danger, .n-row.is-danger .n-row__chev { color: var(--n-danger); }
  .n-row.is-danger .n-row__icon { background: var(--n-danger-wash); color: var(--n-danger); }
  .n-row:disabled, .n-row[aria-disabled="true"] { opacity: .45; cursor: default; }

  /* NEmptyState / NErrorState */
  .n-empty { display: grid; justify-items: center; padding: 40px 24px; text-align: center; }
  .n-empty__icon { display: grid; place-items: center; width: 56px; height: 56px; margin-bottom: 16px; border-radius: 50%; background: var(--n-red-wash); color: var(--n-red); }
  .n-empty__icon { --n-icon-size: 28px; }
  .n-empty--error .n-empty__icon { background: var(--n-danger-wash); color: var(--n-danger); }
  .n-empty__title { margin: 0; font: 700 17px/1.3 var(--n-font-display); color: var(--n-text); text-wrap: balance; }
  .n-empty__body { max-width: 36ch; margin: 6px 0 0; color: var(--n-text-2); font-size: 14px; line-height: 1.5; text-wrap: pretty; }
  .n-empty__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 20px; }
  .n-empty--compact { padding: 24px 16px; }
  .n-empty--go .n-empty__icon { background: var(--n-go-wash); color: var(--n-go); }

  /* Forms: label above field, validation under it */
  .n-form { display: grid; gap: 14px; }
  .n-form__intro { margin: 0 0 16px; }
  .n-form__link { justify-self: center; display: inline-flex; align-items: center; min-height: 44px; color: var(--n-pink); font: 600 13px/1 var(--n-font-body); text-decoration: none; }
  .n-field { display: grid; gap: 6px; }
  .n-label { font: 600 13px/1.3 var(--n-font-body); color: var(--n-text-2); }
  .n-field .validation-message { color: var(--n-danger); font-size: 12px; }
  select.n-input {
    padding-right: 36px; cursor: pointer;
    background: var(--n-sunken) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' stroke='%23a1a1aa' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 12px center;
  }

  /* NInlineAlert: danger wash with a 3px rule by default */
  .n-alert {
    display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: var(--n-r-sm);
    background: var(--n-danger-wash); border-left: 3px solid var(--n-red); color: var(--n-text); font-size: 14px; line-height: 1.45; text-align: left;
  }
  .n-alert { --n-icon-size: 20px; }
  .n-alert > .n-icon { margin-top: -1px; color: var(--n-danger); }
  .n-alert__body { flex: 1 1 auto; min-width: 0; }
  .n-alert__title { display: block; font-weight: 600; }
  .n-alert__action { flex: none; align-self: center; }
  .n-alert--info { background: var(--n-card-2); border-left-color: var(--n-line-3); }
  .n-alert--info > .n-icon { color: var(--n-text-2); }
  .n-alert--go { background: var(--n-go-wash); border-left-color: var(--n-go); }
  .n-alert--go > .n-icon { color: var(--n-go); }
  .n-alert--amber { background: var(--n-amber-wash); border-left-color: var(--n-amber); }
  .n-alert--amber > .n-icon { color: var(--n-amber); }

  /* NSkeleton: first load only; a refetch keeps the old content on screen */
  .n-skel {
    display: block; border-radius: var(--n-r-xs);
    background: linear-gradient(90deg, var(--n-card) 25%, var(--n-card-3) 50%, var(--n-card) 75%) 0 0 / 200% 100%;
    animation: n-shimmer calc(1400ms / var(--n-tempo)) ease-in-out infinite;
  }
  /* On a card the base would vanish into it; step both stops up one surface. */
  .n-card .n-skel, .n-sheet .n-skel { background-image: linear-gradient(90deg, var(--n-card-2) 25%, var(--n-card-3) 50%, var(--n-card-2) 75%); }
  .n-skel--line { height: .8em; border-radius: 6px; }
  .n-skel--block { border-radius: var(--n-r-md); }
  .n-skel--circle { border-radius: 50%; }
  .n-skel-lines { display: grid; gap: 8px; }

  /* NSpinner: the one ring. Buttons, pull-to-refresh and infinite scroll only; screens use skeletons. */
  .n-spinner {
    --s: 20px; display: inline-block; flex: none; width: var(--s); height: var(--s); border-radius: 50%; vertical-align: middle;
    border: 2px solid rgba(255,255,255,.2); border-top-color: var(--n-red);
    animation: n-spin calc(800ms / var(--n-tempo)) linear infinite;
  }
  .n-spinner-wrap { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 16px; }
  .n-spinner-wrap__text { color: var(--n-text-2); font-size: var(--n-fs-small); }

  /* NSheet (port of H.I.T.'s HitSheet). Phones: bottom sheet with a grabber; >= 768px: centred dialog.
     Entry fills backwards only, so the panel never stays a containing block for fixed children (an
     NConfirm opened from inside a sheet still covers the screen). */
  .n-sheet-root { position: fixed; inset: 0; z-index: var(--n-z-sheet); display: flex; align-items: flex-end; justify-content: center; }
  .n-sheet__scrim { position: absolute; inset: 0; background: var(--n-scrim); touch-action: none; animation: n-scrim-in calc(320ms / var(--n-tempo)) ease backwards; }
  .n-sheet {
    position: relative; display: flex; flex-direction: column; width: 100%; max-width: 560px; max-height: calc(100dvh - var(--n-safe-t) - 24px);
    padding-bottom: var(--n-safe-b); border-radius: var(--n-r-sheet) var(--n-r-sheet) 0 0; background: var(--n-card);
    border: 1px solid var(--n-line); border-bottom: 0; box-shadow: var(--n-shadow-sheet); outline: none; touch-action: pan-y;
    animation: n-sheet-up calc(320ms / var(--n-tempo)) var(--n-glide) backwards;
  }
  .n-sheet--tall { height: calc(100dvh - var(--n-safe-t) - 24px); }
  .n-sheet__grab { flex: none; display: grid; place-items: center; height: 24px; cursor: grab; touch-action: none; }
  .n-sheet__grab::before { content: ""; width: 38px; height: 5px; border-radius: 3px; background: var(--n-line-3); }
  .n-sheet__head { flex: none; display: flex; align-items: flex-start; gap: 12px; padding: 0 20px 12px; touch-action: none; }
  .n-sheet__titles { flex: 1 1 auto; min-width: 0; padding-top: 4px; }
  .n-sheet__title { margin: 2px 0 0; font: 700 var(--n-fs-h2)/1.25 var(--n-font-display); color: var(--n-text); }
  .n-sheet__close {
    position: relative; flex: none; display: grid; place-items: center; width: 36px; height: 36px; margin-right: -6px;
    border: 0; border-radius: 50%; background: var(--n-card-2); color: var(--n-text-2); cursor: pointer;
  }
  .n-sheet__close::after { content: ""; position: absolute; inset: -4px; }
  .n-sheet__close:disabled { opacity: .45; cursor: default; }
  .n-sheet__close { --n-icon-size: 20px; }
  .n-sheet__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 20px 20px; }
  .n-sheet--flush .n-sheet__body { padding: 0 8px 8px; }
  .n-sheet__foot { flex: none; display: grid; gap: 8px; padding: 12px 20px; border-top: 1px solid var(--n-line); }
  @media (min-width: 768px) {
    .n-sheet-root { align-items: center; padding: 24px; }
    .n-sheet {
      max-width: 520px; max-height: min(760px, 88dvh); padding-bottom: 0; border-radius: var(--n-r-sheet); border-bottom: 1px solid var(--n-line);
      animation: n-pop calc(260ms / var(--n-tempo)) var(--n-out) backwards;
    }
    .n-sheet--tall { height: min(760px, 88dvh); }
    .n-sheet__grab { height: 16px; visibility: hidden; }
  }

  /* NConfirm */
  .n-sheet--confirm { max-width: 440px; }
  .n-confirm { padding-top: 4px; text-align: center; }
  .n-confirm .n-empty__icon { margin: 0 auto 14px; }
  .n-confirm__title { margin: 0 0 8px; font: 700 var(--n-fs-h2)/1.25 var(--n-font-display); color: var(--n-text); text-wrap: balance; }
  .n-confirm__msg { margin: 0; color: var(--n-text-2); font-size: 14px; line-height: 1.5; text-wrap: pretty; }
  .n-confirm .n-alert { margin-top: 14px; }
  .n-confirm__actions { display: grid; gap: 10px; margin-top: 22px; }
  @media (min-width: 768px) {
    .n-sheet--confirm { max-width: 400px; }
    .n-confirm__actions { grid-template-columns: 1fr 1fr; }
    .n-confirm__actions > :first-child { order: 2; }
  }

  /* NMenu: an action sheet on phones, a popover under its trigger from 768px */
  .n-menu { position: relative; display: inline-flex; }
  /* Anchorless (a sheet with no trigger): no box at all. As an inline-flex it left a line box after the
     page (a 22px scroll under the full-height DM thread); the sheet root is fixed or moved to <body>. */
  .n-menu--sheet { display: contents; }
  .n-menu__list { display: grid; padding: 0 8px 8px; }
  .n-menu__title { padding: 0 12px 8px; }
  .n-menu__item {
    display: flex; align-items: center; gap: 14px; width: 100%; min-height: 50px; padding: 0 12px; border: 0; border-radius: 12px;
    background: none; color: var(--n-text); font: 500 16px/1.2 var(--n-font-body); text-align: left; text-decoration: none; cursor: pointer;
  }
  .n-menu__item { --n-icon-size: 22px; }
  .n-menu__item > .n-icon { color: var(--n-text-2); }
  .n-menu__item:active { background: var(--n-card-2); }
  @media (hover: hover) { .n-menu__item:hover:not(:disabled) { background: var(--n-card-2); } }
  .n-menu__item.is-danger, .n-menu__item.is-danger > .n-icon { color: var(--n-danger); }
  .n-menu__item:disabled { opacity: .45; cursor: default; }
  .n-menu__sub { display: block; margin-top: 2px; color: var(--n-text-3); font-size: 12px; font-weight: 400; }
  @media (min-width: 768px) {
    .n-menu:not(.n-menu--sheet) > .n-sheet-root { position: absolute; inset: auto; top: calc(100% + 6px); right: 0; display: block; padding: 0; }
    .n-menu--start > .n-sheet-root { right: auto; left: 0; }
    .n-menu--start > .n-sheet-root > .n-sheet { transform-origin: top left; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root > .n-sheet__scrim { position: fixed; background: transparent; animation: none; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root > .n-sheet {
      width: max-content; min-width: 220px; max-width: 320px; max-height: min(480px, 70dvh); border: 1px solid var(--n-line-2);
      border-radius: var(--n-r-md); background: var(--n-card-2); box-shadow: var(--n-shadow-float); transform-origin: top right;
      animation: n-pop calc(200ms / var(--n-tempo)) var(--n-out) backwards;
    }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root > .n-sheet .n-sheet__grab { display: none; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-sheet__body { padding: 0; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-menu__list { padding: 6px; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-menu__title { padding: 8px 10px 4px; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-menu__item { min-height: 40px; gap: 12px; padding: 0 10px; border-radius: var(--n-r-sm); font-size: 14px; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-menu__item { --n-icon-size: 20px; }
    .n-menu:not(.n-menu--sheet) > .n-sheet-root .n-menu__item:hover:not(:disabled) { background: var(--n-card-3); }
  }

  /* Upsell sheet (NccShell.ShowUpsell) */
  .n-upsell { padding: 4px 0; text-align: center; }
  .n-upsell__mark { display: grid; place-items: center; width: 64px; height: 64px; margin: 4px auto 14px; border-radius: 18px;
    background: radial-gradient(100% 100% at 30% 20%, rgba(232,35,43,.35), rgba(232,35,43,.08)); color: var(--n-red); }
  .n-upsell__mark { --n-icon-size: 32px; }
  .n-upsell__title { margin: 10px 0 8px; font: 700 22px/1.2 var(--n-font-display); color: var(--n-text); text-wrap: balance; }
  .n-upsell__body { max-width: 34ch; margin: 0 auto; color: var(--n-text-2); font-size: 15px; line-height: 1.5; }
  .n-upsell__actions { display: grid; gap: 10px; margin-top: 22px; }
}

/* NToastHost: top drop-in, above sheets. Unlayered; it is shell chrome like the bars. */
.n-toast-host { position: fixed; z-index: var(--n-z-toast); top: calc(var(--n-safe-t) + 8px); left: 0; right: 0; display: grid; justify-items: center; padding: 0 10px; pointer-events: none; }
.n-toast {
  pointer-events: auto; display: flex; align-items: center; gap: 4px; width: min(100%, 420px); padding: 6px; border-radius: var(--n-r-lg);
  background: rgba(35,36,36,.94); border: 1px solid var(--n-line-2); box-shadow: var(--n-shadow-float);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
  animation: n-drop calc(420ms / var(--n-tempo)) var(--n-pop) backwards;
}
.n-toast.is-leaving { opacity: 0; translate: 0 -30%; transition: opacity calc(220ms / var(--n-tempo)) ease, translate calc(220ms / var(--n-tempo)) ease; }
.n-toast__main { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 12px; padding: 6px 8px 6px 6px; border: 0; background: none; color: inherit; text-align: left; cursor: pointer; }
.n-toast__icon { flex: none; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 11px; background: var(--n-card-3); color: var(--n-text); }
.n-toast__icon { --n-icon-size: 20px; }
.n-toast.is-go .n-toast__icon { background: var(--n-go-wash); color: var(--n-go); }
.n-toast.is-alert .n-toast__icon { background: var(--n-red); color: #fff; }
.n-toast__text { flex: 1 1 auto; min-width: 0; }
.n-toast__k { display: block; font: 700 var(--n-fs-kicker)/1.2 var(--n-font-display); letter-spacing: var(--n-ls-kicker); text-transform: uppercase; color: var(--n-text-3); }
.n-toast__t { display: block; font: 600 14px/1.3 var(--n-font-body); color: var(--n-text-hi); text-wrap: pretty; }
.n-toast__go { flex: none; color: var(--n-text-3); }
.n-toast__action {
  flex: none; min-height: 40px; padding: 0 14px; border: 0; border-radius: 14px; background: var(--n-card-3); color: var(--n-pink); cursor: pointer;
  font: 700 12px/1 var(--n-font-display); letter-spacing: var(--n-ls-btn); text-transform: uppercase;
}

/* Scroll lock while a sheet is open (ncc-ui.js counts nested sheets). On <html> only: body is
   height:100% (h-full), so clipping it too would collapse the page and jump it to the top. */
html.n-locked { overflow: hidden; }

/* NBootCover: the native splash's logo (Resources/Splash/splash_ncc.png, MauiSplashScreen BaseSize
   300x300), same size and centre, on the one ink, with a thin red progress bar under it. The host
   pages paint the static copy (#ncc-boot); ncc.bootDone() fades it after the first layout render. */
.n-boot { position: fixed; inset: 0; z-index: var(--n-z-full); background: var(--n-bg); }
.n-boot--contained { position: absolute; z-index: auto; overflow: hidden; }
.n-boot__logo { position: absolute; top: 50%; left: 50%; width: 300px; height: 300px; margin: -150px 0 0 -150px; }
.n-boot__bar { position: absolute; top: calc(50% + 84px); left: 50%; width: 120px; height: 2px; margin-left: -60px; overflow: hidden; border-radius: 2px; background: rgba(255,255,255,.08); }
.n-boot__bar::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 40%; background: var(--n-red); animation: n-boot-bar calc(1200ms / var(--n-tempo)) ease-in-out infinite; }
.n-boot__label { position: absolute; top: calc(50% + 100px); left: 0; right: 0; text-align: center; color: var(--n-text-2); font: 500 13px/1.4 var(--n-font-body); }
.n-boot.is-done { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity calc(320ms / var(--n-tempo)) ease, visibility 0s linear calc(320ms / var(--n-tempo)); }
@keyframes n-boot-bar { from { translate: -100% 0; } to { translate: 250% 0; } }

/* Full-screen gates (update required, maintenance, the error boundary); --inline sits in the page. */
.n-gate {
  position: fixed; inset: 0; z-index: var(--n-z-full); display: grid; place-items: center; overflow-y: auto;
  padding: calc(var(--n-safe-t) + 24px) 24px calc(var(--n-safe-b) + 24px); background: var(--n-bg); color: var(--n-text);
}
.n-gate--inline { position: static; z-index: auto; min-height: 55dvh; padding: 40px var(--n-gutter); background: none; }
.n-gate__box { display: grid; justify-items: center; width: 100%; max-width: 420px; text-align: center; }
.n-gate__icon { display: grid; place-items: center; width: 80px; height: 80px; margin-bottom: 18px; border-radius: 50%; background: var(--n-red-wash); color: var(--n-red); }
.n-gate__icon { --n-icon-size: 40px; }
.n-gate__title { margin: 10px 0 10px; font: 700 var(--n-fs-title)/1.1 var(--n-font-display); letter-spacing: var(--n-ls-title); color: var(--n-text); text-wrap: balance; }
.n-gate__body { margin: 0 0 24px; color: var(--n-text-2); font-size: 15px; line-height: 1.55; text-wrap: pretty; }
.n-gate__meta { margin: -12px 0 24px; }
.n-gate__actions { display: grid; gap: 10px; width: 100%; }
.n-gate details { width: 100%; margin-top: 20px; text-align: left; color: var(--n-text-2); font-size: 13px; }
.n-gate summary { cursor: pointer; }
.n-gate pre {
  max-height: 240px; margin: 10px 0 0; padding: 12px; overflow: auto; border-radius: var(--n-r-sm); background: var(--n-sunken); color: var(--n-text-2);
  font: 11px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; word-break: break-word; -webkit-user-select: text; user-select: text;
}

/* Blazor reconnect panel (web host, App.razor). Blazor toggles components-reconnect-* on the modal;
   ncc-ui.js retries, resumes or reloads. */
#components-reconnect-modal { display: none; }
#components-reconnect-modal.components-reconnect-show, #components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-failed, #components-reconnect-modal.components-reconnect-rejected,
#components-reconnect-modal.components-reconnect-paused, #components-reconnect-modal.components-reconnect-resume-failed {
  position: fixed; inset: 0; z-index: calc(var(--n-z-full) + 1); display: grid; place-items: end center;
  padding: 16px 16px calc(24px + var(--n-safe-b)); background: rgba(0,0,0,.45); animation: n-fade calc(300ms / var(--n-tempo)) ease backwards;
}
.n-reconnect {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 14px; width: min(420px, 100%); padding: 16px 18px; border-radius: var(--n-r-lg);
  background: var(--n-card); border: 1px solid var(--n-line-2); box-shadow: var(--n-shadow-float); color: var(--n-text-hi); font: 600 15px/1.35 var(--n-font-body);
}
.n-reconnect__dot { width: 12px; height: 12px; border-radius: 50%; background: var(--n-red); animation: n-pulse calc(1200ms / var(--n-tempo)) ease-out infinite; }
.n-reconnect .n-kicker { display: block; margin-bottom: 2px; }
.n-reconnect [data-when] { display: none; }
#components-reconnect-modal.components-reconnect-show [data-when~="show"],
#components-reconnect-modal.components-reconnect-retrying [data-when~="retrying"],
#components-reconnect-modal.components-reconnect-paused [data-when~="paused"],
#components-reconnect-modal.components-reconnect-failed [data-when~="failed"],
#components-reconnect-modal.components-reconnect-rejected [data-when~="failed"],
#components-reconnect-modal.components-reconnect-resume-failed [data-when~="failed"] { display: block; }
@keyframes n-pulse { from { box-shadow: 0 0 0 0 rgba(232,35,43,.55); } to { box-shadow: 0 0 0 12px rgba(232,35,43,0); } }

/* 6. SHELL ------------------------------------------------------------------------------------ */
/* <main> clears the floating tab bar once (phones) and gets 40px of air on desktop. Unlayered so it
   beats the legacy py-4 / lg:py-10 utilities on the same element. */
.n-main--tabs { padding-bottom: var(--n-tab-room); }
/* Pages on <NPage> bring their own gutter and top spacing; the legacy wrapper paddings step aside. */
.n-main:has(> .n-route > .n-page) { padding-top: 0; }
.n-route:has(> .n-page) { padding-inline: 0; }
.n-page { width: 100%; max-width: var(--n-max); margin: 0 auto; padding: var(--n-page-top) var(--n-gutter) 0; }
.n-page--wide { max-width: var(--n-max-wide); }
.n-page--flush { padding-inline: 0; }
/* EmptyLayout (sign-in, onboarding, the paywall): the one ink under the top inset, as tall as the page. */
.n-empty-layout { min-height: 100dvh; padding-top: var(--n-safe-t); overflow-y: auto; background: var(--n-bg); }

/* Top bar: fixed, glass, padded by the top inset with a 56px row. The frosted layer is ::after, so the bar
   itself never becomes the containing block of anything fixed inside it; ::before paints the one ink
   above the bar, so rubber-band overscroll never shows a different black behind the Dynamic Island. The
   hairline appears only once the page has scrolled (html.n-scrolled, ncc-ui.js). */
.n-topbar { position: fixed; top: 0; left: 0; right: 0; z-index: var(--n-z-topbar); padding-top: var(--n-safe-t); color: var(--n-text);
  border-bottom: 1px solid transparent; transition: border-color var(--n-dur) ease; }
.n-topbar::before { content: ""; position: absolute; bottom: 100%; left: 0; right: 0; height: 100vh; background: var(--n-bg); pointer-events: none; }
.n-topbar::after { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--n-glass);
  -webkit-backdrop-filter: var(--n-glass-fx); backdrop-filter: var(--n-glass-fx); pointer-events: none; }
html.n-scrolled .n-topbar { border-bottom-color: var(--n-line); }
.n-topbar__row { position: relative; display: flex; align-items: center; gap: 2px; height: var(--n-topbar-h); padding: 0 calc(var(--n-gutter) - 8px); }
.n-topbar__logo { display: inline-flex; align-items: center; min-height: 44px; padding: 0 6px; margin-right: 4px; }
.n-topbar__logo img { display: block; height: 24px; width: auto; }
.n-topbar__spacer { flex: 1 1 auto; }
.n-topbar__me { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-width: 44px; min-height: 44px; padding: 0 6px;
  border: 0; border-radius: var(--n-r-pill); background: none; color: var(--n-text); cursor: pointer; transition: scale var(--n-dur-fast) ease; }
.n-topbar__me:active { scale: .94; }
.n-topbar__name { display: none; max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 14px/1 var(--n-font-body); }
.n-topbar__crumbs { padding: 8px var(--n-gutter); border-top: 1px solid var(--n-line); background: var(--n-bg); }
/* An admin list page's main action (NButton), from 640px. Unlayered, so it beats .n-btn's display. */
.n-topbar__tool { display: none; margin-right: 6px; }
@media (min-width: 640px) { .n-topbar__tool { display: inline-flex; } }
@media (min-width: 1024px) {
  /* The sidebar carries the logo and the navigation on desktop (these rules are unlayered, so the
     lg:hidden utility on the same elements can't do it). */
  .n-topbar { left: 16rem; }
  .n-topbar__logo, .ncc-nav-notice { display: none; }
  .n-topbar__name { display: inline; }
  @media (hover: hover) { .n-topbar__me:hover { background: var(--n-card); } }
}

/* Streak chip: the streak at a glance from every screen but Licks */
.ncc-streak-chip { display: inline-flex; align-items: center; gap: 2px; height: 28px; padding: 0 10px 0 6px; border-radius: var(--n-r-pill);
  background: var(--n-card); border: 1px solid var(--n-card-3); color: var(--n-text-2);
  font-family: var(--n-font-display); font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; text-decoration: none; }
.ncc-streak-chip { --n-icon-size: 20px; }
.ncc-streak-chip.lit { color: var(--n-text-hi); border-color: rgba(232,35,43,.5); background: var(--n-red-wash); }
.ncc-streak-chip.lit .n-icon { color: var(--n-red); }

/* Notifications: the bell in the bar; a sheet on phones, a dropdown under the bell from 1024px */
.ncc-bell { position: relative; display: inline-flex; }
.ncc-bell__catch { position: fixed; inset: 0; }
.ncc-bell__pop { position: absolute; top: calc(100% + 6px); right: -4px; width: 380px; max-height: min(520px, 70dvh); display: flex; flex-direction: column;
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-md); background: var(--n-card); box-shadow: var(--n-shadow-float); overflow: hidden;
  transform-origin: top right; animation: n-pop calc(200ms / var(--n-tempo)) var(--n-out) backwards; }
.ncc-bell__head { display: flex; align-items: center; gap: 10px; padding: 14px 16px 10px; border-bottom: 1px solid var(--n-line); }
.ncc-bell__title { margin: 0 auto 0 0; font: 700 var(--n-fs-h3)/1.2 var(--n-font-display); color: var(--n-text); }
.ncc-bell__scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 6px; }
.ncc-bell__bar { display: flex; align-items: center; justify-content: flex-end; gap: 10px; min-height: 28px; padding: 0 12px 6px; }
.ncc-bell__bar:empty { display: none; }
.ncc-bell__new { margin-right: auto; padding: 2px 8px; border-radius: var(--n-r-pill); background: var(--n-red-wash); color: var(--n-pink);
  font: 700 var(--n-fs-meta)/1.4 var(--n-font-body); }
.ncc-bell__all { min-height: 36px; padding: 0 4px; border: 0; background: none; color: var(--n-pink); font: 600 13px/1 var(--n-font-body); cursor: pointer; }
.ncc-notif-list { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.ncc-notif { position: relative; display: flex; align-items: flex-start; gap: 4px; padding: 10px 4px 10px 10px; border-radius: 12px; }
.ncc-notif.is-unread { background: var(--n-red-wash); }
.ncc-notif__main { flex: 1 1 auto; min-width: 0; display: flex; align-items: flex-start; gap: 12px; padding: 0; border: 0; background: none;
  color: inherit; text-align: left; cursor: pointer; }
.ncc-notif__icon { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 50%; background: var(--n-card-2); color: var(--n-pink); }
.ncc-notif__body { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.ncc-notif__title { font: 700 14px/1.3 var(--n-font-display); color: var(--n-text); }
.ncc-notif__msg { font-size: var(--n-fs-small); line-height: 1.4; color: var(--n-text-2); }
.ncc-notif__dot { flex: none; width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; background: var(--n-red); }
.ncc-notif__x { margin: -6px 0 0; color: var(--n-text-3); }
@media (hover: hover) { .ncc-notif:hover { background: var(--n-card-2); } .ncc-notif.is-unread:hover { background: rgba(232,35,43,.2); } }

/* "You" sheet (opened from the avatar): rows inside an NSheet, which owns the scrim, the drag and
   the exit. */
.ncc-you .n-sheet__body { display: grid; gap: 2px; padding: 0 8px 12px; }
.ncc-you-head { display: flex; align-items: center; gap: 12px; width: 100%; padding: 4px 8px 12px; margin-bottom: 6px; border: 0;
  border-bottom: 1px solid var(--n-line); border-radius: 0; background: none; color: var(--n-text); text-align: left; cursor: pointer; }
.ncc-you-id { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.ncc-you-name { font: 700 17px/1.25 var(--n-font-display); color: var(--n-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ncc-you-sub { font-size: var(--n-fs-meta); color: var(--n-text-2); }
.ncc-you-chev { color: var(--n-text-3); }
.ncc-you-row { display: flex; align-items: center; gap: 14px; width: 100%; min-height: 48px; padding: 0 8px; border: 0; border-radius: 12px; background: none;
  color: var(--n-text); font: 500 16px/1.2 var(--n-font-body); text-align: left; cursor: pointer; }
.ncc-you-row, .ncc-you-head { --n-icon-size: 22px; }
.ncc-you-row:active, .ncc-you-head:active { background: var(--n-card-2); }
@media (hover: hover) { .ncc-you-row:hover { background: var(--n-card-2); } }
.ncc-you-row .n-icon { color: var(--n-text-2); }
.ncc-you-label { flex: 1 1 auto; min-width: 0; }
.ncc-you-row.accent, .ncc-you-row.accent .n-icon { color: var(--n-pink); }
.ncc-you-row.muted { color: var(--n-text-2); }

/* Desktop sidebar (MainLayout, from 1024px; phones have the tab pill): the top bar's ink with a hairline
   on its edge. 44px Space Grotesk rows in --n-text-2; the current section sits on the red wash, like the
   tab bar's puck. The sections fill the height, so the saved lessons and the NCC Pro button sit at the foot. */
.n-side { display: none; }
@media (min-width: 1024px) {
  .n-side { position: fixed; z-index: var(--n-z-tabbar); top: 0; bottom: 0; left: 0; display: flex; flex-direction: column; gap: 16px; width: 16rem;
    padding-bottom: 32px; overflow-y: auto; overscroll-behavior: contain; background: var(--n-bg); border-right: 1px solid var(--n-line); }
}
.n-side__logo { align-self: flex-start; display: inline-flex; margin: 16px 16px 0; padding: 0 4px; }
.n-side__logo img { display: block; height: 52px; width: auto; }
.n-side__nav { flex: 1 0 auto; display: flex; flex-direction: column; gap: 2px; padding: 0 12px; }
.n-side__item { display: flex; align-items: center; gap: 14px; width: 100%; min-height: 44px; padding: 0 12px; border: 0; border-radius: var(--n-r-md);
  background: none; color: var(--n-text-2); font: 500 15px/1.2 var(--n-font-display); text-align: left; text-decoration: none; cursor: pointer;
  transition: color var(--n-dur-fast) ease, background-color var(--n-dur-fast) ease; }
.n-side__item { --n-icon-size: 22px; }
@media (hover: hover) { .n-side__item:hover { color: var(--n-text); background: var(--n-card); } }
.n-side__item.is-active { color: var(--n-text-hi); background: var(--n-red-wash); }
.n-side__item.is-active .n-icon { color: var(--n-red); }
.n-side__label { display: flex; align-items: center; gap: 6px; padding: 18px 12px 6px; }
.n-side__label { --n-icon-size: 16px; }
.n-side__label .n-icon { color: var(--n-red); }
.n-side__saved { display: flex; flex-direction: column; gap: 2px; padding: 0 12px; }
.n-side__saved > .n-side__label { padding-top: 0; }
.n-side__fav { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 6px 8px; border-radius: var(--n-r-sm);
  color: var(--n-text); text-decoration: none; transition: background-color var(--n-dur-fast) ease; }
@media (hover: hover) { .n-side__fav:hover { background: var(--n-card); } }
.n-side__thumb { flex: none; width: 40px; }
.n-side__fav-text { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.n-side__fav-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 var(--n-fs-small)/1.3 var(--n-font-display); color: var(--n-text); }
.n-side__more { padding: 4px 8px; }
.n-side__cta { padding: 0 24px; }

/* One-time note about the tab change, just above the pill */
.ncc-nav-notice { position: fixed; z-index: calc(var(--n-z-tabbar) + 1); left: 12px; right: 12px; max-width: 520px; margin-inline: auto;
  bottom: calc(var(--n-safe-b) + var(--n-tab-gap) + var(--n-tab-h) + 10px);
  display: flex; align-items: center; gap: 4px; padding: 6px 4px 6px 14px; border: 1px solid var(--n-line-2); border-radius: var(--n-r-md);
  background: var(--n-card-3); box-shadow: var(--n-shadow-card); animation: n-rise calc(420ms / var(--n-tempo)) var(--n-out) backwards; }
.ncc-nav-notice p { flex: 1 1 auto; margin: 0; font-size: var(--n-fs-meta); line-height: 1.45; color: var(--n-text); }
.ncc-nav-notice strong { color: var(--n-pink); }

/* Bottom bar: floating pill with a sliding red puck, ported from H.I.T. --i is the active cell;
   data-none hides the puck off-tab. It slides out of the way while the keyboard is up (html.kb-open). */
.ncc-tabbar { position: fixed; z-index: var(--n-z-tabbar); left: 14px; right: 14px; bottom: calc(var(--n-safe-b) + var(--n-tab-gap));
  max-width: 520px; margin-inline: auto; height: var(--n-tab-h); padding: 6px; border-radius: var(--n-r-pill);
  border: 1px solid var(--n-line); background: var(--n-glass);
  -webkit-backdrop-filter: var(--n-glass-fx); backdrop-filter: var(--n-glass-fx);
  box-shadow: var(--n-shadow-float), inset 0 1px 0 rgba(255,255,255,.05); transform: translateZ(0);
  transition: translate var(--n-dur) var(--n-glide), opacity var(--n-dur) ease; }
html.kb-open .ncc-tabbar, html.kb-open .ncc-nav-notice { translate: 0 calc(100% + var(--n-tab-gap) + var(--n-safe-b) + 24px); opacity: 0; pointer-events: none; }
.ncc-tabbar-inner { --n: 4; --i: 0; position: relative; height: 100%; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); isolation: isolate; }
.ncc-tabbar-puck { position: absolute; z-index: -1; top: 0; bottom: 0; left: 0; width: calc(100% / var(--n)); border-radius: var(--n-r-pill);
  background: var(--n-red-wash); box-shadow: inset 0 0 0 1px var(--n-red-line);
  transform: translateX(calc(var(--i) * 100%)); transition: transform calc(320ms / var(--n-tempo)) var(--n-pop), opacity var(--n-dur) ease; }
.ncc-tabbar-inner[data-none] .ncc-tabbar-puck { opacity: 0; }
.ncc-tab { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; min-width: 44px; min-height: 44px;
  padding: 0; border: 0; background: none; color: var(--n-text-2); text-decoration: none; cursor: pointer; transition: color var(--n-dur) ease;
  -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }
.ncc-tab:hover, .ncc-tab:visited { color: var(--n-text-2); text-decoration: none; }
.ncc-tab-icon { position: relative; display: grid; place-items: center; }
.ncc-tab svg { width: 23px; height: 23px; }
.ncc-tab-dot { position: absolute; top: -1px; right: -4px; width: 8px; height: 8px; border-radius: 50%; background: var(--n-red); box-shadow: 0 0 0 2px var(--n-bg); }
.ncc-tab-label { font: 600 var(--n-fs-kicker)/1 var(--n-font-display); letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; }
.ncc-tab.on, .ncc-tab.on:hover, .ncc-tab.on:visited { color: var(--n-pink); }
.ncc-tab.on svg { color: var(--n-red); }
.ncc-tab:active svg { transform: scale(.9); transition: transform .1s; }

/* Pull-to-refresh (NPullToRefresh), one look on every page: main.js (nccPullToRefresh) drives the
   opacity and transform inline while you pull, so these are the resting values. The arrow shows while
   pulling; the one spinner while the refresh runs (.ncc-ptr-spinning). */
.n-ptr {
  position: fixed; top: calc(var(--n-safe-t) + 8px); left: 0; right: 0; z-index: var(--n-z-push);
  display: flex; justify-content: center; opacity: 0; transform: translateY(0); pointer-events: none;
  will-change: transform, opacity;
}
.n-ptr__puck {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--n-card); border: 1px solid var(--n-line-2); box-shadow: var(--n-shadow-card);
}
.n-ptr__puck > * { grid-area: 1 / 1; }
.n-ptr__arrow { color: var(--n-red); }
.n-ptr__spin { visibility: hidden; }
.n-ptr.ncc-ptr-spinning .n-ptr__arrow { visibility: hidden; }
.n-ptr.ncc-ptr-spinning .n-ptr__spin { visibility: visible; }

/* Admin breadcrumbs (AdminBreadcrumbs, in the top bar on admin pages): kicker-style trail on the tokens. */
.n-crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 0; margin: 0; padding: 0; list-style: none; }
.n-crumbs li { display: inline-flex; align-items: center; min-width: 0; }
.n-crumbs__link, .n-crumbs__here { font: 700 var(--n-fs-kicker)/1.2 var(--n-font-display); letter-spacing: var(--n-ls-kicker); text-transform: uppercase; }
.n-crumbs__link { display: inline-flex; align-items: center; color: var(--n-text-3); text-decoration: none; transition: color var(--n-dur-fast) ease; }
@media (hover: hover) { .n-crumbs__link:hover { color: var(--n-pink); } }
.n-crumbs__here { color: var(--n-text); }
.n-crumbs__sep { margin: 0 var(--n-2); color: var(--n-text-4); }

/* "Get the app" card on the mobile website (InstallAppPrompt): a glass card in the slot just above the
   floating tab pill, shaped like the other floaters there (MiniPlayer, the gear buy bar, the nav notice).
   It shares that slot, so it steps aside while one of them is up, and it hides while the keyboard is open,
   like the pill. MainLayout only renders it on pages with the pill. */
.n-install {
  position: fixed; z-index: var(--n-z-push); left: 14px; right: 14px; bottom: calc(var(--n-safe-b) + var(--n-tab-gap) + var(--n-tab-h) + 10px);
  max-width: 520px; margin-inline: auto; padding: var(--n-2) var(--n-1) var(--n-2) var(--n-3); border: 1px solid var(--n-line-2); border-radius: var(--n-r-lg);
  background: var(--n-glass); -webkit-backdrop-filter: var(--n-glass-fx); backdrop-filter: var(--n-glass-fx);
  box-shadow: var(--n-shadow-float); animation: n-rise var(--n-dur) var(--n-out) backwards;
}
html.kb-open .n-install, body:has(.ln-mini, .gr-buybar, .ncc-nav-notice) .n-install { display: none; }
@media (min-width: 1024px) {
  /* No pill from here (a wide Android tablet): rest on the bottom edge, right of the sidebar. */
  .n-install { left: calc(16rem + 14px); bottom: calc(var(--n-safe-b) + 16px); }
}
.n-install__inner { display: flex; align-items: center; gap: var(--n-2); }
.n-install__icon { flex: none; width: 40px; height: 40px; border-radius: var(--n-r-sm); }
.n-install__text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.n-install .n-btn { flex: none; }

/* Tuner (TunerModal, from the top bar): a glass panel dropped in under the bar, clear of the desktop
   sidebar. Brand red marks the string you're on; the meter and readout go green in tune, amber within
   15 cents, danger beyond. */
.n-tuner {
  position: fixed; top: calc(var(--n-safe-t) + var(--n-topbar-h)); left: 0; right: 0; z-index: var(--n-z-push);
  background: var(--n-glass); -webkit-backdrop-filter: var(--n-glass-fx); backdrop-filter: var(--n-glass-fx);
  border-bottom: 1px solid var(--n-line); box-shadow: var(--n-shadow-float);
  animation: n-drop var(--n-dur) var(--n-glide) backwards;
}
@media (min-width: 1024px) { .n-tuner { left: 16rem; } }
/* Its own name for the way out: re-pointing the finished n-drop at "reverse" wouldn't restart it. */
.n-tuner.is-closing { animation: n-tuner-out var(--n-dur-fast) var(--n-glide) forwards; pointer-events: none; }
@keyframes n-tuner-out { to { opacity: 0; translate: 0 -120%; } }
.n-tuner__head { display: flex; align-items: center; gap: var(--n-2); padding: 6px 6px 6px var(--n-4); border-bottom: 1px solid var(--n-line); }
.n-tuner__glyph { color: var(--n-pink); }
.n-tuner__title { flex: 1; min-width: 0; }
.n-tuner__strings {
  display: flex; align-items: center; justify-content: safe center; gap: 10px; padding: var(--n-3) var(--n-4) 6px;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.n-tuner__strings::-webkit-scrollbar { display: none; }
.n-tuner__string {
  flex-shrink: 0; display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 2px solid var(--n-line-2); background: var(--n-card); color: var(--n-text); font: 700 13px/1 var(--n-font-display);
  transition: background-color var(--n-dur) ease, border-color var(--n-dur) ease, color var(--n-dur) ease, scale var(--n-dur-fast) var(--n-pop);
}
.n-tuner__string:active { scale: .94; }
.n-tuner__string.is-on { border-color: var(--n-red-line); background: var(--n-red); color: var(--n-on-red); scale: 1.06; }
.n-tuner__string.is-tuned { border-color: var(--n-go); background: var(--n-go); color: var(--n-bg); scale: 1.06; }
.n-tuner__readout { display: flex; align-items: center; gap: var(--n-4); padding: 6px var(--n-4) 14px; }
.n-tuner__note {
  min-width: 64px; text-align: center; color: var(--n-text);
  font: 700 30px/1 var(--n-font-display); letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.n-tuner__note.is-tuned { color: var(--n-go); }
.n-tuner__note.is-idle { color: var(--n-text-3); }
.n-tuner__meter-wrap { flex: 1; min-width: 0; }
.n-tuner__meter { position: relative; height: 28px; }
.n-tuner__track { position: absolute; left: 0; right: 0; top: 13px; height: 2px; border-radius: 2px; background: var(--n-line-2); }
.n-tuner__zone { position: absolute; left: 45%; width: 10%; top: 8px; height: 12px; border-radius: 3px; background: var(--n-go-wash); }
.n-tuner__tick { position: absolute; left: 50%; top: 4px; width: 2px; height: 20px; background: var(--n-text-4); translate: -1px 0; }
.n-tuner__needle {
  position: absolute; top: 2px; left: var(--x, 50%); width: 4px; height: 24px; border-radius: 2px; translate: -2px 0; opacity: 0;
  transition: left calc(120ms / var(--n-tempo)) ease-out, background-color var(--n-dur) ease;
}
.n-tuner__needle.is-live { opacity: 1; }
.n-tuner__needle.is-tuned { background: var(--n-go); }
.n-tuner__needle.is-close { background: var(--n-amber); }
.n-tuner__needle.is-off { background: var(--n-danger); }
.n-tuner__scale {
  display: flex; justify-content: space-between; color: var(--n-text-3);
  font: 600 var(--n-fs-kicker)/1.3 var(--n-font-display); letter-spacing: var(--n-ls-kicker); text-transform: uppercase;
}
.n-tuner__dev { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; min-width: 86px; }
.n-tuner__cents { font: 700 var(--n-fs-meta)/1.2 var(--n-font-display); letter-spacing: .06em; text-transform: uppercase; font-variant-numeric: tabular-nums; }
.n-tuner__cents.is-tuned { color: var(--n-go); }
.n-tuner__cents.is-close { color: var(--n-amber); }
.n-tuner__cents.is-off { color: var(--n-danger); }
.n-tuner__hint { animation: n-fade 1s ease-in-out infinite alternate; }
.n-tuner__blocked {
  display: flex; align-items: center; gap: var(--n-3); padding: 10px var(--n-4);
  border-top: 1px solid var(--n-red-line); background: var(--n-danger-wash); color: var(--n-danger);
}
.n-tuner__blocked-text { flex: 1; min-width: 0; display: grid; gap: 2px; color: var(--n-text-2); font-size: var(--n-fs-meta); line-height: 1.35; }
.n-tuner__blocked-text strong { color: var(--n-text); font-size: var(--n-fs-small); font-weight: 600; }
.n-tuner__error { margin: 0; padding: var(--n-2) var(--n-4); border-top: 1px solid var(--n-red-line); background: var(--n-danger-wash); color: var(--n-danger); font-size: var(--n-fs-meta); }

/* 404 (Routes.razor NotFound), an NPage: full width so the wash reaches the edge, its own gutter. */
.ncc-404 { position: relative; max-width: none; min-height: 80vh; overflow: hidden; padding: 48px var(--n-gutter) 0; background: var(--n-bg); }
.ncc-404__wash { position: absolute; top: 0; right: 0; width: 55%; height: 100%; background: linear-gradient(to left, rgba(232,35,43,.12), transparent); pointer-events: none; }
.ncc-404__copy { position: relative; z-index: 2; max-width: 640px; margin: 0 auto; text-align: center; }
.ncc-404__copy .n-kicker { display: block; margin-bottom: 12px; }
.ncc-404__title { margin: 0 0 18px; }
.ncc-404__title span { background: linear-gradient(to right, var(--n-pink), var(--n-red), var(--n-pink)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.ncc-404__body { max-width: 440px; margin: 0 auto 28px; font-size: 15px; line-height: 1.55; color: var(--n-text-2); }
.ncc-404__band { position: absolute; z-index: 1; bottom: 0; left: 50%; translate: -50% 0; width: min(640px, 90vw); max-height: 52vh; object-fit: contain;
  object-position: bottom; opacity: .95; pointer-events: none; }

/* 7. MOTION KIT ------------------------------------------------------------------------------- */
/* Entry keyframes use the individual translate/scale properties so they compose with an element's own
   transform. Durations divide by --n-tempo. */
@keyframes n-rise { from { opacity: 0; translate: 0 var(--rise, 14px); } }
@keyframes n-fade { from { opacity: 0; } }
@keyframes n-pop { from { opacity: 0; scale: .9; } }
@keyframes n-sheet-up { from { translate: 0 100%; } }
@keyframes n-scrim-in { from { opacity: 0; } }
@keyframes n-drop { from { opacity: 0; translate: 0 -120%; } }
@keyframes n-page-in { from { opacity: 0; translate: 14px 0; } }
@keyframes n-page-back { from { opacity: 0; translate: -14px 0; } }
@keyframes n-page-fade { from { opacity: 0; translate: 0 6px; } }
@keyframes n-like { 0% { scale: .6; } 45% { scale: 1.28; } 70% { scale: .94; } }
@keyframes n-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@keyframes n-spin { to { rotate: 360deg; } }

.n-rise { animation: n-rise calc(560ms / var(--n-tempo)) var(--n-out) both; animation-delay: calc(var(--d, 0ms) / var(--n-tempo)); }
.n-fade { animation: n-fade calc(420ms / var(--n-tempo)) var(--n-out) both; animation-delay: calc(var(--d, 0ms) / var(--n-tempo)); }
.n-pop { animation: n-pop calc(420ms / var(--n-tempo)) var(--n-pop) both; animation-delay: calc(var(--d, 0ms) / var(--n-tempo)); }
.n-like { animation: n-like calc(520ms / var(--n-tempo)) var(--n-pop) 1; }

/* Staggered rise for a block's children, 60 ms steps, capped at 10 animated children. */
.n-stagger > * { animation: n-rise calc(560ms / var(--n-tempo)) var(--n-out) both; }
.n-stagger > :nth-child(2) { animation-delay: calc(60ms / var(--n-tempo)); }  .n-stagger > :nth-child(3) { animation-delay: calc(120ms / var(--n-tempo)); }
.n-stagger > :nth-child(4) { animation-delay: calc(180ms / var(--n-tempo)); } .n-stagger > :nth-child(5) { animation-delay: calc(240ms / var(--n-tempo)); }
.n-stagger > :nth-child(6) { animation-delay: calc(300ms / var(--n-tempo)); } .n-stagger > :nth-child(7) { animation-delay: calc(360ms / var(--n-tempo)); }
.n-stagger > :nth-child(8) { animation-delay: calc(420ms / var(--n-tempo)); } .n-stagger > :nth-child(9) { animation-delay: calc(480ms / var(--n-tempo)); }
.n-stagger > :nth-child(10) { animation-delay: calc(540ms / var(--n-tempo)); }
.n-stagger > :nth-child(n+11) { animation: none; }

/* Press feedback for anything tappable. */
.n-press { transition: scale var(--n-dur-fast) ease; }
.n-press:active { scale: .97; }

/* Scroll-driven rise where supported (Safari 26+, Chrome); elsewhere content is simply there. */
@supports (animation-timeline: view()) {
  .n-scroll-rise { animation: n-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 40%; }
}

/* Route transition. MainLayout keys .n-route on the FIRST path segment, so /forums -> /forums/{id} never
   remounts the feed; ncc-ui.js sets html[data-nav] only when that segment changes (a new animation-name
   would replay it on the mounted wrapper). Backwards fill only: a forwards fill would leave a translate
   on the wrapper and make it the containing block for every fixed layer inside the page. "none" is a
   back the OS already animated (the iOS edge swipe, a browser's own back). */
.n-route { animation: n-page-in calc(380ms / var(--n-tempo)) var(--n-glide) backwards; }
html[data-nav="back"] .n-route { animation-name: n-page-back; }
html[data-nav="tab"] .n-route { animation-name: n-page-fade; }
html[data-nav="none"] .n-route { animation: none; }
/* A page that arrives with a full-screen layer open (a post notification to /forums/{id}, ?compose=1,
   the takes viewer) skips the entry: while it runs the wrapper is that layer's containing block and
   stacking context, so it would show as a box under the bars, then jump. Also cuts the entry short if
   such a layer opens before it ends. NSheets move themselves out (ncc.sheetAttach). */
.n-route:has(.post-detail-overlay.is-open, [aria-modal="true"], .dl-feed, .n-sheet-root) { animation: none; }

/* Odometer (ncc.odometer builds the digit columns) */
.n-odo { display: inline-block; font-variant-numeric: tabular-nums; white-space: nowrap; }
.n-odo.is-rolling { display: inline-flex; align-items: baseline; }
.n-odo__col { display: inline-flex; flex-direction: column; position: relative; height: 1.2em; clip-path: inset(0 -0.25em); }
.n-odo__strip { display: block; will-change: transform; }
.n-odo__strip > span { display: block; height: 1.2em; line-height: 1.2; text-align: center; }
.n-odo__ch { display: inline-block; white-space: pre; }

/* View Transitions (ncc.vt): pages set view-transition-name on the parts that move. */
::view-transition-group(*) { animation-duration: calc(380ms / var(--n-tempo)); animation-timing-function: var(--n-glide); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: calc(240ms / var(--n-tempo)); }

/* 8. REDUCED MOTION --------------------------------------------------------------------------- */
/* One switch for the whole app. Animations still run, but in .01ms and once, so anything that ends in
   a forwards fill (older screens fade in from opacity 0) lands visible instead of staying hidden. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; transition-delay: 0s !important; scroll-behavior: auto !important;
  }
  .n-scroll-rise { animation: none !important; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
