/* ============================================================
   NOTIONKIT COMPONENT LIBRARY
   Jungherz GmbH – v1.19.1

   A pure CSS component library for calm, document-centric
   workspace interfaces. No build step, no JavaScript, no
   framework coupling.

   Features:
   - Scoped reset (no unprefixed global selectors)
   - Light mode (default) + dark mode via [data-theme="dark"]
   - ~130 components across app shell, page, database, forms,
     overlays, collaboration and AI surfaces
   - Editor adapter section for TipTap / BlockNote / Novel, sharing
     its rules with .nk-prose for rendered text
   ============================================================ */


/* ============================================================
   A NOTE ON THE TWO-BLOCK STRUCTURE

   This file is physically split into two contiguous blocks:

     BLOCK A – design tokens:  :root { … } [data-theme="dark"] { … }
     BLOCK B – components:     everything else, no --nk-* declarations

   build-styles-js.mjs slices the minified sheet at exactly those
   two rule blocks and emits tokensCss / componentsCss separately.
   The split is asserted at build time; if a --nk-* declaration
   leaks into a component rule, or if the two token blocks stop
   being adjacent, the build fails.

   Why it matters: a shadow root that adopts the *whole* sheet
   also adopts the token blocks, and inside that shadow root the
   selectors match the element's own theme wrapper. Every token is
   then re-declared locally — and a matching rule always beats an
   inherited value, so a consumer's own `:root { --nk-accent: … }`
   never arrives. Consumers that adopt only componentsCss keep
   inheritance intact and put tokensCss on the document instead.

   Practical consequences while editing this file:
   - Never declare a --nk-* custom property outside BLOCK A.
   - Never put a rule between the :root and [data-theme="dark"] blocks.
   - Derive brand-dependent values with color-mix() from a token,
     never from a hard-coded hex. Re-branding must stay reachable
     from a handful of declarations.
   ============================================================ */


/* ============================================================
   A NOTE ON THE ::slotted() PAIRS

   Several rules are written twice, e.g.

     .nk-tree-item .icon,
     .nk-tree-item ::slotted(.icon) { … }

   They are not redundant. When this sheet is adopted into a shadow
   root — as NotionKit Elements will do — content passed in from the
   outside stays in the light DOM and is therefore no descendant of
   anything in the shadow tree. `.nk-tree-item .icon` cannot reach it;
   only `::slotted()` can.

   Do not "simplify" these away. In the document they match nothing,
   so they cost nothing there.

   Three limits worth knowing:
   - ::slotted() only ever matches the assigned node itself. An icon
     wrapped in a container — <span slot="icon"><em>📌</em></span> —
     cannot be styled from inside the shadow root at all. Pass slotted
     content directly.
   - The descendant space is mandatory: `.nk-callout ::slotted(.c-icon)`,
     never `.nk-callout::slotted(.c-icon)`. The compound before
     ::slotted selects the slot element inside the shadow tree.
   - For slotted content the outer tree wins. A consumer's own document
     rule takes precedence over ::slotted() from the shadow tree. That
     is a feature, not a bug.
   - Since 1.1.0 every part that NotionKit Elements exposes as a named
     slot has a second twin keyed on the slot name, e.g.
     `.nk-tree-item ::slotted([slot="icon"])`, so a consumer writes
     <span slot="icon">📁</span> without repeating the internal class.
   - Margin and padding in a twin are marked !important when the scoped
     reset (0. above) also sets them – on buttons, headings, paragraphs.
     The reset lives in the document tree, and for *normal* declarations
     the outer tree beats ::slotted() from the shadow tree; for
     !important ones the inner tree wins. Without the flag a slotted
     <button> inside <nk-segmented> would render with the reset's
     zero padding. Everything else in a twin stays overridable.
   ============================================================ */


/* ============================================================
   0. SCOPED RESET

   NotionKit never touches selectors it does not own (PRD 7.4).
   Instead of `* { margin: 0 }` the reset reaches only elements that
   carry an nk- class and plain content elements *inside* NotionKit
   surfaces. Specificity is (0,1,0), the same as a single class, and
   the reset is declared before every component rule — so component
   rules at equal specificity win on source order.
   ============================================================ */
[class*="nk-"],
[class*="nk-"] *,
[class*="nk-"]::before,
[class*="nk-"]::after,
[class*="nk-"] *::before,
[class*="nk-"] *::after {
  box-sizing: border-box;
}

[class*="nk-"] :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, pre, ul, ol, li) {
  margin: 0;
  padding: 0;
}

[class*="nk-"] :where(ul, ol) {
  list-style: none;
}

[class*="nk-"] :where(button, input, select, textarea, option, optgroup, fieldset, legend),
:where(button, input, select, textarea)[class*="nk-"] {
  margin: 0;
  padding: 0;
}

/* `hidden` hides. The attribute is only a user-agent rule, and every
   component that sets its own display beat it: a hidden button, tag or
   banner stayed on screen. !important gives the attribute its platform
   meaning back, for nk- elements and for slotted nodes in a shadow root;
   hidden="until-found" keeps the browser's own content-visibility. Two
   rules, not one list: a browser that rejects ::slotted() outside a shadow
   root would otherwise drop the document half with it. */
[class*="nk-"][hidden]:not([hidden="until-found" i]) { display: none !important; }
::slotted([hidden]:not([hidden="until-found" i])) { display: none !important; }


/* ============================================================
   BLOCK A – DESIGN TOKENS

   Everything below until the end of the [data-theme="dark"] block
   is extracted verbatim by build-styles-js.mjs. Keep the two rule
   blocks adjacent and free of anything else.

   Re-branding needs one declaration: --nk-accent. Focus rings,
   checked states, the selected model card and the primary button
   are all mixed from it. --nk-danger and the three --nk-decor-*
   values are the second tier, for destructive actions and for the
   decorative avatar/cover gradients.
   ============================================================ */
:root {
  /* Tells the browser which scheme its own widgets should use: date
     and time pickers, number spinners, select popups, scrollbars and
     autofill. Without it they render dark on a light page. */
  color-scheme: light;

  /* ---- Surfaces ----
     Values follow Notion's 2025 light theme: a neutral sidebar grey, a
     hover wash mixed from the text colour, and a filled input surface. */
  --nk-bg: #ffffff;
  --nk-bg-sidebar: #f9f8f7;
  --nk-bg-hover: rgba(55,53,47,0.06);
  --nk-bg-active: rgba(55,53,47,0.08);
  --nk-bg-callout: #f0efed;
  --nk-bg-code: #f7f6f3;
  --nk-bg-card: #ffffff;
  --nk-bg-input: rgba(242,241,238,0.6);

  /* ---- Text ----
     Opaque greys, not alpha: Notion moved from rgba(55,53,47,α) to fixed
     values so text reads the same on white and on the sidebar. The
     sidebar gets its own, darker step – that is where legibility was
     lost most. */
  --nk-text: #2c2c2b;
  --nk-text-secondary: #7d7a75;
  --nk-text-tertiary: #91918e;
  --nk-text-sidebar: #5f5e5b;

  /* ---- Borders ---- */
  --nk-border: rgba(28,19,1,0.11);
  --nk-border-strong: rgba(27,21,0,0.19);

  /* ---- Accent & semantics ---- */
  --nk-accent: #2383e2;
  --nk-on-accent: #ffffff;
  --nk-danger: #cd3c3a;

  /* ---- Colour scale ----
     Notion's nine hues in three roles. `tag`: the select-option pill –
     a saturated fill with near-black text. `tint`: the soft block /
     callout background, for banners and tracks, meant to sit under
     the normal text colour. `color`: the mid-tone for coloured text
     and marks – deltas, date mentions, progress fills. */
  --nk-tag-gray-bg: #e3e2e0;   --nk-tag-gray-text: #32302c;
  --nk-tag-brown-bg: #eee0da;  --nk-tag-brown-text: #442a1e;
  --nk-tag-orange-bg: #fadec9; --nk-tag-orange-text: #49290e;
  --nk-tag-yellow-bg: #fdecc8; --nk-tag-yellow-text: #402c1b;
  --nk-tag-green-bg: #dbeddb;  --nk-tag-green-text: #1c3829;
  --nk-tag-blue-bg: #d3e5ef;   --nk-tag-blue-text: #183347;
  --nk-tag-purple-bg: #e8deee; --nk-tag-purple-text: #412454;
  --nk-tag-pink-bg: #f5e0e9;   --nk-tag-pink-text: #4c2337;
  --nk-tag-red-bg: #ffe2dd;    --nk-tag-red-text: #5d1715;

  --nk-tint-gray: #f1f1ef;   --nk-color-gray: #787774;
  --nk-tint-brown: #f4eeee;  --nk-color-brown: #9f6b53;
  --nk-tint-orange: #fbecdd; --nk-color-orange: #d9730d;
  --nk-tint-yellow: #fbf3db; --nk-color-yellow: #cb912f;
  --nk-tint-green: #edf3ec;  --nk-color-green: #448361;
  --nk-tint-blue: #e7f3f8;   --nk-color-blue: #337ea9;
  --nk-tint-purple: #f8f3fc; --nk-color-purple: #9065b0;
  --nk-tint-pink: #fcf1f6;   --nk-color-pink: #c14c8a;
  --nk-tint-red: #fdebec;    --nk-color-red: #cd3c3a;

  /* ---- Decorative ----
     Avatar gradients and the page cover. Deliberately identical in
     both themes: these are illustrative surfaces, not UI chrome. */
  --nk-decor-purple: #9065b0;
  --nk-decor-blue: #529cca;
  --nk-decor-orange: #d9730d;

  /* ---- Overlays ---- */
  --nk-scrim: rgba(15,15,15,0.6);
  --nk-scrim-soft: rgba(15,15,15,0.5);

  /* ---- Metrics ---- */
  --nk-sidebar-width: 260px;
  --nk-peek-width: 560px;
  --nk-page-full-max: none;
  --nk-cover-height: 200px;
  --nk-panel-cover-height: 64px;
  --nk-tab-bar-height: 58px;
  --nk-radius: 6px;
  --nk-font: ui-sans-serif, -apple-system, "Segoe UI", Inter, Helvetica, Arial, sans-serif;
  --nk-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* ---- Shadows ----
     --nk-shadow-btn is Notion's white button: a 1px inset ring plus a
     1px drop, so the outline is drawn by the shadow, not by a border. */
  --nk-shadow-menu: rgba(15,15,15,0.05) 0px 0px 0px 1px, rgba(15,15,15,0.1) 0px 3px 6px, rgba(15,15,15,0.2) 0px 9px 24px;
  --nk-shadow-card: 0 1px 2px rgba(0,0,0,0.04);
  --nk-shadow-btn: inset 0 0 0 1px rgba(15,15,15,0.1), 0 1px 2px rgba(15,15,15,0.1);
  --nk-shadow-knob: 0 1px 2px rgba(0,0,0,0.2);
  --nk-shadow-segment: 0 1px 2px rgba(0,0,0,0.08);
}

[data-theme="dark"] {
  color-scheme: dark;

  --nk-bg: #191919;
  --nk-bg-sidebar: #202020;
  --nk-bg-hover: rgba(255,255,255,0.055);
  --nk-bg-active: rgba(255,255,255,0.08);
  --nk-bg-callout: #252525;
  --nk-bg-code: #202020;
  --nk-bg-card: #202020;
  --nk-bg-input: rgba(255,255,255,0.055);

  --nk-text: rgba(255,255,255,0.81);
  --nk-text-secondary: rgba(255,255,255,0.46);
  --nk-text-tertiary: rgba(255,255,255,0.32);
  --nk-text-sidebar: rgba(255,255,255,0.62);

  --nk-border: rgba(255,255,255,0.094);
  --nk-border-strong: rgba(255,255,255,0.16);

  --nk-accent: #529CCA;
  --nk-danger: #df5452;

  --nk-tag-gray-bg: #373737;   --nk-tag-gray-text: rgba(255,255,255,0.85);
  --nk-tag-brown-bg: #603b2c;  --nk-tag-brown-text: rgba(255,255,255,0.85);
  --nk-tag-orange-bg: #854c1d; --nk-tag-orange-text: rgba(255,255,255,0.85);
  --nk-tag-yellow-bg: #89632a; --nk-tag-yellow-text: rgba(255,255,255,0.85);
  --nk-tag-green-bg: #2b593f;  --nk-tag-green-text: rgba(255,255,255,0.85);
  --nk-tag-blue-bg: #28456c;   --nk-tag-blue-text: rgba(255,255,255,0.85);
  --nk-tag-purple-bg: #492f64; --nk-tag-purple-text: rgba(255,255,255,0.85);
  --nk-tag-pink-bg: #69314c;   --nk-tag-pink-text: rgba(255,255,255,0.85);
  --nk-tag-red-bg: #6e3630;    --nk-tag-red-text: rgba(255,255,255,0.85);

  --nk-tint-gray: #252525;   --nk-color-gray: #9b9b9b;
  --nk-tint-brown: #2e2724;  --nk-color-brown: #ba856f;
  --nk-tint-orange: #36291f; --nk-color-orange: #c77d48;
  --nk-tint-yellow: #372e20; --nk-color-yellow: #ca8f3d;
  --nk-tint-green: #242b26;  --nk-color-green: #529e72;
  --nk-tint-blue: #1f282d;   --nk-color-blue: #5e87c9;
  --nk-tint-purple: #2a2430; --nk-color-purple: #9d68d3;
  --nk-tint-pink: #2e2328;   --nk-color-pink: #d15796;
  --nk-tint-red: #332523;    --nk-color-red: #df5452;

  --nk-shadow-menu: rgba(15,15,15,0.2) 0px 0px 0px 1px, rgba(15,15,15,0.4) 0px 3px 6px, rgba(15,15,15,0.6) 0px 9px 24px;
  --nk-shadow-card: none;
  --nk-shadow-btn: inset 0 0 0 1px rgba(255,255,255,0.1), 0 1px 2px rgba(0,0,0,0.3);
}


/* ============================================================
   BLOCK B – COMPONENTS

   No --nk-* declarations below this line. Grouped by PRD chapter 5.
   ============================================================ */


/* ============================================================
   B0. DOCUMENT BASE (opt-in)

   Applied by adding class="nk-body" to <body>. Kept opt-in so the
   library never claims the page it is embedded in.
   ============================================================ */
.nk-body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;   /* iOS standalone PWAs count the status bar into 100vh */
  font-family: var(--nk-font);
  font-size: 14px;
  background: var(--nk-bg);
  color: var(--nk-text);
  /* `auto`, as in Notion. `antialiased` thins every glyph on macOS and was
     the single biggest reason text looked lighter than the original. */
  -webkit-font-smoothing: auto;
  transition: background .25s ease, color .25s ease;
}


/* ============================================================
   B1. APP SHELL & LAYOUT  (PRD 5.1)
   ============================================================ */
.nk-app { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }

/* ---- Sidebar ---- */
.nk-sidebar {
  width: calc(var(--nk-sidebar-width) + env(safe-area-inset-left, 0px));
  min-width: calc(var(--nk-sidebar-width) + env(safe-area-inset-left, 0px));
  padding-left: env(safe-area-inset-left, 0px);
  background: var(--nk-bg-sidebar);
  display: flex; flex-direction: column;
  border-right: 1px solid var(--nk-border);
  transition: background .25s ease, margin-left .24s cubic-bezier(.2, .8, .25, 1);
}

.nk-workspace {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; margin: 6px 8px 2px;
  border-radius: var(--nk-radius);
  cursor: pointer; font-weight: 500;
  user-select: none;
}
.nk-workspace:hover { background: var(--nk-bg-hover); }
.nk-workspace .avatar,
.nk-workspace ::slotted(.avatar),
.nk-workspace ::slotted([slot="avatar"]) {
  width: 22px; height: 22px; border-radius: 4px;
  background: linear-gradient(135deg, var(--nk-decor-purple), var(--nk-decor-blue));
  color: var(--nk-on-accent); font-size: 11px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
}
.nk-workspace .chev { margin-left: auto; color: var(--nk-text-tertiary); font-size: 11px; }

.nk-sidebar-scroll { flex: 1; overflow-y: auto; padding: 4px 8px 16px; }
.nk-sidebar-scroll::-webkit-scrollbar { width: 8px; }
.nk-sidebar-scroll::-webkit-scrollbar-thumb { background: var(--nk-border-strong); border-radius: 4px; }

.nk-section-label {
  font-size: 12px; font-weight: 500; letter-spacing: .01em;
  color: var(--nk-text-tertiary);
  padding: 14px 10px 4px;
  display: flex; justify-content: space-between; align-items: center;
}
.nk-section-label .plus {
  cursor: pointer; border-radius: 4px; padding: 0 4px; font-size: 13px;
  opacity: 0; transition: opacity .15s;
}
.nk-section-label:hover .plus { opacity: 1; }
.nk-section-label .plus:hover { background: var(--nk-bg-hover); }

.nk-sidebar-footer {
  padding: 8px; border-top: 1px solid var(--nk-border);
  color: var(--nk-text-sidebar); font-size: 14px;
}
.nk-sidebar-footer .nk-tree-item { min-height: 26px; }
/* The drawer's scrim and the ☰ that opens it; both only act below 860px. */
.nk-sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 59; background: var(--nk-scrim-soft); }
.nk-sidebar-toggle { display: none; }

/* Collapsing on the desktop, Notion's «: .nk-sidebar.collapsed slides the
   sidebar out to the left and the main column takes its width; hidden, it
   takes no focus – it stays visible while it slides, and is back at once
   when it expands. .nk-sidebar-toggle.collapsed shows the topbar's ☰ that
   brings it back, on the desktop too. The « is .nk-sidebar-collapse in
   .nk-sidebar-head beside the workspace row; it shows while the pointer is
   over the sidebar. A phone keeps the drawer (B12). */
.nk-sidebar.collapsed {
  margin-left: calc(0px - var(--nk-sidebar-width) - env(safe-area-inset-left, 0px)); visibility: hidden;
  transition: background .25s ease, margin-left .24s cubic-bezier(.2, .8, .25, 1), visibility 0s linear .24s;
}
.nk-sidebar-toggle.collapsed { display: inline-flex; }
.nk-sidebar-head { display: flex; align-items: center; }
.nk-sidebar-head > .nk-workspace,
.nk-sidebar-head ::slotted(.nk-workspace) { flex: 1; min-width: 0; }
.nk-sidebar-collapse {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: 4px 12px 0 -4px; padding: 0;
  border: none; border-radius: var(--nk-radius); background: transparent;
  color: var(--nk-text-tertiary); cursor: pointer; opacity: 0; transition: opacity .15s;
}
.nk-sidebar:hover .nk-sidebar-collapse,
.nk-sidebar-collapse:focus-visible { opacity: 1; }
.nk-sidebar-collapse:hover { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-sidebar-collapse svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Main / Topbar ---- */
.nk-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.nk-topbar {
  height: 44px; display: flex; align-items: center;
  padding: 0 max(12px, env(safe-area-inset-right, 0px)) 0 max(12px, env(safe-area-inset-left, 0px));
  gap: 8px; flex-shrink: 0;
}
.nk-breadcrumb { display: flex; align-items: center; gap: 4px; font-size: 14px; }
.nk-breadcrumb .crumb,
.nk-breadcrumb ::slotted(.crumb) {
  padding: 2px 6px; border-radius: 4px; cursor: pointer;
  color: var(--nk-text-sidebar);
  display: flex; align-items: center; gap: 5px;
}
.nk-breadcrumb .crumb:hover { background: var(--nk-bg-hover); }
a.crumb { text-decoration: none; }
.nk-breadcrumb .crumb.current,
.nk-breadcrumb ::slotted(.crumb.current) { color: var(--nk-text); }
.nk-breadcrumb .sep { color: var(--nk-text-tertiary); font-size: 12px; }

.nk-topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.nk-topbar-btn {
  padding: 4px 8px; border-radius: var(--nk-radius); cursor: pointer;
  color: var(--nk-text-sidebar); font-size: 14px; user-select: none;
  border: none; background: transparent; font-family: inherit;
}
.nk-topbar-btn:hover { background: var(--nk-bg-hover); }
.nk-topbar-btn svg,
.nk-topbar-btn ::slotted(svg) {
  width: 16px; height: 16px; flex-shrink: 0;
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
/* Borderless since Notion's 2025 topbar: a plain word next to the icons. */
.nk-share-btn { font-size: 14px; padding: 4px 8px; }
/* Passive text among the actions – "Edited 2 min ago": tertiary, one line.
   A phone drops it (B12), as Notion's mobile topbar shows only the page and
   what can be done with it. */
.nk-topbar-meta,
.nk-topbar-actions ::slotted(.nk-topbar-meta) { padding: 4px 8px; font-size: 12px; color: var(--nk-text-tertiary); white-space: nowrap; }
.nk-theme-toggle { font-size: 15px; width: 30px; height: 28px; padding: 0; }

/* ---- Tab bar (phones, installed PWAs) ----
   A bottom row of up to five destinations, the thumb-reachable twin of the
   sidebar the breakpoint hides. Last child of .nk-main it sits below the
   scrolling page; in a document that scrolls itself it sticks to the
   viewport bottom. Hidden above 860px; `always` shows it at every width
   (previews, phone frames), `floating` turns it into a capsule.
   No view-transition-name here: the bar stays put between pages. ---- */
.nk-tab-bar {
  display: none; flex: none; align-items: stretch; gap: 2px;
  position: sticky; bottom: 0; z-index: 30;
  /* Safe areas: the bottom inset replaces the 6px padding rather than
     adding to it – the labels end where iOS ends its own tab bar, right
     above the home indicator. Left/right cover the Dynamic Island in
     landscape; the background still runs edge to edge. */
  box-sizing: border-box; height: calc(var(--nk-tab-bar-height) - 6px + max(6px, env(safe-area-inset-bottom, 0px)));
  padding: 6px max(4px, env(safe-area-inset-right, 0px)) max(6px, env(safe-area-inset-bottom, 0px)) max(4px, env(safe-area-inset-left, 0px));
  background: var(--nk-bg-sidebar);
  border-top: 1px solid var(--nk-border);
}
.nk-tab-bar.always { display: flex; }
/* `fixed`: pinned to the viewport instead of sitting in the column – for
   standalone PWAs where the shell and the screen disagree. The spacer that
   follows it keeps the same height in the flow, so the page still ends
   above the bar. */
.nk-tab-bar.fixed { position: fixed; left: 0; right: 0; bottom: 0; }
.nk-tab-bar-spacer { display: none; flex: none; height: calc(var(--nk-tab-bar-height) - 6px + max(6px, env(safe-area-inset-bottom, 0px))); }
.nk-tab-bar.always.fixed + .nk-tab-bar-spacer { display: block; }
.nk-tab-bar.floating {
  position: fixed; left: max(12px, env(safe-area-inset-left, 0px)); right: max(12px, env(safe-area-inset-right, 0px));
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  height: var(--nk-tab-bar-height);
  padding: 6px; border: 1px solid var(--nk-border); border-radius: 16px;
  box-shadow: var(--nk-shadow-menu);
}
.nk-tab-bar-item {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 4px 2px; border: none; border-radius: var(--nk-radius);
  background: transparent; font-family: inherit; font-size: 10.5px; line-height: 1.2;
  color: var(--nk-text-secondary); text-decoration: none;
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
}
.nk-tab-bar-item:hover { color: var(--nk-text); background: var(--nk-bg-hover); }
.nk-tab-bar-item.active { color: var(--nk-accent); }
.nk-tab-bar-item:disabled { opacity: .5; cursor: not-allowed; }
.nk-tab-bar-item .icon,
.nk-tab-bar-item ::slotted([slot="icon"]) { font-size: 20px; line-height: 1; }
.nk-tab-bar-item .label,
.nk-tab-bar-item ::slotted(.label) { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* ============================================================
   B2. NAVIGATION / PAGE TREE  (PRD 5.2)
   ============================================================ */
.nk-tree-item {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 8px 3px 10px;
  border-radius: var(--nk-radius);
  cursor: pointer; user-select: none;
  color: var(--nk-text-sidebar);
  position: relative;
  /* 28px; 40px inside a sheet, which sets --_nk-row. A private, inherited
     value rather than a descendant rule, so it also reaches rows that sit
     in shadow roots of their own (NotionKit Elements). Not a token. */
  min-height: var(--_nk-row, 28px);
}
.nk-tree-item:hover { background: var(--nk-bg-hover); }
.nk-tree-item.active { background: var(--nk-bg-active); color: var(--nk-text); font-weight: 500; }
/* Explicit form of the footer / settings-nav row height, for a row that is
   not a descendant of those containers (a web component's shadow tree). */
.nk-tree-item.compact { min-height: 26px; }
.nk-tree-item .icon,
.nk-tree-item ::slotted(.icon),
.nk-tree-item ::slotted([slot="icon"]) { font-size: 15px; width: 20px; text-align: center; flex-shrink: 0; }
.nk-tree-item .label,
.nk-tree-item ::slotted(.label) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nk-tree-item .actions {
  margin-left: auto; display: none; gap: 2px; color: var(--nk-text-tertiary);
}
.nk-tree-item:hover .actions { display: flex; }
.nk-tree-item .actions span { padding: 0 3px; border-radius: 3px; font-size: 12px; }
.nk-tree-item .actions span:hover { background: var(--nk-bg-active); }

.nk-tree-children { margin-left: 14px; border-left: 1px solid var(--nk-border); padding-left: 4px; overflow: hidden; }
.nk-tree-children.collapsed { display: none; }

.nk-toggle-arrow {
  width: 16px; height: 16px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9px; color: var(--nk-text-tertiary);
  border-radius: 3px; transition: transform .15s;
}
.nk-toggle-arrow.open { transform: rotate(90deg); }

.nk-kbd-hint { margin-left: auto; display: flex; gap: 3px; align-items: center; }
.nk-kbd {
  font-family: inherit; font-size: 10.5px; background: var(--nk-bg-callout);
  border: 1px solid var(--nk-border-strong); border-bottom-width: 2px;
  border-radius: 4px; padding: 0 4px;
}


/* ============================================================
   B3. PAGE SHELL & DOCUMENT  (PRD 5.3)
   ============================================================ */
.nk-page-scroll { flex: 1; overflow-y: auto; }
.nk-page-scroll::-webkit-scrollbar { width: 10px; }
.nk-page-scroll::-webkit-scrollbar-thumb { background: var(--nk-border-strong); border-radius: 5px; border: 2px solid var(--nk-bg); }

/* The band's height is the token --nk-cover-height (200px), set on :root or
   on one cover – Notion's own takes about 30vh, clamp(200px, 30vh, 300px)
   comes close. */
.nk-cover {
  height: var(--nk-cover-height);
  background:
    radial-gradient(ellipse at 20% 40%, color-mix(in srgb, var(--nk-decor-purple) 35%, transparent), transparent 55%),
    radial-gradient(ellipse at 80% 20%, color-mix(in srgb, var(--nk-decor-blue) 35%, transparent), transparent 55%),
    radial-gradient(ellipse at 60% 90%, color-mix(in srgb, var(--nk-decor-orange) 25%, transparent), transparent 55%),
    var(--nk-bg-callout);
}
/* A picture instead of the gradient: an <img> inside fills the band and is
   cropped, never stretched; object-position moves the crop, as Notion's
   "Reposition" does. The gradient stays underneath while it loads. */
.nk-cover > img,
.nk-cover ::slotted(img) { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Document text is 16px/1.5, one step above the 14px UI chrome – Notion's
   own split between page and app. Tables, tags and controls keep 14px. */
.nk-page { max-width: 760px; margin: 0 auto; padding: 24px max(64px, env(safe-area-inset-right, 0px)) 120px max(64px, env(safe-area-inset-left, 0px)); font-size: 16px; line-height: 1.5; }
/* Page options, as in Notion's page menu, set per page and not per app:
   `full` lifts the 760px cap so the column fills the window – up to
   --nk-page-full-max, none by default: a dashboard of tables may want more
   than 760px but no 1600px lines – and `small` sets the document text one
   step down to 14px. Heading, lead, prose and editor are sized in em and
   follow; title, properties, tables and controls keep their size. */
.nk-page.full { max-width: var(--nk-page-full-max); }
.nk-page.small { font-size: 14px; }
/* With a cover the icon overlaps its bottom edge and the page needs no top
   padding; without a cover it sits inside the padding, fully visible even in
   a scroll container. A cover without an icon keeps the padding, so the
   title never touches the picture – Notion leaves room there too. Class
   markup: the cover is the page's previous sibling and the icon its first
   child. Elements: <nk-page> sets `covered` on the page box when both are
   there. */
.nk-cover + .nk-page:has(> .nk-page-icon:not([hidden])),
.nk-page.covered { padding-top: 0; }

.nk-page-icon,
.nk-page ::slotted(.nk-page-icon),
.nk-page ::slotted([slot="icon"]) {
  font-size: 64px; line-height: 1; margin-top: 0;
  cursor: pointer; user-select: none;
  display: inline-block;
}
.nk-cover + .nk-page .nk-page-icon,
.nk-cover + .nk-page ::slotted(.nk-page-icon),
.nk-cover + .nk-page ::slotted([slot="icon"]),
.nk-page.covered .nk-page-icon,
.nk-page.covered ::slotted(.nk-page-icon),
.nk-page.covered ::slotted([slot="icon"]) { margin-top: -42px; }
.nk-page-title {
  font-size: var(--_nk-title, 40px); font-weight: 700; line-height: 1.2; margin: 8px 0 4px;
  outline: none; letter-spacing: 0;
}
.nk-page-meta {
  color: var(--nk-text-tertiary); font-size: 13px; margin-bottom: 24px;
  display: flex; gap: 16px;
}
/* Page properties, as Notion lists them under the title of a database page:
   one row each, the name in a 160px column with its type icon, the value
   beside it. Both halves take the hover wash, as each opens its own editor
   in Notion. Takes the place of .nk-page-meta on a page that is a row.
   The value keeps at least 220px: in a column narrower than 380px – a side
   panel, a third of the page – it moves under its name instead of breaking
   an address into syllables. */
.nk-props { display: flex; flex-direction: column; margin: 0 0 var(--nk-block-space, 20px); font-size: 14px; line-height: 1.5; }
/* .flush: no outer margin – inside a panel, a cell or a flex column with a
   gap of its own, where the margin meant for the flow under a title only
   adds to their spacing. */
.nk-props.flush { margin: 0; }
.nk-prop { display: flex; flex-wrap: wrap; align-items: flex-start; min-width: 0; }
.nk-prop .p-name {
  flex: 0 0 160px; min-width: 0; min-height: 34px; padding: 0 6px;
  display: flex; align-items: center; gap: 6px; overflow: hidden;
  border-radius: var(--nk-radius); color: var(--nk-text-secondary); white-space: nowrap; user-select: none;
}
.nk-prop .p-icon,
.nk-prop ::slotted([slot="icon"]) { width: 16px; flex-shrink: 0; text-align: center; font-size: 13px; }
.nk-prop .p-value {
  flex: 1 1 220px; min-width: 0; min-height: 34px; padding: 5px 8px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px;
  border-radius: var(--nk-radius); overflow-wrap: anywhere;
}
/* .text: a value that is text – a sentence, an address, a model name with a
   tag – flows and wraps as text instead of setting its parts one under the
   other; tags and people keep the row of items. */
.nk-prop .p-value.text { display: block; align-content: center; }
.nk-prop .p-name:hover,
.nk-prop .p-value:hover { background: var(--nk-bg-hover); }

/* Lead and heading are sized in em, so `small` and a small parent carry
   them along – 16px and 24px on a page, as before. */
.nk-page p.lead { font-size: 1em; line-height: 1.6; color: var(--nk-text-secondary); margin-bottom: 20px; }
.nk-page ::slotted(p.lead) { font-size: 1em; line-height: 1.6; color: var(--nk-text-secondary); margin-bottom: 20px !important; }

.nk-heading {
  font-size: 1.5em; font-weight: 600; line-height: 1.3; margin: 32px 0 10px;
  display: flex; align-items: center; gap: 8px;
}


/* ============================================================
   B4. CONTENT ELEMENTS  (PRD 5.4)
   ============================================================ */
/* A block's outer margin – callout, quote, code, divider, database, panels,
   properties and the rest below – is meant for the flow of a page. A column
   that spaces its children with a gap of its own sets --nk-block-space: 0
   once, on the column, and every block inside drops it; `.flush` drops it on
   one block. Headings keep theirs, they open a section. The property is no
   token: unset, each block keeps its own margin. */
:is(.nk-props, .nk-callout, .nk-bookmark, .nk-toggle, .nk-divider, .nk-quote, .nk-code, .nk-database, .nk-danger-zone, .nk-gallery-grid,
    .nk-template-btn, .nk-synced, .nk-banner, .nk-panels, .nk-skeleton, .nk-steps, .nk-comments, .nk-block-host, .nk-model-card,
    .nk-ai-input-row).flush { margin-top: 0; margin-bottom: 0; }
.nk-callout {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--nk-bg-callout);
  border-radius: var(--nk-radius);
  padding: 16px 16px 16px 12px; margin: var(--nk-block-space, 16px) 0;
  line-height: 1.5;
}
.nk-callout .c-icon,
.nk-callout ::slotted(.c-icon),
.nk-callout ::slotted([slot="icon"]) { font-size: 17px; }

/* Bookmark, Notion's link block: title, two lines of description and the
   address with its icon on the left, the page's preview image on the right
   in a third, 240px at most – a 1200×630 og:image fits it nearly whole in
   a page column and is cropped at the centre on a phone. The whole box is the
   link. Without an image the text takes the width, without a description
   the box gets lower. */
.nk-bookmark {
  display: flex; min-width: 0; margin: var(--nk-block-space, 8px) 0; overflow: hidden;
  border: 1px solid var(--nk-border); border-radius: var(--nk-radius);
  color: var(--nk-text); text-decoration: none; transition: background .12s ease;
}
.nk-bookmark:hover { background: var(--nk-bg-hover); }
.nk-bookmark .bm-text { flex: 1 1 0; min-width: 0; padding: 12px 14px 14px; font-size: 14px; line-height: 20px; }
.nk-bookmark .bm-title { display: block; min-height: 24px; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nk-bookmark .bm-desc {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  max-height: 32px; font-size: 12px; line-height: 16px; color: var(--nk-text-secondary);
}
.nk-bookmark .bm-url { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 12px; line-height: 16px; white-space: nowrap; }
.nk-bookmark .bm-url > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.nk-bookmark .bm-favicon { flex: none; width: 16px; height: 16px; }
.nk-bookmark .bm-cover { position: relative; flex: 0 0 33%; max-width: 240px; }
.nk-bookmark .bm-cover > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.nk-todo { display: flex; align-items: flex-start; gap: 8px; padding: 4px 0; }
.nk-todo input[type="checkbox"] {
  appearance: none; width: 16px; height: 16px; margin-top: 3px;
  border: 1.4px solid var(--nk-border-strong); border-radius: 2px;
  cursor: pointer; flex-shrink: 0; position: relative;
  background: var(--nk-bg);
}
.nk-todo input[type="checkbox"]:checked { background: var(--nk-accent); border-color: var(--nk-accent); }
.nk-todo input[type="checkbox"]:checked::after {
  content: "✓"; color: var(--nk-on-accent); font-size: 11px;
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
}
.nk-todo input:checked + span { text-decoration: line-through; color: var(--nk-text-tertiary); }
.nk-todo input:disabled { opacity: .5; cursor: not-allowed; }

/* The summary marker is a pseudo-element and therefore cannot be
   reached on slotted content — <nk-toggle> must render its own
   summary in the shadow tree rather than accept one via slot. */
.nk-toggle { margin: var(--nk-block-space, 6px) 0; }
.nk-toggle summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 6px;
  padding: 4px 6px; border-radius: var(--nk-radius); font-weight: 500;
  user-select: none;
}
.nk-toggle summary::-webkit-details-marker { display: none; }
.nk-toggle summary:hover { background: var(--nk-bg-hover); }
.nk-toggle summary::before {
  content: "▸"; color: var(--nk-text-tertiary); font-size: 11px;
  transition: transform .15s; display: inline-block;
}
.nk-toggle[open] summary::before { transform: rotate(90deg); }
.nk-toggle .toggle-body,
.nk-toggle ::slotted(.toggle-body) { padding: 4px 0 8px 26px; color: var(--nk-text-secondary); line-height: 1.55; }

.nk-divider { border: none; border-top: 1px solid var(--nk-border); margin: var(--nk-block-space, 24px) 0; }

.nk-quote {
  border-left: 3px solid var(--nk-text); padding: 2px 0 2px 14px;
  margin: var(--nk-block-space, 16px) 0; color: var(--nk-text-secondary);
  line-height: 1.5;
}
.nk-quote .q-cite { display: block; margin-top: 6px; font-size: 12.5px; color: var(--nk-text-tertiary); }

/* ---- Inline ---- */
.nk-mention {
  display: inline-flex; align-items: center; gap: 4px; padding: 0 4px;
  border-radius: 4px; font-weight: 500; cursor: pointer; white-space: nowrap;
}
.nk-mention:hover { background: var(--nk-bg-hover); }
.nk-mention.person { color: var(--nk-text); }
.nk-mention.person .mini-avatar,
.nk-mention.person .nk-avatar,
.nk-mention.person ::slotted(.mini-avatar),
.nk-mention.person ::slotted([slot="avatar"]) {
  width: 16px; height: 16px; border-radius: 50%; color: var(--nk-on-accent);
  font-size: 8.5px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
}
.nk-mention.page { color: var(--nk-text-secondary); text-decoration: underline; text-decoration-color: var(--nk-border-strong); text-underline-offset: 2px; }
.nk-mention.date { color: var(--nk-color-orange); }

.nk-inline-code {
  font-family: var(--nk-font-mono); font-size: 85%;
  color: var(--nk-danger); background: color-mix(in srgb, var(--nk-danger) 8%, transparent);
  border-radius: 4px; padding: 1px 5px;
}

.nk-code {
  background: var(--nk-bg-code); border: 1px solid var(--nk-border);
  border-radius: var(--nk-radius); padding: 20px 24px;
  font-family: var(--nk-font-mono);
  font-size: 13px; line-height: 1.6; margin: var(--nk-block-space, 14px) 0; overflow-x: auto;
  color: var(--nk-text-secondary);
  white-space: pre; position: relative;
}
.nk-code .lang {
  position: absolute; top: 6px; right: 10px;
  font-size: 11px; color: var(--nk-text-tertiary); font-family: var(--nk-font);
}
.nk-code .tag,
.nk-code ::slotted(.tag) { color: var(--nk-accent); }
.nk-code .attr,
.nk-code ::slotted(.attr) { color: var(--nk-color-orange); }


/* ============================================================
   B5. DATABASE VIEWS  (PRD 5.5)
   ============================================================ */
.nk-database { margin: var(--nk-block-space, 12px) 0 var(--nk-block-space, 8px); }

.nk-db-tabs {
  display: flex; gap: 2px; align-items: center;
  padding: 0 0 6px; margin-bottom: 0; font-size: 14px;
}
/* View tabs are pills since Notion's 2025 redesign: the current view sits on
   the active wash, the others are plain words. No underline, no rule. */
.nk-db-tab {
  padding: 4px 8px; cursor: pointer; color: var(--nk-text-secondary);
  border-radius: var(--nk-radius); user-select: none; line-height: 20px;
  display: flex; align-items: center; gap: 6px;
  /* A tab keeps its one line: in a scrolling strip it must not shrink and wrap. */
  flex-shrink: 0; white-space: nowrap;
}
.nk-db-tab:hover { color: var(--nk-text); background: var(--nk-bg-hover); }
.nk-db-tab.active { color: var(--nk-text); background: var(--nk-bg-active); font-weight: 500; }
/* The quiet ＋ that adds a view. */
.nk-db-tab.add { color: var(--nk-text-tertiary); }
.nk-db-tab .badge,
.nk-db-tab ::slotted(.badge) {
  background: var(--nk-bg-callout); border-radius: 8px;
  font-size: 11px; padding: 0 6px; color: var(--nk-text-tertiary);
}

/* The database header as Notion lays it out: the view tabs on the left, the
   view's tools on the right – Filter, Sort, search and "New". A tool that
   is in effect, a set filter, takes the accent. When the row gets narrow
   the tabs scroll sideways and the tools keep their place. */
.nk-db-toolbar { display: flex; align-items: center; gap: 8px; min-width: 0; padding-bottom: 6px; }
.nk-db-toolbar > .nk-db-tabs { flex: 1 1 auto; min-width: 0; padding-bottom: 0; overflow-x: auto; scrollbar-width: none; }
.nk-db-toolbar > .nk-db-tabs::-webkit-scrollbar { display: none; }
.nk-db-toolbar .tools { flex: none; display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nk-db-tool {
  display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 8px;
  border: none; border-radius: var(--nk-radius); background: transparent;
  font-family: inherit; font-size: 14px; color: var(--nk-text-secondary);
  white-space: nowrap; cursor: pointer; user-select: none;
}
.nk-db-tool:hover { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-db-tool.active { color: var(--nk-accent); }

/* The filters in effect, as pills under the toolbar – Notion's
   "Status: Open ▾". A set filter takes an accent tint; `.add` is the quiet
   "＋ Filter" at the end. The pill is one button, or a box holding the
   label button and a `.fp-remove` × when a filter can be removed in place. */
.nk-filter-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; padding: 2px 0 8px; }
.nk-filter-pill {
  display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 0 8px;
  border: 1px solid var(--nk-border-strong); border-radius: 12px; background: transparent;
  font-family: inherit; font-size: 13px; line-height: 1; color: var(--nk-text-secondary);
  white-space: nowrap; cursor: pointer; user-select: none;
}
.nk-filter-pill:hover { background: var(--nk-bg-hover); }
.nk-filter-pill.active {
  color: var(--nk-accent); border-color: color-mix(in srgb, var(--nk-accent) 35%, transparent);
  background: color-mix(in srgb, var(--nk-accent) 6%, transparent);
}
.nk-filter-pill.add { border-color: transparent; color: var(--nk-text-tertiary); }
.nk-filter-pill.add:hover { color: var(--nk-text-secondary); }
.nk-filter-pill button { padding: 0; border: none; background: none; font: inherit; color: inherit; cursor: pointer; }
.nk-filter-pill .fp-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-right: -4px; border-radius: 50%; font-size: 13px;
}
.nk-filter-pill .fp-remove:hover { background: color-mix(in srgb, currentColor 15%, transparent); }

/* Horizontal scrolling instead of breaking — the mobile contract for
   wide tables (PRD 6.3a.4). */
.nk-table-wrap { overflow-x: auto; }
.nk-table { width: 100%; border-collapse: collapse; font-size: 14px; }
/* 36px rows, 14px throughout, hairlines between columns as well as rows –
   measured on a live Notion table. Cells stay on one line; `.wrap` on the
   table or on a cell lets text break, as Notion's "wrap column" does. */
.nk-table th {
  text-align: left; font-weight: 400; color: var(--nk-text-secondary);
  height: 36px; padding: 0 8px; border-bottom: 1px solid var(--nk-border);
  border-right: 1px solid var(--nk-border);
  font-size: 14px; white-space: nowrap; user-select: none; cursor: pointer;
}
.nk-table th:hover { background: var(--nk-bg-hover); }
.nk-table th .th-icon,
.nk-table th ::slotted(.th-icon) { margin-right: 6px; font-size: 13px; color: var(--nk-text-tertiary); }
.nk-table td {
  height: 36px; padding: 6px 8px; line-height: 1.5;
  border-bottom: 1px solid var(--nk-border); border-right: 1px solid var(--nk-border);
  white-space: nowrap; vertical-align: middle;
}
.nk-table th:last-child, .nk-table td:last-child { border-right: none; }
.nk-table.wrap td, .nk-table td.wrap { white-space: normal; vertical-align: top; }
.nk-table tbody tr:hover { background: var(--nk-bg-hover); }
.nk-table .row-title { display: flex; align-items: center; gap: 7px; font-weight: 500; cursor: pointer; }
.nk-table .row-title:hover { text-decoration: underline; text-decoration-color: var(--nk-text-tertiary); }
.nk-table .date-cell { color: var(--nk-text-secondary); }
/* Numbers stand right-aligned in figures of equal width, as Notion sets a
   number property; its header stays left like every other. */
.nk-table .num { text-align: right; font-variant-numeric: tabular-nums; }
/* Actions for a row – “Retry”, “Discard” – as small buttons at the right
   edge of their cell; the header of that column sorts nothing. */
.nk-table .row-actions { display: flex; justify-content: flex-end; gap: 4px; }
.nk-table th.actions { cursor: default; }
.nk-table th.actions:hover { background: none; }
/* A text cell with a tone and a second line: .td-text takes one of Notion's
   nine text colours – an error in orange – and .td-desc sets a quiet line
   under the value – the next run under an error, the sender under a
   subject. The row grows with it. */
.nk-table .td-desc { display: block; font-size: 12px; line-height: 16px; color: var(--nk-text-tertiary); }
.nk-table .td-text.gray { color: var(--nk-color-gray); }
.nk-table .td-text.brown { color: var(--nk-color-brown); }
.nk-table .td-text.orange { color: var(--nk-color-orange); }
.nk-table .td-text.yellow { color: var(--nk-color-yellow); }
.nk-table .td-text.green { color: var(--nk-color-green); }
.nk-table .td-text.blue { color: var(--nk-color-blue); }
.nk-table .td-text.purple { color: var(--nk-color-purple); }
.nk-table .td-text.pink { color: var(--nk-color-pink); }
.nk-table .td-text.red { color: var(--nk-color-red); }
.nk-table .person-cell { display: flex; align-items: center; gap: 6px; color: var(--nk-text-secondary); }
.nk-table .person-cell .mini-avatar,
.nk-table .person-cell ::slotted(.mini-avatar) {
  width: 20px; height: 20px; border-radius: 50%;
  font-size: 10px; color: var(--nk-on-accent); display: inline-flex;
  align-items: center; justify-content: center; font-weight: 600;
}
.nk-new-row,
.nk-table .new-row {
  color: var(--nk-text-tertiary); cursor: pointer; padding: 8px;
  display: flex; align-items: center; gap: 7px; font-size: 14px;
}
.nk-new-row:hover,
.nk-table .new-row:hover { background: var(--nk-bg-hover); }

/* The select option as Notion draws it: 20px tall, 3px corners, the cell's
   14px, dark text on a saturated fill. Without a colour it is the grey tag. */
.nk-tag {
  display: inline-flex; align-items: center; max-width: 100%;
  height: 20px; padding: 0 6px; border-radius: 3px;
  font-size: 14px; font-weight: 400; line-height: 20px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; vertical-align: middle;
  background: var(--nk-tag-gray-bg); color: var(--nk-tag-gray-text);
}
.nk-tag.gray   { background: var(--nk-tag-gray-bg);   color: var(--nk-tag-gray-text); }
.nk-tag.brown  { background: var(--nk-tag-brown-bg);  color: var(--nk-tag-brown-text); }
.nk-tag.orange { background: var(--nk-tag-orange-bg); color: var(--nk-tag-orange-text); }
.nk-tag.yellow { background: var(--nk-tag-yellow-bg); color: var(--nk-tag-yellow-text); }
.nk-tag.green  { background: var(--nk-tag-green-bg);  color: var(--nk-tag-green-text); }
.nk-tag.blue   { background: var(--nk-tag-blue-bg);   color: var(--nk-tag-blue-text); }
.nk-tag.purple { background: var(--nk-tag-purple-bg); color: var(--nk-tag-purple-text); }
.nk-tag.pink   { background: var(--nk-tag-pink-bg);   color: var(--nk-tag-pink-text); }
.nk-tag.red    { background: var(--nk-tag-red-bg);    color: var(--nk-tag-red-text); }

.nk-progress {
  width: 110px; height: 6px; border-radius: 3px;
  background: var(--nk-tint-blue); overflow: hidden; display: inline-block;
}
.nk-progress > i { display: block; height: 100%; background: var(--nk-color-blue); border-radius: 3px; }
/* `wide` fills its row – a property value, a panel, a course overview. In
   a flex row it grows from 60px, so the label keeps its place beside it
   instead of wrapping below; elsewhere it is simply 100% wide. */
/* In a flex column – a panel – the 60px basis would become the bar's height;
   max-height keeps it a bar. */
.nk-progress.wide { width: 100%; flex: 1 1 60px; max-height: 6px; }
.nk-progress-label { font-size: 12px; color: var(--nk-text-tertiary); margin-left: 7px; white-space: nowrap; }
/* A bar and its label as one row: in a flex column – a panel – the two would
   stand one under the other. The label sits beside the bar, on its middle;
   a wide row fills its line like the wide bar, and max-height keeps it from
   growing in a column the way the bar's 60px basis once did.
   <nk-progress label> renders one. */
.nk-progress-row { display: inline-flex; align-items: center; max-width: 100%; vertical-align: middle; }
.nk-progress-row:has(> .nk-progress.wide) { display: flex; flex: 1 1 60px; width: 100%; max-height: max-content; }

/* List view: one line per row – icon, title, a few properties on the right –
   as a Notion database shows it under "List". Hairlines between rows and
   the hover wash across the row, like a table without columns. The title
   gives way first and ends in an ellipsis; the properties keep their place. */
.nk-list { display: flex; flex-direction: column; font-size: 14px; }
.nk-list-item {
  display: flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden;
  min-height: 36px; padding: 4px 6px; border-bottom: 1px solid var(--nk-border);
  color: inherit; text-decoration: none; cursor: pointer;
}
.nk-list-item:hover { background: var(--nk-bg-hover); }
/* .static: a row that is no target itself – a file with its own Remove
   button – takes neither the hand nor the hover wash. */
.nk-list-item.static { cursor: default; }
.nk-list-item.static:hover { background: none; }
.nk-list > .nk-list-item:last-child,
.nk-list ::slotted(.nk-list-item:last-child),
.nk-list-item.last { border-bottom: none; }
.nk-list-item .l-icon,
.nk-list-item ::slotted([slot="icon"]) { width: 20px; flex-shrink: 0; text-align: center; font-size: 15px; }
.nk-list-item .l-title,
.nk-list-item ::slotted(.l-title) { flex: 1 1 auto; min-width: 0; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nk-list-item .l-meta,
.nk-list-item ::slotted(.l-meta) { flex: none; display: flex; align-items: center; gap: 8px; margin-left: auto; font-size: 12px; color: var(--nk-text-secondary); white-space: nowrap; }

/* Calendar view, the database as Notion's month: a head with the month and
   the date picker's .cal-nav buttons (Today, ‹ ›), the weekdays, and a cell per day
   with its number top right – today's on a red pill – and the rows due that
   day as small cards (.cv-item). Days of the next and previous month
   (`.out`) and days not worked (`.off`) are washed. `weeks` adds a column of
   ISO calendar weeks. The cells share the width, so seven always fit. */
.nk-calendar-view { font-size: 14px; }
.nk-calendar-view .cv-head { display: flex; align-items: center; gap: 4px; padding: 2px 0 8px; }
.nk-calendar-view .cv-title { flex: 1; font-weight: 600; white-space: nowrap; }
.nk-calendar-view .cv-grid {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--nk-border); border-left: 1px solid var(--nk-border);
}
.nk-calendar-view.weeks .cv-grid { grid-template-columns: 32px repeat(7, minmax(0, 1fr)); }
.nk-calendar-view :is(.cv-wd, .cv-week, .cv-day) { min-width: 0; border-right: 1px solid var(--nk-border); border-bottom: 1px solid var(--nk-border); }
.nk-calendar-view .cv-wd { padding: 4px 8px; font-size: 12px; color: var(--nk-text-secondary); text-align: center; }
.nk-calendar-view .cv-week { padding: 6px 0; font-size: 11px; color: var(--nk-text-tertiary); text-align: center; font-variant-numeric: tabular-nums; }
.nk-calendar-view .cv-day { display: flex; flex-direction: column; gap: 3px; min-height: 112px; padding: 4px 4px 6px; }
.nk-calendar-view .cv-day:is(.out, .off) { background: var(--nk-bg-sidebar); }
.nk-calendar-view .cv-num {
  align-self: flex-end; min-width: 22px; height: 22px; padding: 0 6px; border-radius: 11px;
  font-size: 13px; line-height: 22px; text-align: center; color: var(--nk-text-secondary); font-variant-numeric: tabular-nums;
}
.nk-calendar-view .cv-day.out .cv-num { color: var(--nk-text-tertiary); }
.nk-calendar-view .cv-day.today .cv-num { background: var(--nk-danger); color: var(--nk-on-accent); }
.nk-calendar-view .cv-item {
  display: block; min-width: 0; padding: 3px 6px; border-radius: 4px;
  background: var(--nk-bg-card); border: 1px solid var(--nk-border); box-shadow: var(--nk-shadow-card);
  font-size: 12.5px; line-height: 18px; color: var(--nk-text); text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer;
}
.nk-calendar-view .cv-item:hover { background: var(--nk-bg-hover); }

/* Board columns scroll horizontally on narrow viewports (PRD 6.3a.4). */
.nk-board { display: none; gap: 12px; padding: 14px 2px; overflow-x: auto; }
.nk-board.active { display: flex; }
.nk-board-col { min-width: 220px; width: 220px; flex-shrink: 0; }
.nk-board-col-header {
  display: flex; align-items: center; gap: 7px; margin-bottom: 8px;
  font-size: 13.5px; font-weight: 500;
}
.nk-board-col-header .count { color: var(--nk-text-tertiary); font-weight: 400; }

.nk-card {
  background: var(--nk-bg-card); border: 1px solid var(--nk-border);
  border-radius: 8px; padding: 10px 12px; margin-bottom: 8px;
  cursor: grab; box-shadow: var(--nk-shadow-card);
  transition: border-color .15s;
}
.nk-card:hover { border-color: var(--nk-border-strong); }
.nk-card .card-title,
.nk-card ::slotted(.card-title) { font-weight: 500; margin-bottom: 7px; display: flex; gap: 6px; align-items: center; }
.nk-card .card-meta,
.nk-card ::slotted(.card-meta) { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; font-size: 12px; color: var(--nk-text-secondary); }

/* Gallery view: the rows as cards with a picture on top, in a grid that
   fills the row – Notion's gallery, for a course catalog or a reading list.
   A card is the board's .nk-card; a .nk-cover as its first child runs to
   the card's edges in 2:1, the picture cropped to fill – the cover gradient
   where a row has none. `.small` and `.large` set the card size, columns
   from 180px and 340px instead of 260px; `.fit` shows a picture whole, for
   logos. The grid drops columns by itself, no breakpoint involved. A card
   that is a link – <a class="nk-card" href>, to open in a new tab – sits
   in a .card-item that carries role="listitem", so the link keeps its own
   role; the card fills it. */
.nk-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 16px; padding: 14px 2px; }
.nk-gallery.small { grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: 12px; }
.nk-gallery.large { grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr)); }
.nk-gallery .nk-card { display: flex; flex-direction: column; min-width: 0; margin: 0; color: inherit; text-decoration: none; cursor: pointer; }
.nk-gallery .nk-card > .nk-cover { flex: none; height: auto; aspect-ratio: 2 / 1; margin: -10px -12px 10px; border-radius: 7px 7px 0 0; overflow: hidden; }
.nk-gallery.fit .nk-card > .nk-cover:has(> img) { background: var(--nk-bg-callout); }
.nk-gallery.fit .nk-card > .nk-cover > img { object-fit: contain; }
.nk-gallery .card-title { min-width: 0; }
.nk-gallery > .card-item { display: flex; min-width: 0; }
.nk-gallery > .card-item > .nk-card { flex: 1 1 auto; }
.nk-gallery > .nk-new-row { justify-content: center; min-height: 64px; border: 1px dashed var(--nk-border-strong); border-radius: 8px; }


/* ============================================================
   B6. FORMS & SETTINGS  (PRD 5.6)
   ============================================================ */
.nk-field { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 9px 0; --_nk-field-min: 210px; }
.nk-field .f-label,
.nk-field ::slotted(.f-label),
.nk-field ::slotted([slot="label"]) { font-size: 14px; }
.nk-field .f-desc,
.nk-field ::slotted(.f-desc),
.nk-field ::slotted([slot="desc"]) { font-size: 12px; color: var(--nk-text-secondary); margin-top: 2px; line-height: 1.45; }
.nk-field .f-control,
.nk-field ::slotted(.f-control) { flex-shrink: 0; }
/* Field layouts. `stacked`: label above a full-width control – textareas,
   long descriptions. `compact`: small tertiary label, no row padding – a
   field inside a grid. `.nk-fields`: the grid itself, short fields side by
   side with a small label each, wrapping as the width allows; its direct
   .nk-field children are stacked and compact by themselves. */
.nk-field.stacked,
.nk-fields > .nk-field { flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; }
.nk-field.stacked .f-control,
.nk-fields > .nk-field .f-control { width: 100%; min-width: 0; }
/* min-width: 0 all the way down: the controls' 210px minimum would otherwise
   become the grid item's automatic minimum and push the input past a
   150px column. */
.nk-field.stacked .nk-input, .nk-field.stacked .nk-textarea, .nk-field.stacked .nk-select,
.nk-fields > .nk-field .nk-input, .nk-fields > .nk-field .nk-textarea, .nk-fields > .nk-field .nk-select { width: 100%; min-width: 0; }
.nk-field.compact,
.nk-fields > .nk-field { padding: 0; gap: 4px; min-width: 0; }
.nk-field.compact .f-label,
.nk-field.compact ::slotted([slot="label"]),
.nk-fields > .nk-field .f-label,
.nk-fields > .nk-field ::slotted([slot="label"]) { font-size: 12px; color: var(--nk-text-tertiary); }
.nk-fields {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px 12px; padding: 9px 0;
}
/* .fit: the fields share the row instead of keeping 150px columns – two
   fields in a 560px dialog are two halves, not two thirds and a gap. */
.nk-fields.fit { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.nk-fields > .nk-field { min-width: 0; }

/* Filled, not outlined: Notion's inputs sit on a faint grey wash inside a
   hairline, 32px tall, and the focus ring is drawn from the accent. */
.nk-input, .nk-select, .nk-textarea {
  font-family: inherit; font-size: 14px; line-height: 20px; color: var(--nk-text);
  background: var(--nk-bg-input); border: 1px solid var(--nk-border);
  border-radius: var(--nk-radius); padding: 5px 10px;
  outline: none; transition: border-color .15s, box-shadow .15s;
  min-width: var(--_nk-field-min, 210px); max-width: 100%;
}
.nk-input:hover, .nk-select:hover, .nk-textarea:hover { border-color: var(--nk-border-strong); }
.nk-input:focus, .nk-select:focus, .nk-textarea:focus {
  border-color: color-mix(in srgb, var(--nk-accent) 60%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--nk-accent) 30%, transparent);
}
.nk-input::placeholder, .nk-textarea::placeholder { color: var(--nk-text-tertiary); }
.nk-input.wide, .nk-textarea.wide, .nk-select.wide { width: 100%; min-width: 0; }
/* iOS draws date and time fields as native controls with a width of their
   own: a wide field ran 21px past its column, two in a .nk-fields row
   overlapped, and the value sat centred. Without the native appearance they
   size like every other field; desktop browsers keep their picker. */
.nk-input[type="date"],
.nk-input[type="time"],
.nk-input[type="datetime-local"],
.nk-input[type="month"] { appearance: none; }
/* A rule of its own: a browser that does not know the pseudo-element
   drops only this one. Without the native control an empty field has no
   value box and collapsed to 12px on iOS; one line keeps it 32px tall. */
.nk-input::-webkit-date-and-time-value { text-align: start; min-height: 1lh; }
.nk-select.compact { min-width: 120px; }
.nk-textarea { resize: vertical; min-height: 70px; line-height: 1.5; }
.nk-select {
  appearance: none; cursor: pointer; padding-right: 26px;
  background-image: linear-gradient(45deg, transparent 50%, var(--nk-text-tertiary) 50%), linear-gradient(135deg, var(--nk-text-tertiary) 50%, transparent 50%);
  background-position: calc(100% - 14px) 55%, calc(100% - 10px) 55%;
  background-size: 4px 4px; background-repeat: no-repeat;
}

/* Copy field, as Notion shows a link to share or an integration secret:
   the value in a field of its own – one line, cut with an ellipsis, taken
   whole by a click – with its actions inside on the right, as tall as an
   input. `mono` for addresses, keys and code; `wrap` lets a long value
   break, the actions stay on the first line. `.copied` is an action's
   moment after, in green. */
.nk-copy-field {
  display: flex; align-items: center; gap: 2px; min-width: var(--_nk-field-min, 210px); max-width: 100%;
  padding: 0 3px 0 10px; font-size: 14px; line-height: 20px; color: var(--nk-text);
  background: var(--nk-bg-input); border: 1px solid var(--nk-border); border-radius: var(--nk-radius);
}
.nk-copy-field.wide { width: 100%; min-width: 0; }
.nk-copy-field.wrap { align-items: flex-start; }
.nk-copy-field .cf-value { flex: 1 1 auto; min-width: 0; padding: 5px 6px 5px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: all; }
.nk-copy-field.mono .cf-value { font-family: var(--nk-font-mono); font-size: 13px; }
.nk-copy-field.wrap .cf-value { white-space: pre-wrap; overflow-wrap: anywhere; }
.nk-copy-field .cf-btn {
  flex: none; height: 24px; margin: 3px 0; padding: 0 8px; border: none; border-radius: 4px;
  background: transparent; font-family: inherit; font-size: 13px; color: var(--nk-text-secondary);
  white-space: nowrap; cursor: pointer;
}
.nk-copy-field .cf-btn:hover { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-copy-field .cf-btn.copied { color: var(--nk-color-green); }
/* Icons instead of words: a .cf-btn may carry an <svg> beside its word in a
   <span> – two overlapping squares for Copy, an eye for Show, a check for
   the moment after. On a phone, and anywhere with `.icons`, the icon stands
   in for the word, as in Notion, and a masked key keeps a dozen characters
   more; give the button the word as aria-label. A button without an icon
   keeps its word. */
.nk-copy-field .cf-btn > svg { display: none; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.nk-copy-field.icons .cf-btn:has(> svg) { display: inline-flex; align-items: center; justify-content: center; width: 28px; padding: 0; }
.nk-copy-field.icons .cf-btn > svg { display: block; }
.nk-copy-field.icons .cf-btn:has(> svg) > span { display: none; }

/* Date picker, Notion's month sheet: a title with the month and the ‹ ›
   buttons, the weekdays, six rows of days. The chosen day takes the accent,
   today is in red. A range fills from `.start` to `.end` in a band of the
   accent's tint (`.in-range`). `.off` greys a day that is not worked – a
   weekend, a holiday; `.out` a day of the next or previous month;
   aria-disabled one outside the bounds. `.cal-marks` holds up to three dots
   (`i.blue`, `i.red` … the nine colours). `weeks` adds a column of ISO
   calendar weeks, `.cal-foot` a time field or actions under the sheet. The
   cells are --_nk-cell square: 36px, so seven and a week column fill a
   popover; 44px in a sheet on a phone. */
.nk-calendar {
  display: block; width: max-content; max-width: 100%; margin-inline: auto;
  font-size: 14px; user-select: none; -webkit-user-select: none;
}
.nk-calendar .cal-head { display: flex; align-items: center; gap: 2px; padding: 0 0 6px 6px; }
.nk-calendar .cal-title { flex: 1; font-weight: 600; white-space: nowrap; }
.nk-calendar .cal-nav,
.nk-calendar-view .cal-nav {
  display: inline-flex; align-items: center; justify-content: center; height: 28px; min-width: 28px; padding: 0 6px;
  border: none; border-radius: var(--nk-radius); background: transparent;
  font-family: inherit; font-size: 13px; color: var(--nk-text-secondary); cursor: pointer;
}
.nk-calendar .cal-nav:hover,
.nk-calendar-view .cal-nav:hover { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-calendar .cal-nav svg,
.nk-calendar-view .cal-nav svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.nk-calendar .cal-grid { display: grid; grid-template-columns: repeat(7, var(--_nk-cell, 36px)); row-gap: 2px; }
.nk-calendar.weeks .cal-grid { grid-template-columns: 24px repeat(7, var(--_nk-cell, 36px)); }
.nk-calendar .cal-wd,
.nk-calendar .cal-week { display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--nk-text-tertiary); font-variant-numeric: tabular-nums; }
.nk-calendar .cal-wd { height: 24px; }
.nk-calendar .cal-week { font-size: 11px; }
.nk-calendar .cal-day {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: var(--_nk-cell, 36px); height: var(--_nk-cell, 36px); padding: 0;
  border: none; border-radius: var(--nk-radius); background: transparent;
  font-family: inherit; font-size: 14px; color: var(--nk-text); font-variant-numeric: tabular-nums; cursor: pointer;
}
.nk-calendar .cal-day:hover { background: var(--nk-bg-hover); }
.nk-calendar .cal-day:focus-visible { outline: 2px solid color-mix(in srgb, var(--nk-accent) 60%, transparent); outline-offset: -2px; }
.nk-calendar .cal-day.out,
.nk-calendar .cal-day.off { color: var(--nk-text-tertiary); }
.nk-calendar .cal-day.today { color: var(--nk-danger); font-weight: 600; }
.nk-calendar .cal-day.in-range { border-radius: 0; background: color-mix(in srgb, var(--nk-accent) 12%, transparent); }
.nk-calendar .cal-day:is(.selected, .start, .end) { background: var(--nk-accent); color: var(--nk-on-accent); font-weight: 500; }
.nk-calendar .cal-day.start:not(.end) { border-radius: var(--nk-radius) 0 0 var(--nk-radius); }
.nk-calendar .cal-day.end:not(.start) { border-radius: 0 var(--nk-radius) var(--nk-radius) 0; }
.nk-calendar .cal-day[aria-disabled="true"] { color: var(--nk-text-tertiary); background: none; opacity: .5; cursor: default; }
.nk-calendar .cal-marks { position: absolute; left: 0; right: 0; bottom: 3px; display: flex; justify-content: center; gap: 2px; pointer-events: none; }
.nk-calendar .cal-marks i { width: 4px; height: 4px; border-radius: 50%; background: var(--nk-color-gray); }
.nk-calendar .cal-day:is(.selected, .start, .end) .cal-marks i { background: var(--nk-on-accent); }
.nk-calendar .cal-foot { display: flex; align-items: center; gap: 8px; margin-top: 8px; padding: 8px 2px 0; border-top: 1px solid var(--nk-border); }
.nk-calendar .cal-foot .nk-input { min-width: 0; flex: 1 1 auto; }

/* 28px tall at 14px. The secondary and danger buttons are Notion's white
   button: the outline comes from --nk-shadow-btn, not from a border. */
.nk-btn {
  font-family: inherit; font-size: 14px; line-height: 20px; font-weight: 500;
  border-radius: var(--nk-radius); cursor: pointer;
  padding: 3px 12px; border: 1px solid transparent;
  transition: background .15s, border-color .15s, box-shadow .15s, opacity .15s;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;
}
.nk-btn svg,
.nk-btn ::slotted(svg) {
  width: 15px; height: 15px; flex-shrink: 0;
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.nk-btn.primary { background: var(--nk-accent); color: var(--nk-on-accent); }
.nk-btn.primary:hover:not(:disabled, [aria-disabled="true"]) { opacity: .88; }
.nk-btn.secondary { background: var(--nk-bg-card); color: var(--nk-text); box-shadow: var(--nk-shadow-btn); }
.nk-btn.secondary:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--nk-bg-card), var(--nk-text) 6%); }
.nk-btn.danger { background: var(--nk-bg-card); color: var(--nk-danger); box-shadow: var(--nk-shadow-btn); }
.nk-btn.danger:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--nk-danger) 8%, var(--nk-bg-card)); }
.nk-btn.danger-solid { background: var(--nk-danger); color: var(--nk-on-accent); }
.nk-btn.danger-solid:hover:not(:disabled, [aria-disabled="true"]) { opacity: .88; }
.nk-btn.small { padding: 1px 8px; font-size: 13px; line-height: 20px; }
a.nk-btn { text-decoration: none; }
/* Disabled still takes the pointer – for its title or tooltip, which often
   says why – but the hover rules above leave it alone. A link button is
   disabled with aria-disabled="true"; stopping its click is your script's. */
.nk-btn:disabled,
.nk-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* Two checked states on purpose: <input class="nk-switch" type="checkbox">
   uses :checked, <button class="nk-switch" role="switch"> uses
   aria-checked. The library ships the state, never the toggling. */
.nk-switch {
  position: relative; width: 34px; height: 20px; flex-shrink: 0;
  appearance: none; border: none; cursor: pointer; border-radius: 20px;
  background: var(--nk-border-strong); transition: background .2s;
}
.nk-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%; background: var(--nk-on-accent);
  transition: transform .2s; box-shadow: var(--nk-shadow-knob);
}
.nk-switch:checked,
.nk-switch[aria-checked="true"] { background: var(--nk-accent); }
.nk-switch:checked::after,
.nk-switch[aria-checked="true"]::after { transform: translateX(14px); }
.nk-switch:disabled { opacity: .5; cursor: not-allowed; }
/* A switch with visible text: the label makes the text part of the hit area
   (a button is a labelable element), for several switches in one row. */
.nk-switch-label { display: inline-flex; align-items: flex-start; gap: 8px; font-size: 14px; cursor: pointer; }
/* Control and text meet on the first line, as in Notion: a label that wraps
   keeps the control beside its first line, not the middle of the block.
   Whichever of the two is shorter is nudged by half the difference, so a
   one-line label sits exactly where it did. 1lh reads the label's line
   height through `inherit`; where lh is unknown the control sits at the top. */
.nk-switch-label > .nk-switch { font-size: inherit; line-height: inherit; margin-top: max(0px, calc((1lh - 20px) / 2)); }
.nk-switch-label > span { padding-top: max(0px, calc((20px - 1lh) / 2)); }
.nk-switch-label:has(.nk-switch:disabled) { cursor: not-allowed; color: var(--nk-text-tertiary); }

.nk-check { display: flex; align-items: flex-start; gap: 8px; padding: 4px 0; font-size: 14px; cursor: pointer; }
.nk-check input {
  appearance: none; width: 16px; height: 16px; flex-shrink: 0;
  border: 1.4px solid var(--nk-border-strong); border-radius: 3px;
  cursor: pointer; position: relative; background: var(--nk-bg);
  /* First line, as with the switch label above. */
  font-size: inherit; line-height: inherit; margin-top: max(0px, calc((1lh - 16px) / 2));
}
.nk-check input[type="radio"] { border-radius: 50%; }
.nk-check input:checked { background: var(--nk-accent); border-color: var(--nk-accent); }
.nk-check input:checked::after {
  content: "✓"; color: var(--nk-on-accent); font-size: 10.5px;
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
}
.nk-check input[type="radio"]:checked::after { content: "●"; font-size: 7px; }
.nk-check input:disabled { opacity: .5; cursor: not-allowed; }
.nk-check input:disabled + * { opacity: .6; }

.nk-slider { width: 210px; accent-color: var(--nk-accent); cursor: pointer; }
.nk-slider-value { font-size: 12.5px; color: var(--nk-text-tertiary); margin-top: 3px; }

.nk-profile-row { display: flex; align-items: center; gap: 14px; padding: 8px 0; }
.nk-profile-row .big-avatar,
.nk-profile-row ::slotted(.big-avatar),
.nk-profile-row ::slotted([slot="avatar"]) {
  width: 56px; height: 56px; border-radius: 50%;
  background: linear-gradient(135deg, var(--nk-decor-purple), var(--nk-decor-blue));
  color: var(--nk-on-accent); font-size: 20px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0;
}
/* The picture you chose, cropped to the circle – or to the rounded square
   of a workspace icon. The actions stand in a column beside it; `.pr-remove`
   is the quiet one. */
.nk-profile-row .big-avatar > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.nk-profile-row .big-avatar.square,
.nk-profile-row ::slotted(.big-avatar.square) { border-radius: 8px; }
.nk-profile-row .pr-actions { display: flex; flex-direction: column; gap: 6px; }
.nk-profile-row .pr-remove { color: var(--nk-text-tertiary); }

.nk-model-card {
  border: 1px solid var(--nk-border-strong); border-radius: 8px;
  padding: 12px 14px; margin-bottom: var(--nk-block-space, 10px); cursor: pointer;
  display: flex; align-items: flex-start; gap: 11px;
  transition: border-color .15s, background .15s;
}
.nk-model-card:hover { background: var(--nk-bg-hover); }
.nk-model-card.selected { border-color: var(--nk-accent); background: color-mix(in srgb, var(--nk-accent) 6%, transparent); }
.nk-model-card .m-radio {
  width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; margin-top: 2px;
  border: 1.4px solid var(--nk-border-strong); position: relative;
}
.nk-model-card.selected .m-radio { border-color: var(--nk-accent); }
.nk-model-card.selected .m-radio::after {
  content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--nk-accent);
}
.nk-model-card .m-name,
.nk-model-card ::slotted(.m-name),
.nk-model-card ::slotted([slot="title"]) { font-weight: 500; font-size: 14px; display: flex; align-items: center; gap: 7px; }
.nk-model-card .m-desc,
.nk-model-card ::slotted(.m-desc),
.nk-model-card ::slotted([slot="desc"]) { font-size: 12px; color: var(--nk-text-secondary); margin-top: 2px; line-height: 1.45; }

.nk-danger-zone {
  border: 1px solid color-mix(in srgb, var(--nk-danger) 40%, transparent); border-radius: 8px;
  padding: 14px 16px; margin-top: var(--nk-block-space, 26px);
}
.nk-danger-zone .dz-title { color: var(--nk-danger); font-weight: 600; font-size: 13px; margin-bottom: 8px; }

/* The separator is keyed on the light-DOM sibling order, so the
   ::slotted() twin keeps working when <nk-member-list> projects rows. */
.nk-member-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--nk-border); }
.nk-member-list > .nk-member-row:last-child,
.nk-member-list ::slotted(.nk-member-row:last-child),
.nk-member-row.last { border-bottom: none; }
.nk-member-row .mini-avatar,
.nk-member-row .nk-avatar,
.nk-member-row ::slotted(.mini-avatar),
.nk-member-row ::slotted([slot="avatar"]) {
  width: 28px; height: 28px; border-radius: 50%; color: var(--nk-on-accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600; flex-shrink: 0;
}
/* The name column may shrink, so an address without a break point ends in
   an ellipsis instead of pushing the role select past the row. */
.nk-member-row > :has(> .m-mail) { min-width: 0; }
.nk-member-row .m-mail { font-size: 12px; color: var(--nk-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nk-member-row .nk-select { min-width: 120px; margin-left: auto; }
.nk-member-row ::slotted([slot="role"]) { margin-left: auto; }


/* ============================================================
   B7. SETTINGS MODAL  (PRD 5.7)
   ============================================================ */
.nk-modal-backdrop {
  position: fixed; inset: 0; background: var(--nk-scrim);
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
  display: flex; align-items: center; justify-content: center;
  z-index: 100; opacity: 0; pointer-events: none;
  transition: opacity .2s ease;
}
.nk-modal-backdrop.open { opacity: 1; pointer-events: auto; }
.nk-modal {
  width: min(1150px, 92vw); height: min(715px, 86vh); max-width: 100%; max-height: 100%;
  background: var(--nk-bg); border-radius: 10px;
  box-shadow: var(--nk-shadow-menu);
  display: flex; overflow: hidden;
  transform: scale(.98) translateY(6px); transition: transform .2s ease;
}
/* At rest the open surfaces carry no transform at all – `none`, not an
   identity – so a floating menu or date picker inside is fixed to the
   window again, not to the surface, and not clipped by its overflow. */
.nk-modal-backdrop.open .nk-modal { transform: none; }

.nk-settings-nav {
  width: 240px; min-width: 240px; background: var(--nk-bg-sidebar);
  border-right: 1px solid var(--nk-border);
  padding: 10px 8px; overflow-y: auto; flex-shrink: 0;
}
.nk-settings-user {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 10px 12px; margin-bottom: 4px;
}
.nk-settings-user .avatar,
.nk-settings-user ::slotted(.avatar),
.nk-settings-user ::slotted([slot="avatar"]) {
  width: 34px; height: 34px; border-radius: 50%;
  background: linear-gradient(135deg, var(--nk-decor-purple), var(--nk-decor-blue));
  color: var(--nk-on-accent); font-weight: 600; font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
.nk-settings-user .name { font-weight: 500; font-size: 14px; }
.nk-settings-user .mail { font-size: 12px; color: var(--nk-text-secondary); }
.nk-settings-nav .nk-tree-item { min-height: 28px; }
.nk-settings-nav .nk-tree-item.active { background: var(--nk-bg-active); color: var(--nk-text); font-weight: 500; }

.nk-settings-content { flex: 1; overflow-y: auto; padding: 36px 60px 80px; min-width: 0; }
.nk-settings-content::-webkit-scrollbar { width: 10px; }
.nk-settings-content::-webkit-scrollbar-thumb { background: var(--nk-border-strong); border-radius: 5px; border: 2px solid var(--nk-bg); }

.nk-settings-pane { display: none; max-width: 800px; }
.nk-settings-pane.active { display: block; }
/* Pane title as a page-like heading, sections as 16px rules – the
   proportions of Notion's 2025 settings dialog. */
.nk-settings-pane > h2 { font-size: 22px; font-weight: 600; line-height: 1.3; margin-bottom: 20px; }
.nk-settings-pane > h3 { font-size: 16px; font-weight: 500; padding-bottom: 8px; border-bottom: 1px solid var(--nk-border); margin: 30px 0 12px; }
/* Slotted headings: the child combinator above cannot cross a slot boundary,
   and slotted nodes miss the scoped reset, so the margins are spelled out. */
.nk-settings-pane ::slotted(h2) { font-size: 22px; font-weight: 600; line-height: 1.3; padding: 0 !important; margin: 0 0 20px !important; }
.nk-settings-pane ::slotted(h3) { font-size: 16px; font-weight: 500; border: 0; border-bottom: 1px solid var(--nk-border); padding: 0 0 8px !important; margin: 30px 0 12px !important; }


/* ============================================================
   B8. OVERLAYS & MENUS  (PRD 5.8)
   ============================================================ */
.nk-pop {
  background: var(--nk-bg); border-radius: 10px; box-shadow: var(--nk-shadow-menu);
  padding: 10px; width: 296px;
}

.nk-emoji-search {
  width: 100%; font-family: inherit; font-size: 14px; color: var(--nk-text);
  background: var(--nk-bg-input); border: 1px solid var(--nk-border); border-radius: var(--nk-radius);
  padding: 6px 10px; outline: none; margin-bottom: 8px;
}
.nk-emoji-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.nk-emoji-grid span,
.nk-emoji-grid ::slotted(span) {
  font-size: 18px; text-align: center; padding: 4px 0; border-radius: 5px;
  cursor: pointer; user-select: none;
}
.nk-emoji-grid span:hover { background: var(--nk-bg-hover); }
.nk-emoji-cats { display: flex; gap: 2px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--nk-border); }
.nk-emoji-cats span {
  font-size: 14px; padding: 3px 7px; border-radius: 5px; cursor: pointer;
  color: var(--nk-text-tertiary); filter: grayscale(1); opacity: .6;
}
.nk-emoji-cats span.active, .nk-emoji-cats span:hover { filter: none; opacity: 1; background: var(--nk-bg-hover); }

.nk-menu { padding: 5px; width: 230px; }
.nk-menu-item {
  display: flex; align-items: center; gap: 9px; padding: 4px 8px; min-height: var(--_nk-row, 28px);
  border-radius: 5px; cursor: pointer; font-size: 14px; user-select: none;
}
.nk-menu-item:hover { background: var(--nk-bg-hover); }
.nk-menu-item .m-icon,
.nk-menu-item ::slotted(.m-icon),
.nk-menu-item ::slotted([slot="icon"]) { width: 17px; text-align: center; font-size: 14px; }
.nk-menu-item .m-shortcut,
.nk-menu-item ::slotted(.m-shortcut) { margin-left: auto; font-size: 12px; color: var(--nk-text-tertiary); }
.nk-menu-item.danger { color: var(--nk-danger); }
/* A switch in a menu row sits on the right, like "Small text" and "Full
   width" in Notion's page menu. */
.nk-menu-item > .nk-switch { margin-left: auto; }
.nk-menu-sep { border-top: 1px solid var(--nk-border); margin: 5px 4px; }
.nk-menu-label { font-size: 12px; color: var(--nk-text-tertiary); padding: 5px 8px 2px; }

/* `floating`: a popover over the page – a page menu, a filter menu – that
   opens and closes with .open, the way the palette does: it fades in and
   settles from 4px higher and 98 %. Closed it takes no clicks and no
   focus. Where it sits is yours: fixed or absolute, top and left or right.
   It never grows past the window: a longer menu scrolls inside, and
   --_nk-float-max, set by a placement script, caps it to the room below or
   above its anchor. It lies above the modal, the sheet and the dialog (106),
   so a menu or a date picker opened from one of them shows over it; the
   palette, the toast and the tooltip stay above. */
.nk-pop.floating {
  z-index: 106; opacity: 0; visibility: hidden; pointer-events: none;
  max-height: min(var(--_nk-float-max, 100dvh), 100dvh - 16px); overflow-y: auto; overscroll-behavior: contain;
  transform: translateY(-4px) scale(.98); transform-origin: top;
  transition: opacity .15s ease, transform .15s ease, visibility 0s linear .15s;
}
.nk-pop.floating.open {
  opacity: 1; visibility: visible; pointer-events: auto; transform: none;
  transition: opacity .15s ease, transform .15s ease, visibility 0s;
}

.nk-cmdk-backdrop {
  position: fixed; inset: 0; background: var(--nk-scrim-soft);
  display: flex; justify-content: center; align-items: flex-start;
  padding: max(14vh, env(safe-area-inset-top, 0px)) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
  z-index: 110; opacity: 0; pointer-events: none;
  transition: opacity .18s ease;
}
.nk-cmdk-backdrop.open { opacity: 1; pointer-events: auto; }
.nk-cmdk {
  max-width: 100%; width: min(560px, 92vw); background: var(--nk-bg);
  border-radius: 12px; box-shadow: var(--nk-shadow-menu);
  overflow: hidden; transform: scale(.98); transition: transform .18s ease;
}
.nk-cmdk-backdrop.open .nk-cmdk { transform: scale(1); }
.nk-cmdk-input-row {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--nk-border);
}
.nk-cmdk-input-row input {
  flex: 1; border: none; outline: none; background: transparent;
  font-family: inherit; font-size: 16px; color: var(--nk-text);
}
.nk-cmdk-input-row input::placeholder { color: var(--nk-text-tertiary); }
.nk-cmdk-list { max-height: 320px; overflow-y: auto; padding: 6px; }
.nk-cmdk-group { font-size: 12px; color: var(--nk-text-tertiary); padding: 8px 10px 3px; }
.nk-cmdk-item {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border-radius: 6px; cursor: pointer; font-size: 14px; user-select: none;
}
.nk-cmdk-item.selected { background: var(--nk-bg-active); }
.nk-cmdk-item .m-icon,
.nk-cmdk-item ::slotted(.m-icon),
.nk-cmdk-item ::slotted([slot="icon"]) { width: 17px; text-align: center; font-size: 14px; }
.nk-cmdk-item .m-shortcut,
.nk-cmdk-item ::slotted(.m-shortcut) { margin-left: auto; font-size: 12px; color: var(--nk-text-tertiary); }
.nk-cmdk-empty { padding: 30px; text-align: center; color: var(--nk-text-tertiary); font-size: 13.5px; }
.nk-cmdk-footer {
  display: flex; gap: 14px; padding: 8px 16px; border-top: 1px solid var(--nk-border);
  font-size: 11.5px; color: var(--nk-text-tertiary);
}

/* The sheet: Notion's mobile surface for menus, properties and more, the
   phone's twin of the modal. The backdrop fades, the panel rises from the
   bottom edge with its top corners rounded and a grabber on top, and the
   home indicator keeps its distance. It lies above the tab bar. Like the
   modal it starts invisible; .open shows it. Closed, the backdrop leaves the
   layout once it has faded – display with allow-discrete where the browser
   has it, at once where not. Up to 640px wide, centred on larger screens. */
.nk-sheet-backdrop {
  position: fixed; inset: 0; z-index: 100;
  display: none; flex-direction: column; align-items: center; justify-content: flex-end;
  padding-top: max(24px, env(safe-area-inset-top, 0px));
  background: var(--nk-scrim-soft); opacity: 0;
  transition: opacity .2s ease, display .25s allow-discrete;
}
.nk-sheet-backdrop.open { display: flex; opacity: 1; }
@starting-style { .nk-sheet-backdrop.open { opacity: 0; } }
.nk-sheet {
  --_nk-row: 40px;   /* rows a thumb can hit, see .nk-tree-item */
  width: 100%; max-width: 640px; max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  padding: 6px max(10px, env(safe-area-inset-right, 0px)) max(16px, env(safe-area-inset-bottom, 0px)) max(10px, env(safe-area-inset-left, 0px));
  background: var(--nk-bg); color: var(--nk-text);
  border-radius: 14px 14px 0 0; box-shadow: var(--nk-shadow-menu);
  translate: 0 100%; transition: translate .25s cubic-bezier(.2, .8, .2, 1);
}
.nk-sheet-backdrop.open .nk-sheet { translate: none; }
@starting-style { .nk-sheet-backdrop.open .nk-sheet { translate: 0 100%; } }
.nk-sheet .sh-grabber,
.nk-sheet ::slotted(.sh-grabber) { width: 36px; height: 4px; margin: 4px auto 10px; border-radius: 2px; background: var(--nk-border-strong); }
.nk-sheet .sh-title,
.nk-sheet ::slotted(.sh-title) { font-size: 14px; font-weight: 600; text-align: center; padding: 0 8px 10px; }

/* Dialog: a question or a short form – "Move to trash?", a name, a link
   between two tasks – with the contract of the modal and the sheet: .open on
   the backdrop fades it in over a scrim and the card settles like the
   modal's. It lies above both, so a question can come from either. 440px,
   .wide 560px; .dl-title, .dl-body, .dl-actions on the right with the
   confirming button last. Below 860px it is a bottom sheet (B12). */
.nk-dialog-backdrop {
  position: fixed; inset: 0; z-index: 105;
  display: none; align-items: center; justify-content: center;
  padding: max(16px, env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px)) max(16px, env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
  background: var(--nk-scrim-soft); opacity: 0;
  transition: opacity .2s ease, display .2s allow-discrete;
}
.nk-dialog-backdrop.open { display: flex; opacity: 1; }
@starting-style { .nk-dialog-backdrop.open { opacity: 0; } }
.nk-dialog {
  width: 440px; max-width: 100%; max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  padding: 20px 24px; border-radius: 10px; outline: none;
  background: var(--nk-bg); color: var(--nk-text); box-shadow: var(--nk-shadow-menu);
  scale: .98; translate: 0 6px; transition: scale .2s ease, translate .2s ease;
}
.nk-dialog.wide { width: 560px; }
.nk-dialog-backdrop.open .nk-dialog { scale: none; translate: none; }
@starting-style { .nk-dialog-backdrop.open .nk-dialog { scale: .98; translate: 0 6px; } }
.nk-dialog .dl-title { font-size: 16px; font-weight: 600; line-height: 1.4; margin-bottom: 6px; }
.nk-dialog .dl-body { font-size: 14px; line-height: 1.5; }
.nk-dialog .dl-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }

/* Side peek, as Notion opens a database row beside the table: the entry in
   a panel at the right edge, full height, a bar for its actions on top –
   close (») and open as page – and the page below it: title in 32px,
   properties, prose, comments. The page behind stays visible and usable,
   so there is no scrim: the backdrop only holds the panel and lets clicks
   through. `.open` slides it in; closed it leaves the layout once it has
   slid out. Under the floating menus, so a menu opened in the peek lies
   above it. Below 860px it is a bottom sheet over a dimmed page (B12). */
.nk-peek-backdrop {
  position: fixed; inset: 0; z-index: 50; display: none; pointer-events: none;
  transition: background-color .2s ease, display .25s allow-discrete;
}
.nk-peek-backdrop.open { display: block; }
.nk-peek {
  --_nk-title: 32px;
  position: absolute; top: 0; right: 0; bottom: 0; width: min(var(--nk-peek-width), 100%);
  display: flex; flex-direction: column; pointer-events: auto; outline: none;
  background: var(--nk-bg); color: var(--nk-text); box-shadow: var(--nk-shadow-menu);
  translate: 100% 0; transition: translate .25s cubic-bezier(.2, .8, .2, 1);
}
.nk-peek-backdrop.open .nk-peek { translate: none; }
@starting-style { .nk-peek-backdrop.open .nk-peek { translate: 100% 0; } }
.nk-peek .pk-bar { flex: none; display: flex; align-items: center; gap: 2px; height: 44px; padding: 0 12px; }
.nk-peek .pk-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 4px 48px 64px; font-size: 16px; line-height: 1.5;
}
/* Its width is the token --nk-peek-width. .pk-resize on the left edge takes
   the pointer to make it wider or narrower, as in Notion – a script sets the
   token on :root – and shows a line while hovered, focused or .active.
   .nk-app.peek-inset gives the main column a right padding as wide as the
   peek: the page moves aside instead of lying under it. */
.nk-peek .pk-resize { position: absolute; top: 0; bottom: 0; left: -4px; width: 8px; z-index: 1; cursor: col-resize; touch-action: none; outline: none; }
.nk-peek .pk-resize::after { content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 2px; transition: background .15s; }
.nk-peek .pk-resize:hover::after,
.nk-peek .pk-resize:focus-visible::after,
.nk-peek .pk-resize.active::after { background: var(--nk-accent); }
.nk-app.peek-inset .nk-main { padding-right: min(var(--nk-peek-width), 100%); }

/* Above every overlay – the modal is 100, the palette 110 – because a toast
   is often the answer to something done in a dialog; above the home
   indicator on a phone. */
.nk-toast {
  position: fixed; bottom: max(20px, calc(env(safe-area-inset-bottom, 0px) + 12px)); left: 50%; transform: translateX(-50%) translateY(80px);
  z-index: 120;
  /* left: 50% leaves the toast only half the viewport to shrink into, so on a
     phone a short message broke over two lines. It takes its own width now,
     up to the viewport minus a 16px margin on each side. */
  width: max-content; max-width: calc(100% - 32px);
  background: var(--nk-text); color: var(--nk-bg);
  padding: 8px 16px; border-radius: 8px; font-size: 14px;
  opacity: 0; transition: all .3s ease; pointer-events: none;
  box-shadow: var(--nk-shadow-menu);
  display: flex; gap: 8px; align-items: center;
}
.nk-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* A toast with an action – Notion's "Moved to trash · Undo": .t-action is a
   quiet button in the toast's own colours, .t-close the × that dismisses a
   toast that stays until one of them is used. Only a shown toast takes the
   pointer; a slotted action meets the page's button reset, so its margin and
   padding take !important there. Negative margins keep both within the
   text's line, however short a system font makes it: the toast keeps its
   height. */
.nk-toast .t-action,
.nk-toast ::slotted([slot="action"]) {
  flex: none; margin: -2px 0 -2px 4px; padding: 2px 8px; border: 0; border-radius: 5px;
  background: color-mix(in srgb, var(--nk-bg) 16%, transparent); color: inherit;
  font: inherit; font-weight: 500; white-space: nowrap; cursor: pointer;
}
.nk-toast ::slotted([slot="action"]) { margin: -2px 0 -2px 4px !important; padding: 2px 8px !important; }
.nk-toast .t-action:hover,
.nk-toast ::slotted([slot="action"]:hover) { background: color-mix(in srgb, var(--nk-bg) 26%, transparent); }
.nk-toast .t-close {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin: -6px -8px -6px -2px; padding: 0; border: 0; border-radius: 5px;
  background: none; color: inherit; opacity: .7; cursor: pointer;
}
.nk-toast .t-close:hover { opacity: 1; background: color-mix(in srgb, var(--nk-bg) 16%, transparent); }
.nk-toast .t-close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.nk-toast :is(.t-action, .t-close):focus-visible,
.nk-toast ::slotted([slot="action"]:focus-visible) { outline: 2px solid color-mix(in srgb, var(--nk-bg) 70%, transparent); outline-offset: 1px; }
.nk-toast.show :is(.t-action, .t-close),
.nk-toast.show ::slotted([slot="action"]) { pointer-events: auto; }

/* Tooltip: a hover hint in the toast's colours, 12px, at most 260px wide,
   a shortcut in .tt-key. Invisible and inert until .open fades it in;
   where it sits is yours – fixed, top and left. Above every overlay. */
.nk-tooltip {
  z-index: 130; max-width: 260px; padding: 4px 8px; border-radius: var(--nk-radius); overflow-wrap: break-word;
  background: var(--nk-text); color: var(--nk-bg); box-shadow: var(--nk-shadow-menu);
  font-size: 12px; font-weight: 500; line-height: 16px; pointer-events: none;
  opacity: 0; visibility: hidden; transition: opacity .1s ease, visibility 0s linear .1s;
}
.nk-tooltip.open { opacity: 1; visibility: visible; transition: opacity .1s ease; }
.nk-tooltip .tt-key { margin-left: 6px; color: color-mix(in srgb, var(--nk-bg) 60%, transparent); }
.nk-tooltip.lines { white-space: pre-line; }


/* ============================================================
   B9. GALLERY & PRODUCTIVITY BLOCKS  (PRD 5.9)
   ============================================================ */
/* Fluid, not breakpoint-driven: two columns in a 760px page column,
   one column as soon as the container drops below ~600px. min(280px, 100%)
   keeps the single column from overflowing containers narrower than 280px. */
.nk-gallery-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 20px 32px; margin: var(--nk-block-space, 12px) 0; }
.nk-g-item > h4 {
  font-size: 12px; font-weight: 500; color: var(--nk-text-tertiary);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px;
}
.nk-g-item ::slotted(h4) {
  font-size: 12px; font-weight: 500; color: var(--nk-text-tertiary);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px !important;
}

.nk-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--nk-border); font-size: 14px; }
.nk-tab {
  padding: 7px 11px; cursor: pointer; color: var(--nk-text-secondary);
  border-bottom: 2px solid transparent; margin-bottom: -1px; user-select: none;
}
.nk-tab:hover { color: var(--nk-text); }
.nk-tab.active { color: var(--nk-text); border-bottom-color: var(--nk-text); font-weight: 500; }
.nk-tab-panel { padding: 12px 2px; color: var(--nk-text-secondary); line-height: 1.55; font-size: 14px; }
/* .scroll: many tabs in one row that scrolls sideways, scrollbar hidden,
   instead of running out of the page. The line moves into the row as an
   inset shadow, so the scroller does not clip the active tab's underline;
   it looks the same. */
.nk-tabs.scroll {
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; white-space: nowrap;
  border-bottom: 0; padding-bottom: 1px; box-shadow: inset 0 -1px 0 var(--nk-border);
}
.nk-tabs.scroll::-webkit-scrollbar { display: none; }

.nk-template-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  font-family: inherit; font-size: 14px; color: var(--nk-text-secondary);
  background: var(--nk-bg-callout); border: none; border-radius: var(--nk-radius);
  padding: 8px 12px; cursor: pointer; margin-bottom: var(--nk-block-space, 6px); text-align: left;
}
.nk-template-btn:hover { background: var(--nk-bg-hover); }

.nk-stats { display: flex; gap: 10px; }
.nk-stat { flex: 1; border: 1px solid var(--nk-border); border-radius: 8px; padding: 12px 14px; }
.nk-stat .s-label,
.nk-stat ::slotted(.s-label),
.nk-stat ::slotted([slot="label"]) { font-size: 12px; color: var(--nk-text-secondary); margin-bottom: 4px; }
.nk-stat .s-value,
.nk-stat ::slotted(.s-value),
.nk-stat ::slotted([slot="value"]) { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.nk-stat .s-delta,
.nk-stat ::slotted(.s-delta),
.nk-stat ::slotted([slot="delta"]) { font-size: 12px; margin-top: 3px; }
.nk-stat .s-delta.up,
.nk-stat ::slotted(.s-delta.up),
.nk-stat ::slotted([slot="delta"].up) { color: var(--nk-color-green); }
.nk-stat .s-delta.down,
.nk-stat ::slotted(.s-delta.down),
.nk-stat ::slotted([slot="delta"].down) { color: var(--nk-danger); }

.nk-synced {
  border: 1.5px solid color-mix(in srgb, var(--nk-danger) 55%, transparent); border-radius: 8px;
  padding: 12px 14px; position: relative; margin: var(--nk-block-space, 8px) 0;
}
.nk-synced .synced-badge {
  position: absolute; top: -9px; right: 10px; font-size: 11px;
  background: var(--nk-danger); color: var(--nk-on-accent); border-radius: 8px; padding: 1px 8px;
}

.nk-segmented { display: inline-flex; background: var(--nk-bg-callout); border-radius: 7px; padding: 2px; }
.nk-segmented button {
  font-family: inherit; font-size: 14px; border: none; background: transparent;
  color: var(--nk-text-secondary); padding: 4px 12px; border-radius: 5px; cursor: pointer;
}
.nk-segmented ::slotted(button) {
  font-family: inherit; font-size: 14px; border: none; background: transparent;
  color: var(--nk-text-secondary); padding: 4px 12px !important; border-radius: 5px; cursor: pointer;
}
.nk-segmented button.active,
.nk-segmented ::slotted(button.active) { background: var(--nk-bg); color: var(--nk-text); font-weight: 500; box-shadow: var(--nk-shadow-segment); }
/* Five filter options do not fit a phone: `wrap` breaks the row, `scroll`
   scrolls it horizontally with the scrollbar hidden. Default stays one row. */
.nk-segmented.wrap { flex-wrap: wrap; }
.nk-segmented.scroll { max-width: 100%; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.nk-segmented.scroll::-webkit-scrollbar { display: none; }
.nk-segmented.scroll button,
.nk-segmented.scroll ::slotted(button) { flex-shrink: 0; white-space: nowrap; }

/* A coloured callout, as Notion tints a block: soft background, the normal
   text colour on top. The hue carries the mood, not the type. */
.nk-banner {
  display: flex; align-items: center; gap: 10px; font-size: 14px;
  border-radius: 8px; padding: 10px 14px; margin-bottom: var(--nk-block-space, 8px); color: var(--nk-text);
}
.nk-banner.info { background: var(--nk-tint-blue); }
.nk-banner.success { background: var(--nk-tint-green); }
.nk-banner.warning { background: var(--nk-tint-yellow); }
.nk-banner.danger { background: var(--nk-tint-red); }
.nk-banner .b-action,
.nk-banner ::slotted(.b-action),
.nk-banner ::slotted([slot="action"]) {
  margin-left: auto; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-weight: 500; text-align: left;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
/* A slotted <button> also meets the page's button reset, and the outer
   tree wins over ::slotted() – the margin that pushes the action to the
   right edge takes !important there. */
.nk-banner ::slotted(.b-action),
.nk-banner ::slotted([slot="action"]) { margin-left: auto !important; }

.nk-avatar-group { display: flex; }
.nk-avatar-group .mini-avatar,
.nk-avatar-group .nk-avatar,
.nk-avatar-group ::slotted(.mini-avatar),
.nk-avatar-group ::slotted(.nk-avatar) {
  width: 26px; height: 26px; border-radius: 50%; color: var(--nk-on-accent);
  font-size: 10.5px; font-weight: 600; border: 2px solid var(--nk-bg);
  display: flex; align-items: center; justify-content: center;
  margin-left: -7px;
}
.nk-avatar-group .mini-avatar:first-child,
.nk-avatar-group .nk-avatar:first-child,
.nk-avatar-group ::slotted(.mini-avatar:first-child),
.nk-avatar-group ::slotted(.nk-avatar:first-child) { margin-left: 0; }
.nk-avatar-group .more,
.nk-avatar-group ::slotted(.more) { background: var(--nk-bg-callout); color: var(--nk-text-secondary); }

/* A person or a workspace: initials, an emoji or a photo in a circle. 24px
   by default; `small` 20px as in cells and properties, `large` 32px,
   `xlarge` 56px as in the profile row. Without a colour it takes the avatar
   gradient, a colour name takes Notion's mid-tone of that name, `square`
   gives it the workspace icon's corners. Works on an <img> as well as on a
   box holding one. Inside a member row, a mention or an avatar group the
   place sizes it, as it always did. */
.nk-avatar {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 24px; height: 24px; border-radius: 50%; overflow: hidden; vertical-align: middle;
  font-size: 10px; font-weight: 600; line-height: 1; color: var(--nk-on-accent); user-select: none;
  background: linear-gradient(135deg, var(--nk-decor-purple), var(--nk-decor-blue));
  object-fit: cover;
}
.nk-avatar.small { width: 20px; height: 20px; font-size: 9px; }
.nk-avatar.large { width: 32px; height: 32px; font-size: 12px; }
.nk-avatar.xlarge { width: 56px; height: 56px; font-size: 20px; }
.nk-avatar.square { border-radius: 4px; }
.nk-avatar > img,
.nk-avatar ::slotted(img) { display: block; width: 100%; height: 100%; object-fit: cover; }
.nk-avatar.gray,
.nk-calendar .cal-marks i.gray { background: var(--nk-color-gray); }
.nk-avatar.brown,
.nk-calendar .cal-marks i.brown { background: var(--nk-color-brown); }
.nk-avatar.orange,
.nk-calendar .cal-marks i.orange { background: var(--nk-color-orange); }
.nk-avatar.yellow,
.nk-calendar .cal-marks i.yellow { background: var(--nk-color-yellow); }
.nk-avatar.green,
.nk-calendar .cal-marks i.green { background: var(--nk-color-green); }
.nk-avatar.blue,
.nk-calendar .cal-marks i.blue { background: var(--nk-color-blue); }
.nk-avatar.purple,
.nk-calendar .cal-marks i.purple { background: var(--nk-color-purple); }
.nk-avatar.pink,
.nk-calendar .cal-marks i.pink { background: var(--nk-color-pink); }
.nk-avatar.red,
.nk-calendar .cal-marks i.red { background: var(--nk-color-red); }

/* A neutral surface for content that belongs together – the cards on
   Notion's Home, the boxes in its settings. Not .nk-card, which is the board
   card. `.nk-panels` sets several in a grid of columns at least 200px wide
   that stretch to the row and fall to one on a phone. A cover as first
   child runs to the panel's edges, --nk-panel-cover-height (64px) tall, and
   a page icon after it overlaps the cover, as on the page itself. As a link
   or button the panel answers the pointer. Inside a panel an input, a
   select or a copy field gives up its 210px floor rather than run past the
   edge of a 200px tile; a field row keeps it. */
.nk-panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); gap: 12px; margin: var(--nk-block-space, 12px) 0; }
.nk-panels.flush { margin: 0; }
.nk-panel {
  display: flex; flex-direction: column; gap: 6px; min-width: 0; --_nk-field-min: min(210px, 100%);
  padding: 14px 16px; border: 1px solid var(--nk-border); border-radius: 10px;
  background: var(--nk-bg-card); box-shadow: var(--nk-shadow-card);
  font-size: 14px; line-height: 1.5; color: inherit; text-decoration: none; text-align: left;
}
:is(a, button).nk-panel { cursor: pointer; font-family: inherit; transition: border-color .15s, background .15s; }
:is(a, button).nk-panel:hover { border-color: var(--nk-border-strong); }
.nk-panel > h3,
.nk-panel > .p-head > h3 { font-size: 14px; font-weight: 600; line-height: 1.4; }
.nk-panel ::slotted(h3) { font-size: 14px; font-weight: 600; line-height: 1.4; margin: 0 !important; }
.nk-panel > p { font-size: 13px; color: var(--nk-text-secondary); }
.nk-panel ::slotted(p) { font-size: 13px; color: var(--nk-text-secondary); margin: 0 !important; }
/* .p-head: the title with something at its right edge – a state as a tag, a
   button – as Notion's settings boxes show whether a connection stands.
   Where both do not fit, the end moves under the title. */
.nk-panel > .p-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0; }
.nk-panel > .p-head > h3 { flex: 1 1 auto; min-width: 0; }
.nk-panel .p-end { flex: none; display: flex; align-items: center; gap: 6px; margin-left: auto; }
.nk-panel > .nk-cover { flex: none; height: var(--nk-panel-cover-height); margin: -14px -16px 2px; border-radius: 9px 9px 0 0; }
.nk-panel > .nk-page-icon { font-size: 28px; }
.nk-panel > .nk-cover + .nk-page-icon { margin-top: -24px; }

.nk-skeleton {
  border-radius: 5px; margin-bottom: var(--nk-block-space, 10px);
  background: linear-gradient(90deg, var(--nk-bg-callout) 25%, var(--nk-bg-hover) 50%, var(--nk-bg-callout) 75%);
  background-size: 200% 100%; animation: nk-shimmer 1.6s infinite;
}
@keyframes nk-shimmer { to { background-position: -200% 0; } }

.nk-empty {
  text-align: center; padding: 36px 20px; border: 1.5px dashed var(--nk-border-strong);
  border-radius: 10px; color: var(--nk-text-tertiary);
}
.nk-empty .e-icon,
.nk-empty ::slotted(.e-icon),
.nk-empty ::slotted([slot="icon"]) { font-size: 30px; margin-bottom: 8px; }
.nk-empty .e-title,
.nk-empty ::slotted(.e-title),
.nk-empty ::slotted([slot="title"]) { font-weight: 500; color: var(--nk-text-secondary); margin-bottom: 3px; font-size: 14px; }
.nk-empty .e-desc,
.nk-empty ::slotted(.e-desc),
.nk-empty ::slotted([slot="desc"]) { font-size: 13px; margin-bottom: 12px; }
/* Several actions: a centred row that wraps, 8px apart in both directions.
   Buttons written without whitespace between them used to touch. */
.nk-empty .e-actions,
.nk-empty ::slotted(.e-actions) { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }

/* Steps through a short flow, calm and vertical: a numbered circle per step
   joined by a hairline, done ones on the green tag with a check, the
   current one ringed in the accent, the rest quiet. Not a Notion block – in
   Notion's idiom it is a numbered list with checks – but LearnHub, Auxdesk
   and NotionKit Web each build one. Write it as an <ol>; mark the current
   step with aria-current="step". */
.nk-steps { display: flex; flex-direction: column; margin: var(--nk-block-space, 8px) 0; padding: 0; list-style: none; font-size: 14px; }
.nk-step { position: relative; display: flex; align-items: flex-start; gap: 10px; padding-bottom: 14px; line-height: 20px; color: var(--nk-text-tertiary); }
.nk-step:last-child { padding-bottom: 0; }
.nk-step:not(:last-child)::after { content: ""; position: absolute; left: 10px; top: 24px; bottom: 4px; width: 1px; background: var(--nk-border); }
.nk-step .st-mark {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--nk-border-strong); background: var(--nk-bg);
  font-size: 11px; font-weight: 600; line-height: 1;
}
.nk-step .st-desc { display: block; font-size: 12px; line-height: 18px; color: var(--nk-text-tertiary); font-weight: 400; }
.nk-step.done { color: var(--nk-text-secondary); }
.nk-step.done .st-mark { background: var(--nk-tag-green-bg); color: var(--nk-tag-green-text); border-color: transparent; }
.nk-step.current { color: var(--nk-text); font-weight: 500; }
.nk-step.current .st-mark { border-color: var(--nk-accent); color: var(--nk-accent); }
/* The states go per step, in any order: a wizard that lets a step be
   skipped marks it .skipped – a dashed ring around a dash – while a later
   one is .done. The label as a <button class="st-label"> makes a step one
   to jump to; as an <a class="st-label" href> one to open in a new tab or
   to copy the address of, and it looks the same. */
.nk-step.skipped .st-mark { border-style: dashed; }
.nk-step button.st-label,
.nk-step a.st-label { font: inherit; color: inherit; text-align: left; text-decoration: none; background: none; border: 0; border-radius: 3px; cursor: pointer; }
.nk-step button.st-label:hover,
.nk-step a.st-label:hover { text-decoration: underline; text-decoration-color: var(--nk-text-tertiary); text-underline-offset: 2px; }
.nk-step button.st-label:focus-visible,
.nk-step a.st-label:focus-visible { outline: 2px solid color-mix(in srgb, var(--nk-accent) 60%, transparent); outline-offset: 2px; }
/* .horizontal: one row above a wizard, each step joined to the next by a
   line that takes the room between them. */
.nk-steps.horizontal { flex-direction: row; align-items: flex-start; gap: 10px; }
.nk-steps.horizontal .nk-step { flex: none; padding-bottom: 0; min-width: 0; white-space: nowrap; }
.nk-steps.horizontal .nk-step:not(:last-child) { flex: 1 1 auto; }
.nk-steps.horizontal .nk-step:not(:last-child)::after { position: static; flex: 1 1 16px; width: auto; min-width: 16px; height: 1px; margin-top: 10px; }


/* ============================================================
   B10. COLLABORATION & AI  (PRD 5.10)
   ============================================================ */
.nk-comments { border-left: 1px solid var(--nk-border); padding: 4px 0 4px 18px; margin: var(--nk-block-space, 8px) 0 var(--nk-block-space, 8px) 8px; }
.nk-comment { display: flex; gap: 9px; margin-bottom: 14px; }
.nk-comment .mini-avatar,
.nk-comment ::slotted(.mini-avatar),
.nk-comment ::slotted([slot="avatar"]) {
  width: 24px; height: 24px; border-radius: 50%; color: var(--nk-on-accent); flex-shrink: 0;
  font-size: 10px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
}
.nk-comment .c-head,
.nk-comment ::slotted(.c-head) { font-size: 12px; color: var(--nk-text-tertiary); margin-bottom: 2px; }
.nk-comment .c-head b { color: var(--nk-text); font-weight: 600; }
.nk-comment .c-body,
.nk-comment ::slotted(.c-body) { font-size: 14px; line-height: 1.5; }
.nk-comment-input { display: flex; gap: 8px; align-items: center; margin-top: 4px; }
.nk-comment-input input { min-width: 0; flex: 1; }

.nk-ai-thread { display: flex; flex-direction: column; gap: 14px; }
.nk-ai-msg { display: flex; gap: 9px; }
.nk-ai-msg .mini-avatar,
.nk-ai-msg ::slotted(.mini-avatar),
.nk-ai-msg ::slotted([slot="avatar"]) {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 12px;
  background: var(--nk-bg-callout);
}
.nk-ai-msg.user .mini-avatar,
.nk-ai-msg.user ::slotted(.mini-avatar),
.nk-ai-msg.user ::slotted([slot="avatar"]) {
  background: linear-gradient(135deg, var(--nk-decor-purple), var(--nk-decor-blue));
  color: var(--nk-on-accent); font-size: 9.5px; font-weight: 600;
}
.nk-ai-msg .a-body,
.nk-ai-msg ::slotted(.a-body) { font-size: 14px; line-height: 1.55; padding-top: 2px; }
.nk-ai-msg .a-name,
.nk-ai-msg ::slotted(.a-name) { font-size: 12px; font-weight: 600; margin-bottom: 2px; }
.nk-ai-msg .a-name span { color: var(--nk-text-tertiary); font-weight: 400; }
/* `bubble`: the message as a grey bubble, no avatar or name needed. Notion's
   AI chat shows your own question that way, on the right – `.user.bubble`. */
.nk-ai-msg.user.bubble { justify-content: flex-end; }
.nk-ai-msg.bubble .a-body,
.nk-ai-msg.bubble ::slotted(.a-body) { max-width: 85%; padding: 6px 12px; border-radius: 16px; background: var(--nk-bg-callout); }
.nk-ai-actions { display: flex; gap: 4px; margin-top: 6px; }
.nk-ai-actions button {
  font-family: inherit; font-size: 12px; color: var(--nk-text-secondary);
  background: transparent; border: 1px solid var(--nk-border); border-radius: 5px;
  padding: 2px 8px; cursor: pointer;
}
.nk-ai-actions ::slotted(button) {
  font-family: inherit; font-size: 12px; color: var(--nk-text-secondary);
  background: transparent; border: 1px solid var(--nk-border); border-radius: 5px;
  padding: 2px 8px !important; cursor: pointer;
}
.nk-ai-actions button:hover,
.nk-ai-actions ::slotted(button:hover) { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-ai-input-row {
  display: flex; align-items: center; gap: 8px; margin-top: var(--nk-block-space, 14px);
  border: 1px solid var(--nk-border-strong); border-radius: 10px; padding: 8px 12px;
}
.nk-ai-input-row:focus-within { border-color: var(--nk-accent); }
.nk-ai-input-row input {
  flex: 1; border: none; outline: none; background: transparent;
  font-family: inherit; font-size: 14px; color: var(--nk-text); min-width: 0;
}
.nk-ai-input-row input::placeholder { color: var(--nk-text-tertiary); }
.nk-ai-send {
  border: none; background: var(--nk-accent); color: var(--nk-on-accent); border-radius: 6px;
  width: 26px; height: 26px; cursor: pointer; font-size: 13px; flex-shrink: 0;
}


/* ============================================================
   B11. EDITOR ADAPTER  (PRD 5.11)

   NotionKit deliberately ships no editor. `.nk-block-host` is the
   optical shell in the document flow; the behaviour comes from an
   editor you mount inside it.

   Every adapter rule below is scoped to `.nk-block-host` so the
   library never claims a third-party class name globally. The
   integration contract is therefore exactly one class on the host:

     <div class="nk-block-host" id="editor"></div>
     new Editor({ element: document.getElementById('editor'), … })
   ============================================================ */
.nk-block-host {
  position: relative;
  border-radius: var(--nk-radius);
  margin: var(--nk-block-space, 8px) 0;
  padding: 2px 0 2px 2px;
  transition: background .15s, box-shadow .15s;
}
.nk-block-host:hover { background: var(--nk-bg-hover); }
.nk-block-host:focus-within { background: transparent; box-shadow: 0 0 0 2px color-mix(in srgb, var(--nk-accent) 25%, transparent); }
.nk-block-host.nk-drop-target { box-shadow: 0 -2px 0 0 var(--nk-accent); background: transparent; }

/* Slot for a drag handle to the left of the content column. */
.nk-block-host .nk-block-handle,
.nk-block-host ::slotted(.nk-block-handle) {
  position: absolute; left: -26px; top: 4px;
  width: 18px; height: 20px; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  color: var(--nk-text-tertiary); font-size: 13px; cursor: grab;
  opacity: 0; transition: opacity .15s; user-select: none;
}
.nk-block-host:hover .nk-block-handle { opacity: 1; }

/* Block action rail (＋ / ⠿) that an editor integration positions beside
   the hovered block. The library only supplies the look; the docs recipe
   (docs-editor.js) shows the ~60 lines of positioning and drag logic. */
.nk-block-host .nk-block-actions {
  position: absolute; display: flex; gap: 1px; z-index: 2;
  opacity: 0; transition: opacity .15s; pointer-events: none;
}
.nk-block-host .nk-block-actions.show { opacity: 1; pointer-events: auto; }
.nk-block-host .nk-block-actions button,
.nk-block-host .nk-block-actions ::slotted(button) {
  width: 20px; height: 22px; padding: 0; border: none; border-radius: 4px;
  background: transparent; color: var(--nk-text-tertiary); font-family: inherit;
  font-size: 14px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.nk-block-host .nk-block-actions button:hover { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-block-host .nk-block-actions .drag { cursor: grab; }
.nk-block-host .nk-block-actions .drag:active { cursor: grabbing; }

/* ---- Prose and TipTap / ProseMirror: one set of rules ----
   .nk-prose gives text the app did not write tag by tag – rendered
   Markdown, help pages, the HTML an editor saved – the document look with
   one class on the container. The editor adapter reads the very same
   rules, so a page shown for reading and the same page in the editor
   match to the pixel. Sizes are in em: the text follows the page (16px,
   14px with `small`) or whatever it sits in. Document-level by design:
   ::slotted() reaches only the slotted node, never a paragraph inside it,
   so there is no <nk-prose> – the class goes on a light-DOM container. */
.nk-prose,
.nk-block-host .ProseMirror { font-family: var(--nk-font); line-height: 1.5; color: var(--nk-text); overflow-wrap: break-word; }
.nk-block-host .ProseMirror { outline: none; min-height: 60px; padding: 4px 2px; }
.nk-prose > * + *,
.nk-block-host .ProseMirror > * + * { margin-top: 6px; }
.nk-prose h1, .nk-block-host .ProseMirror h1 { font-size: 1.875em; font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; margin: 32px 0 4px; }
.nk-prose h2, .nk-block-host .ProseMirror h2 { font-size: 1.5em; font-weight: 600; line-height: 1.3; margin: 24px 0 4px; }
.nk-prose h3, .nk-block-host .ProseMirror h3 { font-size: 1.25em; font-weight: 600; line-height: 1.3; margin: 16px 0 2px; }
.nk-prose :is(h4, h5, h6), .nk-block-host .ProseMirror :is(h4, h5, h6) { font-size: 1em; font-weight: 600; margin: 12px 0 0; }
/* Flush inside a panel or a cell: no outer margin on the first and last block. */
.nk-prose > :first-child,
.nk-block-host .ProseMirror > :first-child { margin-top: 0; }
.nk-prose > :last-child,
.nk-block-host .ProseMirror > :last-child { margin-bottom: 0; }
/* An empty paragraph keeps its line, as it had it in the editor, where a
   trailing <br> holds it open. An inline-block with no content is enough. */
.nk-prose p:empty::before { content: ""; display: inline-block; }
.nk-prose :is(strong, b),
.nk-block-host .ProseMirror :is(strong, b) { font-weight: 600; }
.nk-prose :is(ul, ol),
.nk-block-host .ProseMirror :is(ul, ol) { padding-left: 24px; margin: 4px 0; }
.nk-prose ul, .nk-block-host .ProseMirror ul { list-style: disc; }
.nk-prose ol, .nk-block-host .ProseMirror ol { list-style: decimal; }
.nk-prose li, .nk-block-host .ProseMirror li { margin: 2px 0; }
.nk-prose li::marker, .nk-block-host .ProseMirror li::marker { color: var(--nk-text-tertiary); }
.nk-prose ul[data-type="taskList"],
.nk-block-host .ProseMirror ul[data-type="taskList"] { list-style: none; padding-left: 2px; }
.nk-prose ul[data-type="taskList"] li,
.nk-block-host .ProseMirror ul[data-type="taskList"] li { display: flex; gap: 8px; align-items: flex-start; }
/* The box sits on the first line at any text size: half the line box minus
   half the box, from the label's own line height. */
.nk-prose ul[data-type="taskList"] li > label,
.nk-block-host .ProseMirror ul[data-type="taskList"] li > label { flex-shrink: 0; margin-top: max(0px, calc((1lh - 16px) / 2)); user-select: none; }
.nk-prose ul[data-type="taskList"] li > div,
.nk-block-host .ProseMirror ul[data-type="taskList"] li > div { flex: 1; min-width: 0; }
.nk-prose ul[data-type="taskList"] input[type="checkbox"],
.nk-block-host .ProseMirror ul[data-type="taskList"] input[type="checkbox"] {
  appearance: none; width: 16px; height: 16px; margin: 0;
  border: 1.4px solid var(--nk-border-strong); border-radius: 2px;
  cursor: pointer; position: relative; background: var(--nk-bg); display: block;
}
.nk-prose ul[data-type="taskList"] input[type="checkbox"]:checked,
.nk-block-host .ProseMirror ul[data-type="taskList"] input[type="checkbox"]:checked { background: var(--nk-accent); border-color: var(--nk-accent); }
.nk-prose ul[data-type="taskList"] input[type="checkbox"]:checked::after,
.nk-block-host .ProseMirror ul[data-type="taskList"] input[type="checkbox"]:checked::after {
  content: "✓"; color: var(--nk-on-accent); font-size: 11px;
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
}
.nk-prose li[data-checked="true"] > div,
.nk-block-host .ProseMirror li[data-checked="true"] > div { text-decoration: line-through; color: var(--nk-text-tertiary); }
.nk-prose blockquote,
.nk-block-host .ProseMirror blockquote {
  border-left: 3px solid var(--nk-text); padding: 2px 0 2px 14px;
  margin: 12px 0; color: var(--nk-text-secondary);
}
.nk-prose code,
.nk-block-host .ProseMirror code {
  font-family: var(--nk-font-mono); font-size: 85%;
  color: var(--nk-danger); background: color-mix(in srgb, var(--nk-danger) 8%, transparent);
  border-radius: 4px; padding: 1px 5px;
}
.nk-prose pre,
.nk-block-host .ProseMirror pre {
  background: var(--nk-bg-code); border: 1px solid var(--nk-border);
  border-radius: var(--nk-radius); padding: 16px 20px; margin: 12px 0;
  font-family: var(--nk-font-mono); font-size: 13px; line-height: 1.6;
  color: var(--nk-text-secondary); overflow-x: auto;
}
.nk-prose pre code,
.nk-block-host .ProseMirror pre code { background: none; color: inherit; padding: 0; font-size: inherit; }
.nk-prose hr,
.nk-block-host .ProseMirror hr { border: none; border-top: 1px solid var(--nk-border); margin: 20px 0; }
.nk-prose a,
.nk-block-host .ProseMirror a { color: var(--nk-accent); text-decoration: underline; text-underline-offset: 2px; }
/* What Markdown has and the editor recipe does not: pictures and tables.
   A wide table scrolls in its own box instead of widening the page. */
.nk-prose img { max-width: 100%; height: auto; }
.nk-prose table { display: block; width: max-content; max-width: 100%; overflow-x: auto; border-collapse: collapse; font-size: 14px; margin: 12px 0; }
.nk-prose :is(th, td) { padding: 6px 10px; border: 1px solid var(--nk-border); text-align: left; vertical-align: top; }
.nk-prose th { font-weight: 600; }
.nk-block-host .ProseMirror-gapcursor::after { border-top-color: var(--nk-text); }
.nk-block-host .ProseMirror .ProseMirror-selectednode { background: color-mix(in srgb, var(--nk-accent) 8%, transparent); }
.nk-block-host .ProseMirror-selectednode { box-shadow: 0 0 0 2px color-mix(in srgb, var(--nk-accent) 35%, transparent); border-radius: 3px; }
.nk-block-host .ProseMirror ::selection { background: color-mix(in srgb, var(--nk-accent) 25%, transparent); }
/* Placeholder — TipTap's Placeholder extension emits these classes. */
.nk-block-host .ProseMirror p.is-editor-empty:first-child::before,
.nk-block-host .ProseMirror .is-empty::before {
  content: attr(data-placeholder);
  color: var(--nk-text-tertiary);
  float: left; height: 0; pointer-events: none;
}

/* ---- BlockNote (React path) ---- */
.nk-block-host .bn-container { font-family: var(--nk-font); color: var(--nk-text); background: transparent; }
.nk-block-host .bn-editor { padding: 4px 2px; }
.nk-block-host .bn-block-content { font-size: 14px; line-height: 1.6; }
.nk-block-host .bn-side-menu { color: var(--nk-text-tertiary); }
.nk-block-host .bn-drag-handle { border-radius: 4px; }
.nk-block-host .bn-drag-handle:hover { background: var(--nk-bg-hover); }

/* ---- Novel (Next.js path; ProseMirror-based) ---- */
.nk-block-host .novel-editor { font-family: var(--nk-font); color: var(--nk-text); }
.nk-block-host .novel-prose { max-width: none; }

/* ---- Slash menu & bubble toolbar, mapped onto nk-pop optics ----
   Give the editor's floating containers these classes (TipTap:
   the element you render the suggestion list into; BlockNote:
   `.bn-suggestion-menu`) to inherit the NotionKit popover look. */
.nk-slash-menu,
.nk-block-host .bn-suggestion-menu,
.nk-block-host .tippy-box {
  background: var(--nk-bg); border-radius: 10px; box-shadow: var(--nk-shadow-menu);
  padding: 6px; width: 280px; max-height: 320px; overflow-y: auto;
  font-family: var(--nk-font); font-size: 14px; color: var(--nk-text);
}
.nk-slash-menu-label { font-size: 12px; color: var(--nk-text-tertiary); padding: 6px 9px 2px; }
.nk-slash-item {
  display: flex; align-items: center; gap: 10px; padding: 6px 9px;
  border-radius: 5px; cursor: pointer; user-select: none;
}
.nk-slash-item:hover,
.nk-slash-item.selected { background: var(--nk-bg-hover); }
.nk-slash-item .m-icon,
.nk-slash-item ::slotted(.m-icon) {
  width: 28px; height: 28px; flex-shrink: 0; border-radius: 4px;
  background: var(--nk-bg-callout); border: 1px solid var(--nk-border);
  display: flex; align-items: center; justify-content: center; font-size: 15px;
}
.nk-slash-item .m-desc { font-size: 12px; color: var(--nk-text-tertiary); }

/* Bubble toolbar: a horizontal nk-pop. */
.nk-bubble-menu {
  display: flex; align-items: center; gap: 2px;
  background: var(--nk-bg); border-radius: 8px; box-shadow: var(--nk-shadow-menu);
  padding: 4px;
}
.nk-bubble-menu button {
  font-family: inherit; font-size: 13px; border: none; background: transparent;
  color: var(--nk-text-secondary); padding: 4px 8px; border-radius: 5px; cursor: pointer;
}
.nk-bubble-menu ::slotted(button) {
  font-family: inherit; font-size: 13px; border: none; background: transparent;
  color: var(--nk-text-secondary); padding: 4px 8px !important; border-radius: 5px; cursor: pointer;
}
.nk-bubble-menu button:hover,
.nk-bubble-menu ::slotted(button:hover) { background: var(--nk-bg-hover); color: var(--nk-text); }
.nk-bubble-menu button.active,
.nk-bubble-menu ::slotted(button.active) { color: var(--nk-accent); }


/* ============================================================
   B12. RESPONSIVE  (PRD 6.3a)

   Exactly one breakpoint. Everything else is fluid: max-width plus
   auto margins for the page column, min-width on the sidebar,
   overflow-x on tables and boards, auto-fit grids in the gallery.
   ============================================================ */
@media (max-width: 860px) {
  /* The sidebar steps aside; `.open` brings it back as an off-canvas drawer
     over the page, .nk-sidebar-backdrop as its scrim, opened by the ☰
     .nk-sidebar-toggle in the topbar or a tab bar item. It slides in and the
     scrim fades, CSS only: display transitions with allow-discrete, so the
     old value holds while closing, and @starting-style gives the first
     frame its start; browsers without either switch at once. position:
     fixed sits on the plain sidebar, not on the open state – while closing
     it is still displayed and must not fall back into the flow. */
  .nk-sidebar {
    display: none; position: fixed; inset: 0 auto 0 0; z-index: 60;
    transform: translateX(-100%);
    transition: background .25s ease, transform .24s cubic-bezier(.2, .8, .25, 1), display .24s allow-discrete;
  }
  .nk-sidebar.open { display: flex; transform: none; }
  @starting-style { .nk-sidebar.open { transform: translateX(-100%); } }
  .nk-sidebar-backdrop { opacity: 0; transition: opacity .24s ease, display .24s allow-discrete; }
  .nk-sidebar-backdrop.open { display: block; opacity: 1; }
  @starting-style { .nk-sidebar-backdrop.open { opacity: 0; } }
  .nk-sidebar-toggle { display: inline-flex; }
  .nk-sidebar.collapsed { margin-left: 0; visibility: visible; transition: background .25s ease, transform .24s cubic-bezier(.2, .8, .25, 1), display .24s allow-discrete; }
  .nk-sidebar-collapse { display: none; }
  .nk-tab-bar { display: flex; }
  .nk-tab-bar.fixed + .nk-tab-bar-spacer { display: block; }
  .nk-page { padding-left: max(24px, env(safe-area-inset-left, 0px)); padding-right: max(24px, env(safe-area-inset-right, 0px)); padding-bottom: 80px; }
  .nk-settings-nav { width: 60px; min-width: 60px; }
  .nk-settings-nav .label,
  .nk-settings-nav .nk-section-label,
  .nk-settings-user .u-text { display: none; }
  .nk-settings-content { padding: 24px; }
  .nk-cmdk-backdrop { padding-top: max(6vh, env(safe-area-inset-top, 0px)); }
  .nk-cmdk { width: min(560px, 96vw); }
  .nk-stats { flex-wrap: wrap; }
  /* The topbar shows the page it is on and its actions, as Notion's mobile
     app does: the trail before the last crumb and passive text step aside,
     and the last crumb ends in an ellipsis instead of wrapping. At 390px the
     actions used to wrap over three lines and push "Share" off the screen. */
  .nk-breadcrumb { min-width: 0; }
  .nk-breadcrumb > .crumb:not(:last-child),
  .nk-breadcrumb ::slotted(.crumb:not(:last-child)),
  .nk-breadcrumb > .sep,
  .nk-breadcrumb ::slotted(.sep),
  .nk-topbar-meta,
  .nk-topbar-actions ::slotted(.nk-topbar-meta) { display: none; }
  .nk-breadcrumb > .crumb:last-child,
  .nk-breadcrumb ::slotted(.crumb:last-child) { display: block; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .nk-topbar-actions { flex-shrink: 0; }
  /* A field row wraps: a control that does not fit beside its label moves
     below it, and no control grows past its column. In the settings modal
     five of six panes used to run up to 66px past the screen. */
  .nk-field { flex-wrap: wrap; row-gap: 6px; }
  .nk-field .f-control,
  .nk-field ::slotted(.f-control) { max-width: 100%; min-width: 0; }
  .nk-input, .nk-select, .nk-textarea, .nk-slider { max-width: 100%; }
  /* Properties stack: the name above its value, both flush left, so a
     value gets the whole width instead of what 160px leave of a phone. */
  /* Single-line: a wrapping column takes the width of its widest value – a
     copy field's whole address – instead of its card's. */
  .nk-prop { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
  .nk-prop .p-name { flex: none; min-height: 26px; }
  .nk-prop .p-value { flex: none; min-height: 30px; padding: 3px 6px 7px; }
  /* A copy field's actions become icons where a button carries one. */
  .nk-copy-field .cf-btn:has(> svg) { display: inline-flex; align-items: center; justify-content: center; width: 28px; padding: 0; }
  .nk-copy-field .cf-btn > svg { display: block; }
  .nk-copy-field .cf-btn:has(> svg) > span { display: none; }
  /* A horizontal wizard keeps its row: every mark, but only the current
     step's label. */
  .nk-steps.horizontal .nk-step:not(.current) > :not(.st-mark) { display: none; }
  /* `sheet`: a popover becomes a bottom sheet, as Notion's mobile app opens
     every menu – full width at the bottom edge, top corners rounded, a
     grabber, the page dimmed by a spread shadow that takes no clicks, so a
     tap outside still reaches the page's own close handler. Position
     written inline – by a script, by a positioning library – is overruled
     on purpose. With `floating` it rises from the bottom edge. */
  .nk-pop.sheet {
    position: fixed !important; inset: auto 0 0 0 !important; width: auto !important;
    transform: none !important; z-index: 106; --_nk-row: 40px;
    max-height: 85dvh; overflow-y: auto; overscroll-behavior: contain;
    border-radius: 14px 14px 0 0;
    padding: 6px max(8px, env(safe-area-inset-right, 0px)) max(12px, env(safe-area-inset-bottom, 0px)) max(8px, env(safe-area-inset-left, 0px));
    box-shadow: 0 0 0 100vmax var(--nk-scrim-soft), var(--nk-shadow-menu);
  }
  .nk-pop.sheet::before { content: ""; display: block; width: 36px; height: 4px; margin: 4px auto 8px; border-radius: 2px; background: var(--nk-border-strong); }
  .nk-pop.sheet.floating { translate: 0 100%; transition: opacity .2s ease, translate .25s cubic-bezier(.2, .8, .2, 1), visibility 0s linear .25s; }
  .nk-pop.sheet.floating.open { translate: none; transition: opacity .2s ease, translate .25s cubic-bezier(.2, .8, .2, 1), visibility 0s; }
  /* A date picker in a sheet gets cells a thumb can hit. The calendar view
     keeps seven columns and gets lower. */
  .nk-pop.sheet,
  .nk-sheet { --_nk-cell: 44px; }
  .nk-calendar-view .cv-day { min-height: 64px; padding: 2px 2px 4px; }
  .nk-calendar-view .cv-item { padding: 1px 4px; font-size: 11px; line-height: 16px; }
  /* The side peek rises from the bottom edge instead, over a dimmed page
     that takes the tap to close it; the title steps down to 28px. */
  .nk-peek-backdrop { pointer-events: auto; }
  .nk-peek-backdrop.open { background-color: var(--nk-scrim-soft); }
  @starting-style { .nk-peek-backdrop.open { background-color: transparent; } }
  .nk-peek {
    --_nk-title: 28px;
    top: auto; left: 0; width: auto; max-height: 92dvh;
    border-radius: 14px 14px 0 0; translate: 0 100%;
  }
  .nk-peek-backdrop.open .nk-peek { translate: none; }
  @starting-style { .nk-peek-backdrop.open .nk-peek { translate: 0 100%; } }
  .nk-peek::before { content: ""; flex: none; width: 36px; height: 4px; margin: 10px auto 0; border-radius: 2px; background: var(--nk-border-strong); }
  .nk-peek .pk-bar { height: 40px; padding: 0 max(8px, env(safe-area-inset-right, 0px)) 0 max(8px, env(safe-area-inset-left, 0px)); }
  .nk-peek .pk-body { padding: 0 max(20px, env(safe-area-inset-right, 0px)) max(24px, env(safe-area-inset-bottom, 0px)) max(20px, env(safe-area-inset-left, 0px)); }
  .nk-peek .pk-resize { display: none; }
  /* A banner puts its action under the text instead of squeezing the text
     into a narrow column beside it. */
  .nk-banner { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; }
  .nk-banner .b-action,
  .nk-banner ::slotted(.b-action),
  .nk-banner ::slotted([slot="action"]) { grid-column: 1 / -1; justify-self: start; margin-left: 0; }
  .nk-banner ::slotted(.b-action),
  .nk-banner ::slotted([slot="action"]) { margin-left: 0 !important; }
  .nk-app.peek-inset .nk-main { padding-right: 0; }
  /* A dialog rises from the bottom edge like the sheet, its buttons stacked
     across the width with the confirming one on top. */
  .nk-dialog-backdrop { flex-direction: column; justify-content: flex-end; padding: max(24px, env(safe-area-inset-top, 0px)) 0 0; }
  .nk-dialog {
    width: 100%; max-width: 640px; border-radius: 14px 14px 0 0; scale: none; translate: 0 100%;
    padding: 6px max(20px, env(safe-area-inset-right, 0px)) max(16px, env(safe-area-inset-bottom, 0px)) max(20px, env(safe-area-inset-left, 0px));
    transition: translate .25s cubic-bezier(.2, .8, .2, 1);
  }
  .nk-dialog.wide { width: 100%; }
  .nk-dialog-backdrop.open .nk-dialog { translate: none; }
  @starting-style { .nk-dialog-backdrop.open .nk-dialog { translate: 0 100%; } }
  .nk-dialog::before { content: ""; display: block; width: 36px; height: 4px; margin: 4px auto 14px; border-radius: 2px; background: var(--nk-border-strong); }
  .nk-dialog .dl-actions { flex-direction: column-reverse; }
  /* A visible tab bar would cover the toast, so it rises 12px above the bar.
     :has() sees class markup only; <nk-toast> measures the bar itself. */
  :root:has(.nk-tab-bar:not([hidden])) .nk-toast { bottom: calc(var(--nk-tab-bar-height) + max(6px, env(safe-area-inset-bottom, 0px)) + 6px); }
  :root:has(.nk-tab-bar.floating:not([hidden])) .nk-toast { bottom: calc(var(--nk-tab-bar-height) + 24px + env(safe-area-inset-bottom, 0px)); }
}


/* ============================================================
   B13. REDUCED MOTION

   Respects the OS setting: the skeleton shimmer stops, every
   transition and animation collapses to an instant state change.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .nk-skeleton { animation: none; background: var(--nk-bg-callout); }
  [class*="nk-"],
  [class*="nk-"]::before,
  [class*="nk-"]::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
