@aquera/nile-elements 2.0.11 → 2.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +3 -0
  2. package/demo/app-shell.html +21 -21
  3. package/dist/index.js +76 -66
  4. package/dist/nile-app-shell/nile-app-shell.cjs.js +1 -1
  5. package/dist/nile-app-shell/nile-app-shell.cjs.js.map +1 -1
  6. package/dist/nile-app-shell/nile-app-shell.css.cjs.js +1 -1
  7. package/dist/nile-app-shell/nile-app-shell.css.cjs.js.map +1 -1
  8. package/dist/nile-app-shell/nile-app-shell.css.esm.js +35 -32
  9. package/dist/nile-app-shell/nile-app-shell.esm.js +39 -34
  10. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js +1 -1
  11. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js.map +1 -1
  12. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.esm.js +3 -1
  13. package/dist/src/nile-app-shell/nile-app-shell-regions.test.js +9 -5
  14. package/dist/src/nile-app-shell/nile-app-shell-regions.test.js.map +1 -1
  15. package/dist/src/nile-app-shell/nile-app-shell.css.js +33 -30
  16. package/dist/src/nile-app-shell/nile-app-shell.css.js.map +1 -1
  17. package/dist/src/nile-app-shell/nile-app-shell.d.ts +22 -22
  18. package/dist/src/nile-app-shell/nile-app-shell.js +86 -76
  19. package/dist/src/nile-app-shell/nile-app-shell.js.map +1 -1
  20. package/dist/src/nile-app-shell/nile-app-shell.test.d.ts +1 -0
  21. package/dist/src/nile-app-shell/nile-app-shell.test.js +307 -89
  22. package/dist/src/nile-app-shell/nile-app-shell.test.js.map +1 -1
  23. package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js +3 -1
  24. package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js.map +1 -1
  25. package/dist/src/version.js +1 -1
  26. package/dist/src/version.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +1 -1
  29. package/src/nile-app-shell/nile-app-shell-regions.test.ts +9 -5
  30. package/src/nile-app-shell/nile-app-shell.css.ts +33 -30
  31. package/src/nile-app-shell/nile-app-shell.test.ts +348 -105
  32. package/src/nile-app-shell/nile-app-shell.ts +89 -82
  33. package/src/nile-app-shell-panel/nile-app-shell-panel.css.ts +3 -1
  34. package/vscode-html-custom-data.json +27 -37
@@ -327,8 +327,8 @@ describe('nile-side-bar in the shell track', () => {
327
327
  });
328
328
  });
329
329
  /*
330
- * The HTML API, driven from markup. pageTitle, backLabel, noTabs, panelBack
331
- * and panelBackLabel deliberately declare no `attribute:` option, so Lit
330
+ * The HTML API, driven from markup. pageTitle, headerBack, headerBackLabel,
331
+ * noTabs, panelBack and panelBackLabel declare no kebab `attribute:` option, so Lit
332
332
  * observes the lowercased property name (pagetitle, notabs, ...) and markup
333
333
  * writes them camelCase — HTML lowercases `pageTitle=` to match.
334
334
  *
@@ -344,8 +344,8 @@ describe('nile-app-shell — the attributes the docs advertise', () => {
344
344
  <nile-app-shell
345
345
  style="width: 1440px; height: 600px;"
346
346
  pageTitle="Applications"
347
- backLabel="Integrations"
348
- leading="back"
347
+ headerBack
348
+ headerBackLabel="Integrations"
349
349
  noTabs
350
350
  panelBack
351
351
  panelBackLabel="Chat history"
@@ -361,7 +361,8 @@ describe('nile-app-shell — the attributes the docs advertise', () => {
361
361
  await el.updateComplete;
362
362
  // Each attribute reached its property.
363
363
  expect(el.pageTitle, 'pageTitle').to.equal('Applications');
364
- expect(el.backLabel, 'backLabel').to.equal('Integrations');
364
+ expect(el.headerBack, 'headerBack').to.be.true;
365
+ expect(el.headerBackLabel, 'headerBackLabel').to.equal('Integrations');
365
366
  expect(el.noTabs, 'noTabs').to.be.true;
366
367
  expect(el.panelBack, 'panelBack').to.be.true;
367
368
  expect(el.panelBackLabel, 'panelBackLabel').to.equal('Chat history');
@@ -372,7 +373,10 @@ describe('nile-app-shell — the attributes the docs advertise', () => {
372
373
  // The reflecting pair round-trip to the lowercased name, not to kebab.
373
374
  expect(el.hasAttribute('notabs')).to.be.true;
374
375
  expect(el.hasAttribute('panelback')).to.be.true;
376
+ expect(el.hasAttribute('headerback')).to.be.true;
377
+ expect(el.getAttribute('headerbacklabel')).to.equal('Integrations');
375
378
  expect(el.hasAttribute('no-tabs')).to.be.false;
379
+ expect(el.hasAttribute('header-back')).to.be.false;
376
380
  el.noTabs = false;
377
381
  el.panelBack = false;
378
382
  await el.updateComplete;
@@ -1 +1 @@
1
- {"version":3,"file":"nile-app-shell-regions.test.js","sourceRoot":"","sources":["../../../src/nile-app-shell/nile-app-shell-regions.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html, oneEvent, waitUntil } from '@open-wc/testing';\nimport './nile-app-shell';\nimport '../nile-app-shell-side-nav/nile-app-shell-side-nav';\nimport '../nile-app-shell-main/nile-app-shell-main';\nimport '../nile-app-shell-panel/nile-app-shell-panel';\nimport '../nile-side-bar/nile-side-bar';\nimport '../nile-nav-tab-group/nile-nav-tab-group';\nimport '../nile-nav-tab/nile-nav-tab';\nimport type { NileAppShell } from './nile-app-shell';\nimport type { NileAppShellSideNav } from '../nile-app-shell-side-nav/nile-app-shell-side-nav';\nimport type { NileAppShellMain } from '../nile-app-shell-main/nile-app-shell-main';\nimport type { NileAppShellPanel } from '../nile-app-shell-panel/nile-app-shell-panel';\n\n/** The compositional form: one child element per region, no slot names. */\nconst composed = async (width = 1440, overlayBreakpoint = 0) => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell\n style=\"width: ${width}px; height: 600px;\"\n overlay-breakpoint=${overlayBreakpoint}\n >\n <nile-app-shell-side-nav>\n <span slot=\"header\">Aquera</span>\n <nav>nav</nav>\n <span slot=\"footer\">account</span>\n </nile-app-shell-side-nav>\n\n <span slot=\"top-bar\">Title</span>\n\n <nile-app-shell-main>\n <div class=\"page\">page</div>\n </nile-app-shell-main>\n\n <nile-app-shell-panel label=\"Ask Aquera\">\n <div>answer</div>\n <div slot=\"footer\">composer</div>\n </nile-app-shell-panel>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-panel'));\n return el;\n};\n\nconst region = <T extends Element>(el: NileAppShell, tag: string) =>\n el.querySelector<T>(tag)!;\n\ndescribe('Region components — slot assignment', () => {\n it('1. each region claims the shell slot it belongs to', async () => {\n const el = await composed();\n expect(region(el, 'nile-app-shell-side-nav').getAttribute('slot')).to.equal(\n 'side-nav'\n );\n expect(region(el, 'nile-app-shell-panel').getAttribute('slot')).to.equal(\n 'panel'\n );\n // Main belongs to the default slot, so it must claim no slot at all.\n expect(region(el, 'nile-app-shell-main').hasAttribute('slot')).to.be.false;\n });\n\n it('2. the shell sees all three regions as filled', async () => {\n const el = await composed();\n expect(el.hasAttribute('has-side-nav')).to.be.true;\n expect(el.hasAttribute('has-panel')).to.be.true;\n expect(el.panelAvailable).to.be.true;\n });\n\n it('3. an explicit slot placement is respected, not overwritten', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px;\">\n <nile-app-shell-panel slot=\"aside\">detail</nile-app-shell-panel>\n <nile-app-shell-main>page</nile-app-shell-main>\n </nile-app-shell>\n `);\n await el.updateComplete;\n expect(\n el.querySelector('nile-app-shell-panel')!.getAttribute('slot')\n ).to.equal('aside');\n await waitUntil(() => el.hasAttribute('has-aside'));\n expect(el.hasAttribute('has-panel')).to.be.false;\n });\n});\n\ndescribe('nile-app-shell-side-nav', () => {\n it('4. mirrors the shell rail state onto its own collapsed attribute', async () => {\n const el = await composed();\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n expect(nav.collapsed).to.be.false;\n\n el.collapseNav();\n await el.updateComplete;\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.true;\n\n el.expandNav();\n await el.updateComplete;\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.false;\n });\n\n it('5. follows a rail the shell forces at narrow widths', async () => {\n const el = await composed(1000);\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n el.openPanel();\n await waitUntil(() => el.navLocked);\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.true;\n expect(el.navCollapsed).to.be.false; // the lock, not a preference\n });\n\n it('6. renders header, body and footer regions', async () => {\n const el = await composed();\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n ['header', 'body', 'footer'].forEach(part => {\n expect(nav.shadowRoot!.querySelector(`[part~=\"${part}\"]`)).to.exist;\n });\n });\n});\n\ndescribe('nile-app-shell-main', () => {\n it('7. is the size query container page CSS sizes against', async () => {\n const el = await composed();\n const main = region<NileAppShellMain>(el, 'nile-app-shell-main');\n expect(getComputedStyle(main).containerType).to.equal('inline-size');\n });\n\n it('8. no-container drops the containment', async () => {\n const el = await composed();\n const main = region<NileAppShellMain>(el, 'nile-app-shell-main');\n main.noContainer = true;\n await main.updateComplete;\n expect(getComputedStyle(main).containerType).to.equal('normal');\n });\n});\n\ndescribe('nile-app-shell-panel', () => {\n it('9. takes over the panel chrome from the shell', async () => {\n const el = await composed();\n expect(el.getAttribute('panel-chrome')).to.equal('external');\n // The shell's own header must not also render.\n expect(el.shadowRoot!.querySelector('[part~=\"panel-header\"]')).to.not.exist;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.shadowRoot!.querySelector('[part~=\"header\"]')).to.exist;\n expect(\n panel.shadowRoot!.querySelector('[part~=\"title\"]')!.textContent!.trim()\n ).to.equal('Ask Aquera');\n });\n\n it('10. the shell keeps its own chrome for plain slotted content', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px;\">\n <div slot=\"panel\">answer</div>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-panel'));\n expect(el.getAttribute('panel-chrome')).to.equal('internal');\n expect(el.shadowRoot!.querySelector('[part~=\"panel-header\"]')).to.exist;\n });\n\n it('11. mirrors the shell panel mode', async () => {\n const el = await composed(1000, 1280);\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n await waitUntil(() => el.panelMode === 'overlay');\n await panel.updateComplete;\n expect(panel.getAttribute('mode')).to.equal('overlay');\n });\n\n it('12. its close button closes the panel through the shell', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const close =\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"close\"]')!;\n const closed = oneEvent(panel, 'nile-close');\n close.click();\n const event = await closed;\n expect(event).to.exist;\n await el.updateComplete;\n expect(el.panelOpen).to.be.false;\n });\n\n it('13. no-close and no-header drop those controls', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.noClose = true;\n panel.noHeader = true;\n await panel.updateComplete;\n const close = panel.shadowRoot!.querySelector('[part~=\"close\"]')!;\n const header = panel.shadowRoot!.querySelector('[part~=\"header\"]')!;\n expect(getComputedStyle(close).display).to.equal('none');\n expect(getComputedStyle(header).display).to.equal('none');\n });\n\n it('14. shows the footer only when something is slotted into it', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.hasAttribute('has-footer')).to.be.true;\n\n panel.querySelector('[slot=\"footer\"]')!.remove();\n await waitUntil(() => !panel.hasAttribute('has-footer'));\n expect(\n getComputedStyle(panel.shadowRoot!.querySelector('[part~=\"footer\"]')!)\n .display\n ).to.equal('none');\n });\n\n it('15. names the region for assistive tech from its label', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.getAttribute('role')).to.equal('complementary');\n expect(panel.getAttribute('aria-label')).to.equal('Ask Aquera');\n\n panel.label = 'Ask Nile';\n await panel.updateComplete;\n expect(panel.getAttribute('aria-label')).to.equal('Ask Nile');\n });\n\n it('16. holds the back control until back asks for it', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const back = () => panel.shadowRoot!.querySelector('[part~=\"back\"]');\n const mark = panel.shadowRoot!.querySelector('.mark')!;\n // Not rendered at all in the root view, so no stylesheet override can surface it.\n expect(back()).to.not.exist;\n expect(getComputedStyle(mark).display).to.not.equal('none');\n\n panel.back = true;\n await panel.updateComplete;\n expect(back()).to.exist;\n expect(getComputedStyle(back()!).display).to.not.equal('none');\n // The back control stands where the brand mark stands in the root view.\n expect(getComputedStyle(mark).display).to.equal('none');\n });\n\n it('17. its back control emits nile-back and leaves the panel open', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n panel.backLabel = 'Back to chats';\n await panel.updateComplete;\n\n const back =\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"back\"]')!;\n expect(back.getAttribute('aria-label')).to.equal('Back to chats');\n\n const went = oneEvent(panel, 'nile-back');\n back.click();\n expect(await went).to.exist;\n await el.updateComplete;\n // The panel keeps no view stack, so going back is not closing.\n expect(el.panelOpen).to.be.true;\n });\n\n // Birat's review: a page listening on the shell for nile-panel-back must not go deaf when it slots this panel.\n it('82. its back control also emits nile-panel-back, once, and it reaches the shell', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n await panel.updateComplete;\n\n const order: string[] = [];\n const log = (e: Event) => order.push(e.type);\n el.addEventListener('nile-back', log);\n el.addEventListener('nile-panel-back', log);\n\n const reached = oneEvent(el, 'nile-panel-back');\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"back\"]')!.click();\n const event = await reached;\n\n // Bubbles and composed, so a listener outside the shadow roots hears it.\n expect(event.bubbles).to.be.true;\n expect(event.composed).to.be.true;\n // One press: nile-back then nile-panel-back, each exactly once.\n expect(order).to.deep.equal(['nile-back', 'nile-panel-back']);\n\n order.length = 0;\n panel.goBack();\n expect(order).to.deep.equal(['nile-back', 'nile-panel-back']);\n });\n\n // The panel draws its header controls as bare glyphs via ::part(base), overriding nile-button's circle and ghost surface.\n it('18. draws its header controls bare, in the utility box', async () => {\n const el = await composed();\n // A closed panel is display:none, and a hidden box measures zero.\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n await panel.updateComplete;\n\n /*\n * The contract is \"the control fills the utility box\", not \"the control is\n * 32px\": --nile-app-shell-utility-size is a token chain\n * (--nile-spacing-4xl, else --ng-spacing-4xl -> --ng-spacing-8), and both\n * sheets happen to land on 32 today. Reading the resolved value keeps this\n * honest if either sheet moves. The || 32 is the stylesheet's own literal\n * floor, for this unthemed fixture where neither token is defined.\n */\n const utility =\n parseFloat(\n getComputedStyle(panel).getPropertyValue('--nile-app-shell-utility-size')\n ) || 32;\n expect(utility, 'the utility box resolves to a real size').to.be.above(0);\n\n for (const name of ['back', 'close']) {\n const control = panel.shadowRoot!.querySelector(`[part~=\"${name}\"]`)!;\n const base = control.shadowRoot!.querySelector('[part~=\"base\"]')!;\n expect(getComputedStyle(base).backgroundColor).to.equal(\n 'rgba(0, 0, 0, 0)'\n );\n const box = base.getBoundingClientRect();\n expect(box.width, `${name} width`).to.equal(utility);\n expect(box.height, `${name} height`).to.equal(utility);\n }\n });\n\n // The panel mounts in the shell's light DOM but sizes its header as its own box, independent of the page header.\n it('19. sizes its header independently of the page header', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const header = () =>\n panel.shadowRoot!.querySelector('.header') as HTMLElement;\n\n expect(header().getBoundingClientRect().height).to.equal(56);\n\n // The Description axis moves the page header to 76px, but the panel's header must not follow it.\n el.pageTitle = 'Connected applications';\n el.description = 'Everything connected to Aquera';\n await el.updateComplete;\n await panel.updateComplete;\n\n expect(el.hasAttribute('has-description')).to.be.true;\n expect(header().getBoundingClientRect().height).to.equal(56);\n });\n\n it('20. keeps its 56px header when mounted outside a shell', async () => {\n // No shell, so the literal fallback is the floor; the stray top-bar height stands in for a page that sets it globally.\n const panel = await fixture<NileAppShellPanel>(html`\n <nile-app-shell-panel\n label=\"Ask Aquera\"\n style=\"--nile-app-shell-top-bar-height: 76px;\"\n >\n <div>answer</div>\n </nile-app-shell-panel>\n `);\n\n const header = panel.shadowRoot!.querySelector('.header') as HTMLElement;\n expect(header.getBoundingClientRect().height).to.equal(56);\n });\n});\n\n// The shell's nav track mirrors nile-side-bar's per-theme width, so ::slotted width:100% remains only so a raw nav still fills the track.\ndescribe('nile-side-bar in the shell track', () => {\n const ENTERPRISE = '--nile-width-240px: 240px; --nile-width-70px: 70px;';\n const NXTGEN = '--ng-spacing-296: 296px; --ng-spacing-68: 68px;';\n\n const railedTo = async (tokens: string, expanded: number, rail: number) => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px; ${tokens}\">\n <nile-side-bar slot=\"side-nav\" position=\"left\"></nile-side-bar>\n <p>page</p>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-side-nav'));\n const bar = el.querySelector('nile-side-bar')!;\n const width = () => Math.round(bar.getBoundingClientRect().width);\n\n expect(width(), 'expanded').to.equal(expanded);\n\n el.collapseNav();\n await el.updateComplete;\n await waitUntil(() => width() === rail, 'the rail never settled', {\n timeout: 2000,\n interval: 50,\n });\n expect(width(), 'railed').to.equal(rail);\n };\n\n it('21. matches the deployed enterprise side bar: 240 / 70', async () => {\n await railedTo(ENTERPRISE, 240, 70);\n });\n\n it('22. matches the deployed nxtgen side bar: 296 / 68', async () => {\n await railedTo(NXTGEN, 296, 68);\n });\n\n // The slotted width is not !important, yet the shell's ::slotted rule still beats the side bar's own :host width, so overriding the documented track properties resizes the bar with the track.\n it('83. follows an overridden track width: 200 / 50', async () => {\n const overrides =\n '--nile-app-shell-side-nav-width: 200px; --nile-app-shell-side-nav-rail-width: 50px;';\n await railedTo(`${ENTERPRISE} ${overrides}`, 200, 50);\n await railedTo(`${NXTGEN} ${overrides}`, 200, 50);\n });\n});\n\n/*\n * The HTML API, driven from markup. pageTitle, backLabel, noTabs, panelBack\n * and panelBackLabel deliberately declare no `attribute:` option, so Lit\n * observes the lowercased property name (pagetitle, notabs, ...) and markup\n * writes them camelCase — HTML lowercases `pageTitle=` to match.\n *\n * Every other test in this suite sets these as JS properties, which works no\n * matter what the attribute is called — so if a kebab `attribute:` option is\n * added back, nothing else fails and `<nile-app-shell pageTitle=\"...\">`\n * silently does nothing. This fixture is markup-only on purpose: it is the\n * one that breaks if that happens.\n */\ndescribe('nile-app-shell — the attributes the docs advertise', () => {\n it('23. reads its title block and switches from camelCase markup', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell\n style=\"width: 1440px; height: 600px;\"\n pageTitle=\"Applications\"\n backLabel=\"Integrations\"\n leading=\"back\"\n noTabs\n panelBack\n panelBackLabel=\"Chat history\"\n >\n <nav slot=\"side-nav\">nav</nav>\n <nile-nav-tab-group slot=\"tabs\">\n <nile-nav-tab slot=\"nav\" panel=\"apps\" active>Connected</nile-nav-tab>\n </nile-nav-tab-group>\n <p>page</p>\n <div slot=\"panel\">assistant</div>\n </nile-app-shell>\n `);\n await el.updateComplete;\n\n // Each attribute reached its property.\n expect(el.pageTitle, 'pageTitle').to.equal('Applications');\n expect(el.backLabel, 'backLabel').to.equal('Integrations');\n expect(el.noTabs, 'noTabs').to.be.true;\n expect(el.panelBack, 'panelBack').to.be.true;\n expect(el.panelBackLabel, 'panelBackLabel').to.equal('Chat history');\n\n // And had the effect the attribute promises, not just the assignment.\n const title = el.shadowRoot!.querySelector('[part~=\"page-title\"]');\n expect(title!.textContent!.trim()).to.equal('Applications');\n expect(el.tabsVisible, 'noTabs hides the strip').to.be.false;\n\n // The reflecting pair round-trip to the lowercased name, not to kebab.\n expect(el.hasAttribute('notabs')).to.be.true;\n expect(el.hasAttribute('panelback')).to.be.true;\n expect(el.hasAttribute('no-tabs')).to.be.false;\n el.noTabs = false;\n el.panelBack = false;\n await el.updateComplete;\n expect(el.hasAttribute('notabs'), 'notabs is removed again').to.be.false;\n expect(el.hasAttribute('panelback')).to.be.false;\n });\n});\n"]}
1
+ {"version":3,"file":"nile-app-shell-regions.test.js","sourceRoot":"","sources":["../../../src/nile-app-shell/nile-app-shell-regions.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html, oneEvent, waitUntil } from '@open-wc/testing';\nimport './nile-app-shell';\nimport '../nile-app-shell-side-nav/nile-app-shell-side-nav';\nimport '../nile-app-shell-main/nile-app-shell-main';\nimport '../nile-app-shell-panel/nile-app-shell-panel';\nimport '../nile-side-bar/nile-side-bar';\nimport '../nile-nav-tab-group/nile-nav-tab-group';\nimport '../nile-nav-tab/nile-nav-tab';\nimport type { NileAppShell } from './nile-app-shell';\nimport type { NileAppShellSideNav } from '../nile-app-shell-side-nav/nile-app-shell-side-nav';\nimport type { NileAppShellMain } from '../nile-app-shell-main/nile-app-shell-main';\nimport type { NileAppShellPanel } from '../nile-app-shell-panel/nile-app-shell-panel';\n\n/** The compositional form: one child element per region, no slot names. */\nconst composed = async (width = 1440, overlayBreakpoint = 0) => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell\n style=\"width: ${width}px; height: 600px;\"\n overlay-breakpoint=${overlayBreakpoint}\n >\n <nile-app-shell-side-nav>\n <span slot=\"header\">Aquera</span>\n <nav>nav</nav>\n <span slot=\"footer\">account</span>\n </nile-app-shell-side-nav>\n\n <span slot=\"top-bar\">Title</span>\n\n <nile-app-shell-main>\n <div class=\"page\">page</div>\n </nile-app-shell-main>\n\n <nile-app-shell-panel label=\"Ask Aquera\">\n <div>answer</div>\n <div slot=\"footer\">composer</div>\n </nile-app-shell-panel>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-panel'));\n return el;\n};\n\nconst region = <T extends Element>(el: NileAppShell, tag: string) =>\n el.querySelector<T>(tag)!;\n\ndescribe('Region components — slot assignment', () => {\n it('1. each region claims the shell slot it belongs to', async () => {\n const el = await composed();\n expect(region(el, 'nile-app-shell-side-nav').getAttribute('slot')).to.equal(\n 'side-nav'\n );\n expect(region(el, 'nile-app-shell-panel').getAttribute('slot')).to.equal(\n 'panel'\n );\n // Main belongs to the default slot, so it must claim no slot at all.\n expect(region(el, 'nile-app-shell-main').hasAttribute('slot')).to.be.false;\n });\n\n it('2. the shell sees all three regions as filled', async () => {\n const el = await composed();\n expect(el.hasAttribute('has-side-nav')).to.be.true;\n expect(el.hasAttribute('has-panel')).to.be.true;\n expect(el.panelAvailable).to.be.true;\n });\n\n it('3. an explicit slot placement is respected, not overwritten', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px;\">\n <nile-app-shell-panel slot=\"aside\">detail</nile-app-shell-panel>\n <nile-app-shell-main>page</nile-app-shell-main>\n </nile-app-shell>\n `);\n await el.updateComplete;\n expect(\n el.querySelector('nile-app-shell-panel')!.getAttribute('slot')\n ).to.equal('aside');\n await waitUntil(() => el.hasAttribute('has-aside'));\n expect(el.hasAttribute('has-panel')).to.be.false;\n });\n});\n\ndescribe('nile-app-shell-side-nav', () => {\n it('4. mirrors the shell rail state onto its own collapsed attribute', async () => {\n const el = await composed();\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n expect(nav.collapsed).to.be.false;\n\n el.collapseNav();\n await el.updateComplete;\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.true;\n\n el.expandNav();\n await el.updateComplete;\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.false;\n });\n\n it('5. follows a rail the shell forces at narrow widths', async () => {\n const el = await composed(1000);\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n el.openPanel();\n await waitUntil(() => el.navLocked);\n await nav.updateComplete;\n expect(nav.hasAttribute('collapsed')).to.be.true;\n expect(el.navCollapsed).to.be.false; // the lock, not a preference\n });\n\n it('6. renders header, body and footer regions', async () => {\n const el = await composed();\n const nav = region<NileAppShellSideNav>(el, 'nile-app-shell-side-nav');\n ['header', 'body', 'footer'].forEach(part => {\n expect(nav.shadowRoot!.querySelector(`[part~=\"${part}\"]`)).to.exist;\n });\n });\n});\n\ndescribe('nile-app-shell-main', () => {\n it('7. is the size query container page CSS sizes against', async () => {\n const el = await composed();\n const main = region<NileAppShellMain>(el, 'nile-app-shell-main');\n expect(getComputedStyle(main).containerType).to.equal('inline-size');\n });\n\n it('8. no-container drops the containment', async () => {\n const el = await composed();\n const main = region<NileAppShellMain>(el, 'nile-app-shell-main');\n main.noContainer = true;\n await main.updateComplete;\n expect(getComputedStyle(main).containerType).to.equal('normal');\n });\n});\n\ndescribe('nile-app-shell-panel', () => {\n it('9. takes over the panel chrome from the shell', async () => {\n const el = await composed();\n expect(el.getAttribute('panel-chrome')).to.equal('external');\n // The shell's own header must not also render.\n expect(el.shadowRoot!.querySelector('[part~=\"panel-header\"]')).to.not.exist;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.shadowRoot!.querySelector('[part~=\"header\"]')).to.exist;\n expect(\n panel.shadowRoot!.querySelector('[part~=\"title\"]')!.textContent!.trim()\n ).to.equal('Ask Aquera');\n });\n\n it('10. the shell keeps its own chrome for plain slotted content', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px;\">\n <div slot=\"panel\">answer</div>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-panel'));\n expect(el.getAttribute('panel-chrome')).to.equal('internal');\n expect(el.shadowRoot!.querySelector('[part~=\"panel-header\"]')).to.exist;\n });\n\n it('11. mirrors the shell panel mode', async () => {\n const el = await composed(1000, 1280);\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n await waitUntil(() => el.panelMode === 'overlay');\n await panel.updateComplete;\n expect(panel.getAttribute('mode')).to.equal('overlay');\n });\n\n it('12. its close button closes the panel through the shell', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const close =\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"close\"]')!;\n const closed = oneEvent(panel, 'nile-close');\n close.click();\n const event = await closed;\n expect(event).to.exist;\n await el.updateComplete;\n expect(el.panelOpen).to.be.false;\n });\n\n it('13. no-close and no-header drop those controls', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.noClose = true;\n panel.noHeader = true;\n await panel.updateComplete;\n const close = panel.shadowRoot!.querySelector('[part~=\"close\"]')!;\n const header = panel.shadowRoot!.querySelector('[part~=\"header\"]')!;\n expect(getComputedStyle(close).display).to.equal('none');\n expect(getComputedStyle(header).display).to.equal('none');\n });\n\n it('14. shows the footer only when something is slotted into it', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.hasAttribute('has-footer')).to.be.true;\n\n panel.querySelector('[slot=\"footer\"]')!.remove();\n await waitUntil(() => !panel.hasAttribute('has-footer'));\n expect(\n getComputedStyle(panel.shadowRoot!.querySelector('[part~=\"footer\"]')!)\n .display\n ).to.equal('none');\n });\n\n it('15. names the region for assistive tech from its label', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n expect(panel.getAttribute('role')).to.equal('complementary');\n expect(panel.getAttribute('aria-label')).to.equal('Ask Aquera');\n\n panel.label = 'Ask Nile';\n await panel.updateComplete;\n expect(panel.getAttribute('aria-label')).to.equal('Ask Nile');\n });\n\n it('16. holds the back control until back asks for it', async () => {\n const el = await composed();\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const back = () => panel.shadowRoot!.querySelector('[part~=\"back\"]');\n const mark = panel.shadowRoot!.querySelector('.mark')!;\n // Not rendered at all in the root view, so no stylesheet override can surface it.\n expect(back()).to.not.exist;\n expect(getComputedStyle(mark).display).to.not.equal('none');\n\n panel.back = true;\n await panel.updateComplete;\n expect(back()).to.exist;\n expect(getComputedStyle(back()!).display).to.not.equal('none');\n // The back control stands where the brand mark stands in the root view.\n expect(getComputedStyle(mark).display).to.equal('none');\n });\n\n it('17. its back control emits nile-back and leaves the panel open', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n panel.backLabel = 'Back to chats';\n await panel.updateComplete;\n\n const back =\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"back\"]')!;\n expect(back.getAttribute('aria-label')).to.equal('Back to chats');\n\n const went = oneEvent(panel, 'nile-back');\n back.click();\n expect(await went).to.exist;\n await el.updateComplete;\n // The panel keeps no view stack, so going back is not closing.\n expect(el.panelOpen).to.be.true;\n });\n\n // Birat's review: a page listening on the shell for nile-panel-back must not go deaf when it slots this panel.\n it('82. its back control also emits nile-panel-back, once, and it reaches the shell', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n await panel.updateComplete;\n\n const order: string[] = [];\n const log = (e: Event) => order.push(e.type);\n el.addEventListener('nile-back', log);\n el.addEventListener('nile-panel-back', log);\n\n const reached = oneEvent(el, 'nile-panel-back');\n panel.shadowRoot!.querySelector<HTMLButtonElement>('[part~=\"back\"]')!.click();\n const event = await reached;\n\n // Bubbles and composed, so a listener outside the shadow roots hears it.\n expect(event.bubbles).to.be.true;\n expect(event.composed).to.be.true;\n // One press: nile-back then nile-panel-back, each exactly once.\n expect(order).to.deep.equal(['nile-back', 'nile-panel-back']);\n\n order.length = 0;\n panel.goBack();\n expect(order).to.deep.equal(['nile-back', 'nile-panel-back']);\n });\n\n // The panel draws its header controls as bare glyphs via ::part(base), overriding nile-button's circle and ghost surface.\n it('18. draws its header controls bare, in the utility box', async () => {\n const el = await composed();\n // A closed panel is display:none, and a hidden box measures zero.\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n panel.back = true;\n await panel.updateComplete;\n\n /*\n * The contract is \"the control fills the utility box\", not \"the control is\n * 32px\": --nile-app-shell-utility-size is a token chain\n * (--nile-spacing-4xl, else --ng-spacing-4xl -> --ng-spacing-8), and both\n * sheets happen to land on 32 today. Reading the resolved value keeps this\n * honest if either sheet moves. The || 32 is the stylesheet's own literal\n * floor, for this unthemed fixture where neither token is defined.\n */\n const utility =\n parseFloat(\n getComputedStyle(panel).getPropertyValue('--nile-app-shell-utility-size')\n ) || 32;\n expect(utility, 'the utility box resolves to a real size').to.be.above(0);\n\n for (const name of ['back', 'close']) {\n const control = panel.shadowRoot!.querySelector(`[part~=\"${name}\"]`)!;\n const base = control.shadowRoot!.querySelector('[part~=\"base\"]')!;\n expect(getComputedStyle(base).backgroundColor).to.equal(\n 'rgba(0, 0, 0, 0)'\n );\n const box = base.getBoundingClientRect();\n expect(box.width, `${name} width`).to.equal(utility);\n expect(box.height, `${name} height`).to.equal(utility);\n }\n });\n\n // The panel mounts in the shell's light DOM but sizes its header as its own box, independent of the page header.\n it('19. sizes its header independently of the page header', async () => {\n const el = await composed();\n el.openPanel();\n await el.updateComplete;\n\n const panel = region<NileAppShellPanel>(el, 'nile-app-shell-panel');\n const header = () =>\n panel.shadowRoot!.querySelector('.header') as HTMLElement;\n\n expect(header().getBoundingClientRect().height).to.equal(56);\n\n // The Description axis moves the page header to 76px, but the panel's header must not follow it.\n el.pageTitle = 'Connected applications';\n el.description = 'Everything connected to Aquera';\n await el.updateComplete;\n await panel.updateComplete;\n\n expect(el.hasAttribute('has-description')).to.be.true;\n expect(header().getBoundingClientRect().height).to.equal(56);\n });\n\n it('20. keeps its 56px header when mounted outside a shell', async () => {\n // No shell, so the literal fallback is the floor; the stray top-bar height stands in for a page that sets it globally.\n const panel = await fixture<NileAppShellPanel>(html`\n <nile-app-shell-panel\n label=\"Ask Aquera\"\n style=\"--nile-app-shell-top-bar-height: 76px;\"\n >\n <div>answer</div>\n </nile-app-shell-panel>\n `);\n\n const header = panel.shadowRoot!.querySelector('.header') as HTMLElement;\n expect(header.getBoundingClientRect().height).to.equal(56);\n });\n});\n\n// The shell's nav track mirrors nile-side-bar's per-theme width, so ::slotted width:100% remains only so a raw nav still fills the track.\ndescribe('nile-side-bar in the shell track', () => {\n const ENTERPRISE = '--nile-width-240px: 240px; --nile-width-70px: 70px;';\n const NXTGEN = '--ng-spacing-296: 296px; --ng-spacing-68: 68px;';\n\n const railedTo = async (tokens: string, expanded: number, rail: number) => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell style=\"width: 1440px; height: 600px; ${tokens}\">\n <nile-side-bar slot=\"side-nav\" position=\"left\"></nile-side-bar>\n <p>page</p>\n </nile-app-shell>\n `);\n await waitUntil(() => el.hasAttribute('has-side-nav'));\n const bar = el.querySelector('nile-side-bar')!;\n const width = () => Math.round(bar.getBoundingClientRect().width);\n\n expect(width(), 'expanded').to.equal(expanded);\n\n el.collapseNav();\n await el.updateComplete;\n await waitUntil(() => width() === rail, 'the rail never settled', {\n timeout: 2000,\n interval: 50,\n });\n expect(width(), 'railed').to.equal(rail);\n };\n\n it('21. matches the deployed enterprise side bar: 240 / 70', async () => {\n await railedTo(ENTERPRISE, 240, 70);\n });\n\n it('22. matches the deployed nxtgen side bar: 296 / 68', async () => {\n await railedTo(NXTGEN, 296, 68);\n });\n\n // The slotted width is not !important, yet the shell's ::slotted rule still beats the side bar's own :host width, so overriding the documented track properties resizes the bar with the track.\n it('83. follows an overridden track width: 200 / 50', async () => {\n const overrides =\n '--nile-app-shell-side-nav-width: 200px; --nile-app-shell-side-nav-rail-width: 50px;';\n await railedTo(`${ENTERPRISE} ${overrides}`, 200, 50);\n await railedTo(`${NXTGEN} ${overrides}`, 200, 50);\n });\n});\n\n/*\n * The HTML API, driven from markup. pageTitle, headerBack, headerBackLabel,\n * noTabs, panelBack and panelBackLabel declare no kebab `attribute:` option, so Lit\n * observes the lowercased property name (pagetitle, notabs, ...) and markup\n * writes them camelCase — HTML lowercases `pageTitle=` to match.\n *\n * Every other test in this suite sets these as JS properties, which works no\n * matter what the attribute is called — so if a kebab `attribute:` option is\n * added back, nothing else fails and `<nile-app-shell pageTitle=\"...\">`\n * silently does nothing. This fixture is markup-only on purpose: it is the\n * one that breaks if that happens.\n */\ndescribe('nile-app-shell — the attributes the docs advertise', () => {\n it('23. reads its title block and switches from camelCase markup', async () => {\n const el = await fixture<NileAppShell>(html`\n <nile-app-shell\n style=\"width: 1440px; height: 600px;\"\n pageTitle=\"Applications\"\n headerBack\n headerBackLabel=\"Integrations\"\n noTabs\n panelBack\n panelBackLabel=\"Chat history\"\n >\n <nav slot=\"side-nav\">nav</nav>\n <nile-nav-tab-group slot=\"tabs\">\n <nile-nav-tab slot=\"nav\" panel=\"apps\" active>Connected</nile-nav-tab>\n </nile-nav-tab-group>\n <p>page</p>\n <div slot=\"panel\">assistant</div>\n </nile-app-shell>\n `);\n await el.updateComplete;\n\n // Each attribute reached its property.\n expect(el.pageTitle, 'pageTitle').to.equal('Applications');\n expect(el.headerBack, 'headerBack').to.be.true;\n expect(el.headerBackLabel, 'headerBackLabel').to.equal('Integrations');\n expect(el.noTabs, 'noTabs').to.be.true;\n expect(el.panelBack, 'panelBack').to.be.true;\n expect(el.panelBackLabel, 'panelBackLabel').to.equal('Chat history');\n\n // And had the effect the attribute promises, not just the assignment.\n const title = el.shadowRoot!.querySelector('[part~=\"page-title\"]');\n expect(title!.textContent!.trim()).to.equal('Applications');\n expect(el.tabsVisible, 'noTabs hides the strip').to.be.false;\n\n // The reflecting pair round-trip to the lowercased name, not to kebab.\n expect(el.hasAttribute('notabs')).to.be.true;\n expect(el.hasAttribute('panelback')).to.be.true;\n expect(el.hasAttribute('headerback')).to.be.true;\n expect(el.getAttribute('headerbacklabel')).to.equal('Integrations');\n expect(el.hasAttribute('no-tabs')).to.be.false;\n expect(el.hasAttribute('header-back')).to.be.false;\n el.noTabs = false;\n el.panelBack = false;\n await el.updateComplete;\n expect(el.hasAttribute('notabs'), 'notabs is removed again').to.be.false;\n expect(el.hasAttribute('panelback')).to.be.false;\n });\n});\n"]}
@@ -225,21 +225,21 @@ export const styles = css `
225
225
  flex: 1 1 auto;
226
226
  }
227
227
 
228
- /* The title block: the header's own heading, the Leading axis and the badge; renders before the top-bar slot. */
228
+ /* The title block: the back arrow, then the stack (app icon, heading and badge, with the description under them); renders before the top-bar slot. */
229
229
  .title-area {
230
230
  display: flex;
231
- /* Top-aligned, not centred: the leading element belongs to the title's row, not the title-plus-description stack. */
231
+ /* Top-aligned, not centred: the back arrow belongs to the title's row, not the title-plus-description stack. */
232
232
  align-items: flex-start;
233
- gap: var(--nile-spacing-md, var(--ng-spacing-md));
233
+ /* Figma's Title Area gap: 16px from the arrow to the stack. */
234
+ gap: var(--nile-spacing-xl, var(--ng-spacing-xl));
234
235
  min-width: 0;
235
236
  }
236
237
 
237
- /* The leading line box: exactly the page title's line height, centring whatever leading control sits in it. */
238
- .leading {
238
+ /* The back arrow's line box: exactly the page title's line height, centring the arrow on the title row. */
239
+ .back-line {
239
240
  flex: 0 0 auto;
240
241
  display: inline-flex;
241
242
  align-items: center;
242
- gap: var(--nile-spacing-md, var(--ng-spacing-md));
243
243
  min-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));
244
244
  }
245
245
 
@@ -278,7 +278,7 @@ export const styles = css `
278
278
  font-size: var(--nile-type-scale-1, var(--ng-font-size-text-xs));
279
279
  line-height: var(--nile-line-height-xsmall, var(--ng-line-height-text-xs));
280
280
  font-weight: var(--nile-font-weight-regular, var(--ng-font-weight-regular));
281
- color: var(--nile-colors-dark-500, var(--ng-colors-text-tertiary-600));
281
+ color: var(--nile-colors-dark-500, var(--ng-colors-text-quaternary-500));
282
282
  white-space: nowrap;
283
283
  overflow: hidden;
284
284
  text-overflow: ellipsis;
@@ -312,36 +312,24 @@ export const styles = css `
312
312
  white-space: nowrap;
313
313
  }
314
314
 
315
- /* Leading=Back: drawn as a breadcrumb label; the shell owns no history, so pressing it only emits nile-header-back. */
315
+ /* headerBack: an icon-only native button, so the aria-label names it directly; the shell owns no history, so pressing it only emits nile-click { value: 'back' }. */
316
316
  .back {
317
317
  flex: 0 0 auto;
318
318
  display: inline-flex;
319
319
  align-items: center;
320
- gap: var(--nile-spacing-xs, var(--ng-spacing-xs));
321
320
  margin: 0;
322
321
  padding: 0;
323
322
  border: 0;
324
323
  background: none;
325
324
  cursor: pointer;
326
- font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
327
- font-size: var(--nile-type-scale-3, var(--ng-font-size-text-md));
328
- line-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));
329
- font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-semibold));
330
- color: var(--nile-colors-dark-500, var(--ng-colors-text-tertiary-600));
325
+ color: var(--nile-colors-dark-500, var(--ng-colors-fg-quaternary-400));
331
326
  }
332
327
 
333
328
  .back:hover {
334
329
  color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
335
330
  }
336
331
 
337
- .crumb-divider {
338
- flex: 0 0 auto;
339
- display: inline-flex;
340
- align-items: center;
341
- color: var(--nile-colors-dark-500, var(--ng-colors-fg-quaternary-400));
342
- }
343
-
344
- /* Leading=AppIcon: a 20px block before the title; the page slots the mark, the shell owns the box, surface and radius. */
332
+ /* App icon: a 20px block at the start of the title row, so the description lines up under it; shown whenever the app-icon slot has content. */
345
333
  .app-icon {
346
334
  position: relative;
347
335
  flex: 0 0 auto;
@@ -384,16 +372,15 @@ export const styles = css `
384
372
  padding: 1.4px;
385
373
  }
386
374
 
387
- :host(:not([leading='app-icon'])) .app-icon,
388
- :host(:not([leading='back'])) .back,
389
- :host(:not([leading='back'])) .crumb-divider {
375
+ :host(:not([has-app-icon])) .app-icon {
390
376
  display: none;
391
377
  }
392
378
 
379
+ /* Figma's Header Bar gap: 16px between every header action, the divider and Ask. */
393
380
  .top-bar-actions {
394
381
  display: flex;
395
382
  align-items: center;
396
- gap: var(--nile-spacing-md, var(--ng-spacing-md));
383
+ gap: var(--nile-spacing-xl, var(--ng-spacing-xl));
397
384
  margin-inline-start: auto;
398
385
  }
399
386
 
@@ -402,7 +389,7 @@ export const styles = css `
402
389
  display: none;
403
390
  }
404
391
 
405
- /* The Ask button: a stock <nile-button variant="primary"> the shell renders itself; the only rule here is its flex behaviour as a top-bar item. */
392
+ /* The Ask button: a stock <nile-button variant="secondary"> the shell renders itself; the only rule here is its flex behaviour as a top-bar item. */
406
393
  .ask {
407
394
  flex: 0 0 auto;
408
395
  }
@@ -419,10 +406,11 @@ export const styles = css `
419
406
  height: 16px;
420
407
  }
421
408
 
409
+ /* 10px after the 32px circle is 16px after the 20px glyph (6px overhang + 10), Figma's toggle-to-divider gap. */
422
410
  .nav-toggle-group {
423
411
  display: flex;
424
412
  align-items: center;
425
- gap: var(--nile-spacing-lg, var(--ng-spacing-lg));
413
+ gap: var(--nile-spacing-md-alt, var(--ng-spacing-md-alt));
426
414
  }
427
415
 
428
416
  /* Lands the 20px glyph box, not the 32px utility circle, on the 24px origin: (32 - 20) / 2 = 6. */
@@ -430,10 +418,12 @@ export const styles = css `
430
418
  margin-inline-start: -6px;
431
419
  }
432
420
 
421
+ /* Figma's Divider Line: a 16px 1px stroke that takes no layout width, so the items on both sides sit a clean 16px from it. Used after the nav toggle and, as ask-rule, before Ask. */
433
422
  .rule {
434
423
  flex: 0 0 auto;
435
424
  width: var(--nile-border-width-1, var(--ng-border-width-1));
436
- height: 24px;
425
+ margin-inline-end: calc(-1 * var(--nile-border-width-1, var(--ng-border-width-1)));
426
+ height: 16px;
437
427
  background: var(
438
428
  --nile-colors-neutral-400,
439
429
  var(--ng-colors-border-secondary)
@@ -486,6 +476,17 @@ export const styles = css `
486
476
  /* Scoped to the group, not the slot, so bare tab controls are not stretched to an equal share of the strip. */
487
477
  ::slotted(nile-nav-tab-group[slot='tabs']) {
488
478
  --track-width: 0px;
479
+ /*
480
+ * The active indicator (Figma: fg-brand-primary-alt) is NOT set here: the top placement hard-codes
481
+ * var(--nile-colors-primary-600, var(--ng-colors-text-brand-secondary-700)) inside nile-nav-tab-group's shadow tree, and
482
+ * remapping either token from here would also recolour nile-nav-tab's focus ring and focus label. Known limitation (spec A-7).
483
+ */
484
+ /*
485
+ * The inactive label: nile-nav-tab paints it var(--nile-colors-dark-500, var(--ng-colors-text-secondary-700)), so the strip
486
+ * points the NxtGen fallback at text-quaternary-500. Enterprise defines --nile-colors-dark-500 and is untouched. Inside an
487
+ * underline group nothing else reads text-secondary-700 (only the group's other variants and side placements do).
488
+ */
489
+ --ng-colors-text-secondary-700: var(--ng-colors-text-quaternary-500);
489
490
  flex: 1 1 auto;
490
491
  min-width: 0;
491
492
  align-self: flex-end;
@@ -652,7 +653,9 @@ export const styles = css `
652
653
 
653
654
  .panel-title {
654
655
  margin: 0;
655
- font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
656
+ /* Figma's Assistant Title: Text lg/Semibold, 18/28 on NxtGen. Enterprise keeps --nile-type-scale-3, and it defines no --ng-* tokens, so the line-height declaration is invalid there and the title inherits its line height exactly as before. */
657
+ font-size: var(--nile-type-scale-3, var(--ng-font-size-text-lg));
658
+ line-height: var(--ng-line-height-text-lg);
656
659
  font-weight: var(
657
660
  --nile-font-weight-semi-bold,
658
661
  var(--ng-font-weight-semibold)
@@ -1 +1 @@
1
- {"version":3,"file":"nile-app-shell.css.js","sourceRoot":"","sources":["../../../src/nile-app-shell/nile-app-shell.css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAEpF,iJAAiJ;AACjJ,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAobrB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuSvB,CAAC;AAEF,eAAe,CAAC,MAAM,CAAC,CAAC","sourcesContent":["/**\n * Copyright Aquera Inc 2023\n *\n * This source code is licensed under the BSD-3-Clause license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { css } from 'lit';\nimport { utilityControlStyles } from '../internal/app-shell-utility-control-styles';\n\n/** AppShell CSS: a grid of banner, top bar, side-nav track and content column, whose flex row holds the container, aside and docked AI panel. */\nexport const styles = css`\n :host {\n /* Geometry: design tokens where one exists, bare pixels where none does. */\n /* The nav track mirrors nile-side-bar's own width expressions (enterprise 240/70, NxtGen 296/68); keep in step with nile-side-bar.css.ts. */\n --nile-app-shell-side-nav-width: var(\n --nile-width-240px,\n var(--ng-spacing-296, 240px)\n );\n --nile-app-shell-side-nav-rail-width: var(\n --nile-width-70px,\n var(--ng-spacing-68, 70px)\n );\n --nile-app-shell-gutter: var(--nile-spacing-xs, var(--ng-spacing-xs));\n --nile-app-shell-content-padding: var(\n --nile-spacing-3xl,\n var(--ng-spacing-3xl)\n );\n --nile-app-shell-top-bar-height: 68px;\n /* The panel header keeps its own height, distinct from the page header. */\n --nile-app-shell-panel-header-height: 56px;\n --nile-app-shell-tabs-height: 33px;\n /* The leading app icon is its own 20px size, not the 32px utility box. */\n --nile-app-shell-app-icon-size: 20px;\n --nile-app-shell-panel-width: 480px;\n --nile-app-shell-panel-min-width: 360px;\n --nile-app-shell-aside-width: 320px;\n --nile-app-shell-aside-min-width: 240px;\n --nile-app-shell-content-min-width: 640px;\n --nile-app-shell-min-width: 768px;\n --nile-app-shell-centered-width: 824px;\n /* Both tokens are 32px; the literal is the floor with no theme sheet loaded. */\n --nile-app-shell-utility-size: var(\n --nile-spacing-4xl,\n var(--ng-spacing-4xl, 32px)\n );\n --nile-app-shell-radius: var(--nile-radius-xl, var(--ng-radius-2xl));\n --nile-app-shell-duration: var(\n --nile-transition-duration-default,\n var(--ng-transition-duration-default)\n );\n /* NxtGen ships no easing tokens, so the shell names its own. */\n --nile-app-shell-ease: cubic-bezier(0.2, 0, 0, 1);\n\n --_side-nav-track: var(--nile-app-shell-side-nav-width);\n\n position: relative;\n box-sizing: border-box;\n display: grid;\n grid-template-areas:\n 'banner banner'\n 'top-bar top-bar'\n 'side-nav content';\n grid-template-columns: var(--_side-nav-track) minmax(0, 1fr);\n grid-template-rows: auto auto minmax(0, 1fr);\n /* Below this the window scrolls rather than the shell compressing. */\n min-width: var(--nile-app-shell-min-width);\n height: 100%;\n overflow: hidden;\n background: var(--nile-colors-neutral-100, var(--ng-colors-bg-tertiary));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n font-family: var(--nile-font-family-sans-serif, var(--ng-font-family-body));\n transition: grid-template-columns var(--nile-app-shell-duration)\n var(--nile-app-shell-ease);\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host([full-height]) {\n height: 100dvh;\n }\n\n /* Effective rail state: the user's preference, or a forced rail when narrow. */\n :host([rail]) {\n --_side-nav-track: var(--nile-app-shell-side-nav-rail-width);\n }\n\n :host(:not([has-side-nav])) {\n --_side-nav-track: 0px;\n }\n\n /* The Description axis: a present description adds the 8px its second line occupies. */\n :host([has-description]) {\n --nile-app-shell-top-bar-height: 76px;\n }\n\n /* The top bar compresses before the content does. */\n @media (max-height: 600px) {\n :host {\n --nile-app-shell-top-bar-height: 56px;\n }\n\n :host([has-description]) {\n --nile-app-shell-top-bar-height: 64px;\n }\n }\n\n /* ---------------------------------------------------------------- banner */\n\n .banner {\n grid-area: banner;\n min-width: 0;\n }\n\n :host(:not([has-banner])) .banner {\n display: none;\n }\n\n /* ------------------------------------------------------------- side nav */\n\n .side-nav {\n grid-area: side-nav;\n display: flex;\n min-width: 0;\n overflow: hidden;\n }\n\n :host(:not([has-side-nav])) .side-nav {\n display: none;\n }\n\n /* A slotted sidebar fills the shell-owned track and drops its own surface and edge; set --nile-app-shell-side-nav-bg to restore one. */\n /* width is deliberately not !important: the 100% lets a raw <nav> or nile-app-shell-side-nav fill the track, while a slotted\n nile-side-bar sizes itself from the same tokens the track reads (see the :host geometry block). Tests 21/22 in\n nile-app-shell-regions.test.ts lock the two together; change both or neither. */\n ::slotted([slot='side-nav']) {\n width: 100%;\n height: 100%;\n background: var(--nile-app-shell-side-nav-bg, transparent) !important;\n border-right: var(--nile-app-shell-side-nav-border, 0) !important;\n }\n\n /* -------------------------------------------------------- content column */\n\n .content-section {\n grid-area: content;\n position: relative;\n display: flex;\n min-width: 0;\n gap: var(--nile-app-shell-gutter);\n padding: var(--nile-app-shell-gutter);\n /* Flush against the nav track; the gutter insets the other three sides. */\n padding-inline-start: 0;\n box-sizing: border-box;\n }\n\n /* With no nav track there is nothing to sit flush against, so the start edge takes the gutter too. */\n :host(:not([has-side-nav])) .content-section {\n padding-inline-start: var(--nile-app-shell-gutter);\n }\n\n .container {\n box-sizing: border-box;\n /* The floor is the flex basis, not a min-width, so the container yields instead of overflowing the clipped row. */\n flex: 1 1 var(--nile-app-shell-content-min-width);\n display: flex;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-app-shell-radius);\n box-shadow: var(--nile-box-shadow-none, var(--ng-shadow-none));\n /* The container, not the viewport, is the sizing context for page content. */\n container-type: inline-size;\n container-name: nile-content;\n }\n\n /* content-container moves the size query context onto the slotted page root so page CSS can query nile-content; opt-in as it brings containment. */\n :host([content-container]) slot:not([name])::slotted(*) {\n container-type: inline-size;\n container-name: nile-content;\n }\n\n :host([flat]) .container {\n background: transparent;\n border-color: transparent;\n border-radius: 0;\n }\n\n /* ---------------------------------------------------------------- top bar */\n\n .top-bar {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n height: var(--nile-app-shell-top-bar-height);\n padding-inline: var(--nile-app-shell-content-padding);\n }\n\n /* The header bar draws no bottom rule in any variant; the only divider comes from the tab rail (see .tabs). */\n\n .shell-top-bar {\n grid-area: top-bar;\n min-width: 0;\n padding-inline: var(--nile-spacing-xl, var(--ng-spacing-xl));\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n /* No slotted bar content and no nav toggle means no bar at all. */\n :host(:not([has-top-bar])) .top-bar {\n display: none;\n }\n\n .top-bar-content {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n min-width: 0;\n flex: 1 1 auto;\n }\n\n /* The title block: the header's own heading, the Leading axis and the badge; renders before the top-bar slot. */\n .title-area {\n display: flex;\n /* Top-aligned, not centred: the leading element belongs to the title's row, not the title-plus-description stack. */\n align-items: flex-start;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-width: 0;\n }\n\n /* The leading line box: exactly the page title's line height, centring whatever leading control sits in it. */\n .leading {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));\n }\n\n .title-stack {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: var(--nile-spacing-xxs, var(--ng-spacing-xxs));\n min-width: 0;\n }\n\n .title-row {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-width: 0;\n }\n\n .page-title {\n margin: 0;\n min-width: 0;\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-md));\n line-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-semibold));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .description {\n margin: 0;\n min-width: 0;\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-1, var(--ng-font-size-text-xs));\n line-height: var(--nile-line-height-xsmall, var(--ng-line-height-text-xs));\n font-weight: var(--nile-font-weight-regular, var(--ng-font-weight-regular));\n color: var(--nile-colors-dark-500, var(--ng-colors-text-tertiary-600));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* The badge sits on the title row and never shrinks the title away; each surface token pairs a Nile name with its NxtGen equivalent. */\n .badge {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n padding-inline: var(--nile-spacing-md, var(--ng-spacing-md));\n padding-block: var(--nile-spacing-xxs, var(--ng-spacing-xxs));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(\n --nile-colors-neutral-400,\n var(--ng-componentcolors-utility-gray-200)\n );\n border-radius: var(--nile-radius-full, var(--ng-radius-full));\n background: var(\n --nile-colors-neutral-100,\n var(--ng-componentcolors-utility-gray-50)\n );\n color: var(\n --nile-colors-dark-500,\n var(--ng-componentcolors-utility-gray-700)\n );\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-1, var(--ng-font-size-text-xs));\n line-height: var(--nile-line-height-xsmall, var(--ng-line-height-text-xs));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));\n white-space: nowrap;\n }\n\n /* Leading=Back: drawn as a breadcrumb label; the shell owns no history, so pressing it only emits nile-header-back. */\n .back {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: var(--nile-spacing-xs, var(--ng-spacing-xs));\n margin: 0;\n padding: 0;\n border: 0;\n background: none;\n cursor: pointer;\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-md));\n line-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-semibold));\n color: var(--nile-colors-dark-500, var(--ng-colors-text-tertiary-600));\n }\n\n .back:hover {\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n }\n\n .crumb-divider {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n color: var(--nile-colors-dark-500, var(--ng-colors-fg-quaternary-400));\n }\n\n /* Leading=AppIcon: a 20px block before the title; the page slots the mark, the shell owns the box, surface and radius. */\n .app-icon {\n position: relative;\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--nile-app-shell-app-icon-size);\n height: var(--nile-app-shell-app-icon-size);\n border-radius: var(--nile-radius-sm, var(--ng-radius-sm));\n overflow: hidden;\n }\n\n /* The slotted mark fills the wrapper edge to edge, clipped to the box. */\n .app-icon slot::slotted(*) {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n }\n\n /* The wrapper takes no fill; the rim is a white-12% gradient drawn as a masked ::before, with literal mask fallbacks for the nxtgen-only tokens. */\n .app-icon::before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 1;\n background: linear-gradient(\n 180deg,\n rgb(255 255 255 / 12%) 0%,\n rgb(255 255 255 / 0%) 100%\n );\n mask: var(\n --ng-mask-rim,\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0)\n );\n mask-composite: var(--ng-mask-composite-exclude, exclude);\n padding: 1.4px;\n }\n\n :host(:not([leading='app-icon'])) .app-icon,\n :host(:not([leading='back'])) .back,\n :host(:not([leading='back'])) .crumb-divider {\n display: none;\n }\n\n .top-bar-actions {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n margin-inline-start: auto;\n }\n\n /* Hidden when empty, so an empty group's gap does not pull the bar's content short of the padding edge. */\n :host(:not([has-top-bar-actions]):not([has-ask])) .top-bar-actions {\n display: none;\n }\n\n /* The Ask button: a stock <nile-button variant=\"primary\"> the shell renders itself; the only rule here is its flex behaviour as a top-bar item. */\n .ask {\n flex: 0 0 auto;\n }\n\n .ask-mark {\n display: inline-flex;\n align-items: center;\n }\n\n .ask-mark nile-glyph {\n --nile-svg-fill: currentColor;\n --nile-svg-stroke-width: var(--ng-svg-stroke-width);\n width: 16px;\n height: 16px;\n }\n\n .nav-toggle-group {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-lg, var(--ng-spacing-lg));\n }\n\n /* Lands the 20px glyph box, not the 32px utility circle, on the 24px origin: (32 - 20) / 2 = 6. */\n .nav-toggle {\n margin-inline-start: -6px;\n }\n\n .rule {\n flex: 0 0 auto;\n width: var(--nile-border-width-1, var(--ng-border-width-1));\n height: 24px;\n background: var(\n --nile-colors-neutral-400,\n var(--ng-colors-border-secondary)\n );\n }\n\n /* ------------------------------------------------------- utility controls */\n\n /* The shell's own icon controls (nav toggle, panel back and close): the shared utility-control recipe. */\n ${utilityControlStyles}\n\n /* --------------------------------------------------------------- tab strip */\n\n /* Hoisted out of the scroller so it never scrolls away; sits flush under the top bar and carries the header block's single bottom rule. */\n .tabs {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: stretch;\n gap: var(--nile-spacing-xs, var(--ng-spacing-xs));\n min-width: 0;\n /* A floor, not a fixed box: the strip is as tall as the row it holds plus its rule. */\n min-height: var(--nile-app-shell-tabs-height);\n padding-inline: var(--nile-app-shell-content-padding);\n /* The strip carries the rule for the whole header block. */\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n /* The header tab's 0/4/12/4 padding composes the 32px row; the 12px bottom gives the active indicator its band, set via the group's public padding hook. */\n ::slotted([slot='tabs']) {\n --nile-nav-tab-padding: var(--nile-spacing-none, var(--ng-spacing-none))\n var(--nile-spacing-xs, var(--ng-spacing-xs))\n var(--nile-spacing-lg, var(--ng-spacing-lg))\n var(--nile-spacing-xs, var(--ng-spacing-xs));\n }\n\n .tabs::-webkit-scrollbar {\n display: none;\n }\n\n :host(:not([has-tabs])) .tabs,\n :host([notabs]) .tabs {\n display: none;\n }\n\n /* A slotted nile-nav-tab-group drops its own track (--track-width:0 on the host) and is bottom-aligned so its indicator sits on the region's single rule. */\n /* Scoped to the group, not the slot, so bare tab controls are not stretched to an equal share of the strip. */\n ::slotted(nile-nav-tab-group[slot='tabs']) {\n --track-width: 0px;\n flex: 1 1 auto;\n min-width: 0;\n align-self: flex-end;\n }\n\n /* ------------------------------------------------------------------- main */\n\n .main {\n box-sizing: border-box;\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: auto;\n /* Top and sides only: the page runs to the container's bottom edge. */\n padding: var(--nile-app-shell-content-padding);\n padding-block-end: 0;\n }\n\n .main:focus {\n outline: none;\n }\n\n :host([no-padding]) .main {\n padding: 0;\n }\n\n .main-inner {\n width: 100%;\n min-height: 0;\n }\n\n /* Centred when short, scrolls from the top when tall. */\n :host([content-align='centered']) .main-inner {\n /* width:100% + max-width leaves space for the auto margins to centre it while short, and scroll from the top when tall. */\n width: 100%;\n max-width: var(--nile-app-shell-centered-width);\n margin: auto;\n }\n\n /* ------------------------------------------------------------------ aside */\n\n .aside {\n box-sizing: border-box;\n /* Gives before the page does, down to its own floor. */\n flex: 0 1 var(--nile-app-shell-aside-width);\n min-width: var(--nile-app-shell-aside-min-width);\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: auto;\n padding: var(--nile-app-shell-content-padding);\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n border-radius: var(--nile-app-shell-radius);\n }\n\n :host(:not([has-aside])) .aside {\n display: none;\n }\n\n /* -------------------------------------------------------------- AI panel */\n\n .panel {\n box-sizing: border-box;\n /* The panel pushes the page rather than covering it: full width while the row affords it, shrinking to a real min-width floor. */\n flex: 0 1 var(--nile-app-shell-panel-width);\n width: var(--nile-app-shell-panel-width);\n min-width: var(--nile-app-shell-panel-min-width);\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n /* The panel is elevated, so its edge sits a rung above the container's. */\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-app-shell-radius);\n box-shadow: var(--nile-box-shadow-2, var(--ng-shadow-lg));\n }\n\n /* Docked: a flex sibling. It squeezes the content, it does not cover it. */\n :host(:not([panel-open])) .panel {\n display: none;\n }\n\n /* Overlay: contained to the content column, above it, and animated in. */\n :host([panel-mode='overlay']) .panel {\n position: absolute;\n z-index: 1001;\n inset-block: var(--nile-app-shell-gutter);\n inset-inline-end: var(--nile-app-shell-gutter);\n flex: none;\n display: flex;\n width: min(var(--nile-app-shell-panel-width), 92%);\n visibility: hidden;\n transform: translateX(calc(100% + var(--nile-app-shell-gutter)));\n transition: transform var(--nile-app-shell-duration)\n var(--nile-app-shell-ease),\n visibility 0s linear var(--nile-app-shell-duration);\n }\n\n :host([panel-mode='overlay'][panel-open]) .panel {\n visibility: visible;\n transform: none;\n transition: transform var(--nile-app-shell-duration)\n var(--nile-app-shell-ease);\n }\n\n /* An unavailable panel is unmounted in either mode. */\n :host(:not([has-panel])) .panel {\n display: none;\n }\n\n .panel-header {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n height: var(--nile-app-shell-panel-header-height);\n padding-inline: var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n /* The back control for a panel sub-view; stands where the brand mark does in the root view. */\n .panel-back {\n flex: 0 0 auto;\n margin-inline-start: -6px;\n }\n\n /* Mirrors the back control's offset on the end edge: the 20px glyph, not the 32px circle, lands on the padding line. */\n .panel-close {\n margin-inline-end: -6px;\n }\n\n :host([panelback]) .panel-mark {\n display: none;\n }\n\n .panel-heading {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-width: 0;\n }\n\n .panel-mark {\n display: inline-flex;\n color: var(\n --nile-colors-primary-600,\n var(--ng-colors-fg-brand-primary-600)\n );\n }\n\n .panel-mark nile-glyph {\n --nile-svg-fill: currentColor;\n --nile-svg-stroke-width: var(--ng-svg-stroke-width);\n width: 20px;\n height: 20px;\n }\n\n .panel-title {\n margin: 0;\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));\n font-weight: var(\n --nile-font-weight-semi-bold,\n var(--ng-font-weight-semibold)\n );\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .panel-actions {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xs, var(--ng-spacing-xs));\n margin-inline-start: auto;\n }\n\n .panel-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n /* 16 under the header, 24 on the sides and bottom. */\n padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n display: flex;\n flex-direction: column;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n }\n\n .panel-footer {\n flex: 0 0 auto;\n padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n border-top: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n :host(:not([has-panel-footer])) .panel-footer {\n display: none;\n }\n\n /* ---------------------------------------------------------- skip link */\n\n .skip-link {\n position: absolute;\n z-index: 1002;\n inset-inline-start: var(--nile-spacing-md, var(--ng-spacing-md));\n inset-block-start: var(--nile-spacing-md, var(--ng-spacing-md));\n display: inline-flex;\n align-items: center;\n padding: var(--nile-spacing-md, var(--ng-spacing-md))\n var(--nile-spacing-lg, var(--ng-spacing-lg));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-radius-md, var(--ng-radius-md));\n background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n font: inherit;\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));\n box-shadow: var(--nile-box-shadow-2, var(--ng-shadow-lg));\n cursor: pointer;\n transform: translateY(-200%);\n transition: transform\n var(--nile-transition-duration-short, var(--ng-transition-duration-fast))\n var(--nile-app-shell-ease);\n }\n\n .skip-link:focus-visible {\n outline: none;\n transform: none;\n box-shadow: 0 0 0 2px\n var(--nile-colors-neutral-100, var(--ng-colors-bg-tertiary)),\n 0 0 0 4px\n var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));\n }\n\n :host([no-skip-link]) .skip-link {\n display: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host,\n .panel,\n .skip-link {\n transition: none;\n }\n }\n`;\n\nexport default [styles];\n"]}
1
+ {"version":3,"file":"nile-app-shell.css.js","sourceRoot":"","sources":["../../../src/nile-app-shell/nile-app-shell.css.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAEpF,iJAAiJ;AACjJ,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA0arB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoTvB,CAAC;AAEF,eAAe,CAAC,MAAM,CAAC,CAAC","sourcesContent":["/**\n * Copyright Aquera Inc 2023\n *\n * This source code is licensed under the BSD-3-Clause license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { css } from 'lit';\nimport { utilityControlStyles } from '../internal/app-shell-utility-control-styles';\n\n/** AppShell CSS: a grid of banner, top bar, side-nav track and content column, whose flex row holds the container, aside and docked AI panel. */\nexport const styles = css`\n :host {\n /* Geometry: design tokens where one exists, bare pixels where none does. */\n /* The nav track mirrors nile-side-bar's own width expressions (enterprise 240/70, NxtGen 296/68); keep in step with nile-side-bar.css.ts. */\n --nile-app-shell-side-nav-width: var(\n --nile-width-240px,\n var(--ng-spacing-296, 240px)\n );\n --nile-app-shell-side-nav-rail-width: var(\n --nile-width-70px,\n var(--ng-spacing-68, 70px)\n );\n --nile-app-shell-gutter: var(--nile-spacing-xs, var(--ng-spacing-xs));\n --nile-app-shell-content-padding: var(\n --nile-spacing-3xl,\n var(--ng-spacing-3xl)\n );\n --nile-app-shell-top-bar-height: 68px;\n /* The panel header keeps its own height, distinct from the page header. */\n --nile-app-shell-panel-header-height: 56px;\n --nile-app-shell-tabs-height: 33px;\n /* The leading app icon is its own 20px size, not the 32px utility box. */\n --nile-app-shell-app-icon-size: 20px;\n --nile-app-shell-panel-width: 480px;\n --nile-app-shell-panel-min-width: 360px;\n --nile-app-shell-aside-width: 320px;\n --nile-app-shell-aside-min-width: 240px;\n --nile-app-shell-content-min-width: 640px;\n --nile-app-shell-min-width: 768px;\n --nile-app-shell-centered-width: 824px;\n /* Both tokens are 32px; the literal is the floor with no theme sheet loaded. */\n --nile-app-shell-utility-size: var(\n --nile-spacing-4xl,\n var(--ng-spacing-4xl, 32px)\n );\n --nile-app-shell-radius: var(--nile-radius-xl, var(--ng-radius-2xl));\n --nile-app-shell-duration: var(\n --nile-transition-duration-default,\n var(--ng-transition-duration-default)\n );\n /* NxtGen ships no easing tokens, so the shell names its own. */\n --nile-app-shell-ease: cubic-bezier(0.2, 0, 0, 1);\n\n --_side-nav-track: var(--nile-app-shell-side-nav-width);\n\n position: relative;\n box-sizing: border-box;\n display: grid;\n grid-template-areas:\n 'banner banner'\n 'top-bar top-bar'\n 'side-nav content';\n grid-template-columns: var(--_side-nav-track) minmax(0, 1fr);\n grid-template-rows: auto auto minmax(0, 1fr);\n /* Below this the window scrolls rather than the shell compressing. */\n min-width: var(--nile-app-shell-min-width);\n height: 100%;\n overflow: hidden;\n background: var(--nile-colors-neutral-100, var(--ng-colors-bg-tertiary));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n font-family: var(--nile-font-family-sans-serif, var(--ng-font-family-body));\n transition: grid-template-columns var(--nile-app-shell-duration)\n var(--nile-app-shell-ease);\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host([full-height]) {\n height: 100dvh;\n }\n\n /* Effective rail state: the user's preference, or a forced rail when narrow. */\n :host([rail]) {\n --_side-nav-track: var(--nile-app-shell-side-nav-rail-width);\n }\n\n :host(:not([has-side-nav])) {\n --_side-nav-track: 0px;\n }\n\n /* The Description axis: a present description adds the 8px its second line occupies. */\n :host([has-description]) {\n --nile-app-shell-top-bar-height: 76px;\n }\n\n /* The top bar compresses before the content does. */\n @media (max-height: 600px) {\n :host {\n --nile-app-shell-top-bar-height: 56px;\n }\n\n :host([has-description]) {\n --nile-app-shell-top-bar-height: 64px;\n }\n }\n\n /* ---------------------------------------------------------------- banner */\n\n .banner {\n grid-area: banner;\n min-width: 0;\n }\n\n :host(:not([has-banner])) .banner {\n display: none;\n }\n\n /* ------------------------------------------------------------- side nav */\n\n .side-nav {\n grid-area: side-nav;\n display: flex;\n min-width: 0;\n overflow: hidden;\n }\n\n :host(:not([has-side-nav])) .side-nav {\n display: none;\n }\n\n /* A slotted sidebar fills the shell-owned track and drops its own surface and edge; set --nile-app-shell-side-nav-bg to restore one. */\n /* width is deliberately not !important: the 100% lets a raw <nav> or nile-app-shell-side-nav fill the track, while a slotted\n nile-side-bar sizes itself from the same tokens the track reads (see the :host geometry block). Tests 21/22 in\n nile-app-shell-regions.test.ts lock the two together; change both or neither. */\n ::slotted([slot='side-nav']) {\n width: 100%;\n height: 100%;\n background: var(--nile-app-shell-side-nav-bg, transparent) !important;\n border-right: var(--nile-app-shell-side-nav-border, 0) !important;\n }\n\n /* -------------------------------------------------------- content column */\n\n .content-section {\n grid-area: content;\n position: relative;\n display: flex;\n min-width: 0;\n gap: var(--nile-app-shell-gutter);\n padding: var(--nile-app-shell-gutter);\n /* Flush against the nav track; the gutter insets the other three sides. */\n padding-inline-start: 0;\n box-sizing: border-box;\n }\n\n /* With no nav track there is nothing to sit flush against, so the start edge takes the gutter too. */\n :host(:not([has-side-nav])) .content-section {\n padding-inline-start: var(--nile-app-shell-gutter);\n }\n\n .container {\n box-sizing: border-box;\n /* The floor is the flex basis, not a min-width, so the container yields instead of overflowing the clipped row. */\n flex: 1 1 var(--nile-app-shell-content-min-width);\n display: flex;\n flex-direction: column;\n min-width: 0;\n overflow: hidden;\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-app-shell-radius);\n box-shadow: var(--nile-box-shadow-none, var(--ng-shadow-none));\n /* The container, not the viewport, is the sizing context for page content. */\n container-type: inline-size;\n container-name: nile-content;\n }\n\n /* content-container moves the size query context onto the slotted page root so page CSS can query nile-content; opt-in as it brings containment. */\n :host([content-container]) slot:not([name])::slotted(*) {\n container-type: inline-size;\n container-name: nile-content;\n }\n\n :host([flat]) .container {\n background: transparent;\n border-color: transparent;\n border-radius: 0;\n }\n\n /* ---------------------------------------------------------------- top bar */\n\n .top-bar {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n height: var(--nile-app-shell-top-bar-height);\n padding-inline: var(--nile-app-shell-content-padding);\n }\n\n /* The header bar draws no bottom rule in any variant; the only divider comes from the tab rail (see .tabs). */\n\n .shell-top-bar {\n grid-area: top-bar;\n min-width: 0;\n padding-inline: var(--nile-spacing-xl, var(--ng-spacing-xl));\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n /* No slotted bar content and no nav toggle means no bar at all. */\n :host(:not([has-top-bar])) .top-bar {\n display: none;\n }\n\n .top-bar-content {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n min-width: 0;\n flex: 1 1 auto;\n }\n\n /* The title block: the back arrow, then the stack (app icon, heading and badge, with the description under them); renders before the top-bar slot. */\n .title-area {\n display: flex;\n /* Top-aligned, not centred: the back arrow belongs to the title's row, not the title-plus-description stack. */\n align-items: flex-start;\n /* Figma's Title Area gap: 16px from the arrow to the stack. */\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n min-width: 0;\n }\n\n /* The back arrow's line box: exactly the page title's line height, centring the arrow on the title row. */\n .back-line {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n min-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));\n }\n\n .title-stack {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: var(--nile-spacing-xxs, var(--ng-spacing-xxs));\n min-width: 0;\n }\n\n .title-row {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-width: 0;\n }\n\n .page-title {\n margin: 0;\n min-width: 0;\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-md));\n line-height: var(--nile-line-height-medium, var(--ng-line-height-text-md));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-semibold));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .description {\n margin: 0;\n min-width: 0;\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-1, var(--ng-font-size-text-xs));\n line-height: var(--nile-line-height-xsmall, var(--ng-line-height-text-xs));\n font-weight: var(--nile-font-weight-regular, var(--ng-font-weight-regular));\n color: var(--nile-colors-dark-500, var(--ng-colors-text-quaternary-500));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* The badge sits on the title row and never shrinks the title away; each surface token pairs a Nile name with its NxtGen equivalent. */\n .badge {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n padding-inline: var(--nile-spacing-md, var(--ng-spacing-md));\n padding-block: var(--nile-spacing-xxs, var(--ng-spacing-xxs));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(\n --nile-colors-neutral-400,\n var(--ng-componentcolors-utility-gray-200)\n );\n border-radius: var(--nile-radius-full, var(--ng-radius-full));\n background: var(\n --nile-colors-neutral-100,\n var(--ng-componentcolors-utility-gray-50)\n );\n color: var(\n --nile-colors-dark-500,\n var(--ng-componentcolors-utility-gray-700)\n );\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-1, var(--ng-font-size-text-xs));\n line-height: var(--nile-line-height-xsmall, var(--ng-line-height-text-xs));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));\n white-space: nowrap;\n }\n\n /* headerBack: an icon-only native button, so the aria-label names it directly; the shell owns no history, so pressing it only emits nile-click { value: 'back' }. */\n .back {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n margin: 0;\n padding: 0;\n border: 0;\n background: none;\n cursor: pointer;\n color: var(--nile-colors-dark-500, var(--ng-colors-fg-quaternary-400));\n }\n\n .back:hover {\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n }\n\n /* App icon: a 20px block at the start of the title row, so the description lines up under it; shown whenever the app-icon slot has content. */\n .app-icon {\n position: relative;\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--nile-app-shell-app-icon-size);\n height: var(--nile-app-shell-app-icon-size);\n border-radius: var(--nile-radius-sm, var(--ng-radius-sm));\n overflow: hidden;\n }\n\n /* The slotted mark fills the wrapper edge to edge, clipped to the box. */\n .app-icon slot::slotted(*) {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n }\n\n /* The wrapper takes no fill; the rim is a white-12% gradient drawn as a masked ::before, with literal mask fallbacks for the nxtgen-only tokens. */\n .app-icon::before {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 1;\n background: linear-gradient(\n 180deg,\n rgb(255 255 255 / 12%) 0%,\n rgb(255 255 255 / 0%) 100%\n );\n mask: var(\n --ng-mask-rim,\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0)\n );\n mask-composite: var(--ng-mask-composite-exclude, exclude);\n padding: 1.4px;\n }\n\n :host(:not([has-app-icon])) .app-icon {\n display: none;\n }\n\n /* Figma's Header Bar gap: 16px between every header action, the divider and Ask. */\n .top-bar-actions {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n margin-inline-start: auto;\n }\n\n /* Hidden when empty, so an empty group's gap does not pull the bar's content short of the padding edge. */\n :host(:not([has-top-bar-actions]):not([has-ask])) .top-bar-actions {\n display: none;\n }\n\n /* The Ask button: a stock <nile-button variant=\"secondary\"> the shell renders itself; the only rule here is its flex behaviour as a top-bar item. */\n .ask {\n flex: 0 0 auto;\n }\n\n .ask-mark {\n display: inline-flex;\n align-items: center;\n }\n\n .ask-mark nile-glyph {\n --nile-svg-fill: currentColor;\n --nile-svg-stroke-width: var(--ng-svg-stroke-width);\n width: 16px;\n height: 16px;\n }\n\n /* 10px after the 32px circle is 16px after the 20px glyph (6px overhang + 10), Figma's toggle-to-divider gap. */\n .nav-toggle-group {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md-alt, var(--ng-spacing-md-alt));\n }\n\n /* Lands the 20px glyph box, not the 32px utility circle, on the 24px origin: (32 - 20) / 2 = 6. */\n .nav-toggle {\n margin-inline-start: -6px;\n }\n\n /* Figma's Divider Line: a 16px 1px stroke that takes no layout width, so the items on both sides sit a clean 16px from it. Used after the nav toggle and, as ask-rule, before Ask. */\n .rule {\n flex: 0 0 auto;\n width: var(--nile-border-width-1, var(--ng-border-width-1));\n margin-inline-end: calc(-1 * var(--nile-border-width-1, var(--ng-border-width-1)));\n height: 16px;\n background: var(\n --nile-colors-neutral-400,\n var(--ng-colors-border-secondary)\n );\n }\n\n /* ------------------------------------------------------- utility controls */\n\n /* The shell's own icon controls (nav toggle, panel back and close): the shared utility-control recipe. */\n ${utilityControlStyles}\n\n /* --------------------------------------------------------------- tab strip */\n\n /* Hoisted out of the scroller so it never scrolls away; sits flush under the top bar and carries the header block's single bottom rule. */\n .tabs {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: stretch;\n gap: var(--nile-spacing-xs, var(--ng-spacing-xs));\n min-width: 0;\n /* A floor, not a fixed box: the strip is as tall as the row it holds plus its rule. */\n min-height: var(--nile-app-shell-tabs-height);\n padding-inline: var(--nile-app-shell-content-padding);\n /* The strip carries the rule for the whole header block. */\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n /* The header tab's 0/4/12/4 padding composes the 32px row; the 12px bottom gives the active indicator its band, set via the group's public padding hook. */\n ::slotted([slot='tabs']) {\n --nile-nav-tab-padding: var(--nile-spacing-none, var(--ng-spacing-none))\n var(--nile-spacing-xs, var(--ng-spacing-xs))\n var(--nile-spacing-lg, var(--ng-spacing-lg))\n var(--nile-spacing-xs, var(--ng-spacing-xs));\n }\n\n .tabs::-webkit-scrollbar {\n display: none;\n }\n\n :host(:not([has-tabs])) .tabs,\n :host([notabs]) .tabs {\n display: none;\n }\n\n /* A slotted nile-nav-tab-group drops its own track (--track-width:0 on the host) and is bottom-aligned so its indicator sits on the region's single rule. */\n /* Scoped to the group, not the slot, so bare tab controls are not stretched to an equal share of the strip. */\n ::slotted(nile-nav-tab-group[slot='tabs']) {\n --track-width: 0px;\n /*\n * The active indicator (Figma: fg-brand-primary-alt) is NOT set here: the top placement hard-codes\n * var(--nile-colors-primary-600, var(--ng-colors-text-brand-secondary-700)) inside nile-nav-tab-group's shadow tree, and\n * remapping either token from here would also recolour nile-nav-tab's focus ring and focus label. Known limitation (spec A-7).\n */\n /*\n * The inactive label: nile-nav-tab paints it var(--nile-colors-dark-500, var(--ng-colors-text-secondary-700)), so the strip\n * points the NxtGen fallback at text-quaternary-500. Enterprise defines --nile-colors-dark-500 and is untouched. Inside an\n * underline group nothing else reads text-secondary-700 (only the group's other variants and side placements do).\n */\n --ng-colors-text-secondary-700: var(--ng-colors-text-quaternary-500);\n flex: 1 1 auto;\n min-width: 0;\n align-self: flex-end;\n }\n\n /* ------------------------------------------------------------------- main */\n\n .main {\n box-sizing: border-box;\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: auto;\n /* Top and sides only: the page runs to the container's bottom edge. */\n padding: var(--nile-app-shell-content-padding);\n padding-block-end: 0;\n }\n\n .main:focus {\n outline: none;\n }\n\n :host([no-padding]) .main {\n padding: 0;\n }\n\n .main-inner {\n width: 100%;\n min-height: 0;\n }\n\n /* Centred when short, scrolls from the top when tall. */\n :host([content-align='centered']) .main-inner {\n /* width:100% + max-width leaves space for the auto margins to centre it while short, and scroll from the top when tall. */\n width: 100%;\n max-width: var(--nile-app-shell-centered-width);\n margin: auto;\n }\n\n /* ------------------------------------------------------------------ aside */\n\n .aside {\n box-sizing: border-box;\n /* Gives before the page does, down to its own floor. */\n flex: 0 1 var(--nile-app-shell-aside-width);\n min-width: var(--nile-app-shell-aside-min-width);\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: auto;\n padding: var(--nile-app-shell-content-padding);\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n border-radius: var(--nile-app-shell-radius);\n }\n\n :host(:not([has-aside])) .aside {\n display: none;\n }\n\n /* -------------------------------------------------------------- AI panel */\n\n .panel {\n box-sizing: border-box;\n /* The panel pushes the page rather than covering it: full width while the row affords it, shrinking to a real min-width floor. */\n flex: 0 1 var(--nile-app-shell-panel-width);\n width: var(--nile-app-shell-panel-width);\n min-width: var(--nile-app-shell-panel-min-width);\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background: var(--nile-colors-white-base, var(--ng-colors-bg-secondary));\n /* The panel is elevated, so its edge sits a rung above the container's. */\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-app-shell-radius);\n box-shadow: var(--nile-box-shadow-2, var(--ng-shadow-lg));\n }\n\n /* Docked: a flex sibling. It squeezes the content, it does not cover it. */\n :host(:not([panel-open])) .panel {\n display: none;\n }\n\n /* Overlay: contained to the content column, above it, and animated in. */\n :host([panel-mode='overlay']) .panel {\n position: absolute;\n z-index: 1001;\n inset-block: var(--nile-app-shell-gutter);\n inset-inline-end: var(--nile-app-shell-gutter);\n flex: none;\n display: flex;\n width: min(var(--nile-app-shell-panel-width), 92%);\n visibility: hidden;\n transform: translateX(calc(100% + var(--nile-app-shell-gutter)));\n transition: transform var(--nile-app-shell-duration)\n var(--nile-app-shell-ease),\n visibility 0s linear var(--nile-app-shell-duration);\n }\n\n :host([panel-mode='overlay'][panel-open]) .panel {\n visibility: visible;\n transform: none;\n transition: transform var(--nile-app-shell-duration)\n var(--nile-app-shell-ease);\n }\n\n /* An unavailable panel is unmounted in either mode. */\n :host(:not([has-panel])) .panel {\n display: none;\n }\n\n .panel-header {\n box-sizing: border-box;\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n height: var(--nile-app-shell-panel-header-height);\n padding-inline: var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n border-bottom: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n /* The back control for a panel sub-view; stands where the brand mark does in the root view. */\n .panel-back {\n flex: 0 0 auto;\n margin-inline-start: -6px;\n }\n\n /* Mirrors the back control's offset on the end edge: the 20px glyph, not the 32px circle, lands on the padding line. */\n .panel-close {\n margin-inline-end: -6px;\n }\n\n :host([panelback]) .panel-mark {\n display: none;\n }\n\n .panel-heading {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-md, var(--ng-spacing-md));\n min-width: 0;\n }\n\n .panel-mark {\n display: inline-flex;\n color: var(\n --nile-colors-primary-600,\n var(--ng-colors-fg-brand-primary-600)\n );\n }\n\n .panel-mark nile-glyph {\n --nile-svg-fill: currentColor;\n --nile-svg-stroke-width: var(--ng-svg-stroke-width);\n width: 20px;\n height: 20px;\n }\n\n .panel-title {\n margin: 0;\n /* Figma's Assistant Title: Text lg/Semibold, 18/28 on NxtGen. Enterprise keeps --nile-type-scale-3, and it defines no --ng-* tokens, so the line-height declaration is invalid there and the title inherits its line height exactly as before. */\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-lg));\n line-height: var(--ng-line-height-text-lg);\n font-weight: var(\n --nile-font-weight-semi-bold,\n var(--ng-font-weight-semibold)\n );\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .panel-actions {\n display: flex;\n align-items: center;\n gap: var(--nile-spacing-xs, var(--ng-spacing-xs));\n margin-inline-start: auto;\n }\n\n .panel-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n /* 16 under the header, 24 on the sides and bottom. */\n padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n display: flex;\n flex-direction: column;\n gap: var(--nile-spacing-xl, var(--ng-spacing-xl));\n }\n\n .panel-footer {\n flex: 0 0 auto;\n padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl));\n border-top: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n\n :host(:not([has-panel-footer])) .panel-footer {\n display: none;\n }\n\n /* ---------------------------------------------------------- skip link */\n\n .skip-link {\n position: absolute;\n z-index: 1002;\n inset-inline-start: var(--nile-spacing-md, var(--ng-spacing-md));\n inset-block-start: var(--nile-spacing-md, var(--ng-spacing-md));\n display: inline-flex;\n align-items: center;\n padding: var(--nile-spacing-md, var(--ng-spacing-md))\n var(--nile-spacing-lg, var(--ng-spacing-lg));\n border: var(--nile-border-width-1, var(--ng-border-width-1)) solid\n var(--nile-colors-neutral-500, var(--ng-colors-border-primary));\n border-radius: var(--nile-radius-md, var(--ng-radius-md));\n background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n font: inherit;\n font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));\n box-shadow: var(--nile-box-shadow-2, var(--ng-shadow-lg));\n cursor: pointer;\n transform: translateY(-200%);\n transition: transform\n var(--nile-transition-duration-short, var(--ng-transition-duration-fast))\n var(--nile-app-shell-ease);\n }\n\n .skip-link:focus-visible {\n outline: none;\n transform: none;\n box-shadow: 0 0 0 2px\n var(--nile-colors-neutral-100, var(--ng-colors-bg-tertiary)),\n 0 0 0 4px\n var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));\n }\n\n :host([no-skip-link]) .skip-link {\n display: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host,\n .panel,\n .skip-link {\n transition: none;\n }\n }\n`;\n\nexport default [styles];\n"]}